1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349 |
- ##############################################################################
- #
- # Copyright (c) 2003 Zope Foundation and Contributors.
- # All Rights Reserved.
- #
- # This software is subject to the provisions of the Zope Public License,
- # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
- # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
- # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
- # FOR A PARTICULAR PURPOSE.
- #
- ##############################################################################
- """Acquisition test cases (and useful examples)
- """
-
- from __future__ import print_function
- import gc
- import unittest
- import sys
- import operator
- from doctest import DocTestSuite, DocFileSuite
-
- import ExtensionClass
-
- import Acquisition
- from Acquisition import ( # NOQA
- aq_acquire,
- aq_base,
- aq_chain,
- aq_get,
- aq_inContextOf,
- aq_inner,
- aq_parent,
- aq_self,
- Explicit,
- Implicit,
- IS_PYPY,
- IS_PURE,
- )
-
- if sys.version_info >= (3,):
- PY3 = True
- PY2 = False
-
- def unicode(self):
- # For test purposes, redirect the unicode
- # to the type of the object, just like Py2 did
- try:
- return type(self).__unicode__(self)
- except AttributeError as e:
- return type(self).__str__(self)
- long = int
- else:
- PY2 = True
- PY3 = False
-
- if 'Acquisition._Acquisition' not in sys.modules:
- CAPI = False
- else:
- CAPI = True
-
- MIXIN_POST_CLASS_DEFINITION = True
- try:
- class Plain(object):
- pass
- Plain.__bases__ = (ExtensionClass.Base, )
- except TypeError:
- # Not supported
- MIXIN_POST_CLASS_DEFINITION = False
-
- AQ_PARENT = unicode('aq_parent')
- UNICODE_WAS_CALLED = unicode('unicode was called')
- STR_WAS_CALLED = unicode('str was called')
- TRUE = unicode('True')
-
-
- class I(Implicit):
-
- def __init__(self, id):
- self.id = id
-
- def __repr__(self):
- return self.id
-
-
- class E(Explicit):
-
- def __init__(self, id):
- self.id = id
-
- def __repr__(self):
- return self.id
-
-
- class Location(object):
- __parent__ = None
-
-
- class ECLocation(ExtensionClass.Base):
- __parent__ = None
-
-
- def show(x):
- print(showaq(x).strip())
-
-
- def showaq(m_self, indent=''):
- rval = ''
- obj = m_self
- base = getattr(obj, 'aq_base', obj)
- try:
- id = base.id
- except Exception:
- id = str(base)
- try:
- id = id()
- except Exception:
- pass
-
- if hasattr(obj, 'aq_self'):
- if hasattr(obj.aq_self, 'aq_self'):
- rval = rval + indent + "(" + id + ")\n"
- rval = rval + indent + "| \\\n"
- rval = rval + showaq(obj.aq_self, '| ' + indent)
- rval = rval + indent + "|\n"
- rval = rval + showaq(obj.aq_parent, indent)
- elif hasattr(obj, 'aq_parent'):
- rval = rval + indent + id + "\n"
- rval = rval + indent + "|\n"
- rval = rval + showaq(obj.aq_parent, indent)
- else:
- rval = rval + indent + id + "\n"
- return rval
-
-
- class TestStory(unittest.TestCase):
-
- def test_story(self):
- # Acquisition is a mechanism that allows objects to obtain
- # attributes from their environment. It is similar to inheritence,
- # except that, rather than traversing an inheritence hierarchy
- # to obtain attributes, a containment hierarchy is traversed.
-
- # The "ExtensionClass":ExtensionClass.html. release includes mix-in
- # extension base classes that can be used to add acquisition as a
- # feature to extension subclasses. These mix-in classes use the
- # context-wrapping feature of ExtensionClasses to implement
- # acquisition. Consider the following example:
-
- class C(ExtensionClass.Base):
- color = 'red'
-
- class A(Implicit):
- def report(self):
- return self.color
-
- a = A()
- c = C()
- c.a = a
- self.assertEqual(c.a.report(), 'red')
-
- d = C()
- d.color = 'green'
- d.a = a
- self.assertEqual(d.a.report(), 'green')
-
- with self.assertRaises(AttributeError):
- a.report()
-
- # The class 'A' inherits acquisition behavior from 'Implicit'.
- # The object, 'a', "has" the color of objects 'c' and 'd'
- # when it is accessed through them, but it has no color by itself.
- # The object 'a' obtains attributes from it's environment, where
- # it's environment is defined by the access path used to reach 'a'.
-
- # Acquisition wrappers
-
- # When an object that supports acquisition is accessed through
- # an extension class instance, a special object, called an
- # acquisition wrapper, is returned. In the example above, the
- # expression 'c.a' returns an acquisition wrapper that
- # contains references to both 'c' and 'a'. It is this wrapper
- # that performs attribute lookup in 'c' when an attribute
- # cannot be found in 'a'.
-
- # Aquisition wrappers provide access to the wrapped objects
- # through the attributes 'aq_parent', 'aq_self', 'aq_base'.
- # In the example above, the expressions:
- self.assertIs(c.a.aq_parent, c)
-
- # and:
- self.assertIs(c.a.aq_self, a)
-
- # both evaluate to true, but the expression:
- self.assertIsNot(c.a, a)
-
- # evaluates to false, because the expression 'c.a' evaluates
- # to an acquisition wrapper around 'c' and 'a', not 'a' itself.
-
- # The attribute 'aq_base' is similar to 'aq_self'. Wrappers may be
- # nested and 'aq_self' may be a wrapped object. The 'aq_base'
- # attribute is the underlying object with all wrappers removed.
-
- # Acquisition Control
-
- # Two styles of acquisition are supported in the current
- # ExtensionClass release, implicit and explicit aquisition.
-
- # Implicit acquisition
-
- # Implicit acquisition is so named because it searches for
- # attributes from the environment automatically whenever an
- # attribute cannot be obtained directly from an object or
- # through inheritence.
-
- # An attribute may be implicitly acquired if it's name does
- # not begin with an underscore, '_'.
- # To support implicit acquisition, an object should inherit
- # from the mix-in class 'Implicit'.
-
- # Explicit Acquisition
-
- # When explicit acquisition is used, attributes are not
- # automatically obtained from the environment. Instead, the
- # method 'aq_aquire' must be used, as in:
- # print(c.a.aq_acquire('color'))
-
- # To support explicit acquisition, an object should inherit
- # from the mix-in class 'Explicit'.
-
- # Controlled Acquisition
-
- # A class (or instance) can provide attribute by attribute control
- # over acquisition. This is done by:
- # - subclassing from 'Explicit', and
- # - setting all attributes that should be acquired to the special
- # value: 'Acquisition.Acquired'. Setting an attribute to this
- # value also allows inherited attributes to be overridden with
- # acquired ones.
- # For example, in:
-
- class E(Explicit):
- id = 1
- secret = 2
- color = Acquisition.Acquired
- __roles__ = Acquisition.Acquired
-
- # The *only* attributes that are automatically acquired from
- # containing objects are 'color', and '__roles__'.
-
- c = C()
- c.foo = 'foo'
- c.e = E()
- self.assertEqual(c.e.color, 'red')
- with self.assertRaises(AttributeError):
- c.e.foo
-
- # Note also that the '__roles__' attribute is acquired even
- # though it's name begins with an underscore:
-
- c.__roles__ = 'Manager', 'Member'
- self.assertEqual(c.e.__roles__, ('Manager', 'Member'))
-
- # In fact, the special 'Acquisition.Acquired' value can be used
- # in 'Implicit' objects to implicitly acquire
- # selected objects that smell like private objects.
-
- class I(Implicit):
- __roles__ = Acquisition.Acquired
-
- c.x = C()
- with self.assertRaises(AttributeError):
- c.x.__roles__
-
- c.x = I()
- self.assertEqual(c.x.__roles__, ('Manager', 'Member'))
-
- # Filtered Acquisition
-
- # The acquisition method, 'aq_acquire', accepts two optional
- # arguments. The first of the additional arguments is a
- # "filtering" function that is used when considering whether to
- # acquire an object. The second of the additional arguments is an
- # object that is passed as extra data when calling the filtering
- # function and which defaults to 'None'.
-
- # The filter function is called with five arguments:
- # - The object that the 'aq_acquire' method was called on,
- # - The object where an object was found,
- # - The name of the object, as passed to 'aq_acquire',
- # - The object found, and
- # - The extra data passed to 'aq_acquire'.
-
- # If the filter returns a true object that the object found is
- # returned, otherwise, the acquisition search continues.
- # For example, in:
-
- class HandyForTesting(object):
- def __init__(self, name):
- self.name = name
-
- def __str__(self):
- return "%s(%s)" % (self.name, self.__class__.__name__)
-
- __repr__ = __str__
-
- class E(Explicit, HandyForTesting):
- pass
-
- class Nice(HandyForTesting):
- isNice = 1
-
- def __str__(self):
- return HandyForTesting.__str__(self) + ' and I am nice!'
-
- __repr__ = __str__
-
- a = E('a')
- a.b = E('b')
- a.b.c = E('c')
- a.p = Nice('spam')
- a.b.p = E('p')
-
- def find_nice(self, ancestor, name, object, extra):
- return hasattr(object, 'isNice') and object.isNice
-
- self.assertEqual(str(a.b.c.aq_acquire('p', find_nice)),
- 'spam(Nice) and I am nice!')
-
- # The filtered acquisition in the last line skips over the first
- # attribute it finds with the name 'p', because the attribute
- # doesn't satisfy the condition given in the filter.
-
- # Acquisition and methods
-
- # Python methods of objects that support acquisition can use
- # acquired attributes as in the 'report' method of the first example
- # above. When a Python method is called on an object that is
- # wrapped by an acquisition wrapper, the wrapper is passed to the
- # method as the first argument. This rule also applies to
- # user-defined method types and to C methods defined in pure mix-in
- # classes.
-
- # Unfortunately, C methods defined in extension base classes that
- # define their own data structures, cannot use aquired attributes at
- # this time. This is because wrapper objects do not conform to the
- # data structures expected by these methods.
-
- # Acquiring Acquiring objects
-
- # Consider the following example:
- class C(Implicit):
- def __init__(self, name):
- self.name = name
-
- def __str__(self):
- return "%s(%s)" % (self.name, self.__class__.__name__)
-
- __repr__ = __str__
-
- a = C("a")
- a.b = C("b")
- a.b.pref = "spam"
- a.b.c = C("c")
- a.b.c.color = "red"
- a.b.c.pref = "eggs"
- a.x = C("x")
- o = a.b.c.x
-
- # The expression 'o.color' might be expected to return '"red"'. In
- # earlier versions of ExtensionClass, however, this expression
- # failed. Acquired acquiring objects did not acquire from the
- # environment they were accessed in, because objects were only
- # wrapped when they were first found, and were not rewrapped as they
- # were passed down the acquisition tree.
-
- # In the current release of ExtensionClass, the expression "o.color"
- # does indeed return '"red"'.
- self.assertEqual(o.color, 'red')
-
- # When searching for an attribute in 'o', objects are searched in
- # the order 'x', 'a', 'b', 'c'. So, for example, the expression,
- # 'o.pref' returns '"spam"', not '"eggs"':
- self.assertEqual(o.pref, 'spam')
-
- # In earlier releases of ExtensionClass, the attempt to get the
- # 'pref' attribute from 'o' would have failed.
-
- # If desired, the current rules for looking up attributes in complex
- # expressions can best be understood through repeated application of
- # the '__of__' method:
- # 'a.x' -- 'x.__of__(a)'
- # 'a.b' -- 'b.__of__(a)'
- # 'a.b.x' -- 'x.__of__(a).__of__(b.__of__(a))'
- # 'a.b.c' -- 'c.__of__(b.__of__(a))'
- # 'a.b.c.x' --
- # 'x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))'
-
- # and by keeping in mind that attribute lookup in a wrapper
- # is done by trying to lookup the attribute in the wrapped object
- # first and then in the parent object. In the expressions above
- # involving the '__of__' method, lookup proceeds from left to right.
-
- # Note that heuristics are used to avoid most of the repeated
- # lookups. For example, in the expression: 'a.b.c.x.foo', the object
- # 'a' is searched no more than once, even though it is wrapped three
- # times.
-
-
- def test_unwrapped():
- """
- >>> c = I('unwrapped')
- >>> show(c)
- unwrapped
-
- >>> try:
- ... c.aq_parent
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> try:
- ... c.__parent__
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> aq_acquire(c, 'id')
- 'unwrapped'
-
- >>> try:
- ... aq_acquire(c, 'x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> aq_acquire(c, 'id',
- ... lambda searched, parent, name, ob, extra: extra)
- Traceback (most recent call last):
- ...
- AttributeError: id
-
- >>> aq_acquire(c, 'id',
- ... lambda searched, parent, name, ob, extra: extra,
- ... 1)
- 'unwrapped'
-
- >>> aq_base(c) is c
- 1
-
- >>> aq_chain(c)
- [unwrapped]
-
- >>> aq_chain(c, 1)
- [unwrapped]
-
- >>> aq_get(c, 'id')
- 'unwrapped'
-
- >>> try:
- ... aq_get(c, 'x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> aq_get(c, 'x', 'foo')
- 'foo'
- >>> aq_get(c, 'x', 'foo', 1)
- 'foo'
-
- >>> aq_inner(c) is c
- 1
-
- >>> aq_parent(c)
-
- >>> aq_self(c) is c
- 1
-
- """
-
-
- def test_simple():
- """
- >>> a = I('a')
- >>> a.y = 42
- >>> a.b = I('b')
- >>> a.b.c = I('c')
- >>> show(a.b.c)
- c
- |
- b
- |
- a
-
- >>> show(a.b.c.aq_parent)
- b
- |
- a
-
- >>> show(a.b.c.aq_self)
- c
-
- >>> show(a.b.c.aq_base)
- c
-
- >>> show(a.b.c.aq_inner)
- c
- |
- b
- |
- a
-
- >>> a.b.c.y
- 42
-
- >>> a.b.c.aq_chain
- [c, b, a]
-
- >>> a.b.c.aq_inContextOf(a)
- 1
- >>> a.b.c.aq_inContextOf(a.b)
- 1
- >>> a.b.c.aq_inContextOf(a.b.c)
- 1
-
- >>> aq_inContextOf(a.b.c, a)
- 1
- >>> aq_inContextOf(a.b.c, a.b)
- 1
- >>> aq_inContextOf(a.b.c, a.b.c)
- 1
-
-
- >>> a.b.c.aq_acquire('y')
- 42
-
- >>> a.b.c.aq_acquire('id')
- 'c'
-
- >>> try:
- ... a.b.c.aq_acquire('x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> a.b.c.aq_acquire('id',
- ... lambda searched, parent, name, ob, extra: extra)
- Traceback (most recent call last):
- ...
- AttributeError: id
-
- >>> aq_acquire(a.b.c, 'id',
- ... lambda searched, parent, name, ob, extra: extra,
- ... 1)
- 'c'
-
- >>> aq_acquire(a.b.c, 'id')
- 'c'
-
- >>> try:
- ... aq_acquire(a.b.c, 'x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> aq_acquire(a.b.c, 'y')
- 42
-
- >>> aq_acquire(a.b.c, 'id',
- ... lambda searched, parent, name, ob, extra: extra)
- Traceback (most recent call last):
- ...
- AttributeError: id
-
- >>> aq_acquire(a.b.c, 'id',
- ... lambda searched, parent, name, ob, extra: extra,
- ... 1)
- 'c'
-
- >>> show(aq_base(a.b.c))
- c
-
- >>> aq_chain(a.b.c)
- [c, b, a]
-
- >>> aq_chain(a.b.c, 1)
- [c, b, a]
-
- >>> aq_get(a.b.c, 'id')
- 'c'
-
- >>> try:
- ... aq_get(a.b.c, 'x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> aq_get(a.b.c, 'x', 'foo')
- 'foo'
- >>> aq_get(a.b.c, 'x', 'foo', 1)
- 'foo'
-
- >>> show(aq_inner(a.b.c))
- c
- |
- b
- |
- a
-
- >>> show(aq_parent(a.b.c))
- b
- |
- a
-
- >>> show(aq_self(a.b.c))
- c
-
- A wrapper's __parent__ attribute (which is equivalent to its
- aq_parent attribute) points to the Acquisition parent.
-
- >>> a.b.c.__parent__ == a.b.c.aq_parent
- True
- >>> a.b.c.__parent__ == a.b
- True
- """
-
-
- def test_muliple():
- r"""
- >>> a = I('a')
- >>> a.color = 'red'
- >>> a.a1 = I('a1')
- >>> a.a1.color = 'green'
- >>> a.a1.a11 = I('a11')
- >>> a.a2 = I('a2')
- >>> a.a2.a21 = I('a21')
- >>> show(a.a1.a11.a2.a21)
- a21
- |
- (a2)
- | \
- | (a2)
- | | \
- | | a2
- | | |
- | | a
- | |
- | a1
- | |
- | a
- |
- a11
- |
- a1
- |
- a
-
- >>> a.a1.a11.a2.a21.color
- 'red'
-
- >>> show(a.a1.a11.a2.a21.aq_parent)
- (a2)
- | \
- | (a2)
- | | \
- | | a2
- | | |
- | | a
- | |
- | a1
- | |
- | a
- |
- a11
- |
- a1
- |
- a
-
- >>> show(a.a1.a11.a2.a21.aq_parent.aq_parent)
- a11
- |
- a1
- |
- a
-
- >>> show(a.a1.a11.a2.a21.aq_self)
- a21
-
- >>> show(a.a1.a11.a2.a21.aq_parent.aq_self)
- (a2)
- | \
- | a2
- | |
- | a
- |
- a1
- |
- a
-
- >>> show(a.a1.a11.a2.a21.aq_base)
- a21
-
- >>> show(a.a1.a11.a2.a21.aq_inner)
- a21
- |
- (a2)
- | \
- | (a2)
- | | \
- | | a2
- | | |
- | | a
- | |
- | a1
- | |
- | a
- |
- a11
- |
- a1
- |
- a
-
- >>> show(a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner)
- a2
- |
- a
-
- >>> show(a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner.aq_parent)
- a
-
- >>> a.a1.a11.a2.a21.aq_chain
- [a21, a2, a11, a1, a]
-
- >>> a.a1.a11.a2.a21.aq_inContextOf(a)
- 1
-
- >>> a.a1.a11.a2.a21.aq_inContextOf(a.a2)
- 1
-
- >>> a.a1.a11.a2.a21.aq_inContextOf(a.a1)
- 0
-
- >>> a.a1.a11.a2.a21.aq_acquire('color')
- 'red'
- >>> a.a1.a11.a2.a21.aq_acquire('id')
- 'a21'
-
- >>> a.a1.a11.a2.a21.aq_acquire('color',
- ... lambda ob, parent, name, v, extra: extra)
- Traceback (most recent call last):
- ...
- AttributeError: color
-
- >>> a.a1.a11.a2.a21.aq_acquire('color',
- ... lambda ob, parent, name, v, extra: extra, 1)
- 'red'
-
- >>> a.a1.y = 42
- >>> a.a1.a11.a2.a21.aq_acquire('y')
- 42
-
- >>> try:
- ... a.a1.a11.a2.a21.aq_acquire('y', containment=1)
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- Much of the same, but with methods:
-
- >>> show(aq_parent(a.a1.a11.a2.a21))
- (a2)
- | \
- | (a2)
- | | \
- | | a2
- | | |
- | | a
- | |
- | a1
- | |
- | a
- |
- a11
- |
- a1
- |
- a
-
- >>> show(aq_parent(a.a1.a11.a2.a21.aq_parent))
- a11
- |
- a1
- |
- a
-
- >>> show(aq_self(a.a1.a11.a2.a21))
- a21
-
- >>> show(aq_self(a.a1.a11.a2.a21.aq_parent))
- (a2)
- | \
- | a2
- | |
- | a
- |
- a1
- |
- a
-
- >>> show(aq_base(a.a1.a11.a2.a21))
- a21
-
- >>> show(aq_inner(a.a1.a11.a2.a21))
- a21
- |
- (a2)
- | \
- | (a2)
- | | \
- | | a2
- | | |
- | | a
- | |
- | a1
- | |
- | a
- |
- a11
- |
- a1
- |
- a
-
- >>> show(aq_inner(a.a1.a11.a2.a21.aq_inner.aq_parent))
- a2
- |
- a
-
- >>> show(aq_parent(
- ... a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner))
- a
-
- >>> aq_chain(a.a1.a11.a2.a21)
- [a21, a2, a11, a1, a]
-
- >>> aq_chain(a.a1.a11.a2.a21, 1)
- [a21, a2, a]
-
- >>> aq_acquire(a.a1.a11.a2.a21, 'color')
- 'red'
- >>> aq_acquire(a.a1.a11.a2.a21, 'id')
- 'a21'
-
- >>> aq_acquire(a.a1.a11.a2.a21, 'color',
- ... lambda ob, parent, name, v, extra: extra)
- Traceback (most recent call last):
- ...
- AttributeError: color
-
- >>> aq_acquire(a.a1.a11.a2.a21, 'color',
- ... lambda ob, parent, name, v, extra: extra, 1)
- 'red'
-
- >>> a.a1.y = 42
- >>> aq_acquire(a.a1.a11.a2.a21, 'y')
- 42
-
- >>> try:
- ... aq_acquire(a.a1.a11.a2.a21, 'y', containment=1)
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
- """
-
-
- def test_pinball():
- r"""
- >>> a = I('a')
- >>> a.a1 = I('a1')
- >>> a.a1.a11 = I('a11')
- >>> a.a1.a12 = I('a12')
- >>> a.a2 = I('a2')
- >>> a.a2.a21 = I('a21')
- >>> a.a2.a22 = I('a22')
- >>> show(a.a1.a11.a1.a12.a2.a21.a2.a22)
- a22
- |
- (a2)
- | \
- | (a2)
- | | \
- | | a2
- | | |
- | | a
- | |
- | (a2)
- | | \
- | | (a2)
- | | | \
- | | | a2
- | | | |
- | | | a
- | | |
- | | (a1)
- | | | \
- | | | (a1)
- | | | | \
- | | | | a1
- | | | | |
- | | | | a
- | | | |
- | | | a1
- | | | |
- | | | a
- | | |
- | | a11
- | | |
- | | a1
- | | |
- | | a
- | |
- | a12
- | |
- | (a1)
- | | \
- | | (a1)
- | | | \
- | | | a1
- | | | |
- | | | a
- | | |
- | | a1
- | | |
- | | a
- | |
- | a11
- | |
- | a1
- | |
- | a
- |
- a21
- |
- (a2)
- | \
- | (a2)
- | | \
- | | a2
- | | |
- | | a
- | |
- | (a1)
- | | \
- | | (a1)
- | | | \
- | | | a1
- | | | |
- | | | a
- | | |
- | | a1
- | | |
- | | a
- | |
- | a11
- | |
- | a1
- | |
- | a
- |
- a12
- |
- (a1)
- | \
- | (a1)
- | | \
- | | a1
- | | |
- | | a
- | |
- | a1
- | |
- | a
- |
- a11
- |
- a1
- |
- a
-
- """
-
-
- def test_explicit():
- """
- >>> a = E('a')
- >>> a.y = 42
- >>> a.b = E('b')
- >>> a.b.c = E('c')
- >>> show(a.b.c)
- c
- |
- b
- |
- a
-
- >>> show(a.b.c.aq_parent)
- b
- |
- a
-
- >>> show(a.b.c.aq_self)
- c
-
- >>> show(a.b.c.aq_base)
- c
-
- >>> show(a.b.c.aq_inner)
- c
- |
- b
- |
- a
-
- >>> a.b.c.y
- Traceback (most recent call last):
- ...
- AttributeError: y
-
- >>> a.b.c.aq_chain
- [c, b, a]
-
- >>> a.b.c.aq_inContextOf(a)
- 1
- >>> a.b.c.aq_inContextOf(a.b)
- 1
- >>> a.b.c.aq_inContextOf(a.b.c)
- 1
-
-
- >>> a.b.c.aq_acquire('y')
- 42
-
- >>> a.b.c.aq_acquire('id')
- 'c'
-
- >>> try:
- ... a.b.c.aq_acquire('x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> a.b.c.aq_acquire('id',
- ... lambda searched, parent, name, ob, extra: extra)
- Traceback (most recent call last):
- ...
- AttributeError: id
-
- >>> aq_acquire(a.b.c, 'id',
- ... lambda searched, parent, name, ob, extra: extra,
- ... 1)
- 'c'
-
- >>> aq_acquire(a.b.c, 'id')
- 'c'
-
- >>> try:
- ... aq_acquire(a.b.c, 'x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> aq_acquire(a.b.c, 'y')
- 42
-
- >>> aq_acquire(a.b.c, 'id',
- ... lambda searched, parent, name, ob, extra: extra)
- Traceback (most recent call last):
- ...
- AttributeError: id
-
- >>> aq_acquire(a.b.c, 'id',
- ... lambda searched, parent, name, ob, extra: extra,
- ... 1)
- 'c'
-
- >>> show(aq_base(a.b.c))
- c
-
- >>> aq_chain(a.b.c)
- [c, b, a]
-
- >>> aq_chain(a.b.c, 1)
- [c, b, a]
-
- >>> aq_get(a.b.c, 'id')
- 'c'
-
- >>> try:
- ... aq_get(a.b.c, 'x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> aq_get(a.b.c, 'y')
- 42
-
- >>> aq_get(a.b.c, 'x', 'foo')
- 'foo'
- >>> aq_get(a.b.c, 'x', 'foo', 1)
- 'foo'
-
- >>> show(aq_inner(a.b.c))
- c
- |
- b
- |
- a
-
- >>> show(aq_parent(a.b.c))
- b
- |
- a
-
- >>> show(aq_self(a.b.c))
- c
-
- """
-
-
- def test_mixed_explicit_and_explicit():
- """
- >>> a = I('a')
- >>> a.y = 42
- >>> a.b = E('b')
- >>> a.b.z = 3
- >>> a.b.c = I('c')
- >>> show(a.b.c)
- c
- |
- b
- |
- a
-
- >>> show(a.b.c.aq_parent)
- b
- |
- a
-
- >>> show(a.b.c.aq_self)
- c
-
- >>> show(a.b.c.aq_base)
- c
-
- >>> show(a.b.c.aq_inner)
- c
- |
- b
- |
- a
-
- >>> a.b.c.y
- 42
-
- >>> a.b.c.z
- 3
-
- >>> a.b.c.aq_chain
- [c, b, a]
-
- >>> a.b.c.aq_inContextOf(a)
- 1
- >>> a.b.c.aq_inContextOf(a.b)
- 1
- >>> a.b.c.aq_inContextOf(a.b.c)
- 1
-
- >>> a.b.c.aq_acquire('y')
- 42
-
- >>> a.b.c.aq_acquire('z')
- 3
-
- >>> a.b.c.aq_acquire('id')
- 'c'
-
- >>> try:
- ... a.b.c.aq_acquire('x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> a.b.c.aq_acquire('id',
- ... lambda searched, parent, name, ob, extra: extra)
- Traceback (most recent call last):
- ...
- AttributeError: id
-
- >>> aq_acquire(a.b.c, 'id',
- ... lambda searched, parent, name, ob, extra: extra,
- ... 1)
- 'c'
-
- >>> aq_acquire(a.b.c, 'id')
- 'c'
-
- >>> try:
- ... aq_acquire(a.b.c, 'x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> aq_acquire(a.b.c, 'y')
- 42
-
- >>> aq_acquire(a.b.c, 'id',
- ... lambda searched, parent, name, ob, extra: extra)
- Traceback (most recent call last):
- ...
- AttributeError: id
-
- >>> aq_acquire(a.b.c, 'id',
- ... lambda searched, parent, name, ob, extra: extra,
- ... 1)
- 'c'
-
- >>> show(aq_base(a.b.c))
- c
-
- >>> aq_chain(a.b.c)
- [c, b, a]
-
- >>> aq_chain(a.b.c, 1)
- [c, b, a]
-
- >>> aq_get(a.b.c, 'id')
- 'c'
-
- >>> try:
- ... aq_get(a.b.c, 'x')
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- >>> aq_get(a.b.c, 'y')
- 42
-
- >>> aq_get(a.b.c, 'x', 'foo')
- 'foo'
- >>> aq_get(a.b.c, 'x', 'foo', 1)
- 'foo'
-
- >>> show(aq_inner(a.b.c))
- c
- |
- b
- |
- a
-
- >>> show(aq_parent(a.b.c))
- b
- |
- a
-
- >>> show(aq_self(a.b.c))
- c
-
- """
-
-
- class TestAqAlgorithm(unittest.TestCase):
-
- def test_AqAlg(self):
- A = I('A')
- B = I('B')
- A.B = B
- A.B.color = 'red'
- C = I('C')
- A.C = C
- D = I('D')
- A.C.D = D
-
- self.assertEqual(aq_chain(A), [A])
- self.assertEqual(aq_chain(A, 1), [A])
- self.assertEqual(list(map(aq_base, aq_chain(A, 1))), [A])
-
- self.assertEqual(str(aq_chain(A.C)), str([C, A]))
- self.assertEqual(aq_chain(A.C, 1), [C, A])
- self.assertEqual(list(map(aq_base, aq_chain(A.C, 1))), [C, A])
-
- self.assertEqual(str(aq_chain(A.C.D)), str([D, C, A]))
- self.assertEqual(aq_chain(A.C.D, 1), [D, C, A])
- self.assertEqual(list(map(aq_base, aq_chain(A.C.D, 1))), [D, C, A])
-
- self.assertEqual(str(aq_chain(A.B.C)), str([C, B, A]))
- self.assertEqual(aq_chain(A.B.C, 1), [C, A])
- self.assertEqual(list(map(aq_base, aq_chain(A.B.C, 1))), [C, A])
-
- self.assertEqual(str(aq_chain(A.B.C.D)), str([D, C, B, A]))
- self.assertEqual(aq_chain(A.B.C.D, 1), [D, C, A])
- self.assertEqual(list(map(aq_base, aq_chain(A.B.C.D, 1))), [D, C, A])
-
- self.assertEqual(A.B.C.D.color, 'red')
- self.assertEqual(aq_get(A.B.C.D, "color", None), 'red')
- self.assertIsNone(aq_get(A.B.C.D, "color", None, 1))
-
-
- class TestExplicitAcquisition(unittest.TestCase):
-
- def test_explicit_acquisition(self):
- from ExtensionClass import Base
-
- class B(Base):
- color = 'red'
-
- class A(Explicit):
- def hi(self):
- return self.acquire('color')
-
- b = B()
- b.a = A()
- self.assertEqual(b.a.hi(), 'red')
-
- b.a.color = 'green'
- self.assertEqual(b.a.hi(), 'green')
-
- with self.assertRaises(AttributeError):
- A().hi()
-
-
- class TestCreatingWrappers(unittest.TestCase):
-
- def test_creating_wrappers_directly(self):
- from ExtensionClass import Base
- from Acquisition import ImplicitAcquisitionWrapper
-
- class B(Base):
- pass
-
- a = B()
- a.color = 'red'
- a.b = B()
- w = ImplicitAcquisitionWrapper(a.b, a)
- self.assertEqual(w.color, 'red')
-
- with self.assertRaises(TypeError):
- ImplicitAcquisitionWrapper(a.b)
-
- # We can reassign aq_parent / __parent__ on a wrapper:
-
- x = B()
- x.color = 'green'
- w.aq_parent = x
- self.assertEqual(w.color, 'green')
-
- y = B()
- y.color = 'blue'
- w.__parent__ = y
- self.assertEqual(w.color, 'blue')
-
- # Note that messing with the wrapper won't in any way affect the
- # wrapped object:
-
- with self.assertRaises(AttributeError):
- aq_base(w).__parent__
-
- with self.assertRaises(TypeError):
- ImplicitAcquisitionWrapper()
-
- with self.assertRaises(TypeError):
- ImplicitAcquisitionWrapper(obj=1)
-
-
- class TestPickle(unittest.TestCase):
-
- def test_cant_pickle_acquisition_wrappers_classic(self):
- import pickle
-
- class X(object):
- def __getstate__(self):
- return 1
-
- # We shouldn't be able to pickle wrappers:
-
- from Acquisition import ImplicitAcquisitionWrapper
- w = ImplicitAcquisitionWrapper(X(), X())
- with self.assertRaises(TypeError):
- pickle.dumps(w)
-
- # But that's not enough. We need to defeat persistence as well. :)
- # This is tricky. We want to generate the error in __getstate__, not
- # in the attr access, as attribute errors are too-often hidden:
-
- getstate = w.__getstate__
- with self.assertRaises(TypeError):
- getstate()
-
- # We shouldn't be able to pickle wrappers:
-
- from Acquisition import ExplicitAcquisitionWrapper
- w = ExplicitAcquisitionWrapper(X(), X())
- with self.assertRaises(TypeError):
- pickle.dumps(w)
-
- # But that's not enough. We need to defeat persistence as well. :)
- # This is tricky. We want to generate the error in __getstate__, not
- # in the attr access, as attribute errors are too-often hidden:
-
- getstate = w.__getstate__
- with self.assertRaises(TypeError):
- getstate()
-
- def test_cant_pickle_acquisition_wrappers_newstyle(self):
- import pickle
-
- class X(object):
- def __getstate__(self):
- return 1
-
- # We shouldn't be able to pickle wrappers:
-
- from Acquisition import ImplicitAcquisitionWrapper
- w = ImplicitAcquisitionWrapper(X(), X())
- with self.assertRaises(TypeError):
- pickle.dumps(w)
-
- # But that's not enough. We need to defeat persistence as well. :)
- # This is tricky. We want to generate the error in __getstate__, not
- # in the attr access, as attribute errors are too-often hidden:
-
- getstate = w.__getstate__
- with self.assertRaises(TypeError):
- getstate()
-
- # We shouldn't be able to pickle wrappers:
-
- from Acquisition import ExplicitAcquisitionWrapper
- w = ExplicitAcquisitionWrapper(X(), X())
- with self.assertRaises(TypeError):
- pickle.dumps(w)
-
- # But that's not enough. We need to defeat persistence as well. :)
- # This is tricky. We want to generate the error in __getstate__, not
- # in the attr access, as attribute errors are too-often hidden:
-
- getstate = w.__getstate__
- with self.assertRaises(TypeError):
- getstate()
-
- def test_cant_persist_acquisition_wrappers_classic(self):
- try:
- import cPickle
- except ImportError:
- import pickle as cPickle
-
- class X(object):
- _p_oid = '1234'
-
- def __getstate__(self):
- return 1
-
- # We shouldn't be able to pickle wrappers:
-
- from Acquisition import ImplicitAcquisitionWrapper
- w = ImplicitAcquisitionWrapper(X(), X())
- with self.assertRaises(TypeError):
- cPickle.dumps(w)
-
- # Check for pickle protocol one:
-
- with self.assertRaises(TypeError):
- cPickle.dumps(w, 1)
-
- # Check custom pickler:
-
- from io import BytesIO
- file = BytesIO()
- pickler = cPickle.Pickler(file, 1)
-
- with self.assertRaises(TypeError):
- pickler.dump(w)
-
- # Check custom pickler with a persistent_id method matching
- # the semantics in ZODB.serialize.ObjectWriter.persistent_id:
-
- file = BytesIO()
- pickler = cPickle.Pickler(file, 1)
-
- def persistent_id(obj):
- if not hasattr(obj, '_p_oid'):
- return None
- klass = type(obj)
- oid = obj._p_oid
- if hasattr(klass, '__getnewargs__'):
- # Coverage, make sure it can be called
- assert klass.__getnewargs__(obj) == ()
- return oid
- return 'class_and_oid', klass
-
- try:
- pickler.inst_persistent_id = persistent_id
- except AttributeError:
- pass
- pickler.persistent_id = persistent_id # PyPy and Py3k
- pickler.dump(w)
- state = file.getvalue()
- self.assertTrue(b'1234' in state)
- self.assertFalse(b'class_and_oid' in state)
-
- def test_cant_persist_acquisition_wrappers_newstyle(self):
- try:
- import cPickle
- except ImportError:
- import pickle as cPickle
-
- class X(object):
- _p_oid = '1234'
-
- def __getstate__(self):
- return 1
-
- # We shouldn't be able to pickle wrappers:
-
- from Acquisition import ImplicitAcquisitionWrapper
- w = ImplicitAcquisitionWrapper(X(), X())
- with self.assertRaises(TypeError):
- cPickle.dumps(w)
-
- # Check for pickle protocol one:
-
- with self.assertRaises(TypeError):
- cPickle.dumps(w, 1)
-
- # Check custom pickler:
-
- from io import BytesIO
- file = BytesIO()
- pickler = cPickle.Pickler(file, 1)
-
- with self.assertRaises(TypeError):
- pickler.dump(w)
-
- # Check custom pickler with a persistent_id method matching
- # the semantics in ZODB.serialize.ObjectWriter.persistent_id:
-
- file = BytesIO()
- pickler = cPickle.Pickler(file, 1)
-
- def persistent_id(obj):
- if not hasattr(obj, '_p_oid'):
- return None
- klass = type(obj)
- oid = obj._p_oid
- if hasattr(klass, '__getnewargs__'):
- return oid
- return 'class_and_oid', klass
-
- try:
- pickler.inst_persistent_id = persistent_id
- except AttributeError:
- pass
-
- pickler.persistent_id = persistent_id # PyPy and Py3k
- pickler.dump(w)
- state = file.getvalue()
- self.assertTrue(b'1234' in state)
- self.assertFalse(b'class_and_oid' in state)
-
-
- class TestInterfaces(unittest.TestCase):
-
- def test_interfaces(self):
- from zope.interface.verify import verifyClass
-
- # Explicit and Implicit implement IAcquirer:
- from Acquisition.interfaces import IAcquirer
- self.assertTrue(verifyClass(IAcquirer, Explicit))
- self.assertTrue(verifyClass(IAcquirer, Implicit))
-
- # ExplicitAcquisitionWrapper and ImplicitAcquisitionWrapper implement
- # IAcquisitionWrapper:
-
- from Acquisition import ExplicitAcquisitionWrapper
- from Acquisition import ImplicitAcquisitionWrapper
- from Acquisition.interfaces import IAcquisitionWrapper
- self.assertTrue(
- verifyClass(IAcquisitionWrapper, ExplicitAcquisitionWrapper))
- self.assertTrue(
- verifyClass(IAcquisitionWrapper, ImplicitAcquisitionWrapper))
-
-
- class TestMixin(unittest.TestCase):
-
- @unittest.skipUnless(MIXIN_POST_CLASS_DEFINITION,
- 'Changing __bases__ is not supported.')
- def test_mixin_post_class_definition(self):
- # Assigning to __bases__ is difficult under some versions of python.
- # PyPy usually lets it, but CPython (3 esp) may not.
- # In this example, you get:
- # "TypeError: __bases__ assignment:
- # 'Base' deallocator differs from 'object'"
- # I don't know what the workaround is; the old one of using a dummy
- # superclass no longer works. See http://bugs.python.org/issue672115
-
- # Mixing in Base after class definition doesn't break anything,
- # but also doesn't result in any wrappers.
- from ExtensionClass import Base
-
- class Plain(object):
- pass
-
- self.assertEqual(Plain.__bases__, (object, ))
- Plain.__bases__ = (Base, )
- self.assertIsInstance(Plain(), Base)
-
- # Even after mixing in that base, when we request such an object
- # from an implicit acquiring base, it doesn't come out wrapped:
- class I(Implicit):
- pass
-
- root = I()
- root.a = I()
- root.a.b = Plain()
- self.assertIsInstance(root.a.b, Plain)
-
- # This is because after the mixin, even though Plain is-a Base,
- # it's still not an Explicit/Implicit acquirer and provides
- # neither the `__of__` nor `__get__` methods necessary.
- # `__get__` is added as a consequence of
- # `__of__` at class creation time):
- self.assertFalse(hasattr(Plain, '__get__'))
- self.assertFalse(hasattr(Plain, '__of__'))
-
- def test_mixin_base(self):
- # We can mix-in Base as part of multiple inheritance.
- from ExtensionClass import Base
-
- class MyBase(object):
- pass
-
- class MixedIn(Base, MyBase):
- pass
-
- self.assertEqual(MixedIn.__bases__, (Base, MyBase))
- self.assertIsInstance(MixedIn(), Base)
-
- # Because it's not an acquiring object and doesn't provide `__of__`
- # or `__get__`, when accessed from implicit contexts it doesn't come
- # out wrapped:
- class I(Implicit):
- pass
-
- root = I()
- root.a = I()
- root.a.b = MixedIn()
- self.assertIsInstance(root.a.b, MixedIn)
-
- # This is because after the mixin, even though Plain is-a Base,
- # it doesn't provide the `__of__` method used for wrapping, and so
- # the class definition code that would add the `__get__` method also
- # doesn't run:
- self.assertFalse(hasattr(MixedIn, '__of__'))
- self.assertFalse(hasattr(MixedIn, '__get__'))
-
-
- class TestGC(unittest.TestCase):
- # Tests both `__del__` being called and GC collection.
- # Note that PyPy always reports 0 collected objects even
- # though we can see its finalizers run.
-
- # Not PyPy
- SUPPORTS_GC_THRESHOLD = hasattr(gc, 'get_threshold')
-
- if SUPPORTS_GC_THRESHOLD:
- def setUp(self):
- self.thresholds = gc.get_threshold()
- gc.set_threshold(0)
-
- def tearDown(self):
- gc.set_threshold(*self.thresholds)
-
- def test_Basic_gc(self):
- # Test to make sure that EC instances participate in GC.
- from ExtensionClass import Base
-
- for B in I, E:
- counter = [0]
-
- class C1(B):
- pass
-
- class C2(Base):
- def __del__(self, counter=counter):
- counter[0] += 1
-
- a = C1('a')
- a.b = C1('a.b')
- a.b.a = a
- a.b.c = C2()
- gc.collect()
- del a
- removed = gc.collect()
- if self.SUPPORTS_GC_THRESHOLD:
- self.assertTrue(removed > 0)
- self.assertEqual(counter[0], 1)
-
- def test_Wrapper_gc(self):
- # Test to make sure that EC instances participate in GC.
- for B in I, E:
- counter = [0]
-
- class C(object):
- def __del__(self, counter=counter):
- counter[0] += 1
-
- a = B('a')
- a.b = B('b')
- a.a_b = a.b # circular reference through wrapper
- a.b.c = C()
- gc.collect()
- del a
- removed = gc.collect()
- if self.SUPPORTS_GC_THRESHOLD:
- self.assertTrue(removed > 0)
- self.assertEqual(counter[0], 1)
-
-
- def test_container_proxying():
- """Make sure that recent python container-related slots are proxied.
-
- >>> import sys
- >>> class Impl(Implicit):
- ... pass
-
- >>> class C(Implicit):
- ... def __getitem__(self, key):
- ... if isinstance(key, slice):
- ... print('slicing...')
- ... return (key.start,key.stop)
- ... print('getitem', key)
- ... if key == 4:
- ... raise IndexError
- ... return key
- ... def __contains__(self, key):
- ... print('contains', repr(key))
- ... return key == 5
- ... def __iter__(self):
- ... print('iterating...')
- ... return iter((42,))
- ... def __getslice__(self, start, end):
- ... print('slicing...')
- ... return (start, end)
-
- The naked class behaves like this:
-
- >>> c = C()
- >>> 3 in c
- contains 3
- False
- >>> 5 in c
- contains 5
- True
- >>> list(c)
- iterating...
- [42]
- >>> c[5:10]
- slicing...
- (5, 10)
- >>> c[5:] == (5, sys.maxsize if PY2 else None)
- slicing...
- True
-
- Let's put c in the context of i:
-
- >>> i = Impl()
- >>> i.c = c
-
- Now check that __contains__ is properly used:
-
- >>> 3 in i.c # c.__of__(i)
- contains 3
- False
- >>> 5 in i.c
- contains 5
- True
- >>> list(i.c)
- iterating...
- [42]
- >>> i.c[5:10]
- slicing...
- (5, 10)
- >>> i.c[5:] == (5, sys.maxsize if PY2 else None)
- slicing...
- True
-
- Let's let's test the same again with an explicit wrapper:
-
- >>> class Impl(Explicit):
- ... pass
-
- >>> class C(Explicit):
- ... def __getitem__(self, key):
- ... if isinstance(key, slice):
- ... print('slicing...')
- ... return (key.start,key.stop)
- ... print('getitem', key)
- ... if key == 4:
- ... raise IndexError
- ... return key
- ... def __contains__(self, key):
- ... print('contains', repr(key))
- ... return key == 5
- ... def __iter__(self):
- ... print('iterating...')
- ... return iter((42,))
- ... def __getslice__(self, start, end):
- ... print('slicing...')
- ... return (start, end)
-
- The naked class behaves like this:
-
- >>> c = C()
- >>> 3 in c
- contains 3
- False
- >>> 5 in c
- contains 5
- True
- >>> list(c)
- iterating...
- [42]
- >>> c[5:10]
- slicing...
- (5, 10)
- >>> c[5:] == (5, sys.maxsize if PY2 else None)
- slicing...
- True
-
- Let's put c in the context of i:
-
- >>> i = Impl()
- >>> i.c = c
-
- Now check that __contains__ is properly used:
-
- >>> 3 in i.c # c.__of__(i)
- contains 3
- False
- >>> 5 in i.c
- contains 5
- True
- >>> list(i.c)
- iterating...
- [42]
- >>> i.c[5:10]
- slicing...
- (5, 10)
- >>> i.c[5:] == (5, sys.maxsize if PY2 else None)
- slicing...
- True
-
- Next let's check that the wrapper's __iter__ proxy falls back
- to using the object's __getitem__ if it has no __iter__. See
- https://bugs.launchpad.net/zope2/+bug/360761 .
-
- >>> class C(Implicit):
- ... l=[1,2,3]
- ... def __getitem__(self, i):
- ... return self.l[i]
-
- >>> c1 = C()
- >>> type(iter(c1)) #doctest: +ELLIPSIS
- <... '...iterator'>
- >>> list(c1)
- [1, 2, 3]
-
- >>> c2 = C().__of__(c1)
- >>> type(iter(c2)) #doctest: +ELLIPSIS
- <... '...iterator'>
- >>> list(c2)
- [1, 2, 3]
-
- The __iter__proxy should also pass the wrapped object as self to
- the __iter__ of objects defining __iter__:
-
- >>> class C(Implicit):
- ... def __iter__(self):
- ... print('iterating...')
- ... for i in range(5):
- ... yield i, self.aq_parent.name
- >>> c = C()
- >>> i = Impl()
- >>> i.c = c
- >>> i.name = 'i'
- >>> list(i.c)
- iterating...
- [(0, 'i'), (1, 'i'), (2, 'i'), (3, 'i'), (4, 'i')]
-
- And it should pass the wrapped object as self to
- the __getitem__ of objects without an __iter__:
-
- >>> class C(Implicit):
- ... def __getitem__(self, i):
- ... return self.aq_parent.l[i]
- >>> c = C()
- >>> i = Impl()
- >>> i.c = c
- >>> i.l = range(5)
- >>> list(i.c)
- [0, 1, 2, 3, 4]
-
- Finally let's make sure errors are still correctly raised after having
- to use a modified version of `PyObject_GetIter` for iterator support:
-
- >>> class C(Implicit):
- ... pass
- >>> c = C()
- >>> i = Impl()
- >>> i.c = c
- >>> list(i.c) #doctest: +ELLIPSIS
- Traceback (most recent call last):
- ...
- TypeError: ...iter...
-
- >>> class C(Implicit):
- ... def __iter__(self):
- ... return [42]
- >>> c = C()
- >>> i = Impl()
- >>> i.c = c
- >>> list(i.c) #doctest: +ELLIPSIS
- Traceback (most recent call last):
- ...
- TypeError: iter() returned non-iterator...
-
- """
-
-
- class TestAqParentParentInteraction(unittest.TestCase):
-
- def test___parent__no_wrappers(self):
- # Acquisition also works with objects that aren't wrappers, as long
- # as they have __parent__ pointers. Let's take a hierarchy like
- # z --isParent--> y --isParent--> x:
- x = Location()
- y = Location()
- z = Location()
- x.__parent__ = y
- y.__parent__ = z
-
- # and some attributes that we want to acquire:
- x.hello = 'world'
- y.foo = 42
- z.foo = 43 # this should not be found
- z.bar = 3.145
-
- # ``aq_acquire`` works as we know it from implicit/acquisition
- # wrappers:
- self.assertEqual(aq_acquire(x, 'hello'), 'world')
- self.assertEqual(aq_acquire(x, 'foo'), 42)
- self.assertEqual(aq_acquire(x, 'bar'), 3.145)
-
- # as does ``aq_get``:
- self.assertEqual(aq_get(x, 'hello'), 'world')
- self.assertEqual(aq_get(x, 'foo'), 42)
- self.assertEqual(aq_get(x, 'bar'), 3.145)
-
- # and ``aq_parent``:
- self.assertIs(aq_parent(x), y)
- self.assertIs(aq_parent(y), z)
-
- # as well as ``aq_chain``:
- self.assertEqual(aq_chain(x), [x, y, z])
-
- def test_implicit_wrapper_as___parent__(self):
- # Let's do the same test again, only now not all objects are of the
- # same kind and link to each other via __parent__ pointers. The
- # root is a stupid ExtensionClass object:
- class Root(ExtensionClass.Base):
- bar = 3.145
- z = Root()
-
- # The intermediate parent is an object that supports implicit
- # acquisition. We bind it to the root via the __of__ protocol:
- class Impl(Implicit):
- foo = 42
- y = Impl().__of__(z)
-
- # The child object is again a simple object with a simple __parent__
- # pointer:
- x = Location()
- x.hello = 'world'
- x.__parent__ = y
-
- # ``aq_acquire`` works as expected from implicit/acquisition
- # wrappers:
- self.assertEqual(aq_acquire(x, 'hello'), 'world')
- self.assertEqual(aq_acquire(x, 'foo'), 42)
- self.assertEqual(aq_acquire(x, 'bar'), 3.145)
-
- # as does ``aq_get``:
- self.assertEqual(aq_get(x, 'hello'), 'world')
- self.assertEqual(aq_get(x, 'foo'), 42)
- self.assertEqual(aq_get(x, 'bar'), 3.145)
-
- # and ``aq_parent``:
- self.assertIs(aq_parent(x), y)
- self.assertIs(aq_parent(y), z)
-
- # as well as ``aq_chain``:
- self.assertEqual(aq_chain(x), [x, y, z])
-
- # Note that also the (implicit) acquisition wrapper has a __parent__
- # pointer, which is automatically computed from the acquisition
- # container (it's identical to aq_parent):
- self.assertIs(y.__parent__, z)
-
- # Just as much as you can assign to aq_parent, you can also assign
- # to __parent__ to change the acquisition context of the wrapper:
-
- newroot = Root()
- y.__parent__ = newroot
- self.assertIsNot(y.__parent__, z)
- self.assertIs(y.__parent__, newroot)
-
- # Note that messing with the wrapper won't in any way affect the
- # wrapped object:
- with self.assertRaises(AttributeError):
- aq_base(y).__parent__
-
- def test_explicit_wrapper_as___parent__(self):
- # Let's do this test yet another time, with an explicit wrapper:
- class Root(ExtensionClass.Base):
- bar = 3.145
- z = Root()
-
- # The intermediate parent is an object that supports implicit
- # acquisition. We bind it to the root via the __of__ protocol:
- class Expl(Explicit):
- foo = 42
- y = Expl().__of__(z)
-
- # The child object is again a simple object with a simple __parent__
- # pointer:
- x = Location()
- x.hello = 'world'
- x.__parent__ = y
-
- # ``aq_acquire`` works as expected from implicit/acquisition
- # wrappers:
- self.assertEqual(aq_acquire(x, 'hello'), 'world')
- self.assertEqual(aq_acquire(x, 'foo'), 42)
- self.assertEqual(aq_acquire(x, 'bar'), 3.145)
-
- # as does ``aq_get``:
- self.assertEqual(aq_get(x, 'hello'), 'world')
- self.assertEqual(aq_get(x, 'foo'), 42)
- self.assertEqual(aq_get(x, 'bar'), 3.145)
-
- # and ``aq_parent``:
- self.assertIs(aq_parent(x), y)
- self.assertIs(aq_parent(y), z)
-
- # as well as ``aq_chain``:
- self.assertEqual(aq_chain(x), [x, y, z])
-
- # Note that also the (explicit) acquisition wrapper has a __parent__
- # pointer, which is automatically computed from the acquisition
- # container (it's identical to aq_parent):
- self.assertIs(y.__parent__, z)
-
- # Just as much as you can assign to aq_parent, you can also assign
- # to __parent__ to change the acquisition context of the wrapper:
- newroot = Root()
- y.__parent__ = newroot
- self.assertIsNot(y.__parent__, z)
- self.assertIs(y.__parent__, newroot)
-
- # Note that messing with the wrapper won't in any way affect the
- # wrapped object:
- with self.assertRaises(AttributeError):
- aq_base(y).__parent__
-
- def test_implicit_wrapper_has_nonwrapper_as_aq_parent(self):
- # Let's do this the other way around: The root and the
- # intermediate parent is an object that doesn't support acquisition,
- y = ECLocation()
- z = Location()
- y.__parent__ = z
- y.foo = 42
- z.foo = 43 # this should not be found
- z.bar = 3.145
-
- # only the outmost object does:
- class Impl(Implicit):
- hello = 'world'
- x = Impl().__of__(y)
-
- # Again, acquiring objects works as usual:
- self.assertEqual(aq_acquire(x, 'hello'), 'world')
- self.assertEqual(aq_acquire(x, 'foo'), 42)
- self.assertEqual(aq_acquire(x, 'bar'), 3.145)
-
- # as does ``aq_get``:
- self.assertEqual(aq_get(x, 'hello'), 'world')
- self.assertEqual(aq_get(x, 'foo'), 42)
- self.assertEqual(aq_get(x, 'bar'), 3.145)
-
- # and ``aq_parent``:
- self.assertEqual(aq_parent(x), y)
- self.assertIs(aq_parent(y), z)
- self.assertEqual(x.aq_parent, y)
- self.assertEqual(x.aq_parent.aq_parent, z)
-
- # as well as ``aq_chain``:
- self.assertEqual(aq_chain(x), [x, y, z])
- self.assertEqual(x.aq_chain, [x, y, z])
-
- # Because the outmost object, ``x``, is wrapped in an implicit
- # acquisition wrapper, we can also use direct attribute access:
- self.assertEqual(x.hello, 'world')
- self.assertEqual(x.foo, 42)
- self.assertEqual(x.bar, 3.145)
-
- def test_explicit_wrapper_has_nonwrapper_as_aq_parent(self):
- # Let's do this the other way around: The root and the
- # intermediate parent is an object that doesn't support acquisition,
-
- y = ECLocation()
- z = Location()
- y.__parent__ = z
- y.foo = 42
- z.foo = 43 # this should not be found
- z.bar = 3.145
-
- # only the outmost object does:
- class Expl(Explicit):
- hello = 'world'
- x = Expl().__of__(y)
-
- # Again, acquiring objects works as usual:
- self.assertEqual(aq_acquire(x, 'hello'), 'world')
- self.assertEqual(aq_acquire(x, 'foo'), 42)
- self.assertEqual(aq_acquire(x, 'bar'), 3.145)
-
- # as does ``aq_get``:
- self.assertEqual(aq_get(x, 'hello'), 'world')
- self.assertEqual(aq_get(x, 'foo'), 42)
- self.assertEqual(aq_get(x, 'bar'), 3.145)
-
- # and ``aq_parent``:
- self.assertEqual(aq_parent(x), y)
- self.assertIs(aq_parent(y), z)
- self.assertEqual(x.aq_parent, y)
- self.assertEqual(x.aq_parent.aq_parent, z)
-
- # as well as ``aq_chain``:
- self.assertEqual(aq_chain(x), [x, y, z])
- self.assertEqual(x.aq_chain, [x, y, z])
-
-
- class TestParentCircles(unittest.TestCase):
-
- def test___parent__aq_parent_circles(self):
- # As a general safety belt, Acquisition won't follow a mixture of
- # circular __parent__ pointers and aq_parent wrappers. These can
- # occurr when code that uses implicit acquisition wrappers meets
- # code that uses __parent__ pointers.
- class Impl(Implicit):
- hello = 'world'
-
- class Impl2(Implicit):
- hello = 'world2'
- only = 'here'
-
- x = Impl()
- y = Impl2().__of__(x)
- x.__parent__ = y
-
- self.assertTrue(x.__parent__.aq_base is y.aq_base)
- self.assertTrue(aq_parent(x) is y)
- self.assertTrue(x.__parent__.__parent__ is x)
-
- self.assertEqual(x.hello, 'world')
- self.assertEqual(aq_acquire(x, 'hello'), 'world')
-
- with self.assertRaises(AttributeError):
- x.only
-
- self.assertEqual(aq_acquire(x, 'only'), 'here')
-
- with self.assertRaises(AttributeError):
- aq_acquire(x, 'non_existant_attr')
-
- with self.assertRaises(RuntimeError):
- aq_acquire(y, 'non_existant_attr')
-
- with self.assertRaises(AttributeError):
- x.non_existant_attr
-
- with self.assertRaises(RuntimeError):
- y.non_existant_attr
-
- @unittest.skipUnless(
- hasattr(Acquisition.ImplicitAcquisitionWrapper, '_obj'),
- 'Pure Python specific test')
- def test_python_impl_cycle(self):
- # An extra safety belt, specific to the Python implementation
- # because it's not clear how one could arrive in this situation
- # naturally.
- class Impl(Implicit):
- pass
-
- root = Impl()
- root.child = Impl()
- child_wrapper = root.child
-
- # Now set up the python specific boo-boo:
- child_wrapper._obj = child_wrapper
-
- # Now nothing works:
-
- with self.assertRaises(RuntimeError):
- child_wrapper.non_existant_attr
-
- with self.assertRaises(RuntimeError):
- aq_acquire(child_wrapper, 'non_existant_attr')
-
- def test_unwrapped_implicit_acquirer_unwraps__parent__(self):
- # Set up an implicit acquirer with a parent:
- class Impl(Implicit):
- pass
-
- y = Impl()
- x = Impl()
- x.__parent__ = y
-
- # Now if we retrieve the parent from the (unwrapped) instance, the
- # parent should not be wrapped in the instance's acquisition chain.
- self.assertIs(x.__parent__, y)
-
-
- class TestBugs(unittest.TestCase):
-
- def test__iter__after_AttributeError(self):
- # See https://bugs.launchpad.net/zope2/+bug/1155760
- import time
-
- class C(Implicit):
- l = [0, 1, 2, 3, 4]
-
- def __getitem__(self, i):
- return self.l[i]
-
- a = C()
- b = C().__of__(a)
- try:
- for n in b:
- time.gmtime()
- except AttributeError:
- raise
-
-
- class TestSpecialNames(unittest.TestCase):
-
- def test_special_names(self):
- # This test captures some aq_special names that are not otherwise
- # tested for.
- class Impl(Implicit):
- pass
-
- root = Impl()
- root.child = Impl()
-
- # First, the 'aq_explicit' name returns an explicit wrapper
- # instead of an explicit wrapper:
- ex_wrapper = root.child.aq_explicit
- self.assertIsInstance(
- ex_wrapper, Acquisition.ExplicitAcquisitionWrapper)
-
- # If we ask an explicit wrapper to be explicit, we get back
- # the same object:
- self.assertIs(ex_wrapper.aq_explicit, ex_wrapper.aq_explicit)
-
- # These special names can also be filtered:
- self.assertIsNone(
- aq_acquire(root.child, 'aq_explicit',
- lambda searched, parent, name, ob, extra: None,
- default=None))
-
- self.assertIsNotNone(
- aq_acquire(root.child, 'aq_explicit',
- lambda searched, parent, name, ob, extra: True,
- default=None))
-
- # Last, a value that can be used for testing that you have a wrapper:
- self.assertEqual(root.child.aq_uncle, 'Bob')
-
-
- class TestWrapper(unittest.TestCase):
-
- def test_deleting_parent_attrs(self):
- # We can detach a wrapper object from its chain by deleting its
- # parent.
-
- class Impl(Implicit):
- pass
-
- root = Impl()
- root.a = 42
- root.child = Impl()
-
- # Initially, a wrapped object has the parent we expect:
- child_wrapper = root.child
- self.assertIs(child_wrapper.__parent__, root)
- self.assertIs(child_wrapper.aq_parent, root)
-
- # Even though we acquired the 'a' attribute, we can't delete it:
- self.assertEqual(child_wrapper.a, 42)
- with self.assertRaises(AttributeError):
- del child_wrapper.a
-
- # Now if we delete it (as many times as we want)
- # we lose access to the parent and acquired attributes:
- del child_wrapper.__parent__
- del child_wrapper.aq_parent
-
- self.assertIs(child_wrapper.__parent__, None)
- self.assertIs(child_wrapper.aq_parent, None)
- self.assertFalse(hasattr(child_wrapper, 'a'))
-
- def test__cmp__is_called_on_wrapped_object(self):
- # If we define an object that implements `__cmp__`:
- class Impl(Implicit):
- def __cmp__(self, other):
- return self.a
-
- # Then it gets called when a wrapper is compared (we call it
- # directly to avoid any Python2/3 issues):
- root = Impl()
- root.a = 42
- root.child = Impl()
- self.assertEqual(root.child.a, 42)
- self.assertEqual(root.child.__cmp__(None), 42)
-
- def test_wrapped_methods_have_correct_self(self):
- # Getting a method from a wrapper returns an object that uses the
- # wrapper as its `__self__`, no matter how many layers deep we go;
- # this makes acquisition work in that code.
-
- class Impl(Implicit):
- def method(self):
- return self.a
-
- root = Impl()
- root.a = 42
- root.child = Impl()
- root.child.child = Impl()
-
- # We explicitly construct a wrapper to bypass some of the optimizations
- # that remove redundant wrappers and thus get more full code coverage:
- child_wrapper = Acquisition.ImplicitAcquisitionWrapper(
- root.child.child, root.child)
- method = child_wrapper.method
- self.assertIs(method.__self__, child_wrapper)
- self.assertEqual(method(), 42)
-
- def test_cannot_set_attributes_on_empty_wrappers(self):
- # If a wrapper is around None, no attributes can be set on it:
- wrapper = Acquisition.ImplicitAcquisitionWrapper(None, None)
-
- with self.assertRaises(AttributeError):
- wrapper.a = 42
-
- # Likewise, we can't really get any attributes on such an empty wrapper
- with self.assertRaises(AttributeError):
- wrapper.a
-
- def test_getitem_setitem_not_implemented(self):
- # If a wrapper wraps something that doesn't implement get/setitem,
- # those failures propagate up.
- class Impl(Implicit):
- pass
-
- root = Impl()
- root.child = Impl()
-
- # We can't set anything:
- with self.assertRaises(AttributeError):
- root.child['key'] = 42
-
- # We can't get anything:
- with self.assertRaises(AttributeError):
- root.child['key']
-
- def test_getitem_setitem_implemented(self):
- # The wrapper delegates to get/set item.
- class Root(Implicit):
- pass
-
- class Impl(Implicit):
- def __getitem__(self, i):
- return self.a
-
- def __setitem__(self, key, value):
- self.a[key] = value
-
- root = Root()
- root.a = dict()
- root.child = Impl()
- self.assertEqual(root.child[1], {})
-
- root.child['a'] = 'b'
- self.assertEqual(root.child[1], {'a': 'b'})
-
- def test_wrapped_objects_are_unwrapped_on_set(self):
- # A wrapper is not passed to the base object during `setattr`.
- class Impl(Implicit):
- pass
-
- # Given two different wrappers:
- root = Impl()
- child = Impl()
- child2 = Impl()
- root.child = child
- root.child2 = child2
-
- # If we pass one to the other as an attribute:
- root.child.child2 = root.child2
-
- # By the time it gets there, it's not wrapped:
- self.assertIs(type(child.__dict__['child2']), Impl)
-
-
- class TestOf(unittest.TestCase):
-
- def test__of__exception(self):
- # Wrapper_findattr did't check for an exception in a user defined
- # __of__ method before passing the result to the filter. In this
- # case the 'value' argument of the filter was NULL, which caused
- # a segfault when being accessed.
-
- class X(Implicit):
- def __of__(self, parent):
- if aq_base(parent) is not parent:
- raise NotImplementedError('ack')
- return X.inheritedAttribute('__of__')(self, parent)
-
- a = I('a')
- a.b = I('b')
- a.b.x = X('x')
- with self.assertRaises(NotImplementedError):
- aq_acquire(a.b, 'x',
- lambda self, object, name, value, extra: repr(value))
-
- def test_wrapper_calls_of_on_non_wrapper(self):
- # The ExtensionClass protocol is respected even for non-Acquisition
- # objects.
-
- class MyBase(ExtensionClass.Base):
- call_count = 0
-
- def __of__(self, other):
- self.call_count += 1
- return 42
-
- class Impl(Implicit):
- pass
-
- # If we have a wrapper around an object that is an extension class,
- # but not an Acquisition wrapper:
- root = Impl()
- base = MyBase()
- wrapper = Acquisition.ImplicitAcquisitionWrapper(base, root)
-
- # And access that object itself through a wrapper:
- root.child = Impl()
- root.child.wrapper = wrapper
-
- # The `__of__` protocol is respected implicitly:
- self.assertEqual(root.child.wrapper, 42)
- self.assertEqual(base.call_count, 1)
-
- # Here it is explicitly:
- self.assertEqual(wrapper.__of__(root.child), 42)
- self.assertEqual(base.call_count, 2)
-
-
- class TestAQInContextOf(unittest.TestCase):
-
- def test_aq_inContextOf(self):
- from ExtensionClass import Base
-
- class B(Base):
- color = 'red'
-
- class A(Implicit):
- def hi(self):
- return self.color
-
- class Location(object):
- __parent__ = None
-
- b = B()
- b.a = A()
- self.assertEqual(b.a.hi(), 'red')
-
- b.a.color = 'green'
- self.assertEqual(b.a.hi(), 'green')
-
- with self.assertRaises(AttributeError):
- A().hi()
-
- # New test for wrapper comparisons.
- foo = b.a
- bar = b.a
- self.assertEqual(foo, bar)
-
- c = A()
- b.c = c
- b.c.d = c
- self.assertEqual(b.c.d, c)
- self.assertEqual(b.c.d, b.c)
- self.assertEqual(b.c, c)
-
- l = Location()
- l.__parent__ = b.c
-
- def checkContext(self, o):
- # Python equivalent to aq_inContextOf
- next = self
- o = aq_base(o)
- while 1:
- if aq_base(next) is o:
- return True
- self = aq_inner(next)
- if self is None:
- break
- next = aq_parent(self)
- if next is None:
- break
- return False
-
- self.assertTrue(checkContext(b.c, b))
- self.assertFalse(checkContext(b.c, b.a))
-
- self.assertTrue(checkContext(l, b))
- self.assertTrue(checkContext(l, b.c))
- self.assertFalse(checkContext(l, b.a))
-
- # aq_inContextOf works the same way:
- self.assertTrue(aq_inContextOf(b.c, b))
- self.assertFalse(aq_inContextOf(b.c, b.a))
-
- self.assertTrue(aq_inContextOf(l, b))
- self.assertTrue(aq_inContextOf(l, b.c))
- self.assertFalse(aq_inContextOf(l, b.a))
-
- self.assertTrue(b.a.aq_inContextOf(b))
- self.assertTrue(b.c.aq_inContextOf(b))
- self.assertTrue(b.c.d.aq_inContextOf(b))
- self.assertTrue(b.c.d.aq_inContextOf(c))
- self.assertTrue(b.c.d.aq_inContextOf(b.c))
- self.assertFalse(b.c.aq_inContextOf(foo))
- self.assertFalse(b.c.aq_inContextOf(b.a))
- self.assertFalse(b.a.aq_inContextOf('somestring'))
-
- def test_aq_inContextOf_odd_cases(self):
- # The aq_inContextOf function still works in some artificial cases.
- root = object()
- wrapper_around_none = Acquisition.ImplicitAcquisitionWrapper(
- None, None)
- self.assertEqual(aq_inContextOf(wrapper_around_none, root), 0)
-
- # If we don't ask for inner objects, the same thing happens
- # in this case:
- self.assertEqual(aq_inContextOf(wrapper_around_none, root, False), 0)
-
- # Somewhat surprisingly, the `aq_inner` of this wrapper
- # is itself a wrapper:
- self.assertIsInstance(aq_inner(wrapper_around_none),
- Acquisition.ImplicitAcquisitionWrapper)
-
- # If we manipulate the Python implementation
- # to make this no longer true, nothing breaks:
- if hasattr(wrapper_around_none, '_obj'):
- setattr(wrapper_around_none, '_obj', None)
-
- self.assertEqual(aq_inContextOf(wrapper_around_none, root), 0)
- self.assertIsInstance(wrapper_around_none,
- Acquisition.ImplicitAcquisitionWrapper)
-
- # Following parent pointers in weird circumstances works too:
- class WithParent(object):
- __parent__ = None
-
- self.assertEqual(aq_inContextOf(WithParent(), root), 0)
-
-
- class TestCircles(unittest.TestCase):
-
- def test_search_repeated_objects(self):
- # If an acquisition wrapper object is wrapping another wrapper, and
- # also has another wrapper as its parent, and both of *those*
- # wrappers have the same object (one as its direct object, one as
- # its parent), then acquisition proceeds as normal: we don't get
- # into any cycles or fail to acquire expected attributes. In fact,
- # we actually can optimize out a level of the search in that case.
-
- # This is a bit of a convoluted scenario to set up when the code is
- # written out all in one place, but it may occur organically when
- # spread across a project.
-
- # We begin with some simple setup, importing the objects we'll use
- # and setting up the object that we'll repeat. This particular test
- # is specific to the Python implementation, so we're using low-level
- # functions from that module:
-
- from Acquisition import _Wrapper as Wrapper
- from Acquisition import _Wrapper_acquire
-
- class Repeated(object):
- hello = "world"
-
- def __repr__(self):
- return 'repeated'
-
- repeated = Repeated()
-
- # Now the tricky part, creating the repeating pattern. To rephrase
- # the opening sentence, we need a wrapper whose object and parent
- # (container) are themselves both wrappers, and the object's parent is
- # the same object as the wrapper's parent's object. That might be a
- # bit more clear in code:
- wrappers_object = Wrapper('a', repeated)
- wrappers_parent = Wrapper(repeated, 'b')
- wrapper = Wrapper(wrappers_object, wrappers_parent)
- self.assertIs(wrapper._obj._container, wrapper._container._obj)
-
- # Using the low-level function on the wrapper fails to find the
- # desired attribute. This is because of the optimization that cuts
- # out a level of the search (it is assumed that the higher level
- # `_Wrapper_findattr` function is driving the search and will take
- # the appropriate steps):
- with self.assertRaises(AttributeError):
- _Wrapper_acquire(wrapper, 'hello')
-
- # In fact, if we go through the public interface of the high-level
- # functions, we do find the attribute as expected:
- self.assertEqual(aq_acquire(wrapper, 'hello'), 'world')
-
- def test_parent_parent_circles(self):
-
- class Impl(Implicit):
- hello = 'world'
-
- class Impl2(Implicit):
- hello = 'world2'
- only = 'here'
-
- x = Impl()
- y = Impl2()
- x.__parent__ = y
- y.__parent__ = x
-
- self.assertTrue(x.__parent__.__parent__ is x)
- self.assertEqual(aq_acquire(x, 'hello'), 'world')
- self.assertEqual(aq_acquire(x, 'only'), 'here')
-
- self.assertRaises(AttributeError, aq_acquire, x, 'non_existant_attr')
- self.assertRaises(AttributeError, aq_acquire, y, 'non_existant_attr')
-
- def test_parent_parent_parent_circles(self):
-
- class Impl(Implicit):
- hello = 'world'
-
- class Impl2(Implicit):
- hello = 'world'
-
- class Impl3(Implicit):
- hello = 'world2'
- only = 'here'
-
- a = Impl()
- b = Impl2()
- c = Impl3()
- a.__parent__ = b
- b.__parent__ = c
- c.__parent__ = a
-
- self.assertTrue(a.__parent__.__parent__ is c)
- self.assertTrue(
- aq_base(a.__parent__.__parent__.__parent__) is a)
- self.assertTrue(b.__parent__.__parent__ is a)
- self.assertTrue(c.__parent__.__parent__ is b)
-
- self.assertEqual(aq_acquire(a, 'hello'), 'world')
- self.assertEqual(aq_acquire(b, 'hello'), 'world')
- self.assertEqual(aq_acquire(c, 'hello'), 'world2')
-
- self.assertEqual(aq_acquire(a, 'only'), 'here')
- self.assertEqual(aq_acquire(b, 'only'), 'here')
- self.assertEqual(aq_acquire(c, 'only'), 'here')
-
- self.assertRaises(AttributeError, getattr, a, 'non_existant_attr')
- self.assertRaises(AttributeError, getattr, b, 'non_existant_attr')
- self.assertRaises(AttributeError, getattr, c, 'non_existant_attr')
-
-
- class TestAcquire(unittest.TestCase):
-
- def setUp(self):
-
- class Impl(Implicit):
- pass
-
- class Expl(Explicit):
- pass
-
- a = Impl('a')
- a.y = 42
- a.b = Expl('b')
- a.b.z = 3
- a.b.c = Impl('c')
- self.a = a
-
- def test_explicit_module_default(self):
- self.assertEqual(aq_acquire(self.a.b.c, 'z'), 3)
-
- def test_explicit_module_true(self):
- self.assertEqual(aq_acquire(self.a.b.c, 'z', explicit=True), 3)
-
- def test_explicit_module_false(self):
- self.assertEqual(aq_acquire(self.a.b.c, 'z', explicit=False), 3)
-
- def test_explicit_wrapper_default(self):
- self.assertEqual(self.a.b.c.aq_acquire('z'), 3)
-
- def test_explicit_wrapper_true(self):
- self.assertEqual(self.a.b.c.aq_acquire('z', explicit=True), 3)
-
- def test_explicit_wrapper_false(self):
- self.assertEqual(self.a.b.c.aq_acquire('z', explicit=False), 3)
-
- def test_wrapper_falls_back_to_default(self):
- self.assertEqual(aq_acquire(self.a.b.c, 'nonesuch', default=4), 4)
-
- def test_no_wrapper_but___parent___falls_back_to_default(self):
- class NotWrapped(object):
- pass
- child = NotWrapped()
- child.__parent__ = NotWrapped()
- self.assertEqual(aq_acquire(child, 'nonesuch', default=4), 4)
-
- def test_unwrapped_falls_back_to_default(self):
- self.assertEqual(aq_acquire(object(), 'nonesuch', default=4), 4)
-
- def test_w_unicode_attr_name(self):
- # See https://bugs.launchpad.net/acquisition/+bug/143358
- found = aq_acquire(self.a.b.c, AQ_PARENT)
- self.assertTrue(found.aq_self is self.a.b.aq_self)
-
-
- class TestCooperativeBase(unittest.TestCase):
-
- def _make_acquirer(self, kind):
- from ExtensionClass import Base
-
- class ExtendsBase(Base):
- def __getattribute__(self, name):
- if name == 'magic':
- return 42
- return super(ExtendsBase, self).__getattribute__(name)
-
- class Acquirer(kind, ExtendsBase):
- pass
-
- return Acquirer()
-
- def _check___getattribute___is_cooperative(self, acquirer):
- self.assertEqual(getattr(acquirer, 'magic'), 42)
-
- def test_implicit___getattribute__is_cooperative(self):
- self._check___getattribute___is_cooperative(
- self._make_acquirer(Implicit))
-
- def test_explicit___getattribute__is_cooperative(self):
- self._check___getattribute___is_cooperative(
- self._make_acquirer(Explicit))
-
-
- class TestImplicitWrappingGetattribute(unittest.TestCase):
- # Implicitly wrapping an object that uses object.__getattribute__
- # in its implementation of __getattribute__ doesn't break.
- # This can arise with the `persistent` library or other
- # "base" classes.
-
- # The C implementation doesn't directly support this; however,
- # it is used heavily in the Python implementation of Persistent.
-
- @unittest.skipIf(CAPI, 'Pure Python test.')
- def test_object_getattribute_in_rebound_method_with_slots(self):
-
- class Persistent(object):
- __slots__ = ('__flags',)
-
- def __init__(self):
- self.__flags = 42
-
- def get_flags(self):
- return object.__getattribute__(self, '_Persistent__flags')
-
- wrapped = Persistent()
- wrapper = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
-
- self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
-
- # Changing it is not reflected in the wrapper's dict (this is an
- # implementation detail)
- wrapper._Persistent__flags = -1
- self.assertEqual(wrapped.get_flags(), -1)
- self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
-
- wrapper_dict = object.__getattribute__(wrapper, '__dict__')
- self.assertFalse('_Persistent__flags' in wrapper_dict)
-
- @unittest.skipIf(CAPI, 'Pure Python test.')
- def test_type_with_slots_reused(self):
-
- class Persistent(object):
- __slots__ = ('__flags',)
-
- def __init__(self):
- self.__flags = 42
-
- def get_flags(self):
- return object.__getattribute__(self, '_Persistent__flags')
-
- wrapped = Persistent()
- wrapper = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
- wrapper2 = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
-
- self.assertTrue(type(wrapper) is type(wrapper2))
-
- @unittest.skipIf(CAPI, 'Pure Python test.')
- def test_object_getattribute_in_rebound_method_with_dict(self):
-
- class Persistent(object):
- def __init__(self):
- self.__flags = 42
-
- def get_flags(self):
- return object.__getattribute__(self, '_Persistent__flags')
-
- wrapped = Persistent()
- wrapper = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
-
- self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
-
- # Changing it is also reflected in both dicts (this is an
- # implementation detail)
- wrapper._Persistent__flags = -1
- self.assertEqual(wrapped.get_flags(), -1)
- self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
-
- wrapper_dict = object.__getattribute__(wrapper, '__dict__')
- self.assertTrue('_Persistent__flags' in wrapper_dict)
-
- @unittest.skipIf(CAPI, 'Pure Python test.')
- def test_object_getattribute_in_rebound_method_with_slots_and_dict(self):
-
- class Persistent(object):
- __slots__ = ('__flags', '__dict__')
-
- def __init__(self):
- self.__flags = 42
- self.__oid = 'oid'
-
- def get_flags(self):
- return object.__getattribute__(self, '_Persistent__flags')
-
- def get_oid(self):
- return object.__getattribute__(self, '_Persistent__oid')
-
- wrapped = Persistent()
- wrapper = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
-
- self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
- self.assertEqual(wrapped.get_oid(), wrapper.get_oid())
-
-
- class TestUnicode(unittest.TestCase):
-
- def test_implicit_aq_unicode_should_be_called(self):
- class A(Implicit):
- def __unicode__(self):
- return UNICODE_WAS_CALLED
- wrapped = A().__of__(A())
- self.assertEqual(UNICODE_WAS_CALLED, unicode(wrapped))
- self.assertEqual(str(wrapped), repr(wrapped))
-
- def test_explicit_aq_unicode_should_be_called(self):
- class A(Explicit):
- def __unicode__(self):
- return UNICODE_WAS_CALLED
- wrapped = A().__of__(A())
- self.assertEqual(UNICODE_WAS_CALLED, unicode(wrapped))
- self.assertEqual(str(wrapped), repr(wrapped))
-
- def test_implicit_should_fall_back_to_str(self):
- class A(Implicit):
- def __str__(self):
- return 'str was called'
- wrapped = A().__of__(A())
- self.assertEqual(STR_WAS_CALLED, unicode(wrapped))
- self.assertEqual('str was called', str(wrapped))
-
- def test_explicit_should_fall_back_to_str(self):
- class A(Explicit):
- def __str__(self):
- return 'str was called'
- wrapped = A().__of__(A())
- self.assertEqual(STR_WAS_CALLED, unicode(wrapped))
- self.assertEqual('str was called', str(wrapped))
-
- def test_str_fallback_should_be_called_with_wrapped_self(self):
- class A(Implicit):
- def __str__(self):
- return str(self.aq_parent == outer)
- outer = A()
- inner = A().__of__(outer)
- self.assertEqual(TRUE, unicode(inner))
-
- def test_unicode_should_be_called_with_wrapped_self(self):
- class A(Implicit):
- def __unicode__(self):
- return str(self.aq_parent == outer)
- outer = A()
- inner = A().__of__(outer)
- self.assertEqual(TRUE, unicode(inner))
-
-
- class TestProxying(unittest.TestCase):
-
- __binary_numeric_methods__ = [
- '__add__',
- '__sub__',
- '__mul__',
- # '__floordiv__', # not implemented in C
- '__mod__',
- '__divmod__',
- '__pow__',
- '__lshift__',
- '__rshift__',
- '__and__',
- '__xor__',
- '__or__',
- # division
- '__truediv__',
- '__div__',
- # reflected
- '__radd__',
- '__rsub__',
- '__rmul__',
- '__rdiv__',
- '__rtruediv__',
- '__rfloordiv__',
- '__rmod__',
- '__rdivmod__',
- '__rpow__',
- '__rlshift__',
- '__rrshift__',
- '__rand__',
- '__rxor__',
- '__ror__',
- # in place
- '__iadd__',
- '__isub__',
- '__imul__',
- '__idiv__',
- '__itruediv__',
- '__ifloordiv__',
- '__imod__',
- '__idivmod__',
- '__ipow__',
- '__ilshift__',
- '__irshift__',
- '__iand__',
- '__ixor__',
- '__ior__',
- # conversion
- # implementing it messes up all the arithmetic tests
- # '__coerce__',
- ]
-
- if PY3 and sys.version_info.minor >= 5:
- __binary_numeric_methods__.extend([
- '__matmul__',
- '__imatmul__'
- ])
-
- __unary_special_methods__ = [
- # arithmetic
- '__neg__',
- '__pos__',
- '__abs__',
- '__invert__',
- ]
-
- __unary_conversion_methods__ = {
- # conversion
- '__complex__': complex,
- '__int__': int,
- '__long__': long,
- '__float__': float,
- '__oct__': oct,
- '__hex__': hex,
- '__len__': lambda o: o if isinstance(o, int) else len(o),
- # '__index__': operator.index, # not implemented in C
- }
-
- def _check_special_methods(self, base_class=Implicit):
- # Check that special methods are proxied
- # when called implicitly by the interpreter
-
- def binary_acquired_func(self, other, modulo=None):
- return self.value
-
- def unary_acquired_func(self):
- return self.value
-
- acquire_meths = {}
- for k in self.__binary_numeric_methods__:
- acquire_meths[k] = binary_acquired_func
- for k in self.__unary_special_methods__:
- acquire_meths[k] = unary_acquired_func
-
- def make_converter(f):
- def converter(self, *args):
- return f(self.value)
- return converter
- for k, convert in self.__unary_conversion_methods__.items():
- acquire_meths[k] = make_converter(convert)
-
- acquire_meths['__len__'] = lambda self: self.value
-
- if PY3:
- # Under Python 3, oct() and hex() call __index__ directly
- acquire_meths['__index__'] = acquire_meths['__int__']
-
- if base_class == Explicit:
- acquire_meths['value'] = Acquisition.Acquired
- AcquireValue = type('AcquireValue', (base_class,), acquire_meths)
-
- class B(Implicit):
- pass
-
- base = B()
- base.value = 42
- base.derived = AcquireValue()
-
- # one syntax check for the heck of it
- self.assertEqual(base.value, base.derived + 1)
- # divmod is not in the operator module
- self.assertEqual(base.value, divmod(base.derived, 1))
-
- _found_at_least_one_div = False
-
- for meth in self.__binary_numeric_methods__:
- op = getattr(operator, meth, None)
- if op is not None:
- # called on the instance
- self.assertEqual(base.value, op(base.derived, -1))
-
- # called on the type, as the interpreter does
- # Note that the C version can only implement either __truediv__
- # or __div__, not both
- op = getattr(operator, meth, None)
- if op is not None:
- try:
- self.assertEqual(base.value,
- op(base.derived, 1))
- if meth in ('__div__', '__truediv__'):
- _found_at_least_one_div = True
- except TypeError:
- if meth in ('__div__', '__truediv__'):
- pass
-
- self.assertTrue(
- _found_at_least_one_div,
- "Must implement at least one of __div__ and __truediv__")
-
- # Unary methods
- for meth in self.__unary_special_methods__:
- self.assertEqual(base.value, getattr(base.derived, meth)())
- op = getattr(operator, meth)
- self.assertEqual(base.value, op(base.derived))
-
- # Conversion functions
- for meth, converter in self.__unary_conversion_methods__.items():
- if not converter:
- continue
- self.assertEqual(converter(base.value),
- getattr(base.derived, meth)())
-
- self.assertEqual(converter(base.value),
- converter(base.derived))
-
- def test_implicit_proxy_special_meths(self):
- self._check_special_methods()
-
- def test_explicit_proxy_special_meths(self):
- self._check_special_methods(base_class=Explicit)
-
- def _check_contains(self, base_class=Implicit):
- # Contains has lots of fallback behaviour
- class B(Implicit):
- pass
- base = B()
- base.value = 42
-
- # The simple case is if the object implements contains itself
- class ReallyContains(base_class):
- if base_class is Explicit:
- value = Acquisition.Acquired
-
- def __contains__(self, item):
- return self.value == item
-
- base.derived = ReallyContains()
-
- self.assertTrue(42 in base.derived)
- self.assertFalse(24 in base.derived)
-
- # Iterable objects are NOT iterated
- # XXX: Is this a bug in the C code? Shouldn't it do
- # what the interpreter does and fallback to iteration?
- class IterContains(base_class):
- if base_class is Explicit:
- value = Acquisition.Acquired
-
- def __iter__(self):
- return iter((42,))
- base.derived = IterContains()
-
- self.assertRaises(AttributeError, operator.contains, base.derived, 42)
-
- def test_implicit_proxy_contains(self):
- self._check_contains()
-
- def test_explicit_proxy_contains(self):
- self._check_contains(base_class=Explicit)
-
- def _check_call(self, base_class=Implicit):
- class B(Implicit):
- pass
- base = B()
- base.value = 42
-
- class Callable(base_class):
- if base_class is Explicit:
- value = Acquisition.Acquired
-
- def __call__(self, arg, k=None):
- return self.value, arg, k
-
- base.derived = Callable()
-
- self.assertEqual(base.derived(1, k=2), (42, 1, 2))
-
- if not IS_PYPY:
- # XXX: This test causes certain versions
- # of PyPy to segfault (at least 2.6.0-alpha1)
- class NotCallable(base_class):
- pass
-
- base.derived = NotCallable()
- try:
- base.derived()
- self.fail("Not callable")
- except (TypeError, AttributeError):
- pass
-
- def test_implicit_proxy_call(self):
- self._check_call()
-
- def test_explicit_proxy_call(self):
- self._check_call(base_class=Explicit)
-
- def _check_hash(self, base_class=Implicit):
- class B(Implicit):
- pass
- base = B()
- base.value = B()
- base.value.hash = 42
-
- class NoAcquired(base_class):
- def __hash__(self):
- return 1
-
- hashable = NoAcquired()
- base.derived = hashable
- self.assertEqual(1, hash(hashable))
- self.assertEqual(1, hash(base.derived))
-
- # cannot access acquired attributes during
- # __hash__
-
- class CannotAccessAcquiredAttributesAtHash(base_class):
- if base_class is Explicit:
- value = Acquisition.Acquired
-
- def __hash__(self):
- return self.value.hash
-
- hashable = CannotAccessAcquiredAttributesAtHash()
- base.derived = hashable
- self.assertRaises(AttributeError, hash, hashable)
- self.assertRaises(AttributeError, hash, base.derived)
-
- def test_implicit_proxy_hash(self):
- self._check_hash()
-
- def test_explicit_proxy_hash(self):
- self._check_hash(base_class=Explicit)
-
- def _check_comparison(self, base_class=Implicit):
- # Comparison behaviour is complex; see notes in _Wrapper
- class B(Implicit):
- pass
- base = B()
- base.value = 42
-
- rich_cmp_methods = ['__lt__', '__gt__', '__eq__',
- '__ne__', '__ge__', '__le__']
-
- def _never_called(self, other):
- raise RuntimeError("This should never be called")
-
- class RichCmpNeverCalled(base_class):
- for _name in rich_cmp_methods:
- locals()[_name] = _never_called
-
- base.derived = RichCmpNeverCalled()
- base.derived2 = RichCmpNeverCalled()
- # We can access all of the operators, but only because
- # they are masked
- for name in rich_cmp_methods:
- getattr(operator, name)(base.derived, base.derived2)
-
- self.assertFalse(base.derived2 == base.derived)
- self.assertEqual(base.derived, base.derived)
-
- def test_implicit_proxy_comporison(self):
- self._check_comparison()
-
- def test_explicit_proxy_comporison(self):
- self._check_comparison(base_class=Explicit)
-
- def _check_bool(self, base_class=Implicit):
- class B(Implicit):
- pass
- base = B()
- base.value = 42
-
- class WithBool(base_class):
- if base_class is Explicit:
- value = Acquisition.Acquired
-
- def __nonzero__(self):
- return bool(self.value)
- __bool__ = __nonzero__
-
- class WithLen(base_class):
- if base_class is Explicit:
- value = Acquisition.Acquired
-
- def __len__(self):
- return self.value
-
- class WithNothing(base_class):
- pass
-
- base.wbool = WithBool()
- base.wlen = WithLen()
- base.wnothing = WithNothing()
-
- self.assertEqual(bool(base.wbool), True)
- self.assertEqual(bool(base.wlen), True)
- self.assertEqual(bool(base.wnothing), True)
-
- base.value = 0
- self.assertFalse(base.wbool)
- self.assertFalse(base.wlen)
-
- def test_implicit_proxy_bool(self):
- self._check_bool()
-
- def test_explicit_proxy_bool(self):
- self._check_bool(base_class=Explicit)
-
-
- class TestCompilation(unittest.TestCase):
-
- def test_compile(self):
- if IS_PYPY or IS_PURE:
- with self.assertRaises((AttributeError, ImportError)):
- from Acquisition import _Acquisition
- else:
- from Acquisition import _Acquisition
- self.assertTrue(hasattr(_Acquisition, 'AcquisitionCAPI'))
-
-
- def test_suite():
- import os.path
- here = os.path.dirname(__file__)
- root = os.path.join(here, os.pardir, os.pardir)
- readme = os.path.join(root, 'README.rst')
-
- suites = [
- DocTestSuite(),
- unittest.defaultTestLoader.loadTestsFromName(__name__),
- ]
-
- # This file is only available in a source checkout, skip it
- # when tests are run for an installed version.
- if os.path.isfile(readme):
- suites.append(DocFileSuite(readme, module_relative=False))
-
- return unittest.TestSuite(suites)
|