summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Howitz <mh@gocept.com>2021-07-22 08:15:28 +0200
committerGitHub <noreply@github.com>2021-07-22 08:15:28 +0200
commit67da8197f2b8ed8eae915aa5e28798bc5c884094 (patch)
treeb4527b3ac8ff36d8ba4b74b496b3d4433495e5f2
parentb0f4124e950f2e8dde1d4e6c65c12e9e8b82c05d (diff)
parentafe9e808349251851e25c8739d8d92c3a82bfd8b (diff)
downloadzope-proxy-67da8197f2b8ed8eae915aa5e28798bc5c884094.tar.gz
Merge pull request #47 from zopefoundation/config-with-c-code
Config with c code
-rw-r--r--.coveragerc24
-rw-r--r--.editorconfig39
-rw-r--r--.github/workflows/tests.yml450
-rw-r--r--.gitignore39
-rwxr-xr-x.manylinux-install.sh31
-rwxr-xr-x.manylinux.sh13
-rw-r--r--.meta.toml37
-rw-r--r--.travis.yml116
-rw-r--r--CHANGES.rst4
-rw-r--r--MANIFEST.in24
-rw-r--r--appveyor.yml27
-rw-r--r--bootstrap.py210
-rw-r--r--setup.cfg24
-rw-r--r--setup.py7
-rw-r--r--src/zope/proxy/__init__.py78
-rw-r--r--src/zope/proxy/decorator.py3
-rw-r--r--src/zope/proxy/interfaces.py1
-rw-r--r--src/zope/proxy/tests/test_decorator.py24
-rw-r--r--src/zope/proxy/tests/test_proxy.py229
-rw-r--r--tox.ini80
20 files changed, 942 insertions, 518 deletions
diff --git a/.coveragerc b/.coveragerc
index e901a7d..b412d61 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,9 +1,29 @@
+# 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 =
- pragma: no cover
+ except ImportError:
if __name__ == '__main__':
- raise NotImplementedError
+ pragma: no cover
+ pragma: nocover
raise AssertionError
+ raise NotImplementedError
+ raise unittest.Skip
+ self.fail\(
+
+[html]
+directory = parts/htmlcov
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..9d3c4f2
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,39 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/c-code
+#
+# EditorConfig Configuration file, for more details see:
+# http://EditorConfig.org
+# EditorConfig is a convention description, that could be interpreted
+# by multiple editors to enforce common coding conventions for specific
+# file types
+
+# top-most EditorConfig file:
+# Will ignore other EditorConfig files in Home directory or upper tree level.
+root = true
+
+
+[*] # For All Files
+# Unix-style newlines with a newline ending every file
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+# Set default charset
+charset = utf-8
+# Indent style default
+indent_style = space
+# Max Line Length - a hard line wrap, should be disabled
+max_line_length = off
+
+[*.{py,cfg,ini}]
+# 4 space indentation
+indent_size = 4
+
+[*.{yml,zpt,pt,dtml,zcml}]
+# 2 space indentation
+indent_size = 2
+
+[{Makefile,.gitmodules}]
+# Tab indentation (no size specified, but view as 4 spaces)
+indent_style = tab
+indent_size = unset
+tab_width = unset
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
new file mode 100644
index 0000000..b66af7a
--- /dev/null
+++ b/.github/workflows/tests.yml
@@ -0,0 +1,450 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/c-code
+###
+# Initially copied from
+# https://github.com/actions/starter-workflows/blob/main/ci/python-package.yml
+# And later based on the version jamadden updated at
+# gevent/gevent, and then at zodb/relstorage and zodb/perfmetrics
+#
+# Original comment follows.
+###
+###
+# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
+###
+
+###
+# Important notes on GitHub actions:
+#
+# - We only get 2,000 free minutes a month (private repos)
+# - We only get 500MB of artifact storage
+# - Cache storage is limited to 7 days and 5GB.
+# - macOS minutes are 10x as expensive as Linux minutes
+# - windows minutes are twice as expensive.
+#
+# So keep those workflows light. Note: Currently, they seem to be free
+# and unlimited for open source projects. But for how long...
+#
+# In December 2020, github only supports x86/64. If we wanted to test
+# on other architectures, we can use docker emulation, but there's no
+# native support. It works, but is slow.
+#
+# Another major downside: You can't just re-run the job for one part
+# of the matrix. So if there's a transient test failure that hit, say, 3.8,
+# to get a clean run every version of Python runs again. That's bad.
+# https://github.community/t/ability-to-rerun-just-a-single-job-in-a-workflow/17234/65
+
+name: tests
+
+
+# Triggers the workflow on push or pull request events and periodically
+on:
+ push:
+ pull_request:
+ schedule:
+ - cron: '0 12 * * 0' # run once a week on Sunday
+ # Allow to run this workflow manually from the Actions tab
+ workflow_dispatch:
+
+env:
+ # Weirdly, this has to be a top-level key, not ``defaults.env``
+ PYTHONHASHSEED: 8675309
+ PYTHONUNBUFFERED: 1
+ PYTHONDONTWRITEBYTECODE: 1
+ PYTHONDEVMODE: 1
+ PYTHONFAULTHANDLER: 1
+ ZOPE_INTERFACE_STRICT_IRO: 1
+
+ PIP_UPGRADE_STRATEGY: eager
+ # Don't get warnings about Python 2 support being deprecated. We
+ # know. The env var works for pip 20.
+ PIP_NO_PYTHON_VERSION_WARNING: 1
+ PIP_NO_WARN_SCRIPT_LOCATION: 1
+
+ CFLAGS: -Ofast -pipe
+ CXXFLAGS: -Ofast -pipe
+ # Uploading built wheels for releases.
+ # TWINE_PASSWORD is encrypted and stored directly in the
+ # github repo settings.
+ TWINE_USERNAME: __token__
+
+ ###
+ # caching
+ # This is where we'd set up ccache, but this compiles so fast its not worth it.
+ ###
+
+
+jobs:
+ # Because sharing code/steps is so hard, and because it can be
+ # extremely valuable to be able to get binary wheels without
+ # uploading to PyPI and even if there is some failure, (e.g., for
+ # other people to test/debug), the strategy is to divide the process
+ # into several different jobs. The first builds and saves the binary
+ # wheels. It has dependent jobs that download and install the wheel
+ # to run tests, build docs, and perform linting. Building the
+ # manylinux wheels is an independent set of jobs.
+ #
+ # This division is time-saving for projects that take awhile to
+ # build, but somewhat less of a clear-cut win given how quick this
+ # is to compile (at least at this writing).
+ build-package:
+ # Sigh. Note that the matrix must be kept in sync
+ # with `test`, and `docs` must use a subset.
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ python-version:
+ - 2.7
+ - 3.5
+ - pypy-2.7
+ - pypy-3.6
+ - 3.6
+ - 3.7
+ - 3.8
+ - 3.9
+ os: [ubuntu-20.04, macos-latest]
+ exclude:
+ - os: macos-latest
+ python-version: pypy-2.7
+ - os: macos-latest
+ python-version: pypy-3.6
+ - os: macos-latest
+ python-version: 3.5
+
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ ###
+ # Caching.
+ # This actually *restores* a cache and schedules a cleanup action
+ # to save the cache. So it must come before the thing we want to use
+ # the cache.
+ ###
+ - name: Get pip cache dir
+ id: pip-cache
+ run: |
+ echo "::set-output name=dir::$(pip cache dir)"
+
+ - name: pip cache
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.pip-cache.outputs.dir }}
+ key: ${{ runner.os }}-pip-${{ matrix.python-version }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+
+ - name: Install Build Dependencies
+ run: |
+ pip install -U pip
+ pip install -U setuptools wheel twine cffi
+ pip install -U coveralls coverage
+
+ - name: Build zope.proxy
+ run: |
+ # Next, build the wheel *in place*. This helps ccache, and also lets us cache the configure
+ # output (pip install uses a random temporary directory, making this difficult).
+ python setup.py build_ext -i
+ python setup.py bdist_wheel
+ # Also install it, so that we get dependencies in the (pip) cache.
+ pip install -U coverage
+ pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"'
+ pip install .[test]
+
+ - name: Check zope.proxy build
+ run: |
+ ls -l dist
+ twine check dist/*
+ - name: Upload zope.proxy wheel
+ uses: actions/upload-artifact@v2
+ with:
+ name: zope.proxy-${{ runner.os }}-${{ matrix.python-version }}.whl
+ path: dist/*whl
+ - name: Publish package to PyPI (mac)
+ # We cannot 'uses: pypa/gh-action-pypi-publish@v1.4.1' because
+ # that's apparently a container action, and those don't run on
+ # the Mac.
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') && startsWith(runner.os, 'Mac')
+ env:
+ TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
+ run: |
+ twine upload --skip-existing dist/*
+
+ test:
+ needs: build-package
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ python-version:
+ - 2.7
+ - 3.5
+ - pypy-2.7
+ - pypy-3.6
+ - 3.6
+ - 3.7
+ - 3.8
+ - 3.9
+ os: [ubuntu-20.04, macos-latest]
+ exclude:
+ - os: macos-latest
+ python-version: pypy-2.7
+ - os: macos-latest
+ python-version: pypy-3.6
+ - os: macos-latest
+ python-version: 3.5
+
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ ###
+ # Caching.
+ # This actually *restores* a cache and schedules a cleanup action
+ # to save the cache. So it must come before the thing we want to use
+ # the cache.
+ ###
+ - name: Get pip cache dir
+ id: pip-cache
+ run: |
+ echo "::set-output name=dir::$(pip cache dir)"
+
+ - name: pip cache
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.pip-cache.outputs.dir }}
+ key: ${{ runner.os }}-pip-${{ matrix.python-version }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+
+ - name: Download zope.proxy wheel
+ uses: actions/download-artifact@v2
+ with:
+ name: zope.proxy-${{ runner.os }}-${{ matrix.python-version }}.whl
+ path: dist/
+ - name: Install zope.proxy
+ run: |
+ pip install -U wheel
+ pip install -U coverage coverage-python-version
+ pip install -U 'faulthandler; python_version == "2.7" and platform_python_implementation == "CPython"'
+ # Unzip into src/ so that testrunner can find the .so files
+ # when we ask it to load tests from that directory. This
+ # might also save some build time?
+ unzip -n dist/zope.proxy-*whl -d src
+ pip install -U -e .[test]
+ - name: Run tests with C extensions
+ if: ${{ !startsWith(matrix.python-version, 'pypy') }}
+ run: |
+ python -m coverage run -p -m zope.testrunner --test-path=src --auto-color --auto-progress
+ - name: Run tests without C extensions
+ run:
+ # coverage makes PyPy run about 3x slower!
+ PURE_PYTHON=1 python -m coverage run -p -m zope.testrunner --test-path=src --auto-color --auto-progress
+ - name: Report Coverage
+ run: |
+ coverage combine
+ coverage report -i
+ - name: Submit to Coveralls
+ # This is a container action, which only runs on Linux.
+ if: ${{ startsWith(runner.os, 'Linux') }}
+ uses: AndreMiras/coveralls-python-action@develop
+ with:
+ parallel: true
+
+ coveralls_finish:
+ needs: test
+ runs-on: ubuntu-20.04
+ steps:
+ - name: Coveralls Finished
+ uses: AndreMiras/coveralls-python-action@develop
+ with:
+ parallel-finished: true
+
+ docs:
+ needs: build-package
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ python-version: [3.9]
+ os: [ubuntu-20.04]
+
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ ###
+ # Caching.
+ # This actually *restores* a cache and schedules a cleanup action
+ # to save the cache. So it must come before the thing we want to use
+ # the cache.
+ ###
+ - name: Get pip cache dir
+ id: pip-cache
+ run: |
+ echo "::set-output name=dir::$(pip cache dir)"
+
+ - name: pip cache
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.pip-cache.outputs.dir }}
+ key: ${{ runner.os }}-pip-${{ matrix.python-version }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+
+ - name: Download zope.proxy wheel
+ uses: actions/download-artifact@v2
+ with:
+ name: zope.proxy-${{ runner.os }}-${{ matrix.python-version }}.whl
+ path: dist/
+ - name: Install zope.proxy
+ run: |
+ pip install -U wheel
+ pip install -U coverage
+ pip install -U "`ls dist/zope.proxy-*.whl`[docs]"
+ # Until repoze.sphinx.autointerface supports Sphinx 4.x we cannot use it:
+ pip install -U "Sphinx < 4"
+ - name: Build docs
+ env:
+ ZOPE_INTERFACE_STRICT_IRO: 1
+ run: |
+ sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html
+ sphinx-build -b doctest -d docs/_build/doctrees docs docs/_build/doctest
+
+ lint:
+ needs: build-package
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ python-version: [3.9]
+ os: [ubuntu-20.04]
+
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ ###
+ # Caching.
+ # This actually *restores* a cache and schedules a cleanup action
+ # to save the cache. So it must come before the thing we want to use
+ # the cache.
+ ###
+ - name: Get pip cache dir
+ id: pip-cache
+ run: |
+ echo "::set-output name=dir::$(pip cache dir)"
+
+ - name: pip cache
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.pip-cache.outputs.dir }}
+ key: ${{ runner.os }}-pip-${{ matrix.python-version }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+
+ - name: Download zope.proxy wheel
+ uses: actions/download-artifact@v2
+ with:
+ name: zope.proxy-${{ runner.os }}-${{ matrix.python-version }}.whl
+ path: dist/
+ - name: Install zope.proxy
+ run: |
+ pip install -U pip
+ pip install -U wheel
+ pip install -U `ls dist/zope.proxy-*`[test]
+ - name: Lint
+ # We only need to do this on one version, and it should be Python 3, because
+ # pylint has stopped updating for Python 2.
+ # TODO: Pick a linter and configuration and make this step right.
+ run: |
+ pip install -U pylint
+ # python -m pylint --limit-inference-results=1 --rcfile=.pylintrc zope.proxy -f parseable -r n
+
+ manylinux:
+ runs-on: ubuntu-20.04
+ # We use a regular Python matrix entry to share as much code as possible.
+ strategy:
+ matrix:
+ python-version: [3.9]
+ image: [manylinux2010_x86_64, manylinux2010_i686, manylinux2014_aarch64]
+
+ steps:
+ - name: checkout
+ uses: actions/checkout@v2
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v2
+ with:
+ python-version: ${{ matrix.python-version }}
+ ###
+ # Caching.
+ # This actually *restores* a cache and schedules a cleanup action
+ # to save the cache. So it must come before the thing we want to use
+ # the cache.
+ ###
+ - name: Get pip cache dir
+ id: pip-cache
+ run: |
+ echo "::set-output name=dir::$(pip cache dir)"
+
+ - name: pip cache
+ uses: actions/cache@v2
+ with:
+ path: ${{ steps.pip-cache.outputs.dir }}
+ key: ${{ runner.os }}-pip_manylinux-${{ matrix.image }}-${{ matrix.python-version }}
+ restore-keys: |
+ ${{ runner.os }}-pip-
+
+ - name: Update pip
+ run: pip install -U pip
+ - name: Build zope.proxy (x86_64)
+ if: matrix.image == 'manylinux2010_x86_64'
+ # An alternate way to do this is to run the container directly with a uses:
+ # and then the script runs inside it. That may work better with caching.
+ # See https://github.com/pyca/bcrypt/blob/f6b5ee2eda76d077c531362ac65e16f045cf1f29/.github/workflows/wheel-builder.yml
+ # The 2010 image is the most recent spec that comes with Python 2.7,
+ # and only up through the tag 2021-02-06-3d322a5
+ env:
+ DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }}
+ run: |
+ bash .manylinux.sh
+ - name: Build zope.proxy (i686)
+ if: matrix.image == 'manylinux2010_i686'
+ env:
+ DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }}
+ PRE_CMD: linux32
+ run: |
+ bash .manylinux.sh
+ - name: Build zope.proxy (aarch64)
+ if: matrix.image == 'manylinux2014_aarch64'
+ env:
+ DOCKER_IMAGE: quay.io/pypa/${{ matrix.image }}
+ run: |
+ # First we must enable emulation
+ docker run --rm --privileged hypriot/qemu-register
+ bash .manylinux.sh
+
+ - name: Upload zope.proxy wheels
+ uses: actions/upload-artifact@v2
+ with:
+ path: wheelhouse/*whl
+ name: manylinux_${{ matrix.image }}_wheels.zip
+ - name: Restore pip cache permissions
+ run: sudo chown -R $(whoami) ${{ steps.pip-cache.outputs.dir }}
+ - name: Publish package to PyPI
+ uses: pypa/gh-action-pypi-publish@v1.4.1
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags')
+ with:
+ user: __token__
+ password: ${{ secrets.TWINE_PASSWORD }}
+ skip_existing: true
+ packages_dir: wheelhouse/
diff --git a/.gitignore b/.gitignore
index 340eda5..20b2128 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,16 +1,31 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/c-code
+*.dll
+*.egg-info/
+*.profraw
*.pyc
+*.pyo
*.so
-__pycache__
-build
-*.egg-info
-docs/_build
-.installed.cfg
-bin
-develop-eggs
-eggs
-parts
-.tox
.coverage
-htmlcov/
-nosetests.xml
+.coverage.*
+.eggs/
+.installed.cfg
+.mr.developer.cfg
+.tox/
+.vscode/
+__pycache__/
+bin/
+build/
coverage.xml
+develop-eggs/
+develop/
+dist/
+docs/_build
+eggs/
+etc/
+lib/
+lib64
+log/
+parts/
+pyvenv.cfg
+var/
diff --git a/.manylinux-install.sh b/.manylinux-install.sh
index 6ce44bf..57220ed 100755
--- a/.manylinux-install.sh
+++ b/.manylinux-install.sh
@@ -1,17 +1,44 @@
#!/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
+
# Compile wheels
for PYBIN in /opt/python/*/bin; do
if [[ "${PYBIN}" == *"cp27"* ]] || \
[[ "${PYBIN}" == *"cp35"* ]] || \
[[ "${PYBIN}" == *"cp36"* ]] || \
[[ "${PYBIN}" == *"cp37"* ]] || \
- [[ "${PYBIN}" == *"cp38"* ]]; then
- "${PYBIN}/pip" install -U pip setuptools cffi
+ [[ "${PYBIN}" == *"cp38"* ]] || \
+ [[ "${PYBIN}" == *"cp39"* ]]; then
"${PYBIN}/pip" install -e /io/
"${PYBIN}/pip" wheel /io/ -w wheelhouse/
+ if [ `uname -m` == 'aarch64' ]; then
+ cd /io/
+ "${PYBIN}/pip" install tox
+ "${PYBIN}/tox" -e py
+ cd ..
+ fi
rm -rf /io/build /io/*.egg-info
fi
done
diff --git a/.manylinux.sh b/.manylinux.sh
index 2fed778..ea4ef41 100755
--- a/.manylinux.sh
+++ b/.manylinux.sh
@@ -1,5 +1,16 @@
#!/usr/bin/env bash
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/c-code
set -e -x
-docker run --rm -v "$(pwd)":/io $DOCKER_IMAGE $PRE_CMD /io/.manylinux-install.sh
+# 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
diff --git a/.meta.toml b/.meta.toml
new file mode 100644
index 0000000..efa741c
--- /dev/null
+++ b/.meta.toml
@@ -0,0 +1,37 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/c-code
+[meta]
+template = "c-code"
+commit-id = "bf824746f106a5f6314af285f3d5642e3ce490ce"
+
+[python]
+with-appveyor = true
+with-windows = false
+with-pypy = true
+with-future-python = false
+with-legacy-python = true
+with-docs = true
+with-sphinx-doctests = true
+
+[tox]
+use-flake8 = true
+
+[coverage]
+fail-under = 99
+
+[manifest]
+additional-rules = [
+ "include *.sh",
+ "recursive-include docs *.bat",
+ "recursive-include src *.h",
+ ]
+
+[appveyor]
+global-env-vars = [
+ "# 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==",
+ ]
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index db51783..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,116 +0,0 @@
-language: python
-
-env:
- global:
- TWINE_USERNAME: zope.wheelbuilder
- TWINE_PASSWORD:
- secure: "BWyhZtoO9jM3vatjfwdloThv7RY2p8AaN3D8T/8nEIupcgT5E6QKfLlIDibtlMNds2UU0q/HOJiSM/CwBsm5nzMke55m8OhfxfyHG+5TuBafwHtEkMyXe1VQtxnyB7Rlya2ylI9f4/3qXYqyLinBr3F+osE1g2nQmqQL2tpNmRA="
-
-python:
- - 2.7
- - 3.5
- - 3.6
- - 3.7
- - 3.8
- - pypy
- - pypy3
-
-jobs:
- include:
- - name: "Python: 2.7, pure (no C extensions)"
- python: "2.7"
- env: PURE_PYTHON=1
-
- # manylinux wheel builds
- - name: 64-bit manylinux wheels (all Pythons)
- services: docker
- env: DOCKER_IMAGE=quay.io/pypa/manylinux2010_x86_64
- install: docker pull $DOCKER_IMAGE
- script: bash .manylinux.sh
-
- - name: 32-bit manylinux wheels (all Pythons)
- services: docker
- env: DOCKER_IMAGE=quay.io/pypa/manylinux2010_i686 PRE_CMD=linux32
- install: docker pull $DOCKER_IMAGE
- script: bash .manylinux.sh
-
- # It's important to use 'macpython' builds to get the least
- # restrictive wheel tag. It's also important to avoid
- # 'homebrew 3' because it floats instead of being a specific version.
- - name: Python 2.7 wheels for MacOS
- os: osx
- language: generic
- env: TERRYFY_PYTHON='macpython 2.7.17'
- - name: Python 3.5 wheels for MacOS
- os: osx
- language: generic
- env: TERRYFY_PYTHON='macpython 3.5'
- - name: Python 3.6 wheels for MacOS
- os: osx
- language: generic
- env: TERRYFY_PYTHON='macpython 3.6.2'
- - name: Python 3.7 wheels for MacOS
- os: osx
- language: generic
- env: TERRYFY_PYTHON='macpython 3.7.0'
- - name: Python 3.8 wheels for MacOS
- os: osx
- language: generic
- env: TERRYFY_PYTHON='macpython 3.8.0'
-
-before_install:
- - |
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
- git clone https://github.com/MacPython/terryfy
- source terryfy/travis_tools.sh
- get_python_environment $TERRYFY_PYTHON venv
- fi
-
-install:
- - pip install -U pip
- - pip install -U setuptools
- - pip install -U coverage coveralls
- # NB: let's install . (zope.proxy) first separately, because we have a nasty
- # dependency loop: .[test] wants zope.security that setup_requires zope.proxy
- # (and setup_requires is broken on Mac OS Python 3.5 due to TLS version
- # compatibility issues that pip knows how to work around, but setuptools
- # don't).
- - pip install -e .
- - pip install -e .[test,docs]
-
-script:
- - python --version
- - coverage run -m zope.testrunner --test-path=src
- - sphinx-build -b html -d docs/_build/doctrees docs docs/_build/html
- - coverage run -a -m sphinx -b doctest -d docs/_build/doctrees docs docs/_build/doctest
- - python setup.py bdist_wheel
-
-after_success:
- - coveralls
- - |
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
- # macpython 3.5 doesn't support recent TLS protocols which causes twine
- # upload to fail, so we use the system Python to run twine
- /usr/bin/python -m ensurepip --user
- /usr/bin/python -m pip install --user -U pip
- /usr/bin/python -m pip install --user -U -I twine
- /usr/bin/python -m twine check dist/*
- if [[ $TRAVIS_TAG ]]; then
- /usr/bin/python -m twine upload --skip-existing dist/*
- fi
- fi
- - |
- if [[ -n "$DOCKER_IMAGE" ]]; then
- pip install twine
- twine check wheelhouse/*
- if [[ $TRAVIS_TAG ]]; then
- twine upload --skip-existing wheelhouse/*
- fi
- fi
-
-notifications:
- email: false
-
-cache: pip
-before_cache:
- - rm -f $HOME/.cache/pip/log/debug.log
diff --git a/CHANGES.rst b/CHANGES.rst
index 1fd639a..2369fef 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -5,7 +5,9 @@
4.3.6 (unreleased)
==================
-- Nothing changed yet.
+- Add support for Python 3.9.
+
+- Create aarch64 wheels.
4.3.5 (2020-03-16)
diff --git a/MANIFEST.in b/MANIFEST.in
index 2a03b09..c8bc394 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,18 +1,18 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/c-code
include *.rst
include *.txt
-include *.py
-include tox.ini
include buildout.cfg
-include .travis.yml
+include tox.ini
+include appveyor.yml
include .coveragerc
-recursive-include docs *
-recursive-include src *
-
-global-exclude *.dll
-global-exclude *.pyc
-global-exclude *.pyo
-global-exclude *.so
+recursive-include docs *.py
+recursive-include docs *.rst
+recursive-include docs *.txt
+recursive-include docs Makefile
-# added by check_manifest.py
-include *.yml
+recursive-include src *.py
+include *.sh
+recursive-include docs *.bat
+recursive-include src *.h
diff --git a/appveyor.yml b/appveyor.yml
index 9afaa42..4ebbe68 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,11 +1,12 @@
-# Currently the builds use @mgedmin's Appveyor account. The PyPI token belongs
-# to zope.wheelbuilder, which is managed by @mgedmin and @dataflake.
-
+# 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==
+ TWINE_USERNAME: __token__
+ TWINE_PASSWORD:
+ secure: aoZC/+rvJKg8B5GMGIxd1bg9UDShk28EhfPQFKI9zy7kzygdgj0XuaK619sLe3s4B08bIJaIUAThxEvWq13IvdLb5Oyk8B9qubd+NnDiNuw8WCGy4owYnbl+61fUVVKJIf1ETQyGDooYrEuBo798/+ycQbilTpmncAHZb2KyZkmA210fcWr7OhwmlRtC4IiW7GPCaxU6qhzLlP5pnS2Tl+yy/qx2DiW2fKWqUqynrb1ZMsk6ygN4qV72glTY6wV0eYboAGlghrws1x5+Z10Yug==
matrix:
- python: 27
@@ -18,8 +19,11 @@ environment:
- python: 37-x64
- python: 38
- python: 38-x64
+ - python: 39
+ - python: 39-x64
install:
+ - "SET PYTHONVERSION=%PYTHON%"
- "SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH%"
- ps: |
$env:PYTHON = "C:\\Python${env:PYTHON}"
@@ -31,20 +35,21 @@ install:
- 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 -e .
+ - pip install -U -e .[test]
+
+matrix:
+ fast_finish: true
build_script:
- - pip install wheel
- python -W ignore setup.py -q bdist_wheel
test_script:
- - python setup.py test -q
-
+ - 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/* }
+ - ps: if ($env:APPVEYOR_REPO_TAG -eq $TRUE) { pip install twine; twine upload --skip-existing dist\*.whl }
deploy: on
diff --git a/bootstrap.py b/bootstrap.py
deleted file mode 100644
index a459921..0000000
--- a/bootstrap.py
+++ /dev/null
@@ -1,210 +0,0 @@
-##############################################################################
-#
-# Copyright (c) 2006 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.
-#
-##############################################################################
-"""Bootstrap a buildout-based project
-
-Simply run this script in a directory containing a buildout.cfg.
-The script accepts buildout command-line options, so you can
-use the -c option to specify an alternate configuration file.
-"""
-
-import os
-import shutil
-import sys
-import tempfile
-
-from optparse import OptionParser
-
-__version__ = '2015-07-01'
-# See zc.buildout's changelog if this version is up to date.
-
-tmpeggs = tempfile.mkdtemp(prefix='bootstrap-')
-
-usage = '''\
-[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options]
-
-Bootstraps a buildout-based project.
-
-Simply run this script in a directory containing a buildout.cfg, using the
-Python that you want bin/buildout to use.
-
-Note that by using --find-links to point to local resources, you can keep
-this script from going over the network.
-'''
-
-parser = OptionParser(usage=usage)
-parser.add_option("--version",
- action="store_true", default=False,
- help=("Return bootstrap.py version."))
-parser.add_option("-t", "--accept-buildout-test-releases",
- dest='accept_buildout_test_releases',
- action="store_true", default=False,
- help=("Normally, if you do not specify a --version, the "
- "bootstrap script and buildout gets the newest "
- "*final* versions of zc.buildout and its recipes and "
- "extensions for you. If you use this flag, "
- "bootstrap and buildout will get the newest releases "
- "even if they are alphas or betas."))
-parser.add_option("-c", "--config-file",
- help=("Specify the path to the buildout configuration "
- "file to be used."))
-parser.add_option("-f", "--find-links",
- help=("Specify a URL to search for buildout releases"))
-parser.add_option("--allow-site-packages",
- action="store_true", default=False,
- help=("Let bootstrap.py use existing site packages"))
-parser.add_option("--buildout-version",
- help="Use a specific zc.buildout version")
-parser.add_option("--setuptools-version",
- help="Use a specific setuptools version")
-parser.add_option("--setuptools-to-dir",
- help=("Allow for re-use of existing directory of "
- "setuptools versions"))
-
-options, args = parser.parse_args()
-if options.version:
- print("bootstrap.py version %s" % __version__)
- sys.exit(0)
-
-
-######################################################################
-# load/install setuptools
-
-try:
- from urllib.request import urlopen
-except ImportError:
- from urllib2 import urlopen
-
-ez = {}
-if os.path.exists('ez_setup.py'):
- exec(open('ez_setup.py').read(), ez)
-else:
- exec(urlopen('https://bootstrap.pypa.io/ez_setup.py').read(), ez)
-
-if not options.allow_site_packages:
- # ez_setup imports site, which adds site packages
- # this will remove them from the path to ensure that incompatible versions
- # of setuptools are not in the path
- import site
- # inside a virtualenv, there is no 'getsitepackages'.
- # We can't remove these reliably
- if hasattr(site, 'getsitepackages'):
- for sitepackage_path in site.getsitepackages():
- # Strip all site-packages directories from sys.path that
- # are not sys.prefix; this is because on Windows
- # sys.prefix is a site-package directory.
- if sitepackage_path != sys.prefix:
- sys.path[:] = [x for x in sys.path
- if sitepackage_path not in x]
-
-setup_args = dict(to_dir=tmpeggs, download_delay=0)
-
-if options.setuptools_version is not None:
- setup_args['version'] = options.setuptools_version
-if options.setuptools_to_dir is not None:
- setup_args['to_dir'] = options.setuptools_to_dir
-
-ez['use_setuptools'](**setup_args)
-import setuptools
-import pkg_resources
-
-# This does not (always?) update the default working set. We will
-# do it.
-for path in sys.path:
- if path not in pkg_resources.working_set.entries:
- pkg_resources.working_set.add_entry(path)
-
-######################################################################
-# Install buildout
-
-ws = pkg_resources.working_set
-
-setuptools_path = ws.find(
- pkg_resources.Requirement.parse('setuptools')).location
-
-# Fix sys.path here as easy_install.pth added before PYTHONPATH
-cmd = [sys.executable, '-c',
- 'import sys; sys.path[0:0] = [%r]; ' % setuptools_path +
- 'from setuptools.command.easy_install import main; main()',
- '-mZqNxd', tmpeggs]
-
-find_links = os.environ.get(
- 'bootstrap-testing-find-links',
- options.find_links or
- ('http://downloads.buildout.org/'
- if options.accept_buildout_test_releases else None)
- )
-if find_links:
- cmd.extend(['-f', find_links])
-
-requirement = 'zc.buildout'
-version = options.buildout_version
-if version is None and not options.accept_buildout_test_releases:
- # Figure out the most recent final version of zc.buildout.
- import setuptools.package_index
- _final_parts = '*final-', '*final'
-
- def _final_version(parsed_version):
- try:
- return not parsed_version.is_prerelease
- except AttributeError:
- # Older setuptools
- for part in parsed_version:
- if (part[:1] == '*') and (part not in _final_parts):
- return False
- return True
-
- index = setuptools.package_index.PackageIndex(
- search_path=[setuptools_path])
- if find_links:
- index.add_find_links((find_links,))
- req = pkg_resources.Requirement.parse(requirement)
- if index.obtain(req) is not None:
- best = []
- bestv = None
- for dist in index[req.project_name]:
- distv = dist.parsed_version
- if _final_version(distv):
- if bestv is None or distv > bestv:
- best = [dist]
- bestv = distv
- elif distv == bestv:
- best.append(dist)
- if best:
- best.sort()
- version = best[-1].version
-if version:
- requirement = '=='.join((requirement, version))
-cmd.append(requirement)
-
-import subprocess
-if subprocess.call(cmd) != 0:
- raise Exception(
- "Failed to execute command:\n%s" % repr(cmd)[1:-1])
-
-######################################################################
-# Import and run buildout
-
-ws.add_entry(tmpeggs)
-ws.require(requirement)
-import zc.buildout.buildout
-
-if not [a for a in args if '=' not in a]:
- args.append('bootstrap')
-
-# if -c was provided, we push it back into args for buildout' main function
-if options.config_file is not None:
- args[0:0] = ['-c', options.config_file]
-
-zc.buildout.buildout.main(args)
-shutil.rmtree(tmpeggs)
diff --git a/setup.cfg b/setup.cfg
index 68cf005..1ffc947 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,13 +1,17 @@
-[nosetests]
-nocapture=1
-cover-package=zope.proxy
-cover-erase=1
-with-doctest=0
-where=src
-
-[aliases]
-dev = develop easy_install zope.proxy[testing]
-docs = easy_install zope.proxy[docs]
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/c-code
+[bdist_wheel]
+universal = 1
[zest.releaser]
create-wheel = no
+
+[flake8]
+doctests = 1
+
+[check-manifest]
+ignore =
+ .editorconfig
+ .meta.toml
+ docs/_build/html/_sources/*
+ docs/_build/doctest/*
diff --git a/setup.py b/setup.py
index bf9e1a7..477219f 100644
--- a/setup.py
+++ b/setup.py
@@ -36,6 +36,7 @@ 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)
@@ -103,6 +104,7 @@ setup(name='zope.proxy',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
+ 'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
'Framework :: Zope :: 3',
@@ -130,8 +132,9 @@ setup(name='zope.proxy',
'zope.testrunner',
],
'docs': [
- 'Sphinx<4', # Until repoze.sphinx.autointerface supports Sphinx 4.x we cannot use it
+ # Need < 4 until repoze.sphinx.autointerface supports Sphinx 4:
+ 'Sphinx < 4',
'repoze.sphinx.autointerface',
],
},
-)
+ )
diff --git a/src/zope/proxy/__init__.py b/src/zope/proxy/__init__.py
index 620e565..d17187a 100644
--- a/src/zope/proxy/__init__.py
+++ b/src/zope/proxy/__init__.py
@@ -16,7 +16,6 @@
import operator
import os
import pickle
-import sys
from zope.interface import moduleProvides
from zope.proxy.interfaces import IProxyIntrospection
@@ -24,6 +23,7 @@ from zope.proxy.interfaces import IProxyIntrospection
moduleProvides(IProxyIntrospection)
__all__ = tuple(IProxyIntrospection)
+
def ProxyIterator(p):
yield p
while isProxy(p):
@@ -33,6 +33,7 @@ def ProxyIterator(p):
_MARKER = object()
+
def _WrapperType_Lookup(type_, name):
"""
Looks up information in class dictionaries in MRO
@@ -49,12 +50,14 @@ def _WrapperType_Lookup(type_, name):
return res
return _MARKER
+
def _get_wrapped(self):
"""
Helper method to access the wrapped object.
"""
return super(AbstractPyProxyBase, self).__getattribute__('_wrapped')
+
class _EmptyInterfaceDescriptor(object):
"""A descriptor for the attributes used on the class by the
Python implementation of `zope.interface`.
@@ -79,11 +82,13 @@ class _EmptyInterfaceDescriptor(object):
raise StopIteration()
next = __next__
+
class _ProxyMetaclass(type):
# The metaclass is applied after the class definition
# for Py2/Py3 compatibility.
__implemented__ = _EmptyInterfaceDescriptor()
+
class AbstractPyProxyBase(object):
"""
A reference implementation that cannot be instantiated. Most users
@@ -116,10 +121,10 @@ class AbstractPyProxyBase(object):
def __str__(self):
return str(self._wrapped)
- def __unicode__(self):
- return unicode(self._wrapped)
+ def __unicode__(self): # pragma: no cover PY2
+ return unicode(self._wrapped) # noqa: F821 undefined name
- def __reduce__(self): # pragma: no cover (__reduce_ex__ prevents normal)
+ def __reduce__(self): # pragma: no cover (__reduce_ex__ prevents normal)
raise pickle.PicklingError
def __reduce_ex__(self, proto):
@@ -146,7 +151,7 @@ class AbstractPyProxyBase(object):
def __nonzero__(self):
return bool(self._wrapped)
- __bool__ = __nonzero__ # Python3 compat
+ __bool__ = __nonzero__ # Python3 compat
def __hash__(self):
return hash(self._wrapped)
@@ -240,18 +245,19 @@ class AbstractPyProxyBase(object):
del self._wrapped[key]
def __iter__(self):
- # This handles a custom __iter__ and generator support at the same time.
+ # This handles a custom __iter__ and generator support at the same
+ # time.
return iter(self._wrapped)
- def next(self):
+ def next(self): # pragma: no cover PY2
# Called when we wrap an iterator itself.
return self._wrapped.next()
- def __next__(self): # pragma: no cover Python3
+ def __next__(self):
return self._wrapped.__next__()
# Python 2.7 won't let the C wrapper support __reversed__ :(
- #def __reversed__(self):
+ # def __reversed__(self):
# return reversed(self._wrapped)
def __contains__(self, item):
@@ -277,8 +283,8 @@ class AbstractPyProxyBase(object):
def __int__(self):
return int(self._wrapped)
- def __long__(self):
- return long(self._wrapped)
+ def __long__(self): # pragma: no cover PY2
+ return long(self._wrapped) # noqa: F821 undefined name
def __float__(self):
return float(self._wrapped)
@@ -293,9 +299,10 @@ class AbstractPyProxyBase(object):
return operator.index(self._wrapped)
# Numeric protocol: binary coercion
- def __coerce__(self, other):
- left, right = coerce(self._wrapped, other)
- if left == self._wrapped and type(left) is type(self._wrapped):
+ def __coerce__(self, other): # pragma: no cover PY2
+ left, right = coerce(self._wrapped, other) # noqa: F821 undefined name
+ if (left == self._wrapped
+ and type(left) is type(self._wrapped)): # noqa: E721
left = self
return left, right
@@ -312,11 +319,11 @@ class AbstractPyProxyBase(object):
def __floordiv__(self, other):
return self._wrapped // other
- def __truediv__(self, other): # pragma: no cover
+ def __truediv__(self, other): # pragma: no cover
# Only one of __truediv__ and __div__ is meaningful at any one time.
return self._wrapped / other
- def __div__(self, other): # pragma: no cover
+ def __div__(self, other): # pragma: no cover
# Only one of __truediv__ and __div__ is meaningful at any one time.
return self._wrapped / other
@@ -343,11 +350,11 @@ class AbstractPyProxyBase(object):
def __rfloordiv__(self, other):
return other // self._wrapped
- def __rtruediv__(self, other): # pragma: no cover
+ def __rtruediv__(self, other): # pragma: no cover
# Only one of __rtruediv__ and __rdiv__ is meaningful at any one time.
return other / self._wrapped
- def __rdiv__(self, other): # pragma: no cover
+ def __rdiv__(self, other): # pragma: no cover
# Only one of __rtruediv__ and __rdiv__ is meaningful at any one time.
return other / self._wrapped
@@ -361,7 +368,7 @@ class AbstractPyProxyBase(object):
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
+ return pow(other, self._wrapped, modulus) # pragma: no cover
# Numeric protocol: binary bitwise operators
def __lshift__(self, other):
@@ -407,12 +414,12 @@ class AbstractPyProxyBase(object):
self._wrapped *= other
return self
- def __idiv__(self, other): # pragma: no cover
+ def __idiv__(self, other): # pragma: no cover
# Only one of __itruediv__ and __idiv__ is meaningful at any one time.
self._wrapped /= other
return self
- def __itruediv__(self, other): # pragma: no cover
+ def __itruediv__(self, other): # pragma: no cover
# Only one of __itruediv__ and __idiv__ is meaningful at any one time.
self._wrapped /= other
return self
@@ -448,14 +455,16 @@ class AbstractPyProxyBase(object):
def __ipow__(self, other, modulus=None):
if modulus is None:
self._wrapped **= other
- else: # pragma: no cover
+ 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(str('AbstractPyProxyBase'), (),
dict(AbstractPyProxyBase.__dict__))
+
class PyProxyBase(AbstractPyProxyBase):
"""Reference implementation.
"""
@@ -467,17 +476,20 @@ def py_getProxiedObject(obj):
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')
@@ -485,6 +497,7 @@ def py_sameProxiedObjects(lhs, rhs):
rhs = super(PyProxyBase, rhs).__getattribute__('_wrapped')
return lhs is rhs
+
def py_queryProxy(obj, klass=None, default=None):
if klass is None:
klass = PyProxyBase
@@ -494,36 +507,42 @@ def py_queryProxy(obj, klass=None, default=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
+ 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:
+ try: # pragma: no cover
from zope.proxy._zope_proxy_proxy import ProxyBase as _c_available
- except ImportError: # pragma: no cover
+ except ImportError:
pass
+
class PyNonOverridable(object):
"Deprecated, only for BWC."
- def __init__(self, method_desc): # pragma: no cover PyPy
+
+ def __init__(self, method_desc): # pragma: no cover PyPy
self.desc = method_desc
-if _c_available:
+
+if _c_available: # pragma: no cover
# Python API: not used in this module
from zope.proxy._zope_proxy_proxy import ProxyBase
from zope.proxy._zope_proxy_proxy import getProxiedObject
@@ -535,9 +554,9 @@ if _c_available:
from zope.proxy._zope_proxy_proxy import removeAllProxies
# API for proxy-using C extensions.
- from zope.proxy._zope_proxy_proxy import _CAPI
+ from zope.proxy._zope_proxy_proxy import _CAPI # noqa: F401 unused
-else: # pragma: no cover
+else:
# no C extension available, fall back
ProxyBase = PyProxyBase
getProxiedObject = py_getProxiedObject
@@ -548,5 +567,6 @@ else: # pragma: no cover
queryInnerProxy = py_queryInnerProxy
removeAllProxies = py_removeAllProxies
+
def non_overridable(func):
return property(lambda self: func.__get__(self))
diff --git a/src/zope/proxy/decorator.py b/src/zope/proxy/decorator.py
index 9f2084f..9a53dfb 100644
--- a/src/zope/proxy/decorator.py
+++ b/src/zope/proxy/decorator.py
@@ -24,9 +24,11 @@ from zope.interface.declarations import getObjectSpecification
from zope.interface.declarations import ObjectSpecification
from zope.interface import providedBy
+
class DecoratorSpecificationDescriptor(ObjectSpecificationDescriptor):
"""Support for interface declarations on decorators
"""
+
def __get__(self, inst, cls=None):
if inst is None:
return getObjectSpecification(cls)
@@ -46,4 +48,3 @@ class SpecificationDecoratorBase(ProxyBase):
"""Base class for a proxy that provides additional interfaces."""
__providedBy__ = DecoratorSpecificationDescriptor()
-
diff --git a/src/zope/proxy/interfaces.py b/src/zope/proxy/interfaces.py
index 71f113d..50a0547 100644
--- a/src/zope/proxy/interfaces.py
+++ b/src/zope/proxy/interfaces.py
@@ -16,6 +16,7 @@
from zope.interface import Interface
+
class IProxyIntrospection(Interface):
"""Provides methods for indentifying proxies and extracting proxied objects
"""
diff --git a/src/zope/proxy/tests/test_decorator.py b/src/zope/proxy/tests/test_decorator.py
index 4003377..a2a27ee 100644
--- a/src/zope/proxy/tests/test_decorator.py
+++ b/src/zope/proxy/tests/test_decorator.py
@@ -29,10 +29,13 @@ class DecoratorSpecificationDescriptorTests(unittest.TestCase):
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(object):
@@ -44,10 +47,13 @@ class DecoratorSpecificationDescriptorTests(unittest.TestCase):
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(object):
@@ -60,10 +66,13 @@ class DecoratorSpecificationDescriptorTests(unittest.TestCase):
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(object):
@@ -78,18 +87,24 @@ class DecoratorSpecificationDescriptorTests(unittest.TestCase):
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(object):
pass
+
class IProxyFactory(Interface):
pass
+
class IProxy(Interface):
pass
+
@provider(IProxyFactory)
@implementer(IProxy)
class Proxy(ProxyBase):
@@ -103,8 +118,10 @@ class DecoratorSpecificationDescriptorTests(unittest.TestCase):
def test___set___not_allowed(self):
from zope.interface import Interface
from zope.interface import implementer
+
class IFoo(Interface):
pass
+
@implementer(IFoo)
class Foo(object):
pass
@@ -126,8 +143,10 @@ class SpecificationDecoratorBaseTests(unittest.TestCase):
from zope.interface import Interface
from zope.interface import implementer
from zope.interface import providedBy
+
class IFoo(Interface):
pass
+
@implementer(IFoo)
class Foo(object):
pass
@@ -141,14 +160,17 @@ class SpecificationDecoratorBaseTests(unittest.TestCase):
from zope.interface import Interface
from zope.interface import implementer
from zope.interface import providedBy
+
class IFoo(Interface):
pass
+
@implementer(IFoo)
class Foo(object):
from_foo = 1
class IWrapper(Interface):
pass
+
@implementer(IWrapper)
class Proxy(self._getTargetClass()):
pass
@@ -157,7 +179,7 @@ class SpecificationDecoratorBaseTests(unittest.TestCase):
proxy = Proxy(foo)
self.assertEqual(proxy.from_foo, 1)
- self.assertEqual(list(providedBy(proxy)), [IFoo,IWrapper])
+ self.assertEqual(list(providedBy(proxy)), [IFoo, IWrapper])
def test_suite():
diff --git a/src/zope/proxy/tests/test_proxy.py b/src/zope/proxy/tests/test_proxy.py
index c96492d..5d7124c 100644
--- a/src/zope/proxy/tests/test_proxy.py
+++ b/src/zope/proxy/tests/test_proxy.py
@@ -17,13 +17,15 @@ import unittest
try:
import zope.security
-except ImportError: # pragma: no cover
+except ImportError: # pragma: no cover
_HAVE_ZOPE_SECURITY = False
else:
_HAVE_ZOPE_SECURITY = True
+ del zope.security
from zope.proxy._compat import PY3
+
class ModuleConformanceCase(unittest.TestCase):
def test_module_conforms_to_IProxyIntrospection(self):
@@ -39,6 +41,10 @@ class PyProxyBaseTestCase(unittest.TestCase):
getslice = '__getitem__' if PY3 else '__getslice__'
setslice = '__setitem__' if PY3 else '__setslice__'
+ # Avoid DeprecationWarning for assertRaisesRegexp on Python 3 while
+ # coping with Python 2 not having the Regex spelling variant
+ assertRaisesRegex = getattr(unittest.TestCase, 'assertRaisesRegex',
+ unittest.TestCase.assertRaisesRegexp)
def _getTargetClass(self):
from zope.proxy import PyProxyBase
@@ -57,6 +63,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
class MyProxy(self._getTargetClass()):
def __new__(cls, *args, **kwds):
return super(MyProxy, cls).__new__(cls, *args, **kwds)
+
def __init__(self, *args, **kwds):
super(MyProxy, self).__init__(*args, **kwds)
o1 = object()
@@ -115,30 +122,30 @@ class PyProxyBaseTestCase(unittest.TestCase):
self.assertEqual(42.0, float(proxy))
@unittest.skipIf(PY3, "Gone in Py3")
- def test___unicode__of_unicode(self):
+ def test___unicode__of_unicode(self): # pragma: no cover PY2
s = u'Hello, \u2603'
proxy = self._makeOne(s)
- self.assertEqual(unicode(proxy), s)
+ self.assertEqual(unicode(proxy), s) # noqa: F821 undef
@unittest.skipIf(PY3, "Gone in Py3")
- def test___unicode__of_custom_class(self):
+ def test___unicode__of_custom_class(self): # pragma: no cover PY2
class CustomClass(object):
def __unicode__(self):
return u'Hello, \u2603'
cc = CustomClass()
- self.assertEqual(unicode(cc), u'Hello, \u2603')
+ self.assertEqual(unicode(cc), u'Hello, \u2603') # noqa: F821 undef
proxy = self._makeOne(cc)
- self.assertEqual(unicode(proxy), u'Hello, \u2603')
+ self.assertEqual(unicode(proxy), u'Hello, \u2603') # noqa: F821 undef
@unittest.skipIf(PY3, "Gone in Py3")
- def test___unicode__of_custom_class_no_unicode(self):
+ def test___unicode__of_custom_class_no_unicode(self): # pragma: no cover
class CustomClass(object):
pass
cc = CustomClass()
- cc_unicode = unicode(cc)
- self.assertEqual(type(cc_unicode), unicode)
+ cc_unicode = unicode(cc) # noqa: F821 undef
+ self.assertEqual(type(cc_unicode), unicode) # noqa: F821 undef
proxy = self._makeOne(cc)
- self.assertEqual(unicode(proxy), cc_unicode)
+ self.assertEqual(unicode(proxy), cc_unicode) # noqa: F821 undef
def test___call__(self):
def _foo():
@@ -147,7 +154,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
self.assertEqual(proxy(), 'FOO')
@unittest.skipIf(PY3, "Gone in Py3")
- def test_callable(self):
+ def test_callable(self): # pragma: no cover PY2
w = self._makeOne({}.get)
self.assertTrue(callable(w))
@@ -164,14 +171,15 @@ class PyProxyBaseTestCase(unittest.TestCase):
self.assertEqual(str(proxy), str(_foo))
@unittest.skipIf(PY3, "Gone in Py3")
- def test___unicode__(self):
+ def test___unicode__(self): # pragma: no cover PY2
def _foo():
raise AssertionError("Not called")
proxy = self._makeOne(_foo)
- self.assertTrue(unicode(proxy).startswith('<function _foo'))
+ self.assertTrue(
+ unicode(proxy).startswith('<function _foo')) # noqa: F821 undef
@unittest.skipIf(PY3, "No old-style classes in Python 3")
- def test___reduce___via_pickling(self):
+ def test___reduce___via_pickling(self): # pragma: no cover PY2
import pickle
# Proxies of old-style classes can't be pickled.
@@ -246,6 +254,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
pass
o = Foo()
w = self._makeOne(o)
+
def _try():
return w.nonesuch
self.assertRaises(AttributeError, _try)
@@ -262,6 +271,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
class Proxy(self._getTargetClass()):
def foo(self):
raise AssertionError("Not called")
+
class Foo(object):
def foo(self):
return 'FOO'
@@ -282,7 +292,8 @@ class PyProxyBaseTestCase(unittest.TestCase):
bar = property(
lambda s: s.__dict__.get('_bar'),
lambda s, v: s.__dict__.__setitem__('_bar', v)
- )
+ )
+
class Foo(object):
pass
o = Foo()
@@ -297,6 +308,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
o = Foo()
o.foo = 1
w = self._makeOne(o)
+
def _try():
del w._wrapped
self.assertRaises(AttributeError, _try)
@@ -311,10 +323,10 @@ class PyProxyBaseTestCase(unittest.TestCase):
self.assertFalse('foo' in o.__dict__)
def test___len__(self):
- l = []
- w = self._makeOne(l)
+ l_ = []
+ w = self._makeOne(l_)
self.assertEqual(len(w), 0)
- l.append(0)
+ l_.append(0)
self.assertEqual(len(w), 1)
def test___getitem_____setitem_____delitem__(self):
@@ -324,6 +336,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
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)
@@ -344,8 +357,9 @@ class PyProxyBaseTestCase(unittest.TestCase):
def test___getitem__w_slice_against_derived_list(self):
data = [1, 2]
+
class DerivedList(list):
- def __getslice__(self, start, stop):
+ def __getslice__(self, start, stop): # pragma: no cover PY2
return list.__getslice__(self, start, stop)
pList = self._makeOne(DerivedList(data))
@@ -357,21 +371,23 @@ class PyProxyBaseTestCase(unittest.TestCase):
def test___getitem__w_slice_against_class_w_custom___getslice__(self):
import sys
test = self
+
class Slicer(object):
def __len__(self):
return 2
- def __getslice__(self, start, end):
+ def __getslice__(self, start, end): # pragma: no cover PY2
return (start, end)
- def __getitem__(self, a_slice): # pragma: no cover
+ def __getitem__(self, a_slice):
test.assertTrue(PY3)
# 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)
+ 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)
@@ -385,34 +401,36 @@ class PyProxyBaseTestCase(unittest.TestCase):
def test___getslice___dne_uses_getitem(self):
class Missing(Exception):
pass
+
class Get(object):
def __getitem__(self, x):
raise Missing('__getitem__')
target = Get()
proxy = self._makeOne(target)
- with self.assertRaisesRegexp(Missing,
- '__getitem__'):
+ with self.assertRaisesRegex(Missing, '__getitem__'):
proxy[1:2]
def test___getslice___error_propagates(self):
test = self
+
class Missing(Exception):
pass
+
class Get(object):
- def __getitem__(self, x): # pragma: no cover (only py3)
+ def __getitem__(self, x):
test.assertTrue(PY3)
raise Missing('__getitem__')
- def __getslice__(self, start, stop):
+
+ def __getslice__(self, start, stop): # pragma: no cover PY2
raise Missing("__getslice__")
target = Get()
proxy = self._makeOne(target)
- with self.assertRaisesRegexp(Missing,
- self.getslice):
+ with self.assertRaisesRegex(Missing, self.getslice):
proxy[1:2]
def test___setslice___against_list(self):
- # Lists have special slicing bahvior for assignment as well.
+ # Lists have special slicing behavior for assignment as well.
pList = self._makeOne([1, 2])
pList[-1:] = [3, 4]
self.assertEqual(pList, [1, 3, 4])
@@ -441,31 +459,31 @@ class PyProxyBaseTestCase(unittest.TestCase):
def test___setslice___error_propagates(self):
class Missing(Exception):
pass
+
class Set(object):
def __setitem__(self, k, v):
- raise Missing('__setitem__') # pragma: no cover (only py3)
- def __setslice__(self, start, stop, value):
+ raise Missing('__setitem__')
+
+ def __setslice__(self, start, stop, value): # pragma: no cover PY2
raise Missing("__setslice__")
target = Set()
proxy = self._makeOne(target)
- with self.assertRaisesRegexp(Missing,
- self.setslice):
+ with self.assertRaisesRegex(Missing, self.setslice):
proxy[1:2] = 1
def test___setslice___dne_uses_setitem(self):
class Missing(Exception):
pass
+
class Set(object):
def __setitem__(self, k, v):
raise Missing('__setitem__')
target = Set()
proxy = self._makeOne(target)
- with self.assertRaisesRegexp(Missing,
- '__setitem__'):
+ with self.assertRaisesRegex(Missing, '__setitem__'):
proxy[1:2] = 1
-
def test___iter___w_wrapped_iterable(self):
a = [1, 2, 3]
b = []
@@ -489,6 +507,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
class MyIter(object):
def __iter__(self):
return self
+
def __next__(self):
raise AssertionError("Not called")
next = __next__
@@ -506,6 +525,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
def __init__(self, test, data):
self.test = test
self.data = data
+
def __iter__(self):
return self.test._makeOne(iter(self.data))
@@ -516,7 +536,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
self.assertEqual(a, b)
# Python 2.7 won't let the C wrapper support __reversed__ :(
- #def test___reversed__(self):
+ # def test___reversed__(self):
# w = self._makeOne([0, 1, 2, 3])
# self.assertEqual(list(reversed(w)), [3, 2, 1, 0])
@@ -543,8 +563,8 @@ class PyProxyBaseTestCase(unittest.TestCase):
"float(x)",
"complex(x)",
]
- if not PY3: # long is gone in Python 3
- ops.append("long(x)")
+ if not PY3: # long is gone in Python 3
+ ops.append("long(x)") # pragma: no cover PY2
return ops
def test_unops(self):
@@ -560,15 +580,15 @@ class PyProxyBaseTestCase(unittest.TestCase):
# unops that don't return a proxy
funcs = (lambda x: not x,)
if not PY3:
- funcs += (oct, hex)
+ funcs += (oct, hex) # pragma: no cover PY2
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", # "pow(x,y,3)" (RHS coercion not supported w/ modulus)
"x<<y", "x>>y", "x&y", "x|y", "x^y",
- ]
+ ]
def test_binops(self):
for expr in self.binops:
@@ -631,72 +651,72 @@ class PyProxyBaseTestCase(unittest.TestCase):
self.assertEqual(pa, 20)
@unittest.skipIf(PY3, "No coercion in Py3")
- def test_coerce(self):
+ def test_coerce(self): # pragma: no cover PY2
# Before 2.3, coerce() of two proxies returns them unchanged
x = self._makeOne(1)
y = self._makeOne(2)
- a, b = coerce(x, y)
+ a, b = coerce(x, y) # noqa: F821 undefined name
self.assertTrue(a is x and b is y)
x = self._makeOne(1)
y = self._makeOne(2.1)
- a, b = coerce(x, y)
- self.assertTrue(isinstance(a, float)) # a was coerced
+ a, b = coerce(x, y) # noqa: F821 undefined name
+ self.assertTrue(isinstance(a, float)) # a was coerced
self.assertFalse(a is x)
self.assertEqual(a, float(x))
self.assertTrue(b is y)
x = self._makeOne(1.1)
y = self._makeOne(2)
- a, b = coerce(x, y)
+ a, b = coerce(x, y) # noqa: F821 undefined name
self.assertTrue(a is x)
- self.assertTrue(isinstance(b, float)) # b was coerced
+ self.assertTrue(isinstance(b, float)) # b was coerced
self.assertFalse(b is y)
self.assertEqual(b, float(y))
x = self._makeOne(1)
y = 2
- a, b = coerce(x, y)
- self.assertTrue(a is x) # neither was coerced
+ a, b = coerce(x, y) # noqa: F821 undefined name
+ self.assertTrue(a is x) # neither was coerced
self.assertTrue(b is y)
x = self._makeOne(1)
y = 2.1
- a, b = coerce(x, y)
- self.assertTrue(isinstance(a, float)) # a was coerced
+ a, b = coerce(x, y) # noqa: F821 undefined name
+ self.assertTrue(isinstance(a, float)) # a was coerced
self.assertFalse(a is x)
self.assertEqual(a, float(x))
self.assertTrue(b is y)
x = self._makeOne(1.1)
y = 2
- a, b = coerce(x, y)
+ a, b = coerce(x, y) # noqa: F821 undefined name
self.assertTrue(a is x)
- self.assertTrue(isinstance(b, float)) # b was coerced
+ self.assertTrue(isinstance(b, float)) # b was coerced
self.assertFalse(b is y)
- self.assertEqual(b,float(y))
+ self.assertEqual(b, float(y))
x = 1
y = self._makeOne(2)
- a, b = coerce(x, y)
- self.assertTrue(a is x) # neither was coerced
+ a, b = coerce(x, y) # noqa: F821 undefined name
+ self.assertTrue(a is x) # neither was coerced
self.assertTrue(b is y)
x = 1.1
y = self._makeOne(2)
- a, b = coerce(x, y)
+ a, b = coerce(x, y) # noqa: F821 undefined name
self.assertTrue(a is x)
- self.assertTrue(isinstance(b, float)) # b was coerced
+ self.assertTrue(isinstance(b, float)) # b was coerced
self.assertFalse(b is y)
- self.assertEqual(b, float(y))
+ self.assertEqual(b, float(y))
x = 1
y = self._makeOne(2.1)
- a, b = coerce(x, y)
- self.assertTrue(isinstance(a, float)) # a was coerced
+ a, b = coerce(x, y) # noqa: F821 undefined name
+ self.assertTrue(isinstance(a, float)) # a was coerced
self.assertFalse(a is x)
- self.assertEqual(a, float(x))
+ self.assertEqual(a, float(x))
self.assertTrue(b is y)
def test___class__(self):
@@ -709,11 +729,13 @@ class PyProxyBaseTestCase(unittest.TestCase):
class Descriptor(object):
value = None
instance = None
+
def __set__(self, instance, value):
self.value = value
self.instance = instance
descriptor = Descriptor()
+
class Proxy(self._getTargetClass()):
attr = descriptor
@@ -741,6 +763,7 @@ class PyProxyBaseTestCase(unittest.TestCase):
descriptor = Descriptor()
descriptor.value = "descriptor value"
+
class Proxy(self._getTargetClass()):
attr = descriptor
@@ -765,14 +788,14 @@ class PyProxyBaseTestCase(unittest.TestCase):
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):
+ 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
- from zope.interface import implementedBy
# Set up the builtin interface
class IFoo(Interface):
@@ -794,31 +817,37 @@ class PyProxyBaseTestCase(unittest.TestCase):
self.assertTrue(IFoo in list(provided_instance))
proxy_type = proxy_class(builtin_type)
- from zope.interface.declarations import BuiltinImplementationSpecifications
+ from zope.interface.declarations import \
+ BuiltinImplementationSpecifications
self.assertIn(proxy_type, BuiltinImplementationSpecifications)
- self.assertIsNot(BuiltinImplementationSpecifications.get(proxy_type, self),
- self)
+ 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)
+ self._check_wrapping_builtin_returns_correct_provided_by(
+ self._getTargetClass(), list)
- def _check_wrapping_builtin_with_subclass_returns_correct_provided_by(self, builtin_type):
+ 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)
+ 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
+ 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)
+ self._check_wrapping_builtin_with_subclass_returns_correct_provided_by(
+ list)
def test_method_in_proxy_subclass(self):
class Proxy(self._getTargetClass()):
@@ -836,19 +865,22 @@ class PyProxyBaseTestCase(unittest.TestCase):
proxy = self._makeOne("14")
self.assertEqual(14, int(proxy))
+
class ProxyBaseTestCase(PyProxyBaseTestCase):
def _getTargetClass(self):
from zope.proxy import ProxyBase
return ProxyBase
+
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,
+ # 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
+ # 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):
@@ -856,7 +888,6 @@ class Test_py__module(unittest.TestCase):
return PyProxyBase
def _makeProxy(self, obj):
- from zope.proxy import PyProxyBase
return self._getTargetClass()(obj)
def _check_module(self, obj, expected):
@@ -892,6 +923,7 @@ class Test_py__module(unittest.TestCase):
class Module(object):
def __init__(self):
self.__module__ = __name__
+
def __eq__(self, other):
return self.__module__ == other.__module__
@@ -904,23 +936,28 @@ class Test_py__module(unittest.TestCase):
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()):
+ 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()):
+ class ProxySubclass(
+ super(Test_subclass__module, self)._getTargetClass()):
pass
return ProxySubclass
@@ -956,6 +993,7 @@ class Test_py_getProxiedObject(unittest.TestCase):
proxy2 = self._makeProxy(proxy)
self.assertTrue(self._callFUT(proxy2) is proxy)
+
class Test_getProxiedObject(Test_py_getProxiedObject):
def _callFUT(self, *args):
@@ -1041,6 +1079,7 @@ class Test_py_isProxy(unittest.TestCase):
def test_proxy_no_class(self):
class P1(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1050,6 +1089,7 @@ class Test_py_isProxy(unittest.TestCase):
def test_proxy_w_same_class(self):
class P1(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1059,8 +1099,10 @@ class Test_py_isProxy(unittest.TestCase):
def test_proxy_w_other_class(self):
class P1(self._proxyClass()):
pass
+
class P2(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1126,6 +1168,7 @@ class Test_py_sameProxiedObjects(unittest.TestCase):
def test_proxies_w_same_bare(self):
_mP = self._makeProxy
+
class C(object):
pass
c1 = C()
@@ -1133,6 +1176,7 @@ class Test_py_sameProxiedObjects(unittest.TestCase):
def test_proxies_w_other_bare(self):
_mP = self._makeProxy
+
class C(object):
pass
c1 = C()
@@ -1142,6 +1186,7 @@ class Test_py_sameProxiedObjects(unittest.TestCase):
def test_nested_proxy_and_same_bare(self):
_mP = self._makeProxy
+
class C(object):
pass
c1 = C()
@@ -1150,6 +1195,7 @@ class Test_py_sameProxiedObjects(unittest.TestCase):
def test_nested_proxy_and_other_bare(self):
_mP = self._makeProxy
+
class C(object):
pass
c1 = C()
@@ -1172,6 +1218,7 @@ class Test_py_sameProxiedObjects(unittest.TestCase):
proxy2 = self._makeSecurityProxy(c2)
self.assertFalse(self._callFUT(proxy1, proxy2))
+
class Test_sameProxiedObjects(Test_py_sameProxiedObjects):
def _callFUT(self, *args):
@@ -1188,6 +1235,7 @@ class Test_sameProxiedObjects(Test_py_sameProxiedObjects):
checker = Checker({})
return Proxy(obj, checker)
+
class Test_py_queryProxy(unittest.TestCase):
def _callFUT(self, *args):
@@ -1207,6 +1255,7 @@ class Test_py_queryProxy(unittest.TestCase):
def test_proxy_no_class(self):
class P1(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1216,6 +1265,7 @@ class Test_py_queryProxy(unittest.TestCase):
def test_proxy_w_same_class(self):
class P1(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1226,8 +1276,10 @@ class Test_py_queryProxy(unittest.TestCase):
def test_proxy_w_other_class(self):
class P1(self._proxyClass()):
pass
+
class P2(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1238,8 +1290,10 @@ class Test_py_queryProxy(unittest.TestCase):
def test_proxy_w_base_class(self):
class P1(self._proxyClass()):
pass
+
class P2(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1278,6 +1332,7 @@ class Test_py_queryInnerProxy(unittest.TestCase):
def test_proxy_no_class(self):
class P1(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1287,6 +1342,7 @@ class Test_py_queryInnerProxy(unittest.TestCase):
def test_proxy_w_same_class(self):
class P1(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1297,8 +1353,10 @@ class Test_py_queryInnerProxy(unittest.TestCase):
def test_nested_proxy(self):
class P1(self._proxyClass()):
pass
+
class P2(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1312,8 +1370,10 @@ class Test_py_queryInnerProxy(unittest.TestCase):
def test_re_nested_proxy(self):
class P1(self._proxyClass()):
pass
+
class P2(self._proxyClass()):
pass
+
class C(object):
pass
c = C()
@@ -1381,6 +1441,7 @@ class Test_py_removeAllProxies(unittest.TestCase):
proxy = self._makeSecurityProxy(c)
self.assertIs(self._callFUT(proxy), c)
+
class Test_removeAllProxies(Test_py_removeAllProxies):
def _callFUT(self, *args):
@@ -1396,6 +1457,7 @@ class Test_removeAllProxies(Test_py_removeAllProxies):
checker = object()
return Proxy(obj, checker)
+
class Test_ProxyIterator(unittest.TestCase):
def _callFUT(self, *args):
@@ -1410,6 +1472,7 @@ class Test_ProxyIterator(unittest.TestCase):
def test_w_simple_proxy(self):
from zope.proxy import ProxyBase
+
class C(object):
pass
c = C()
@@ -1418,6 +1481,7 @@ class Test_ProxyIterator(unittest.TestCase):
def test_w_nested_proxies(self):
from zope.proxy import ProxyBase
+
class C(object):
pass
c = C()
@@ -1434,15 +1498,19 @@ 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(object):
def who(self):
return 'FOO'
+
def what(self):
return 'FOO'
p0 = ProxyBase(Foo())
@@ -1457,6 +1525,7 @@ class TestEmptyInterfaceDescriptor(unittest.TestCase):
def _makeOne(self):
from zope.proxy import _EmptyInterfaceDescriptor
+
class It(object):
feature = _EmptyInterfaceDescriptor()
return It()
@@ -1500,7 +1569,7 @@ class Comparable(object):
def __gt__(self, other):
return not self.__le__(other)
- def __repr__(self): # pragma: no cover
+ def __repr__(self): # pragma: no cover
return "<Comparable: %r>" % self.value
diff --git a/tox.ini b/tox.ini
index 682954e..e01039b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,43 +1,67 @@
+# Generated from:
+# https://github.com/zopefoundation/meta/tree/master/config/c-code
[tox]
+minversion = 3.18
envlist =
- py27,py27-pure,py35,py36,py36-pure,py37,py38,pypy,coverage,docs
+ lint
+ py27,py27-pure
+ py35,py35-pure
+ py36,py36-pure
+ py37,py37-pure
+ py38,py38-pure
+ py39,py39-pure
+ pypy
+ pypy3
+ docs
+ coverage
[testenv]
+usedevelop = true
deps =
- .[test,docs]
+ # Until repoze.sphinx.autointerface supports Sphinx 4.x we cannot use it:
+ Sphinx < 4
+setenv =
+ pure: PURE_PYTHON=1
+ !pure-!pypy-!pypy3: PURE_PYTHON=0
commands =
- zope-testrunner --test-path=src
- sphinx-build -b doctest -d {envdir}/doctrees docs {envdir}/doctest
+ zope-testrunner --test-path=src {posargs:-vc}
+ !py27-!pypy: sphinx-build -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest
+extras =
+ test
+ docs
[testenv:coverage]
-usedevelop = true
-basepython =
- python2.7
-commands =
- coverage run -m zope.testrunner --test-path=src []
- coverage run -a -m sphinx -b doctest -d {envdir}/.cache/doctrees docs {envdir}/.cache/doctest
- coverage report --fail-under=100
+basepython = python3
+allowlist_externals =
+ mkdir
deps =
- {[testenv]deps}
coverage
+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
+deps =
+ flake8
+ check-manifest
+ check-python-versions
+commands =
+ flake8 src setup.py
+ check-manifest
+ check-python-versions
[testenv:docs]
-basepython =
- python2.7
+basepython = python3
+skip_install = false
+# Until repoze.sphinx.autointerface supports Sphinx 4.x we cannot use it:
+deps = Sphinx < 4
+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
-deps =
- .[test,docs]
-
-[testenv:py27-pure]
-basepython =
- python2.7
-setenv =
- PURE_PYTHON = 1
-
-[testenv:py36-pure]
-basepython =
- python3.6
-setenv =
- PURE_PYTHON = 1