Import Upstream version 1.7.1

This commit is contained in:
su-fang 2022-11-14 17:04:46 +08:00
commit b5d35b32b7
43 changed files with 7807 additions and 0 deletions

24
.bumpversion.cfg Normal file
View File

@ -0,0 +1,24 @@
[bumpversion]
current_version = 1.7.1
commit = True
tag = True
[bumpversion:file:setup.py]
search = 'fallback_version': '{current_version}'
replace = 'fallback_version': '{new_version}'
[bumpversion:file (badge):README.rst]
search = /v{current_version}.svg
replace = /v{new_version}.svg
[bumpversion:file (link):README.rst]
search = /v{current_version}...master
replace = /v{new_version}...master
[bumpversion:file:docs/conf.py]
search = version = release = '{current_version}'
replace = version = release = '{new_version}'
[bumpversion:file:src/lazy_object_proxy/__init__.py]
search = __version__ = '{current_version}'
replace = __version__ = '{new_version}'

55
.cookiecutterrc Normal file
View File

@ -0,0 +1,55 @@
# Generated by cookiepatcher, a small shim around cookiecutter (pip install cookiepatcher)
default_context:
allow_tests_inside_package: no
appveyor: no
c_extension_function: '-'
c_extension_module: '-'
c_extension_optional: yes
c_extension_support: yes
c_extension_test_pypi: yes
c_extension_test_pypi_username: ionel
codacy: no
codacy_projectid: 862e7946eabb4112be6503a667381b71
codeclimate: no
codecov: yes
command_line_interface: no
command_line_interface_bin_name: '-'
coveralls: yes
distribution_name: lazy-object-proxy
email: contact@ionelmc.ro
full_name: Ionel Cristian Mărieș
github_actions: yes
legacy_python: no
license: BSD 2-Clause License
linter: flake8
package_name: lazy_object_proxy
pre_commit: yes
project_name: lazy-object-proxy
project_short_description: A fast and thorough lazy object proxy.
pypi_badge: yes
pypi_disable_upload: no
release_date: '2021-03-22'
repo_hosting: github.com
repo_hosting_domain: github.com
repo_main_branch: master
repo_name: python-lazy-object-proxy
repo_username: ionelmc
requiresio: yes
scrutinizer: no
setup_py_uses_setuptools_scm: yes
setup_py_uses_test_runner: no
sphinx_docs: yes
sphinx_docs_hosting: https://python-lazy-object-proxy.readthedocs.io/
sphinx_doctest: no
sphinx_theme: sphinx-py3doc-enhanced-theme
test_matrix_configurator: no
test_matrix_separate_coverage: yes
test_runner: pytest
travis: no
travis_osx: no
version: 1.6.0
version_manager: bump2version
website: https://blog.ionelmc.ro
year_from: '2014'
year_to: '2021'

14
.coveragerc Normal file
View File

@ -0,0 +1,14 @@
[paths]
source = src
[run]
branch = true
source =
src
tests
parallel = true
[report]
show_missing = true
precision = 2
omit = *migrations*

20
.editorconfig Normal file
View File

@ -0,0 +1,20 @@
# see https://editorconfig.org/
root = true
[*]
# Use Unix-style newlines for most files (except Windows files, see below).
end_of_line = lf
trim_trailing_whitespace = true
indent_style = space
insert_final_newline = true
indent_size = 4
charset = utf-8
[*.{bat,cmd,ps1}]
end_of_line = crlf
[*.{yml,yaml}]
indent_size = 2
[*.tsv]
indent_style = tab

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
tidelift: "pypi/lazy-object-proxy"

573
.github/workflows/github-actions.yml vendored Normal file
View File

@ -0,0 +1,573 @@
name: build
on: [push, pull_request]
jobs:
test:
name: ${{ matrix.name }}
runs-on: ${{ matrix.os }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- name: 'check'
python: '3.9'
toxpython: 'python3.9'
tox_env: 'check'
os: 'ubuntu-latest'
- name: 'docs'
python: '3.9'
toxpython: 'python3.9'
tox_env: 'docs'
os: 'ubuntu-latest'
- name: 'py36-cover (ubuntu/x86_64)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x64'
tox_env: 'py36-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'ubuntu-latest'
- name: 'py36-cover (windows/AMD64)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x64'
tox_env: 'py36-cover,codecov'
cibw_arch: 'AMD64'
cibw_build: false
os: 'windows-latest'
- name: 'py36-cover (macos/x86_64)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x64'
tox_env: 'py36-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'macos-latest'
- name: 'py36-nocov (ubuntu/x86_64/manylinux)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x64'
tox_env: 'py36-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp36-*manylinux*'
os: 'ubuntu-latest'
- name: 'py36-nocov (ubuntu/x86_64/musllinux)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x64'
tox_env: 'py36-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp36-*musllinux*'
os: 'ubuntu-latest'
- name: 'py36-nocov (ubuntu/aarch64/manylinux)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x64'
tox_env: 'py36-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp36-*manylinux*'
os: 'ubuntu-latest'
- name: 'py36-nocov (ubuntu/aarch64/musllinux)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x64'
tox_env: 'py36-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp36-*musllinux*'
os: 'ubuntu-latest'
- name: 'py36-nocov (windows/AMD64)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x64'
tox_env: 'py36-nocov'
cibw_arch: 'AMD64'
cibw_build: 'cp36-*'
os: 'windows-latest'
- name: 'py36-nocov (windows/x86)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x86'
tox_env: 'py36-nocov'
cibw_arch: 'x86'
cibw_build: 'cp36-*'
os: 'windows-latest'
- name: 'py36-nocov (macos/x86_64)'
python: '3.6'
toxpython: 'python3.6'
python_arch: 'x64'
tox_env: 'py36-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp36-*'
os: 'macos-latest'
- name: 'py37-cover (ubuntu/x86_64)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x64'
tox_env: 'py37-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'ubuntu-latest'
- name: 'py37-cover (windows/AMD64)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x64'
tox_env: 'py37-cover,codecov'
cibw_arch: 'AMD64'
cibw_build: false
os: 'windows-latest'
- name: 'py37-cover (macos/x86_64)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x64'
tox_env: 'py37-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'macos-latest'
- name: 'py37-nocov (ubuntu/x86_64/manylinux)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x64'
tox_env: 'py37-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp37-*manylinux*'
os: 'ubuntu-latest'
- name: 'py37-nocov (ubuntu/x86_64/musllinux)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x64'
tox_env: 'py37-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp37-*musllinux*'
os: 'ubuntu-latest'
- name: 'py37-nocov (ubuntu/aarch64/manylinux)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x64'
tox_env: 'py37-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp37-*manylinux*'
os: 'ubuntu-latest'
- name: 'py37-nocov (ubuntu/aarch64/musllinux)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x64'
tox_env: 'py37-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp37-*musllinux*'
os: 'ubuntu-latest'
- name: 'py37-nocov (windows/AMD64)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x64'
tox_env: 'py37-nocov'
cibw_arch: 'AMD64'
cibw_build: 'cp37-*'
os: 'windows-latest'
- name: 'py37-nocov (windows/x86)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x86'
tox_env: 'py37-nocov'
cibw_arch: 'x86'
cibw_build: 'cp37-*'
os: 'windows-latest'
- name: 'py37-nocov (macos/x86_64)'
python: '3.7'
toxpython: 'python3.7'
python_arch: 'x64'
tox_env: 'py37-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp37-*'
os: 'macos-latest'
- name: 'py38-cover (ubuntu/x86_64)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x64'
tox_env: 'py38-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'ubuntu-latest'
- name: 'py38-cover (windows/AMD64)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x64'
tox_env: 'py38-cover,codecov'
cibw_arch: 'AMD64'
cibw_build: false
os: 'windows-latest'
- name: 'py38-cover (macos/x86_64)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x64'
tox_env: 'py38-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'macos-latest'
- name: 'py38-nocov (ubuntu/x86_64/manylinux)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x64'
tox_env: 'py38-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp38-*manylinux*'
os: 'ubuntu-latest'
- name: 'py38-nocov (ubuntu/x86_64/musllinux)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x64'
tox_env: 'py38-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp38-*musllinux*'
os: 'ubuntu-latest'
- name: 'py38-nocov (ubuntu/aarch64/manylinux)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x64'
tox_env: 'py38-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp38-*manylinux*'
os: 'ubuntu-latest'
- name: 'py38-nocov (ubuntu/aarch64/musllinux)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x64'
tox_env: 'py38-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp38-*musllinux*'
os: 'ubuntu-latest'
- name: 'py38-nocov (windows/AMD64)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x64'
tox_env: 'py38-nocov'
cibw_arch: 'AMD64'
cibw_build: 'cp38-*'
os: 'windows-latest'
- name: 'py38-nocov (windows/x86)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x86'
tox_env: 'py38-nocov'
cibw_arch: 'x86'
cibw_build: 'cp38-*'
os: 'windows-latest'
- name: 'py38-nocov (macos/x86_64)'
python: '3.8'
toxpython: 'python3.8'
python_arch: 'x64'
tox_env: 'py38-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp38-*'
os: 'macos-latest'
- name: 'py39-cover (ubuntu/x86_64)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x64'
tox_env: 'py39-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'ubuntu-latest'
- name: 'py39-cover (windows/AMD64)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x64'
tox_env: 'py39-cover,codecov'
cibw_arch: 'AMD64'
cibw_build: false
os: 'windows-latest'
- name: 'py39-cover (macos/x86_64)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x64'
tox_env: 'py39-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'macos-latest'
- name: 'py39-nocov (ubuntu/x86_64/manylinux)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x64'
tox_env: 'py39-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp39-*manylinux*'
os: 'ubuntu-latest'
- name: 'py39-nocov (ubuntu/x86_64/musllinux)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x64'
tox_env: 'py39-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp39-*musllinux*'
os: 'ubuntu-latest'
- name: 'py39-nocov (ubuntu/aarch64/manylinux)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x64'
tox_env: 'py39-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp39-*manylinux*'
os: 'ubuntu-latest'
- name: 'py39-nocov (ubuntu/aarch64/musllinux)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x64'
tox_env: 'py39-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp39-*musllinux*'
os: 'ubuntu-latest'
- name: 'py39-nocov (windows/AMD64)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x64'
tox_env: 'py39-nocov'
cibw_arch: 'AMD64'
cibw_build: 'cp39-*'
os: 'windows-latest'
- name: 'py39-nocov (windows/x86)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x86'
tox_env: 'py39-nocov'
cibw_arch: 'x86'
cibw_build: 'cp39-*'
os: 'windows-latest'
- name: 'py39-nocov (macos/x86_64)'
python: '3.9'
toxpython: 'python3.9'
python_arch: 'x64'
tox_env: 'py39-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp39-*'
os: 'macos-latest'
- name: 'py310-cover (ubuntu/x86_64)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x64'
tox_env: 'py310-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'ubuntu-latest'
- name: 'py310-cover (windows/AMD64)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x64'
tox_env: 'py310-cover,codecov'
cibw_arch: 'AMD64'
cibw_build: false
os: 'windows-latest'
- name: 'py310-cover (macos/x86_64)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x64'
tox_env: 'py310-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'macos-latest'
- name: 'py310-nocov (ubuntu/x86_64/manylinux)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x64'
tox_env: 'py310-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp310-*manylinux*'
os: 'ubuntu-latest'
- name: 'py310-nocov (ubuntu/x86_64/musllinux)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x64'
tox_env: 'py310-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp310-*musllinux*'
os: 'ubuntu-latest'
- name: 'py310-nocov (ubuntu/aarch64/manylinux)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x64'
tox_env: 'py310-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp310-*manylinux*'
os: 'ubuntu-latest'
- name: 'py310-nocov (ubuntu/aarch64/musllinux)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x64'
tox_env: 'py310-nocov'
cibw_arch: 'aarch64'
cibw_build: 'cp310-*musllinux*'
os: 'ubuntu-latest'
- name: 'py310-nocov (windows/AMD64)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x64'
tox_env: 'py310-nocov'
cibw_arch: 'AMD64'
cibw_build: 'cp310-*'
os: 'windows-latest'
- name: 'py310-nocov (windows/x86)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x86'
tox_env: 'py310-nocov'
cibw_arch: 'x86'
cibw_build: 'cp310-*'
os: 'windows-latest'
- name: 'py310-nocov (macos/x86_64)'
python: '3.10'
toxpython: 'python3.10'
python_arch: 'x64'
tox_env: 'py310-nocov'
cibw_arch: 'x86_64'
cibw_build: 'cp310-*'
os: 'macos-latest'
- name: 'pypy37-cover (ubuntu/x86_64)'
python: 'pypy-3.7'
toxpython: 'pypy3.7'
python_arch: 'x64'
tox_env: 'pypy37-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'ubuntu-latest'
- name: 'pypy37-cover (windows/AMD64)'
python: 'pypy-3.7'
toxpython: 'pypy3.7'
python_arch: 'x64'
tox_env: 'pypy37-cover,codecov'
cibw_arch: 'AMD64'
cibw_build: false
os: 'windows-latest'
- name: 'pypy37-cover (macos/x86_64)'
python: 'pypy-3.7'
toxpython: 'pypy3.7'
python_arch: 'x64'
tox_env: 'pypy37-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'macos-latest'
- name: 'pypy37-nocov (ubuntu/x86_64/manylinux)'
python: 'pypy-3.7'
toxpython: 'pypy3.7'
python_arch: 'x64'
tox_env: 'pypy37-nocov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'ubuntu-latest'
- name: 'pypy37-nocov (windows/AMD64)'
python: 'pypy-3.7'
toxpython: 'pypy3.7'
python_arch: 'x64'
tox_env: 'pypy37-nocov'
cibw_arch: 'AMD64'
cibw_build: false
os: 'windows-latest'
- name: 'pypy37-nocov (macos/x86_64)'
python: 'pypy-3.7'
toxpython: 'pypy3.7'
python_arch: 'x64'
tox_env: 'pypy37-nocov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'macos-latest'
- name: 'pypy38-cover (ubuntu/x86_64)'
python: 'pypy-3.8'
toxpython: 'pypy3.8'
python_arch: 'x64'
tox_env: 'pypy38-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'ubuntu-latest'
- name: 'pypy38-cover (windows/AMD64)'
python: 'pypy-3.8'
toxpython: 'pypy3.8'
python_arch: 'x64'
tox_env: 'pypy38-cover,codecov'
cibw_arch: 'AMD64'
cibw_build: false
os: 'windows-latest'
- name: 'pypy38-cover (macos/x86_64)'
python: 'pypy-3.8'
toxpython: 'pypy3.8'
python_arch: 'x64'
tox_env: 'pypy38-cover,codecov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'macos-latest'
- name: 'pypy38-nocov (ubuntu/x86_64/manylinux)'
python: 'pypy-3.8'
toxpython: 'pypy3.8'
python_arch: 'x64'
tox_env: 'pypy38-nocov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'ubuntu-latest'
- name: 'pypy38-nocov (windows/AMD64)'
python: 'pypy-3.8'
toxpython: 'pypy3.8'
python_arch: 'x64'
tox_env: 'pypy38-nocov'
cibw_arch: 'AMD64'
cibw_build: false
os: 'windows-latest'
- name: 'pypy38-nocov (macos/x86_64)'
python: 'pypy-3.8'
toxpython: 'pypy3.8'
python_arch: 'x64'
tox_env: 'pypy38-nocov'
cibw_arch: 'x86_64'
cibw_build: false
os: 'macos-latest'
steps:
- uses: docker/setup-qemu-action@v1
if: matrix.cibw_arch == 'aarch64'
with:
platforms: arm64
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
architecture: ${{ matrix.python_arch }}
- name: install dependencies
run: |
python -mpip install --progress-bar=off twine tox cibuildwheel -r ci/requirements.txt
virtualenv --version
pip --version
tox --version
pip list --format=freeze
- name: install dependencies (gdb)
if: >
!matrix.cibw_build && matrix.os == 'ubuntu'
run: >
sudo apt-get install gdb
- name: cibw build and test
if: matrix.cibw_build
run: cibuildwheel
env:
TOXPYTHON: '${{ matrix.toxpython }}'
CIBW_ARCHS: '${{ matrix.cibw_arch }}'
CIBW_BUILD: '${{ matrix.cibw_build }}'
CIBW_BUILD_VERBOSITY: '3'
CIBW_TEST_REQUIRES: >
tox
tox-direct
CIBW_TEST_COMMAND: >
cd {project} &&
tox --skip-pkg-install --direct-yolo -e ${{ matrix.tox_env }} -v
CIBW_TEST_COMMAND_WINDOWS: >
cd /d {project} &&
tox --skip-pkg-install --direct-yolo -e ${{ matrix.tox_env }} -v
- name: regular build and test
env:
TOXPYTHON: '${{ matrix.toxpython }}'
if: >
!matrix.cibw_build
run: >
tox -e ${{ matrix.tox_env }} -v
- name: check wheel
if: matrix.cibw_build
run: twine check wheelhouse/*.whl
- name: upload wheel
uses: actions/upload-artifact@v2
if: matrix.cibw_build
with:
path: wheelhouse/*.whl

77
.gitignore vendored Normal file
View File

@ -0,0 +1,77 @@
*.py[cod]
__pycache__
# C extensions
*.so
# Packages
*.egg
*.egg-info
dist
build
eggs
.eggs
parts
bin
var
sdist
wheelhouse
develop-eggs
.installed.cfg
lib
lib64
venv*/
pyvenv*/
pip-wheel-metadata/
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
.coverage.*
.pytest_cache/
nosetests.xml
coverage.xml
htmlcov
# Translations
*.mo
# Buildout
.mr.developer.cfg
# IDE project files
.project
.pydevproject
.idea
.vscode
*.iml
*.komodoproject
# Complexity
output/*.html
output/*/index.html
# Sphinx
docs/_build
.DS_Store
*~
.*.sw[po]
.build
.ve
.env
.cache
.pytest
.benchmarks
.bootstrap
.appveyor.token
*.bak
# Mypy Cache
.mypy_cache/
# Generated by setuptools-scm
src/*/_version.py

20
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,20 @@
# To install the git pre-commit hook run:
# pre-commit install
# To update the pre-commit hooks run:
# pre-commit install-hooks
exclude: '^(\.tox|ci/templates|\.bumpversion\.cfg)(/|$)'
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.0.1
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: debug-statements
- repo: https://github.com/timothycrosley/isort
rev: 5.9.3
hooks:
- id: isort
- repo: https://gitlab.com/pycqa/flake8
rev: 3.9.2
hooks:
- id: flake8

10
.readthedocs.yml Normal file
View File

@ -0,0 +1,10 @@
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
version: 2
sphinx:
configuration: docs/conf.py
formats: all
python:
install:
- requirements: docs/requirements.txt
- method: pip
path: .

10
AUTHORS.rst Normal file
View File

@ -0,0 +1,10 @@
Authors
=======
* Ionel Cristian Mărieș - https://blog.ionelmc.ro
* Alvin Chow - https://github.com/alvinchow86
* Astrum Kuo - https://github.com/xowenx
* Erik M. Bray - http://iguananaut.net
* Ran Benita - https://github.com/bluetech
* "hugovk" - https://github.com/hugovk

124
CHANGELOG.rst Normal file
View File

@ -0,0 +1,124 @@
Changelog
=========
1.7.1 (2021-12-15)
------------------
* Removed most of the Python 2 support code and fixed ``python_requires`` to require at least Python 3.6.
Note that 1.7.0 has been yanked because it could not install on Python 2.7.
Installing lazy-object-proxy on Python 2.7 should automatically fall back to the 1.6.0 release now.
1.7.0 (2021-12-15)
------------------
* Switched CI to GitHub Actions, this has a couple consequences:
* Support for Python 2.7 is dropped. You can still install it there but it's not tested anymore and
Python 2 specific handling will be removed at some point.
* Linux wheels are now provided in `musllinux` and `manylinux2014` variants.
* Fixed ``__index__`` to fallback to ``int`` if the wrapped object doesn't have an ``__index__`` method.
This prevents situations where code using a proxy would otherwise likely just call ``int`` had the object
not have an ``__index__`` method.
1.6.0 (2021-03-22)
------------------
* Added support for async special methods (``__aiter__``, ``__anext__``,
``__await__``, ``__aenter__``, ``__aexit__``).
These are used in the ``async for``, ``await` and ``async with`` statements.
Note that ``__await__`` returns a wrapper that tries to emulate the crazy
stuff going on in the ceval loop, so there will be a small performance overhead.
* Added the ``__resolved__`` property. You can use it to check if the factory has
been called.
1.5.2 (2020-11-26)
------------------
* Added Python 3.9 wheels.
* Removed Python 2.7 Windows wheels
(not supported on newest image with Python 3.9).
1.5.1 (2020-07-22)
------------------
* Added ARM64 wheels (manylinux2014).
1.5.0 (2020-06-05)
------------------
* Added support for ``__fspath__``.
* Dropped support for Python 3.4.
1.4.3 (2019-10-26)
------------------
* Added binary wheels for Python 3.8.
* Fixed license metadata.
1.4.2 (2019-08-22)
------------------
* Included a ``pyproject.toml`` to allow users install the sdist with old python/setuptools, as the
setuptools-scm dep will be fetched by pip instead of setuptools.
Fixes `#30 <https://github.com/ionelmc/python-lazy-object-proxy/issues/30>`_.
1.4.1 (2019-05-10)
------------------
* Fixed wheels being built with ``-coverage`` cflags. No more issues about bogus ``cext.gcda`` files.
* Removed useless C file from wheels.
* Changed ``setup.py`` to use setuptools-scm.
1.4.0 (2019-05-05)
------------------
* Fixed ``__mod__`` for the slots backend. Contributed by Ran Benita in
`#28 <https://github.com/ionelmc/python-lazy-object-proxy/pull/28>`_.
* Dropped support for Python 2.6 and 3.3. Contributed by "hugovk" in
`#24 <https://github.com/ionelmc/python-lazy-object-proxy/pull/24>`_.
1.3.1 (2017-05-05)
------------------
* Fix broken release (``sdist`` had a broken ``MANIFEST.in``).
1.3.0 (2017-05-02)
------------------
* Speed up arithmetic operations involving ``cext.Proxy`` subclasses.
1.2.2 (2016-04-14)
------------------
* Added `manylinux <https://www.python.org/dev/peps/pep-0513/>`_ wheels.
* Minor cleanup in readme.
1.2.1 (2015-08-18)
------------------
* Fix a memory leak (the wrapped object would get bogus references). Contributed by Astrum Kuo in
`#10 <https://github.com/ionelmc/python-lazy-object-proxy/pull/10>`_.
1.2.0 (2015-07-06)
------------------
* Don't instantiate the object when __repr__ is called. This aids with debugging (allows one to see exactly in
what state the proxy is).
1.1.0 (2015-07-05)
------------------
* Added support for pickling. The pickled value is going to be the wrapped object *without* any Proxy container.
* Fixed a memory management issue in the C extension (reference cycles weren't garbage collected due to improper
handling in the C extension). Contributed by Alvin Chow in
`#8 <https://github.com/ionelmc/python-lazy-object-proxy/pull/8>`_.
1.0.2 (2015-04-11)
-----------------------------------------
* First release on PyPI.

87
CONTRIBUTING.rst Normal file
View File

@ -0,0 +1,87 @@
============
Contributing
============
Contributions are welcome, and they are greatly appreciated! Every
little bit helps, and credit will always be given.
Bug reports
===========
When `reporting a bug <https://github.com/ionelmc/python-lazy-object-proxy/issues>`_ please include:
* Your operating system name and version.
* Any details about your local setup that might be helpful in troubleshooting.
* Detailed steps to reproduce the bug.
Documentation improvements
==========================
lazy-object-proxy could always use more documentation, whether as part of the
official lazy-object-proxy docs, in docstrings, or even on the web in blog posts,
articles, and such.
Feature requests and feedback
=============================
The best way to send feedback is to file an issue at https://github.com/ionelmc/python-lazy-object-proxy/issues.
If you are proposing a feature:
* Explain in detail how it would work.
* Keep the scope as narrow as possible, to make it easier to implement.
* Remember that this is a volunteer-driven project, and that code contributions are welcome :)
Development
===========
To set up `python-lazy-object-proxy` for local development:
1. Fork `python-lazy-object-proxy <https://github.com/ionelmc/python-lazy-object-proxy>`_
(look for the "Fork" button).
2. Clone your fork locally::
git clone git@github.com:YOURGITHUBNAME/python-lazy-object-proxy.git
3. Create a branch for local development::
git checkout -b name-of-your-bugfix-or-feature
Now you can make your changes locally.
4. When you're done making changes run all the checks and docs builder with `tox <https://tox.readthedocs.io/en/latest/install.html>`_ one command::
tox
5. Commit your changes and push your branch to GitHub::
git add .
git commit -m "Your detailed description of your changes."
git push origin name-of-your-bugfix-or-feature
6. Submit a pull request through the GitHub website.
Pull Request Guidelines
-----------------------
If you need some code review or feedback while you're developing the code just make the pull request.
For merging, you should:
1. Include passing tests (run ``tox``).
2. Update documentation when there's new API, functionality etc.
3. Add a note to ``CHANGELOG.rst`` about the changes.
4. Add yourself to ``AUTHORS.rst``.
Tips
----
To run a subset of tests::
tox -e envname -- pytest -k test_myfeature
To run all the test environments in *parallel*::
tox -p auto

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
BSD 2-Clause License
Copyright (c) 2014-2019, Ionel Cristian Mărieș
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 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 HOLDER OR CONTRIBUTORS 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.

115
README.rst Normal file
View File

@ -0,0 +1,115 @@
========
Overview
========
.. start-badges
.. list-table::
:stub-columns: 1
* - docs
- |docs|
* - tests
- | |github-actions| |requires|
| |coveralls| |codecov|
* - package
- | |version| |wheel| |supported-versions| |supported-implementations|
| |commits-since|
.. |docs| image:: https://readthedocs.org/projects/python-lazy-object-proxy/badge/?style=flat
:target: https://python-lazy-object-proxy.readthedocs.io/
:alt: Documentation Status
.. |github-actions| image:: https://github.com/ionelmc/python-lazy-object-proxy/actions/workflows/github-actions.yml/badge.svg
:alt: GitHub Actions Build Status
:target: https://github.com/ionelmc/python-lazy-object-proxy/actions
.. |requires| image:: https://requires.io/github/ionelmc/python-lazy-object-proxy/requirements.svg?branch=master
:alt: Requirements Status
:target: https://requires.io/github/ionelmc/python-lazy-object-proxy/requirements/?branch=master
.. |coveralls| image:: https://coveralls.io/repos/ionelmc/python-lazy-object-proxy/badge.svg?branch=master&service=github
:alt: Coverage Status
:target: https://coveralls.io/r/ionelmc/python-lazy-object-proxy
.. |codecov| image:: https://codecov.io/gh/ionelmc/python-lazy-object-proxy/branch/master/graphs/badge.svg?branch=master
:alt: Coverage Status
:target: https://codecov.io/github/ionelmc/python-lazy-object-proxy
.. |version| image:: https://img.shields.io/pypi/v/lazy-object-proxy.svg
:alt: PyPI Package latest release
:target: https://pypi.org/project/lazy-object-proxy
.. |wheel| image:: https://img.shields.io/pypi/wheel/lazy-object-proxy.svg
:alt: PyPI Wheel
:target: https://pypi.org/project/lazy-object-proxy
.. |supported-versions| image:: https://img.shields.io/pypi/pyversions/lazy-object-proxy.svg
:alt: Supported versions
:target: https://pypi.org/project/lazy-object-proxy
.. |supported-implementations| image:: https://img.shields.io/pypi/implementation/lazy-object-proxy.svg
:alt: Supported implementations
:target: https://pypi.org/project/lazy-object-proxy
.. |commits-since| image:: https://img.shields.io/github/commits-since/ionelmc/python-lazy-object-proxy/v1.7.1.svg
:alt: Commits since latest release
:target: https://github.com/ionelmc/python-lazy-object-proxy/compare/v1.7.1...master
.. end-badges
A fast and thorough lazy object proxy.
* Free software: BSD 2-Clause License
Note that this is based on `wrapt`_'s ObjectProxy with one big change: it calls a function the first time the proxy object is
used, while `wrapt.ObjectProxy` just forwards the method calls to the target object.
In other words, you use `lazy-object-proxy` when you only have the object way later and you use `wrapt.ObjectProxy` when you
want to override few methods (by subclassing) and forward everything else to the target object.
Example::
import lazy_object_proxy
def expensive_func():
from time import sleep
print('starting calculation')
# just as example for a very slow computation
sleep(2)
print('finished calculation')
# return the result of the calculation
return 10
obj = lazy_object_proxy.Proxy(expensive_func)
# function is called only when object is actually used
print(obj) # now expensive_func is called
print(obj) # the result without calling the expensive_func
Installation
============
::
pip install lazy-object-proxy
Documentation
=============
https://python-lazy-object-proxy.readthedocs.io/
Development
===========
To run all the tests run::
tox
Acknowledgements
================
This project is based on some code from `wrapt`_ as you can see in the git history.
.. _wrapt: https://github.com/GrahamDumpleton/wrapt

93
ci/bootstrap.py Executable file
View File

@ -0,0 +1,93 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from __future__ import unicode_literals
import os
import subprocess
import sys
from os.path import abspath
from os.path import dirname
from os.path import exists
from os.path import join
from os.path import relpath
base_path = dirname(dirname(abspath(__file__)))
templates_path = join(base_path, "ci", "templates")
def check_call(args):
print("+", *args)
subprocess.check_call(args)
def exec_in_env():
env_path = join(base_path, ".tox", "bootstrap")
if sys.platform == "win32":
bin_path = join(env_path, "Scripts")
else:
bin_path = join(env_path, "bin")
if not exists(env_path):
import subprocess
print("Making bootstrap env in: {0} ...".format(env_path))
try:
check_call([sys.executable, "-m", "venv", env_path])
except subprocess.CalledProcessError:
try:
check_call([sys.executable, "-m", "virtualenv", env_path])
except subprocess.CalledProcessError:
check_call(["virtualenv", env_path])
print("Installing `jinja2` into bootstrap environment...")
check_call([join(bin_path, "pip"), "install", "jinja2", "tox"])
python_executable = join(bin_path, "python")
if not os.path.exists(python_executable):
python_executable += '.exe'
print("Re-executing with: {0}".format(python_executable))
print("+ exec", python_executable, __file__, "--no-env")
os.execv(python_executable, [python_executable, __file__, "--no-env"])
def main():
import jinja2
print("Project path: {0}".format(base_path))
jinja = jinja2.Environment(
loader=jinja2.FileSystemLoader(templates_path),
trim_blocks=True,
lstrip_blocks=True,
keep_trailing_newline=True
)
tox_environments = [
line.strip()
# 'tox' need not be installed globally, but must be importable
# by the Python that is running this script.
# This uses sys.executable the same way that the call in
# cookiecutter-pylibrary/hooks/post_gen_project.py
# invokes this bootstrap.py itself.
for line in subprocess.check_output([sys.executable, '-m', 'tox', '--listenvs'], universal_newlines=True).splitlines()
]
tox_environments = [line for line in tox_environments if line.startswith('py')]
for root, _, files in os.walk(templates_path):
for name in files:
relative = relpath(root, templates_path)
with open(join(base_path, relative, name), "w") as fh:
fh.write(jinja.get_template(join(relative, name)).render(tox_environments=tox_environments))
print("Wrote {}".format(name))
print("DONE.")
if __name__ == "__main__":
args = sys.argv[1:]
if args == ["--no-env"]:
main()
elif not args:
exec_in_env()
else:
print("Unexpected arguments {0}".format(args), file=sys.stderr)
sys.exit(1)

4
ci/requirements.txt Normal file
View File

@ -0,0 +1,4 @@
virtualenv>=20.4.7
pip>=19.1.1
setuptools>=18.0.1
six>=1.14.0

View File

@ -0,0 +1,115 @@
name: build
on: [push, pull_request]
jobs:
test:
name: {{ '${{ matrix.name }}' }}
runs-on: {{ '${{ matrix.os }}' }}
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- name: 'check'
python: '3.9'
toxpython: 'python3.9'
tox_env: 'check'
os: 'ubuntu-latest'
- name: 'docs'
python: '3.9'
toxpython: 'python3.9'
tox_env: 'docs'
os: 'ubuntu-latest'
{% for env in tox_environments %}
{% set prefix = env.split('-')[0] -%}
{% if prefix.startswith('pypy') %}
{% set python %}pypy-{{ prefix[4] }}.{{ prefix[5] }}{% endset %}
{% set cpython %}pp{{ prefix[4:5] }}{% endset %}
{% set toxpython %}pypy{{ prefix[4] }}.{{ prefix[5] }}{% endset %}
{% else %}
{% set python %}{{ prefix[2] }}.{{ prefix[3:] }}{% endset %}
{% set cpython %}cp{{ prefix[2:] }}{% endset %}
{% set toxpython %}python{{ prefix[2] }}.{{ prefix[3:] }}{% endset %}
{% endif %}
{% for os, python_arch, cibw_arch, wheel_arch, include_cover in [
['ubuntu', 'x64', 'x86_64', '*manylinux*', True],
['ubuntu', 'x64', 'x86_64', '*musllinux*', False],
['ubuntu', 'x64', 'aarch64', '*manylinux*', False],
['ubuntu', 'x64', 'aarch64', '*musllinux*', False],
['windows', 'x64', 'AMD64', '*', True],
['windows', 'x86', 'x86', '*', False],
['macos', 'x64', 'x86_64', '*', True],
] %}
{% if include_cover or ('nocov' in env and not prefix.startswith('pypy')) %}
{% set wheel_suffix = 'nocov' in env and wheel_arch.strip('*') %}
{% set name_suffix = '/' + wheel_suffix if wheel_suffix else '' %}
- name: '{{ env }} ({{ os }}/{{ cibw_arch }}{{ name_suffix }})'
python: '{{ python }}'
toxpython: '{{ toxpython }}'
python_arch: '{{ python_arch }}'
tox_env: '{{ env }}{% if 'cover' in env %},codecov{% endif %}'
cibw_arch: '{{ cibw_arch }}'
{% if 'nocov' in env and not prefix.startswith('pypy') %}
cibw_build: '{{ cpython }}-{{ wheel_arch }}'
{% else %}
cibw_build: false
{% endif %}
os: '{{ os }}-latest'
{% endif %}
{% endfor %}
{% endfor %}
steps:
- uses: docker/setup-qemu-action@v1
if: matrix.cibw_arch == 'aarch64'
with:
platforms: arm64
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-python@v2
with:
python-version: {{ '${{ matrix.python }}' }}
architecture: {{ '${{ matrix.python_arch }}' }}
- name: install dependencies
run: |
python -mpip install --progress-bar=off twine tox cibuildwheel -r ci/requirements.txt
virtualenv --version
pip --version
tox --version
pip list --format=freeze
- name: install dependencies (gdb)
if: >
!matrix.cibw_build && matrix.os == 'ubuntu'
run: >
sudo apt-get install gdb
- name: cibw build and test
if: matrix.cibw_build
run: cibuildwheel
env:
TOXPYTHON: '{{ '${{ matrix.toxpython }}' }}'
CIBW_ARCHS: '{{ '${{ matrix.cibw_arch }}' }}'
CIBW_BUILD: '{{ '${{ matrix.cibw_build }}' }}'
CIBW_BUILD_VERBOSITY: '3'
CIBW_TEST_REQUIRES: >
tox
tox-direct
CIBW_TEST_COMMAND: >
cd {project} &&
tox --skip-pkg-install --direct-yolo -e {{ '${{ matrix.tox_env }}' }} -v
CIBW_TEST_COMMAND_WINDOWS: >
cd /d {project} &&
tox --skip-pkg-install --direct-yolo -e {{ '${{ matrix.tox_env }}' }} -v
- name: regular build and test
env:
TOXPYTHON: '{{ '${{ matrix.toxpython }}' }}'
if: >
!matrix.cibw_build
run: >
tox -e {{ '${{ matrix.tox_env }}' }} -v
- name: check wheel
if: matrix.cibw_build
run: twine check wheelhouse/*.whl
- name: upload wheel
uses: actions/upload-artifact@v2
if: matrix.cibw_build
with:
path: wheelhouse/*.whl

10
conftest.py Normal file
View File

@ -0,0 +1,10 @@
import sys
PY3 = sys.version_info[0] >= 3
def pytest_ignore_collect(path, config):
basename = path.basename
if not PY3 and "py3" in basename or PY3 and "py2" in basename:
return True

1
docs/authors.rst Normal file
View File

@ -0,0 +1 @@
.. include:: ../AUTHORS.rst

1
docs/changelog.rst Normal file
View File

@ -0,0 +1 @@
.. include:: ../CHANGELOG.rst

54
docs/conf.py Normal file
View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import traceback
import sphinx_py3doc_enhanced_theme
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.autosummary',
'sphinx.ext.coverage',
'sphinx.ext.doctest',
'sphinx.ext.extlinks',
'sphinx.ext.ifconfig',
'sphinx.ext.napoleon',
'sphinx.ext.todo',
'sphinx.ext.viewcode',
]
source_suffix = '.rst'
master_doc = 'index'
project = 'lazy-object-proxy'
year = '2014-2021'
author = 'Ionel Cristian Mărieș'
copyright = '{0}, {1}'.format(year, author)
try:
from pkg_resources import get_distribution
version = release = get_distribution('lazy_object_proxy').version
except Exception:
traceback.print_exc()
version = release = '1.7.1'
pygments_style = 'trac'
templates_path = ['.']
extlinks = {
'issue': ('https://github.com/ionelmc/python-lazy-object-proxy/issues/%s', '#'),
'pr': ('https://github.com/ionelmc/python-lazy-object-proxy/pull/%s', 'PR #'),
}
html_theme = "sphinx_py3doc_enhanced_theme"
html_theme_path = [sphinx_py3doc_enhanced_theme.get_html_theme_path()]
html_theme_options = {
'githuburl': 'https://github.com/ionelmc/python-lazy-object-proxy/'
}
html_use_smartypants = True
html_last_updated_fmt = '%b %d, %Y'
html_split_index = False
html_sidebars = {
'**': ['searchbox.html', 'globaltoc.html', 'sourcelink.html'],
}
html_short_title = '%s-%s' % (project, version)
napoleon_use_ivar = True
napoleon_use_rtype = False
napoleon_use_param = False

1
docs/contributing.rst Normal file
View File

@ -0,0 +1 @@
.. include:: ../CONTRIBUTING.rst

21
docs/index.rst Normal file
View File

@ -0,0 +1,21 @@
========
Contents
========
.. toctree::
:maxdepth: 2
readme
installation
usage
contributing
authors
changelog
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

7
docs/installation.rst Normal file
View File

@ -0,0 +1,7 @@
============
Installation
============
At the command line::
pip install lazy-object-proxy

1
docs/readme.rst Normal file
View File

@ -0,0 +1 @@
.. include:: ../README.rst

2
docs/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
sphinx>=1.3
sphinx-py3doc-enhanced-theme

View File

@ -0,0 +1,11 @@
builtin
builtins
classmethod
staticmethod
classmethods
staticmethods
args
kwargs
callstack
Changelog
Indices

7
docs/usage.rst Normal file
View File

@ -0,0 +1,7 @@
=====
Usage
=====
To use lazy-object-proxy in a project::
import lazy_object_proxy

6
pyproject.toml Normal file
View File

@ -0,0 +1,6 @@
[build-system]
requires = [
"setuptools>=30.3.0",
"wheel",
"setuptools_scm>=3.3.1",
]

48
setup.cfg Normal file
View File

@ -0,0 +1,48 @@
[options]
setup_requires =
setuptools_scm>=3.3.1
[flake8]
max-line-length = 140
exclude = .tox,.eggs,ci/templates,build,dist
[tool:pytest]
# If a pytest section is found in one of the possible config files
# (pytest.ini, tox.ini or setup.cfg), then pytest will not look for any others,
# so if you add a pytest config section elsewhere,
# you will need to delete this section from setup.cfg.
norecursedirs =
.git
.tox
.env
dist
build
migrations
python_files =
test_*.py
*_test.py
tests.py
markers =
xfail_subclass: Expected test to fail with a subclass of Proxy.
xfail_simple: Expected test to fail on the `simple` implementation.
addopts =
-ra
--strict-markers
--ignore=docs/conf.py
--ignore=setup.py
--ignore=ci
--ignore=.eggs
--doctest-modules
--doctest-glob=\*.rst
--tb=short
testpaths =
tests
[tool:isort]
force_single_line = True
line_length = 120
known_first_party = lazy_object_proxy
default_section = THIRDPARTY
forced_separate = test_lazy_object_proxy
skip = .tox,.eggs,ci/templates,build,dist

147
setup.py Executable file
View File

@ -0,0 +1,147 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
import io
import os
import platform
import re
import sys
from glob import glob
from os.path import basename
from os.path import dirname
from os.path import join
from os.path import relpath
from os.path import splitext
from setuptools import Extension
from setuptools import find_packages
from setuptools import setup
from setuptools.command.build_ext import build_ext
from setuptools.dist import Distribution
# Enable code coverage for C code: we can't use CFLAGS=-coverage in tox.ini, since that may mess with compiling
# dependencies (e.g. numpy). Therefore we set SETUPPY_CFLAGS=-coverage in tox.ini and copy it to CFLAGS here (after
# deps have been safely installed).
if 'TOX_ENV_NAME' in os.environ and os.environ.get('SETUPPY_EXT_COVERAGE') == 'yes' and platform.system() == 'Linux':
CFLAGS = os.environ['CFLAGS'] = '-fprofile-arcs -ftest-coverage'
LFLAGS = os.environ['LFLAGS'] = '-lgcov'
else:
CFLAGS = ''
LFLAGS = ''
class OptionalBuildExt(build_ext):
"""Allow the building of C extensions to fail."""
def run(self):
try:
super().run()
except Exception as e:
self._unavailable(e)
self.extensions = [] # avoid copying missing files (it would fail).
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('CAUSE:')
print('')
print(' ' + repr(e))
print('*' * 80)
def read(*names, **kwargs):
with io.open(
join(dirname(__file__), *names),
encoding=kwargs.get('encoding', 'utf8')
) as fh:
return fh.read()
class BinaryDistribution(Distribution):
"""Distribution which almost always forces a binary package with platform name"""
def has_ext_modules(self):
return super().has_ext_modules() or not os.environ.get('SETUPPY_ALLOW_PURE')
setup(
name='lazy-object-proxy',
use_scm_version={
'local_scheme': 'dirty-tag',
'write_to': 'src/lazy_object_proxy/_version.py',
'fallback_version': '1.7.1',
},
license='BSD-2-Clause',
description='A fast and thorough lazy object proxy.',
long_description='%s\n%s' % (
re.compile('^.. start-badges.*^.. end-badges', re.M | re.S).sub('', read('README.rst')),
re.sub(':[a-z]+:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst'))
),
author='Ionel Cristian Mărieș',
author_email='contact@ionelmc.ro',
url='https://github.com/ionelmc/python-lazy-object-proxy',
packages=find_packages('src'),
package_dir={'': 'src'},
py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')],
include_package_data=False,
zip_safe=False,
classifiers=[
# complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: Unix',
'Operating System :: POSIX',
'Operating System :: Microsoft :: Windows',
'Programming Language :: Python',
'Programming Language :: Python :: 3 :: Only',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy',
# uncomment if you test on these interpreters:
# 'Programming Language :: Python :: Implementation :: IronPython',
# 'Programming Language :: Python :: Implementation :: Jython',
# 'Programming Language :: Python :: Implementation :: Stackless',
'Topic :: Utilities',
],
project_urls={
'Documentation': 'https://python-lazy-object-proxy.readthedocs.io/',
'Changelog': 'https://python-lazy-object-proxy.readthedocs.io/en/latest/changelog.html',
'Issue Tracker': 'https://github.com/ionelmc/python-lazy-object-proxy/issues',
},
keywords=[
# eg: 'keyword1', 'keyword2', 'keyword3',
],
python_requires='>=3.6',
install_requires=[
# eg: 'aspectlib==1.1.1', 'six>=1.7',
],
extras_require={
# eg:
# 'rst': ['docutils>=0.11'],
# ':python_version=="2.6"': ['argparse'],
},
cmdclass={'build_ext': OptionalBuildExt},
ext_modules=[] if hasattr(sys, 'pypy_version_info') else [
Extension(
splitext(relpath(path, 'src').replace(os.sep, '.'))[0],
sources=[path],
extra_compile_args=CFLAGS.split(),
extra_link_args=LFLAGS.split(),
include_dirs=[dirname(path)]
)
for root, _, _ in os.walk('src')
for path in glob(join(root, '*.c'))
],
distclass=BinaryDistribution,
)

View File

@ -0,0 +1,23 @@
try:
import copy_reg as copyreg
except ImportError:
import copyreg
from .utils import identity
copyreg.constructor(identity)
try:
from .cext import Proxy
from .cext import identity
except ImportError:
from .slots import Proxy
else:
copyreg.constructor(identity)
try:
from ._version import version as __version__
except ImportError:
__version__ = '1.7.1'
__all__ = "Proxy",

1397
src/lazy_object_proxy/cext.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
import sys
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
if PY3:
string_types = str, bytes
else:
string_types = basestring, # noqa: F821
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
return meta("NewBase", bases, {})

View File

@ -0,0 +1,278 @@
import operator
from .compat import PY2
from .compat import PY3
from .compat import string_types
from .compat import with_metaclass
from .utils import await_
from .utils import cached_property
from .utils import identity
def make_proxy_method(code):
def proxy_wrapper(self, *args):
return code(self.__wrapped__, *args)
return proxy_wrapper
class _ProxyMethods(object):
# We use properties to override the values of __module__ and
# __doc__. If we add these in ObjectProxy, the derived class
# __dict__ will still be setup to have string variants of these
# attributes and the rules of descriptors means that they appear to
# take precedence over the properties in the base class. To avoid
# that, we copy the properties into the derived class type itself
# via a meta class. In that way the properties will always take
# precedence.
@property
def __module__(self):
return self.__wrapped__.__module__
@__module__.setter
def __module__(self, value):
self.__wrapped__.__module__ = value
@property
def __doc__(self):
return self.__wrapped__.__doc__
@__doc__.setter
def __doc__(self, value):
self.__wrapped__.__doc__ = value
# Need to also propagate the special __weakref__ attribute for case
# where decorating classes which will define this. If do not define
# it and use a function like inspect.getmembers() on a decorator
# class it will fail. This can't be in the derived classes.
@property
def __weakref__(self):
return self.__wrapped__.__weakref__
class _ProxyMetaType(type):
def __new__(cls, name, bases, dictionary):
# Copy our special properties into the class so that they
# always take precedence over attributes of the same name added
# during construction of a derived class. This is to save
# duplicating the implementation for them in all derived classes.
dictionary.update(vars(_ProxyMethods))
dictionary.pop('__dict__')
return type.__new__(cls, name, bases, dictionary)
class Proxy(with_metaclass(_ProxyMetaType)):
__factory__ = None
def __init__(self, factory):
self.__dict__['__factory__'] = factory
@property
def __resolved__(self):
return '__wrapped__' in self.__dict__
@cached_property
def __wrapped__(self):
self = self.__dict__
if '__factory__' in self:
factory = self['__factory__']
return factory()
else:
raise ValueError("Proxy hasn't been initiated: __factory__ is missing.")
__name__ = property(make_proxy_method(operator.attrgetter('__name__')))
__class__ = property(make_proxy_method(operator.attrgetter('__class__')))
__annotations__ = property(make_proxy_method(operator.attrgetter('__anotations__')))
__dir__ = make_proxy_method(dir)
__str__ = make_proxy_method(str)
if PY3:
__bytes__ = make_proxy_method(bytes)
def __repr__(self, __getattr__=object.__getattribute__):
if '__wrapped__' in self.__dict__:
return '<{} at 0x{:x} wrapping {!r} at 0x{:x} with factory {!r}>'.format(
type(self).__name__, id(self),
self.__wrapped__, id(self.__wrapped__),
self.__factory__
)
else:
return '<{} at 0x{:x} with factory {!r}>'.format(
type(self).__name__, id(self),
self.__factory__
)
def __fspath__(self):
wrapped = self.__wrapped__
if isinstance(wrapped, string_types):
return wrapped
else:
fspath = getattr(wrapped, '__fspath__', None)
if fspath is None:
return wrapped
else:
return fspath()
__reversed__ = make_proxy_method(reversed)
if PY3:
__round__ = make_proxy_method(round)
__lt__ = make_proxy_method(operator.lt)
__le__ = make_proxy_method(operator.le)
__eq__ = make_proxy_method(operator.eq)
__ne__ = make_proxy_method(operator.ne)
__gt__ = make_proxy_method(operator.gt)
__ge__ = make_proxy_method(operator.ge)
__hash__ = make_proxy_method(hash)
__nonzero__ = make_proxy_method(bool)
__bool__ = make_proxy_method(bool)
def __setattr__(self, name, value):
if hasattr(type(self), name):
self.__dict__[name] = value
else:
setattr(self.__wrapped__, name, value)
def __getattr__(self, name):
if name in ('__wrapped__', '__factory__'):
raise AttributeError(name)
else:
return getattr(self.__wrapped__, name)
def __delattr__(self, name):
if hasattr(type(self), name):
del self.__dict__[name]
else:
delattr(self.__wrapped__, name)
__add__ = make_proxy_method(operator.add)
__sub__ = make_proxy_method(operator.sub)
__mul__ = make_proxy_method(operator.mul)
__div__ = make_proxy_method(operator.div if PY2 else operator.truediv)
__truediv__ = make_proxy_method(operator.truediv)
__floordiv__ = make_proxy_method(operator.floordiv)
__mod__ = make_proxy_method(operator.mod)
__divmod__ = make_proxy_method(divmod)
__pow__ = make_proxy_method(pow)
__lshift__ = make_proxy_method(operator.lshift)
__rshift__ = make_proxy_method(operator.rshift)
__and__ = make_proxy_method(operator.and_)
__xor__ = make_proxy_method(operator.xor)
__or__ = make_proxy_method(operator.or_)
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 __rdiv__(self, other):
return operator.div(other, self.__wrapped__)
def __rtruediv__(self, other):
return operator.truediv(other, self.__wrapped__)
def __rfloordiv__(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, *args):
return pow(other, self.__wrapped__, *args)
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__
__iadd__ = make_proxy_method(operator.iadd)
__isub__ = make_proxy_method(operator.isub)
__imul__ = make_proxy_method(operator.imul)
__idiv__ = make_proxy_method(operator.idiv if PY2 else operator.itruediv)
__itruediv__ = make_proxy_method(operator.itruediv)
__ifloordiv__ = make_proxy_method(operator.ifloordiv)
__imod__ = make_proxy_method(operator.imod)
__ipow__ = make_proxy_method(operator.ipow)
__ilshift__ = make_proxy_method(operator.ilshift)
__irshift__ = make_proxy_method(operator.irshift)
__iand__ = make_proxy_method(operator.iand)
__ixor__ = make_proxy_method(operator.ixor)
__ior__ = make_proxy_method(operator.ior)
__neg__ = make_proxy_method(operator.neg)
__pos__ = make_proxy_method(operator.pos)
__abs__ = make_proxy_method(operator.abs)
__invert__ = make_proxy_method(operator.invert)
__int__ = make_proxy_method(int)
if PY2:
__long__ = make_proxy_method(long) # noqa
__float__ = make_proxy_method(float)
__oct__ = make_proxy_method(oct)
__hex__ = make_proxy_method(hex)
def __index__(self):
if hasattr(self.__wrapped__, '__index__'):
return operator.index(self.__wrapped__)
else:
return int(self.__wrapped__)
__len__ = make_proxy_method(len)
__contains__ = make_proxy_method(operator.contains)
__getitem__ = make_proxy_method(operator.getitem)
__setitem__ = make_proxy_method(operator.setitem)
__delitem__ = make_proxy_method(operator.delitem)
if PY2:
__getslice__ = make_proxy_method(operator.getslice)
__setslice__ = make_proxy_method(operator.setslice)
__delslice__ = make_proxy_method(operator.delslice)
def __enter__(self):
return self.__wrapped__.__enter__()
def __exit__(self, *args, **kwargs):
return self.__wrapped__.__exit__(*args, **kwargs)
__iter__ = make_proxy_method(iter)
def __call__(self, *args, **kwargs):
return self.__wrapped__(*args, **kwargs)
def __reduce__(self):
return identity, (self.__wrapped__,)
def __reduce_ex__(self, protocol):
return identity, (self.__wrapped__,)
if await_:
from .utils import __aenter__
from .utils import __aexit__
from .utils import __aiter__
from .utils import __anext__
from .utils import __await__
__aiter__, __anext__, __await__, __aenter__, __aexit__ # noqa

View File

@ -0,0 +1,452 @@
import operator
from .compat import PY2
from .compat import PY3
from .compat import string_types
from .compat import with_metaclass
from .utils import await_
from .utils import identity
class _ProxyMethods(object):
# We use properties to override the values of __module__ and
# __doc__. If we add these in ObjectProxy, the derived class
# __dict__ will still be setup to have string variants of these
# attributes and the rules of descriptors means that they appear to
# take precedence over the properties in the base class. To avoid
# that, we copy the properties into the derived class type itself
# via a meta class. In that way the properties will always take
# precedence.
@property
def __module__(self):
return self.__wrapped__.__module__
@__module__.setter
def __module__(self, value):
self.__wrapped__.__module__ = value
@property
def __doc__(self):
return self.__wrapped__.__doc__
@__doc__.setter
def __doc__(self, value):
self.__wrapped__.__doc__ = value
# We similar use a property for __dict__. We need __dict__ to be
# explicit to ensure that vars() works as expected.
@property
def __dict__(self):
return self.__wrapped__.__dict__
# Need to also propagate the special __weakref__ attribute for case
# where decorating classes which will define this. If do not define
# it and use a function like inspect.getmembers() on a decorator
# class it will fail. This can't be in the derived classes.
@property
def __weakref__(self):
return self.__wrapped__.__weakref__
class _ProxyMetaType(type):
def __new__(cls, name, bases, dictionary):
# Copy our special properties into the class so that they
# always take precedence over attributes of the same name added
# during construction of a derived class. This is to save
# duplicating the implementation for them in all derived classes.
dictionary.update(vars(_ProxyMethods))
return type.__new__(cls, name, bases, dictionary)
class Proxy(with_metaclass(_ProxyMetaType)):
"""
A proxy implementation in pure Python, using slots. You can subclass this to add
local methods or attributes, or enable __dict__.
The most important internals:
* ``__factory__`` is the callback that "materializes" the object we proxy to.
* ``__target__`` will contain the object we proxy to, once it's "materialized".
* ``__resolved__`` is a boolean, `True` if factory was called.
* ``__wrapped__`` is a property that does either:
* return ``__target__`` if it's set.
* calls ``__factory__``, saves result to ``__target__`` and returns said result.
"""
__slots__ = '__target__', '__factory__'
def __init__(self, factory):
object.__setattr__(self, '__factory__', factory)
@property
def __resolved__(self, __getattr__=object.__getattribute__):
try:
__getattr__(self, '__target__')
except AttributeError:
return False
else:
return True
@property
def __wrapped__(self, __getattr__=object.__getattribute__, __setattr__=object.__setattr__,
__delattr__=object.__delattr__):
try:
return __getattr__(self, '__target__')
except AttributeError:
try:
factory = __getattr__(self, '__factory__')
except AttributeError:
raise ValueError("Proxy hasn't been initiated: __factory__ is missing.")
target = factory()
__setattr__(self, '__target__', target)
return target
@__wrapped__.deleter
def __wrapped__(self, __delattr__=object.__delattr__):
__delattr__(self, '__target__')
@__wrapped__.setter
def __wrapped__(self, target, __setattr__=object.__setattr__):
__setattr__(self, '__target__', target)
@property
def __name__(self):
return self.__wrapped__.__name__
@__name__.setter
def __name__(self, value):
self.__wrapped__.__name__ = value
@property
def __class__(self):
return self.__wrapped__.__class__
@__class__.setter # noqa: F811
def __class__(self, value): # noqa: F811
self.__wrapped__.__class__ = value
@property
def __annotations__(self):
return self.__wrapped__.__anotations__
@__annotations__.setter
def __annotations__(self, value):
self.__wrapped__.__annotations__ = value
def __dir__(self):
return dir(self.__wrapped__)
def __str__(self):
return str(self.__wrapped__)
if PY3:
def __bytes__(self):
return bytes(self.__wrapped__)
def __repr__(self, __getattr__=object.__getattribute__):
try:
target = __getattr__(self, '__target__')
except AttributeError:
return '<{} at 0x{:x} with factory {!r}>'.format(
type(self).__name__, id(self),
self.__factory__
)
else:
return '<{} at 0x{:x} wrapping {!r} at 0x{:x} with factory {!r}>'.format(
type(self).__name__, id(self),
target, id(target),
self.__factory__
)
def __fspath__(self):
wrapped = self.__wrapped__
if isinstance(wrapped, string_types):
return wrapped
else:
fspath = getattr(wrapped, '__fspath__', None)
if fspath is None:
return wrapped
else:
return fspath()
def __reversed__(self):
return reversed(self.__wrapped__)
if PY3:
def __round__(self):
return round(self.__wrapped__)
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 __hash__(self):
return hash(self.__wrapped__)
def __nonzero__(self):
return bool(self.__wrapped__)
def __bool__(self):
return bool(self.__wrapped__)
def __setattr__(self, name, value, __setattr__=object.__setattr__):
if hasattr(type(self), name):
__setattr__(self, name, value)
else:
setattr(self.__wrapped__, name, value)
def __getattr__(self, name):
if name in ('__wrapped__', '__factory__'):
raise AttributeError(name)
else:
return getattr(self.__wrapped__, name)
def __delattr__(self, name, __delattr__=object.__delattr__):
if hasattr(type(self), name):
__delattr__(self, name)
else:
delattr(self.__wrapped__, name)
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 __div__(self, other):
return operator.div(self.__wrapped__, other)
def __truediv__(self, other):
return operator.truediv(self.__wrapped__, other)
def __floordiv__(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, *args):
return pow(self.__wrapped__, other, *args)
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 __radd__(self, other):
return other + self.__wrapped__
def __rsub__(self, other):
return other - self.__wrapped__
def __rmul__(self, other):
return other * self.__wrapped__
def __rdiv__(self, other):
return operator.div(other, self.__wrapped__)
def __rtruediv__(self, other):
return operator.truediv(other, self.__wrapped__)
def __rfloordiv__(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, *args):
return pow(other, self.__wrapped__, *args)
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__
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 __idiv__(self, other):
self.__wrapped__ = operator.idiv(self.__wrapped__, other)
return self
def __itruediv__(self, other):
self.__wrapped__ = operator.itruediv(self.__wrapped__, other)
return self
def __ifloordiv__(self, other):
self.__wrapped__ //= other
return self
def __imod__(self, other):
self.__wrapped__ %= other
return self
def __ipow__(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 __neg__(self):
return -self.__wrapped__
def __pos__(self):
return +self.__wrapped__
def __abs__(self):
return abs(self.__wrapped__)
def __invert__(self):
return ~self.__wrapped__
def __int__(self):
return int(self.__wrapped__)
if PY2:
def __long__(self):
return long(self.__wrapped__) # noqa
def __float__(self):
return float(self.__wrapped__)
def __oct__(self):
return oct(self.__wrapped__)
def __hex__(self):
return hex(self.__wrapped__)
def __index__(self):
if hasattr(self.__wrapped__, '__index__'):
return operator.index(self.__wrapped__)
else:
return int(self.__wrapped__)
def __len__(self):
return len(self.__wrapped__)
def __contains__(self, value):
return value in 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 __getslice__(self, i, j):
return self.__wrapped__[i:j]
def __setslice__(self, i, j, value):
self.__wrapped__[i:j] = value
def __delslice__(self, i, j):
del self.__wrapped__[i:j]
def __enter__(self):
return self.__wrapped__.__enter__()
def __exit__(self, *args, **kwargs):
return self.__wrapped__.__exit__(*args, **kwargs)
def __iter__(self):
return iter(self.__wrapped__)
def __next__(self):
return next(self.__wrapped__)
def __call__(self, *args, **kwargs):
return self.__wrapped__(*args, **kwargs)
def __reduce__(self):
return identity, (self.__wrapped__,)
def __reduce_ex__(self, protocol):
return identity, (self.__wrapped__,)
if await_:
from .utils import __aenter__
from .utils import __aexit__
from .utils import __aiter__
from .utils import __anext__
from .utils import __await__
__aiter__, __anext__, __await__, __aenter__, __aexit__ # noqa

View File

@ -0,0 +1,25 @@
# flake8: noqa
try:
from .utils_py3 import __aenter__
from .utils_py3 import __aexit__
from .utils_py3 import __aiter__
from .utils_py3 import __anext__
from .utils_py3 import __await__
from .utils_py3 import await_
except (ImportError, SyntaxError):
await_ = None
def identity(obj):
return obj
class cached_property(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, cls):
if obj is None:
return self
value = obj.__dict__[self.func.__name__] = self.func(obj)
return value

View File

@ -0,0 +1,44 @@
from collections.abc import Awaitable
from inspect import CO_ITERABLE_COROUTINE
from types import CoroutineType
from types import GeneratorType
async def do_await(obj):
return await obj
def do_yield_from(gen):
return (yield from gen)
def await_(obj):
obj_type = type(obj)
if (
obj_type is CoroutineType or
obj_type is GeneratorType and bool(obj.gi_code.co_flags & CO_ITERABLE_COROUTINE) or
isinstance(obj, Awaitable)
):
return do_await(obj).__await__()
else:
return do_yield_from(obj)
def __aiter__(self):
return self.__wrapped__.__aiter__()
async def __anext__(self):
return await self.__wrapped__.__anext__()
def __await__(self):
return await_(self.__wrapped__)
def __aenter__(self):
return self.__wrapped__.__aenter__()
def __aexit__(self, *args, **kwargs):
return self.__wrapped__.__aexit__(*args, **kwargs)

26
tests/compat.py Normal file
View File

@ -0,0 +1,26 @@
import sys
PY2 = sys.version_info[0] < 3
PY3 = sys.version_info[0] >= 3
if PY3:
import builtins
exec_ = getattr(builtins, "exec")
del builtins
else:
def exec_(_code_, _globs_=None, _locs_=None):
"""Execute code in a namespace."""
if _globs_ is None:
frame = sys._getframe(1)
_globs_ = frame.f_globals
if _locs_ is None:
_locs_ = frame.f_locals
del frame
elif _locs_ is None:
_locs_ = _globs_
exec("""exec _code_ in _globs_, _locs_""")
exec_("""def reraise(tp, value, tb=None):
raise tp, value, tb
""")

74
tests/conftest.py Normal file
View File

@ -0,0 +1,74 @@
import sys
import pytest
PYPY = '__pypy__' in sys.builtin_module_names
@pytest.fixture(scope="session")
def lop_loader():
def load_implementation(name):
class FakeModule:
subclass = False
kind = name
if name == "slots":
from lazy_object_proxy.slots import Proxy
elif name == "simple":
from lazy_object_proxy.simple import Proxy
elif name == "cext":
try:
from lazy_object_proxy.cext import Proxy
except ImportError:
if PYPY:
pytest.skip(msg="C Extension not available.")
else:
raise
elif name == "objproxies":
Proxy = pytest.importorskip("objproxies").LazyProxy
elif name == "django":
Proxy = pytest.importorskip("django.utils.functional").SimpleLazyObject
else:
raise RuntimeError("Unsupported param: %r." % name)
Proxy
return FakeModule
return load_implementation
@pytest.fixture(scope="session", params=[
"slots", "cext",
"simple",
# "external-django", "external-objproxies"
])
def lop_implementation(request, lop_loader):
return lop_loader(request.param)
@pytest.fixture(scope="session", params=[True, False], ids=['subclassed', 'normal'])
def lop_subclass(request, lop_implementation):
if request.param:
class submod(lop_implementation):
subclass = True
Proxy = type("SubclassOf_" + lop_implementation.Proxy.__name__,
(lop_implementation.Proxy,), {})
return submod
else:
return lop_implementation
@pytest.fixture(scope="function")
def lop(request, lop_subclass):
if request.node.get_closest_marker('xfail_subclass'):
request.applymarker(pytest.mark.xfail(
reason="This test can't work because subclassing disables certain "
"features like __doc__ and __module__ proxying."
))
if request.node.get_closest_marker('xfail_simple'):
request.applymarker(pytest.mark.xfail(
reason="The lazy_object_proxy.simple.Proxy has some limitations."
))
return lop_subclass

1760
tests/test_async_py3.py Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

115
tox.ini Normal file
View File

@ -0,0 +1,115 @@
[testenv:bootstrap]
deps =
jinja2
matrix
tox
skip_install = true
commands =
python ci/bootstrap.py --no-env
passenv =
*
; a generative tox configuration, see: https://tox.readthedocs.io/en/latest/config.html#generative-envlist
[tox]
envlist =
clean,
check,
docs,
{py36,py37,py38,py39,py310,pypy37,pypy38}-{cover,nocov},
report
ignore_basepython_conflict = true
[testenv]
basepython =
pypy: {env:TOXPYTHON:pypy}
pypy37: {env:TOXPYTHON:pypy3.7}
pypy38: {env:TOXPYTHON:pypy3.8}
py27: {env:TOXPYTHON:python2.7}
py36: {env:TOXPYTHON:python3.6}
py37: {env:TOXPYTHON:python3.7}
py38: {env:TOXPYTHON:python3.8}
py39: {env:TOXPYTHON:python3.9}
py310: {env:TOXPYTHON:python3.10}
{bootstrap,clean,check,report,docs,codecov,coveralls,extension-coveralls}: {env:TOXPYTHON:python3}
setenv =
PYTHONPATH={toxinidir}/tests
PYTHONUNBUFFERED=yes
cover: SETUPPY_EXT_COVERAGE=yes
passenv =
*
usedevelop =
cover: true
nocov: false
wheel =
cover: false
nocov: true
deps =
pytest
pytest-benchmark
Django
objproxies==0.9.4
hunter
cover: pytest-cov
commands =
cover: python setup.py clean --all build_ext --force --inplace
nocov: {posargs:pytest -vv --ignore=src}
cover: {posargs:pytest --cov --cov-report=term-missing -vv}
[testenv:check]
deps =
docutils
flake8
readme-renderer
pygments
isort
setuptools-scm
skip_install = true
commands =
python setup.py check --strict --metadata --restructuredtext
flake8
isort --verbose --check-only --diff --filter-files .
[testenv:docs]
usedevelop = true
install_command =
python -m pip install --no-use-pep517 {opts} {packages}
deps =
-r{toxinidir}/docs/requirements.txt
commands =
sphinx-build {posargs:-E} -b html docs dist/docs
sphinx-build -b linkcheck docs dist/docs
[testenv:coveralls]
deps =
coveralls
skip_install = true
commands =
coveralls {env:COVERALLS_EXTRAS:--merge=extension-coveralls.json} []
[testenv:extension-coveralls]
deps =
cpp-coveralls
skip_install = true
commands =
coveralls --build-root=. --include=src --dump=extension-coveralls.json []
[testenv:codecov]
deps =
codecov
skip_install = true
commands =
codecov --gcov-root=. []
[testenv:report]
deps =
coverage
skip_install = true
commands =
coverage report
coverage html
[testenv:clean]
commands = coverage erase
skip_install = true
deps =
coverage