123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697 |
- Metadata-Version: 1.1
- Name: Acquisition
- Version: 4.5
- Summary: Acquisition is a mechanism that allows objects to obtain attributes from the containment hierarchy they're in.
- Home-page: https://github.com/zopefoundation/Acquisition
- Author: Zope Foundation and Contributors
- Author-email: zope-dev@zope.org
- License: ZPL 2.1
- Description: Environmental Acquisiton
- ========================
-
- This package implements "environmental acquisiton" for Python, as
- proposed in the OOPSLA96_ paper by Joseph Gil and David H. Lorenz:
-
- We propose a new programming paradigm, environmental acquisition in
- the context of object aggregation, in which objects acquire
- behaviour from their current containers at runtime. The key idea is
- that the behaviour of a component may depend upon its enclosing
- composite(s). In particular, we propose a form of feature sharing in
- which an object "inherits" features from the classes of objects in
- its environment. By examining the declaration of classes, it is
- possible to determine which kinds of classes may contain a
- component, and which components must be contained in a given kind of
- composite. These relationships are the basis for language constructs
- that supports acquisition.
-
- .. _OOPSLA96: http://www.cs.virginia.edu/~lorenz/papers/oopsla96/>`_:
-
- .. contents::
-
- Introductory Example
- --------------------
-
- Zope implements acquisition with "Extension Class" mix-in classes. To
- use acquisition your classes must inherit from an acquisition base
- class. For example::
-
- >>> import ExtensionClass, Acquisition
-
- >>> class C(ExtensionClass.Base):
- ... color = 'red'
-
- >>> class A(Acquisition.Implicit):
- ... def report(self):
- ... print(self.color)
- ...
- >>> a = A()
- >>> c = C()
- >>> c.a = a
-
- >>> c.a.report()
- red
-
- >>> d = C()
- >>> d.color = 'green'
- >>> d.a = a
-
- >>> d.a.report()
- green
-
- >>> try:
- ... a.report()
- ... except AttributeError:
- ... pass
- ... else:
- ... raise AssertionError('AttributeError not raised.')
-
- The class ``A`` inherits acquisition behavior from
- ``Acquisition.Implicit``. The object, ``a``, "has" the color of
- objects ``c`` and d when it is accessed through them, but it has no
- color by itself. The object ``a`` obtains attributes from its
- environment, where its environment is defined by the access path used
- to reach ``a``.
-
- Acquisition Wrappers
- --------------------
-
- When an object that supports acquisition is accessed through an
- extension class instance, a special object, called an acquisition
- wrapper, is returned. In the example above, the expression ``c.a``
- returns an acquisition wrapper that contains references to both ``c``
- and ``a``. It is this wrapper that performs attribute lookup in ``c``
- when an attribute cannot be found in ``a``.
-
- Acquisition wrappers provide access to the wrapped objects through the
- attributes ``aq_parent``, ``aq_self``, ``aq_base``. Continue the
- example from above::
-
- >>> c.a.aq_parent is c
- True
- >>> c.a.aq_self is a
- True
-
- Explicit and Implicit Acquisition
- ---------------------------------
-
- Two styles of acquisition are supported: implicit and explicit
- acquisition.
-
- Implicit acquisition
- --------------------
-
- Implicit acquisition is so named because it searches for attributes
- from the environment automatically whenever an attribute cannot be
- obtained directly from an object or through inheritance.
-
- An attribute can be implicitly acquired if its name does not begin
- with an underscore.
-
- To support implicit acquisition, your class should inherit from the
- mix-in class ``Acquisition.Implicit``.
-
- Explicit Acquisition
- --------------------
-
- When explicit acquisition is used, attributes are not automatically
- obtained from the environment. Instead, the method aq_acquire must be
- used. For example::
-
- >>> print(c.a.aq_acquire('color'))
- red
-
- To support explicit acquisition, your class should inherit from the
- mix-in class ``Acquisition.Explicit``.
-
- Controlling Acquisition
- -----------------------
-
- A class (or instance) can provide attribute by attribute control over
- acquisition. Your should subclass from ``Acquisition.Explicit``, and set
- all attributes that should be acquired to the special value
- ``Acquisition.Acquired``. Setting an attribute to this value also allows
- inherited attributes to be overridden with acquired ones. For example::
-
- >>> class C(Acquisition.Explicit):
- ... id = 1
- ... secret = 2
- ... color = Acquisition.Acquired
- ... __roles__ = Acquisition.Acquired
-
- The only attributes that are automatically acquired from containing
- objects are color, and ``__roles__``. Note that the ``__roles__``
- attribute is acquired even though its name begins with an
- underscore. In fact, the special ``Acquisition.Acquired`` value can be
- used in ``Acquisition.Implicit`` objects to implicitly acquire
- selected objects that smell like private objects.
-
- Sometimes, you want to dynamically make an implicitly acquiring object
- acquire explicitly. You can do this by getting the object's
- aq_explicit attribute. This attribute provides the object with an
- explicit wrapper that replaces the original implicit wrapper.
-
- Filtered Acquisition
- --------------------
-
- The acquisition method, ``aq_acquire``, accepts two optional
- arguments. The first of the additional arguments is a "filtering"
- function that is used when considering whether to acquire an
- object. The second of the additional arguments is an object that is
- passed as extra data when calling the filtering function and which
- defaults to ``None``. The filter function is called with five
- arguments:
-
- * The object that the aq_acquire method was called on,
-
- * The object where an object was found,
-
- * The name of the object, as passed to aq_acquire,
-
- * The object found, and
-
- * The extra data passed to aq_acquire.
-
- If the filter returns a true object that the object found is returned,
- otherwise, the acquisition search continues.
-
- Here's an example::
-
- >>> from Acquisition import Explicit
-
- >>> class HandyForTesting(object):
- ... def __init__(self, name):
- ... self.name = name
- ... def __str__(self):
- ... return "%s(%s)" % (self.name, self.__class__.__name__)
- ... __repr__=__str__
- ...
- >>> class E(Explicit, HandyForTesting): pass
- ...
- >>> class Nice(HandyForTesting):
- ... isNice = 1
- ... def __str__(self):
- ... return HandyForTesting.__str__(self)+' and I am nice!'
- ... __repr__ = __str__
- ...
- >>> a = E('a')
- >>> a.b = E('b')
- >>> a.b.c = E('c')
- >>> a.p = Nice('spam')
- >>> a.b.p = E('p')
-
- >>> def find_nice(self, ancestor, name, object, extra):
- ... return hasattr(object,'isNice') and object.isNice
-
- >>> print(a.b.c.aq_acquire('p', find_nice))
- spam(Nice) and I am nice!
-
- The filtered acquisition in the last line skips over the first
- attribute it finds with the name ``p``, because the attribute doesn't
- satisfy the condition given in the filter.
-
- Filtered acquisition is rarely used in Zope.
-
- Acquiring from Context
- ----------------------
-
- Normally acquisition allows objects to acquire data from their
- containers. However an object can acquire from objects that aren't its
- containers.
-
- Most of the examples we've seen so far show establishing of an
- acquisition context using getattr semantics. For example, ``a.b`` is a
- reference to ``b`` in the context of ``a``.
-
- You can also manually set acquisition context using the ``__of__``
- method. For example::
-
- >>> from Acquisition import Implicit
- >>> class C(Implicit): pass
- ...
- >>> a = C()
- >>> b = C()
- >>> a.color = "red"
- >>> print(b.__of__(a).color)
- red
-
- In this case, ``a`` does not contain ``b``, but it is put in ``b``'s
- context using the ``__of__`` method.
-
- Here's another subtler example that shows how you can construct an
- acquisition context that includes non-container objects::
-
- >>> from Acquisition import Implicit
-
- >>> class C(Implicit):
- ... def __init__(self, name):
- ... self.name = name
-
- >>> a = C("a")
- >>> a.b = C("b")
- >>> a.b.color = "red"
- >>> a.x = C("x")
-
- >>> print(a.b.x.color)
- red
-
- Even though ``b`` does not contain ``x``, ``x`` can acquire the color
- attribute from ``b``. This works because in this case, ``x`` is accessed
- in the context of ``b`` even though it is not contained by ``b``.
-
- Here acquisition context is defined by the objects used to access
- another object.
-
- Containment Before Context
- --------------------------
-
- If in the example above suppose both a and b have an color attribute::
-
- >>> a = C("a")
- >>> a.color = "green"
- >>> a.b = C("b")
- >>> a.b.color = "red"
- >>> a.x = C("x")
-
- >>> print(a.b.x.color)
- green
-
- Why does ``a.b.x.color`` acquire color from ``a`` and not from ``b``?
- The answer is that an object acquires from its containers before
- non-containers in its context.
-
- To see why consider this example in terms of expressions using the
- ``__of__`` method::
-
- a.x -> x.__of__(a)
-
- a.b -> b.__of__(a)
-
- a.b.x -> x.__of__(a).__of__(b.__of__(a))
-
- Keep in mind that attribute lookup in a wrapper is done by trying to
- look up the attribute in the wrapped object first and then in the
- parent object. So in the expressions above proceeds from left to
- right.
-
- The upshot of these rules is that attributes are looked up by
- containment before context.
-
- This rule holds true also for more complex examples. For example,
- ``a.b.c.d.e.f.g.attribute`` would search for attribute in ``g`` and
- all its containers first. (Containers are searched in order from the
- innermost parent to the outermost container.) If the attribute is not
- found in ``g`` or any of its containers, then the search moves to
- ``f`` and all its containers, and so on.
-
- Additional Attributes and Methods
- ---------------------------------
-
- You can use the special method ``aq_inner`` to access an object
- wrapped only by containment. So in the example above,
- ``a.b.x.aq_inner`` is equivalent to ``a.x``.
-
- You can find out the acquisition context of an object using the
- aq_chain method like so:
-
- >>> [obj.name for obj in a.b.x.aq_chain]
- ['x', 'b', 'a']
-
- You can find out if an object is in the containment context of another
- object using the ``aq_inContextOf`` method. For example:
-
- >>> a.b.aq_inContextOf(a)
- True
-
- .. Note: as of this writing the aq_inContextOf examples don't work the
- way they should be working. According to Jim, this is because
- aq_inContextOf works by comparing object pointer addresses, which
- (because they are actually different wrapper objects) doesn't give
- you the expected results. He acknowledges that this behavior is
- controversial, and says that there is a collector entry to change
- it so that you would get the answer you expect in the above. (We
- just need to get to it).
-
- Acquisition Module Functions
- ----------------------------
-
- In addition to using acquisition attributes and methods directly on
- objects you can use similar functions defined in the ``Acquisition``
- module. These functions have the advantage that you don't need to
- check to make sure that the object has the method or attribute before
- calling it.
-
- ``aq_acquire(object, name [, filter, extra, explicit, default, containment])``
- Acquires an object with the given name.
-
- This function can be used to explictly acquire when using explicit
- acquisition and to acquire names that wouldn't normally be
- acquired.
-
- The function accepts a number of optional arguments:
-
- ``filter``
- A callable filter object that is used to decide if an object
- should be acquired.
-
- The filter is called with five arguments:
-
- * The object that the aq_acquire method was called on,
-
- * The object where an object was found,
-
- * The name of the object, as passed to aq_acquire,
-
- * The object found, and
-
- * The extra argument passed to aq_acquire.
-
- If the filter returns a true object that the object found is
- returned, otherwise, the acquisition search continues.
-
- ``extra``
- Extra data to be passed as the last argument to the filter.
-
- ``explicit``
- A flag (boolean value) indicating whether explicit acquisition
- should be used. The default value is true. If the flag is
- true, then acquisition will proceed regardless of whether
- wrappers encountered in the search of the acquisition
- hierarchy are explicit or implicit wrappers. If the flag is
- false, then parents of explicit wrappers are not searched.
-
- This argument is useful if you want to apply a filter without
- overriding explicit wrappers.
-
- ``default``
- A default value to return if no value can be acquired.
-
- ``containment``
- A flag indicating whether the search should be limited to the
- containment hierarchy.
-
- In addition, arguments can be provided as keywords.
-
- ``aq_base(object)``
- Return the object with all wrapping removed.
-
- ``aq_chain(object [, containment])``
- Return a list containing the object and it's acquisition
- parents. The optional argument, containment, controls whether the
- containment or access hierarchy is used.
-
- ``aq_get(object, name [, default, containment])``
- Acquire an attribute, name. A default value can be provided, as
- can a flag that limits search to the containment hierarchy.
-
- ``aq_inner(object)``
- Return the object with all but the innermost layer of wrapping
- removed.
-
- ``aq_parent(object)``
- Return the acquisition parent of the object or None if the object
- is unwrapped.
-
- ``aq_self(object)``
- Return the object with one layer of wrapping removed, unless the
- object is unwrapped, in which case the object is returned.
-
- In most cases it is more convenient to use these module functions
- instead of the acquisition attributes and methods directly.
-
- Acquisition and Methods
- -----------------------
-
- Python methods of objects that support acquisition can use acquired
- attributes. When a Python method is called on an object that is
- wrapped by an acquisition wrapper, the wrapper is passed to the method
- as the first argument. This rule also applies to user-defined method
- types and to C methods defined in pure mix-in classes.
-
- Unfortunately, C methods defined in extension base classes that define
- their own data structures, cannot use aquired attributes at this
- time. This is because wrapper objects do not conform to the data
- structures expected by these methods. In practice, you will seldom
- find this a problem.
-
- Conclusion
- ----------
-
- Acquisition provides a powerful way to dynamically share information
- between objects. Zope 2 uses acquisition for a number of its key
- features including security, object publishing, and DTML variable
- lookup. Acquisition also provides an elegant solution to the problem
- of circular references for many classes of problems. While acquisition
- is powerful, you should take care when using acquisition in your
- applications. The details can get complex, especially with the
- differences between acquiring from context and acquiring from
- containment.
-
-
- Changelog
- =========
-
- 4.5 (2018-10-05)
- ----------------
-
- - Avoid deprecation warnings by using current API.
-
- - Add support for Python 3.7.
-
- 4.4.4 (2017-11-24)
- ------------------
-
- - Add Appveyor configuration to automate building Windows eggs.
-
- 4.4.3 (2017-11-23)
- ------------------
-
- - Fix the extremely rare potential for a crash when the C extensions
- are in use. See `issue 21 <https://github.com/zopefoundation/Acquisition/issues/21>`_.
-
- 4.4.2 (2017-05-12)
- ------------------
-
- - Fix C capsule name to fix import errors.
-
- - Ensure our dependencies match our expactations about C extensions.
-
- 4.4.1 (2017-05-04)
- ------------------
-
- - Fix C code under Python 3.4, with missing Py_XSETREF.
-
- 4.4.0 (2017-05-04)
- ------------------
-
- - Enable the C extension under Python 3.
-
- - Drop support for Python 3.3.
-
- 4.3.0 (2017-01-20)
- ------------------
-
- - Make tests compatible with ExtensionClass 4.2.0.
-
- - Drop support for Python 2.6 and 3.2.
-
- - Add support for Python 3.5 and 3.6.
-
- 4.2.2 (2015-05-19)
- ------------------
-
- - Make the pure-Python Acquirer objects cooperatively use the
- superclass ``__getattribute__`` method, like the C implementation.
- See https://github.com/zopefoundation/Acquisition/issues/7.
-
- - The pure-Python implicit acquisition wrapper allows wrapped objects
- to use ``object.__getattribute__(self, name)``. This differs from
- the C implementation, but is important for compatibility with the
- pure-Python versions of libraries like ``persistent``. See
- https://github.com/zopefoundation/Acquisition/issues/9.
-
- 4.2.1 (2015-04-23)
- ------------------
-
- - Correct several dangling pointer uses in the C extension,
- potentially fixing a few interpreter crashes. See
- https://github.com/zopefoundation/Acquisition/issues/5.
-
- 4.2 (2015-04-04)
- ----------------
-
- - Add support for PyPy, PyPy3, and Python 3.2, 3.3, and 3.4.
-
- 4.1 (2014-12-18)
- ----------------
-
- - Bump dependency on ``ExtensionClass`` to match current release.
-
- 4.0.3 (2014-11-02)
- ------------------
-
- - Skip readme.rst tests when tests are run outside a source checkout.
-
- 4.0.2 (2014-11-02)
- ------------------
-
- - Include ``*.rst`` files in the release.
-
- 4.0.1 (2014-10-30)
- ------------------
-
- - Tolerate Unicode attribute names (ASCII only). LP #143358.
-
- - Make module-level ``aq_acquire`` API respect the ``default`` parameter.
- LP #1387363.
-
- - Don't raise an attribute error for ``__iter__`` if the fallback to
- ``__getitem__`` succeeds. LP #1155760.
-
-
- 4.0 (2013-02-24)
- ----------------
-
- - Added trove classifiers to project metadata.
-
- 4.0a1 (2011-12-13)
- ------------------
-
- - Raise `RuntimeError: Recursion detected in acquisition wrapper` if an object
- with a `__parent__` pointer points to a wrapper that in turn points to the
- original object.
-
- - Prevent wrappers to be created while accessing `__parent__` on types derived
- from Explicit or Implicit base classes.
-
- 2.13.9 (2015-02-17)
- -------------------
-
- - Tolerate Unicode attribute names (ASCII only). LP #143358.
-
- - Make module-level ``aq_acquire`` API respect the ``default`` parameter.
- LP #1387363.
-
- - Don't raise an attribute error for ``__iter__`` if the fallback to
- ``__getitem__`` succeeds. LP #1155760.
-
- 2.13.8 (2011-06-11)
- -------------------
-
- - Fixed a segfault on 64bit platforms when providing the `explicit` argument to
- the aq_acquire method of an Acquisition wrapper. Thx to LP #675064 for the
- hint to the solution. The code passed an int instead of a pointer into a
- function.
-
- 2.13.7 (2011-03-02)
- -------------------
-
- - Fixed bug: When an object did not implement ``__unicode__``, calling
- ``unicode(wrapped)`` was calling ``__str__`` with an unwrapped ``self``.
-
- 2.13.6 (2011-02-19)
- -------------------
-
- - Add ``aq_explicit`` to ``IAcquisitionWrapper``.
-
- - Fixed bug: ``unicode(wrapped)`` was not calling a ``__unicode__``
- method on wrapped objects.
-
- 2.13.5 (2010-09-29)
- -------------------
-
- - Fixed unit tests that failed on 64bit Python on Windows machines.
-
- 2.13.4 (2010-08-31)
- -------------------
-
- - LP 623665: Fixed typo in Acquisition.h.
-
- 2.13.3 (2010-04-19)
- -------------------
-
- - Use the doctest module from the standard library and no longer depend on
- zope.testing.
-
- 2.13.2 (2010-04-04)
- -------------------
-
- - Give both wrapper classes a ``__getnewargs__`` method, which causes the ZODB
- optimization to fail and create persistent references using the ``_p_oid``
- alone. This happens to be the persistent oid of the wrapped object. This lets
- these objects to be persisted correctly, even though they are passed to the
- ZODB in a wrapped state.
-
- - Added failing tests for http://dev.plone.org/plone/ticket/10318. This shows
- an edge-case where AQ wrappers can be pickled using the specific combination
- of cPickle, pickle protocol one and a custom Pickler class with an
- ``inst_persistent_id`` hook. Unfortunately this is the exact combination used
- by ZODB3.
-
- 2.13.1 (2010-02-23)
- -------------------
-
- - Update to include ExtensionClass 2.13.0.
-
- - Fix the ``tp_name`` of the ImplicitAcquisitionWrapper and
- ExplicitAcquisitionWrapper to match their Python visible names and thus have
- a correct ``__name__``.
-
- - Expand the ``tp_name`` of our extension types to hold the fully qualified
- name. This ensures classes have their ``__module__`` set correctly.
-
- 2.13.0 (2010-02-14)
- -------------------
-
- - Added support for method cache in Acquisition. Patch contributed by
- Yoshinori K. Okuji. See https://bugs.launchpad.net/zope2/+bug/486182.
-
- 2.12.4 (2009-10-29)
- -------------------
-
- - Fix iteration proxying to pass `self` acquisition-wrapped into both
- `__iter__` as well as `__getitem__` (this fixes
- https://bugs.launchpad.net/zope2/+bug/360761).
-
- - Add tests for the __getslice__ proxying, including open-ended slicing.
-
- 2.12.3 (2009-08-08)
- -------------------
-
- - More 64-bit fixes in Py_BuildValue calls.
-
- - More 64-bit issues fixed: Use correct integer size for slice operations.
-
- 2.12.2 (2009-08-02)
- -------------------
-
- - Fixed 64-bit compatibility issues for Python 2.5.x / 2.6.x. See
- http://www.python.org/dev/peps/pep-0353/ for details.
-
- 2.12.1 (2009-04-15)
- -------------------
-
- - Update for iteration proxying: The proxy for `__iter__` must not rely on the
- object to have an `__iter__` itself, but also support fall-back iteration via
- `__getitem__` (this fixes https://bugs.launchpad.net/zope2/+bug/360761).
-
- 2.12 (2009-01-25)
- -----------------
-
- - Release as separate package.
-
- Platform: UNKNOWN
- Classifier: Development Status :: 6 - Mature
- Classifier: Environment :: Web Environment
- Classifier: Framework :: Zope2
- Classifier: License :: OSI Approved :: Zope Public License
- Classifier: Operating System :: OS Independent
- Classifier: Programming Language :: Python
- Classifier: Programming Language :: Python :: 2
- Classifier: Programming Language :: Python :: 2.7
- Classifier: Programming Language :: Python :: 3
- Classifier: Programming Language :: Python :: 3.4
- Classifier: Programming Language :: Python :: 3.5
- Classifier: Programming Language :: Python :: 3.6
- Classifier: Programming Language :: Python :: 3.7
- Classifier: Programming Language :: Python :: Implementation :: CPython
- Classifier: Programming Language :: Python :: Implementation :: PyPy
|