././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1696517994.5431473 zope.proxy-5.1/0000755000076500000240000000000014507547553012415 5ustar00jensstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696501643.0 zope.proxy-5.1/.coveragerc0000644000076500000240000000111014507507613014520 0ustar00jensstaff# Generated from: # https://github.com/zopefoundation/meta/tree/master/config/c-code [run] source = zope.proxy # New in 5.0; required for the GHA coveralls submission. relative_files = True branch = true [paths] source = src/ .tox/*/lib/python*/site-packages/ .tox/pypy*/site-packages/ [report] show_missing = true precision = 2 exclude_lines = except ImportError: if __name__ == '__main__': pragma: no cover pragma: nocover raise AssertionError raise NotImplementedError raise unittest.Skip self.fail\( [html] directory = parts/htmlcov ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696516779.0 zope.proxy-5.1/.manylinux-install.sh0000755000076500000240000000370714507545253016524 0ustar00jensstaff#!/usr/bin/env bash # Generated from: # https://github.com/zopefoundation/meta/tree/master/config/c-code set -e -x # Running inside docker # Set a cache directory for pip. This was # mounted to be the same as it is outside docker so it # can be persisted. export XDG_CACHE_HOME="/cache" # XXX: This works for macOS, where everything bind-mounted # is seen as owned by root in the container. But when the host is Linux # the actual UIDs come through to the container, triggering # pip to disable the cache when it detects that the owner doesn't match. # The below is an attempt to fix that, taken from bcrypt. It seems to work on # Github Actions. if [ -n "$GITHUB_ACTIONS" ]; then echo Adjusting pip cache permissions mkdir -p $XDG_CACHE_HOME/pip chown -R $(whoami) $XDG_CACHE_HOME fi ls -ld /cache ls -ld /cache/pip # We need some libraries because we build wheels from scratch: yum -y install libffi-devel tox_env_map() { case $1 in *"cp37"*) echo 'py37';; *"cp38"*) echo 'py38';; *"cp39"*) echo 'py39';; *"cp310"*) echo 'py310';; *"cp311"*) echo 'py311';; *"cp312"*) echo 'py312';; *) echo 'py';; esac } # Compile wheels for PYBIN in /opt/python/*/bin; do if \ [[ "${PYBIN}" == *"cp311"* ]] || \ [[ "${PYBIN}" == *"cp312"* ]] || \ [[ "${PYBIN}" == *"cp37"* ]] || \ [[ "${PYBIN}" == *"cp38"* ]] || \ [[ "${PYBIN}" == *"cp39"* ]] || \ [[ "${PYBIN}" == *"cp310"* ]] ; then "${PYBIN}/pip" install -e /io/ "${PYBIN}/pip" wheel /io/ -w wheelhouse/ if [ `uname -m` == 'aarch64' ]; then cd /io/ ${PYBIN}/pip install tox TOXENV=$(tox_env_map "${PYBIN}") ${PYBIN}/tox -e ${TOXENV} cd .. fi rm -rf /io/build /io/*.egg-info fi done # Bundle external shared libraries into the wheels for whl in wheelhouse/zope.proxy*.whl; do auditwheel repair "$whl" -w /io/wheelhouse/ done ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696501643.0 zope.proxy-5.1/.manylinux.sh0000755000076500000240000000077514507507613015060 0ustar00jensstaff#!/usr/bin/env bash # Generated from: # https://github.com/zopefoundation/meta/tree/master/config/c-code set -e -x # Mount the current directory as /io # Mount the pip cache directory as /cache # `pip cache` requires pip 20.1 echo Setting up caching python --version python -mpip --version LCACHE="$(dirname `python -mpip cache dir`)" echo Sharing pip cache at $LCACHE $(ls -ld $LCACHE) docker run --rm -e GITHUB_ACTIONS -v "$(pwd)":/io -v "$LCACHE:/cache" $DOCKER_IMAGE $PRE_CMD /io/.manylinux-install.sh ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696501643.0 zope.proxy-5.1/.readthedocs.yaml0000644000076500000240000000123014507507613015631 0ustar00jensstaff# Generated from: # https://github.com/zopefoundation/meta/tree/master/config/c-code # Read the Docs configuration file # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details # Required version: 2 # Set the version of Python and other tools you might need build: os: ubuntu-22.04 tools: python: "3.11" # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/conf.py # We recommend specifying your dependencies to enable reproducible builds: # https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html python: install: - requirements: docs/requirements.txt - method: pip path: . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696516779.0 zope.proxy-5.1/CHANGES.rst0000644000076500000240000002005414507545253014213 0ustar00jensstaff========= Changes ========= 5.1 (2023-10-05) ================ - Add support for Python 3.12. 5.0.0 (2023-01-18) ================== - Drop support for Python 2.7, 3.5, 3.6. - Remove proxying code for names that no longer exist in Python 3 like ``__long__`` and some others. (`#55 `_) 4.6.1 (2022-11-16) ================== - Add support for building arm64 wheels on macOS. 4.6.0 (2022-11-03) ================== - Add support for Python 3.11. 4.5.1 (2022-09-15) ================== - Disable unsafe math optimizations in C code. See `pull request 53 `_. 4.5.0 (2021-11-17) ================== - Add support for Python 3.10. 4.4.0 (2021-07-22) ================== - Add support for Python 3.9. - Create aarch64 wheels. 4.3.5 (2020-03-16) ================== - Stop installing C header files on PyPy (which is what zope.proxy before 4.3.4 used to do), fixes `issue 39 `_. 4.3.4 (2020-03-13) ================== - Fix a compilation warning on Python 3.8. The slot ``tp_print`` changed to ``tp_vectorcall_offset`` in 3.8 and must not be set. Prior to 3.8, it was reserved and ignored in all Python 3 versions. See `issue 36 `_. - Remove deprecated use of setuptools features. See `issue 38 `_. 4.3.3 (2019-11-11) ================== - Add support for Python 3.8. - Drop support for Python 3.4. 4.3.2 (2019-07-12) ================== - Fix error handling in ``ProxyBase.__setattr__``: any the exception raised by ``PyString_AsString``/``PyUnicode_AsUTF8`` would be silently swallowed up and ignored. See `issue 31 `_. 4.3.1 (2018-08-09) ================== - Simplify the internal C handling of attribute names in ``__getattribute__`` and ``__setattr__``. - Make building the C extension optional. We still attempt to build it on supported platforms, but we allow it to fail in case of a missing compiler or headers. See `issue 26 `_. - Test the PURE_PYTHON environment and PyPy3 on Travis CI. - Add support for Python 3.7. 4.3.0 (2017-09-13) ================== - Fix a potential rare crash when deallocating proxies. See `issue 20 `_. - Drop support for Python 3.3. - Drop support for "python setup.py test". - 100% test coverage. - Fix indexing pure-Python proxies with slices under Python 3, and restore the use of ``__getslice__`` (if implemented by the target's type) under Python 2. Previously, pure-Python proxies would fail with an AttributeError when given a slice on Python 3, and on Python 2, a custom ``__getslice__`` was ignored. See `issue 21 `_. 4.2.1 (2017-04-23) ================== - Make the pure-Python implementation of ``sameProxiedObjects`` handle ``zope.security`` proxies. See `issue 15 `_. - Add support for Python 3.6. 4.2.0 (2016-05-05) ================== - Correctly strip ``zope.security`` proxies in ``removeAllProxies``. See `issue 13 `_. - Avoid poisoning the user's global wheel cache when testing ``PURE_PYTHON`` environments under ``tox``, - Drop support for Python 2.6 and 3.2. - Add support for Python 3.5. 4.1.6 (2015-06-02) ================== - Make subclasses of ProxyBase properly delegate ``__module__`` to the wrapped object. This fixes some ``zope.interface`` lookups under PyPy. - Make the pure-Python implementation of ProxyBase properly report the ``zope.interface`` interfaces implemented by builtin types like ``list``. This fixes some ``zope.interface`` lookups under PyPy. 4.1.5 (2015-05-19) ================== - Make the C implementation proxy ``__unicode__`` correctly. - Make the C implementation use the standard methods to proxy ``int`` and ``float``. - Make the pure Python implementation handle descriptors defined in subclasses like the C version. See https://github.com/zopefoundation/zope.proxy/issues/5. 4.1.4 (2014-03-19) ================== - Add support for Python 3.4. - Update ``bootstrap.py`` to version 2.2. 4.1.3 (2013-03-12) ================== - Fix interface object introspection in PyPy. For some reason PyPy makes attributes available despite the restrictive ``__slots__`` declaration. - Add a bunch of tests surrounding interface lookup and adaptation. 4.1.2 (2013-03-11) ================== - Make ``PyProxyBase.__iter__()`` return the result of ``PyProxyBase._wrapped.__iter__`` if available, otherwise falling back to Python internals. The previous implementation always created a generator. - In ``PyProxyBase.__setattr__()``, allow setting of properties on the proxy itself. This is needed to properly allow proxy extensions as was evidenced int he ``zope.security.decorator`` module. 4.1.1 (2012-12-31) ================== - Fleshed out PyPI Trove classifiers. 4.1.0 (2012-12-19) ================== - Enable compilation of dependent modules under Py3k. - Replace use of ``PyCObject`` APIs with equivalent ``PyCapsule`` APIs, except under Python 2.6. N.B. This change is an ABI incompatibility under Python 2.7: extensions built under Python 2.7 against 4.0.x versions of ``zope.proxy`` must be rebuilt. 4.0.1 (2012-11-21) ================== - Add support for Python 3.3. 4.0.0 (2012-06-06) ================== - Add support for PyPy. N.B.: the C extension is *not* built under PyPy. - Add a pure-Python reference / fallback implementations of ``zope.proxy.ProxyBase`` and the proxy module API functions. N.B.: the pure-Python proxy implements all regular features of ``ProxyBase``; however, it does not exclude access to the wrapped object in the same way that the C version does. If you need that information hiding (e.g., to implement security sandboxing), you still need to use the C version. - Add support for continuous integration using ``tox`` and ``jenkins``. - 100% unit test coverage. - Add Sphinx documentation: moved doctest examples to API reference. - Add 'setup.py docs' alias (installs ``Sphinx`` and dependencies). - Add 'setup.py dev' alias (runs ``setup.py develop`` plus installs ``nose`` and ``coverage``). - Replace deprecated ``zope.interface.implements`` usage with equivalent ``zope.interface.implementer`` decorator. - Drop support for Python 2.4 and 2.5. - Add Python 3.2 support. 3.6.1 (2010-07-06) ================== - Make tests compatible with Python 2.7. 3.6.0 (2010-04-30) ================== - Remove test extra and the remaining dependency on zope.testing. - Remove use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest. 3.5.0 (2009/01/31) ================== - Add support to bootstrap on Jython. - Use ``zope.container`` instead of ``zope.app.container``. 3.4.2 (2008/07/27) ================== - Make C code compatible with Python 2.5 on 64bit architectures. 3.4.1 (2008/06/24) ================== - Bug: Update ``setup.py`` script to conform to common layout. Also updated some of the fields. - Bug: Honor pre-cooked indices for tuples and lists in the ``__getslice__()`` and ``__setslice__()`` methods. See http://docs.python.org/ref/sequence-methods.html. 3.4.0 (2007/07/12) ================== - Feature: Add a ``decorator`` module that supports declaring interfaces on proxies that get blended with the interfaces of the things they proxy. 3.3.0 (2006/12/20) ================== - Corresponds to the verison of the ``zope.proxy`` package shipped as part of the Zope 3.3.0 release. 3.2.0 (2006/01/05) ================== - Corresponds to the verison of the ``zope.proxy`` package shipped as part of the Zope 3.2.0 release. 3.0.0 (2004/11/07) ================== - Corresponds to the verison of the ``zope.proxy`` package shipped as part of the Zope X3.0.0 release. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696501643.0 zope.proxy-5.1/CONTRIBUTING.md0000644000076500000240000000143714507507613014644 0ustar00jensstaff # Contributing to zopefoundation projects The projects under the zopefoundation GitHub organization are open source and welcome contributions in different forms: * bug reports * code improvements and bug fixes * documentation improvements * pull request reviews For any changes in the repository besides trivial typo fixes you are required to sign the contributor agreement. See https://www.zope.dev/developer/becoming-a-committer.html for details. Please visit our [Developer Guidelines](https://www.zope.dev/developer/guidelines.html) if you'd like to contribute code changes and our [guidelines for reporting bugs](https://www.zope.dev/developer/reporting-bugs.html) if you want to file a bug report. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/COPYRIGHT.txt0000644000076500000240000000004014330441244014500 0ustar00jensstaffZope Foundation and Contributors././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/LICENSE.txt0000644000076500000240000000402614330441244014222 0ustar00jensstaffZope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696501643.0 zope.proxy-5.1/MANIFEST.in0000644000076500000240000000066214507507613014150 0ustar00jensstaff# Generated from: # https://github.com/zopefoundation/meta/tree/master/config/c-code include *.md include *.rst include *.txt include buildout.cfg include tox.ini include appveyor.yml include .coveragerc recursive-include docs *.py recursive-include docs *.rst recursive-include docs *.txt recursive-include docs Makefile recursive-include src *.py include *.yaml include *.sh recursive-include docs *.bat recursive-include src *.h ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1696517994.543065 zope.proxy-5.1/PKG-INFO0000644000076500000240000002653414507547553013524 0ustar00jensstaffMetadata-Version: 2.1 Name: zope.proxy Version: 5.1 Summary: Generic Transparent Proxies Home-page: http://github.com/zopefoundation/zope.proxy Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Project-URL: Documentation, https://zopeproxy.readthedocs.io Project-URL: Issue Tracker, https://github.com/zopefoundation/zope.proxy/issues Project-URL: Sources, https://github.com/zopefoundation/zope.proxy Keywords: proxy generic transparent Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Framework :: Zope :: 3 Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Requires-Python: >=3.7 License-File: LICENSE.txt Requires-Dist: zope.interface Requires-Dist: setuptools Provides-Extra: test Requires-Dist: zope.security; extra == "test" Requires-Dist: zope.testrunner; extra == "test" Provides-Extra: docs Requires-Dist: Sphinx; extra == "docs" Requires-Dist: repoze.sphinx.autointerface; extra == "docs" Requires-Dist: sphinx_rtd_theme; extra == "docs" ================ ``zope.proxy`` ================ .. image:: https://github.com/zopefoundation/zope.proxy/actions/workflows/tests.yml/badge.svg :target: https://github.com/zopefoundation/zope.proxy/actions/workflows/tests.yml .. image:: https://ci.appveyor.com/api/projects/status/github/zopefoundation/zope.proxy?branch=master&svg=true :target: https://ci.appveyor.com/project/mgedmin/zope-proxy .. image:: https://coveralls.io/repos/github/zopefoundation/zope.proxy/badge.svg?branch=master :target: https://coveralls.io/github/zopefoundation/zope.proxy?branch=master .. image:: https://readthedocs.org/projects/zopeproxy/badge/?version=latest :target: https://zopeproxy.readthedocs.io/en/latest/ :alt: Documentation Status .. image:: https://img.shields.io/pypi/v/zope.proxy.svg :target: https://pypi.org/project/zope.proxy/ :alt: Latest release .. image:: https://img.shields.io/pypi/pyversions/zope.proxy.svg :target: https://pypi.org/project/zope.proxy/ :alt: Python versions Proxies are special objects which serve as mostly-transparent wrappers around another object, intervening in the apparent behavior of the wrapped object only when necessary to apply the policy (e.g., access checking, location brokering, etc.) for which the proxy is responsible. zope.proxy is implemented via a C extension module, which lets it do things like lie about its own ``__class__`` that are difficult in pure Python (and were completely impossible before metaclasses). It also proxies all the internal slots (such as ``__int__``/``__str__``/``__add__``). Complete documentation is at https://zopeproxy.readthedocs.io ========= Changes ========= 5.1 (2023-10-05) ================ - Add support for Python 3.12. 5.0.0 (2023-01-18) ================== - Drop support for Python 2.7, 3.5, 3.6. - Remove proxying code for names that no longer exist in Python 3 like ``__long__`` and some others. (`#55 `_) 4.6.1 (2022-11-16) ================== - Add support for building arm64 wheels on macOS. 4.6.0 (2022-11-03) ================== - Add support for Python 3.11. 4.5.1 (2022-09-15) ================== - Disable unsafe math optimizations in C code. See `pull request 53 `_. 4.5.0 (2021-11-17) ================== - Add support for Python 3.10. 4.4.0 (2021-07-22) ================== - Add support for Python 3.9. - Create aarch64 wheels. 4.3.5 (2020-03-16) ================== - Stop installing C header files on PyPy (which is what zope.proxy before 4.3.4 used to do), fixes `issue 39 `_. 4.3.4 (2020-03-13) ================== - Fix a compilation warning on Python 3.8. The slot ``tp_print`` changed to ``tp_vectorcall_offset`` in 3.8 and must not be set. Prior to 3.8, it was reserved and ignored in all Python 3 versions. See `issue 36 `_. - Remove deprecated use of setuptools features. See `issue 38 `_. 4.3.3 (2019-11-11) ================== - Add support for Python 3.8. - Drop support for Python 3.4. 4.3.2 (2019-07-12) ================== - Fix error handling in ``ProxyBase.__setattr__``: any the exception raised by ``PyString_AsString``/``PyUnicode_AsUTF8`` would be silently swallowed up and ignored. See `issue 31 `_. 4.3.1 (2018-08-09) ================== - Simplify the internal C handling of attribute names in ``__getattribute__`` and ``__setattr__``. - Make building the C extension optional. We still attempt to build it on supported platforms, but we allow it to fail in case of a missing compiler or headers. See `issue 26 `_. - Test the PURE_PYTHON environment and PyPy3 on Travis CI. - Add support for Python 3.7. 4.3.0 (2017-09-13) ================== - Fix a potential rare crash when deallocating proxies. See `issue 20 `_. - Drop support for Python 3.3. - Drop support for "python setup.py test". - 100% test coverage. - Fix indexing pure-Python proxies with slices under Python 3, and restore the use of ``__getslice__`` (if implemented by the target's type) under Python 2. Previously, pure-Python proxies would fail with an AttributeError when given a slice on Python 3, and on Python 2, a custom ``__getslice__`` was ignored. See `issue 21 `_. 4.2.1 (2017-04-23) ================== - Make the pure-Python implementation of ``sameProxiedObjects`` handle ``zope.security`` proxies. See `issue 15 `_. - Add support for Python 3.6. 4.2.0 (2016-05-05) ================== - Correctly strip ``zope.security`` proxies in ``removeAllProxies``. See `issue 13 `_. - Avoid poisoning the user's global wheel cache when testing ``PURE_PYTHON`` environments under ``tox``, - Drop support for Python 2.6 and 3.2. - Add support for Python 3.5. 4.1.6 (2015-06-02) ================== - Make subclasses of ProxyBase properly delegate ``__module__`` to the wrapped object. This fixes some ``zope.interface`` lookups under PyPy. - Make the pure-Python implementation of ProxyBase properly report the ``zope.interface`` interfaces implemented by builtin types like ``list``. This fixes some ``zope.interface`` lookups under PyPy. 4.1.5 (2015-05-19) ================== - Make the C implementation proxy ``__unicode__`` correctly. - Make the C implementation use the standard methods to proxy ``int`` and ``float``. - Make the pure Python implementation handle descriptors defined in subclasses like the C version. See https://github.com/zopefoundation/zope.proxy/issues/5. 4.1.4 (2014-03-19) ================== - Add support for Python 3.4. - Update ``bootstrap.py`` to version 2.2. 4.1.3 (2013-03-12) ================== - Fix interface object introspection in PyPy. For some reason PyPy makes attributes available despite the restrictive ``__slots__`` declaration. - Add a bunch of tests surrounding interface lookup and adaptation. 4.1.2 (2013-03-11) ================== - Make ``PyProxyBase.__iter__()`` return the result of ``PyProxyBase._wrapped.__iter__`` if available, otherwise falling back to Python internals. The previous implementation always created a generator. - In ``PyProxyBase.__setattr__()``, allow setting of properties on the proxy itself. This is needed to properly allow proxy extensions as was evidenced int he ``zope.security.decorator`` module. 4.1.1 (2012-12-31) ================== - Fleshed out PyPI Trove classifiers. 4.1.0 (2012-12-19) ================== - Enable compilation of dependent modules under Py3k. - Replace use of ``PyCObject`` APIs with equivalent ``PyCapsule`` APIs, except under Python 2.6. N.B. This change is an ABI incompatibility under Python 2.7: extensions built under Python 2.7 against 4.0.x versions of ``zope.proxy`` must be rebuilt. 4.0.1 (2012-11-21) ================== - Add support for Python 3.3. 4.0.0 (2012-06-06) ================== - Add support for PyPy. N.B.: the C extension is *not* built under PyPy. - Add a pure-Python reference / fallback implementations of ``zope.proxy.ProxyBase`` and the proxy module API functions. N.B.: the pure-Python proxy implements all regular features of ``ProxyBase``; however, it does not exclude access to the wrapped object in the same way that the C version does. If you need that information hiding (e.g., to implement security sandboxing), you still need to use the C version. - Add support for continuous integration using ``tox`` and ``jenkins``. - 100% unit test coverage. - Add Sphinx documentation: moved doctest examples to API reference. - Add 'setup.py docs' alias (installs ``Sphinx`` and dependencies). - Add 'setup.py dev' alias (runs ``setup.py develop`` plus installs ``nose`` and ``coverage``). - Replace deprecated ``zope.interface.implements`` usage with equivalent ``zope.interface.implementer`` decorator. - Drop support for Python 2.4 and 2.5. - Add Python 3.2 support. 3.6.1 (2010-07-06) ================== - Make tests compatible with Python 2.7. 3.6.0 (2010-04-30) ================== - Remove test extra and the remaining dependency on zope.testing. - Remove use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest. 3.5.0 (2009/01/31) ================== - Add support to bootstrap on Jython. - Use ``zope.container`` instead of ``zope.app.container``. 3.4.2 (2008/07/27) ================== - Make C code compatible with Python 2.5 on 64bit architectures. 3.4.1 (2008/06/24) ================== - Bug: Update ``setup.py`` script to conform to common layout. Also updated some of the fields. - Bug: Honor pre-cooked indices for tuples and lists in the ``__getslice__()`` and ``__setslice__()`` methods. See http://docs.python.org/ref/sequence-methods.html. 3.4.0 (2007/07/12) ================== - Feature: Add a ``decorator`` module that supports declaring interfaces on proxies that get blended with the interfaces of the things they proxy. 3.3.0 (2006/12/20) ================== - Corresponds to the verison of the ``zope.proxy`` package shipped as part of the Zope 3.3.0 release. 3.2.0 (2006/01/05) ================== - Corresponds to the verison of the ``zope.proxy`` package shipped as part of the Zope 3.2.0 release. 3.0.0 (2004/11/07) ================== - Corresponds to the verison of the ``zope.proxy`` package shipped as part of the Zope X3.0.0 release. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1668592736.0 zope.proxy-5.1/README.rst0000644000076500000240000000323214335132140014061 0ustar00jensstaff================ ``zope.proxy`` ================ .. image:: https://github.com/zopefoundation/zope.proxy/actions/workflows/tests.yml/badge.svg :target: https://github.com/zopefoundation/zope.proxy/actions/workflows/tests.yml .. image:: https://ci.appveyor.com/api/projects/status/github/zopefoundation/zope.proxy?branch=master&svg=true :target: https://ci.appveyor.com/project/mgedmin/zope-proxy .. image:: https://coveralls.io/repos/github/zopefoundation/zope.proxy/badge.svg?branch=master :target: https://coveralls.io/github/zopefoundation/zope.proxy?branch=master .. image:: https://readthedocs.org/projects/zopeproxy/badge/?version=latest :target: https://zopeproxy.readthedocs.io/en/latest/ :alt: Documentation Status .. image:: https://img.shields.io/pypi/v/zope.proxy.svg :target: https://pypi.org/project/zope.proxy/ :alt: Latest release .. image:: https://img.shields.io/pypi/pyversions/zope.proxy.svg :target: https://pypi.org/project/zope.proxy/ :alt: Python versions Proxies are special objects which serve as mostly-transparent wrappers around another object, intervening in the apparent behavior of the wrapped object only when necessary to apply the policy (e.g., access checking, location brokering, etc.) for which the proxy is responsible. zope.proxy is implemented via a C extension module, which lets it do things like lie about its own ``__class__`` that are difficult in pure Python (and were completely impossible before metaclasses). It also proxies all the internal slots (such as ``__int__``/``__str__``/``__add__``). Complete documentation is at https://zopeproxy.readthedocs.io ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696516779.0 zope.proxy-5.1/appveyor.yml0000644000076500000240000000341414507545253015002 0ustar00jensstaff# Generated from: # https://github.com/zopefoundation/meta/tree/master/config/c-code environment: # Currently the builds use @mgedmin's Appveyor account. The PyPI token belongs # to zope.wheelbuilder, which is managed by @mgedmin and @dataflake. global: TWINE_USERNAME: __token__ TWINE_PASSWORD: secure: aoZC/+rvJKg8B5GMGIxd1bg9UDShk28EhfPQFKI9zy7kzygdgj0XuaK619sLe3s4B08bIJaIUAThxEvWq13IvdLb5Oyk8B9qubd+NnDiNuw8WCGy4owYnbl+61fUVVKJIf1ETQyGDooYrEuBo798/+ycQbilTpmncAHZb2KyZkmA210fcWr7OhwmlRtC4IiW7GPCaxU6qhzLlP5pnS2Tl+yy/qx2DiW2fKWqUqynrb1ZMsk6ygN4qV72glTY6wV0eYboAGlghrws1x5+Z10Yug== matrix: - python: 37-x64 - python: 38-x64 - python: 39-x64 - python: 310-x64 - python: 311-x64 - python: 312-x64 install: - "SET PYTHONVERSION=%PYTHON%" - "SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH%" - ps: | $env:PYTHON = "C:\\Python${env:PYTHON}" if (-not (Test-Path $env:PYTHON)) { curl -o install_python.ps1 https://raw.githubusercontent.com/matthew-brett/multibuild/11a389d78892cf90addac8f69433d5e22bfa422a/install_python.ps1 .\install_python.ps1 } - ps: if (-not (Test-Path $env:PYTHON)) { throw "No $env:PYTHON" } - echo "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" /x64 > "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\amd64\vcvars64.bat" - python -m pip install -U pip - pip install -U setuptools wheel - pip install -U -e .[test] matrix: fast_finish: true build_script: - python -W ignore setup.py -q bdist_wheel test_script: - zope-testrunner --test-path=src artifacts: - path: 'dist\*.whl' name: wheel deploy_script: - ps: if ($env:APPVEYOR_REPO_TAG -eq $TRUE) { pip install twine; twine upload --skip-existing dist\*.whl } deploy: on ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667730716.0 zope.proxy-5.1/buildout.cfg0000644000076500000240000000032114331706434014707 0ustar00jensstaff[buildout] parts = test test-wo-zope-security develop = . [test] recipe = zc.recipe.testrunner eggs = zope.proxy[test] [test-wo-zope-security] recipe = zc.recipe.testrunner eggs = zope.proxy ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1696517994.538836 zope.proxy-5.1/docs/0000755000076500000240000000000014507547553013345 5ustar00jensstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/Makefile0000644000076500000240000001271014330441244014766 0ustar00jensstaff# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/zopeproxy.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/zopeproxy.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/zopeproxy" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/zopeproxy" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1696517994.534812 zope.proxy-5.1/docs/_build/0000755000076500000240000000000014507547553014603 5ustar00jensstaff././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1696517994.5389705 zope.proxy-5.1/docs/_build/doctest/0000755000076500000240000000000014507547553016250 5ustar00jensstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696502424.0 zope.proxy-5.1/docs/_build/doctest/output.txt0000644000076500000240000000077514507511230020341 0ustar00jensstaffResults of doctest builder run on 2023-10-05 12:40:24 ===================================================== Document: narr -------------- 1 items passed all tests: 37 tests in default 37 tests in 1 items. 37 passed and 0 failed. Test passed. Document: api ------------- 1 items passed all tests: 23 tests in default 23 tests in 1 items. 23 passed and 0 failed. Test passed. Doctest summary =============== 60 tests 0 failures in tests 0 failures in setup code 0 failures in cleanup code ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1696517994.534859 zope.proxy-5.1/docs/_build/html/0000755000076500000240000000000014507547553015547 5ustar00jensstaff././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1696517994.5399592 zope.proxy-5.1/docs/_build/html/_sources/0000755000076500000240000000000014507547553017371 5ustar00jensstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/_build/html/_sources/api.rst.txt0000644000076500000240000000447714330441244021506 0ustar00jensstaff:mod:`zope.proxy` API ===================== :mod:`zope.proxy.interfaces` ---------------------------- .. automodule:: zope.proxy.interfaces .. autointerface:: IProxyIntrospection :members: :member-order: bysource :mod:`zope.proxy` ----------------- .. automodule:: zope.proxy :members: :mod:`zope.proxy.decorator` --------------------------- .. automodule:: zope.proxy.decorator .. doctest:: >>> from zope.interface import Interface >>> from zope.interface import directlyProvides >>> from zope.interface import implementer >>> class I1(Interface): ... pass >>> class I2(Interface): ... pass >>> class I3(Interface): ... pass >>> class I4(Interface): ... pass >>> from zope.proxy.decorator import SpecificationDecoratorBase >>> @implementer(I1) ... class D1(SpecificationDecoratorBase): ... pass >>> @implementer(I2) ... class D2(SpecificationDecoratorBase): ... pass >>> @implementer(I3) ... class X(object): ... pass >>> x = X() >>> directlyProvides(x, I4) Interfaces of X are ordered with the directly-provided interfaces first. .. doctest:: >>> from zope.interface import providedBy >>> [interface.getName() for interface in list(providedBy(x))] ['I4', 'I3'] When we decorate objects, what order should the interfaces come in? One could argue that decorators are less specific, so they should come last. .. doctest:: >>> [interface.getName() for interface in list(providedBy(D1(x)))] ['I4', 'I3', 'I1'] >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))] ['I4', 'I3', 'I1', 'I2'] SpecificationDecorators also work with old-style classes: .. doctest:: >>> @implementer(I3) ... class X: ... pass >>> x = X() >>> directlyProvides(x, I4) >>> [interface.getName() for interface in list(providedBy(x))] ['I4', 'I3'] >>> [interface.getName() for interface in list(providedBy(D1(x)))] ['I4', 'I3', 'I1'] >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))] ['I4', 'I3', 'I1', 'I2'] .. autoclass:: DecoratorSpecificationDescriptor :members: .. autoclass:: SpecificationDecoratorBase ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/_build/html/_sources/changes.rst.txt0000644000076500000240000000003414330441244022326 0ustar00jensstaff.. include:: ../CHANGES.rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/_build/html/_sources/hacking.rst.txt0000644000076500000240000002112114330441244022322 0ustar00jensstaffHacking on :mod:`zope.proxy` ============================ Getting the Code ################ The main repository for :mod:`zope.proxy` is in the Zope Foundation Github repository: https://github.com/zopefoundation/zope.proxy You can get a read-only checkout from there: .. code-block:: sh $ git clone https://github.com/zopefoundation/zope.proxy.git or fork it and get a writeable checkout of your fork: .. code-block:: sh $ git clone git@github.com/jrandom/zope.proxy.git The project also mirrors the trunk from the Github repository as a Bazaar branch on Launchpad: https://code.launchpad.net/zope.proxy You can branch the trunk from there using Bazaar: .. code-block:: sh $ bzr branch lp:zope.proxy Working in a ``virtualenv`` ########################### Installing ---------- If you use the ``virtualenv`` package to create lightweight Python development environments, you can run the tests using nothing more than the ``python`` binary in a virtualenv. First, create a scratch environment: .. code-block:: sh $ /path/to/virtualenv --no-site-packages /tmp/hack-zope.proxy Next, get this package registered as a "development egg" in the environment: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/python setup.py develop Running the tests ----------------- Then, you canrun the tests using the build-in ``setuptools`` testrunner: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/python setup.py test -q ................................................................................................................................................... ---------------------------------------------------------------------- Ran 147 tests in 0.010s OK If you have the :mod:`nose` package installed in the virtualenv, you can use its testrunner too: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/easy_install nose ... $ /tmp/hack-zope.proxy/bin/nosetests ..................................................................................................................................................... ---------------------------------------------------------------------- Ran 149 tests in 0.107s OK If you have the :mod:`coverage` pacakge installed in the virtualenv, you can see how well the tests cover the code: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/easy_install nose coverage ... $ /tmp/hack-zope.proxy/bin/nosetests --with coverage ..................................................................................................................................................... Name Stmts Miss Cover Missing ----------------------------------------------------- zope.proxy 271 0 100% zope.proxy._compat 2 0 100% zope.proxy.decorator 18 0 100% zope.proxy.interfaces 10 0 100% ----------------------------------------------------- TOTAL 301 0 100% ---------------------------------------------------------------------- Ran 149 tests in 0.148s OK Building the documentation -------------------------- :mod:`zope.proxy` uses the nifty :mod:`Sphinx` documentation system for building its docs. Using the same virtualenv you set up to run the tests, you can build the docs: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/easy_install Sphinx ... $ cd docs $ /tmp/hack-zope.proxy/bin/sphinx-build \ -b html -d _build/doctrees . _build/html ... build succeeded. You can also test the code snippets in the documentation: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/sphinx-build \ -b doctest -d _build/doctrees . _build/doctest ... running tests... Document: api ------------- 1 items passed all tests: 23 tests in default 23 tests in 1 items. 23 passed and 0 failed. Test passed. Document: narr -------------- 1 items passed all tests: 37 tests in default 37 tests in 1 items. 37 passed and 0 failed. Test passed. Doctest summary =============== 60 tests 0 failures in tests 0 failures in setup code 0 failures in cleanup code build succeeded. Using :mod:`zc.buildout` ######################## Setting up the buildout ----------------------- :mod:`zope.proxy` ships with its own :file:`buildout.cfg` file and :file:`bootstrap.py` for setting up a development buildout: .. code-block:: sh $ /path/to/python2.6 bootstrap.py ... Generated script '.../bin/buildout' $ bin/buildout Develop: '/home/jrandom/projects/Zope/BTK/event/.' ... Generated script '.../bin/test'. Running the tests ----------------- You can now run the tests: .. code-block:: sh $ bin/test --all Running zope.testing.testrunner.layer.UnitTests tests: Set up zope.testing.testrunner.layer.UnitTests in 0.000 seconds. Ran 147 tests with 0 failures and 0 errors in 0.000 seconds. Tearing down left over layers: Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds. Using :mod:`tox` ################ Running Tests on Multiple Python Versions ----------------------------------------- `tox `_ is a Python-based test automation tool designed to run tests against multiple Python versions. It creates a ``virtualenv`` for each configured version, installs the current package and configured dependencies into each ``virtualenv``, and then runs the configured commands. :mod:`zope.proxy` configures the following :mod:`tox` environments via its ``tox.ini`` file: - The ``py26``, ``py27``, ``py33``, ``py34``, and ``pypy`` environments builds a ``virtualenv`` with ``pypy``, installs :mod:`zope.proxy` and dependencies, and runs the tests via ``python setup.py test -q``. - The ``coverage`` environment builds a ``virtualenv`` with ``python2.6``, installs :mod:`zope.proxy`, installs :mod:`nose` and :mod:`coverage`, and runs ``nosetests`` with statement coverage. - The ``docs`` environment builds a virtualenv with ``python2.6``, installs :mod:`zope.proxy`, installs ``Sphinx`` and dependencies, and then builds the docs and exercises the doctest snippets. This example requires that you have a working ``python2.6`` on your path, as well as installing ``tox``: .. code-block:: sh $ tox -e py26 GLOB sdist-make: .../zope.proxy/setup.py py26 sdist-reinst: .../zope.proxy/.tox/dist/zope.proxy-4.0.2dev.zip py26 runtests: commands[0] ... ---------------------------------------------------------------------- Ran 147 tests in 0.000s OK ___________________________________ summary ____________________________________ py26: commands succeeded congratulations :) Running ``tox`` with no arguments runs all the configured environments, including building the docs and testing their snippets: .. code-block:: sh $ tox GLOB sdist-make: .../zope.proxy/setup.py py26 sdist-reinst: .../zope.proxy/.tox/dist/zope.proxy-4.0.2dev.zip py26 runtests: commands[0] ... Doctest summary =============== 60 tests 0 failures in tests 0 failures in setup code 0 failures in cleanup code build succeeded. ___________________________________ summary ____________________________________ py26: commands succeeded py27: commands succeeded py32: commands succeeded pypy: commands succeeded coverage: commands succeeded docs: commands succeeded congratulations :) Contributing to :mod:`zope.proxy` ################################# Submitting a Bug Report ----------------------- :mod:`zope.proxy` tracks its bugs on Github: https://github.com/zopefoundation/zope.proxy/issues Please submit bug reports and feature requests there. Sharing Your Changes -------------------- .. note:: Please ensure that all tests are passing before you submit your code. If possible, your submission should include new tests for new features or bug fixes, although it is possible that you may have tested your new code by updating existing tests. If have made a change you would like to share, the best route is to fork the Githb repository, check out your fork, make your changes on a branch in your fork, and push it. You can then submit a pull request from your branch: https://github.com/zopefoundation/zope.proxy/pulls If you branched the code from Launchpad using Bazaar, you have another option: you can "push" your branch to Launchpad: .. code-block:: sh $ bzr push lp:~jrandom/zope.proxy/cool_feature After pushing your branch, you can link it to a bug report on Github, or request that the maintainers merge your branch using the Launchpad "merge request" feature. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/_build/html/_sources/index.rst.txt0000644000076500000240000000032014330441244022023 0ustar00jensstaff:mod:`zope.proxy` ================= Contents: .. toctree:: :maxdepth: 2 narr api hacking changes Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/_build/html/_sources/narr.rst.txt0000644000076500000240000000615314330441244021670 0ustar00jensstaff:mod:`zope.proxy` Narrative Documentation ========================================= Subclassing :class:`ProxyBase` ------------------------------ If you subclass a proxy, instances of the subclass have access to data defined in the class, including descriptors. Your subclass instances don't get instance dictionaries, but they can have slots. .. doctest:: >>> from zope.proxy import ProxyBase >>> class MyProxy(ProxyBase): ... __slots__ = 'x', 'y' ... ... def f(self): ... return self.x >>> l = [1, 2, 3] >>> p = MyProxy(l) You can use attributes defined by the class, including slots: .. doctest:: >>> p.x = 'x' >>> p.x 'x' >>> p.f() 'x' You can also use attributes of the proxied object: .. doctest:: >>> p [1, 2, 3] >>> p.pop() 3 >>> p [1, 2] Using get descriptors in proxy classes -------------------------------------- A non-data descriptor in a proxy class doesn't hide an attribute on a proxied object or prevent writing the attribute. .. doctest:: >>> class ReadDescr(object): ... def __get__(self, i, c): ... return 'read' >>> from zope.proxy import ProxyBase >>> class MyProxy(ProxyBase): ... __slots__ = () ... ... z = ReadDescr() ... q = ReadDescr() >>> class MyOb: ... q = 1 >>> o = MyOb() >>> p = MyProxy(o) >>> p.q 1 >>> p.z 'read' >>> p.z = 1 >>> o.z, p.z (1, 1) Marking proxy attributes as non-overridable ------------------------------------------- Normally, methods defined in proxies are overridden by methods of proxied objects. This applies to all non-data descriptors. The non_overridable function can be used to convert a non-data descriptor to a data descriptor that disallows writes. This function can be used as a decorator to make functions defined in proxy classes take precedence over functions defined in proxied objects. .. doctest:: >>> from zope.proxy import ProxyBase >>> from zope.proxy import non_overridable >>> class MyProxy(ProxyBase): ... __slots__ = () ... ... @non_overridable ... def foo(self): ... return 'MyProxy foo' >>> class MyOb: ... def foo(self): ... return 'MyOb foo' >>> o = MyOb() >>> p = MyProxy(o) >>> p.foo() 'MyProxy foo' Changing the proxied object --------------------------- .. doctest:: >>> from zope.proxy import ProxyBase >>> from zope.proxy import setProxiedObject, getProxiedObject >>> class C(object): ... pass >>> c1 = C() >>> c2 = C() >>> p = ProxyBase(c1) `setProxiedObject()` allows us to change the object a proxy refers to, returning the previous referent: .. doctest:: >>> old = setProxiedObject(p, c2) >>> old is c1 True >>> getProxiedObject(p) is c2 True The first argument to `setProxiedObject()` must be a proxy; other objects cause it to raise an exception: .. doctest:: >>> try: ... setProxiedObject(c1, None) ... except TypeError: ... print("TypeError raised") ... else: ... print("Expected TypeError not raised") TypeError raised ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/api.rst0000644000076500000240000000447714330441244014644 0ustar00jensstaff:mod:`zope.proxy` API ===================== :mod:`zope.proxy.interfaces` ---------------------------- .. automodule:: zope.proxy.interfaces .. autointerface:: IProxyIntrospection :members: :member-order: bysource :mod:`zope.proxy` ----------------- .. automodule:: zope.proxy :members: :mod:`zope.proxy.decorator` --------------------------- .. automodule:: zope.proxy.decorator .. doctest:: >>> from zope.interface import Interface >>> from zope.interface import directlyProvides >>> from zope.interface import implementer >>> class I1(Interface): ... pass >>> class I2(Interface): ... pass >>> class I3(Interface): ... pass >>> class I4(Interface): ... pass >>> from zope.proxy.decorator import SpecificationDecoratorBase >>> @implementer(I1) ... class D1(SpecificationDecoratorBase): ... pass >>> @implementer(I2) ... class D2(SpecificationDecoratorBase): ... pass >>> @implementer(I3) ... class X(object): ... pass >>> x = X() >>> directlyProvides(x, I4) Interfaces of X are ordered with the directly-provided interfaces first. .. doctest:: >>> from zope.interface import providedBy >>> [interface.getName() for interface in list(providedBy(x))] ['I4', 'I3'] When we decorate objects, what order should the interfaces come in? One could argue that decorators are less specific, so they should come last. .. doctest:: >>> [interface.getName() for interface in list(providedBy(D1(x)))] ['I4', 'I3', 'I1'] >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))] ['I4', 'I3', 'I1', 'I2'] SpecificationDecorators also work with old-style classes: .. doctest:: >>> @implementer(I3) ... class X: ... pass >>> x = X() >>> directlyProvides(x, I4) >>> [interface.getName() for interface in list(providedBy(x))] ['I4', 'I3'] >>> [interface.getName() for interface in list(providedBy(D1(x)))] ['I4', 'I3', 'I1'] >>> [interface.getName() for interface in list(providedBy(D2(D1(x))))] ['I4', 'I3', 'I1', 'I2'] .. autoclass:: DecoratorSpecificationDescriptor :members: .. autoclass:: SpecificationDecoratorBase ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/changes.rst0000644000076500000240000000003414330441244015464 0ustar00jensstaff.. include:: ../CHANGES.rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696516779.0 zope.proxy-5.1/docs/conf.py0000644000076500000240000001746114507545253014650 0ustar00jensstaff# -*- coding: utf-8 -*- # # zope.proxy documentation build configuration file, created by # sphinx-quickstart on Mon Jun 4 15:12:17 2012. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', 'repoze.sphinx.autointerface', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'zope.proxy' copyright = u'2012, Zope Foundation Contributors' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '4.0' # The full version, including alpha/beta/rc tags. release = '4.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'sphinx_rtd_theme' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'zopeproxydoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'zopeproxy.tex', u'zope.proxy Documentation', u'Zope Foundation Contributors', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'zopeproxy', u'zope.proxy Documentation', [u'Zope Foundation Contributors'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'zopeproxy', u'zope.proxy Documentation', u'Zope Foundation Contributors', 'zopeproxy', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/hacking.rst0000644000076500000240000002112114330441244015460 0ustar00jensstaffHacking on :mod:`zope.proxy` ============================ Getting the Code ################ The main repository for :mod:`zope.proxy` is in the Zope Foundation Github repository: https://github.com/zopefoundation/zope.proxy You can get a read-only checkout from there: .. code-block:: sh $ git clone https://github.com/zopefoundation/zope.proxy.git or fork it and get a writeable checkout of your fork: .. code-block:: sh $ git clone git@github.com/jrandom/zope.proxy.git The project also mirrors the trunk from the Github repository as a Bazaar branch on Launchpad: https://code.launchpad.net/zope.proxy You can branch the trunk from there using Bazaar: .. code-block:: sh $ bzr branch lp:zope.proxy Working in a ``virtualenv`` ########################### Installing ---------- If you use the ``virtualenv`` package to create lightweight Python development environments, you can run the tests using nothing more than the ``python`` binary in a virtualenv. First, create a scratch environment: .. code-block:: sh $ /path/to/virtualenv --no-site-packages /tmp/hack-zope.proxy Next, get this package registered as a "development egg" in the environment: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/python setup.py develop Running the tests ----------------- Then, you canrun the tests using the build-in ``setuptools`` testrunner: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/python setup.py test -q ................................................................................................................................................... ---------------------------------------------------------------------- Ran 147 tests in 0.010s OK If you have the :mod:`nose` package installed in the virtualenv, you can use its testrunner too: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/easy_install nose ... $ /tmp/hack-zope.proxy/bin/nosetests ..................................................................................................................................................... ---------------------------------------------------------------------- Ran 149 tests in 0.107s OK If you have the :mod:`coverage` pacakge installed in the virtualenv, you can see how well the tests cover the code: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/easy_install nose coverage ... $ /tmp/hack-zope.proxy/bin/nosetests --with coverage ..................................................................................................................................................... Name Stmts Miss Cover Missing ----------------------------------------------------- zope.proxy 271 0 100% zope.proxy._compat 2 0 100% zope.proxy.decorator 18 0 100% zope.proxy.interfaces 10 0 100% ----------------------------------------------------- TOTAL 301 0 100% ---------------------------------------------------------------------- Ran 149 tests in 0.148s OK Building the documentation -------------------------- :mod:`zope.proxy` uses the nifty :mod:`Sphinx` documentation system for building its docs. Using the same virtualenv you set up to run the tests, you can build the docs: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/easy_install Sphinx ... $ cd docs $ /tmp/hack-zope.proxy/bin/sphinx-build \ -b html -d _build/doctrees . _build/html ... build succeeded. You can also test the code snippets in the documentation: .. code-block:: sh $ /tmp/hack-zope.proxy/bin/sphinx-build \ -b doctest -d _build/doctrees . _build/doctest ... running tests... Document: api ------------- 1 items passed all tests: 23 tests in default 23 tests in 1 items. 23 passed and 0 failed. Test passed. Document: narr -------------- 1 items passed all tests: 37 tests in default 37 tests in 1 items. 37 passed and 0 failed. Test passed. Doctest summary =============== 60 tests 0 failures in tests 0 failures in setup code 0 failures in cleanup code build succeeded. Using :mod:`zc.buildout` ######################## Setting up the buildout ----------------------- :mod:`zope.proxy` ships with its own :file:`buildout.cfg` file and :file:`bootstrap.py` for setting up a development buildout: .. code-block:: sh $ /path/to/python2.6 bootstrap.py ... Generated script '.../bin/buildout' $ bin/buildout Develop: '/home/jrandom/projects/Zope/BTK/event/.' ... Generated script '.../bin/test'. Running the tests ----------------- You can now run the tests: .. code-block:: sh $ bin/test --all Running zope.testing.testrunner.layer.UnitTests tests: Set up zope.testing.testrunner.layer.UnitTests in 0.000 seconds. Ran 147 tests with 0 failures and 0 errors in 0.000 seconds. Tearing down left over layers: Tear down zope.testing.testrunner.layer.UnitTests in 0.000 seconds. Using :mod:`tox` ################ Running Tests on Multiple Python Versions ----------------------------------------- `tox `_ is a Python-based test automation tool designed to run tests against multiple Python versions. It creates a ``virtualenv`` for each configured version, installs the current package and configured dependencies into each ``virtualenv``, and then runs the configured commands. :mod:`zope.proxy` configures the following :mod:`tox` environments via its ``tox.ini`` file: - The ``py26``, ``py27``, ``py33``, ``py34``, and ``pypy`` environments builds a ``virtualenv`` with ``pypy``, installs :mod:`zope.proxy` and dependencies, and runs the tests via ``python setup.py test -q``. - The ``coverage`` environment builds a ``virtualenv`` with ``python2.6``, installs :mod:`zope.proxy`, installs :mod:`nose` and :mod:`coverage`, and runs ``nosetests`` with statement coverage. - The ``docs`` environment builds a virtualenv with ``python2.6``, installs :mod:`zope.proxy`, installs ``Sphinx`` and dependencies, and then builds the docs and exercises the doctest snippets. This example requires that you have a working ``python2.6`` on your path, as well as installing ``tox``: .. code-block:: sh $ tox -e py26 GLOB sdist-make: .../zope.proxy/setup.py py26 sdist-reinst: .../zope.proxy/.tox/dist/zope.proxy-4.0.2dev.zip py26 runtests: commands[0] ... ---------------------------------------------------------------------- Ran 147 tests in 0.000s OK ___________________________________ summary ____________________________________ py26: commands succeeded congratulations :) Running ``tox`` with no arguments runs all the configured environments, including building the docs and testing their snippets: .. code-block:: sh $ tox GLOB sdist-make: .../zope.proxy/setup.py py26 sdist-reinst: .../zope.proxy/.tox/dist/zope.proxy-4.0.2dev.zip py26 runtests: commands[0] ... Doctest summary =============== 60 tests 0 failures in tests 0 failures in setup code 0 failures in cleanup code build succeeded. ___________________________________ summary ____________________________________ py26: commands succeeded py27: commands succeeded py32: commands succeeded pypy: commands succeeded coverage: commands succeeded docs: commands succeeded congratulations :) Contributing to :mod:`zope.proxy` ################################# Submitting a Bug Report ----------------------- :mod:`zope.proxy` tracks its bugs on Github: https://github.com/zopefoundation/zope.proxy/issues Please submit bug reports and feature requests there. Sharing Your Changes -------------------- .. note:: Please ensure that all tests are passing before you submit your code. If possible, your submission should include new tests for new features or bug fixes, although it is possible that you may have tested your new code by updating existing tests. If have made a change you would like to share, the best route is to fork the Githb repository, check out your fork, make your changes on a branch in your fork, and push it. You can then submit a pull request from your branch: https://github.com/zopefoundation/zope.proxy/pulls If you branched the code from Launchpad using Bazaar, you have another option: you can "push" your branch to Launchpad: .. code-block:: sh $ bzr push lp:~jrandom/zope.proxy/cool_feature After pushing your branch, you can link it to a bug report on Github, or request that the maintainers merge your branch using the Launchpad "merge request" feature. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/index.rst0000644000076500000240000000032014330441244015161 0ustar00jensstaff:mod:`zope.proxy` ================= Contents: .. toctree:: :maxdepth: 2 narr api hacking changes Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/make.bat0000644000076500000240000001175614330441244014744 0ustar00jensstaff@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\zopeproxy.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\zopeproxy.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/docs/narr.rst0000644000076500000240000000615314330441244015026 0ustar00jensstaff:mod:`zope.proxy` Narrative Documentation ========================================= Subclassing :class:`ProxyBase` ------------------------------ If you subclass a proxy, instances of the subclass have access to data defined in the class, including descriptors. Your subclass instances don't get instance dictionaries, but they can have slots. .. doctest:: >>> from zope.proxy import ProxyBase >>> class MyProxy(ProxyBase): ... __slots__ = 'x', 'y' ... ... def f(self): ... return self.x >>> l = [1, 2, 3] >>> p = MyProxy(l) You can use attributes defined by the class, including slots: .. doctest:: >>> p.x = 'x' >>> p.x 'x' >>> p.f() 'x' You can also use attributes of the proxied object: .. doctest:: >>> p [1, 2, 3] >>> p.pop() 3 >>> p [1, 2] Using get descriptors in proxy classes -------------------------------------- A non-data descriptor in a proxy class doesn't hide an attribute on a proxied object or prevent writing the attribute. .. doctest:: >>> class ReadDescr(object): ... def __get__(self, i, c): ... return 'read' >>> from zope.proxy import ProxyBase >>> class MyProxy(ProxyBase): ... __slots__ = () ... ... z = ReadDescr() ... q = ReadDescr() >>> class MyOb: ... q = 1 >>> o = MyOb() >>> p = MyProxy(o) >>> p.q 1 >>> p.z 'read' >>> p.z = 1 >>> o.z, p.z (1, 1) Marking proxy attributes as non-overridable ------------------------------------------- Normally, methods defined in proxies are overridden by methods of proxied objects. This applies to all non-data descriptors. The non_overridable function can be used to convert a non-data descriptor to a data descriptor that disallows writes. This function can be used as a decorator to make functions defined in proxy classes take precedence over functions defined in proxied objects. .. doctest:: >>> from zope.proxy import ProxyBase >>> from zope.proxy import non_overridable >>> class MyProxy(ProxyBase): ... __slots__ = () ... ... @non_overridable ... def foo(self): ... return 'MyProxy foo' >>> class MyOb: ... def foo(self): ... return 'MyOb foo' >>> o = MyOb() >>> p = MyProxy(o) >>> p.foo() 'MyProxy foo' Changing the proxied object --------------------------- .. doctest:: >>> from zope.proxy import ProxyBase >>> from zope.proxy import setProxiedObject, getProxiedObject >>> class C(object): ... pass >>> c1 = C() >>> c2 = C() >>> p = ProxyBase(c1) `setProxiedObject()` allows us to change the object a proxy refers to, returning the previous referent: .. doctest:: >>> old = setProxiedObject(p, c2) >>> old is c1 True >>> getProxiedObject(p) is c2 True The first argument to `setProxiedObject()` must be a proxy; other objects cause it to raise an exception: .. doctest:: >>> try: ... setProxiedObject(c1, None) ... except TypeError: ... print("TypeError raised") ... else: ... print("Expected TypeError not raised") TypeError raised ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696516779.0 zope.proxy-5.1/docs/requirements.txt0000644000076500000240000000010414507545253016617 0ustar00jensstaffSphinx repoze.sphinx.autointerface sphinx_rtd_theme>1 docutils<0.19 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1696517994.5433753 zope.proxy-5.1/setup.cfg0000644000076500000240000000106414507547553014237 0ustar00jensstaff[bdist_wheel] universal = 0 [zest.releaser] create-wheel = no [flake8] doctests = 1 [check-manifest] ignore = .editorconfig .meta.toml docs/_build/html/_sources/* docs/_build/doctest/* docs/_static docs/_build docs/_build/* docs/_build/*/* [isort] force_single_line = True combine_as_imports = True sections = FUTURE,STDLIB,THIRDPARTY,ZOPE,FIRSTPARTY,LOCALFOLDER known_third_party = docutils, pkg_resources, pytz known_zope = known_first_party = default_section = ZOPE line_length = 79 lines_after_imports = 2 [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696516779.0 zope.proxy-5.1/setup.py0000644000076500000240000001130614507545253014123 0ustar00jensstaff############################################################################## # # Copyright (c) 2006-2008 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## # This package is developed by the Zope Toolkit project, documented here: # http://docs.zope.org/zopetoolkit # When developing and releasing this package, please follow the documented # Zope Toolkit policies as described by this documentation. ############################################################################## """Setup for zope.proxy package """ import os import platform from distutils.errors import CCompilerError from distutils.errors import DistutilsExecError from distutils.errors import DistutilsPlatformError from setuptools import Extension from setuptools import setup from setuptools.command.build_ext import build_ext class optional_build_ext(build_ext): """This class subclasses build_ext and allows the building of C extensions to fail. """ def run(self): try: build_ext.run(self) except DistutilsPlatformError as e: self._unavailable(e) def build_extension(self, ext): try: build_ext.build_extension(self, ext) except (CCompilerError, DistutilsExecError, OSError) as e: self._unavailable(e) def _unavailable(self, e): print('*' * 80) print("""WARNING: An optional code optimization (C extension) could not be compiled. Optimizations for this package will not be available!""") print() print(e) print('*' * 80) def read(*rnames): with open(os.path.join(os.path.dirname(__file__), *rnames)) as f: return f.read() codeoptimization = [ Extension( "zope.proxy._zope_proxy_proxy", [os.path.join('src', 'zope', 'proxy', "_zope_proxy_proxy.c")], ), ] # PyPy won't build the extension. is_pypy = platform.python_implementation() == 'PyPy' if is_pypy: ext_modules = [] headers = [] else: ext_modules = codeoptimization headers = [os.path.join('src', 'zope', 'proxy', 'proxy.h')] setup(name='zope.proxy', version='5.1', author='Zope Foundation and Contributors', author_email='zope-dev@zope.org', description='Generic Transparent Proxies', long_description=( read('README.rst') + '\n\n' + read('CHANGES.rst') ), url='http://github.com/zopefoundation/zope.proxy', project_urls={ 'Documentation': 'https://zopeproxy.readthedocs.io', 'Issue Tracker': 'https://github.com/zopefoundation/zope.proxy/issues', 'Sources': 'https://github.com/zopefoundation/zope.proxy', }, license='ZPL 2.1', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Framework :: Zope :: 3', 'Natural Language :: English', 'Operating System :: OS Independent', ], keywords='proxy generic transparent', packages=['zope', 'zope.proxy'], package_dir={'': 'src'}, namespace_packages=['zope'], cmdclass={ 'build_ext': optional_build_ext, }, headers=headers, ext_modules=ext_modules, python_requires='>=3.7', install_requires=[ 'zope.interface', 'setuptools', ], include_package_data=True, zip_safe=False, extras_require={ 'test': [ 'zope.security', # We have a circular dependency for testing 'zope.testrunner', ], 'docs': [ 'Sphinx', 'repoze.sphinx.autointerface', 'sphinx_rtd_theme', ], }, ) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1696517994.5350294 zope.proxy-5.1/src/0000755000076500000240000000000014507547553013204 5ustar00jensstaff././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1696517994.5400817 zope.proxy-5.1/src/zope/0000755000076500000240000000000014507547553014161 5ustar00jensstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/src/zope/__init__.py0000644000076500000240000000007014330441244016247 0ustar00jensstaff__import__('pkg_resources').declare_namespace(__name__) ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1696517994.5418797 zope.proxy-5.1/src/zope/proxy/0000755000076500000240000000000014507547553015342 5ustar00jensstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1674028936.0 zope.proxy-5.1/src/zope/proxy/__init__.py0000644000076500000240000003447214361723610017451 0ustar00jensstaff############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """More convenience functions for dealing with proxies. """ import operator import os import pickle from zope.interface import moduleProvides from zope.proxy.interfaces import IProxyIntrospection moduleProvides(IProxyIntrospection) __all__ = tuple(IProxyIntrospection) def ProxyIterator(p): yield p while isProxy(p): p = getProxiedObject(p) yield p _MARKER = object() def _WrapperType_Lookup(type_, name): """ Looks up information in class dictionaries in MRO order, ignoring the proxy type itself. Returns the first found object, or _MARKER """ for base in type_.mro(): if base is AbstractPyProxyBase: continue res = base.__dict__.get(name, _MARKER) if res is not _MARKER: return res return _MARKER def _get_wrapped(self): """ Helper method to access the wrapped object. """ return super(AbstractPyProxyBase, self).__getattribute__('_wrapped') class _EmptyInterfaceDescriptor: """A descriptor for the attributes used on the class by the Python implementation of `zope.interface`. When wrapping builtin types, these descriptors prevent the objects we find in the AbstractPyProxyBase from being used. """ def __get__(self, inst, klass): raise AttributeError() def __set__(self, inst, value): raise TypeError() def __delete__(self, inst): pass def __iter__(self): return self def __next__(self): raise StopIteration() next = __next__ class _ProxyMetaclass(type): # The metaclass is applied after the class definition # for Py2/Py3 compatibility. __implemented__ = _EmptyInterfaceDescriptor() class AbstractPyProxyBase: """ A reference implementation that cannot be instantiated. Most users will want to use :class:`PyProxyBase`. This type is intended to be used in multiple-inheritance scenarios, where another super class already has defined ``__slots__``. In order to subclass both that class and this class, you must include the ``_wrapped`` value in your own ``__slots__`` definition (or else you will get the infamous TypeError: "multiple bases have instance lay-out conflicts") """ __slots__ = () def __new__(cls, value=None): # Some subclasses (zope.security.proxy) fail to pass the object inst = super(AbstractPyProxyBase, cls).__new__(cls) inst._wrapped = value return inst def __init__(self, obj): self._wrapped = obj def __call__(self, *args, **kw): return self._wrapped(*args, **kw) def __repr__(self): return repr(self._wrapped) def __str__(self): return str(self._wrapped) def __reduce__(self): # pragma: no cover (__reduce_ex__ prevents normal) raise pickle.PicklingError def __reduce_ex__(self, proto): raise pickle.PicklingError # Rich comparison protocol def __lt__(self, other): return self._wrapped < other def __le__(self, other): return self._wrapped <= other def __eq__(self, other): return self._wrapped == other def __ne__(self, other): return self._wrapped != other def __gt__(self, other): return self._wrapped > other def __ge__(self, other): return self._wrapped >= other def __bool__(self): return bool(self._wrapped) def __hash__(self): return hash(self._wrapped) # Attribute protocol def __getattribute__(self, name): # Try to avoid accessing the _wrapped value until we need to. # We don't know how subclasses may be storing it # (e.g., persistent subclasses) if name == '_wrapped': return _get_wrapped(self) if name in ('__class__', '__module__'): # __class__ and __module__ are special cased in the C # implementation, because we will always find them on the # type of this object if we are being subclassed return getattr(_get_wrapped(self), name) if name in ('__reduce__', '__reduce_ex__'): # These things we specifically override and no one # can stop us, not even a subclass return object.__getattribute__(self, name) # First, look for descriptors in this object's type type_self = type(self) descriptor = _WrapperType_Lookup(type_self, name) if descriptor is _MARKER: # Nothing in the class, go straight to the wrapped object return getattr(_get_wrapped(self), name) if hasattr(descriptor, '__get__'): if not hasattr(descriptor, '__set__'): # Non-data-descriptor: call through to the wrapped object # to see if it's there try: return getattr(_get_wrapped(self), name) except AttributeError: pass # Data-descriptor on this type. Call it return descriptor.__get__(self, type_self) return descriptor def __getattr__(self, name): return getattr(self._wrapped, name) def __setattr__(self, name, value): if name == '_wrapped': return super(AbstractPyProxyBase, self).__setattr__(name, value) # First, look for descriptors in this object's type type_self = type(self) descriptor = _WrapperType_Lookup(type_self, name) if descriptor is _MARKER or not hasattr(descriptor, '__set__'): # Nothing in the class that's a descriptor, # go straight to the wrapped object return setattr(self._wrapped, name, value) return object.__setattr__(self, name, value) def __delattr__(self, name): if name == '_wrapped': raise AttributeError() delattr(self._wrapped, name) # Container protocols def __len__(self): return len(self._wrapped) def __getitem__(self, key): return self._wrapped[key] def __setitem__(self, key, value): self._wrapped[key] = value def __delitem__(self, key): del self._wrapped[key] def __iter__(self): # This handles a custom __iter__ and generator support at the same # time. return iter(self._wrapped) def next(self): # Called when we wrap an iterator itself. return next(self._wrapped) def __next__(self): return self._wrapped.__next__() # Python 2.7 won't let the C wrapper support __reversed__ # Uncomment this when the supported Python versions do # def __reversed__(self): # return reversed(self._wrapped) def __contains__(self, item): return item in self._wrapped # Numeric protocol: unary operators def __neg__(self): return -self._wrapped def __pos__(self): return +self._wrapped def __abs__(self): return abs(self._wrapped) def __invert__(self): return ~self._wrapped # Numeric protocol: unary conversions def __complex__(self): return complex(self._wrapped) def __int__(self): return int(self._wrapped) def __float__(self): return float(self._wrapped) def __index__(self): return operator.index(self._wrapped) # Numeric protocol: binary arithmetic operators def __add__(self, other): return self._wrapped + other def __sub__(self, other): return self._wrapped - other def __mul__(self, other): return self._wrapped * other def __floordiv__(self, other): return self._wrapped // other def __truediv__(self, other): return self._wrapped / other def __mod__(self, other): return self._wrapped % other def __divmod__(self, other): return divmod(self._wrapped, other) def __pow__(self, other, modulus=None): if modulus is None: return pow(self._wrapped, other) return pow(self._wrapped, other, modulus) def __radd__(self, other): return other + self._wrapped def __rsub__(self, other): return other - self._wrapped def __rmul__(self, other): return other * self._wrapped def __rfloordiv__(self, other): return other // self._wrapped def __rtruediv__(self, other): return other / self._wrapped def __rmod__(self, other): return other % self._wrapped def __rdivmod__(self, other): return divmod(other, self._wrapped) def __rpow__(self, other, modulus=None): if modulus is None: return pow(other, self._wrapped) # We can't actually get here, because we can't lie about our type() return pow(other, self._wrapped, modulus) # pragma: no cover # Numeric protocol: binary bitwise operators def __lshift__(self, other): return self._wrapped << other def __rshift__(self, other): return self._wrapped >> other def __and__(self, other): return self._wrapped & other def __xor__(self, other): return self._wrapped ^ other def __or__(self, other): return self._wrapped | other def __rlshift__(self, other): return other << self._wrapped def __rrshift__(self, other): return other >> self._wrapped def __rand__(self, other): return other & self._wrapped def __rxor__(self, other): return other ^ self._wrapped def __ror__(self, other): return other | self._wrapped # Numeric protocol: binary in-place operators def __iadd__(self, other): self._wrapped += other return self def __isub__(self, other): self._wrapped -= other return self def __imul__(self, other): self._wrapped *= other return self def __itruediv__(self, other): self._wrapped /= other return self def __ifloordiv__(self, other): self._wrapped //= other return self def __imod__(self, other): self._wrapped %= other return self def __ilshift__(self, other): self._wrapped <<= other return self def __irshift__(self, other): self._wrapped >>= other return self def __iand__(self, other): self._wrapped &= other return self def __ixor__(self, other): self._wrapped ^= other return self def __ior__(self, other): self._wrapped |= other return self def __ipow__(self, other, modulus=None): if modulus is None: self._wrapped **= other else: # pragma: no cover # There is no syntax which triggers in-place pow w/ modulus self._wrapped = pow(self._wrapped, other, modulus) return self AbstractPyProxyBase = _ProxyMetaclass('AbstractPyProxyBase', (), dict(AbstractPyProxyBase.__dict__)) class PyProxyBase(AbstractPyProxyBase): """Reference implementation. """ __slots__ = ('_wrapped', ) def py_getProxiedObject(obj): if isinstance(obj, PyProxyBase): return obj._wrapped return obj def py_setProxiedObject(obj, new_value): if not isinstance(obj, PyProxyBase): raise TypeError('Not a proxy') old, obj._wrapped = obj._wrapped, new_value return old def py_isProxy(obj, klass=None): if klass is None: klass = PyProxyBase return isinstance(obj, klass) def py_sameProxiedObjects(lhs, rhs): while isinstance(lhs, PyProxyBase): lhs = super(PyProxyBase, lhs).__getattribute__('_wrapped') while isinstance(rhs, PyProxyBase): rhs = super(PyProxyBase, rhs).__getattribute__('_wrapped') return lhs is rhs def py_queryProxy(obj, klass=None, default=None): if klass is None: klass = PyProxyBase while obj is not None and not isinstance(obj, klass): obj = getattr(obj, '_wrapped', None) if obj is not None: return obj return default def py_queryInnerProxy(obj, klass=None, default=None): if klass is None: klass = PyProxyBase found = [] while obj is not None: if isinstance(obj, klass): found.append(obj) # stack obj = getattr(obj, '_wrapped', None) if found: return found[-1] return default def py_removeAllProxies(obj): while isinstance(obj, PyProxyBase): obj = super(PyProxyBase, obj).__getattribute__('_wrapped') return obj _c_available = False if 'PURE_PYTHON' not in os.environ: try: # pragma: no cover from zope.proxy._zope_proxy_proxy import ProxyBase as _c_available except ImportError: pass class PyNonOverridable: "Deprecated, only for BWC." def __init__(self, method_desc): # pragma: no cover PyPy self.desc = method_desc if _c_available: # pragma: no cover # Python API: not used in this module # API for proxy-using C extensions. from zope.proxy._zope_proxy_proxy import _CAPI # noqa: F401 unused from zope.proxy._zope_proxy_proxy import ProxyBase from zope.proxy._zope_proxy_proxy import getProxiedObject from zope.proxy._zope_proxy_proxy import isProxy from zope.proxy._zope_proxy_proxy import queryInnerProxy from zope.proxy._zope_proxy_proxy import queryProxy from zope.proxy._zope_proxy_proxy import removeAllProxies from zope.proxy._zope_proxy_proxy import sameProxiedObjects from zope.proxy._zope_proxy_proxy import setProxiedObject else: # no C extension available, fall back ProxyBase = PyProxyBase getProxiedObject = py_getProxiedObject setProxiedObject = py_setProxiedObject isProxy = py_isProxy sameProxiedObjects = py_sameProxiedObjects queryProxy = py_queryProxy queryInnerProxy = py_queryInnerProxy removeAllProxies = py_removeAllProxies def non_overridable(func): return property(lambda self: func.__get__(self)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1674028936.0 zope.proxy-5.1/src/zope/proxy/_zope_proxy_proxy.c0000644000076500000240000006532614361723610021324 0ustar00jensstaff/*############################################################################ # # Copyright (c) 2004 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################*/ /* * This file is also used as a really extensive macro in * ../container/_zope_container_contained.c. If you need to * change this file, you need to "svn copy" it to ../container/. * * This approach is taken to allow the sources for the two packages * to be compilable when the relative locations of these aren't * related in the same way as they are in a checkout. * * This will be revisited in the future, but works for now. */ #include "Python.h" #include "modsupport.h" #define PROXY_MODULE #include "proxy.h" static PyTypeObject ProxyType; #define Proxy_Check(wrapper) (PyObject_TypeCheck((wrapper), &ProxyType)) static PyObject * empty_tuple = NULL; #define MOD_ERROR_VAL NULL #define MOD_SUCCESS_VAL(val) val #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) #define MOD_DEF(ob, name, doc, methods) \ static struct PyModuleDef moduledef = { \ PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \ ob = PyModule_Create(&moduledef); /* * Slot methods. */ static PyObject * wrap_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *result = NULL; PyObject *object; if (PyArg_UnpackTuple(args, "__new__", 1, 1, &object)) { if (kwds != NULL && PyDict_Size(kwds) != 0) { PyErr_SetString(PyExc_TypeError, "proxy.__new__ does not accept keyword args"); return NULL; } result = PyType_GenericNew(type, args, kwds); if (result != NULL) { ProxyObject *wrapper = (ProxyObject *) result; Py_INCREF(object); wrapper->proxy_object = object; } } return result; } static int wrap_init(PyObject *self, PyObject *args, PyObject *kwds) { int result = -1; PyObject *object; if (PyArg_UnpackTuple(args, "__init__", 1, 1, &object)) { ProxyObject *wrapper = (ProxyObject *)self; if (kwds != NULL && PyDict_Size(kwds) != 0) { PyErr_SetString(PyExc_TypeError, "proxy.__init__ does not accept keyword args"); return -1; } /* If the object in this proxy is not the one we * received in args, replace it with the new one. */ if (wrapper->proxy_object != object) { PyObject *temp = wrapper->proxy_object; Py_INCREF(object); wrapper->proxy_object = object; Py_DECREF(temp); } result = 0; } return result; } static int wrap_traverse(PyObject *self, visitproc visit, void *arg) { PyObject *ob = Proxy_GET_OBJECT(self); if (ob != NULL) return visit(ob, arg); else return 0; } static int wrap_clear(PyObject *self) { ProxyObject *proxy = (ProxyObject *)self; PyObject *temp = proxy->proxy_object; if (temp != NULL) { proxy->proxy_object = NULL; Py_DECREF(temp); } return 0; } static PyObject * wrap_richcompare(PyObject* self, PyObject* other, int op) { if (Proxy_Check(self)) { self = Proxy_GET_OBJECT(self); } else { other = Proxy_GET_OBJECT(other); } return PyObject_RichCompare(self, other, op); } static PyObject * wrap_iter(PyObject *self) { return PyObject_GetIter(Proxy_GET_OBJECT(self)); } static PyObject * wrap_iternext(PyObject *self) { return PyIter_Next(Proxy_GET_OBJECT(self)); } static void wrap_dealloc(PyObject *self) { PyObject_GC_UnTrack(self); (void) wrap_clear(self); self->ob_type->tp_free(self); } /* A variant of _PyType_Lookup that doesn't look in ProxyType. * * If argument search_wrappertype is nonzero, we can look in WrapperType. */ PyObject * WrapperType_Lookup(PyTypeObject *type, PyObject *name) { int i, n; PyObject *mro, *res, *base, *dict; /* Look in tp_dict of types in MRO */ mro = type->tp_mro; /* If mro is NULL, the type is either not yet initialized by PyType_Ready(), or already cleared by type_clear(). Either way the safest thing to do is to return NULL. */ if (mro == NULL) return NULL; assert(PyTuple_Check(mro)); n = PyTuple_GET_SIZE(mro) - 1; /* We don't want to look at the last item, which is object. */ for (i = 0; i < n; i++) { base = PyTuple_GET_ITEM(mro, i); if (((PyTypeObject *)base) != &ProxyType) { assert(PyType_Check(base)); dict = ((PyTypeObject *)base)->tp_dict; assert(dict && PyDict_Check(dict)); res = PyDict_GetItem(dict, name); if (res != NULL) return res; } } return NULL; } static PyObject * wrap_getattro(PyObject *self, PyObject *name) { PyObject *wrapped; PyObject *descriptor; PyObject *res = NULL; const char *name_as_string; int maybe_special_name; name_as_string = PyUnicode_AsUTF8(name); if (name_as_string == NULL) { return NULL; } wrapped = Proxy_GET_OBJECT(self); if (wrapped == NULL) { PyErr_Format(PyExc_RuntimeError, "object is NULL; requested to get attribute '%s'", name_as_string); goto finally; } maybe_special_name = name_as_string[0] == '_' && name_as_string[1] == '_'; if (!(maybe_special_name && (strcmp(name_as_string, "__class__") == 0 || strcmp(name_as_string, "__module__") == 0))) { descriptor = WrapperType_Lookup(self->ob_type, name); if (descriptor != NULL) { if (descriptor->ob_type->tp_descr_get != NULL ){ if (descriptor->ob_type->tp_descr_set == NULL) { res = PyObject_GetAttr(wrapped, name); if (res != NULL) goto finally; if (PyErr_ExceptionMatches(PyExc_AttributeError)) PyErr_Clear(); else goto finally; } res = descriptor->ob_type->tp_descr_get( descriptor, self, (PyObject *)self->ob_type); } else { Py_INCREF(descriptor); res = descriptor; } goto finally; } } res = PyObject_GetAttr(wrapped, name); finally: return res; } static int wrap_setattro(PyObject *self, PyObject *name, PyObject *value) { PyObject *wrapped; PyObject *descriptor; const char *name_as_string; int res = -1; name_as_string = PyUnicode_AsUTF8(name); if (name_as_string == NULL) { goto finally; } descriptor = WrapperType_Lookup(self->ob_type, name); if (descriptor != NULL && descriptor->ob_type->tp_descr_set != NULL) { res = descriptor->ob_type->tp_descr_set(descriptor, self, value); goto finally; } wrapped = Proxy_GET_OBJECT(self); if (wrapped == NULL) { PyErr_Format(PyExc_RuntimeError, "object is NULL; requested to set attribute '%s'", name_as_string); goto finally; } res = PyObject_SetAttr(wrapped, name, value); finally: return res; } static PyObject * wrap_str(PyObject *wrapper) { return PyObject_Str(Proxy_GET_OBJECT(wrapper)); } static PyObject * wrap_repr(PyObject *wrapper) { return PyObject_Repr(Proxy_GET_OBJECT(wrapper)); } static long wrap_hash(PyObject *self) { return PyObject_Hash(Proxy_GET_OBJECT(self)); } static PyObject * wrap_call(PyObject *self, PyObject *args, PyObject *kw) { if (kw) return PyEval_CallObjectWithKeywords(Proxy_GET_OBJECT(self), args, kw); else return PyObject_CallObject(Proxy_GET_OBJECT(self), args); } /* * Number methods. */ static PyObject * call_int(PyObject *self) { return PyNumber_Long(self); } static PyObject * call_index(PyObject *self) { return PyNumber_Index(self); } static PyObject * call_float(PyObject *self) { return PyNumber_Float(self); } static PyObject * call_ipow(PyObject *self, PyObject *other) { /* PyNumber_InPlacePower has three args. How silly. :-) */ return PyNumber_InPlacePower(self, other, Py_None); } typedef PyObject *(*function1)(PyObject *); static PyObject * check1(ProxyObject *self, char *opname, function1 operation) { PyObject *result = NULL; result = operation(Proxy_GET_OBJECT(self)); #if 0 if (result != NULL) /* ??? create proxy for result? */ ; #endif return result; } static PyObject * check2(PyObject *self, PyObject *other, char *opname, char *ropname, binaryfunc operation) { PyObject *result = NULL; PyObject *object; if (Proxy_Check(self)) { object = Proxy_GET_OBJECT(self); result = operation(object, other); } else if (Proxy_Check(other)) { object = Proxy_GET_OBJECT(other); result = operation(self, object); } else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } #if 0 if (result != NULL) /* ??? create proxy for result? */ ; #endif return result; } static PyObject * check2i(ProxyObject *self, PyObject *other, char *opname, binaryfunc operation) { PyObject *result = NULL; PyObject *object = Proxy_GET_OBJECT(self); result = operation(object, other); if (result == object) { /* If the operation was really carried out inplace, don't create a new proxy, but use the old one. */ Py_INCREF(self); Py_DECREF(object); result = (PyObject *)self; } #if 0 else if (result != NULL) /* ??? create proxy for result? */ ; #endif return result; } #define UNOP(NAME, CALL) \ static PyObject *wrap_##NAME(PyObject *self) \ { return check1((ProxyObject *)self, "__"#NAME"__", CALL); } #define BINOP(NAME, CALL) \ static PyObject *wrap_##NAME(PyObject *self, PyObject *other) \ { return check2(self, other, "__"#NAME"__", "__r"#NAME"__", CALL); } #define INPLACE(NAME, CALL) \ static PyObject *wrap_i##NAME(PyObject *self, PyObject *other) \ { return check2i((ProxyObject *)self, other, "__i"#NAME"__", CALL); } BINOP(add, PyNumber_Add) BINOP(sub, PyNumber_Subtract) BINOP(mul, PyNumber_Multiply) BINOP(mod, PyNumber_Remainder) BINOP(divmod, PyNumber_Divmod) static PyObject * wrap_pow(PyObject *self, PyObject *other, PyObject *modulus) { PyObject *result = NULL; PyObject *object; if (Proxy_Check(self)) { object = Proxy_GET_OBJECT(self); result = PyNumber_Power(object, other, modulus); } else if (Proxy_Check(other)) { object = Proxy_GET_OBJECT(other); result = PyNumber_Power(self, object, modulus); } else if (modulus != NULL && Proxy_Check(modulus)) { object = Proxy_GET_OBJECT(modulus); result = PyNumber_Power(self, other, modulus); } else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } return result; } BINOP(lshift, PyNumber_Lshift) BINOP(rshift, PyNumber_Rshift) BINOP(and, PyNumber_And) BINOP(xor, PyNumber_Xor) BINOP(or, PyNumber_Or) UNOP(neg, PyNumber_Negative) UNOP(pos, PyNumber_Positive) UNOP(abs, PyNumber_Absolute) UNOP(invert, PyNumber_Invert) UNOP(int, call_int) UNOP(float, call_float) INPLACE(add, PyNumber_InPlaceAdd) INPLACE(sub, PyNumber_InPlaceSubtract) INPLACE(mul, PyNumber_InPlaceMultiply) INPLACE(mod, PyNumber_InPlaceRemainder) INPLACE(pow, call_ipow) INPLACE(lshift, PyNumber_InPlaceLshift) INPLACE(rshift, PyNumber_InPlaceRshift) INPLACE(and, PyNumber_InPlaceAnd) INPLACE(xor, PyNumber_InPlaceXor) INPLACE(or, PyNumber_InPlaceOr) BINOP(floordiv, PyNumber_FloorDivide) BINOP(truediv, PyNumber_TrueDivide) INPLACE(floordiv, PyNumber_InPlaceFloorDivide) INPLACE(truediv, PyNumber_InPlaceTrueDivide) UNOP(index, call_index) static int wrap_bool(PyObject *self) { return PyObject_IsTrue(Proxy_GET_OBJECT(self)); } /* * Sequence methods */ static Py_ssize_t wrap_length(PyObject *self) { return PyObject_Length(Proxy_GET_OBJECT(self)); } static int wrap_contains(PyObject *self, PyObject *value) { return PySequence_Contains(Proxy_GET_OBJECT(self), value); } /* * Mapping methods */ static PyObject * wrap_getitem(PyObject *wrapper, PyObject *v) { return PyObject_GetItem(Proxy_GET_OBJECT(wrapper), v); } static int wrap_setitem(PyObject *self, PyObject *key, PyObject *value) { if (value == NULL) return PyObject_DelItem(Proxy_GET_OBJECT(self), key); else return PyObject_SetItem(Proxy_GET_OBJECT(self), key, value); } /* * Normal methods */ static char reduce__doc__[] = "__reduce__()\n" "Raise an exception; this prevents proxies from being picklable by\n" "default, even if the underlying object is picklable."; static PyObject * wrap_reduce(PyObject *self) { PyObject *pickle_error = NULL; PyObject *pickle = PyImport_ImportModule("pickle"); if (pickle == NULL) PyErr_Clear(); else { pickle_error = PyObject_GetAttrString(pickle, "PicklingError"); if (pickle_error == NULL) PyErr_Clear(); } if (pickle_error == NULL) { pickle_error = PyExc_RuntimeError; Py_INCREF(pickle_error); } PyErr_SetString(pickle_error, "proxy instances cannot be pickled"); Py_DECREF(pickle_error); return NULL; } static PyNumberMethods wrap_as_number = { wrap_add, /* nb_add */ wrap_sub, /* nb_subtract */ wrap_mul, /* nb_multiply */ wrap_mod, /* nb_remainder */ wrap_divmod, /* nb_divmod */ wrap_pow, /* nb_power */ wrap_neg, /* nb_negative */ wrap_pos, /* nb_positive */ wrap_abs, /* nb_absolute */ wrap_bool, /* nb_bool, formerly nb_nonzero */ wrap_invert, /* nb_invert */ wrap_lshift, /* nb_lshift */ wrap_rshift, /* nb_rshift */ wrap_and, /* nb_and */ wrap_xor, /* nb_xor */ wrap_or, /* nb_or */ wrap_int, /* nb_int */ 0, /* formerly known as nb_long */ wrap_float, /* nb_float */ /* Added in release 2.0 */ /* These require the Py_TPFLAGS_HAVE_INPLACEOPS flag */ wrap_iadd, /* nb_inplace_add */ wrap_isub, /* nb_inplace_subtract */ wrap_imul, /* nb_inplace_multiply */ wrap_imod, /* nb_inplace_remainder */ (ternaryfunc)wrap_ipow, /* nb_inplace_power */ wrap_ilshift, /* nb_inplace_lshift */ wrap_irshift, /* nb_inplace_rshift */ wrap_iand, /* nb_inplace_and */ wrap_ixor, /* nb_inplace_xor */ wrap_ior, /* nb_inplace_or */ /* Added in release 2.2 */ /* These require the Py_TPFLAGS_HAVE_CLASS flag */ wrap_floordiv, /* nb_floor_divide */ wrap_truediv, /* nb_true_divide */ wrap_ifloordiv, /* nb_inplace_floor_divide */ wrap_itruediv, /* nb_inplace_true_divide */ wrap_index, /* nb_index */ }; static PySequenceMethods wrap_as_sequence = { wrap_length, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ 0, /* sq_item */ 0, /* sq_slice, unused in PY3 */ 0, /* sq_ass_item */ 0, /* sq_ass_slice, unused in PY3 */ wrap_contains, /* sq_contains */ }; static PyMappingMethods wrap_as_mapping = { wrap_length, /* mp_length */ wrap_getitem, /* mp_subscript */ wrap_setitem, /* mp_ass_subscript */ }; static PyMethodDef wrap_methods[] = { {"__reduce__", (PyCFunction)wrap_reduce, METH_NOARGS, reduce__doc__}, {NULL, NULL}, }; /* * Note that the numeric methods are not supported. This is primarily * because of the way coercion-less operations are performed with * new-style numbers; since we can't tell which side of the operation * is 'self', we can't ensure we'd unwrap the right thing to perform * the actual operation. We also can't afford to just unwrap both * sides the way weakrefs do, since we don't know what semantics will * be associated with the wrapper itself. */ static PyTypeObject ProxyType = { PyVarObject_HEAD_INIT(NULL, 0) "zope.proxy.ProxyBase", sizeof(ProxyObject), 0, wrap_dealloc, /* tp_dealloc */ 0, /* reserved 3.0--3.7; tp_vectorcall_offset 3.8+ */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ wrap_repr, /* tp_repr */ &wrap_as_number, /* tp_as_number */ &wrap_as_sequence, /* tp_as_sequence */ &wrap_as_mapping, /* tp_as_mapping */ wrap_hash, /* tp_hash */ wrap_call, /* tp_call */ wrap_str, /* tp_str */ wrap_getattro, /* tp_getattro */ wrap_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, /* tp_flags */ 0, /* tp_doc */ wrap_traverse, /* tp_traverse */ wrap_clear, /* tp_clear */ wrap_richcompare, /* tp_richcompare */ 0, /* tp_weaklistoffset */ wrap_iter, /* tp_iter */ wrap_iternext, /* tp_iternext */ wrap_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ wrap_init, /* tp_init */ 0, /* tp_alloc */ wrap_new, /* tp_new */ 0, /*PyObject_GC_Del,*/ /* tp_free */ }; static PyObject * create_proxy(PyObject *object) { PyObject *result = NULL; PyObject *args; args = PyTuple_New(1); if (args != NULL) { Py_INCREF(object); PyTuple_SET_ITEM(args, 0, object); result = PyObject_CallObject((PyObject *)&ProxyType, args); Py_DECREF(args); } return result; } static int api_check(PyObject *obj) { return obj ? Proxy_Check(obj) : 0; } static PyObject * api_create(PyObject *object) { if (object == NULL) { PyErr_SetString(PyExc_ValueError, "cannot create proxy around NULL"); return NULL; } return create_proxy(object); } static PyObject * api_getobject(PyObject *proxy) { if (proxy == NULL) { PyErr_SetString(PyExc_RuntimeError, "cannot pass NULL to ProxyAPI.getobject()"); return NULL; } if (Proxy_Check(proxy)) return Proxy_GET_OBJECT(proxy); else { PyErr_Format(PyExc_TypeError, "expected proxy object, got %s", proxy->ob_type->tp_name); return NULL; } } static ProxyInterface wrapper_capi = { &ProxyType, api_check, api_create, api_getobject, }; static PyObject *api_object = NULL; static char getobject__doc__[] = "getProxiedObject(proxy) --> object\n" "\n" "Get the underlying object for proxy, or the object itself, if it is\n" "not a proxy."; static PyObject * wrapper_getobject(PyObject *unused, PyObject *obj) { if (Proxy_Check(obj)) obj = Proxy_GET_OBJECT(obj); if (obj == NULL) obj = Py_None; Py_INCREF(obj); return obj; } static char setobject__doc__[] = "setProxiedObject(proxy, object) --> object\n" "\n" "Set the underlying object for proxy, returning the old proxied object.\n" "Raises TypeError if proxy is not a proxy.\n"; static PyObject * wrapper_setobject(PyObject *unused, PyObject *args) { PyObject *proxy; PyObject *object; PyObject *result = NULL; if (PyArg_ParseTuple(args, "O!O:setProxiedObject", &ProxyType, &proxy, &object)) { result = Proxy_GET_OBJECT(proxy); Py_INCREF(object); ((ProxyObject *) proxy)->proxy_object = object; } return result; } static char isProxy__doc__[] = "Check whether the given object is a proxy\n" "\n" "If proxytype is not None, checkes whether the object is\n" "proxied by the given proxytype.\n" ; static PyObject * wrapper_isProxy(PyObject *unused, PyObject *args) { PyObject *obj, *result; PyTypeObject *proxytype=&ProxyType; if (! PyArg_ParseTuple(args, "O|O!:isProxy", &obj, &PyType_Type, &proxytype) ) return NULL; while (obj && Proxy_Check(obj)) { if (PyObject_TypeCheck(obj, proxytype)) { result = Py_True; Py_INCREF(result); return result; } obj = Proxy_GET_OBJECT(obj); } result = Py_False; Py_INCREF(result); return result; } static char removeAllProxies__doc__[] = "removeAllProxies(proxy) --> object\n" "\n" "Get the proxied object with no proxies\n" "\n" "If obj is not a proxied object, return obj.\n" "\n" "The returned object has no proxies.\n" ; static PyObject * wrapper_removeAllProxies(PyObject *unused, PyObject *obj) { while (obj && Proxy_Check(obj)) obj = Proxy_GET_OBJECT(obj); if (obj == NULL) obj = Py_None; Py_INCREF(obj); return obj; } static char sameProxiedObjects__doc__[] = "Check whether two objects are the same or proxies of the same object"; static PyObject * wrapper_sameProxiedObjects(PyObject *unused, PyObject *args) { PyObject *ob1, *ob2; if (! PyArg_ParseTuple(args, "OO:sameProxiedObjects", &ob1, &ob2)) return NULL; while (ob1 && Proxy_Check(ob1)) ob1 = Proxy_GET_OBJECT(ob1); while (ob2 && Proxy_Check(ob2)) ob2 = Proxy_GET_OBJECT(ob2); if (ob1 == ob2) ob1 = Py_True; else ob1 = Py_False; Py_INCREF(ob1); return ob1; } static char queryProxy__doc__[] = "Look for a proxy of the given type around the object\n" "\n" "If no such proxy can be found, return the default.\n" ; static PyObject * wrapper_queryProxy(PyObject *unused, PyObject *args) { PyObject *obj, *result=Py_None; PyTypeObject *proxytype=&ProxyType; if (! PyArg_ParseTuple(args, "O|O!O:queryProxy", &obj, &PyType_Type, &proxytype, &result) ) return NULL; while (obj && Proxy_Check(obj)) { if (PyObject_TypeCheck(obj, proxytype)) { Py_INCREF(obj); return obj; } obj = Proxy_GET_OBJECT(obj); } Py_INCREF(result); return result; } static char queryInnerProxy__doc__[] = "Look for the inner-most proxy of the given type around the object\n" "\n" "If no such proxy can be found, return the default.\n" "\n" "If there is such a proxy, return the inner-most one.\n" ; static PyObject * wrapper_queryInnerProxy(PyObject *unused, PyObject *args) { PyObject *obj, *result=Py_None; PyTypeObject *proxytype=&ProxyType; if (! PyArg_ParseTuple(args, "O|O!O:queryInnerProxy", &obj, &PyType_Type, &proxytype, &result) ) return NULL; while (obj && Proxy_Check(obj)) { if (PyObject_TypeCheck(obj, proxytype)) result = obj; obj = Proxy_GET_OBJECT(obj); } Py_INCREF(result); return result; } /* Module initialization */ static char module___doc__[] = "Association between an object, a context object, and a dictionary.\n\ \n\ The context object and dictionary give additional context information\n\ associated with a reference to the basic object. The wrapper objects\n\ act as proxies for the original object."; static PyMethodDef module_functions[] = { {"getProxiedObject", wrapper_getobject, METH_O, getobject__doc__}, {"setProxiedObject", wrapper_setobject, METH_VARARGS, setobject__doc__}, {"isProxy", wrapper_isProxy, METH_VARARGS, isProxy__doc__}, {"sameProxiedObjects", wrapper_sameProxiedObjects, METH_VARARGS, sameProxiedObjects__doc__}, {"queryProxy", wrapper_queryProxy, METH_VARARGS, queryProxy__doc__}, {"queryInnerProxy", wrapper_queryInnerProxy, METH_VARARGS, queryInnerProxy__doc__}, {"removeAllProxies", wrapper_removeAllProxies, METH_O, removeAllProxies__doc__}, {NULL} }; MOD_INIT(_zope_proxy_proxy) { PyObject *m; MOD_DEF(m, "_zope_proxy_proxy", module___doc__, module_functions) if (m == NULL) return MOD_ERROR_VAL; if (empty_tuple == NULL) empty_tuple = PyTuple_New(0); ProxyType.tp_free = PyObject_GC_Del; if (PyType_Ready(&ProxyType) < 0) return MOD_ERROR_VAL; Py_INCREF(&ProxyType); PyModule_AddObject(m, "ProxyBase", (PyObject *)&ProxyType); if (api_object == NULL) { api_object = PyCapsule_New(&wrapper_capi, NULL, NULL); if (api_object == NULL) return MOD_ERROR_VAL; } Py_INCREF(api_object); PyModule_AddObject(m, "_CAPI", api_object); return MOD_SUCCESS_VAL(m); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/src/zope/proxy/decorator.py0000644000076500000240000000357114330441244017664 0ustar00jensstaff############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Decorator support Decorators are proxies that are mostly transparent but that may provide additional features. """ __docformat__ = "reStructuredText" from zope.interface import providedBy from zope.interface.declarations import ObjectSpecification from zope.interface.declarations import ObjectSpecificationDescriptor from zope.interface.declarations import getObjectSpecification from zope.proxy import ProxyBase from zope.proxy import getProxiedObject class DecoratorSpecificationDescriptor(ObjectSpecificationDescriptor): """Support for interface declarations on decorators """ def __get__(self, inst, cls=None): if inst is None: return getObjectSpecification(cls) else: provided = providedBy(getProxiedObject(inst)) # Use type rather than __class__ because inst is a proxy and # will return the proxied object's class. cls = type(inst) return ObjectSpecification(provided, cls) def __set__(self, inst, value): raise TypeError("Can't set __providedBy__ on a decorated object") class SpecificationDecoratorBase(ProxyBase): """Base class for a proxy that provides additional interfaces.""" __providedBy__ = DecoratorSpecificationDescriptor() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/src/zope/proxy/interfaces.py0000644000076500000240000000414414330441244020022 0ustar00jensstaff############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## """Proxy-related interfaces. """ from zope.interface import Interface class IProxyIntrospection(Interface): """Provides methods for indentifying proxies and extracting proxied objects """ def isProxy(obj, proxytype=None): """Check whether the given object is a proxy If proxytype is not None, checkes whether the object is proxied by the given proxytype. """ def sameProxiedObjects(ob1, ob2): """Check whether ob1 and ob2 are the same or proxies of the same object """ def getProxiedObject(obj): """Get the proxied Object If the object isn't proxied, then just return the object. """ def setProxiedObject(ob1, ob2): """Set the underlying object for ob1 to ob2, returning the old object. Raises TypeError if ob1 is not a proxy. """ def removeAllProxies(obj): """Get the proxied object with no proxies If obj is not a proxied object, return obj. The returned object has no proxies. """ def queryProxy(obj, proxytype, default=None): """Look for a proxy of the given type around the object If no such proxy can be found, return the default. """ def queryInnerProxy(obj, proxytype, default=None): """Look for the inner-most proxy of the given type around the object If no such proxy can be found, return the default. If there is such a proxy, return the inner-most one. """ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1672995421.0 zope.proxy-5.1/src/zope/proxy/proxy.h0000644000076500000240000000266114355761135016674 0ustar00jensstaff#ifndef _proxy_H_ #define _proxy_H_ 1 typedef struct { PyObject_HEAD PyObject *proxy_object; } ProxyObject; #define Proxy_GET_OBJECT(ob) (((ProxyObject *)(ob))->proxy_object) typedef struct { PyTypeObject *proxytype; int (*check)(PyObject *obj); PyObject *(*create)(PyObject *obj); PyObject *(*getobject)(PyObject *proxy); } ProxyInterface; #ifndef PROXY_MODULE /* These are only defined in the public interface, and are not * available within the module implementation. There we use the * classic Python/C API only. */ static ProxyInterface *_proxy_api = NULL; static int Proxy_Import(void) { if (_proxy_api == NULL) { PyObject *m = PyImport_ImportModule("zope.proxy"); if (m != NULL) { PyObject *tmp = PyObject_GetAttrString(m, "_CAPI"); if (tmp != NULL) { if (PyCapsule_CheckExact(tmp)) _proxy_api = (ProxyInterface *) PyCapsule_GetPointer(tmp, NULL); Py_DECREF(tmp); } } } return (_proxy_api == NULL) ? -1 : 0; } #define ProxyType (*_proxy_api->proxytype) #define Proxy_Check(obj) (_proxy_api->check((obj))) #define Proxy_CheckExact(obj) ((obj)->ob_type == ProxyType) #define Proxy_New(obj) (_proxy_api->create((obj))) #define Proxy_GetObject(proxy) (_proxy_api->getobject((proxy))) #endif /* PROXY_MODULE */ #endif /* _proxy_H_ */ ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1696517994.542558 zope.proxy-5.1/src/zope/proxy/tests/0000755000076500000240000000000014507547553016504 5ustar00jensstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/src/zope/proxy/tests/__init__.py0000644000076500000240000000007514330441244020577 0ustar00jensstaff# # This file is necessary to make this directory a package. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667383972.0 zope.proxy-5.1/src/zope/proxy/tests/test_compile_flags.py0000644000076500000240000000240614330441244022703 0ustar00jensstaff############################################################################## # # Copyright (c) 2022 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE # ############################################################################## import struct import unittest import zope.proxy # noqa: try to load a C module for side effects class TestFloatingPoint(unittest.TestCase): def test_no_fast_math_optimization(self): # Building with -Ofast enables -ffast-math, which sets certain FPU # flags that can cause breakage elsewhere. A library such as BTrees # has no business changing global FPU flags for the entire process. zero_bits = struct.unpack("!Q", struct.pack("!d", 0.0))[0] next_up = zero_bits + 1 smallest_subnormal = struct.unpack("!d", struct.pack("!Q", next_up))[0] self.assertNotEqual(smallest_subnormal, 0.0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1672995421.0 zope.proxy-5.1/src/zope/proxy/tests/test_decorator.py0000644000076500000240000001260714355761135022100 0ustar00jensstaff############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Test Harness """ import unittest class DecoratorSpecificationDescriptorTests(unittest.TestCase): def _getTargetClass(self): from zope.proxy.decorator import DecoratorSpecificationDescriptor return DecoratorSpecificationDescriptor def _makeOne(self): return self._getTargetClass()() def test___get___w_class(self): from zope.interface import Interface from zope.interface import implementer from zope.interface import provider class IContextFactory(Interface): pass class IContext(Interface): pass @provider(IContextFactory) @implementer(IContext) class Context: pass dsd = self._makeOne() self.assertEqual(list(dsd.__get__(None, Context)), [IContextFactory]) def test___get___w_inst_no_proxy(self): from zope.interface import Interface from zope.interface import implementer from zope.interface import provider class IContextFactory(Interface): pass class IContext(Interface): pass @provider(IContextFactory) @implementer(IContext) class Context: pass dsd = self._makeOne() self.assertEqual(list(dsd.__get__(Context(), None)), [IContext]) def test___get___w_inst_w_proxy(self): from zope.interface import Interface from zope.interface import implementer from zope.interface import provider from zope.proxy import ProxyBase class IContextFactory(Interface): pass class IContext(Interface): pass @provider(IContextFactory) @implementer(IContext) class Context: pass context = Context() proxy = ProxyBase(context) dsd = self._makeOne() self.assertEqual(list(dsd.__get__(proxy, None)), [IContext]) def test___get___w_inst_w_derived_proxy(self): from zope.interface import Interface from zope.interface import implementer from zope.interface import provider from zope.proxy import ProxyBase class IContextFactory(Interface): pass class IContext(Interface): pass @provider(IContextFactory) @implementer(IContext) class Context: pass class IProxyFactory(Interface): pass class IProxy(Interface): pass @provider(IProxyFactory) @implementer(IProxy) class Proxy(ProxyBase): pass context = Context() proxy = Proxy(context) dsd = self._makeOne() self.assertEqual(list(dsd.__get__(proxy, None)), [IContext, IProxy]) def test___set___not_allowed(self): from zope.interface import Interface from zope.interface import implementer class IFoo(Interface): pass @implementer(IFoo) class Foo: pass foo = Foo() dsd = self._makeOne() self.assertRaises(TypeError, dsd.__set__, foo, object()) class SpecificationDecoratorBaseTests(unittest.TestCase): def _getTargetClass(self): from zope.proxy.decorator import SpecificationDecoratorBase return SpecificationDecoratorBase def _makeOne(self, wrapped): return self._getTargetClass()(wrapped) def test_wrapped_instance(self): from zope.interface import Interface from zope.interface import implementer from zope.interface import providedBy class IFoo(Interface): pass @implementer(IFoo) class Foo: pass foo = Foo() proxy = self._makeOne(foo) self.assertEqual(list(providedBy(proxy)), list(providedBy(foo))) def test_proxy_that_provides_interface_as_well_as_wrapped(self): # If both the wrapper and the wrapped object provide # interfaces, the wrapper provides the sum from zope.interface import Interface from zope.interface import implementer from zope.interface import providedBy class IFoo(Interface): pass @implementer(IFoo) class Foo: from_foo = 1 class IWrapper(Interface): pass @implementer(IWrapper) class Proxy(self._getTargetClass()): pass foo = Foo() proxy = Proxy(foo) self.assertEqual(proxy.from_foo, 1) self.assertEqual(list(providedBy(proxy)), [IFoo, IWrapper]) def test_suite(): return unittest.TestSuite(( unittest.defaultTestLoader.loadTestsFromTestCase( DecoratorSpecificationDescriptorTests), unittest.defaultTestLoader.loadTestsFromTestCase( SpecificationDecoratorBaseTests), )) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1674028936.0 zope.proxy-5.1/src/zope/proxy/tests/test_proxy.py0000644000076500000240000012302314361723610021263 0ustar00jensstaff############################################################################## # # Copyright (c) 2003 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Test base proxy class. """ import pickle import unittest from .. import _c_available try: import zope.security except ImportError: # pragma: no cover _HAVE_ZOPE_SECURITY = False else: _HAVE_ZOPE_SECURITY = True del zope.security class ModuleConformanceCase(unittest.TestCase): def test_module_conforms_to_IProxyIntrospection(self): from zope.interface.verify import verifyObject import zope.proxy from zope.proxy.interfaces import IProxyIntrospection verifyObject(IProxyIntrospection, zope.proxy) class PyProxyBaseTestCase(unittest.TestCase): # Names of special methods getslice = '__getitem__' setslice = '__setitem__' # Avoid DeprecationWarning for assertRaisesRegexp on Python 3 while # coping with Python 2 not having the Regex spelling variant assertRaisesRegex = getattr( unittest.TestCase, 'assertRaisesRegex', getattr(unittest.TestCase, 'assertRaisesRegexp', None)) def _getTargetClass(self): from zope.proxy import PyProxyBase return PyProxyBase def _makeOne(self, o): return self._getTargetClass()(o) def test_constructor(self): o = object() self.assertRaises(TypeError, self._makeOne, o, o) self.assertRaises(TypeError, self._makeOne, o, key='value') self.assertRaises(TypeError, self._makeOne, key='value') def test_subclass_constructor(self): class MyProxy(self._getTargetClass()): def __new__(cls, *args, **kwds): return super().__new__(cls, *args, **kwds) def __init__(self, *args, **kwds): super().__init__(*args, **kwds) o1 = object() o2 = object() o = MyProxy((o1, o2)) self.assertEqual(o1, o[0]) self.assertEqual(o2, o[1]) self.assertRaises(TypeError, MyProxy, o1, o2) self.assertRaises(TypeError, MyProxy, o1, key='value') self.assertRaises(TypeError, MyProxy, key='value') # Check that are passed to __init__() overrides what's passed # to __new__(). class MyProxy2(self._getTargetClass()): def __new__(cls, *args, **kwds): return super().__new__(cls, 'value') proxy = MyProxy2('splat!') self.assertEqual(list(proxy), list('splat!')) class MyProxy3(MyProxy2): def __init__(self, arg): if list(self) != list('value'): raise AssertionError("list(self) != list('value')") super().__init__('another') proxy = MyProxy3('notused') self.assertEqual(list(proxy), list('another')) def test_custom_int_to_int(self): class CustomClass: def __int__(self): return 42 proxy = self._makeOne(CustomClass()) self.assertEqual(42, int(proxy)) def test_string_to_float(self): proxy = self._makeOne("14") self.assertEqual(float("14"), float(proxy)) def test_incorrect_string_to_int(self): proxy = self._makeOne("") self.assertRaises(ValueError, int, proxy) def test_incorrect_string_to_float(self): proxy = self._makeOne("") self.assertRaises(ValueError, float, proxy) def test_custom_float_to_float(self): class CustomClass: def __float__(self): return 42.0 proxy = self._makeOne(CustomClass()) self.assertEqual(42.0, float(proxy)) def test___call__(self): def _foo(): return 'FOO' proxy = self._makeOne(_foo) self.assertEqual(proxy(), 'FOO') def test___repr__(self): def _foo(): raise AssertionError("Not called") proxy = self._makeOne(_foo) self.assertEqual(repr(proxy), repr(_foo)) def test___str__(self): def _foo(): raise AssertionError("Not called") proxy = self._makeOne(_foo) self.assertEqual(str(proxy), str(_foo)) def test__reduce__raises(self): proxy = self._makeOne('foo') with self.assertRaises(pickle.PicklingError): proxy.__reduce__() def test__reduce_ex__raises(self): proxy = self._makeOne('foo') with self.assertRaises(pickle.PicklingError): proxy.__reduce_ex__(0) def test___eq___and___ne__(self): w = self._makeOne('foo') self.assertEqual(w, 'foo') o1 = Comparable(1) o2 = Comparable(1.0) o3 = Comparable("splat!") w1 = self._makeOne(o1) w2 = self._makeOne(o2) w3 = self._makeOne(o3) self.assertTrue(o1 == w1) self.assertTrue(o1 == w2) self.assertTrue(o2 == w1) self.assertTrue(w1 == o2) self.assertTrue(w2 == o1) self.assertTrue(o3 != w1) self.assertTrue(w1 != o3) self.assertTrue(w3 != o1) self.assertTrue(o1 != w3) def test___lt___and___le__(self): o1 = Comparable(1) o2 = Comparable(2.0) w1 = self._makeOne(o1) w2 = self._makeOne(o2) self.assertTrue(w1 < w2) self.assertTrue(w1 <= w2) self.assertTrue(o1 < w2) self.assertTrue(o1 <= w2) self.assertTrue(w1 < o2) self.assertTrue(w2 <= o2) def test___gt___and___ge__(self): o1 = Comparable(1) o2 = Comparable(2.0) w1 = self._makeOne(o1) w2 = self._makeOne(o2) self.assertTrue(w2 > w1) self.assertTrue(w2 >= w1) self.assertTrue(w2 > o1) self.assertTrue(w2 >= o1) self.assertTrue(o2 > w1) self.assertTrue(o2 >= w2) def test___bool__(self): w = self._makeOne(None) self.assertFalse(w) self.assertTrue(not w) def test___hash__(self): w1 = self._makeOne(1) self.assertEqual(hash(w1), hash(1)) def test___getattr__miss_both(self): class Foo: pass o = Foo() w = self._makeOne(o) def _try(): return w.nonesuch self.assertRaises(AttributeError, _try) def test___getattr__delegates_to_wrapped(self): class Foo: pass o = Foo() o.foo = 1 w = self._makeOne(o) self.assertEqual(w.foo, 1) def test___getattr__delegates_to_wrapped_when_conflict(self): class Proxy(self._getTargetClass()): def foo(self): raise AssertionError("Not called") class Foo: def foo(self): return 'FOO' o = Foo() w = Proxy(o) self.assertEqual(w.foo(), 'FOO') def test___setattr__delegates_to_wrapped(self): class Foo: pass o = Foo() w = self._makeOne(o) w.foo = 1 self.assertEqual(o.foo, 1) def test___setattr__sets_proxy_property(self): class Proxy(self._getTargetClass()): bar = property( lambda s: s.__dict__.get('_bar'), lambda s, v: s.__dict__.__setitem__('_bar', v) ) class Foo: pass o = Foo() w = Proxy(o) w.bar = 43 self.assertEqual(w.bar, 43) self.assertRaises(AttributeError, getattr, o, 'bar') def test___delattr___wrapped(self): class Foo: pass o = Foo() o.foo = 1 w = self._makeOne(o) def _try(): del w._wrapped self.assertRaises(AttributeError, _try) def test___delattr__delegates_to_wrapped(self): class Foo: pass o = Foo() o.foo = 1 w = self._makeOne(o) del w.foo self.assertFalse('foo' in o.__dict__) def test___len__(self): l_ = [] w = self._makeOne(l_) self.assertEqual(len(w), 0) l_.append(0) self.assertEqual(len(w), 1) def test___getitem_____setitem_____delitem__(self): w = self._makeOne({}) self.assertRaises(KeyError, lambda: w[1]) w[1] = 'a' self.assertEqual(w[1], 'a') del w[1] self.assertRaises(KeyError, lambda: w[1]) def del_w_1(): del w[1] self.assertRaises(KeyError, del_w_1) def test___getitem__w_slice_against_list(self): # Lists have special slicing behavior. pList = self._makeOne([1, 2]) self.assertEqual(pList[-1:], [2]) self.assertEqual(pList[-2:], [1, 2]) self.assertEqual(pList[-3:], [1, 2]) def test___getitem__w_slice_against_tuple(self): # Tuples also have special slicing behavior. pTuple = self._makeOne((1, 2)) self.assertEqual(pTuple[-1:], (2,)) self.assertEqual(pTuple[-2:], (1, 2)) self.assertEqual(pTuple[-3:], (1, 2)) def test___getitem__w_slice_against_derived_list(self): data = [1, 2] class DerivedList(list): pass pList = self._makeOne(DerivedList(data)) self.assertEqual(pList[-1:], data[-1:]) self.assertEqual(pList[-2:], data[-2:]) self.assertEqual(pList[-3:], data[-3:]) def test___getitem__w_slice_against_class_w_custom___getslice__(self): import sys class Slicer: def __len__(self): return 2 def __getitem__(self, a_slice): # On Python 3, we basically just return what the test expects. # Mostly that's the computed indices (yay!) but there are # a few special cases. indices = a_slice.indices(len(self)) return ( indices[0] if a_slice.start != -3 else -1, indices[-1] if a_slice.stop is not None else sys.maxsize) pSlicer = self._makeOne(Slicer()) self.assertEqual(pSlicer[:1][0], 0) self.assertEqual(pSlicer[:1][1], 1) self.assertEqual(pSlicer[:-1][0], 0) self.assertEqual(pSlicer[:-1][1], 1) self.assertEqual(pSlicer[-1:][0], 1) self.assertEqual(pSlicer[-2:][0], 0) self.assertEqual(pSlicer[-3:], (-1, sys.maxsize)) def test___getslice___dne_uses_getitem(self): class Missing(Exception): pass class Get: def __getitem__(self, x): raise Missing('__getitem__') target = Get() proxy = self._makeOne(target) with self.assertRaisesRegex(Missing, '__getitem__'): proxy[1:2] def test___getslice___error_propagates(self): class Missing(Exception): pass class Get: def __getitem__(self, x): raise Missing('__getitem__') target = Get() proxy = self._makeOne(target) with self.assertRaisesRegex(Missing, self.getslice): proxy[1:2] def test___setslice___against_list(self): # Lists have special slicing behavior for assignment as well. pList = self._makeOne([1, 2]) pList[-1:] = [3, 4] self.assertEqual(pList, [1, 3, 4]) pList = self._makeOne([1, 2]) pList[-2:] = [3, 4] self.assertEqual(pList, [3, 4]) pList = self._makeOne([1, 2]) pList[-3:] = [3, 4] self.assertEqual(pList, [3, 4]) def test___setslice___against_derived_list(self): # This behavior should be true for all list-derived classes. class DerivedList(list): pass pList = self._makeOne(DerivedList([1, 2])) pList[-1:] = [3, 4] self.assertEqual(pList, [1, 3, 4]) pList = self._makeOne(DerivedList([1, 2])) pList[-2:] = [3, 4] self.assertEqual(pList, [3, 4]) pList = self._makeOne(DerivedList([1, 2])) pList[-3:] = [3, 4] self.assertEqual(pList, [3, 4]) def test___setslice___error_propagates(self): class Missing(Exception): pass class Set: def __setitem__(self, k, v): raise Missing('__setitem__') target = Set() proxy = self._makeOne(target) with self.assertRaisesRegex(Missing, self.setslice): proxy[1:2] = 1 def test___setslice___dne_uses_setitem(self): class Missing(Exception): pass class Set: def __setitem__(self, k, v): raise Missing('__setitem__') target = Set() proxy = self._makeOne(target) with self.assertRaisesRegex(Missing, '__setitem__'): proxy[1:2] = 1 def test___iter___w_wrapped_iterable(self): a = [1, 2, 3] b = [] for x in self._makeOne(a): b.append(x) self.assertEqual(a, b) def test___iter___w_wrapped_iterator(self): # Wrap an iterator before starting iteration. # PyObject_GetIter() will still be called on the proxy. a = [1, 2, 3] b = [] for x in self._makeOne(iter(a)): b.append(x) self.assertEqual(a, b) t = tuple(self._makeOne(iter(a))) self.assertEqual(t, (1, 2, 3)) def test___iter___returns_self_if_defined(self): # Return the wrapped object itself, if it is an iterator. class MyIter: def __iter__(self): return self def __next__(self): raise AssertionError("Not called") next = __next__ myIter = MyIter() p = self._makeOne(myIter) self.assertEqual(iter(p), p) self.assertTrue(isinstance(iter(p), MyIter)) def test___iter___next_when_returned_by_iterable(self): # Wrap an iterator within the iteration protocol, expecting it # still to work. PyObject_GetIter() will not be called on the # proxy, so the tp_iter slot won't unwrap it. class Iterable: def __init__(self, test, data): self.test = test self.data = data def __iter__(self): return self.test._makeOne(iter(self.data)) a = [1, 2, 3] b = [] for x in Iterable(self, a): b.append(x) self.assertEqual(a, b) # Python 2.7 won't let the C wrapper support __reversed__ :( # def test___reversed__(self): # w = self._makeOne([0, 1, 2, 3]) # self.assertEqual(list(reversed(w)), [3, 2, 1, 0]) def test___contains__(self): w = self._makeOne([0, 1, 2, 3]) self.assertTrue(1 in w) self.assertFalse(4 in w) def test___index__(self): import operator w = self._makeOne(42) self.assertEqual(operator.index(w), 42) # Numeric ops. @property def unops(self): ops = [ "-x", "+x", "abs(x)", "~x", "int(x)", "float(x)", "complex(x)", ] return ops def test_unops(self): for expr in self.unops: x = 1 y = eval(expr) x = self._makeOne(1) z = eval(expr) self.assertEqual(z, y, f'x={x!r}; expr={expr!r}') def test_odd_unops(self): # unops that don't return a proxy funcs = (lambda x: not x,) for func in funcs: self.assertEqual(func(self._makeOne(100)), func(100)) binops = [ "x+y", "x-y", "x*y", "x/y", "x//y", "x%y", "divmod(x, y)", "x**y", # "pow(x,y,3)" (RHS coercion not supported w/ modulus) "x<>y", "x&y", "x|y", "x^y", ] def test_binops(self): for expr in self.binops: first = 1 for x in [1, self._makeOne(1)]: for y in [2, self._makeOne(2)]: if first: z = eval(expr) first = 0 else: msg = f'x={x!r}; y={y!r}; expr={expr!r}' self.assertEqual(eval(expr), z, msg) def test_pow_w_modulus(self): x = self._makeOne(2) # Can't coerce 2nd / 3rd args in pure Python, because we can't # lie about our type self.assertEqual(pow(x, 3, 3), 2) def test_inplace(self): # TODO: should test all inplace operators... pa = self._makeOne(1) pa += 2 self.assertEqual(pa, 3) a = [1, 2, 3] pa = qa = self._makeOne(a) pa += [4, 5, 6] self.assertTrue(pa is qa) self.assertEqual(a, [1, 2, 3, 4, 5, 6]) pa = self._makeOne(2) pa -= 1 self.assertEqual(pa, 1) pa *= 4 self.assertEqual(pa, 4) pa /= 2 self.assertEqual(pa, 2) pa //= 2 self.assertEqual(pa, 1) pa += 2 self.assertEqual(pa, 3) pa %= 2 self.assertEqual(pa, 1) pa = self._makeOne(2) pa **= 2 self.assertEqual(pa, 4) pa <<= 1 self.assertEqual(pa, 8) pa >>= 2 self.assertEqual(pa, 2) pa = self._makeOne(7) pa &= 6 self.assertEqual(pa, 6) pa |= 16 self.assertEqual(pa, 22) pa ^= 2 self.assertEqual(pa, 20) def test___class__(self): o = object() w = self._makeOne(o) self.assertTrue(w.__class__ is o.__class__) def test_descriptor__set___only_in_proxy_subclass(self): class Descriptor: value = None instance = None def __set__(self, instance, value): self.value = value self.instance = instance descriptor = Descriptor() class Proxy(self._getTargetClass()): attr = descriptor proxy = Proxy(object()) proxy.attr = 42 self.assertEqual(proxy.attr, descriptor) self.assertEqual(descriptor.value, 42) self.assertEqual(descriptor.instance, proxy) def test_descriptor__get___set___in_proxy_subclass(self): class Descriptor: value = None instance = None cls = None def __get__(self, instance, cls): self.cls = cls return self.value def __set__(self, instance, value): self.value = value self.instance = instance descriptor = Descriptor() descriptor.value = "descriptor value" class Proxy(self._getTargetClass()): attr = descriptor proxy = Proxy(object()) self.assertEqual(proxy.attr, "descriptor value") self.assertEqual(descriptor.cls, Proxy) proxy.attr = 42 self.assertEqual(descriptor.value, 42) self.assertEqual(descriptor.instance, proxy) def test_non_descriptor_in_proxy_subclass__dict__(self): # Non-descriptors in the class dict of the subclass # are always passed through to the wrapped instance class Proxy(self._getTargetClass()): attr = "constant value" proxy = Proxy(object()) self.assertEqual(proxy.attr, "constant value") self.assertRaises(AttributeError, setattr, proxy, 'attr', 42) self.assertEqual(proxy.attr, "constant value") def _check_wrapping_builtin_returns_correct_provided_by( self, proxy_class, builtin_type): # We get the __implemented__ (fallback) of the type, not our own from zope.interface import Interface from zope.interface import classImplements from zope.interface import classImplementsOnly from zope.interface import implementedBy from zope.interface import providedBy # Set up the builtin interface class IFoo(Interface): pass impl_before = list(implementedBy(builtin_type)) classImplements(builtin_type, IFoo) builtin = builtin_type() self.assertTrue(IFoo in list(providedBy(builtin))) self.assertTrue(IFoo in list(implementedBy(builtin_type))) try: # The asserts must be before we remove the interface # because there's a single object that gets mutated proxy_instance = proxy_class(builtin) provided_instance = providedBy(proxy_instance) self.assertTrue(IFoo in list(provided_instance)) proxy_type = proxy_class(builtin_type) from zope.interface.declarations import \ BuiltinImplementationSpecifications self.assertIn(proxy_type, BuiltinImplementationSpecifications) self.assertIsNot( BuiltinImplementationSpecifications.get(proxy_type, self), self) provided_type = implementedBy(proxy_type) self.assertTrue(IFoo in list(provided_type)) finally: classImplementsOnly(builtin_type, *impl_before) def test_wrapping_builtin_type_returns_correct_provided_by(self): self._check_wrapping_builtin_returns_correct_provided_by( self._getTargetClass(), list) def _check_wrapping_builtin_with_subclass_returns_correct_provided_by( self, builtin_type): class Proxy(self._getTargetClass()): pass self._check_wrapping_builtin_returns_correct_provided_by( Proxy, builtin_type) # Our new class did not gain an __implemented__ attribute, unless we're # the pure-python version if hasattr(Proxy, '__implemented__'): # pragma: no cover from zope.proxy import PyProxyBase self.assertTrue(self._getTargetClass() is PyProxyBase) def test_wrapping_builtin_with_subclass_returns_correct_provided_by(self): self._check_wrapping_builtin_with_subclass_returns_correct_provided_by( list) def test_method_in_proxy_subclass(self): class Proxy(self._getTargetClass()): def __getitem__(self, k): return k proxy = Proxy(object()) # Both when called by the interpreter, which bypasses # __getattribute__ self.assertEqual(proxy[42], 42) # And when asked for as an attribute self.assertNotEqual(getattr(proxy, '__getitem__'), self) def test_string_to_int(self): proxy = self._makeOne("14") self.assertEqual(14, int(proxy)) # When the C extension is not available the target class will be the same as # the Python implementation class. No need to run tests twice in that case. @unittest.skipUnless(_c_available, 'C extension not available') class ProxyBaseTestCase(PyProxyBaseTestCase): def _getTargetClass(self): from zope.proxy import ProxyBase return ProxyBase def test__reduce__raises(self): # With the C extension available the call to __reduce__ # is delegated to copyreg._reduce_ex from the standard library. # That function raises TypeErrors and not pickle's exceptions proxy = self._makeOne('foo') with self.assertRaises(TypeError): proxy.__reduce__() def test__reduce_ex__raises(self): # With the C extension available the call to __reduce_ex__ # is delegated to copyreg._reduce_ex from the standard library. # That function raises TypeErrors and not pickle's exceptions proxy = self._makeOne('foo') with self.assertRaises(TypeError): proxy.__reduce_ex__(0) class Test_py__module(unittest.TestCase): # Historically, proxying __module__ has been troublesome, # especially when subclasses of the proxy class are involved; # there was also a discrepancy between the C and Python implementations # in that the C implementation only failed # Test_subclass__module:test__module__in_instance, # whereas the Python version failed every test. # See https://github.com/zopefoundation/zopetoolkit/pull/2#issuecomment-106075153 # noqa: E501 line too long # and https://github.com/zopefoundation/zope.proxy/pull/8 def _getTargetClass(self): from zope.proxy import PyProxyBase return PyProxyBase def _makeProxy(self, obj): return self._getTargetClass()(obj) def _check_module(self, obj, expected): self.assertEqual(expected, obj.__module__) self.assertEqual(expected, self._makeProxy(obj).__module__) def test__module__in_instance(self): # We can find __module__ in an instance dict class Module: def __init__(self): self.__module__ = 'module' self._check_module(Module(), 'module') def test__module__in_class_instance(self): # We can find module in an instance of a class class Module: pass self._check_module(Module(), __name__) def test__module__in_class(self): # We can find module in a class itself class Module: pass self._check_module(Module, __name__) def test__module_in_eq_transitive(self): # An object that uses __module__ in its implementation # of __eq__ is transitively equal to a proxy of itself. # Seen with zope.interface.interface.Interface class Module: def __init__(self): self.__module__ = __name__ def __eq__(self, other): return self.__module__ == other.__module__ module = Module() # Sanity checks self.assertEqual(module, module) self.assertEqual(module.__module__, __name__) # transitive equal self.assertEqual(module, self._makeProxy(module)) self.assertEqual(self._makeProxy(module), module) class Test__module(Test_py__module): def _getTargetClass(self): from zope.proxy import ProxyBase return ProxyBase class Test_py_subclass__module(Test_py__module): def _getTargetClass(self): class ProxySubclass( super(Test_py_subclass__module, self)._getTargetClass()): pass return ProxySubclass class Test_subclass__module(Test__module): def _getTargetClass(self): class ProxySubclass( super(Test_subclass__module, self)._getTargetClass()): pass return ProxySubclass class Test_py_getProxiedObject(unittest.TestCase): def _callFUT(self, *args): from zope.proxy import py_getProxiedObject return py_getProxiedObject(*args) def _makeProxy(self, obj): from zope.proxy import PyProxyBase return PyProxyBase(obj) def test_no_proxy(self): class C: pass c = C() self.assertTrue(self._callFUT(c) is c) def test_simple_proxy(self): class C: pass c = C() proxy = self._makeProxy(c) self.assertTrue(self._callFUT(proxy) is c) def test_nested_proxy(self): class C: pass c = C() proxy = self._makeProxy(c) proxy2 = self._makeProxy(proxy) self.assertTrue(self._callFUT(proxy2) is proxy) class Test_getProxiedObject(Test_py_getProxiedObject): def _callFUT(self, *args): from zope.proxy import getProxiedObject return getProxiedObject(*args) def _makeProxy(self, obj): from zope.proxy import ProxyBase return ProxyBase(obj) class Test_py_setProxiedObject(unittest.TestCase): def _callFUT(self, *args): from zope.proxy import py_setProxiedObject return py_setProxiedObject(*args) def _makeProxy(self, obj): from zope.proxy import PyProxyBase return PyProxyBase(obj) def test_no_proxy(self): class C: pass c1 = C() c2 = C() self.assertRaises(TypeError, self._callFUT, c1, c2) def test_w_proxy(self): class C: def __init__(self, name): self.name = name c1 = C('c1') c2 = C('c2') proxy = self._makeProxy(c1) self.assertEqual(proxy.name, 'c1') old = self._callFUT(proxy, c2) self.assertTrue(old is c1) self.assertEqual(proxy.name, 'c2') def test_w_nested_proxy(self): class C: def __init__(self, name): self.name = name c1 = C('c1') c2 = C('c2') p1 = self._makeProxy(c1) proxy2 = self._makeProxy(c2) proxy = self._makeProxy(p1) self.assertEqual(proxy.name, 'c1') old = self._callFUT(proxy, proxy2) self.assertTrue(old is p1) self.assertEqual(proxy.name, 'c2') class Test_setProxiedObject(Test_py_setProxiedObject): def _callFUT(self, *args): from zope.proxy import setProxiedObject return setProxiedObject(*args) def _makeProxy(self, obj): from zope.proxy import ProxyBase return ProxyBase(obj) class Test_py_isProxy(unittest.TestCase): def _callFUT(self, *args): from zope.proxy import py_isProxy return py_isProxy(*args) def _proxyClass(self): from zope.proxy import PyProxyBase return PyProxyBase def test_bare_instance(self): class C: pass c = C() self.assertFalse(self._callFUT(c)) def test_proxy_no_class(self): class P1(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) self.assertTrue(self._callFUT(p1)) def test_proxy_w_same_class(self): class P1(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) self.assertTrue(self._callFUT(p1, P1)) def test_proxy_w_other_class(self): class P1(self._proxyClass()): pass class P2(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) self.assertFalse(self._callFUT(p1, P2)) class Test_isProxy(Test_py_isProxy): def _callFUT(self, *args): from zope.proxy import isProxy return isProxy(*args) def _proxyClass(self): from zope.proxy import ProxyBase return ProxyBase class Test_py_sameProxiedObjects(unittest.TestCase): def _callFUT(self, *args): from zope.proxy import py_sameProxiedObjects return py_sameProxiedObjects(*args) def _makeProxy(self, obj): from zope.proxy import PyProxyBase return PyProxyBase(obj) def _makeSecurityProxy(self, obj): from zope.security.checker import CheckerPy from zope.security.proxy import ProxyPy checker = CheckerPy({}) return ProxyPy(obj, checker) def test_bare_instance_identical(self): class C: pass c1 = C() self.assertTrue(self._callFUT(c1, c1)) def test_bare_instances_different(self): class C: pass c1 = C() c2 = C() self.assertFalse(self._callFUT(c1, c2)) self.assertFalse(self._callFUT(c2, c1)) def test_proxy_and_same_bare(self): class C: pass c1 = C() self.assertTrue(self._callFUT(self._makeProxy(c1), c1)) self.assertTrue(self._callFUT(c1, self._makeProxy(c1))) def test_proxy_and_other_bare(self): class C: pass c1 = C() c2 = C() self.assertFalse(self._callFUT(self._makeProxy(c1), c2)) self.assertFalse(self._callFUT(c2, self._makeProxy(c1))) def test_proxies_w_same_bare(self): _mP = self._makeProxy class C: pass c1 = C() self.assertTrue(self._callFUT(_mP(c1), _mP(c1))) def test_proxies_w_other_bare(self): _mP = self._makeProxy class C: pass c1 = C() c2 = C() self.assertFalse(self._callFUT(_mP(c1), _mP(c2))) self.assertFalse(self._callFUT(_mP(c2), _mP(c1))) def test_nested_proxy_and_same_bare(self): _mP = self._makeProxy class C: pass c1 = C() self.assertTrue(self._callFUT(_mP(_mP(c1)), c1)) self.assertTrue(self._callFUT(c1, _mP(_mP(c1)))) def test_nested_proxy_and_other_bare(self): _mP = self._makeProxy class C: pass c1 = C() c2 = C() self.assertFalse(self._callFUT(_mP(_mP(c1)), c2)) self.assertFalse(self._callFUT(c2, _mP(_mP(c1)))) @unittest.skipUnless(_HAVE_ZOPE_SECURITY, 'zope.security missing') def test_security_proxy(self): class C: pass c1 = C() proxy1 = self._makeSecurityProxy(c1) proxy1_2 = self._makeSecurityProxy(c1) self.assertTrue(self._callFUT(proxy1, proxy1)) self.assertTrue(self._callFUT(proxy1, proxy1_2)) c2 = C() proxy2 = self._makeSecurityProxy(c2) self.assertFalse(self._callFUT(proxy1, proxy2)) class Test_sameProxiedObjects(Test_py_sameProxiedObjects): def _callFUT(self, *args): from zope.proxy import sameProxiedObjects return sameProxiedObjects(*args) def _makeProxy(self, obj): from zope.proxy import ProxyBase return ProxyBase(obj) def _makeSecurityProxy(self, obj): from zope.security.checker import Checker from zope.security.proxy import Proxy checker = Checker({}) return Proxy(obj, checker) class Test_py_queryProxy(unittest.TestCase): def _callFUT(self, *args): from zope.proxy import py_queryProxy return py_queryProxy(*args) def _proxyClass(self): from zope.proxy import PyProxyBase return PyProxyBase def test_bare_instance(self): class C: pass c = C() self.assertEqual(self._callFUT(c), None) def test_proxy_no_class(self): class P1(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) self.assertTrue(self._callFUT(p1) is p1) def test_proxy_w_same_class(self): class P1(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) self.assertTrue(self._callFUT(p1, P1) is p1) self.assertTrue(self._callFUT(p1, P1, 42) is p1) def test_proxy_w_other_class(self): class P1(self._proxyClass()): pass class P2(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) self.assertEqual(self._callFUT(p1, P2), None) self.assertEqual(self._callFUT(p1, P2, 42), 42) def test_proxy_w_base_class(self): class P1(self._proxyClass()): pass class P2(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) self.assertTrue(self._callFUT(p1, self._proxyClass()) is p1) self.assertTrue(self._callFUT(p1, self._proxyClass(), 42) is p1) class Test_queryProxy(Test_py_queryProxy): def _callFUT(self, *args): from zope.proxy import queryProxy return queryProxy(*args) def _proxyClass(self): from zope.proxy import ProxyBase return ProxyBase class Test_py_queryInnerProxy(unittest.TestCase): def _callFUT(self, *args): from zope.proxy import py_queryInnerProxy return py_queryInnerProxy(*args) def _proxyClass(self): from zope.proxy import PyProxyBase return PyProxyBase def test_bare_instance(self): class C: pass c = C() self.assertEqual(self._callFUT(c), None) def test_proxy_no_class(self): class P1(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) self.assertTrue(self._callFUT(p1) is p1) def test_proxy_w_same_class(self): class P1(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) self.assertTrue(self._callFUT(p1, P1) is p1) self.assertTrue(self._callFUT(p1, P1, 42) is p1) def test_nested_proxy(self): class P1(self._proxyClass()): pass class P2(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) proxy2 = P2(p1) self.assertTrue(self._callFUT(proxy2, P1) is p1) self.assertTrue(self._callFUT(proxy2, P1, 42) is p1) self.assertTrue(self._callFUT(proxy2, P2) is proxy2) self.assertTrue(self._callFUT(proxy2, P2, 42) is proxy2) def test_re_nested_proxy(self): class P1(self._proxyClass()): pass class P2(self._proxyClass()): pass class C: pass c = C() p1 = P1(c) proxy2 = P2(p1) proxy3 = P1(proxy2) self.assertTrue(self._callFUT(proxy3, P1) is p1) self.assertTrue(self._callFUT(proxy3, P1, 42) is p1) self.assertTrue(self._callFUT(proxy3, P2) is proxy2) self.assertTrue(self._callFUT(proxy3, P2, 42) is proxy2) class Test_queryInnerProxy(Test_py_queryInnerProxy): def _callFUT(self, *args): from zope.proxy import queryInnerProxy return queryInnerProxy(*args) def _proxyClass(self): from zope.proxy import ProxyBase return ProxyBase class Test_py_removeAllProxies(unittest.TestCase): def _callFUT(self, *args): from zope.proxy import py_removeAllProxies return py_removeAllProxies(*args) def _makeProxy(self, obj): from zope.proxy import PyProxyBase return PyProxyBase(obj) def _makeSecurityProxy(self, obj): from zope.security.proxy import ProxyPy checker = object() return ProxyPy(obj, checker) def test_no_proxy(self): class C: pass c = C() self.assertTrue(self._callFUT(c) is c) def test_simple_proxy(self): class C: pass c = C() proxy = self._makeProxy(c) self.assertTrue(self._callFUT(proxy) is c) def test_nested_proxy(self): class C: pass c = C() proxy = self._makeProxy(c) proxy2 = self._makeProxy(proxy) self.assertTrue(self._callFUT(proxy2) is c) @unittest.skipUnless(_HAVE_ZOPE_SECURITY, 'zope.security missing') def test_security_proxy(self): class C: pass c = C() proxy = self._makeSecurityProxy(c) self.assertIs(self._callFUT(proxy), c) class Test_removeAllProxies(Test_py_removeAllProxies): def _callFUT(self, *args): from zope.proxy import removeAllProxies return removeAllProxies(*args) def _makeProxy(self, obj): from zope.proxy import ProxyBase return ProxyBase(obj) def _makeSecurityProxy(self, obj): from zope.security.proxy import Proxy checker = object() return Proxy(obj, checker) class Test_ProxyIterator(unittest.TestCase): def _callFUT(self, *args): from zope.proxy import ProxyIterator return ProxyIterator(*args) def test_no_proxy(self): class C: pass c = C() self.assertEqual(list(self._callFUT(c)), [c]) def test_w_simple_proxy(self): from zope.proxy import ProxyBase class C: pass c = C() proxy = ProxyBase(c) self.assertEqual(list(self._callFUT(proxy)), [proxy, c]) def test_w_nested_proxies(self): from zope.proxy import ProxyBase class C: pass c = C() proxy = ProxyBase(c) proxy2 = ProxyBase(proxy) proxy3 = ProxyBase(proxy2) proxy4 = ProxyBase(proxy3) self.assertEqual(list(self._callFUT(proxy4)), [proxy4, proxy3, proxy2, proxy, c]) class Test_nonOverridable(unittest.TestCase): def test_it(self): from zope.proxy import ProxyBase from zope.proxy import non_overridable class Proxy(ProxyBase): def who(self): raise AssertionError("Not called") @non_overridable def what(self): return 'PROXY' class Foo: def who(self): return 'FOO' def what(self): return 'FOO' p0 = ProxyBase(Foo()) self.assertEqual(p0.who(), 'FOO') self.assertEqual(p0.what(), 'FOO') proxy = Proxy(Foo()) self.assertEqual(proxy.who(), 'FOO') self.assertEqual(proxy.what(), 'PROXY') class TestEmptyInterfaceDescriptor(unittest.TestCase): def _makeOne(self): from zope.proxy import _EmptyInterfaceDescriptor class It: feature = _EmptyInterfaceDescriptor() return It() def test_set(self): it = self._makeOne() with self.assertRaises(TypeError): it.feature = 42 def test_delete(self): it = self._makeOne() del it.feature with self.assertRaises(AttributeError): getattr(it, 'feature') def test_iter(self): it = type(self._makeOne()) feature = it.__dict__['feature'] self.assertEqual([], list(feature)) class Comparable: def __init__(self, value): self.value = value def __eq__(self, other): return self.value == getattr(other, 'value', other) def __ne__(self, other): return not self.__eq__(other) def __lt__(self, other): return self.value < getattr(other, 'value', other) def __ge__(self, other): return not self.__lt__(other) def __le__(self, other): return self.value <= getattr(other, 'value', other) def __gt__(self, other): return not self.__le__(other) def __repr__(self): # pragma: no cover return "" % self.value def test_suite(): return unittest.defaultTestLoader.loadTestsFromName(__name__) ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1696517994.540909 zope.proxy-5.1/src/zope.proxy.egg-info/0000755000076500000240000000000014507547553017033 5ustar00jensstaff././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696517994.0 zope.proxy-5.1/src/zope.proxy.egg-info/PKG-INFO0000644000076500000240000002653414507547552020141 0ustar00jensstaffMetadata-Version: 2.1 Name: zope.proxy Version: 5.1 Summary: Generic Transparent Proxies Home-page: http://github.com/zopefoundation/zope.proxy Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Project-URL: Documentation, https://zopeproxy.readthedocs.io Project-URL: Issue Tracker, https://github.com/zopefoundation/zope.proxy/issues Project-URL: Sources, https://github.com/zopefoundation/zope.proxy Keywords: proxy generic transparent Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Framework :: Zope :: 3 Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Requires-Python: >=3.7 License-File: LICENSE.txt Requires-Dist: zope.interface Requires-Dist: setuptools Provides-Extra: test Requires-Dist: zope.security; extra == "test" Requires-Dist: zope.testrunner; extra == "test" Provides-Extra: docs Requires-Dist: Sphinx; extra == "docs" Requires-Dist: repoze.sphinx.autointerface; extra == "docs" Requires-Dist: sphinx_rtd_theme; extra == "docs" ================ ``zope.proxy`` ================ .. image:: https://github.com/zopefoundation/zope.proxy/actions/workflows/tests.yml/badge.svg :target: https://github.com/zopefoundation/zope.proxy/actions/workflows/tests.yml .. image:: https://ci.appveyor.com/api/projects/status/github/zopefoundation/zope.proxy?branch=master&svg=true :target: https://ci.appveyor.com/project/mgedmin/zope-proxy .. image:: https://coveralls.io/repos/github/zopefoundation/zope.proxy/badge.svg?branch=master :target: https://coveralls.io/github/zopefoundation/zope.proxy?branch=master .. image:: https://readthedocs.org/projects/zopeproxy/badge/?version=latest :target: https://zopeproxy.readthedocs.io/en/latest/ :alt: Documentation Status .. image:: https://img.shields.io/pypi/v/zope.proxy.svg :target: https://pypi.org/project/zope.proxy/ :alt: Latest release .. image:: https://img.shields.io/pypi/pyversions/zope.proxy.svg :target: https://pypi.org/project/zope.proxy/ :alt: Python versions Proxies are special objects which serve as mostly-transparent wrappers around another object, intervening in the apparent behavior of the wrapped object only when necessary to apply the policy (e.g., access checking, location brokering, etc.) for which the proxy is responsible. zope.proxy is implemented via a C extension module, which lets it do things like lie about its own ``__class__`` that are difficult in pure Python (and were completely impossible before metaclasses). It also proxies all the internal slots (such as ``__int__``/``__str__``/``__add__``). Complete documentation is at https://zopeproxy.readthedocs.io ========= Changes ========= 5.1 (2023-10-05) ================ - Add support for Python 3.12. 5.0.0 (2023-01-18) ================== - Drop support for Python 2.7, 3.5, 3.6. - Remove proxying code for names that no longer exist in Python 3 like ``__long__`` and some others. (`#55 `_) 4.6.1 (2022-11-16) ================== - Add support for building arm64 wheels on macOS. 4.6.0 (2022-11-03) ================== - Add support for Python 3.11. 4.5.1 (2022-09-15) ================== - Disable unsafe math optimizations in C code. See `pull request 53 `_. 4.5.0 (2021-11-17) ================== - Add support for Python 3.10. 4.4.0 (2021-07-22) ================== - Add support for Python 3.9. - Create aarch64 wheels. 4.3.5 (2020-03-16) ================== - Stop installing C header files on PyPy (which is what zope.proxy before 4.3.4 used to do), fixes `issue 39 `_. 4.3.4 (2020-03-13) ================== - Fix a compilation warning on Python 3.8. The slot ``tp_print`` changed to ``tp_vectorcall_offset`` in 3.8 and must not be set. Prior to 3.8, it was reserved and ignored in all Python 3 versions. See `issue 36 `_. - Remove deprecated use of setuptools features. See `issue 38 `_. 4.3.3 (2019-11-11) ================== - Add support for Python 3.8. - Drop support for Python 3.4. 4.3.2 (2019-07-12) ================== - Fix error handling in ``ProxyBase.__setattr__``: any the exception raised by ``PyString_AsString``/``PyUnicode_AsUTF8`` would be silently swallowed up and ignored. See `issue 31 `_. 4.3.1 (2018-08-09) ================== - Simplify the internal C handling of attribute names in ``__getattribute__`` and ``__setattr__``. - Make building the C extension optional. We still attempt to build it on supported platforms, but we allow it to fail in case of a missing compiler or headers. See `issue 26 `_. - Test the PURE_PYTHON environment and PyPy3 on Travis CI. - Add support for Python 3.7. 4.3.0 (2017-09-13) ================== - Fix a potential rare crash when deallocating proxies. See `issue 20 `_. - Drop support for Python 3.3. - Drop support for "python setup.py test". - 100% test coverage. - Fix indexing pure-Python proxies with slices under Python 3, and restore the use of ``__getslice__`` (if implemented by the target's type) under Python 2. Previously, pure-Python proxies would fail with an AttributeError when given a slice on Python 3, and on Python 2, a custom ``__getslice__`` was ignored. See `issue 21 `_. 4.2.1 (2017-04-23) ================== - Make the pure-Python implementation of ``sameProxiedObjects`` handle ``zope.security`` proxies. See `issue 15 `_. - Add support for Python 3.6. 4.2.0 (2016-05-05) ================== - Correctly strip ``zope.security`` proxies in ``removeAllProxies``. See `issue 13 `_. - Avoid poisoning the user's global wheel cache when testing ``PURE_PYTHON`` environments under ``tox``, - Drop support for Python 2.6 and 3.2. - Add support for Python 3.5. 4.1.6 (2015-06-02) ================== - Make subclasses of ProxyBase properly delegate ``__module__`` to the wrapped object. This fixes some ``zope.interface`` lookups under PyPy. - Make the pure-Python implementation of ProxyBase properly report the ``zope.interface`` interfaces implemented by builtin types like ``list``. This fixes some ``zope.interface`` lookups under PyPy. 4.1.5 (2015-05-19) ================== - Make the C implementation proxy ``__unicode__`` correctly. - Make the C implementation use the standard methods to proxy ``int`` and ``float``. - Make the pure Python implementation handle descriptors defined in subclasses like the C version. See https://github.com/zopefoundation/zope.proxy/issues/5. 4.1.4 (2014-03-19) ================== - Add support for Python 3.4. - Update ``bootstrap.py`` to version 2.2. 4.1.3 (2013-03-12) ================== - Fix interface object introspection in PyPy. For some reason PyPy makes attributes available despite the restrictive ``__slots__`` declaration. - Add a bunch of tests surrounding interface lookup and adaptation. 4.1.2 (2013-03-11) ================== - Make ``PyProxyBase.__iter__()`` return the result of ``PyProxyBase._wrapped.__iter__`` if available, otherwise falling back to Python internals. The previous implementation always created a generator. - In ``PyProxyBase.__setattr__()``, allow setting of properties on the proxy itself. This is needed to properly allow proxy extensions as was evidenced int he ``zope.security.decorator`` module. 4.1.1 (2012-12-31) ================== - Fleshed out PyPI Trove classifiers. 4.1.0 (2012-12-19) ================== - Enable compilation of dependent modules under Py3k. - Replace use of ``PyCObject`` APIs with equivalent ``PyCapsule`` APIs, except under Python 2.6. N.B. This change is an ABI incompatibility under Python 2.7: extensions built under Python 2.7 against 4.0.x versions of ``zope.proxy`` must be rebuilt. 4.0.1 (2012-11-21) ================== - Add support for Python 3.3. 4.0.0 (2012-06-06) ================== - Add support for PyPy. N.B.: the C extension is *not* built under PyPy. - Add a pure-Python reference / fallback implementations of ``zope.proxy.ProxyBase`` and the proxy module API functions. N.B.: the pure-Python proxy implements all regular features of ``ProxyBase``; however, it does not exclude access to the wrapped object in the same way that the C version does. If you need that information hiding (e.g., to implement security sandboxing), you still need to use the C version. - Add support for continuous integration using ``tox`` and ``jenkins``. - 100% unit test coverage. - Add Sphinx documentation: moved doctest examples to API reference. - Add 'setup.py docs' alias (installs ``Sphinx`` and dependencies). - Add 'setup.py dev' alias (runs ``setup.py develop`` plus installs ``nose`` and ``coverage``). - Replace deprecated ``zope.interface.implements`` usage with equivalent ``zope.interface.implementer`` decorator. - Drop support for Python 2.4 and 2.5. - Add Python 3.2 support. 3.6.1 (2010-07-06) ================== - Make tests compatible with Python 2.7. 3.6.0 (2010-04-30) ================== - Remove test extra and the remaining dependency on zope.testing. - Remove use of 'zope.testing.doctestunit' in favor of stdlib's 'doctest. 3.5.0 (2009/01/31) ================== - Add support to bootstrap on Jython. - Use ``zope.container`` instead of ``zope.app.container``. 3.4.2 (2008/07/27) ================== - Make C code compatible with Python 2.5 on 64bit architectures. 3.4.1 (2008/06/24) ================== - Bug: Update ``setup.py`` script to conform to common layout. Also updated some of the fields. - Bug: Honor pre-cooked indices for tuples and lists in the ``__getslice__()`` and ``__setslice__()`` methods. See http://docs.python.org/ref/sequence-methods.html. 3.4.0 (2007/07/12) ================== - Feature: Add a ``decorator`` module that supports declaring interfaces on proxies that get blended with the interfaces of the things they proxy. 3.3.0 (2006/12/20) ================== - Corresponds to the verison of the ``zope.proxy`` package shipped as part of the Zope 3.3.0 release. 3.2.0 (2006/01/05) ================== - Corresponds to the verison of the ``zope.proxy`` package shipped as part of the Zope 3.2.0 release. 3.0.0 (2004/11/07) ================== - Corresponds to the verison of the ``zope.proxy`` package shipped as part of the Zope X3.0.0 release. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696517994.0 zope.proxy-5.1/src/zope.proxy.egg-info/SOURCES.txt0000644000076500000240000000220014507547552020710 0ustar00jensstaff.coveragerc .manylinux-install.sh .manylinux.sh .readthedocs.yaml CHANGES.rst CONTRIBUTING.md COPYRIGHT.txt LICENSE.txt MANIFEST.in README.rst appveyor.yml buildout.cfg setup.cfg setup.py tox.ini docs/Makefile docs/api.rst docs/changes.rst docs/conf.py docs/hacking.rst docs/index.rst docs/make.bat docs/narr.rst docs/requirements.txt docs/_build/doctest/output.txt docs/_build/html/_sources/api.rst.txt docs/_build/html/_sources/changes.rst.txt docs/_build/html/_sources/hacking.rst.txt docs/_build/html/_sources/index.rst.txt docs/_build/html/_sources/narr.rst.txt src/zope/__init__.py src/zope.proxy.egg-info/PKG-INFO src/zope.proxy.egg-info/SOURCES.txt src/zope.proxy.egg-info/dependency_links.txt src/zope.proxy.egg-info/namespace_packages.txt src/zope.proxy.egg-info/not-zip-safe src/zope.proxy.egg-info/requires.txt src/zope.proxy.egg-info/top_level.txt src/zope/proxy/__init__.py src/zope/proxy/_zope_proxy_proxy.c src/zope/proxy/decorator.py src/zope/proxy/interfaces.py src/zope/proxy/proxy.h src/zope/proxy/tests/__init__.py src/zope/proxy/tests/test_compile_flags.py src/zope/proxy/tests/test_decorator.py src/zope/proxy/tests/test_proxy.py././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696517994.0 zope.proxy-5.1/src/zope.proxy.egg-info/dependency_links.txt0000644000076500000240000000000114507547552023100 0ustar00jensstaff ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696517994.0 zope.proxy-5.1/src/zope.proxy.egg-info/namespace_packages.txt0000644000076500000240000000000514507547552023360 0ustar00jensstaffzope ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1667384082.0 zope.proxy-5.1/src/zope.proxy.egg-info/not-zip-safe0000644000076500000240000000000114330441422021237 0ustar00jensstaff ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696517994.0 zope.proxy-5.1/src/zope.proxy.egg-info/requires.txt0000644000076500000240000000017414507547552021434 0ustar00jensstaffzope.interface setuptools [docs] Sphinx repoze.sphinx.autointerface sphinx_rtd_theme [test] zope.security zope.testrunner ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696517994.0 zope.proxy-5.1/src/zope.proxy.egg-info/top_level.txt0000644000076500000240000000000514507547552021557 0ustar00jensstaffzope ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1696516779.0 zope.proxy-5.1/tox.ini0000644000076500000240000000316314507545253013726 0ustar00jensstaff# Generated from: # https://github.com/zopefoundation/meta/tree/master/config/c-code [tox] minversion = 4.0 envlist = lint py37,py37-pure py38,py38-pure py39,py39-pure py310,py310-pure py311,py311-pure py312,py312-pure pypy3 docs coverage [testenv] usedevelop = true deps = py37: urllib3 < 2 setenv = pure: PURE_PYTHON=1 !pure-!pypy3: PURE_PYTHON=0 py312: VIRTUALENV_PIP=23.1.2 py312: PIP_REQUIRE_VIRTUALENV=0 commands = zope-testrunner --test-path=src {posargs:-vc} sphinx-build -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest extras = test docs [testenv:coverage] basepython = python3 allowlist_externals = mkdir deps = coverage py37: urllib3 < 2 setenv = PURE_PYTHON=1 commands = mkdir -p {toxinidir}/parts/htmlcov coverage run -m zope.testrunner --test-path=src {posargs:-vc} coverage html -i coverage report -i -m --fail-under=99 [testenv:lint] basepython = python3 skip_install = true commands = isort --check-only --diff {toxinidir}/src {toxinidir}/setup.py flake8 src setup.py check-manifest check-python-versions deps = check-manifest check-python-versions >= 0.19.1 wheel flake8 isort [testenv:isort-apply] basepython = python3 skip_install = true commands_pre = deps = isort commands = isort {toxinidir}/src {toxinidir}/setup.py [] [testenv:docs] basepython = python3 skip_install = false commands_pre = commands = sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest