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.

__init__.py 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. from __future__ import absolute_import, print_function
  2. # pylint:disable=W0212,R0911,R0912
  3. import os
  4. import operator
  5. import platform
  6. import sys
  7. import types
  8. import weakref
  9. import ExtensionClass
  10. from zope.interface import classImplements
  11. from .interfaces import IAcquirer
  12. from .interfaces import IAcquisitionWrapper
  13. IS_PYPY = getattr(platform, 'python_implementation', lambda: None)() == 'PyPy'
  14. IS_PURE = 'PURE_PYTHON' in os.environ
  15. class Acquired(object):
  16. "Marker for explicit acquisition"
  17. _NOT_FOUND = object() # marker
  18. ###
  19. # Helper functions
  20. ###
  21. def _has__of__(obj):
  22. """Check whether an object has an __of__ method for returning itself
  23. in the context of a container."""
  24. # It is necessary to check both the type (or we get into cycles)
  25. # as well as the presence of the method (or mixins of Base pre- or
  26. # post-class-creation as done in, e.g.,
  27. # zopefoundation/Persistence) can fail.
  28. return (isinstance(obj, ExtensionClass.Base) and
  29. hasattr(type(obj), '__of__'))
  30. def _apply_filter(predicate, inst, name, result, extra, orig):
  31. return predicate(orig, inst, name, result, extra)
  32. if sys.version_info < (3,):
  33. import copy_reg
  34. def _rebound_method(method, wrapper):
  35. """Returns a version of the method with self bound to `wrapper`"""
  36. if isinstance(method, types.MethodType):
  37. method = types.MethodType(method.im_func, wrapper, method.im_class)
  38. return method
  39. exec("""def _reraise(tp, value, tb=None):
  40. raise tp, value, tb
  41. """)
  42. else: # pragma: no cover (python 2 is currently our reference)
  43. import copyreg as copy_reg
  44. def _rebound_method(method, wrapper):
  45. """Returns a version of the method with self bound to `wrapper`"""
  46. if isinstance(method, types.MethodType):
  47. method = types.MethodType(method.__func__, wrapper)
  48. return method
  49. def _reraise(tp, value, tb=None):
  50. if value is None:
  51. value = tp()
  52. if value.__traceback__ is not tb:
  53. raise value.with_traceback(tb)
  54. raise value
  55. ###
  56. # Wrapper object protocol, mostly ported from C directly
  57. ###
  58. def _Wrapper_findspecial(wrapper, name):
  59. """
  60. Looks up the special acquisition attributes of an object.
  61. :param str name: The attribute to find, with 'aq' already stripped.
  62. """
  63. result = _NOT_FOUND
  64. if name == 'base':
  65. result = wrapper._obj
  66. while isinstance(result, _Wrapper) and result._obj is not None:
  67. result = result._obj
  68. elif name == 'parent':
  69. result = wrapper._container
  70. elif name == 'self':
  71. result = wrapper._obj
  72. elif name == 'explicit':
  73. if type(wrapper)._IS_IMPLICIT:
  74. result = ExplicitAcquisitionWrapper(
  75. wrapper._obj, wrapper._container)
  76. else:
  77. result = wrapper
  78. elif name == 'acquire':
  79. result = object.__getattribute__(wrapper, 'aq_acquire')
  80. elif name == 'chain':
  81. # XXX: C has a second implementation here
  82. result = aq_chain(wrapper)
  83. elif name == 'inContextOf':
  84. result = object.__getattribute__(wrapper, 'aq_inContextOf')
  85. elif name == 'inner':
  86. # XXX: C has a second implementation here
  87. result = aq_inner(wrapper)
  88. elif name == 'uncle':
  89. result = 'Bob'
  90. return result
  91. def _Wrapper_acquire(wrapper, name,
  92. predicate=None, predicate_extra=None,
  93. orig_object=None,
  94. explicit=True, containment=True):
  95. """
  96. Attempt to acquire the `name` from the parent of the wrapper.
  97. :raises AttributeError: If the wrapper has no parent or the
  98. attribute cannot be found.
  99. """
  100. if wrapper._container is None:
  101. raise AttributeError(name)
  102. search_self = True
  103. search_parent = True
  104. # If the container has an acquisition wrapper itself, we'll use
  105. # _Wrapper_findattr to progress further
  106. if isinstance(wrapper._container, _Wrapper):
  107. if isinstance(wrapper._obj, _Wrapper):
  108. # try to optimize search by recognizing repeated objects in path
  109. if wrapper._obj._container is wrapper._container._container:
  110. search_parent = False
  111. elif wrapper._obj._container is wrapper._container._obj:
  112. search_self = False
  113. # Don't search the container when the container of the container
  114. # is the same object as `wrapper`
  115. if wrapper._container._container is wrapper._obj:
  116. search_parent = False
  117. containment = True
  118. result = _Wrapper_findattr(wrapper._container, name,
  119. predicate=predicate,
  120. predicate_extra=predicate_extra,
  121. orig_object=orig_object,
  122. search_self=search_self,
  123. search_parent=search_parent,
  124. explicit=explicit,
  125. containment=containment)
  126. # XXX: Why does this branch of the C code check __of__,
  127. # but the next one doesn't?
  128. if _has__of__(result):
  129. result = result.__of__(wrapper)
  130. return result
  131. # If the container has a __parent__ pointer, we create an
  132. # acquisition wrapper for it accordingly. Then we can proceed
  133. # with Wrapper_findattr, just as if the container had an
  134. # acquisition wrapper in the first place (see above).
  135. # NOTE: This mutates the wrapper
  136. elif hasattr(wrapper._container, '__parent__'):
  137. parent = wrapper._container.__parent__
  138. # Don't search the container when the parent of the parent
  139. # is the same object as 'self'
  140. if parent is wrapper._obj:
  141. search_parent = False
  142. elif isinstance(parent, _Wrapper) and parent._obj is wrapper._obj:
  143. # XXX: C code just does parent._obj, assumes its a wrapper
  144. search_parent = False
  145. wrapper._container = ImplicitAcquisitionWrapper(
  146. wrapper._container, parent)
  147. return _Wrapper_findattr(wrapper._container, name,
  148. predicate=predicate,
  149. predicate_extra=predicate_extra,
  150. orig_object=orig_object,
  151. search_self=search_self,
  152. search_parent=search_parent,
  153. explicit=explicit,
  154. containment=containment)
  155. else:
  156. # The container is the end of the acquisition chain; if we
  157. # can't look up the attributes here, we can't look it up at all
  158. result = getattr(wrapper._container, name)
  159. if result is not Acquired:
  160. if predicate:
  161. if _apply_filter(predicate, wrapper._container, name,
  162. result, predicate_extra, orig_object):
  163. return (result.__of__(wrapper)
  164. if _has__of__(result) else result)
  165. else:
  166. raise AttributeError(name)
  167. else:
  168. if _has__of__(result):
  169. result = result.__of__(wrapper)
  170. return result
  171. # this line cannot be reached
  172. raise AttributeError(name) # pragma: no cover
  173. def _Wrapper_findattr(wrapper, name,
  174. predicate=None, predicate_extra=None,
  175. orig_object=None,
  176. search_self=True, search_parent=True,
  177. explicit=True, containment=True):
  178. """
  179. Search the `wrapper` object for the attribute `name`.
  180. :param bool search_self: Search `wrapper.aq_self` for the attribute.
  181. :param bool search_parent: Search `wrapper.aq_parent` for the attribute.
  182. :param bool explicit: Explicitly acquire the attribute from the parent
  183. (should be assumed with implicit wrapper)
  184. :param bool containment: Use the innermost wrapper (`aq_inner`)
  185. for looking up the attribute.
  186. """
  187. orig_name = name
  188. if orig_object is None:
  189. orig_object = wrapper
  190. # First, special names
  191. if name.startswith('aq') or name == '__parent__':
  192. # __parent__ is an alias of aq_parent
  193. if name == '__parent__':
  194. name = 'parent'
  195. else:
  196. name = name[3:]
  197. result = _Wrapper_findspecial(wrapper, name)
  198. if result is not _NOT_FOUND:
  199. if predicate:
  200. if _apply_filter(predicate, wrapper, orig_name,
  201. result, predicate_extra, orig_object):
  202. return result
  203. else:
  204. raise AttributeError(orig_name)
  205. return result
  206. elif name in ('__reduce__', '__reduce_ex__', '__getstate__',
  207. '__of__', '__cmp__', '__eq__', '__ne__', '__lt__',
  208. '__le__', '__gt__', '__ge__'):
  209. return object.__getattribute__(wrapper, orig_name)
  210. # If we're doing a containment search, replace the wrapper with aq_inner
  211. if containment:
  212. while isinstance(wrapper._obj, _Wrapper):
  213. wrapper = wrapper._obj
  214. if search_self and wrapper._obj is not None:
  215. if isinstance(wrapper._obj, _Wrapper):
  216. if wrapper is wrapper._obj:
  217. raise RuntimeError("Recursion detected in acquisition wrapper")
  218. try:
  219. result = _Wrapper_findattr(wrapper._obj, orig_name,
  220. predicate=predicate,
  221. predicate_extra=predicate_extra,
  222. orig_object=orig_object,
  223. search_self=True,
  224. search_parent=explicit or isinstance(wrapper._obj, ImplicitAcquisitionWrapper), # NOQA
  225. explicit=explicit,
  226. containment=containment)
  227. if isinstance(result, types.MethodType):
  228. result = _rebound_method(result, wrapper)
  229. elif _has__of__(result):
  230. result = result.__of__(wrapper)
  231. return result
  232. except AttributeError:
  233. pass
  234. # deal with mixed __parent__ / aq_parent circles
  235. elif (isinstance(wrapper._container, _Wrapper) and
  236. wrapper._container._container is wrapper):
  237. raise RuntimeError("Recursion detected in acquisition wrapper")
  238. else:
  239. # normal attribute lookup
  240. try:
  241. result = getattr(wrapper._obj, orig_name)
  242. except AttributeError:
  243. pass
  244. else:
  245. if result is Acquired:
  246. return _Wrapper_acquire(wrapper, orig_name,
  247. predicate=predicate,
  248. predicate_extra=predicate_extra,
  249. orig_object=orig_object,
  250. explicit=True,
  251. containment=containment)
  252. if isinstance(result, types.MethodType):
  253. result = _rebound_method(result, wrapper)
  254. elif _has__of__(result):
  255. result = result.__of__(wrapper)
  256. if predicate:
  257. if _apply_filter(predicate, wrapper, orig_name,
  258. result, predicate_extra, orig_object):
  259. return result
  260. else:
  261. return result
  262. # lookup has failed, acquire from the parent
  263. if search_parent and (not name.startswith('_') or explicit):
  264. return _Wrapper_acquire(wrapper, orig_name,
  265. predicate=predicate,
  266. predicate_extra=predicate_extra,
  267. orig_object=orig_object,
  268. explicit=explicit,
  269. containment=containment)
  270. raise AttributeError(orig_name)
  271. _NOT_GIVEN = object() # marker
  272. _OGA = object.__getattribute__
  273. # Map from object types with slots to their generated, derived
  274. # types (or None if no derived type is needed)
  275. _wrapper_subclass_cache = weakref.WeakKeyDictionary()
  276. def _make_wrapper_subclass_if_needed(cls, obj, container):
  277. # If the type of an object to be wrapped has __slots__, then we
  278. # must create a wrapper subclass that has descriptors for those
  279. # same slots. In this way, its methods that use object.__getattribute__
  280. # directly will continue to work, even when given an instance of _Wrapper
  281. if getattr(cls, '_Wrapper__DERIVED', False):
  282. return None
  283. type_obj = type(obj)
  284. wrapper_subclass = _wrapper_subclass_cache.get(type_obj, _NOT_GIVEN)
  285. if wrapper_subclass is _NOT_GIVEN:
  286. slotnames = copy_reg._slotnames(type_obj)
  287. if slotnames and not isinstance(obj, _Wrapper):
  288. new_type_dict = {'_Wrapper__DERIVED': True}
  289. def _make_property(slotname):
  290. return property(lambda s: getattr(s._obj, slotname),
  291. lambda s, v: setattr(s._obj, slotname, v),
  292. lambda s: delattr(s._obj, slotname))
  293. for slotname in slotnames:
  294. new_type_dict[slotname] = _make_property(slotname)
  295. new_type = type(cls.__name__ + '_' + type_obj.__name__,
  296. (cls,),
  297. new_type_dict)
  298. else:
  299. new_type = None
  300. wrapper_subclass = _wrapper_subclass_cache[type_obj] = new_type
  301. return wrapper_subclass
  302. class _Wrapper(ExtensionClass.Base):
  303. __slots__ = ('_obj', '_container', '__dict__')
  304. _IS_IMPLICIT = None
  305. def __new__(cls, obj, container):
  306. wrapper_subclass = _make_wrapper_subclass_if_needed(cls, obj, container) # NOQA
  307. if wrapper_subclass:
  308. inst = wrapper_subclass(obj, container)
  309. else:
  310. inst = super(_Wrapper, cls).__new__(cls)
  311. inst._obj = obj
  312. inst._container = container
  313. if hasattr(obj, '__dict__') and not isinstance(obj, _Wrapper):
  314. # Make our __dict__ refer to the same dict as the other object,
  315. # so that if it has methods that use `object.__getattribute__`
  316. # they still work. Note that because we have slots,
  317. # we won't interfere with the contents of that dict.
  318. object.__setattr__(inst, '__dict__', obj.__dict__)
  319. return inst
  320. def __init__(self, obj, container):
  321. super(_Wrapper, self).__init__()
  322. self._obj = obj
  323. self._container = container
  324. def __setattr__(self, name, value):
  325. if name == '__parent__' or name == 'aq_parent':
  326. object.__setattr__(self, '_container', value)
  327. return
  328. if name == '_obj' or name == '_container':
  329. # should only happen at init time
  330. object.__setattr__(self, name, value)
  331. return
  332. # If we are wrapping something, unwrap passed in wrappers
  333. if self._obj is None:
  334. raise AttributeError(
  335. 'Attempt to set attribute on empty acquisition wrapper')
  336. while value is not None and isinstance(value, _Wrapper):
  337. value = value._obj
  338. setattr(self._obj, name, value)
  339. def __delattr__(self, name):
  340. if name == '__parent__' or name == 'aq_parent':
  341. self._container = None
  342. else:
  343. delattr(self._obj, name)
  344. def __getattribute__(self, name):
  345. if name in ('_obj', '_container'):
  346. return _OGA(self, name)
  347. if (_OGA(self, '_obj') is not None or
  348. _OGA(self, '_container') is not None):
  349. return _Wrapper_findattr(self, name, None, None, None, True,
  350. type(self)._IS_IMPLICIT, False, False)
  351. return _OGA(self, name)
  352. def __of__(self, parent):
  353. # Based on __of__ in the C code;
  354. # simplify a layer of wrapping.
  355. # We have to call the raw __of__ method or we recurse on our
  356. # own lookup (the C code does not have this issue, it can use
  357. # the wrapped __of__ method because it gets here via the
  358. # descriptor code path)...
  359. wrapper = self._obj.__of__(parent)
  360. if (not isinstance(wrapper, _Wrapper) or
  361. not isinstance(wrapper._container, _Wrapper)):
  362. return wrapper
  363. # but the returned wrapper should be based on this object's
  364. # wrapping chain
  365. wrapper._obj = self
  366. while (isinstance(wrapper._obj, _Wrapper) and
  367. (wrapper._obj._container is wrapper._container._obj)):
  368. # Since we mutate the wrapper as we walk up, we must copy
  369. # XXX: This comes from the C implementation. Do we really need to
  370. # copy?
  371. wrapper = type(wrapper)(wrapper._obj, wrapper._container)
  372. wrapper._obj = wrapper._obj._obj
  373. return wrapper
  374. def aq_acquire(self, name,
  375. filter=None, extra=None,
  376. explicit=True,
  377. default=_NOT_GIVEN,
  378. containment=False):
  379. try:
  380. return _Wrapper_findattr(self, name,
  381. predicate=filter,
  382. predicate_extra=extra,
  383. orig_object=self,
  384. search_self=True,
  385. search_parent=explicit or type(self)._IS_IMPLICIT, # NOQA
  386. explicit=explicit,
  387. containment=containment)
  388. except AttributeError:
  389. if default is _NOT_GIVEN:
  390. raise
  391. return default
  392. acquire = aq_acquire
  393. def aq_inContextOf(self, o, inner=True):
  394. return aq_inContextOf(self, o, inner=inner)
  395. # Wrappers themselves are not picklable, but if the underlying
  396. # object has a _p_oid, then the __getnewargs__ method is allowed
  397. def __reduce__(self, *args):
  398. raise TypeError("Can't pickle objects in acquisition wrappers.")
  399. __reduce_ex__ = __reduce__
  400. __getstate__ = __reduce__
  401. def __getnewargs__(self):
  402. return ()
  403. # Equality and comparisons
  404. def __hash__(self):
  405. # The C implementation doesn't pass the wrapper
  406. # to any __hash__ that the object implements,
  407. # so it can't access derived attributes.
  408. # (If that changes, just add this to __unary_special_methods__
  409. # and remove this method)
  410. return hash(self._obj)
  411. # The C implementation forces all comparisons through the
  412. # __cmp__ method, if it's implemented. If it's not implemented,
  413. # then comparisons are based strictly on the memory addresses
  414. # of the underlying object (aq_base). We could mostly emulate
  415. # this behaviour on Python 2, but on Python 3 __cmp__ is gone,
  416. # so users won't have an expectation to write it.
  417. # Because users have never had an expectation that the rich comparison
  418. # methods would be called on their wrapped objects (and so would not be
  419. # accessing acquired attributes there), we can't/don't want to start
  420. # proxying to them?
  421. # For the moment, we settle for an emulation of the C behaviour:
  422. # define __cmp__ the same way, and redirect the rich comparison operators
  423. # to it. (Note that these attributes are also hardcoded in getattribute)
  424. def __cmp__(self, other):
  425. aq_self = self._obj
  426. if hasattr(type(aq_self), '__cmp__'):
  427. return _rebound_method(aq_self.__cmp__, self)(other)
  428. my_base = aq_base(self)
  429. other_base = aq_base(other)
  430. if my_base is other_base:
  431. return 0
  432. return -1 if id(my_base) < id(other_base) else 1
  433. def __eq__(self, other):
  434. return self.__cmp__(other) == 0
  435. def __ne__(self, other):
  436. return self.__cmp__(other) != 0
  437. def __lt__(self, other):
  438. return self.__cmp__(other) < 0
  439. def __le__(self, other):
  440. return self.__cmp__(other) <= 0
  441. def __gt__(self, other):
  442. return self.__cmp__(other) > 0
  443. def __ge__(self, other):
  444. return self.__cmp__(other) >= 0
  445. # Special methods looked up by the type of self._obj,
  446. # but which must have the wrapper as self when called
  447. def __nonzero__(self):
  448. aq_self = self._obj
  449. type_aq_self = type(aq_self)
  450. nonzero = getattr(type_aq_self, '__nonzero__', None)
  451. if nonzero is None:
  452. # Py3 bool?
  453. nonzero = getattr(type_aq_self, '__bool__', None)
  454. if nonzero is None:
  455. # a len?
  456. nonzero = getattr(type_aq_self, '__len__', None)
  457. if nonzero:
  458. return bool(nonzero(self)) # Py3 is strict about the return type
  459. # If nothing was defined, then it's true
  460. return True
  461. __bool__ = __nonzero__
  462. def __unicode__(self):
  463. f = getattr(self.aq_self, '__unicode__',
  464. getattr(self.aq_self, '__str__', object.__str__))
  465. return _rebound_method(f, self)()
  466. def __repr__(self):
  467. aq_self = self._obj
  468. try:
  469. return _rebound_method(aq_self.__repr__, self)()
  470. except (AttributeError, TypeError):
  471. return repr(aq_self)
  472. def __str__(self):
  473. aq_self = self._obj
  474. try:
  475. return _rebound_method(aq_self.__str__, self)()
  476. except (AttributeError, TypeError): # pragma: no cover (Only Py3)
  477. return str(aq_self)
  478. __binary_special_methods__ = [
  479. # general numeric
  480. '__add__',
  481. '__sub__',
  482. '__mul__',
  483. '__matmul__',
  484. '__floordiv__', # not implemented in C
  485. '__mod__',
  486. '__divmod__',
  487. '__pow__',
  488. '__lshift__',
  489. '__rshift__',
  490. '__and__',
  491. '__xor__',
  492. '__or__',
  493. # division; only one of these will be used at any one time
  494. '__truediv__',
  495. '__div__',
  496. # reflected numeric
  497. '__radd__',
  498. '__rsub__',
  499. '__rmul__',
  500. '__rdiv__',
  501. '__rtruediv__',
  502. '__rfloordiv__',
  503. '__rmod__',
  504. '__rdivmod__',
  505. '__rpow__',
  506. '__rlshift__',
  507. '__rrshift__',
  508. '__rand__',
  509. '__rxor__',
  510. '__ror__',
  511. # in place numeric
  512. '__iadd__',
  513. '__isub__',
  514. '__imul__',
  515. '__imatmul__',
  516. '__idiv__',
  517. '__itruediv__',
  518. '__ifloordiv__',
  519. '__imod__',
  520. '__idivmod__',
  521. '__ipow__',
  522. '__ilshift__',
  523. '__irshift__',
  524. '__iand__',
  525. '__ixor__',
  526. '__ior__',
  527. # conversion
  528. '__coerce__',
  529. # container
  530. '__delitem__',
  531. ]
  532. __unary_special_methods__ = [
  533. # arithmetic
  534. '__neg__',
  535. '__pos__',
  536. '__abs__',
  537. '__invert__',
  538. # conversion
  539. '__complex__',
  540. '__int__',
  541. '__long__',
  542. '__float__',
  543. '__oct__',
  544. '__hex__',
  545. '__index__',
  546. # '__len__',
  547. # strings are special
  548. # '__repr__',
  549. # '__str__',
  550. ]
  551. for _name in __binary_special_methods__:
  552. def _make_op(_name):
  553. def op(self, other):
  554. aq_self = self._obj
  555. return getattr(type(aq_self), _name)(self, other)
  556. return op
  557. locals()[_name] = _make_op(_name)
  558. for _name in __unary_special_methods__:
  559. def _make_op(_name):
  560. def op(self):
  561. aq_self = self._obj
  562. return getattr(type(aq_self), _name)(self)
  563. return op
  564. locals()[_name] = _make_op(_name)
  565. del _make_op
  566. del _name
  567. # Container protocol
  568. def __len__(self):
  569. # if len is missing, it should raise TypeError
  570. # (AttributeError is acceptable under Py2, but Py3
  571. # breaks list conversion if AttributeError is raised)
  572. try:
  573. l = getattr(type(self._obj), '__len__')
  574. except AttributeError:
  575. raise TypeError('object has no len()')
  576. else:
  577. return l(self)
  578. def __iter__(self):
  579. # For things that provide either __iter__ or just __getitem__,
  580. # we need to be sure that the wrapper is provided as self
  581. if hasattr(self._obj, '__iter__'):
  582. return _rebound_method(self._obj.__iter__, self)()
  583. if hasattr(self._obj, '__getitem__'):
  584. # Unfortunately we cannot simply call iter(self._obj)
  585. # and rebind im_self like we do above: the Python runtime
  586. # complains:
  587. # (TypeError: 'sequenceiterator' expected, got 'Wrapper' instead)
  588. class WrapperIter(object):
  589. __slots__ = ('_wrapper',)
  590. def __init__(self, o):
  591. self._wrapper = o
  592. def __getitem__(self, i):
  593. return self._wrapper.__getitem__(i)
  594. it = WrapperIter(self)
  595. return iter(it)
  596. return iter(self._obj)
  597. def __contains__(self, item):
  598. # First, if the type of the object defines __contains__ then
  599. # use it
  600. aq_self = self._obj
  601. aq_contains = getattr(type(aq_self), '__contains__', None)
  602. if aq_contains:
  603. return aq_contains(self, item)
  604. # Next, we should attempt to iterate like the interpreter;
  605. # but the C code doesn't do this, so we don't either.
  606. # return item in iter(self)
  607. raise AttributeError('__contains__')
  608. def __setitem__(self, key, value):
  609. aq_self = self._obj
  610. try:
  611. setter = type(aq_self).__setitem__
  612. except AttributeError:
  613. raise AttributeError("__setitem__") # doctests care about the name
  614. else:
  615. setter(self, key, value)
  616. def __getitem__(self, key):
  617. if isinstance(key, slice) and hasattr(operator, 'getslice'):
  618. # Only on Python 2
  619. # XXX: This is probably not proxying correctly, but the existing
  620. # tests pass with this behaviour
  621. return operator.getslice(
  622. self._obj,
  623. key.start if key.start is not None else 0,
  624. key.stop if key.stop is not None else sys.maxint)
  625. aq_self = self._obj
  626. try:
  627. getter = type(aq_self).__getitem__
  628. except AttributeError:
  629. raise AttributeError("__getitem__") # doctests care about the name
  630. else:
  631. return getter(self, key)
  632. def __call__(self, *args, **kwargs):
  633. try:
  634. # Note we look this up on the completely unwrapped
  635. # object, so as not to get a class
  636. call = getattr(self.aq_base, '__call__')
  637. except AttributeError: # pragma: no cover
  638. # A TypeError is what the interpreter raises;
  639. # AttributeError is allowed to percolate through the
  640. # C proxy
  641. raise TypeError('object is not callable')
  642. else:
  643. return _rebound_method(call, self)(*args, **kwargs)
  644. class ImplicitAcquisitionWrapper(_Wrapper):
  645. _IS_IMPLICIT = True
  646. class ExplicitAcquisitionWrapper(_Wrapper):
  647. _IS_IMPLICIT = False
  648. def __getattribute__(self, name):
  649. # Special case backwards-compatible acquire method
  650. if name == 'acquire':
  651. return object.__getattribute__(self, name)
  652. return _Wrapper.__getattribute__(self, name)
  653. class _Acquirer(ExtensionClass.Base):
  654. def __getattribute__(self, name):
  655. try:
  656. return super(_Acquirer, self).__getattribute__(name)
  657. except AttributeError:
  658. # the doctests have very specific error message
  659. # requirements (but at least we can preserve the traceback)
  660. _, _, tb = sys.exc_info()
  661. try:
  662. _reraise(AttributeError, AttributeError(name), tb)
  663. finally:
  664. del tb
  665. def __of__(self, context):
  666. return type(self)._Wrapper(self, context)
  667. class Implicit(_Acquirer):
  668. _Wrapper = ImplicitAcquisitionWrapper
  669. ImplicitAcquisitionWrapper._Wrapper = ImplicitAcquisitionWrapper
  670. class Explicit(_Acquirer):
  671. _Wrapper = ExplicitAcquisitionWrapper
  672. ExplicitAcquisitionWrapper._Wrapper = ExplicitAcquisitionWrapper
  673. ###
  674. # Exported module functions
  675. ###
  676. def aq_acquire(obj, name,
  677. filter=None, extra=None,
  678. explicit=True,
  679. default=_NOT_GIVEN,
  680. containment=False):
  681. if isinstance(obj, _Wrapper):
  682. return obj.aq_acquire(name,
  683. filter=filter, extra=extra,
  684. default=default,
  685. explicit=explicit or type(obj)._IS_IMPLICIT,
  686. containment=containment)
  687. # Does it have a parent, or do we have a filter?
  688. # Then go through the acquisition code
  689. if hasattr(obj, '__parent__') or filter is not None:
  690. parent = getattr(obj, '__parent__', None)
  691. return aq_acquire(ImplicitAcquisitionWrapper(obj, parent),
  692. name,
  693. filter=filter, extra=extra,
  694. default=default,
  695. explicit=explicit,
  696. containment=containment)
  697. # no parent and no filter, simple case
  698. try:
  699. return getattr(obj, name)
  700. except AttributeError:
  701. if default is _NOT_GIVEN:
  702. raise AttributeError(name) # doctests are strict
  703. return default
  704. def aq_parent(obj):
  705. # needs to be safe to call from __getattribute__ of a wrapper
  706. # and reasonably fast
  707. if isinstance(obj, _Wrapper):
  708. return object.__getattribute__(obj, '_container')
  709. # if not a wrapper, deal with the __parent__
  710. return getattr(obj, '__parent__', None)
  711. def aq_chain(obj, containment=False):
  712. result = []
  713. while True:
  714. if isinstance(obj, _Wrapper):
  715. if obj._obj is not None:
  716. if containment:
  717. while isinstance(obj._obj, _Wrapper):
  718. obj = obj._obj
  719. result.append(obj)
  720. if obj._container is not None:
  721. obj = obj._container
  722. continue
  723. else:
  724. result.append(obj)
  725. obj = getattr(obj, '__parent__', None)
  726. if obj is not None:
  727. continue
  728. break
  729. return result
  730. def aq_base(obj):
  731. result = obj
  732. while isinstance(result, _Wrapper):
  733. result = result._obj
  734. return result
  735. def aq_get(obj, name, default=_NOT_GIVEN, containment=False):
  736. # Not wrapped. If we have a __parent__ pointer, create a wrapper
  737. # and go as usual
  738. if not isinstance(obj, _Wrapper) and hasattr(obj, '__parent__'):
  739. obj = ImplicitAcquisitionWrapper(obj, obj.__parent__)
  740. try:
  741. # We got a wrapped object, business as usual
  742. return (_Wrapper_findattr(obj, name, None, None, obj,
  743. True, True, True, containment)
  744. if isinstance(obj, _Wrapper)
  745. # ok, plain getattr
  746. else getattr(obj, name))
  747. except AttributeError:
  748. if default is _NOT_GIVEN:
  749. raise
  750. return default
  751. def aq_inner(obj):
  752. if not isinstance(obj, _Wrapper):
  753. return obj
  754. result = obj._obj
  755. while isinstance(result, _Wrapper):
  756. obj = result
  757. result = result._obj
  758. result = obj
  759. return result
  760. def aq_self(obj):
  761. if isinstance(obj, _Wrapper):
  762. return obj.aq_self
  763. return obj
  764. def aq_inContextOf(self, o, inner=True):
  765. next = self
  766. o = aq_base(o)
  767. while True:
  768. if aq_base(next) is o:
  769. return True
  770. if inner:
  771. self = aq_inner(next)
  772. if self is None: # pragma: no cover
  773. # This branch is normally impossible to hit,
  774. # it just mirrors a check in C
  775. break
  776. else:
  777. self = next
  778. next = aq_parent(self)
  779. if next is None:
  780. break
  781. return False
  782. if not (IS_PYPY or IS_PURE): # pragma: no cover
  783. # Make sure we can import the C extension of our dependency.
  784. from ExtensionClass import _ExtensionClass # NOQA
  785. from ._Acquisition import * # NOQA
  786. classImplements(Explicit, IAcquirer)
  787. classImplements(ExplicitAcquisitionWrapper, IAcquisitionWrapper)
  788. classImplements(Implicit, IAcquirer)
  789. classImplements(ImplicitAcquisitionWrapper, IAcquisitionWrapper)