diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | python-objproxies.spec | 777 | ||||
-rw-r--r-- | sources | 1 |
3 files changed, 779 insertions, 0 deletions
@@ -0,0 +1 @@ +/objproxies-0.9.4.tar.gz diff --git a/python-objproxies.spec b/python-objproxies.spec new file mode 100644 index 0000000..fea142c --- /dev/null +++ b/python-objproxies.spec @@ -0,0 +1,777 @@ +%global _empty_manifest_terminate_build 0 +Name: python-objproxies +Version: 0.9.4 +Release: 1 +Summary: General purpose proxy and wrapper types +License: PSF or ZPL +URL: http://github.com/soulrebel/objproxies +Source0: https://mirrors.nju.edu.cn/pypi/web/packages/1d/6b/0434d100d411760d4d634e21dc256e259af720887b0c856c5a9b2c97ea30/objproxies-0.9.4.tar.gz +BuildArch: noarch + + +%description +The ``objproxies`` module provides some useful base classes for creating +proxies and wrappers for ordinary Python objects. Proxy objects automatically +delegate all attribute access and operations to the proxied object. Wrappers +are similar, but can be subclassed to allow additional attributes and +operations to be added to the wrapped object. +Note that these proxy types are not intended to be tamper-proof; the unproxied +form of an object can be readily accessed using a proxy's ``__subject__`` +attribute, and some proxy types even allow this attribute to be set (This can +be handy for algorithms that lazily create circular structures and thus need to +be able to hand out "forward reference" proxies.) +Development status +****************** +This is Python 3 port of `ProxyTypes +<http://cheeseshop.python.org/pypi/ProxyTypes>`_ wrote by Phillip J. Eby as +part of `PEAK <http://www.eby-sarna.com/mailman/listinfo/peak>`_ for Python 2. +The namespace was changed from ``peak.util.proxies`` to ``objproxies``. Other +than that it should be a compatible replacement. +So far the following was accomplished: +* Streamlined files and setup +* Ported unittests and doctests +* Cleaned up syntax +v1.0 TODO ++++++++++ +* Turn the module in a package, separate functionalities in different modules +* Simplify code wherever possible +* Get positive feedback from a couple of users +Contributions and bug reports are welcome. +Testing ++++++++ +When nose is available all tests can be run using: + nosetests3 --with-doctest --doctest-extension=rst . +Otherwise standard python will suffice: + python -m unittest objproxies_tests.py + python -m doctest README.rst +Proxy Basics +************ +Here's a quick demo of the ``ObjectProxy`` type:: + >>> from objproxies import ObjectProxy + >>> p = ObjectProxy(42) + >>> p + 42 + >>> isinstance(p, int) + True + >>> p.__class__ + <class 'int'> + >>> p*2 + 84 + >>> 'X' * p + 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + >>> hex(p) + '0x2a' + >>> chr(p) + '*' + >>> p ^ 1 + 43 + >>> p ** 2 + 1764 +As you can see, a proxy is virtually indistinguishable from the object it +proxies, except via its ``__subject__`` attribute, and its ``type()``:: + >>> p.__subject__ + 42 + >>> type(p) + <class 'objproxies.ObjectProxy'> +You can change the ``__subject__`` of an ``ObjectProxy``, and it will then +refer to something else:: + >>> p.__subject__ = 99 + >>> p + 99 + >>> p-33 + 66 + >>> p.__subject__ = "foo" + >>> p + 'foo' +All operations are delegated to the subject, including ``setattr`` and +``delattr``:: + >>> class Dummy: pass + >>> d = Dummy() + >>> p = ObjectProxy(d) + >>> p.foo = "bar" + >>> d.foo + 'bar' + >>> del p.foo + >>> hasattr(d,'foo') + False +Callback Proxies +**************** +Sometimes, you may want a proxy's subject to be determined dynamically whenever +the proxy is used. For this purpose, you can use the ``CallbackProxy`` type, +which accepts a callback function and creates a proxy that will invoke the +callback in order to get the target. Here's a quick example of a counter that +gets incremented each time it's used, from zero to three:: + >>> from objproxies import CallbackProxy + >>> callback = iter(range(4)).__next__ + >>> counter = CallbackProxy(callback) + >>> counter + 0 + >>> counter + 1 + >>> str(counter) + '2' + >>> hex(counter) + '0x3' + >>> counter + Traceback (most recent call last): + StopIteration +As you can see, the callback is automatically invoked on any attempt to use the +proxy. This is a somewhat silly example; a better one would be something like +a ``thread_id`` proxy that is always equal to the ID # of the thread it's +running in. +A callback proxy's callback can be obtained or changed via the ``get_callback`` +and ``set_callback`` functions:: + >>> from objproxies import get_callback, set_callback + >>> set_callback(counter, lambda: 42) + >>> counter + 42 + >>> type(get_callback(counter)) + <class 'function'> +Lazy Proxies +************ +A ``LazyProxy`` is similar to a ``CallbackProxy``, but its callback is called +at most once, and then cached:: + >>> from objproxies import LazyProxy + >>> def callback(): + >>> lazy = LazyProxy(callback) + >>> lazy + called + 42 + >>> lazy + 42 +You can use the ``get_callback`` and ``set_callback`` functions on lazy +proxies, but it has no effect if the callback was already called:: + >>> set_callback(lazy, lambda: 99) + >>> lazy + 42 +But you can use the ``get_cache`` and ``set_cache`` functions to tamper with +the cached value:: + >>> from objproxies import get_cache, set_cache + >>> get_cache(lazy) + 42 + >>> set_cache(lazy, 99) + >>> lazy + 99 +Wrappers +******** +The ``ObjectWrapper``, ``CallbackWrapper`` and ``LazyWrapper`` classes are +similar to their proxy counterparts, except that they are intended to be +subclassed in order to add custom extra attributes or methods. Any attribute +that exists in a subclass of these classes will be read or written from the +wrapper instance, instead of the wrapped object. For example:: + >>> from objproxies import ObjectWrapper + >>> class NameWrapper(ObjectWrapper): + >>> w = NameWrapper(42, "The Ultimate Answer") + >>> w + 42 + >>> print(w) + The Ultimate Answer + >>> w * 2 + 84 + >>> w.name + 'The Ultimate Answer' +Notice that any attributes you add must be defined *in the class*. You can't +add arbitrary attributes at runtime, because they'll be set on the wrapped +object instead of the wrapper:: + >>> w.foo = 'bar' + Traceback (most recent call last): + AttributeError: 'int' object has no attribute 'foo' +Note that this means that all instance attributes must be implemented as either +slots, properties, or have a default value defined in the class body (like the +``name = None`` shown in the example above. +The ``CallbackWrapper`` and ``LazyWrapper`` base classes are basically the same +as ``ObjectWrapper``, except that they use a callback or cached lazy callback +instead of expecting an object as their subject. +``LazyWrapper`` objects are particularly useful when working with expensive +resources, like connections or web browsers, to avoid their creation unless +absolutely needed. +However resources usually must be released after use by calling a "``close``" +method of some sort. In this case the lazy creation could be triggered just +when the object is not needed anymore, by the call to ``close`` itself. For +this reason when extending ``LazyWrapper`` these methods can be overridden with +a ``@lazymethod`` replacement:: + >>> from objproxies import LazyWrapper, lazymethod + >>> class LazyCloseable(LazyWrapper): + >>> import tempfile + >>> def openf(): + >>> lazyfile = LazyCloseable(openf) + >>> lazyfile.tell() + 0 + >>> lazyfile.close() + bye + >>> bool(lazyfile) + False + >>> lazyfile = LazyCloseable(openf) + >>> lazyfile.write('wake up') + called + 7 + >>> lazyfile.tell() + 7 + >>> lazyfile.close() # close for real + >>> bool(lazyfile) + True +Advanced: custom subclasses and mixins +************************************** +In addition to all the concrete classes described above, there are also two +abstract base classes: ``AbstractProxy`` and ``AbstractWrapper``. If you want +to create a mixin type that can be used with any of the concrete types, you +should subclass the abstract version and set ``__slots__`` to an empty list:: + >>> from objproxies import AbstractWrapper + >>> class NamedMixin(AbstractWrapper): +Then, when you mix it in with the respective base class, you can add back in +any necessary slots, or leave off ``__slots__`` to give the subclass instances +a dictionary of their own:: + >>> from objproxies import CallbackWrapper, LazyWrapper + >>> class NamedObject(NamedMixin, ObjectWrapper): pass + >>> class NamedCallback(NamedMixin, CallbackWrapper): pass + >>> class NamedLazy(NamedMixin, LazyWrapper): pass + >>> print(NamedObject(42, "The Answer")) + The Answer + >>> n = NamedCallback(callback, "Test") + >>> n + called + 42 + >>> n + called + 42 + >>> n = NamedLazy(callback, "Once") + >>> n + called + 42 + >>> n + 42 +Both the ``AbstractProxy`` and ``AbstractWrapper`` base classes work by +assuming that ``self.__subject__`` will be the wrapped or proxed object. If +you don't want to use any of the standard three ways of defining +``__subject__`` (i.e., as an object, callback, or lazy callback), you will need +to subclass ``AbstractProxy`` or ``AbstractWrapper`` and provide your own way +of defining ``__subject__``. + +%package -n python3-objproxies +Summary: General purpose proxy and wrapper types +Provides: python-objproxies +BuildRequires: python3-devel +BuildRequires: python3-setuptools +BuildRequires: python3-pip +%description -n python3-objproxies +The ``objproxies`` module provides some useful base classes for creating +proxies and wrappers for ordinary Python objects. Proxy objects automatically +delegate all attribute access and operations to the proxied object. Wrappers +are similar, but can be subclassed to allow additional attributes and +operations to be added to the wrapped object. +Note that these proxy types are not intended to be tamper-proof; the unproxied +form of an object can be readily accessed using a proxy's ``__subject__`` +attribute, and some proxy types even allow this attribute to be set (This can +be handy for algorithms that lazily create circular structures and thus need to +be able to hand out "forward reference" proxies.) +Development status +****************** +This is Python 3 port of `ProxyTypes +<http://cheeseshop.python.org/pypi/ProxyTypes>`_ wrote by Phillip J. Eby as +part of `PEAK <http://www.eby-sarna.com/mailman/listinfo/peak>`_ for Python 2. +The namespace was changed from ``peak.util.proxies`` to ``objproxies``. Other +than that it should be a compatible replacement. +So far the following was accomplished: +* Streamlined files and setup +* Ported unittests and doctests +* Cleaned up syntax +v1.0 TODO ++++++++++ +* Turn the module in a package, separate functionalities in different modules +* Simplify code wherever possible +* Get positive feedback from a couple of users +Contributions and bug reports are welcome. +Testing ++++++++ +When nose is available all tests can be run using: + nosetests3 --with-doctest --doctest-extension=rst . +Otherwise standard python will suffice: + python -m unittest objproxies_tests.py + python -m doctest README.rst +Proxy Basics +************ +Here's a quick demo of the ``ObjectProxy`` type:: + >>> from objproxies import ObjectProxy + >>> p = ObjectProxy(42) + >>> p + 42 + >>> isinstance(p, int) + True + >>> p.__class__ + <class 'int'> + >>> p*2 + 84 + >>> 'X' * p + 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + >>> hex(p) + '0x2a' + >>> chr(p) + '*' + >>> p ^ 1 + 43 + >>> p ** 2 + 1764 +As you can see, a proxy is virtually indistinguishable from the object it +proxies, except via its ``__subject__`` attribute, and its ``type()``:: + >>> p.__subject__ + 42 + >>> type(p) + <class 'objproxies.ObjectProxy'> +You can change the ``__subject__`` of an ``ObjectProxy``, and it will then +refer to something else:: + >>> p.__subject__ = 99 + >>> p + 99 + >>> p-33 + 66 + >>> p.__subject__ = "foo" + >>> p + 'foo' +All operations are delegated to the subject, including ``setattr`` and +``delattr``:: + >>> class Dummy: pass + >>> d = Dummy() + >>> p = ObjectProxy(d) + >>> p.foo = "bar" + >>> d.foo + 'bar' + >>> del p.foo + >>> hasattr(d,'foo') + False +Callback Proxies +**************** +Sometimes, you may want a proxy's subject to be determined dynamically whenever +the proxy is used. For this purpose, you can use the ``CallbackProxy`` type, +which accepts a callback function and creates a proxy that will invoke the +callback in order to get the target. Here's a quick example of a counter that +gets incremented each time it's used, from zero to three:: + >>> from objproxies import CallbackProxy + >>> callback = iter(range(4)).__next__ + >>> counter = CallbackProxy(callback) + >>> counter + 0 + >>> counter + 1 + >>> str(counter) + '2' + >>> hex(counter) + '0x3' + >>> counter + Traceback (most recent call last): + StopIteration +As you can see, the callback is automatically invoked on any attempt to use the +proxy. This is a somewhat silly example; a better one would be something like +a ``thread_id`` proxy that is always equal to the ID # of the thread it's +running in. +A callback proxy's callback can be obtained or changed via the ``get_callback`` +and ``set_callback`` functions:: + >>> from objproxies import get_callback, set_callback + >>> set_callback(counter, lambda: 42) + >>> counter + 42 + >>> type(get_callback(counter)) + <class 'function'> +Lazy Proxies +************ +A ``LazyProxy`` is similar to a ``CallbackProxy``, but its callback is called +at most once, and then cached:: + >>> from objproxies import LazyProxy + >>> def callback(): + >>> lazy = LazyProxy(callback) + >>> lazy + called + 42 + >>> lazy + 42 +You can use the ``get_callback`` and ``set_callback`` functions on lazy +proxies, but it has no effect if the callback was already called:: + >>> set_callback(lazy, lambda: 99) + >>> lazy + 42 +But you can use the ``get_cache`` and ``set_cache`` functions to tamper with +the cached value:: + >>> from objproxies import get_cache, set_cache + >>> get_cache(lazy) + 42 + >>> set_cache(lazy, 99) + >>> lazy + 99 +Wrappers +******** +The ``ObjectWrapper``, ``CallbackWrapper`` and ``LazyWrapper`` classes are +similar to their proxy counterparts, except that they are intended to be +subclassed in order to add custom extra attributes or methods. Any attribute +that exists in a subclass of these classes will be read or written from the +wrapper instance, instead of the wrapped object. For example:: + >>> from objproxies import ObjectWrapper + >>> class NameWrapper(ObjectWrapper): + >>> w = NameWrapper(42, "The Ultimate Answer") + >>> w + 42 + >>> print(w) + The Ultimate Answer + >>> w * 2 + 84 + >>> w.name + 'The Ultimate Answer' +Notice that any attributes you add must be defined *in the class*. You can't +add arbitrary attributes at runtime, because they'll be set on the wrapped +object instead of the wrapper:: + >>> w.foo = 'bar' + Traceback (most recent call last): + AttributeError: 'int' object has no attribute 'foo' +Note that this means that all instance attributes must be implemented as either +slots, properties, or have a default value defined in the class body (like the +``name = None`` shown in the example above. +The ``CallbackWrapper`` and ``LazyWrapper`` base classes are basically the same +as ``ObjectWrapper``, except that they use a callback or cached lazy callback +instead of expecting an object as their subject. +``LazyWrapper`` objects are particularly useful when working with expensive +resources, like connections or web browsers, to avoid their creation unless +absolutely needed. +However resources usually must be released after use by calling a "``close``" +method of some sort. In this case the lazy creation could be triggered just +when the object is not needed anymore, by the call to ``close`` itself. For +this reason when extending ``LazyWrapper`` these methods can be overridden with +a ``@lazymethod`` replacement:: + >>> from objproxies import LazyWrapper, lazymethod + >>> class LazyCloseable(LazyWrapper): + >>> import tempfile + >>> def openf(): + >>> lazyfile = LazyCloseable(openf) + >>> lazyfile.tell() + 0 + >>> lazyfile.close() + bye + >>> bool(lazyfile) + False + >>> lazyfile = LazyCloseable(openf) + >>> lazyfile.write('wake up') + called + 7 + >>> lazyfile.tell() + 7 + >>> lazyfile.close() # close for real + >>> bool(lazyfile) + True +Advanced: custom subclasses and mixins +************************************** +In addition to all the concrete classes described above, there are also two +abstract base classes: ``AbstractProxy`` and ``AbstractWrapper``. If you want +to create a mixin type that can be used with any of the concrete types, you +should subclass the abstract version and set ``__slots__`` to an empty list:: + >>> from objproxies import AbstractWrapper + >>> class NamedMixin(AbstractWrapper): +Then, when you mix it in with the respective base class, you can add back in +any necessary slots, or leave off ``__slots__`` to give the subclass instances +a dictionary of their own:: + >>> from objproxies import CallbackWrapper, LazyWrapper + >>> class NamedObject(NamedMixin, ObjectWrapper): pass + >>> class NamedCallback(NamedMixin, CallbackWrapper): pass + >>> class NamedLazy(NamedMixin, LazyWrapper): pass + >>> print(NamedObject(42, "The Answer")) + The Answer + >>> n = NamedCallback(callback, "Test") + >>> n + called + 42 + >>> n + called + 42 + >>> n = NamedLazy(callback, "Once") + >>> n + called + 42 + >>> n + 42 +Both the ``AbstractProxy`` and ``AbstractWrapper`` base classes work by +assuming that ``self.__subject__`` will be the wrapped or proxed object. If +you don't want to use any of the standard three ways of defining +``__subject__`` (i.e., as an object, callback, or lazy callback), you will need +to subclass ``AbstractProxy`` or ``AbstractWrapper`` and provide your own way +of defining ``__subject__``. + +%package help +Summary: Development documents and examples for objproxies +Provides: python3-objproxies-doc +%description help +The ``objproxies`` module provides some useful base classes for creating +proxies and wrappers for ordinary Python objects. Proxy objects automatically +delegate all attribute access and operations to the proxied object. Wrappers +are similar, but can be subclassed to allow additional attributes and +operations to be added to the wrapped object. +Note that these proxy types are not intended to be tamper-proof; the unproxied +form of an object can be readily accessed using a proxy's ``__subject__`` +attribute, and some proxy types even allow this attribute to be set (This can +be handy for algorithms that lazily create circular structures and thus need to +be able to hand out "forward reference" proxies.) +Development status +****************** +This is Python 3 port of `ProxyTypes +<http://cheeseshop.python.org/pypi/ProxyTypes>`_ wrote by Phillip J. Eby as +part of `PEAK <http://www.eby-sarna.com/mailman/listinfo/peak>`_ for Python 2. +The namespace was changed from ``peak.util.proxies`` to ``objproxies``. Other +than that it should be a compatible replacement. +So far the following was accomplished: +* Streamlined files and setup +* Ported unittests and doctests +* Cleaned up syntax +v1.0 TODO ++++++++++ +* Turn the module in a package, separate functionalities in different modules +* Simplify code wherever possible +* Get positive feedback from a couple of users +Contributions and bug reports are welcome. +Testing ++++++++ +When nose is available all tests can be run using: + nosetests3 --with-doctest --doctest-extension=rst . +Otherwise standard python will suffice: + python -m unittest objproxies_tests.py + python -m doctest README.rst +Proxy Basics +************ +Here's a quick demo of the ``ObjectProxy`` type:: + >>> from objproxies import ObjectProxy + >>> p = ObjectProxy(42) + >>> p + 42 + >>> isinstance(p, int) + True + >>> p.__class__ + <class 'int'> + >>> p*2 + 84 + >>> 'X' * p + 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + >>> hex(p) + '0x2a' + >>> chr(p) + '*' + >>> p ^ 1 + 43 + >>> p ** 2 + 1764 +As you can see, a proxy is virtually indistinguishable from the object it +proxies, except via its ``__subject__`` attribute, and its ``type()``:: + >>> p.__subject__ + 42 + >>> type(p) + <class 'objproxies.ObjectProxy'> +You can change the ``__subject__`` of an ``ObjectProxy``, and it will then +refer to something else:: + >>> p.__subject__ = 99 + >>> p + 99 + >>> p-33 + 66 + >>> p.__subject__ = "foo" + >>> p + 'foo' +All operations are delegated to the subject, including ``setattr`` and +``delattr``:: + >>> class Dummy: pass + >>> d = Dummy() + >>> p = ObjectProxy(d) + >>> p.foo = "bar" + >>> d.foo + 'bar' + >>> del p.foo + >>> hasattr(d,'foo') + False +Callback Proxies +**************** +Sometimes, you may want a proxy's subject to be determined dynamically whenever +the proxy is used. For this purpose, you can use the ``CallbackProxy`` type, +which accepts a callback function and creates a proxy that will invoke the +callback in order to get the target. Here's a quick example of a counter that +gets incremented each time it's used, from zero to three:: + >>> from objproxies import CallbackProxy + >>> callback = iter(range(4)).__next__ + >>> counter = CallbackProxy(callback) + >>> counter + 0 + >>> counter + 1 + >>> str(counter) + '2' + >>> hex(counter) + '0x3' + >>> counter + Traceback (most recent call last): + StopIteration +As you can see, the callback is automatically invoked on any attempt to use the +proxy. This is a somewhat silly example; a better one would be something like +a ``thread_id`` proxy that is always equal to the ID # of the thread it's +running in. +A callback proxy's callback can be obtained or changed via the ``get_callback`` +and ``set_callback`` functions:: + >>> from objproxies import get_callback, set_callback + >>> set_callback(counter, lambda: 42) + >>> counter + 42 + >>> type(get_callback(counter)) + <class 'function'> +Lazy Proxies +************ +A ``LazyProxy`` is similar to a ``CallbackProxy``, but its callback is called +at most once, and then cached:: + >>> from objproxies import LazyProxy + >>> def callback(): + >>> lazy = LazyProxy(callback) + >>> lazy + called + 42 + >>> lazy + 42 +You can use the ``get_callback`` and ``set_callback`` functions on lazy +proxies, but it has no effect if the callback was already called:: + >>> set_callback(lazy, lambda: 99) + >>> lazy + 42 +But you can use the ``get_cache`` and ``set_cache`` functions to tamper with +the cached value:: + >>> from objproxies import get_cache, set_cache + >>> get_cache(lazy) + 42 + >>> set_cache(lazy, 99) + >>> lazy + 99 +Wrappers +******** +The ``ObjectWrapper``, ``CallbackWrapper`` and ``LazyWrapper`` classes are +similar to their proxy counterparts, except that they are intended to be +subclassed in order to add custom extra attributes or methods. Any attribute +that exists in a subclass of these classes will be read or written from the +wrapper instance, instead of the wrapped object. For example:: + >>> from objproxies import ObjectWrapper + >>> class NameWrapper(ObjectWrapper): + >>> w = NameWrapper(42, "The Ultimate Answer") + >>> w + 42 + >>> print(w) + The Ultimate Answer + >>> w * 2 + 84 + >>> w.name + 'The Ultimate Answer' +Notice that any attributes you add must be defined *in the class*. You can't +add arbitrary attributes at runtime, because they'll be set on the wrapped +object instead of the wrapper:: + >>> w.foo = 'bar' + Traceback (most recent call last): + AttributeError: 'int' object has no attribute 'foo' +Note that this means that all instance attributes must be implemented as either +slots, properties, or have a default value defined in the class body (like the +``name = None`` shown in the example above. +The ``CallbackWrapper`` and ``LazyWrapper`` base classes are basically the same +as ``ObjectWrapper``, except that they use a callback or cached lazy callback +instead of expecting an object as their subject. +``LazyWrapper`` objects are particularly useful when working with expensive +resources, like connections or web browsers, to avoid their creation unless +absolutely needed. +However resources usually must be released after use by calling a "``close``" +method of some sort. In this case the lazy creation could be triggered just +when the object is not needed anymore, by the call to ``close`` itself. For +this reason when extending ``LazyWrapper`` these methods can be overridden with +a ``@lazymethod`` replacement:: + >>> from objproxies import LazyWrapper, lazymethod + >>> class LazyCloseable(LazyWrapper): + >>> import tempfile + >>> def openf(): + >>> lazyfile = LazyCloseable(openf) + >>> lazyfile.tell() + 0 + >>> lazyfile.close() + bye + >>> bool(lazyfile) + False + >>> lazyfile = LazyCloseable(openf) + >>> lazyfile.write('wake up') + called + 7 + >>> lazyfile.tell() + 7 + >>> lazyfile.close() # close for real + >>> bool(lazyfile) + True +Advanced: custom subclasses and mixins +************************************** +In addition to all the concrete classes described above, there are also two +abstract base classes: ``AbstractProxy`` and ``AbstractWrapper``. If you want +to create a mixin type that can be used with any of the concrete types, you +should subclass the abstract version and set ``__slots__`` to an empty list:: + >>> from objproxies import AbstractWrapper + >>> class NamedMixin(AbstractWrapper): +Then, when you mix it in with the respective base class, you can add back in +any necessary slots, or leave off ``__slots__`` to give the subclass instances +a dictionary of their own:: + >>> from objproxies import CallbackWrapper, LazyWrapper + >>> class NamedObject(NamedMixin, ObjectWrapper): pass + >>> class NamedCallback(NamedMixin, CallbackWrapper): pass + >>> class NamedLazy(NamedMixin, LazyWrapper): pass + >>> print(NamedObject(42, "The Answer")) + The Answer + >>> n = NamedCallback(callback, "Test") + >>> n + called + 42 + >>> n + called + 42 + >>> n = NamedLazy(callback, "Once") + >>> n + called + 42 + >>> n + 42 +Both the ``AbstractProxy`` and ``AbstractWrapper`` base classes work by +assuming that ``self.__subject__`` will be the wrapped or proxed object. If +you don't want to use any of the standard three ways of defining +``__subject__`` (i.e., as an object, callback, or lazy callback), you will need +to subclass ``AbstractProxy`` or ``AbstractWrapper`` and provide your own way +of defining ``__subject__``. + +%prep +%autosetup -n objproxies-0.9.4 + +%build +%py3_build + +%install +%py3_install +install -d -m755 %{buildroot}/%{_pkgdocdir} +if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi +if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi +if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi +if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi +pushd %{buildroot} +if [ -d usr/lib ]; then + find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/lib64 ]; then + find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/bin ]; then + find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst +fi +if [ -d usr/sbin ]; then + find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst +fi +touch doclist.lst +if [ -d usr/share/man ]; then + find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst +fi +popd +mv %{buildroot}/filelist.lst . +mv %{buildroot}/doclist.lst . + +%files -n python3-objproxies -f filelist.lst +%dir %{python3_sitelib}/* + +%files help -f doclist.lst +%{_docdir}/* + +%changelog +* Wed May 10 2023 Python_Bot <Python_Bot@openeuler.org> - 0.9.4-1 +- Package Spec generated @@ -0,0 +1 @@ +cc6108a5a0b74fd89a90c87ee58849d3 objproxies-0.9.4.tar.gz |