Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tests.py 91KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349
  1. ##############################################################################
  2. #
  3. # Copyright (c) 2003 Zope Foundation and Contributors.
  4. # All Rights Reserved.
  5. #
  6. # This software is subject to the provisions of the Zope Public License,
  7. # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  8. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  9. # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  10. # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  11. # FOR A PARTICULAR PURPOSE.
  12. #
  13. ##############################################################################
  14. """Acquisition test cases (and useful examples)
  15. """
  16. from __future__ import print_function
  17. import gc
  18. import unittest
  19. import sys
  20. import operator
  21. from doctest import DocTestSuite, DocFileSuite
  22. import ExtensionClass
  23. import Acquisition
  24. from Acquisition import ( # NOQA
  25. aq_acquire,
  26. aq_base,
  27. aq_chain,
  28. aq_get,
  29. aq_inContextOf,
  30. aq_inner,
  31. aq_parent,
  32. aq_self,
  33. Explicit,
  34. Implicit,
  35. IS_PYPY,
  36. IS_PURE,
  37. )
  38. if sys.version_info >= (3,):
  39. PY3 = True
  40. PY2 = False
  41. def unicode(self):
  42. # For test purposes, redirect the unicode
  43. # to the type of the object, just like Py2 did
  44. try:
  45. return type(self).__unicode__(self)
  46. except AttributeError as e:
  47. return type(self).__str__(self)
  48. long = int
  49. else:
  50. PY2 = True
  51. PY3 = False
  52. if 'Acquisition._Acquisition' not in sys.modules:
  53. CAPI = False
  54. else:
  55. CAPI = True
  56. MIXIN_POST_CLASS_DEFINITION = True
  57. try:
  58. class Plain(object):
  59. pass
  60. Plain.__bases__ = (ExtensionClass.Base, )
  61. except TypeError:
  62. # Not supported
  63. MIXIN_POST_CLASS_DEFINITION = False
  64. AQ_PARENT = unicode('aq_parent')
  65. UNICODE_WAS_CALLED = unicode('unicode was called')
  66. STR_WAS_CALLED = unicode('str was called')
  67. TRUE = unicode('True')
  68. class I(Implicit):
  69. def __init__(self, id):
  70. self.id = id
  71. def __repr__(self):
  72. return self.id
  73. class E(Explicit):
  74. def __init__(self, id):
  75. self.id = id
  76. def __repr__(self):
  77. return self.id
  78. class Location(object):
  79. __parent__ = None
  80. class ECLocation(ExtensionClass.Base):
  81. __parent__ = None
  82. def show(x):
  83. print(showaq(x).strip())
  84. def showaq(m_self, indent=''):
  85. rval = ''
  86. obj = m_self
  87. base = getattr(obj, 'aq_base', obj)
  88. try:
  89. id = base.id
  90. except Exception:
  91. id = str(base)
  92. try:
  93. id = id()
  94. except Exception:
  95. pass
  96. if hasattr(obj, 'aq_self'):
  97. if hasattr(obj.aq_self, 'aq_self'):
  98. rval = rval + indent + "(" + id + ")\n"
  99. rval = rval + indent + "| \\\n"
  100. rval = rval + showaq(obj.aq_self, '| ' + indent)
  101. rval = rval + indent + "|\n"
  102. rval = rval + showaq(obj.aq_parent, indent)
  103. elif hasattr(obj, 'aq_parent'):
  104. rval = rval + indent + id + "\n"
  105. rval = rval + indent + "|\n"
  106. rval = rval + showaq(obj.aq_parent, indent)
  107. else:
  108. rval = rval + indent + id + "\n"
  109. return rval
  110. class TestStory(unittest.TestCase):
  111. def test_story(self):
  112. # Acquisition is a mechanism that allows objects to obtain
  113. # attributes from their environment. It is similar to inheritence,
  114. # except that, rather than traversing an inheritence hierarchy
  115. # to obtain attributes, a containment hierarchy is traversed.
  116. # The "ExtensionClass":ExtensionClass.html. release includes mix-in
  117. # extension base classes that can be used to add acquisition as a
  118. # feature to extension subclasses. These mix-in classes use the
  119. # context-wrapping feature of ExtensionClasses to implement
  120. # acquisition. Consider the following example:
  121. class C(ExtensionClass.Base):
  122. color = 'red'
  123. class A(Implicit):
  124. def report(self):
  125. return self.color
  126. a = A()
  127. c = C()
  128. c.a = a
  129. self.assertEqual(c.a.report(), 'red')
  130. d = C()
  131. d.color = 'green'
  132. d.a = a
  133. self.assertEqual(d.a.report(), 'green')
  134. with self.assertRaises(AttributeError):
  135. a.report()
  136. # The class 'A' inherits acquisition behavior from 'Implicit'.
  137. # The object, 'a', "has" the color of objects 'c' and 'd'
  138. # when it is accessed through them, but it has no color by itself.
  139. # The object 'a' obtains attributes from it's environment, where
  140. # it's environment is defined by the access path used to reach 'a'.
  141. # Acquisition wrappers
  142. # When an object that supports acquisition is accessed through
  143. # an extension class instance, a special object, called an
  144. # acquisition wrapper, is returned. In the example above, the
  145. # expression 'c.a' returns an acquisition wrapper that
  146. # contains references to both 'c' and 'a'. It is this wrapper
  147. # that performs attribute lookup in 'c' when an attribute
  148. # cannot be found in 'a'.
  149. # Aquisition wrappers provide access to the wrapped objects
  150. # through the attributes 'aq_parent', 'aq_self', 'aq_base'.
  151. # In the example above, the expressions:
  152. self.assertIs(c.a.aq_parent, c)
  153. # and:
  154. self.assertIs(c.a.aq_self, a)
  155. # both evaluate to true, but the expression:
  156. self.assertIsNot(c.a, a)
  157. # evaluates to false, because the expression 'c.a' evaluates
  158. # to an acquisition wrapper around 'c' and 'a', not 'a' itself.
  159. # The attribute 'aq_base' is similar to 'aq_self'. Wrappers may be
  160. # nested and 'aq_self' may be a wrapped object. The 'aq_base'
  161. # attribute is the underlying object with all wrappers removed.
  162. # Acquisition Control
  163. # Two styles of acquisition are supported in the current
  164. # ExtensionClass release, implicit and explicit aquisition.
  165. # Implicit acquisition
  166. # Implicit acquisition is so named because it searches for
  167. # attributes from the environment automatically whenever an
  168. # attribute cannot be obtained directly from an object or
  169. # through inheritence.
  170. # An attribute may be implicitly acquired if it's name does
  171. # not begin with an underscore, '_'.
  172. # To support implicit acquisition, an object should inherit
  173. # from the mix-in class 'Implicit'.
  174. # Explicit Acquisition
  175. # When explicit acquisition is used, attributes are not
  176. # automatically obtained from the environment. Instead, the
  177. # method 'aq_aquire' must be used, as in:
  178. # print(c.a.aq_acquire('color'))
  179. # To support explicit acquisition, an object should inherit
  180. # from the mix-in class 'Explicit'.
  181. # Controlled Acquisition
  182. # A class (or instance) can provide attribute by attribute control
  183. # over acquisition. This is done by:
  184. # - subclassing from 'Explicit', and
  185. # - setting all attributes that should be acquired to the special
  186. # value: 'Acquisition.Acquired'. Setting an attribute to this
  187. # value also allows inherited attributes to be overridden with
  188. # acquired ones.
  189. # For example, in:
  190. class E(Explicit):
  191. id = 1
  192. secret = 2
  193. color = Acquisition.Acquired
  194. __roles__ = Acquisition.Acquired
  195. # The *only* attributes that are automatically acquired from
  196. # containing objects are 'color', and '__roles__'.
  197. c = C()
  198. c.foo = 'foo'
  199. c.e = E()
  200. self.assertEqual(c.e.color, 'red')
  201. with self.assertRaises(AttributeError):
  202. c.e.foo
  203. # Note also that the '__roles__' attribute is acquired even
  204. # though it's name begins with an underscore:
  205. c.__roles__ = 'Manager', 'Member'
  206. self.assertEqual(c.e.__roles__, ('Manager', 'Member'))
  207. # In fact, the special 'Acquisition.Acquired' value can be used
  208. # in 'Implicit' objects to implicitly acquire
  209. # selected objects that smell like private objects.
  210. class I(Implicit):
  211. __roles__ = Acquisition.Acquired
  212. c.x = C()
  213. with self.assertRaises(AttributeError):
  214. c.x.__roles__
  215. c.x = I()
  216. self.assertEqual(c.x.__roles__, ('Manager', 'Member'))
  217. # Filtered Acquisition
  218. # The acquisition method, 'aq_acquire', accepts two optional
  219. # arguments. The first of the additional arguments is a
  220. # "filtering" function that is used when considering whether to
  221. # acquire an object. The second of the additional arguments is an
  222. # object that is passed as extra data when calling the filtering
  223. # function and which defaults to 'None'.
  224. # The filter function is called with five arguments:
  225. # - The object that the 'aq_acquire' method was called on,
  226. # - The object where an object was found,
  227. # - The name of the object, as passed to 'aq_acquire',
  228. # - The object found, and
  229. # - The extra data passed to 'aq_acquire'.
  230. # If the filter returns a true object that the object found is
  231. # returned, otherwise, the acquisition search continues.
  232. # For example, in:
  233. class HandyForTesting(object):
  234. def __init__(self, name):
  235. self.name = name
  236. def __str__(self):
  237. return "%s(%s)" % (self.name, self.__class__.__name__)
  238. __repr__ = __str__
  239. class E(Explicit, HandyForTesting):
  240. pass
  241. class Nice(HandyForTesting):
  242. isNice = 1
  243. def __str__(self):
  244. return HandyForTesting.__str__(self) + ' and I am nice!'
  245. __repr__ = __str__
  246. a = E('a')
  247. a.b = E('b')
  248. a.b.c = E('c')
  249. a.p = Nice('spam')
  250. a.b.p = E('p')
  251. def find_nice(self, ancestor, name, object, extra):
  252. return hasattr(object, 'isNice') and object.isNice
  253. self.assertEqual(str(a.b.c.aq_acquire('p', find_nice)),
  254. 'spam(Nice) and I am nice!')
  255. # The filtered acquisition in the last line skips over the first
  256. # attribute it finds with the name 'p', because the attribute
  257. # doesn't satisfy the condition given in the filter.
  258. # Acquisition and methods
  259. # Python methods of objects that support acquisition can use
  260. # acquired attributes as in the 'report' method of the first example
  261. # above. When a Python method is called on an object that is
  262. # wrapped by an acquisition wrapper, the wrapper is passed to the
  263. # method as the first argument. This rule also applies to
  264. # user-defined method types and to C methods defined in pure mix-in
  265. # classes.
  266. # Unfortunately, C methods defined in extension base classes that
  267. # define their own data structures, cannot use aquired attributes at
  268. # this time. This is because wrapper objects do not conform to the
  269. # data structures expected by these methods.
  270. # Acquiring Acquiring objects
  271. # Consider the following example:
  272. class C(Implicit):
  273. def __init__(self, name):
  274. self.name = name
  275. def __str__(self):
  276. return "%s(%s)" % (self.name, self.__class__.__name__)
  277. __repr__ = __str__
  278. a = C("a")
  279. a.b = C("b")
  280. a.b.pref = "spam"
  281. a.b.c = C("c")
  282. a.b.c.color = "red"
  283. a.b.c.pref = "eggs"
  284. a.x = C("x")
  285. o = a.b.c.x
  286. # The expression 'o.color' might be expected to return '"red"'. In
  287. # earlier versions of ExtensionClass, however, this expression
  288. # failed. Acquired acquiring objects did not acquire from the
  289. # environment they were accessed in, because objects were only
  290. # wrapped when they were first found, and were not rewrapped as they
  291. # were passed down the acquisition tree.
  292. # In the current release of ExtensionClass, the expression "o.color"
  293. # does indeed return '"red"'.
  294. self.assertEqual(o.color, 'red')
  295. # When searching for an attribute in 'o', objects are searched in
  296. # the order 'x', 'a', 'b', 'c'. So, for example, the expression,
  297. # 'o.pref' returns '"spam"', not '"eggs"':
  298. self.assertEqual(o.pref, 'spam')
  299. # In earlier releases of ExtensionClass, the attempt to get the
  300. # 'pref' attribute from 'o' would have failed.
  301. # If desired, the current rules for looking up attributes in complex
  302. # expressions can best be understood through repeated application of
  303. # the '__of__' method:
  304. # 'a.x' -- 'x.__of__(a)'
  305. # 'a.b' -- 'b.__of__(a)'
  306. # 'a.b.x' -- 'x.__of__(a).__of__(b.__of__(a))'
  307. # 'a.b.c' -- 'c.__of__(b.__of__(a))'
  308. # 'a.b.c.x' --
  309. # 'x.__of__(a).__of__(b.__of__(a)).__of__(c.__of__(b.__of__(a)))'
  310. # and by keeping in mind that attribute lookup in a wrapper
  311. # is done by trying to lookup the attribute in the wrapped object
  312. # first and then in the parent object. In the expressions above
  313. # involving the '__of__' method, lookup proceeds from left to right.
  314. # Note that heuristics are used to avoid most of the repeated
  315. # lookups. For example, in the expression: 'a.b.c.x.foo', the object
  316. # 'a' is searched no more than once, even though it is wrapped three
  317. # times.
  318. def test_unwrapped():
  319. """
  320. >>> c = I('unwrapped')
  321. >>> show(c)
  322. unwrapped
  323. >>> try:
  324. ... c.aq_parent
  325. ... except AttributeError:
  326. ... pass
  327. ... else:
  328. ... raise AssertionError('AttributeError not raised.')
  329. >>> try:
  330. ... c.__parent__
  331. ... except AttributeError:
  332. ... pass
  333. ... else:
  334. ... raise AssertionError('AttributeError not raised.')
  335. >>> aq_acquire(c, 'id')
  336. 'unwrapped'
  337. >>> try:
  338. ... aq_acquire(c, 'x')
  339. ... except AttributeError:
  340. ... pass
  341. ... else:
  342. ... raise AssertionError('AttributeError not raised.')
  343. >>> aq_acquire(c, 'id',
  344. ... lambda searched, parent, name, ob, extra: extra)
  345. Traceback (most recent call last):
  346. ...
  347. AttributeError: id
  348. >>> aq_acquire(c, 'id',
  349. ... lambda searched, parent, name, ob, extra: extra,
  350. ... 1)
  351. 'unwrapped'
  352. >>> aq_base(c) is c
  353. 1
  354. >>> aq_chain(c)
  355. [unwrapped]
  356. >>> aq_chain(c, 1)
  357. [unwrapped]
  358. >>> aq_get(c, 'id')
  359. 'unwrapped'
  360. >>> try:
  361. ... aq_get(c, 'x')
  362. ... except AttributeError:
  363. ... pass
  364. ... else:
  365. ... raise AssertionError('AttributeError not raised.')
  366. >>> aq_get(c, 'x', 'foo')
  367. 'foo'
  368. >>> aq_get(c, 'x', 'foo', 1)
  369. 'foo'
  370. >>> aq_inner(c) is c
  371. 1
  372. >>> aq_parent(c)
  373. >>> aq_self(c) is c
  374. 1
  375. """
  376. def test_simple():
  377. """
  378. >>> a = I('a')
  379. >>> a.y = 42
  380. >>> a.b = I('b')
  381. >>> a.b.c = I('c')
  382. >>> show(a.b.c)
  383. c
  384. |
  385. b
  386. |
  387. a
  388. >>> show(a.b.c.aq_parent)
  389. b
  390. |
  391. a
  392. >>> show(a.b.c.aq_self)
  393. c
  394. >>> show(a.b.c.aq_base)
  395. c
  396. >>> show(a.b.c.aq_inner)
  397. c
  398. |
  399. b
  400. |
  401. a
  402. >>> a.b.c.y
  403. 42
  404. >>> a.b.c.aq_chain
  405. [c, b, a]
  406. >>> a.b.c.aq_inContextOf(a)
  407. 1
  408. >>> a.b.c.aq_inContextOf(a.b)
  409. 1
  410. >>> a.b.c.aq_inContextOf(a.b.c)
  411. 1
  412. >>> aq_inContextOf(a.b.c, a)
  413. 1
  414. >>> aq_inContextOf(a.b.c, a.b)
  415. 1
  416. >>> aq_inContextOf(a.b.c, a.b.c)
  417. 1
  418. >>> a.b.c.aq_acquire('y')
  419. 42
  420. >>> a.b.c.aq_acquire('id')
  421. 'c'
  422. >>> try:
  423. ... a.b.c.aq_acquire('x')
  424. ... except AttributeError:
  425. ... pass
  426. ... else:
  427. ... raise AssertionError('AttributeError not raised.')
  428. >>> a.b.c.aq_acquire('id',
  429. ... lambda searched, parent, name, ob, extra: extra)
  430. Traceback (most recent call last):
  431. ...
  432. AttributeError: id
  433. >>> aq_acquire(a.b.c, 'id',
  434. ... lambda searched, parent, name, ob, extra: extra,
  435. ... 1)
  436. 'c'
  437. >>> aq_acquire(a.b.c, 'id')
  438. 'c'
  439. >>> try:
  440. ... aq_acquire(a.b.c, 'x')
  441. ... except AttributeError:
  442. ... pass
  443. ... else:
  444. ... raise AssertionError('AttributeError not raised.')
  445. >>> aq_acquire(a.b.c, 'y')
  446. 42
  447. >>> aq_acquire(a.b.c, 'id',
  448. ... lambda searched, parent, name, ob, extra: extra)
  449. Traceback (most recent call last):
  450. ...
  451. AttributeError: id
  452. >>> aq_acquire(a.b.c, 'id',
  453. ... lambda searched, parent, name, ob, extra: extra,
  454. ... 1)
  455. 'c'
  456. >>> show(aq_base(a.b.c))
  457. c
  458. >>> aq_chain(a.b.c)
  459. [c, b, a]
  460. >>> aq_chain(a.b.c, 1)
  461. [c, b, a]
  462. >>> aq_get(a.b.c, 'id')
  463. 'c'
  464. >>> try:
  465. ... aq_get(a.b.c, 'x')
  466. ... except AttributeError:
  467. ... pass
  468. ... else:
  469. ... raise AssertionError('AttributeError not raised.')
  470. >>> aq_get(a.b.c, 'x', 'foo')
  471. 'foo'
  472. >>> aq_get(a.b.c, 'x', 'foo', 1)
  473. 'foo'
  474. >>> show(aq_inner(a.b.c))
  475. c
  476. |
  477. b
  478. |
  479. a
  480. >>> show(aq_parent(a.b.c))
  481. b
  482. |
  483. a
  484. >>> show(aq_self(a.b.c))
  485. c
  486. A wrapper's __parent__ attribute (which is equivalent to its
  487. aq_parent attribute) points to the Acquisition parent.
  488. >>> a.b.c.__parent__ == a.b.c.aq_parent
  489. True
  490. >>> a.b.c.__parent__ == a.b
  491. True
  492. """
  493. def test_muliple():
  494. r"""
  495. >>> a = I('a')
  496. >>> a.color = 'red'
  497. >>> a.a1 = I('a1')
  498. >>> a.a1.color = 'green'
  499. >>> a.a1.a11 = I('a11')
  500. >>> a.a2 = I('a2')
  501. >>> a.a2.a21 = I('a21')
  502. >>> show(a.a1.a11.a2.a21)
  503. a21
  504. |
  505. (a2)
  506. | \
  507. | (a2)
  508. | | \
  509. | | a2
  510. | | |
  511. | | a
  512. | |
  513. | a1
  514. | |
  515. | a
  516. |
  517. a11
  518. |
  519. a1
  520. |
  521. a
  522. >>> a.a1.a11.a2.a21.color
  523. 'red'
  524. >>> show(a.a1.a11.a2.a21.aq_parent)
  525. (a2)
  526. | \
  527. | (a2)
  528. | | \
  529. | | a2
  530. | | |
  531. | | a
  532. | |
  533. | a1
  534. | |
  535. | a
  536. |
  537. a11
  538. |
  539. a1
  540. |
  541. a
  542. >>> show(a.a1.a11.a2.a21.aq_parent.aq_parent)
  543. a11
  544. |
  545. a1
  546. |
  547. a
  548. >>> show(a.a1.a11.a2.a21.aq_self)
  549. a21
  550. >>> show(a.a1.a11.a2.a21.aq_parent.aq_self)
  551. (a2)
  552. | \
  553. | a2
  554. | |
  555. | a
  556. |
  557. a1
  558. |
  559. a
  560. >>> show(a.a1.a11.a2.a21.aq_base)
  561. a21
  562. >>> show(a.a1.a11.a2.a21.aq_inner)
  563. a21
  564. |
  565. (a2)
  566. | \
  567. | (a2)
  568. | | \
  569. | | a2
  570. | | |
  571. | | a
  572. | |
  573. | a1
  574. | |
  575. | a
  576. |
  577. a11
  578. |
  579. a1
  580. |
  581. a
  582. >>> show(a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner)
  583. a2
  584. |
  585. a
  586. >>> show(a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner.aq_parent)
  587. a
  588. >>> a.a1.a11.a2.a21.aq_chain
  589. [a21, a2, a11, a1, a]
  590. >>> a.a1.a11.a2.a21.aq_inContextOf(a)
  591. 1
  592. >>> a.a1.a11.a2.a21.aq_inContextOf(a.a2)
  593. 1
  594. >>> a.a1.a11.a2.a21.aq_inContextOf(a.a1)
  595. 0
  596. >>> a.a1.a11.a2.a21.aq_acquire('color')
  597. 'red'
  598. >>> a.a1.a11.a2.a21.aq_acquire('id')
  599. 'a21'
  600. >>> a.a1.a11.a2.a21.aq_acquire('color',
  601. ... lambda ob, parent, name, v, extra: extra)
  602. Traceback (most recent call last):
  603. ...
  604. AttributeError: color
  605. >>> a.a1.a11.a2.a21.aq_acquire('color',
  606. ... lambda ob, parent, name, v, extra: extra, 1)
  607. 'red'
  608. >>> a.a1.y = 42
  609. >>> a.a1.a11.a2.a21.aq_acquire('y')
  610. 42
  611. >>> try:
  612. ... a.a1.a11.a2.a21.aq_acquire('y', containment=1)
  613. ... except AttributeError:
  614. ... pass
  615. ... else:
  616. ... raise AssertionError('AttributeError not raised.')
  617. Much of the same, but with methods:
  618. >>> show(aq_parent(a.a1.a11.a2.a21))
  619. (a2)
  620. | \
  621. | (a2)
  622. | | \
  623. | | a2
  624. | | |
  625. | | a
  626. | |
  627. | a1
  628. | |
  629. | a
  630. |
  631. a11
  632. |
  633. a1
  634. |
  635. a
  636. >>> show(aq_parent(a.a1.a11.a2.a21.aq_parent))
  637. a11
  638. |
  639. a1
  640. |
  641. a
  642. >>> show(aq_self(a.a1.a11.a2.a21))
  643. a21
  644. >>> show(aq_self(a.a1.a11.a2.a21.aq_parent))
  645. (a2)
  646. | \
  647. | a2
  648. | |
  649. | a
  650. |
  651. a1
  652. |
  653. a
  654. >>> show(aq_base(a.a1.a11.a2.a21))
  655. a21
  656. >>> show(aq_inner(a.a1.a11.a2.a21))
  657. a21
  658. |
  659. (a2)
  660. | \
  661. | (a2)
  662. | | \
  663. | | a2
  664. | | |
  665. | | a
  666. | |
  667. | a1
  668. | |
  669. | a
  670. |
  671. a11
  672. |
  673. a1
  674. |
  675. a
  676. >>> show(aq_inner(a.a1.a11.a2.a21.aq_inner.aq_parent))
  677. a2
  678. |
  679. a
  680. >>> show(aq_parent(
  681. ... a.a1.a11.a2.a21.aq_inner.aq_parent.aq_inner))
  682. a
  683. >>> aq_chain(a.a1.a11.a2.a21)
  684. [a21, a2, a11, a1, a]
  685. >>> aq_chain(a.a1.a11.a2.a21, 1)
  686. [a21, a2, a]
  687. >>> aq_acquire(a.a1.a11.a2.a21, 'color')
  688. 'red'
  689. >>> aq_acquire(a.a1.a11.a2.a21, 'id')
  690. 'a21'
  691. >>> aq_acquire(a.a1.a11.a2.a21, 'color',
  692. ... lambda ob, parent, name, v, extra: extra)
  693. Traceback (most recent call last):
  694. ...
  695. AttributeError: color
  696. >>> aq_acquire(a.a1.a11.a2.a21, 'color',
  697. ... lambda ob, parent, name, v, extra: extra, 1)
  698. 'red'
  699. >>> a.a1.y = 42
  700. >>> aq_acquire(a.a1.a11.a2.a21, 'y')
  701. 42
  702. >>> try:
  703. ... aq_acquire(a.a1.a11.a2.a21, 'y', containment=1)
  704. ... except AttributeError:
  705. ... pass
  706. ... else:
  707. ... raise AssertionError('AttributeError not raised.')
  708. """
  709. def test_pinball():
  710. r"""
  711. >>> a = I('a')
  712. >>> a.a1 = I('a1')
  713. >>> a.a1.a11 = I('a11')
  714. >>> a.a1.a12 = I('a12')
  715. >>> a.a2 = I('a2')
  716. >>> a.a2.a21 = I('a21')
  717. >>> a.a2.a22 = I('a22')
  718. >>> show(a.a1.a11.a1.a12.a2.a21.a2.a22)
  719. a22
  720. |
  721. (a2)
  722. | \
  723. | (a2)
  724. | | \
  725. | | a2
  726. | | |
  727. | | a
  728. | |
  729. | (a2)
  730. | | \
  731. | | (a2)
  732. | | | \
  733. | | | a2
  734. | | | |
  735. | | | a
  736. | | |
  737. | | (a1)
  738. | | | \
  739. | | | (a1)
  740. | | | | \
  741. | | | | a1
  742. | | | | |
  743. | | | | a
  744. | | | |
  745. | | | a1
  746. | | | |
  747. | | | a
  748. | | |
  749. | | a11
  750. | | |
  751. | | a1
  752. | | |
  753. | | a
  754. | |
  755. | a12
  756. | |
  757. | (a1)
  758. | | \
  759. | | (a1)
  760. | | | \
  761. | | | a1
  762. | | | |
  763. | | | a
  764. | | |
  765. | | a1
  766. | | |
  767. | | a
  768. | |
  769. | a11
  770. | |
  771. | a1
  772. | |
  773. | a
  774. |
  775. a21
  776. |
  777. (a2)
  778. | \
  779. | (a2)
  780. | | \
  781. | | a2
  782. | | |
  783. | | a
  784. | |
  785. | (a1)
  786. | | \
  787. | | (a1)
  788. | | | \
  789. | | | a1
  790. | | | |
  791. | | | a
  792. | | |
  793. | | a1
  794. | | |
  795. | | a
  796. | |
  797. | a11
  798. | |
  799. | a1
  800. | |
  801. | a
  802. |
  803. a12
  804. |
  805. (a1)
  806. | \
  807. | (a1)
  808. | | \
  809. | | a1
  810. | | |
  811. | | a
  812. | |
  813. | a1
  814. | |
  815. | a
  816. |
  817. a11
  818. |
  819. a1
  820. |
  821. a
  822. """
  823. def test_explicit():
  824. """
  825. >>> a = E('a')
  826. >>> a.y = 42
  827. >>> a.b = E('b')
  828. >>> a.b.c = E('c')
  829. >>> show(a.b.c)
  830. c
  831. |
  832. b
  833. |
  834. a
  835. >>> show(a.b.c.aq_parent)
  836. b
  837. |
  838. a
  839. >>> show(a.b.c.aq_self)
  840. c
  841. >>> show(a.b.c.aq_base)
  842. c
  843. >>> show(a.b.c.aq_inner)
  844. c
  845. |
  846. b
  847. |
  848. a
  849. >>> a.b.c.y
  850. Traceback (most recent call last):
  851. ...
  852. AttributeError: y
  853. >>> a.b.c.aq_chain
  854. [c, b, a]
  855. >>> a.b.c.aq_inContextOf(a)
  856. 1
  857. >>> a.b.c.aq_inContextOf(a.b)
  858. 1
  859. >>> a.b.c.aq_inContextOf(a.b.c)
  860. 1
  861. >>> a.b.c.aq_acquire('y')
  862. 42
  863. >>> a.b.c.aq_acquire('id')
  864. 'c'
  865. >>> try:
  866. ... a.b.c.aq_acquire('x')
  867. ... except AttributeError:
  868. ... pass
  869. ... else:
  870. ... raise AssertionError('AttributeError not raised.')
  871. >>> a.b.c.aq_acquire('id',
  872. ... lambda searched, parent, name, ob, extra: extra)
  873. Traceback (most recent call last):
  874. ...
  875. AttributeError: id
  876. >>> aq_acquire(a.b.c, 'id',
  877. ... lambda searched, parent, name, ob, extra: extra,
  878. ... 1)
  879. 'c'
  880. >>> aq_acquire(a.b.c, 'id')
  881. 'c'
  882. >>> try:
  883. ... aq_acquire(a.b.c, 'x')
  884. ... except AttributeError:
  885. ... pass
  886. ... else:
  887. ... raise AssertionError('AttributeError not raised.')
  888. >>> aq_acquire(a.b.c, 'y')
  889. 42
  890. >>> aq_acquire(a.b.c, 'id',
  891. ... lambda searched, parent, name, ob, extra: extra)
  892. Traceback (most recent call last):
  893. ...
  894. AttributeError: id
  895. >>> aq_acquire(a.b.c, 'id',
  896. ... lambda searched, parent, name, ob, extra: extra,
  897. ... 1)
  898. 'c'
  899. >>> show(aq_base(a.b.c))
  900. c
  901. >>> aq_chain(a.b.c)
  902. [c, b, a]
  903. >>> aq_chain(a.b.c, 1)
  904. [c, b, a]
  905. >>> aq_get(a.b.c, 'id')
  906. 'c'
  907. >>> try:
  908. ... aq_get(a.b.c, 'x')
  909. ... except AttributeError:
  910. ... pass
  911. ... else:
  912. ... raise AssertionError('AttributeError not raised.')
  913. >>> aq_get(a.b.c, 'y')
  914. 42
  915. >>> aq_get(a.b.c, 'x', 'foo')
  916. 'foo'
  917. >>> aq_get(a.b.c, 'x', 'foo', 1)
  918. 'foo'
  919. >>> show(aq_inner(a.b.c))
  920. c
  921. |
  922. b
  923. |
  924. a
  925. >>> show(aq_parent(a.b.c))
  926. b
  927. |
  928. a
  929. >>> show(aq_self(a.b.c))
  930. c
  931. """
  932. def test_mixed_explicit_and_explicit():
  933. """
  934. >>> a = I('a')
  935. >>> a.y = 42
  936. >>> a.b = E('b')
  937. >>> a.b.z = 3
  938. >>> a.b.c = I('c')
  939. >>> show(a.b.c)
  940. c
  941. |
  942. b
  943. |
  944. a
  945. >>> show(a.b.c.aq_parent)
  946. b
  947. |
  948. a
  949. >>> show(a.b.c.aq_self)
  950. c
  951. >>> show(a.b.c.aq_base)
  952. c
  953. >>> show(a.b.c.aq_inner)
  954. c
  955. |
  956. b
  957. |
  958. a
  959. >>> a.b.c.y
  960. 42
  961. >>> a.b.c.z
  962. 3
  963. >>> a.b.c.aq_chain
  964. [c, b, a]
  965. >>> a.b.c.aq_inContextOf(a)
  966. 1
  967. >>> a.b.c.aq_inContextOf(a.b)
  968. 1
  969. >>> a.b.c.aq_inContextOf(a.b.c)
  970. 1
  971. >>> a.b.c.aq_acquire('y')
  972. 42
  973. >>> a.b.c.aq_acquire('z')
  974. 3
  975. >>> a.b.c.aq_acquire('id')
  976. 'c'
  977. >>> try:
  978. ... a.b.c.aq_acquire('x')
  979. ... except AttributeError:
  980. ... pass
  981. ... else:
  982. ... raise AssertionError('AttributeError not raised.')
  983. >>> a.b.c.aq_acquire('id',
  984. ... lambda searched, parent, name, ob, extra: extra)
  985. Traceback (most recent call last):
  986. ...
  987. AttributeError: id
  988. >>> aq_acquire(a.b.c, 'id',
  989. ... lambda searched, parent, name, ob, extra: extra,
  990. ... 1)
  991. 'c'
  992. >>> aq_acquire(a.b.c, 'id')
  993. 'c'
  994. >>> try:
  995. ... aq_acquire(a.b.c, 'x')
  996. ... except AttributeError:
  997. ... pass
  998. ... else:
  999. ... raise AssertionError('AttributeError not raised.')
  1000. >>> aq_acquire(a.b.c, 'y')
  1001. 42
  1002. >>> aq_acquire(a.b.c, 'id',
  1003. ... lambda searched, parent, name, ob, extra: extra)
  1004. Traceback (most recent call last):
  1005. ...
  1006. AttributeError: id
  1007. >>> aq_acquire(a.b.c, 'id',
  1008. ... lambda searched, parent, name, ob, extra: extra,
  1009. ... 1)
  1010. 'c'
  1011. >>> show(aq_base(a.b.c))
  1012. c
  1013. >>> aq_chain(a.b.c)
  1014. [c, b, a]
  1015. >>> aq_chain(a.b.c, 1)
  1016. [c, b, a]
  1017. >>> aq_get(a.b.c, 'id')
  1018. 'c'
  1019. >>> try:
  1020. ... aq_get(a.b.c, 'x')
  1021. ... except AttributeError:
  1022. ... pass
  1023. ... else:
  1024. ... raise AssertionError('AttributeError not raised.')
  1025. >>> aq_get(a.b.c, 'y')
  1026. 42
  1027. >>> aq_get(a.b.c, 'x', 'foo')
  1028. 'foo'
  1029. >>> aq_get(a.b.c, 'x', 'foo', 1)
  1030. 'foo'
  1031. >>> show(aq_inner(a.b.c))
  1032. c
  1033. |
  1034. b
  1035. |
  1036. a
  1037. >>> show(aq_parent(a.b.c))
  1038. b
  1039. |
  1040. a
  1041. >>> show(aq_self(a.b.c))
  1042. c
  1043. """
  1044. class TestAqAlgorithm(unittest.TestCase):
  1045. def test_AqAlg(self):
  1046. A = I('A')
  1047. B = I('B')
  1048. A.B = B
  1049. A.B.color = 'red'
  1050. C = I('C')
  1051. A.C = C
  1052. D = I('D')
  1053. A.C.D = D
  1054. self.assertEqual(aq_chain(A), [A])
  1055. self.assertEqual(aq_chain(A, 1), [A])
  1056. self.assertEqual(list(map(aq_base, aq_chain(A, 1))), [A])
  1057. self.assertEqual(str(aq_chain(A.C)), str([C, A]))
  1058. self.assertEqual(aq_chain(A.C, 1), [C, A])
  1059. self.assertEqual(list(map(aq_base, aq_chain(A.C, 1))), [C, A])
  1060. self.assertEqual(str(aq_chain(A.C.D)), str([D, C, A]))
  1061. self.assertEqual(aq_chain(A.C.D, 1), [D, C, A])
  1062. self.assertEqual(list(map(aq_base, aq_chain(A.C.D, 1))), [D, C, A])
  1063. self.assertEqual(str(aq_chain(A.B.C)), str([C, B, A]))
  1064. self.assertEqual(aq_chain(A.B.C, 1), [C, A])
  1065. self.assertEqual(list(map(aq_base, aq_chain(A.B.C, 1))), [C, A])
  1066. self.assertEqual(str(aq_chain(A.B.C.D)), str([D, C, B, A]))
  1067. self.assertEqual(aq_chain(A.B.C.D, 1), [D, C, A])
  1068. self.assertEqual(list(map(aq_base, aq_chain(A.B.C.D, 1))), [D, C, A])
  1069. self.assertEqual(A.B.C.D.color, 'red')
  1070. self.assertEqual(aq_get(A.B.C.D, "color", None), 'red')
  1071. self.assertIsNone(aq_get(A.B.C.D, "color", None, 1))
  1072. class TestExplicitAcquisition(unittest.TestCase):
  1073. def test_explicit_acquisition(self):
  1074. from ExtensionClass import Base
  1075. class B(Base):
  1076. color = 'red'
  1077. class A(Explicit):
  1078. def hi(self):
  1079. return self.acquire('color')
  1080. b = B()
  1081. b.a = A()
  1082. self.assertEqual(b.a.hi(), 'red')
  1083. b.a.color = 'green'
  1084. self.assertEqual(b.a.hi(), 'green')
  1085. with self.assertRaises(AttributeError):
  1086. A().hi()
  1087. class TestCreatingWrappers(unittest.TestCase):
  1088. def test_creating_wrappers_directly(self):
  1089. from ExtensionClass import Base
  1090. from Acquisition import ImplicitAcquisitionWrapper
  1091. class B(Base):
  1092. pass
  1093. a = B()
  1094. a.color = 'red'
  1095. a.b = B()
  1096. w = ImplicitAcquisitionWrapper(a.b, a)
  1097. self.assertEqual(w.color, 'red')
  1098. with self.assertRaises(TypeError):
  1099. ImplicitAcquisitionWrapper(a.b)
  1100. # We can reassign aq_parent / __parent__ on a wrapper:
  1101. x = B()
  1102. x.color = 'green'
  1103. w.aq_parent = x
  1104. self.assertEqual(w.color, 'green')
  1105. y = B()
  1106. y.color = 'blue'
  1107. w.__parent__ = y
  1108. self.assertEqual(w.color, 'blue')
  1109. # Note that messing with the wrapper won't in any way affect the
  1110. # wrapped object:
  1111. with self.assertRaises(AttributeError):
  1112. aq_base(w).__parent__
  1113. with self.assertRaises(TypeError):
  1114. ImplicitAcquisitionWrapper()
  1115. with self.assertRaises(TypeError):
  1116. ImplicitAcquisitionWrapper(obj=1)
  1117. class TestPickle(unittest.TestCase):
  1118. def test_cant_pickle_acquisition_wrappers_classic(self):
  1119. import pickle
  1120. class X(object):
  1121. def __getstate__(self):
  1122. return 1
  1123. # We shouldn't be able to pickle wrappers:
  1124. from Acquisition import ImplicitAcquisitionWrapper
  1125. w = ImplicitAcquisitionWrapper(X(), X())
  1126. with self.assertRaises(TypeError):
  1127. pickle.dumps(w)
  1128. # But that's not enough. We need to defeat persistence as well. :)
  1129. # This is tricky. We want to generate the error in __getstate__, not
  1130. # in the attr access, as attribute errors are too-often hidden:
  1131. getstate = w.__getstate__
  1132. with self.assertRaises(TypeError):
  1133. getstate()
  1134. # We shouldn't be able to pickle wrappers:
  1135. from Acquisition import ExplicitAcquisitionWrapper
  1136. w = ExplicitAcquisitionWrapper(X(), X())
  1137. with self.assertRaises(TypeError):
  1138. pickle.dumps(w)
  1139. # But that's not enough. We need to defeat persistence as well. :)
  1140. # This is tricky. We want to generate the error in __getstate__, not
  1141. # in the attr access, as attribute errors are too-often hidden:
  1142. getstate = w.__getstate__
  1143. with self.assertRaises(TypeError):
  1144. getstate()
  1145. def test_cant_pickle_acquisition_wrappers_newstyle(self):
  1146. import pickle
  1147. class X(object):
  1148. def __getstate__(self):
  1149. return 1
  1150. # We shouldn't be able to pickle wrappers:
  1151. from Acquisition import ImplicitAcquisitionWrapper
  1152. w = ImplicitAcquisitionWrapper(X(), X())
  1153. with self.assertRaises(TypeError):
  1154. pickle.dumps(w)
  1155. # But that's not enough. We need to defeat persistence as well. :)
  1156. # This is tricky. We want to generate the error in __getstate__, not
  1157. # in the attr access, as attribute errors are too-often hidden:
  1158. getstate = w.__getstate__
  1159. with self.assertRaises(TypeError):
  1160. getstate()
  1161. # We shouldn't be able to pickle wrappers:
  1162. from Acquisition import ExplicitAcquisitionWrapper
  1163. w = ExplicitAcquisitionWrapper(X(), X())
  1164. with self.assertRaises(TypeError):
  1165. pickle.dumps(w)
  1166. # But that's not enough. We need to defeat persistence as well. :)
  1167. # This is tricky. We want to generate the error in __getstate__, not
  1168. # in the attr access, as attribute errors are too-often hidden:
  1169. getstate = w.__getstate__
  1170. with self.assertRaises(TypeError):
  1171. getstate()
  1172. def test_cant_persist_acquisition_wrappers_classic(self):
  1173. try:
  1174. import cPickle
  1175. except ImportError:
  1176. import pickle as cPickle
  1177. class X(object):
  1178. _p_oid = '1234'
  1179. def __getstate__(self):
  1180. return 1
  1181. # We shouldn't be able to pickle wrappers:
  1182. from Acquisition import ImplicitAcquisitionWrapper
  1183. w = ImplicitAcquisitionWrapper(X(), X())
  1184. with self.assertRaises(TypeError):
  1185. cPickle.dumps(w)
  1186. # Check for pickle protocol one:
  1187. with self.assertRaises(TypeError):
  1188. cPickle.dumps(w, 1)
  1189. # Check custom pickler:
  1190. from io import BytesIO
  1191. file = BytesIO()
  1192. pickler = cPickle.Pickler(file, 1)
  1193. with self.assertRaises(TypeError):
  1194. pickler.dump(w)
  1195. # Check custom pickler with a persistent_id method matching
  1196. # the semantics in ZODB.serialize.ObjectWriter.persistent_id:
  1197. file = BytesIO()
  1198. pickler = cPickle.Pickler(file, 1)
  1199. def persistent_id(obj):
  1200. if not hasattr(obj, '_p_oid'):
  1201. return None
  1202. klass = type(obj)
  1203. oid = obj._p_oid
  1204. if hasattr(klass, '__getnewargs__'):
  1205. # Coverage, make sure it can be called
  1206. assert klass.__getnewargs__(obj) == ()
  1207. return oid
  1208. return 'class_and_oid', klass
  1209. try:
  1210. pickler.inst_persistent_id = persistent_id
  1211. except AttributeError:
  1212. pass
  1213. pickler.persistent_id = persistent_id # PyPy and Py3k
  1214. pickler.dump(w)
  1215. state = file.getvalue()
  1216. self.assertTrue(b'1234' in state)
  1217. self.assertFalse(b'class_and_oid' in state)
  1218. def test_cant_persist_acquisition_wrappers_newstyle(self):
  1219. try:
  1220. import cPickle
  1221. except ImportError:
  1222. import pickle as cPickle
  1223. class X(object):
  1224. _p_oid = '1234'
  1225. def __getstate__(self):
  1226. return 1
  1227. # We shouldn't be able to pickle wrappers:
  1228. from Acquisition import ImplicitAcquisitionWrapper
  1229. w = ImplicitAcquisitionWrapper(X(), X())
  1230. with self.assertRaises(TypeError):
  1231. cPickle.dumps(w)
  1232. # Check for pickle protocol one:
  1233. with self.assertRaises(TypeError):
  1234. cPickle.dumps(w, 1)
  1235. # Check custom pickler:
  1236. from io import BytesIO
  1237. file = BytesIO()
  1238. pickler = cPickle.Pickler(file, 1)
  1239. with self.assertRaises(TypeError):
  1240. pickler.dump(w)
  1241. # Check custom pickler with a persistent_id method matching
  1242. # the semantics in ZODB.serialize.ObjectWriter.persistent_id:
  1243. file = BytesIO()
  1244. pickler = cPickle.Pickler(file, 1)
  1245. def persistent_id(obj):
  1246. if not hasattr(obj, '_p_oid'):
  1247. return None
  1248. klass = type(obj)
  1249. oid = obj._p_oid
  1250. if hasattr(klass, '__getnewargs__'):
  1251. return oid
  1252. return 'class_and_oid', klass
  1253. try:
  1254. pickler.inst_persistent_id = persistent_id
  1255. except AttributeError:
  1256. pass
  1257. pickler.persistent_id = persistent_id # PyPy and Py3k
  1258. pickler.dump(w)
  1259. state = file.getvalue()
  1260. self.assertTrue(b'1234' in state)
  1261. self.assertFalse(b'class_and_oid' in state)
  1262. class TestInterfaces(unittest.TestCase):
  1263. def test_interfaces(self):
  1264. from zope.interface.verify import verifyClass
  1265. # Explicit and Implicit implement IAcquirer:
  1266. from Acquisition.interfaces import IAcquirer
  1267. self.assertTrue(verifyClass(IAcquirer, Explicit))
  1268. self.assertTrue(verifyClass(IAcquirer, Implicit))
  1269. # ExplicitAcquisitionWrapper and ImplicitAcquisitionWrapper implement
  1270. # IAcquisitionWrapper:
  1271. from Acquisition import ExplicitAcquisitionWrapper
  1272. from Acquisition import ImplicitAcquisitionWrapper
  1273. from Acquisition.interfaces import IAcquisitionWrapper
  1274. self.assertTrue(
  1275. verifyClass(IAcquisitionWrapper, ExplicitAcquisitionWrapper))
  1276. self.assertTrue(
  1277. verifyClass(IAcquisitionWrapper, ImplicitAcquisitionWrapper))
  1278. class TestMixin(unittest.TestCase):
  1279. @unittest.skipUnless(MIXIN_POST_CLASS_DEFINITION,
  1280. 'Changing __bases__ is not supported.')
  1281. def test_mixin_post_class_definition(self):
  1282. # Assigning to __bases__ is difficult under some versions of python.
  1283. # PyPy usually lets it, but CPython (3 esp) may not.
  1284. # In this example, you get:
  1285. # "TypeError: __bases__ assignment:
  1286. # 'Base' deallocator differs from 'object'"
  1287. # I don't know what the workaround is; the old one of using a dummy
  1288. # superclass no longer works. See http://bugs.python.org/issue672115
  1289. # Mixing in Base after class definition doesn't break anything,
  1290. # but also doesn't result in any wrappers.
  1291. from ExtensionClass import Base
  1292. class Plain(object):
  1293. pass
  1294. self.assertEqual(Plain.__bases__, (object, ))
  1295. Plain.__bases__ = (Base, )
  1296. self.assertIsInstance(Plain(), Base)
  1297. # Even after mixing in that base, when we request such an object
  1298. # from an implicit acquiring base, it doesn't come out wrapped:
  1299. class I(Implicit):
  1300. pass
  1301. root = I()
  1302. root.a = I()
  1303. root.a.b = Plain()
  1304. self.assertIsInstance(root.a.b, Plain)
  1305. # This is because after the mixin, even though Plain is-a Base,
  1306. # it's still not an Explicit/Implicit acquirer and provides
  1307. # neither the `__of__` nor `__get__` methods necessary.
  1308. # `__get__` is added as a consequence of
  1309. # `__of__` at class creation time):
  1310. self.assertFalse(hasattr(Plain, '__get__'))
  1311. self.assertFalse(hasattr(Plain, '__of__'))
  1312. def test_mixin_base(self):
  1313. # We can mix-in Base as part of multiple inheritance.
  1314. from ExtensionClass import Base
  1315. class MyBase(object):
  1316. pass
  1317. class MixedIn(Base, MyBase):
  1318. pass
  1319. self.assertEqual(MixedIn.__bases__, (Base, MyBase))
  1320. self.assertIsInstance(MixedIn(), Base)
  1321. # Because it's not an acquiring object and doesn't provide `__of__`
  1322. # or `__get__`, when accessed from implicit contexts it doesn't come
  1323. # out wrapped:
  1324. class I(Implicit):
  1325. pass
  1326. root = I()
  1327. root.a = I()
  1328. root.a.b = MixedIn()
  1329. self.assertIsInstance(root.a.b, MixedIn)
  1330. # This is because after the mixin, even though Plain is-a Base,
  1331. # it doesn't provide the `__of__` method used for wrapping, and so
  1332. # the class definition code that would add the `__get__` method also
  1333. # doesn't run:
  1334. self.assertFalse(hasattr(MixedIn, '__of__'))
  1335. self.assertFalse(hasattr(MixedIn, '__get__'))
  1336. class TestGC(unittest.TestCase):
  1337. # Tests both `__del__` being called and GC collection.
  1338. # Note that PyPy always reports 0 collected objects even
  1339. # though we can see its finalizers run.
  1340. # Not PyPy
  1341. SUPPORTS_GC_THRESHOLD = hasattr(gc, 'get_threshold')
  1342. if SUPPORTS_GC_THRESHOLD:
  1343. def setUp(self):
  1344. self.thresholds = gc.get_threshold()
  1345. gc.set_threshold(0)
  1346. def tearDown(self):
  1347. gc.set_threshold(*self.thresholds)
  1348. def test_Basic_gc(self):
  1349. # Test to make sure that EC instances participate in GC.
  1350. from ExtensionClass import Base
  1351. for B in I, E:
  1352. counter = [0]
  1353. class C1(B):
  1354. pass
  1355. class C2(Base):
  1356. def __del__(self, counter=counter):
  1357. counter[0] += 1
  1358. a = C1('a')
  1359. a.b = C1('a.b')
  1360. a.b.a = a
  1361. a.b.c = C2()
  1362. gc.collect()
  1363. del a
  1364. removed = gc.collect()
  1365. if self.SUPPORTS_GC_THRESHOLD:
  1366. self.assertTrue(removed > 0)
  1367. self.assertEqual(counter[0], 1)
  1368. def test_Wrapper_gc(self):
  1369. # Test to make sure that EC instances participate in GC.
  1370. for B in I, E:
  1371. counter = [0]
  1372. class C(object):
  1373. def __del__(self, counter=counter):
  1374. counter[0] += 1
  1375. a = B('a')
  1376. a.b = B('b')
  1377. a.a_b = a.b # circular reference through wrapper
  1378. a.b.c = C()
  1379. gc.collect()
  1380. del a
  1381. removed = gc.collect()
  1382. if self.SUPPORTS_GC_THRESHOLD:
  1383. self.assertTrue(removed > 0)
  1384. self.assertEqual(counter[0], 1)
  1385. def test_container_proxying():
  1386. """Make sure that recent python container-related slots are proxied.
  1387. >>> import sys
  1388. >>> class Impl(Implicit):
  1389. ... pass
  1390. >>> class C(Implicit):
  1391. ... def __getitem__(self, key):
  1392. ... if isinstance(key, slice):
  1393. ... print('slicing...')
  1394. ... return (key.start,key.stop)
  1395. ... print('getitem', key)
  1396. ... if key == 4:
  1397. ... raise IndexError
  1398. ... return key
  1399. ... def __contains__(self, key):
  1400. ... print('contains', repr(key))
  1401. ... return key == 5
  1402. ... def __iter__(self):
  1403. ... print('iterating...')
  1404. ... return iter((42,))
  1405. ... def __getslice__(self, start, end):
  1406. ... print('slicing...')
  1407. ... return (start, end)
  1408. The naked class behaves like this:
  1409. >>> c = C()
  1410. >>> 3 in c
  1411. contains 3
  1412. False
  1413. >>> 5 in c
  1414. contains 5
  1415. True
  1416. >>> list(c)
  1417. iterating...
  1418. [42]
  1419. >>> c[5:10]
  1420. slicing...
  1421. (5, 10)
  1422. >>> c[5:] == (5, sys.maxsize if PY2 else None)
  1423. slicing...
  1424. True
  1425. Let's put c in the context of i:
  1426. >>> i = Impl()
  1427. >>> i.c = c
  1428. Now check that __contains__ is properly used:
  1429. >>> 3 in i.c # c.__of__(i)
  1430. contains 3
  1431. False
  1432. >>> 5 in i.c
  1433. contains 5
  1434. True
  1435. >>> list(i.c)
  1436. iterating...
  1437. [42]
  1438. >>> i.c[5:10]
  1439. slicing...
  1440. (5, 10)
  1441. >>> i.c[5:] == (5, sys.maxsize if PY2 else None)
  1442. slicing...
  1443. True
  1444. Let's let's test the same again with an explicit wrapper:
  1445. >>> class Impl(Explicit):
  1446. ... pass
  1447. >>> class C(Explicit):
  1448. ... def __getitem__(self, key):
  1449. ... if isinstance(key, slice):
  1450. ... print('slicing...')
  1451. ... return (key.start,key.stop)
  1452. ... print('getitem', key)
  1453. ... if key == 4:
  1454. ... raise IndexError
  1455. ... return key
  1456. ... def __contains__(self, key):
  1457. ... print('contains', repr(key))
  1458. ... return key == 5
  1459. ... def __iter__(self):
  1460. ... print('iterating...')
  1461. ... return iter((42,))
  1462. ... def __getslice__(self, start, end):
  1463. ... print('slicing...')
  1464. ... return (start, end)
  1465. The naked class behaves like this:
  1466. >>> c = C()
  1467. >>> 3 in c
  1468. contains 3
  1469. False
  1470. >>> 5 in c
  1471. contains 5
  1472. True
  1473. >>> list(c)
  1474. iterating...
  1475. [42]
  1476. >>> c[5:10]
  1477. slicing...
  1478. (5, 10)
  1479. >>> c[5:] == (5, sys.maxsize if PY2 else None)
  1480. slicing...
  1481. True
  1482. Let's put c in the context of i:
  1483. >>> i = Impl()
  1484. >>> i.c = c
  1485. Now check that __contains__ is properly used:
  1486. >>> 3 in i.c # c.__of__(i)
  1487. contains 3
  1488. False
  1489. >>> 5 in i.c
  1490. contains 5
  1491. True
  1492. >>> list(i.c)
  1493. iterating...
  1494. [42]
  1495. >>> i.c[5:10]
  1496. slicing...
  1497. (5, 10)
  1498. >>> i.c[5:] == (5, sys.maxsize if PY2 else None)
  1499. slicing...
  1500. True
  1501. Next let's check that the wrapper's __iter__ proxy falls back
  1502. to using the object's __getitem__ if it has no __iter__. See
  1503. https://bugs.launchpad.net/zope2/+bug/360761 .
  1504. >>> class C(Implicit):
  1505. ... l=[1,2,3]
  1506. ... def __getitem__(self, i):
  1507. ... return self.l[i]
  1508. >>> c1 = C()
  1509. >>> type(iter(c1)) #doctest: +ELLIPSIS
  1510. <... '...iterator'>
  1511. >>> list(c1)
  1512. [1, 2, 3]
  1513. >>> c2 = C().__of__(c1)
  1514. >>> type(iter(c2)) #doctest: +ELLIPSIS
  1515. <... '...iterator'>
  1516. >>> list(c2)
  1517. [1, 2, 3]
  1518. The __iter__proxy should also pass the wrapped object as self to
  1519. the __iter__ of objects defining __iter__:
  1520. >>> class C(Implicit):
  1521. ... def __iter__(self):
  1522. ... print('iterating...')
  1523. ... for i in range(5):
  1524. ... yield i, self.aq_parent.name
  1525. >>> c = C()
  1526. >>> i = Impl()
  1527. >>> i.c = c
  1528. >>> i.name = 'i'
  1529. >>> list(i.c)
  1530. iterating...
  1531. [(0, 'i'), (1, 'i'), (2, 'i'), (3, 'i'), (4, 'i')]
  1532. And it should pass the wrapped object as self to
  1533. the __getitem__ of objects without an __iter__:
  1534. >>> class C(Implicit):
  1535. ... def __getitem__(self, i):
  1536. ... return self.aq_parent.l[i]
  1537. >>> c = C()
  1538. >>> i = Impl()
  1539. >>> i.c = c
  1540. >>> i.l = range(5)
  1541. >>> list(i.c)
  1542. [0, 1, 2, 3, 4]
  1543. Finally let's make sure errors are still correctly raised after having
  1544. to use a modified version of `PyObject_GetIter` for iterator support:
  1545. >>> class C(Implicit):
  1546. ... pass
  1547. >>> c = C()
  1548. >>> i = Impl()
  1549. >>> i.c = c
  1550. >>> list(i.c) #doctest: +ELLIPSIS
  1551. Traceback (most recent call last):
  1552. ...
  1553. TypeError: ...iter...
  1554. >>> class C(Implicit):
  1555. ... def __iter__(self):
  1556. ... return [42]
  1557. >>> c = C()
  1558. >>> i = Impl()
  1559. >>> i.c = c
  1560. >>> list(i.c) #doctest: +ELLIPSIS
  1561. Traceback (most recent call last):
  1562. ...
  1563. TypeError: iter() returned non-iterator...
  1564. """
  1565. class TestAqParentParentInteraction(unittest.TestCase):
  1566. def test___parent__no_wrappers(self):
  1567. # Acquisition also works with objects that aren't wrappers, as long
  1568. # as they have __parent__ pointers. Let's take a hierarchy like
  1569. # z --isParent--> y --isParent--> x:
  1570. x = Location()
  1571. y = Location()
  1572. z = Location()
  1573. x.__parent__ = y
  1574. y.__parent__ = z
  1575. # and some attributes that we want to acquire:
  1576. x.hello = 'world'
  1577. y.foo = 42
  1578. z.foo = 43 # this should not be found
  1579. z.bar = 3.145
  1580. # ``aq_acquire`` works as we know it from implicit/acquisition
  1581. # wrappers:
  1582. self.assertEqual(aq_acquire(x, 'hello'), 'world')
  1583. self.assertEqual(aq_acquire(x, 'foo'), 42)
  1584. self.assertEqual(aq_acquire(x, 'bar'), 3.145)
  1585. # as does ``aq_get``:
  1586. self.assertEqual(aq_get(x, 'hello'), 'world')
  1587. self.assertEqual(aq_get(x, 'foo'), 42)
  1588. self.assertEqual(aq_get(x, 'bar'), 3.145)
  1589. # and ``aq_parent``:
  1590. self.assertIs(aq_parent(x), y)
  1591. self.assertIs(aq_parent(y), z)
  1592. # as well as ``aq_chain``:
  1593. self.assertEqual(aq_chain(x), [x, y, z])
  1594. def test_implicit_wrapper_as___parent__(self):
  1595. # Let's do the same test again, only now not all objects are of the
  1596. # same kind and link to each other via __parent__ pointers. The
  1597. # root is a stupid ExtensionClass object:
  1598. class Root(ExtensionClass.Base):
  1599. bar = 3.145
  1600. z = Root()
  1601. # The intermediate parent is an object that supports implicit
  1602. # acquisition. We bind it to the root via the __of__ protocol:
  1603. class Impl(Implicit):
  1604. foo = 42
  1605. y = Impl().__of__(z)
  1606. # The child object is again a simple object with a simple __parent__
  1607. # pointer:
  1608. x = Location()
  1609. x.hello = 'world'
  1610. x.__parent__ = y
  1611. # ``aq_acquire`` works as expected from implicit/acquisition
  1612. # wrappers:
  1613. self.assertEqual(aq_acquire(x, 'hello'), 'world')
  1614. self.assertEqual(aq_acquire(x, 'foo'), 42)
  1615. self.assertEqual(aq_acquire(x, 'bar'), 3.145)
  1616. # as does ``aq_get``:
  1617. self.assertEqual(aq_get(x, 'hello'), 'world')
  1618. self.assertEqual(aq_get(x, 'foo'), 42)
  1619. self.assertEqual(aq_get(x, 'bar'), 3.145)
  1620. # and ``aq_parent``:
  1621. self.assertIs(aq_parent(x), y)
  1622. self.assertIs(aq_parent(y), z)
  1623. # as well as ``aq_chain``:
  1624. self.assertEqual(aq_chain(x), [x, y, z])
  1625. # Note that also the (implicit) acquisition wrapper has a __parent__
  1626. # pointer, which is automatically computed from the acquisition
  1627. # container (it's identical to aq_parent):
  1628. self.assertIs(y.__parent__, z)
  1629. # Just as much as you can assign to aq_parent, you can also assign
  1630. # to __parent__ to change the acquisition context of the wrapper:
  1631. newroot = Root()
  1632. y.__parent__ = newroot
  1633. self.assertIsNot(y.__parent__, z)
  1634. self.assertIs(y.__parent__, newroot)
  1635. # Note that messing with the wrapper won't in any way affect the
  1636. # wrapped object:
  1637. with self.assertRaises(AttributeError):
  1638. aq_base(y).__parent__
  1639. def test_explicit_wrapper_as___parent__(self):
  1640. # Let's do this test yet another time, with an explicit wrapper:
  1641. class Root(ExtensionClass.Base):
  1642. bar = 3.145
  1643. z = Root()
  1644. # The intermediate parent is an object that supports implicit
  1645. # acquisition. We bind it to the root via the __of__ protocol:
  1646. class Expl(Explicit):
  1647. foo = 42
  1648. y = Expl().__of__(z)
  1649. # The child object is again a simple object with a simple __parent__
  1650. # pointer:
  1651. x = Location()
  1652. x.hello = 'world'
  1653. x.__parent__ = y
  1654. # ``aq_acquire`` works as expected from implicit/acquisition
  1655. # wrappers:
  1656. self.assertEqual(aq_acquire(x, 'hello'), 'world')
  1657. self.assertEqual(aq_acquire(x, 'foo'), 42)
  1658. self.assertEqual(aq_acquire(x, 'bar'), 3.145)
  1659. # as does ``aq_get``:
  1660. self.assertEqual(aq_get(x, 'hello'), 'world')
  1661. self.assertEqual(aq_get(x, 'foo'), 42)
  1662. self.assertEqual(aq_get(x, 'bar'), 3.145)
  1663. # and ``aq_parent``:
  1664. self.assertIs(aq_parent(x), y)
  1665. self.assertIs(aq_parent(y), z)
  1666. # as well as ``aq_chain``:
  1667. self.assertEqual(aq_chain(x), [x, y, z])
  1668. # Note that also the (explicit) acquisition wrapper has a __parent__
  1669. # pointer, which is automatically computed from the acquisition
  1670. # container (it's identical to aq_parent):
  1671. self.assertIs(y.__parent__, z)
  1672. # Just as much as you can assign to aq_parent, you can also assign
  1673. # to __parent__ to change the acquisition context of the wrapper:
  1674. newroot = Root()
  1675. y.__parent__ = newroot
  1676. self.assertIsNot(y.__parent__, z)
  1677. self.assertIs(y.__parent__, newroot)
  1678. # Note that messing with the wrapper won't in any way affect the
  1679. # wrapped object:
  1680. with self.assertRaises(AttributeError):
  1681. aq_base(y).__parent__
  1682. def test_implicit_wrapper_has_nonwrapper_as_aq_parent(self):
  1683. # Let's do this the other way around: The root and the
  1684. # intermediate parent is an object that doesn't support acquisition,
  1685. y = ECLocation()
  1686. z = Location()
  1687. y.__parent__ = z
  1688. y.foo = 42
  1689. z.foo = 43 # this should not be found
  1690. z.bar = 3.145
  1691. # only the outmost object does:
  1692. class Impl(Implicit):
  1693. hello = 'world'
  1694. x = Impl().__of__(y)
  1695. # Again, acquiring objects works as usual:
  1696. self.assertEqual(aq_acquire(x, 'hello'), 'world')
  1697. self.assertEqual(aq_acquire(x, 'foo'), 42)
  1698. self.assertEqual(aq_acquire(x, 'bar'), 3.145)
  1699. # as does ``aq_get``:
  1700. self.assertEqual(aq_get(x, 'hello'), 'world')
  1701. self.assertEqual(aq_get(x, 'foo'), 42)
  1702. self.assertEqual(aq_get(x, 'bar'), 3.145)
  1703. # and ``aq_parent``:
  1704. self.assertEqual(aq_parent(x), y)
  1705. self.assertIs(aq_parent(y), z)
  1706. self.assertEqual(x.aq_parent, y)
  1707. self.assertEqual(x.aq_parent.aq_parent, z)
  1708. # as well as ``aq_chain``:
  1709. self.assertEqual(aq_chain(x), [x, y, z])
  1710. self.assertEqual(x.aq_chain, [x, y, z])
  1711. # Because the outmost object, ``x``, is wrapped in an implicit
  1712. # acquisition wrapper, we can also use direct attribute access:
  1713. self.assertEqual(x.hello, 'world')
  1714. self.assertEqual(x.foo, 42)
  1715. self.assertEqual(x.bar, 3.145)
  1716. def test_explicit_wrapper_has_nonwrapper_as_aq_parent(self):
  1717. # Let's do this the other way around: The root and the
  1718. # intermediate parent is an object that doesn't support acquisition,
  1719. y = ECLocation()
  1720. z = Location()
  1721. y.__parent__ = z
  1722. y.foo = 42
  1723. z.foo = 43 # this should not be found
  1724. z.bar = 3.145
  1725. # only the outmost object does:
  1726. class Expl(Explicit):
  1727. hello = 'world'
  1728. x = Expl().__of__(y)
  1729. # Again, acquiring objects works as usual:
  1730. self.assertEqual(aq_acquire(x, 'hello'), 'world')
  1731. self.assertEqual(aq_acquire(x, 'foo'), 42)
  1732. self.assertEqual(aq_acquire(x, 'bar'), 3.145)
  1733. # as does ``aq_get``:
  1734. self.assertEqual(aq_get(x, 'hello'), 'world')
  1735. self.assertEqual(aq_get(x, 'foo'), 42)
  1736. self.assertEqual(aq_get(x, 'bar'), 3.145)
  1737. # and ``aq_parent``:
  1738. self.assertEqual(aq_parent(x), y)
  1739. self.assertIs(aq_parent(y), z)
  1740. self.assertEqual(x.aq_parent, y)
  1741. self.assertEqual(x.aq_parent.aq_parent, z)
  1742. # as well as ``aq_chain``:
  1743. self.assertEqual(aq_chain(x), [x, y, z])
  1744. self.assertEqual(x.aq_chain, [x, y, z])
  1745. class TestParentCircles(unittest.TestCase):
  1746. def test___parent__aq_parent_circles(self):
  1747. # As a general safety belt, Acquisition won't follow a mixture of
  1748. # circular __parent__ pointers and aq_parent wrappers. These can
  1749. # occurr when code that uses implicit acquisition wrappers meets
  1750. # code that uses __parent__ pointers.
  1751. class Impl(Implicit):
  1752. hello = 'world'
  1753. class Impl2(Implicit):
  1754. hello = 'world2'
  1755. only = 'here'
  1756. x = Impl()
  1757. y = Impl2().__of__(x)
  1758. x.__parent__ = y
  1759. self.assertTrue(x.__parent__.aq_base is y.aq_base)
  1760. self.assertTrue(aq_parent(x) is y)
  1761. self.assertTrue(x.__parent__.__parent__ is x)
  1762. self.assertEqual(x.hello, 'world')
  1763. self.assertEqual(aq_acquire(x, 'hello'), 'world')
  1764. with self.assertRaises(AttributeError):
  1765. x.only
  1766. self.assertEqual(aq_acquire(x, 'only'), 'here')
  1767. with self.assertRaises(AttributeError):
  1768. aq_acquire(x, 'non_existant_attr')
  1769. with self.assertRaises(RuntimeError):
  1770. aq_acquire(y, 'non_existant_attr')
  1771. with self.assertRaises(AttributeError):
  1772. x.non_existant_attr
  1773. with self.assertRaises(RuntimeError):
  1774. y.non_existant_attr
  1775. @unittest.skipUnless(
  1776. hasattr(Acquisition.ImplicitAcquisitionWrapper, '_obj'),
  1777. 'Pure Python specific test')
  1778. def test_python_impl_cycle(self):
  1779. # An extra safety belt, specific to the Python implementation
  1780. # because it's not clear how one could arrive in this situation
  1781. # naturally.
  1782. class Impl(Implicit):
  1783. pass
  1784. root = Impl()
  1785. root.child = Impl()
  1786. child_wrapper = root.child
  1787. # Now set up the python specific boo-boo:
  1788. child_wrapper._obj = child_wrapper
  1789. # Now nothing works:
  1790. with self.assertRaises(RuntimeError):
  1791. child_wrapper.non_existant_attr
  1792. with self.assertRaises(RuntimeError):
  1793. aq_acquire(child_wrapper, 'non_existant_attr')
  1794. def test_unwrapped_implicit_acquirer_unwraps__parent__(self):
  1795. # Set up an implicit acquirer with a parent:
  1796. class Impl(Implicit):
  1797. pass
  1798. y = Impl()
  1799. x = Impl()
  1800. x.__parent__ = y
  1801. # Now if we retrieve the parent from the (unwrapped) instance, the
  1802. # parent should not be wrapped in the instance's acquisition chain.
  1803. self.assertIs(x.__parent__, y)
  1804. class TestBugs(unittest.TestCase):
  1805. def test__iter__after_AttributeError(self):
  1806. # See https://bugs.launchpad.net/zope2/+bug/1155760
  1807. import time
  1808. class C(Implicit):
  1809. l = [0, 1, 2, 3, 4]
  1810. def __getitem__(self, i):
  1811. return self.l[i]
  1812. a = C()
  1813. b = C().__of__(a)
  1814. try:
  1815. for n in b:
  1816. time.gmtime()
  1817. except AttributeError:
  1818. raise
  1819. class TestSpecialNames(unittest.TestCase):
  1820. def test_special_names(self):
  1821. # This test captures some aq_special names that are not otherwise
  1822. # tested for.
  1823. class Impl(Implicit):
  1824. pass
  1825. root = Impl()
  1826. root.child = Impl()
  1827. # First, the 'aq_explicit' name returns an explicit wrapper
  1828. # instead of an explicit wrapper:
  1829. ex_wrapper = root.child.aq_explicit
  1830. self.assertIsInstance(
  1831. ex_wrapper, Acquisition.ExplicitAcquisitionWrapper)
  1832. # If we ask an explicit wrapper to be explicit, we get back
  1833. # the same object:
  1834. self.assertIs(ex_wrapper.aq_explicit, ex_wrapper.aq_explicit)
  1835. # These special names can also be filtered:
  1836. self.assertIsNone(
  1837. aq_acquire(root.child, 'aq_explicit',
  1838. lambda searched, parent, name, ob, extra: None,
  1839. default=None))
  1840. self.assertIsNotNone(
  1841. aq_acquire(root.child, 'aq_explicit',
  1842. lambda searched, parent, name, ob, extra: True,
  1843. default=None))
  1844. # Last, a value that can be used for testing that you have a wrapper:
  1845. self.assertEqual(root.child.aq_uncle, 'Bob')
  1846. class TestWrapper(unittest.TestCase):
  1847. def test_deleting_parent_attrs(self):
  1848. # We can detach a wrapper object from its chain by deleting its
  1849. # parent.
  1850. class Impl(Implicit):
  1851. pass
  1852. root = Impl()
  1853. root.a = 42
  1854. root.child = Impl()
  1855. # Initially, a wrapped object has the parent we expect:
  1856. child_wrapper = root.child
  1857. self.assertIs(child_wrapper.__parent__, root)
  1858. self.assertIs(child_wrapper.aq_parent, root)
  1859. # Even though we acquired the 'a' attribute, we can't delete it:
  1860. self.assertEqual(child_wrapper.a, 42)
  1861. with self.assertRaises(AttributeError):
  1862. del child_wrapper.a
  1863. # Now if we delete it (as many times as we want)
  1864. # we lose access to the parent and acquired attributes:
  1865. del child_wrapper.__parent__
  1866. del child_wrapper.aq_parent
  1867. self.assertIs(child_wrapper.__parent__, None)
  1868. self.assertIs(child_wrapper.aq_parent, None)
  1869. self.assertFalse(hasattr(child_wrapper, 'a'))
  1870. def test__cmp__is_called_on_wrapped_object(self):
  1871. # If we define an object that implements `__cmp__`:
  1872. class Impl(Implicit):
  1873. def __cmp__(self, other):
  1874. return self.a
  1875. # Then it gets called when a wrapper is compared (we call it
  1876. # directly to avoid any Python2/3 issues):
  1877. root = Impl()
  1878. root.a = 42
  1879. root.child = Impl()
  1880. self.assertEqual(root.child.a, 42)
  1881. self.assertEqual(root.child.__cmp__(None), 42)
  1882. def test_wrapped_methods_have_correct_self(self):
  1883. # Getting a method from a wrapper returns an object that uses the
  1884. # wrapper as its `__self__`, no matter how many layers deep we go;
  1885. # this makes acquisition work in that code.
  1886. class Impl(Implicit):
  1887. def method(self):
  1888. return self.a
  1889. root = Impl()
  1890. root.a = 42
  1891. root.child = Impl()
  1892. root.child.child = Impl()
  1893. # We explicitly construct a wrapper to bypass some of the optimizations
  1894. # that remove redundant wrappers and thus get more full code coverage:
  1895. child_wrapper = Acquisition.ImplicitAcquisitionWrapper(
  1896. root.child.child, root.child)
  1897. method = child_wrapper.method
  1898. self.assertIs(method.__self__, child_wrapper)
  1899. self.assertEqual(method(), 42)
  1900. def test_cannot_set_attributes_on_empty_wrappers(self):
  1901. # If a wrapper is around None, no attributes can be set on it:
  1902. wrapper = Acquisition.ImplicitAcquisitionWrapper(None, None)
  1903. with self.assertRaises(AttributeError):
  1904. wrapper.a = 42
  1905. # Likewise, we can't really get any attributes on such an empty wrapper
  1906. with self.assertRaises(AttributeError):
  1907. wrapper.a
  1908. def test_getitem_setitem_not_implemented(self):
  1909. # If a wrapper wraps something that doesn't implement get/setitem,
  1910. # those failures propagate up.
  1911. class Impl(Implicit):
  1912. pass
  1913. root = Impl()
  1914. root.child = Impl()
  1915. # We can't set anything:
  1916. with self.assertRaises(AttributeError):
  1917. root.child['key'] = 42
  1918. # We can't get anything:
  1919. with self.assertRaises(AttributeError):
  1920. root.child['key']
  1921. def test_getitem_setitem_implemented(self):
  1922. # The wrapper delegates to get/set item.
  1923. class Root(Implicit):
  1924. pass
  1925. class Impl(Implicit):
  1926. def __getitem__(self, i):
  1927. return self.a
  1928. def __setitem__(self, key, value):
  1929. self.a[key] = value
  1930. root = Root()
  1931. root.a = dict()
  1932. root.child = Impl()
  1933. self.assertEqual(root.child[1], {})
  1934. root.child['a'] = 'b'
  1935. self.assertEqual(root.child[1], {'a': 'b'})
  1936. def test_wrapped_objects_are_unwrapped_on_set(self):
  1937. # A wrapper is not passed to the base object during `setattr`.
  1938. class Impl(Implicit):
  1939. pass
  1940. # Given two different wrappers:
  1941. root = Impl()
  1942. child = Impl()
  1943. child2 = Impl()
  1944. root.child = child
  1945. root.child2 = child2
  1946. # If we pass one to the other as an attribute:
  1947. root.child.child2 = root.child2
  1948. # By the time it gets there, it's not wrapped:
  1949. self.assertIs(type(child.__dict__['child2']), Impl)
  1950. class TestOf(unittest.TestCase):
  1951. def test__of__exception(self):
  1952. # Wrapper_findattr did't check for an exception in a user defined
  1953. # __of__ method before passing the result to the filter. In this
  1954. # case the 'value' argument of the filter was NULL, which caused
  1955. # a segfault when being accessed.
  1956. class X(Implicit):
  1957. def __of__(self, parent):
  1958. if aq_base(parent) is not parent:
  1959. raise NotImplementedError('ack')
  1960. return X.inheritedAttribute('__of__')(self, parent)
  1961. a = I('a')
  1962. a.b = I('b')
  1963. a.b.x = X('x')
  1964. with self.assertRaises(NotImplementedError):
  1965. aq_acquire(a.b, 'x',
  1966. lambda self, object, name, value, extra: repr(value))
  1967. def test_wrapper_calls_of_on_non_wrapper(self):
  1968. # The ExtensionClass protocol is respected even for non-Acquisition
  1969. # objects.
  1970. class MyBase(ExtensionClass.Base):
  1971. call_count = 0
  1972. def __of__(self, other):
  1973. self.call_count += 1
  1974. return 42
  1975. class Impl(Implicit):
  1976. pass
  1977. # If we have a wrapper around an object that is an extension class,
  1978. # but not an Acquisition wrapper:
  1979. root = Impl()
  1980. base = MyBase()
  1981. wrapper = Acquisition.ImplicitAcquisitionWrapper(base, root)
  1982. # And access that object itself through a wrapper:
  1983. root.child = Impl()
  1984. root.child.wrapper = wrapper
  1985. # The `__of__` protocol is respected implicitly:
  1986. self.assertEqual(root.child.wrapper, 42)
  1987. self.assertEqual(base.call_count, 1)
  1988. # Here it is explicitly:
  1989. self.assertEqual(wrapper.__of__(root.child), 42)
  1990. self.assertEqual(base.call_count, 2)
  1991. class TestAQInContextOf(unittest.TestCase):
  1992. def test_aq_inContextOf(self):
  1993. from ExtensionClass import Base
  1994. class B(Base):
  1995. color = 'red'
  1996. class A(Implicit):
  1997. def hi(self):
  1998. return self.color
  1999. class Location(object):
  2000. __parent__ = None
  2001. b = B()
  2002. b.a = A()
  2003. self.assertEqual(b.a.hi(), 'red')
  2004. b.a.color = 'green'
  2005. self.assertEqual(b.a.hi(), 'green')
  2006. with self.assertRaises(AttributeError):
  2007. A().hi()
  2008. # New test for wrapper comparisons.
  2009. foo = b.a
  2010. bar = b.a
  2011. self.assertEqual(foo, bar)
  2012. c = A()
  2013. b.c = c
  2014. b.c.d = c
  2015. self.assertEqual(b.c.d, c)
  2016. self.assertEqual(b.c.d, b.c)
  2017. self.assertEqual(b.c, c)
  2018. l = Location()
  2019. l.__parent__ = b.c
  2020. def checkContext(self, o):
  2021. # Python equivalent to aq_inContextOf
  2022. next = self
  2023. o = aq_base(o)
  2024. while 1:
  2025. if aq_base(next) is o:
  2026. return True
  2027. self = aq_inner(next)
  2028. if self is None:
  2029. break
  2030. next = aq_parent(self)
  2031. if next is None:
  2032. break
  2033. return False
  2034. self.assertTrue(checkContext(b.c, b))
  2035. self.assertFalse(checkContext(b.c, b.a))
  2036. self.assertTrue(checkContext(l, b))
  2037. self.assertTrue(checkContext(l, b.c))
  2038. self.assertFalse(checkContext(l, b.a))
  2039. # aq_inContextOf works the same way:
  2040. self.assertTrue(aq_inContextOf(b.c, b))
  2041. self.assertFalse(aq_inContextOf(b.c, b.a))
  2042. self.assertTrue(aq_inContextOf(l, b))
  2043. self.assertTrue(aq_inContextOf(l, b.c))
  2044. self.assertFalse(aq_inContextOf(l, b.a))
  2045. self.assertTrue(b.a.aq_inContextOf(b))
  2046. self.assertTrue(b.c.aq_inContextOf(b))
  2047. self.assertTrue(b.c.d.aq_inContextOf(b))
  2048. self.assertTrue(b.c.d.aq_inContextOf(c))
  2049. self.assertTrue(b.c.d.aq_inContextOf(b.c))
  2050. self.assertFalse(b.c.aq_inContextOf(foo))
  2051. self.assertFalse(b.c.aq_inContextOf(b.a))
  2052. self.assertFalse(b.a.aq_inContextOf('somestring'))
  2053. def test_aq_inContextOf_odd_cases(self):
  2054. # The aq_inContextOf function still works in some artificial cases.
  2055. root = object()
  2056. wrapper_around_none = Acquisition.ImplicitAcquisitionWrapper(
  2057. None, None)
  2058. self.assertEqual(aq_inContextOf(wrapper_around_none, root), 0)
  2059. # If we don't ask for inner objects, the same thing happens
  2060. # in this case:
  2061. self.assertEqual(aq_inContextOf(wrapper_around_none, root, False), 0)
  2062. # Somewhat surprisingly, the `aq_inner` of this wrapper
  2063. # is itself a wrapper:
  2064. self.assertIsInstance(aq_inner(wrapper_around_none),
  2065. Acquisition.ImplicitAcquisitionWrapper)
  2066. # If we manipulate the Python implementation
  2067. # to make this no longer true, nothing breaks:
  2068. if hasattr(wrapper_around_none, '_obj'):
  2069. setattr(wrapper_around_none, '_obj', None)
  2070. self.assertEqual(aq_inContextOf(wrapper_around_none, root), 0)
  2071. self.assertIsInstance(wrapper_around_none,
  2072. Acquisition.ImplicitAcquisitionWrapper)
  2073. # Following parent pointers in weird circumstances works too:
  2074. class WithParent(object):
  2075. __parent__ = None
  2076. self.assertEqual(aq_inContextOf(WithParent(), root), 0)
  2077. class TestCircles(unittest.TestCase):
  2078. def test_search_repeated_objects(self):
  2079. # If an acquisition wrapper object is wrapping another wrapper, and
  2080. # also has another wrapper as its parent, and both of *those*
  2081. # wrappers have the same object (one as its direct object, one as
  2082. # its parent), then acquisition proceeds as normal: we don't get
  2083. # into any cycles or fail to acquire expected attributes. In fact,
  2084. # we actually can optimize out a level of the search in that case.
  2085. # This is a bit of a convoluted scenario to set up when the code is
  2086. # written out all in one place, but it may occur organically when
  2087. # spread across a project.
  2088. # We begin with some simple setup, importing the objects we'll use
  2089. # and setting up the object that we'll repeat. This particular test
  2090. # is specific to the Python implementation, so we're using low-level
  2091. # functions from that module:
  2092. from Acquisition import _Wrapper as Wrapper
  2093. from Acquisition import _Wrapper_acquire
  2094. class Repeated(object):
  2095. hello = "world"
  2096. def __repr__(self):
  2097. return 'repeated'
  2098. repeated = Repeated()
  2099. # Now the tricky part, creating the repeating pattern. To rephrase
  2100. # the opening sentence, we need a wrapper whose object and parent
  2101. # (container) are themselves both wrappers, and the object's parent is
  2102. # the same object as the wrapper's parent's object. That might be a
  2103. # bit more clear in code:
  2104. wrappers_object = Wrapper('a', repeated)
  2105. wrappers_parent = Wrapper(repeated, 'b')
  2106. wrapper = Wrapper(wrappers_object, wrappers_parent)
  2107. self.assertIs(wrapper._obj._container, wrapper._container._obj)
  2108. # Using the low-level function on the wrapper fails to find the
  2109. # desired attribute. This is because of the optimization that cuts
  2110. # out a level of the search (it is assumed that the higher level
  2111. # `_Wrapper_findattr` function is driving the search and will take
  2112. # the appropriate steps):
  2113. with self.assertRaises(AttributeError):
  2114. _Wrapper_acquire(wrapper, 'hello')
  2115. # In fact, if we go through the public interface of the high-level
  2116. # functions, we do find the attribute as expected:
  2117. self.assertEqual(aq_acquire(wrapper, 'hello'), 'world')
  2118. def test_parent_parent_circles(self):
  2119. class Impl(Implicit):
  2120. hello = 'world'
  2121. class Impl2(Implicit):
  2122. hello = 'world2'
  2123. only = 'here'
  2124. x = Impl()
  2125. y = Impl2()
  2126. x.__parent__ = y
  2127. y.__parent__ = x
  2128. self.assertTrue(x.__parent__.__parent__ is x)
  2129. self.assertEqual(aq_acquire(x, 'hello'), 'world')
  2130. self.assertEqual(aq_acquire(x, 'only'), 'here')
  2131. self.assertRaises(AttributeError, aq_acquire, x, 'non_existant_attr')
  2132. self.assertRaises(AttributeError, aq_acquire, y, 'non_existant_attr')
  2133. def test_parent_parent_parent_circles(self):
  2134. class Impl(Implicit):
  2135. hello = 'world'
  2136. class Impl2(Implicit):
  2137. hello = 'world'
  2138. class Impl3(Implicit):
  2139. hello = 'world2'
  2140. only = 'here'
  2141. a = Impl()
  2142. b = Impl2()
  2143. c = Impl3()
  2144. a.__parent__ = b
  2145. b.__parent__ = c
  2146. c.__parent__ = a
  2147. self.assertTrue(a.__parent__.__parent__ is c)
  2148. self.assertTrue(
  2149. aq_base(a.__parent__.__parent__.__parent__) is a)
  2150. self.assertTrue(b.__parent__.__parent__ is a)
  2151. self.assertTrue(c.__parent__.__parent__ is b)
  2152. self.assertEqual(aq_acquire(a, 'hello'), 'world')
  2153. self.assertEqual(aq_acquire(b, 'hello'), 'world')
  2154. self.assertEqual(aq_acquire(c, 'hello'), 'world2')
  2155. self.assertEqual(aq_acquire(a, 'only'), 'here')
  2156. self.assertEqual(aq_acquire(b, 'only'), 'here')
  2157. self.assertEqual(aq_acquire(c, 'only'), 'here')
  2158. self.assertRaises(AttributeError, getattr, a, 'non_existant_attr')
  2159. self.assertRaises(AttributeError, getattr, b, 'non_existant_attr')
  2160. self.assertRaises(AttributeError, getattr, c, 'non_existant_attr')
  2161. class TestAcquire(unittest.TestCase):
  2162. def setUp(self):
  2163. class Impl(Implicit):
  2164. pass
  2165. class Expl(Explicit):
  2166. pass
  2167. a = Impl('a')
  2168. a.y = 42
  2169. a.b = Expl('b')
  2170. a.b.z = 3
  2171. a.b.c = Impl('c')
  2172. self.a = a
  2173. def test_explicit_module_default(self):
  2174. self.assertEqual(aq_acquire(self.a.b.c, 'z'), 3)
  2175. def test_explicit_module_true(self):
  2176. self.assertEqual(aq_acquire(self.a.b.c, 'z', explicit=True), 3)
  2177. def test_explicit_module_false(self):
  2178. self.assertEqual(aq_acquire(self.a.b.c, 'z', explicit=False), 3)
  2179. def test_explicit_wrapper_default(self):
  2180. self.assertEqual(self.a.b.c.aq_acquire('z'), 3)
  2181. def test_explicit_wrapper_true(self):
  2182. self.assertEqual(self.a.b.c.aq_acquire('z', explicit=True), 3)
  2183. def test_explicit_wrapper_false(self):
  2184. self.assertEqual(self.a.b.c.aq_acquire('z', explicit=False), 3)
  2185. def test_wrapper_falls_back_to_default(self):
  2186. self.assertEqual(aq_acquire(self.a.b.c, 'nonesuch', default=4), 4)
  2187. def test_no_wrapper_but___parent___falls_back_to_default(self):
  2188. class NotWrapped(object):
  2189. pass
  2190. child = NotWrapped()
  2191. child.__parent__ = NotWrapped()
  2192. self.assertEqual(aq_acquire(child, 'nonesuch', default=4), 4)
  2193. def test_unwrapped_falls_back_to_default(self):
  2194. self.assertEqual(aq_acquire(object(), 'nonesuch', default=4), 4)
  2195. def test_w_unicode_attr_name(self):
  2196. # See https://bugs.launchpad.net/acquisition/+bug/143358
  2197. found = aq_acquire(self.a.b.c, AQ_PARENT)
  2198. self.assertTrue(found.aq_self is self.a.b.aq_self)
  2199. class TestCooperativeBase(unittest.TestCase):
  2200. def _make_acquirer(self, kind):
  2201. from ExtensionClass import Base
  2202. class ExtendsBase(Base):
  2203. def __getattribute__(self, name):
  2204. if name == 'magic':
  2205. return 42
  2206. return super(ExtendsBase, self).__getattribute__(name)
  2207. class Acquirer(kind, ExtendsBase):
  2208. pass
  2209. return Acquirer()
  2210. def _check___getattribute___is_cooperative(self, acquirer):
  2211. self.assertEqual(getattr(acquirer, 'magic'), 42)
  2212. def test_implicit___getattribute__is_cooperative(self):
  2213. self._check___getattribute___is_cooperative(
  2214. self._make_acquirer(Implicit))
  2215. def test_explicit___getattribute__is_cooperative(self):
  2216. self._check___getattribute___is_cooperative(
  2217. self._make_acquirer(Explicit))
  2218. class TestImplicitWrappingGetattribute(unittest.TestCase):
  2219. # Implicitly wrapping an object that uses object.__getattribute__
  2220. # in its implementation of __getattribute__ doesn't break.
  2221. # This can arise with the `persistent` library or other
  2222. # "base" classes.
  2223. # The C implementation doesn't directly support this; however,
  2224. # it is used heavily in the Python implementation of Persistent.
  2225. @unittest.skipIf(CAPI, 'Pure Python test.')
  2226. def test_object_getattribute_in_rebound_method_with_slots(self):
  2227. class Persistent(object):
  2228. __slots__ = ('__flags',)
  2229. def __init__(self):
  2230. self.__flags = 42
  2231. def get_flags(self):
  2232. return object.__getattribute__(self, '_Persistent__flags')
  2233. wrapped = Persistent()
  2234. wrapper = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
  2235. self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
  2236. # Changing it is not reflected in the wrapper's dict (this is an
  2237. # implementation detail)
  2238. wrapper._Persistent__flags = -1
  2239. self.assertEqual(wrapped.get_flags(), -1)
  2240. self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
  2241. wrapper_dict = object.__getattribute__(wrapper, '__dict__')
  2242. self.assertFalse('_Persistent__flags' in wrapper_dict)
  2243. @unittest.skipIf(CAPI, 'Pure Python test.')
  2244. def test_type_with_slots_reused(self):
  2245. class Persistent(object):
  2246. __slots__ = ('__flags',)
  2247. def __init__(self):
  2248. self.__flags = 42
  2249. def get_flags(self):
  2250. return object.__getattribute__(self, '_Persistent__flags')
  2251. wrapped = Persistent()
  2252. wrapper = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
  2253. wrapper2 = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
  2254. self.assertTrue(type(wrapper) is type(wrapper2))
  2255. @unittest.skipIf(CAPI, 'Pure Python test.')
  2256. def test_object_getattribute_in_rebound_method_with_dict(self):
  2257. class Persistent(object):
  2258. def __init__(self):
  2259. self.__flags = 42
  2260. def get_flags(self):
  2261. return object.__getattribute__(self, '_Persistent__flags')
  2262. wrapped = Persistent()
  2263. wrapper = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
  2264. self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
  2265. # Changing it is also reflected in both dicts (this is an
  2266. # implementation detail)
  2267. wrapper._Persistent__flags = -1
  2268. self.assertEqual(wrapped.get_flags(), -1)
  2269. self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
  2270. wrapper_dict = object.__getattribute__(wrapper, '__dict__')
  2271. self.assertTrue('_Persistent__flags' in wrapper_dict)
  2272. @unittest.skipIf(CAPI, 'Pure Python test.')
  2273. def test_object_getattribute_in_rebound_method_with_slots_and_dict(self):
  2274. class Persistent(object):
  2275. __slots__ = ('__flags', '__dict__')
  2276. def __init__(self):
  2277. self.__flags = 42
  2278. self.__oid = 'oid'
  2279. def get_flags(self):
  2280. return object.__getattribute__(self, '_Persistent__flags')
  2281. def get_oid(self):
  2282. return object.__getattribute__(self, '_Persistent__oid')
  2283. wrapped = Persistent()
  2284. wrapper = Acquisition.ImplicitAcquisitionWrapper(wrapped, None)
  2285. self.assertEqual(wrapped.get_flags(), wrapper.get_flags())
  2286. self.assertEqual(wrapped.get_oid(), wrapper.get_oid())
  2287. class TestUnicode(unittest.TestCase):
  2288. def test_implicit_aq_unicode_should_be_called(self):
  2289. class A(Implicit):
  2290. def __unicode__(self):
  2291. return UNICODE_WAS_CALLED
  2292. wrapped = A().__of__(A())
  2293. self.assertEqual(UNICODE_WAS_CALLED, unicode(wrapped))
  2294. self.assertEqual(str(wrapped), repr(wrapped))
  2295. def test_explicit_aq_unicode_should_be_called(self):
  2296. class A(Explicit):
  2297. def __unicode__(self):
  2298. return UNICODE_WAS_CALLED
  2299. wrapped = A().__of__(A())
  2300. self.assertEqual(UNICODE_WAS_CALLED, unicode(wrapped))
  2301. self.assertEqual(str(wrapped), repr(wrapped))
  2302. def test_implicit_should_fall_back_to_str(self):
  2303. class A(Implicit):
  2304. def __str__(self):
  2305. return 'str was called'
  2306. wrapped = A().__of__(A())
  2307. self.assertEqual(STR_WAS_CALLED, unicode(wrapped))
  2308. self.assertEqual('str was called', str(wrapped))
  2309. def test_explicit_should_fall_back_to_str(self):
  2310. class A(Explicit):
  2311. def __str__(self):
  2312. return 'str was called'
  2313. wrapped = A().__of__(A())
  2314. self.assertEqual(STR_WAS_CALLED, unicode(wrapped))
  2315. self.assertEqual('str was called', str(wrapped))
  2316. def test_str_fallback_should_be_called_with_wrapped_self(self):
  2317. class A(Implicit):
  2318. def __str__(self):
  2319. return str(self.aq_parent == outer)
  2320. outer = A()
  2321. inner = A().__of__(outer)
  2322. self.assertEqual(TRUE, unicode(inner))
  2323. def test_unicode_should_be_called_with_wrapped_self(self):
  2324. class A(Implicit):
  2325. def __unicode__(self):
  2326. return str(self.aq_parent == outer)
  2327. outer = A()
  2328. inner = A().__of__(outer)
  2329. self.assertEqual(TRUE, unicode(inner))
  2330. class TestProxying(unittest.TestCase):
  2331. __binary_numeric_methods__ = [
  2332. '__add__',
  2333. '__sub__',
  2334. '__mul__',
  2335. # '__floordiv__', # not implemented in C
  2336. '__mod__',
  2337. '__divmod__',
  2338. '__pow__',
  2339. '__lshift__',
  2340. '__rshift__',
  2341. '__and__',
  2342. '__xor__',
  2343. '__or__',
  2344. # division
  2345. '__truediv__',
  2346. '__div__',
  2347. # reflected
  2348. '__radd__',
  2349. '__rsub__',
  2350. '__rmul__',
  2351. '__rdiv__',
  2352. '__rtruediv__',
  2353. '__rfloordiv__',
  2354. '__rmod__',
  2355. '__rdivmod__',
  2356. '__rpow__',
  2357. '__rlshift__',
  2358. '__rrshift__',
  2359. '__rand__',
  2360. '__rxor__',
  2361. '__ror__',
  2362. # in place
  2363. '__iadd__',
  2364. '__isub__',
  2365. '__imul__',
  2366. '__idiv__',
  2367. '__itruediv__',
  2368. '__ifloordiv__',
  2369. '__imod__',
  2370. '__idivmod__',
  2371. '__ipow__',
  2372. '__ilshift__',
  2373. '__irshift__',
  2374. '__iand__',
  2375. '__ixor__',
  2376. '__ior__',
  2377. # conversion
  2378. # implementing it messes up all the arithmetic tests
  2379. # '__coerce__',
  2380. ]
  2381. if PY3 and sys.version_info.minor >= 5:
  2382. __binary_numeric_methods__.extend([
  2383. '__matmul__',
  2384. '__imatmul__'
  2385. ])
  2386. __unary_special_methods__ = [
  2387. # arithmetic
  2388. '__neg__',
  2389. '__pos__',
  2390. '__abs__',
  2391. '__invert__',
  2392. ]
  2393. __unary_conversion_methods__ = {
  2394. # conversion
  2395. '__complex__': complex,
  2396. '__int__': int,
  2397. '__long__': long,
  2398. '__float__': float,
  2399. '__oct__': oct,
  2400. '__hex__': hex,
  2401. '__len__': lambda o: o if isinstance(o, int) else len(o),
  2402. # '__index__': operator.index, # not implemented in C
  2403. }
  2404. def _check_special_methods(self, base_class=Implicit):
  2405. # Check that special methods are proxied
  2406. # when called implicitly by the interpreter
  2407. def binary_acquired_func(self, other, modulo=None):
  2408. return self.value
  2409. def unary_acquired_func(self):
  2410. return self.value
  2411. acquire_meths = {}
  2412. for k in self.__binary_numeric_methods__:
  2413. acquire_meths[k] = binary_acquired_func
  2414. for k in self.__unary_special_methods__:
  2415. acquire_meths[k] = unary_acquired_func
  2416. def make_converter(f):
  2417. def converter(self, *args):
  2418. return f(self.value)
  2419. return converter
  2420. for k, convert in self.__unary_conversion_methods__.items():
  2421. acquire_meths[k] = make_converter(convert)
  2422. acquire_meths['__len__'] = lambda self: self.value
  2423. if PY3:
  2424. # Under Python 3, oct() and hex() call __index__ directly
  2425. acquire_meths['__index__'] = acquire_meths['__int__']
  2426. if base_class == Explicit:
  2427. acquire_meths['value'] = Acquisition.Acquired
  2428. AcquireValue = type('AcquireValue', (base_class,), acquire_meths)
  2429. class B(Implicit):
  2430. pass
  2431. base = B()
  2432. base.value = 42
  2433. base.derived = AcquireValue()
  2434. # one syntax check for the heck of it
  2435. self.assertEqual(base.value, base.derived + 1)
  2436. # divmod is not in the operator module
  2437. self.assertEqual(base.value, divmod(base.derived, 1))
  2438. _found_at_least_one_div = False
  2439. for meth in self.__binary_numeric_methods__:
  2440. op = getattr(operator, meth, None)
  2441. if op is not None:
  2442. # called on the instance
  2443. self.assertEqual(base.value, op(base.derived, -1))
  2444. # called on the type, as the interpreter does
  2445. # Note that the C version can only implement either __truediv__
  2446. # or __div__, not both
  2447. op = getattr(operator, meth, None)
  2448. if op is not None:
  2449. try:
  2450. self.assertEqual(base.value,
  2451. op(base.derived, 1))
  2452. if meth in ('__div__', '__truediv__'):
  2453. _found_at_least_one_div = True
  2454. except TypeError:
  2455. if meth in ('__div__', '__truediv__'):
  2456. pass
  2457. self.assertTrue(
  2458. _found_at_least_one_div,
  2459. "Must implement at least one of __div__ and __truediv__")
  2460. # Unary methods
  2461. for meth in self.__unary_special_methods__:
  2462. self.assertEqual(base.value, getattr(base.derived, meth)())
  2463. op = getattr(operator, meth)
  2464. self.assertEqual(base.value, op(base.derived))
  2465. # Conversion functions
  2466. for meth, converter in self.__unary_conversion_methods__.items():
  2467. if not converter:
  2468. continue
  2469. self.assertEqual(converter(base.value),
  2470. getattr(base.derived, meth)())
  2471. self.assertEqual(converter(base.value),
  2472. converter(base.derived))
  2473. def test_implicit_proxy_special_meths(self):
  2474. self._check_special_methods()
  2475. def test_explicit_proxy_special_meths(self):
  2476. self._check_special_methods(base_class=Explicit)
  2477. def _check_contains(self, base_class=Implicit):
  2478. # Contains has lots of fallback behaviour
  2479. class B(Implicit):
  2480. pass
  2481. base = B()
  2482. base.value = 42
  2483. # The simple case is if the object implements contains itself
  2484. class ReallyContains(base_class):
  2485. if base_class is Explicit:
  2486. value = Acquisition.Acquired
  2487. def __contains__(self, item):
  2488. return self.value == item
  2489. base.derived = ReallyContains()
  2490. self.assertTrue(42 in base.derived)
  2491. self.assertFalse(24 in base.derived)
  2492. # Iterable objects are NOT iterated
  2493. # XXX: Is this a bug in the C code? Shouldn't it do
  2494. # what the interpreter does and fallback to iteration?
  2495. class IterContains(base_class):
  2496. if base_class is Explicit:
  2497. value = Acquisition.Acquired
  2498. def __iter__(self):
  2499. return iter((42,))
  2500. base.derived = IterContains()
  2501. self.assertRaises(AttributeError, operator.contains, base.derived, 42)
  2502. def test_implicit_proxy_contains(self):
  2503. self._check_contains()
  2504. def test_explicit_proxy_contains(self):
  2505. self._check_contains(base_class=Explicit)
  2506. def _check_call(self, base_class=Implicit):
  2507. class B(Implicit):
  2508. pass
  2509. base = B()
  2510. base.value = 42
  2511. class Callable(base_class):
  2512. if base_class is Explicit:
  2513. value = Acquisition.Acquired
  2514. def __call__(self, arg, k=None):
  2515. return self.value, arg, k
  2516. base.derived = Callable()
  2517. self.assertEqual(base.derived(1, k=2), (42, 1, 2))
  2518. if not IS_PYPY:
  2519. # XXX: This test causes certain versions
  2520. # of PyPy to segfault (at least 2.6.0-alpha1)
  2521. class NotCallable(base_class):
  2522. pass
  2523. base.derived = NotCallable()
  2524. try:
  2525. base.derived()
  2526. self.fail("Not callable")
  2527. except (TypeError, AttributeError):
  2528. pass
  2529. def test_implicit_proxy_call(self):
  2530. self._check_call()
  2531. def test_explicit_proxy_call(self):
  2532. self._check_call(base_class=Explicit)
  2533. def _check_hash(self, base_class=Implicit):
  2534. class B(Implicit):
  2535. pass
  2536. base = B()
  2537. base.value = B()
  2538. base.value.hash = 42
  2539. class NoAcquired(base_class):
  2540. def __hash__(self):
  2541. return 1
  2542. hashable = NoAcquired()
  2543. base.derived = hashable
  2544. self.assertEqual(1, hash(hashable))
  2545. self.assertEqual(1, hash(base.derived))
  2546. # cannot access acquired attributes during
  2547. # __hash__
  2548. class CannotAccessAcquiredAttributesAtHash(base_class):
  2549. if base_class is Explicit:
  2550. value = Acquisition.Acquired
  2551. def __hash__(self):
  2552. return self.value.hash
  2553. hashable = CannotAccessAcquiredAttributesAtHash()
  2554. base.derived = hashable
  2555. self.assertRaises(AttributeError, hash, hashable)
  2556. self.assertRaises(AttributeError, hash, base.derived)
  2557. def test_implicit_proxy_hash(self):
  2558. self._check_hash()
  2559. def test_explicit_proxy_hash(self):
  2560. self._check_hash(base_class=Explicit)
  2561. def _check_comparison(self, base_class=Implicit):
  2562. # Comparison behaviour is complex; see notes in _Wrapper
  2563. class B(Implicit):
  2564. pass
  2565. base = B()
  2566. base.value = 42
  2567. rich_cmp_methods = ['__lt__', '__gt__', '__eq__',
  2568. '__ne__', '__ge__', '__le__']
  2569. def _never_called(self, other):
  2570. raise RuntimeError("This should never be called")
  2571. class RichCmpNeverCalled(base_class):
  2572. for _name in rich_cmp_methods:
  2573. locals()[_name] = _never_called
  2574. base.derived = RichCmpNeverCalled()
  2575. base.derived2 = RichCmpNeverCalled()
  2576. # We can access all of the operators, but only because
  2577. # they are masked
  2578. for name in rich_cmp_methods:
  2579. getattr(operator, name)(base.derived, base.derived2)
  2580. self.assertFalse(base.derived2 == base.derived)
  2581. self.assertEqual(base.derived, base.derived)
  2582. def test_implicit_proxy_comporison(self):
  2583. self._check_comparison()
  2584. def test_explicit_proxy_comporison(self):
  2585. self._check_comparison(base_class=Explicit)
  2586. def _check_bool(self, base_class=Implicit):
  2587. class B(Implicit):
  2588. pass
  2589. base = B()
  2590. base.value = 42
  2591. class WithBool(base_class):
  2592. if base_class is Explicit:
  2593. value = Acquisition.Acquired
  2594. def __nonzero__(self):
  2595. return bool(self.value)
  2596. __bool__ = __nonzero__
  2597. class WithLen(base_class):
  2598. if base_class is Explicit:
  2599. value = Acquisition.Acquired
  2600. def __len__(self):
  2601. return self.value
  2602. class WithNothing(base_class):
  2603. pass
  2604. base.wbool = WithBool()
  2605. base.wlen = WithLen()
  2606. base.wnothing = WithNothing()
  2607. self.assertEqual(bool(base.wbool), True)
  2608. self.assertEqual(bool(base.wlen), True)
  2609. self.assertEqual(bool(base.wnothing), True)
  2610. base.value = 0
  2611. self.assertFalse(base.wbool)
  2612. self.assertFalse(base.wlen)
  2613. def test_implicit_proxy_bool(self):
  2614. self._check_bool()
  2615. def test_explicit_proxy_bool(self):
  2616. self._check_bool(base_class=Explicit)
  2617. class TestCompilation(unittest.TestCase):
  2618. def test_compile(self):
  2619. if IS_PYPY or IS_PURE:
  2620. with self.assertRaises((AttributeError, ImportError)):
  2621. from Acquisition import _Acquisition
  2622. else:
  2623. from Acquisition import _Acquisition
  2624. self.assertTrue(hasattr(_Acquisition, 'AcquisitionCAPI'))
  2625. def test_suite():
  2626. import os.path
  2627. here = os.path.dirname(__file__)
  2628. root = os.path.join(here, os.pardir, os.pardir)
  2629. readme = os.path.join(root, 'README.rst')
  2630. suites = [
  2631. DocTestSuite(),
  2632. unittest.defaultTestLoader.loadTestsFromName(__name__),
  2633. ]
  2634. # This file is only available in a source checkout, skip it
  2635. # when tests are run for an installed version.
  2636. if os.path.isfile(readme):
  2637. suites.append(DocFileSuite(readme, module_relative=False))
  2638. return unittest.TestSuite(suites)