pax_global_header00006660000000000000000000000064145370545520014524gustar00rootroot0000000000000052 comment=aa46e846fa2eb7cb845a07e122f2984267551098 python-lazy-object-proxy-1.10.0/000077500000000000000000000000001453705455200165245ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/.bumpversion.cfg000066400000000000000000000014031453705455200216320ustar00rootroot00000000000000[bumpversion] current_version = 1.10.0 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}' [bumpversion:file:.cookiecutterrc] search = version: {current_version} replace = version: {new_version} python-lazy-object-proxy-1.10.0/.cookiecutterrc000066400000000000000000000030241453705455200215510ustar00rootroot00000000000000# Generated by cookiepatcher, a small shim around cookiecutter (pip install cookiepatcher) default_context: allow_tests_inside_package: 'no' c_extension_function: '-' c_extension_module: '-' c_extension_optional: 'yes' c_extension_support: 'yes' 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 formatter_quote_style: single full_name: Ionel Cristian Mărieș github_actions: 'yes' github_actions_osx: 'yes' github_actions_windows: 'yes' license: BSD 2-Clause License 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: '2023-01-04' repo_hosting: github.com repo_hosting_domain: github.com repo_main_branch: master repo_name: python-lazy-object-proxy repo_username: ionelmc scrutinizer: 'no' setup_py_uses_setuptools_scm: 'yes' sphinx_docs: 'yes' sphinx_docs_hosting: https://python-lazy-object-proxy.readthedocs.io/ sphinx_doctest: 'no' sphinx_theme: sphinx-py3doc-enhanced-theme test_matrix_separate_coverage: 'yes' version: 1.10.0 version_manager: bump2version website: https://blog.ionelmc.ro year_from: '2014' year_to: '2023' python-lazy-object-proxy-1.10.0/.coveragerc000066400000000000000000000002251453705455200206440ustar00rootroot00000000000000[paths] source = src [run] branch = true source = src tests parallel = true [report] show_missing = true precision = 2 omit = *migrations* python-lazy-object-proxy-1.10.0/.editorconfig000066400000000000000000000005411453705455200212010ustar00rootroot00000000000000# 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 python-lazy-object-proxy-1.10.0/.git-archival.txt000066400000000000000000000001751453705455200217200ustar00rootroot00000000000000node: $Format:%H$ node-date: $Format:%cI$ describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$ ref-names: $Format:%D$ python-lazy-object-proxy-1.10.0/.gitattributes000066400000000000000000000000371453705455200214170ustar00rootroot00000000000000.git_archival.txt export-subst python-lazy-object-proxy-1.10.0/.github/000077500000000000000000000000001453705455200200645ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/.github/FUNDING.yml000066400000000000000000000000431453705455200216760ustar00rootroot00000000000000tidelift: "pypi/lazy-object-proxy" python-lazy-object-proxy-1.10.0/.github/workflows/000077500000000000000000000000001453705455200221215ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/.github/workflows/github-actions.yml000066400000000000000000000533351453705455200255750ustar00rootroot00000000000000name: 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.11' toxpython: 'python3.11' tox_env: 'check' os: 'ubuntu-latest' - name: 'docs' python: '3.11' toxpython: 'python3.11' tox_env: 'docs' os: 'ubuntu-latest' - name: 'py38-cover (ubuntu/x86_64)' python: '3.8' toxpython: 'python3.8' python_arch: 'x64' tox_env: 'py38-cover' cover: true 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' cover: true 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' cover: true 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' cover: true 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' cover: true 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' cover: true 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' cover: true 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' cover: true 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' cover: true 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: 'py311-cover (ubuntu/x86_64)' python: '3.11' toxpython: 'python3.11' python_arch: 'x64' tox_env: 'py311-cover' cover: true cibw_arch: 'x86_64' cibw_build: false os: 'ubuntu-latest' - name: 'py311-cover (windows/AMD64)' python: '3.11' toxpython: 'python3.11' python_arch: 'x64' tox_env: 'py311-cover' cover: true cibw_arch: 'AMD64' cibw_build: false os: 'windows-latest' - name: 'py311-cover (macos/x86_64)' python: '3.11' toxpython: 'python3.11' python_arch: 'x64' tox_env: 'py311-cover' cover: true cibw_arch: 'x86_64' cibw_build: false os: 'macos-latest' - name: 'py311-nocov (ubuntu/x86_64/manylinux)' python: '3.11' toxpython: 'python3.11' python_arch: 'x64' tox_env: 'py311-nocov' cibw_arch: 'x86_64' cibw_build: 'cp311-*manylinux*' os: 'ubuntu-latest' - name: 'py311-nocov (ubuntu/x86_64/musllinux)' python: '3.11' toxpython: 'python3.11' python_arch: 'x64' tox_env: 'py311-nocov' cibw_arch: 'x86_64' cibw_build: 'cp311-*musllinux*' os: 'ubuntu-latest' - name: 'py311-nocov (ubuntu/aarch64/manylinux)' python: '3.11' toxpython: 'python3.11' python_arch: 'x64' tox_env: 'py311-nocov' cibw_arch: 'aarch64' cibw_build: 'cp311-*manylinux*' os: 'ubuntu-latest' - name: 'py311-nocov (ubuntu/aarch64/musllinux)' python: '3.11' toxpython: 'python3.11' python_arch: 'x64' tox_env: 'py311-nocov' cibw_arch: 'aarch64' cibw_build: 'cp311-*musllinux*' os: 'ubuntu-latest' - name: 'py311-nocov (windows/AMD64)' python: '3.11' toxpython: 'python3.11' python_arch: 'x64' tox_env: 'py311-nocov' cibw_arch: 'AMD64' cibw_build: 'cp311-*' os: 'windows-latest' - name: 'py311-nocov (windows/x86)' python: '3.11' toxpython: 'python3.11' python_arch: 'x86' tox_env: 'py311-nocov' cibw_arch: 'x86' cibw_build: 'cp311-*' os: 'windows-latest' - name: 'py311-nocov (macos/x86_64)' python: '3.11' toxpython: 'python3.11' python_arch: 'x64' tox_env: 'py311-nocov' cibw_arch: 'x86_64' cibw_build: 'cp311-*' os: 'macos-latest' - name: 'py312-cover (ubuntu/x86_64)' python: '3.12' toxpython: 'python3.12' python_arch: 'x64' tox_env: 'py312-cover' cover: true cibw_arch: 'x86_64' cibw_build: false os: 'ubuntu-latest' - name: 'py312-cover (windows/AMD64)' python: '3.12' toxpython: 'python3.12' python_arch: 'x64' tox_env: 'py312-cover' cover: true cibw_arch: 'AMD64' cibw_build: false os: 'windows-latest' - name: 'py312-cover (macos/x86_64)' python: '3.12' toxpython: 'python3.12' python_arch: 'x64' tox_env: 'py312-cover' cover: true cibw_arch: 'x86_64' cibw_build: false os: 'macos-latest' - name: 'py312-nocov (ubuntu/x86_64/manylinux)' python: '3.12' toxpython: 'python3.12' python_arch: 'x64' tox_env: 'py312-nocov' cibw_arch: 'x86_64' cibw_build: 'cp312-*manylinux*' os: 'ubuntu-latest' - name: 'py312-nocov (ubuntu/x86_64/musllinux)' python: '3.12' toxpython: 'python3.12' python_arch: 'x64' tox_env: 'py312-nocov' cibw_arch: 'x86_64' cibw_build: 'cp312-*musllinux*' os: 'ubuntu-latest' - name: 'py312-nocov (ubuntu/aarch64/manylinux)' python: '3.12' toxpython: 'python3.12' python_arch: 'x64' tox_env: 'py312-nocov' cibw_arch: 'aarch64' cibw_build: 'cp312-*manylinux*' os: 'ubuntu-latest' - name: 'py312-nocov (ubuntu/aarch64/musllinux)' python: '3.12' toxpython: 'python3.12' python_arch: 'x64' tox_env: 'py312-nocov' cibw_arch: 'aarch64' cibw_build: 'cp312-*musllinux*' os: 'ubuntu-latest' - name: 'py312-nocov (windows/AMD64)' python: '3.12' toxpython: 'python3.12' python_arch: 'x64' tox_env: 'py312-nocov' cibw_arch: 'AMD64' cibw_build: 'cp312-*' os: 'windows-latest' - name: 'py312-nocov (windows/x86)' python: '3.12' toxpython: 'python3.12' python_arch: 'x86' tox_env: 'py312-nocov' cibw_arch: 'x86' cibw_build: 'cp312-*' os: 'windows-latest' - name: 'py312-nocov (macos/x86_64)' python: '3.12' toxpython: 'python3.12' python_arch: 'x64' tox_env: 'py312-nocov' cibw_arch: 'x86_64' cibw_build: 'cp312-*' os: 'macos-latest' - name: 'pypy38-cover (ubuntu/x86_64)' python: 'pypy-3.8' toxpython: 'pypy3.8' python_arch: 'x64' tox_env: 'pypy38-cover' cover: true 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' cover: true 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' cover: true 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' - name: 'pypy39-cover (ubuntu/x86_64)' python: 'pypy-3.9' toxpython: 'pypy3.9' python_arch: 'x64' tox_env: 'pypy39-cover' cover: true cibw_arch: 'x86_64' cibw_build: false os: 'ubuntu-latest' - name: 'pypy39-cover (windows/AMD64)' python: 'pypy-3.9' toxpython: 'pypy3.9' python_arch: 'x64' tox_env: 'pypy39-cover' cover: true cibw_arch: 'AMD64' cibw_build: false os: 'windows-latest' - name: 'pypy39-cover (macos/x86_64)' python: 'pypy-3.9' toxpython: 'pypy3.9' python_arch: 'x64' tox_env: 'pypy39-cover' cover: true cibw_arch: 'x86_64' cibw_build: false os: 'macos-latest' - name: 'pypy39-nocov (ubuntu/x86_64/manylinux)' python: 'pypy-3.9' toxpython: 'pypy3.9' python_arch: 'x64' tox_env: 'pypy39-nocov' cibw_arch: 'x86_64' cibw_build: false os: 'ubuntu-latest' - name: 'pypy39-nocov (windows/AMD64)' python: 'pypy-3.9' toxpython: 'pypy3.9' python_arch: 'x64' tox_env: 'pypy39-nocov' cibw_arch: 'AMD64' cibw_build: false os: 'windows-latest' - name: 'pypy39-nocov (macos/x86_64)' python: 'pypy-3.9' toxpython: 'pypy3.9' python_arch: 'x64' tox_env: 'pypy39-nocov' cibw_arch: 'x86_64' cibw_build: false os: 'macos-latest' - name: 'pypy310-cover (ubuntu/x86_64)' python: 'pypy-3.10' toxpython: 'pypy3.10' python_arch: 'x64' tox_env: 'pypy310-cover' cover: true cibw_arch: 'x86_64' cibw_build: false os: 'ubuntu-latest' - name: 'pypy310-cover (windows/AMD64)' python: 'pypy-3.10' toxpython: 'pypy3.10' python_arch: 'x64' tox_env: 'pypy310-cover' cover: true cibw_arch: 'AMD64' cibw_build: false os: 'windows-latest' - name: 'pypy310-cover (macos/x86_64)' python: 'pypy-3.10' toxpython: 'pypy3.10' python_arch: 'x64' tox_env: 'pypy310-cover' cover: true cibw_arch: 'x86_64' cibw_build: false os: 'macos-latest' - name: 'pypy310-nocov (ubuntu/x86_64/manylinux)' python: 'pypy-3.10' toxpython: 'pypy3.10' python_arch: 'x64' tox_env: 'pypy310-nocov' cibw_arch: 'x86_64' cibw_build: false os: 'ubuntu-latest' - name: 'pypy310-nocov (windows/AMD64)' python: 'pypy-3.10' toxpython: 'pypy3.10' python_arch: 'x64' tox_env: 'pypy310-nocov' cibw_arch: 'AMD64' cibw_build: false os: 'windows-latest' - name: 'pypy310-nocov (macos/x86_64)' python: 'pypy-3.10' toxpython: 'pypy3.10' python_arch: 'x64' tox_env: 'pypy310-nocov' cibw_arch: 'x86_64' cibw_build: false os: 'macos-latest' steps: - uses: docker/setup-qemu-action@v3 if: matrix.cibw_arch == 'aarch64' with: platforms: arm64 - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} architecture: ${{ matrix.python_arch }} - name: install dependencies run: | python -mpip install --progress-bar=off 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 - uses: coverallsapp/github-action@v2 if: matrix.cover continue-on-error: true with: parallel: true flag-name: ${{ matrix.tox_env }} - uses: codecov/codecov-action@v3 if: matrix.cover with: verbose: true flags: ${{ matrix.tox_env }} - name: check wheel if: matrix.cibw_build run: twine check wheelhouse/*.whl - name: upload wheel uses: actions/upload-artifact@v3 if: matrix.cibw_build with: path: wheelhouse/*.whl finish: needs: test if: ${{ always() }} runs-on: ubuntu-latest steps: - uses: coverallsapp/github-action@v2 with: parallel-finished: true python-lazy-object-proxy-1.10.0/.gitignore000066400000000000000000000013271453705455200205170ustar00rootroot00000000000000*.py[cod] __pycache__ # Temp files .*.sw[po] *~ *.bak .DS_Store # C extensions *.so # Build and package files *.egg *.egg-info .bootstrap .build .cache .eggs .env .installed.cfg .ve bin build develop-eggs dist eggs lib lib64 parts pip-wheel-metadata/ pyvenv*/ sdist var venv*/ wheelhouse # Installer logs pip-log.txt # Unit test / coverage reports .benchmarks .coverage .coverage.* .pytest .pytest_cache/ .tox coverage.xml htmlcov nosetests.xml # Translations *.mo # Buildout .mr.developer.cfg # IDE project files *.iml *.komodoproject .idea .project .pydevproject .vscode # Complexity output/*.html output/*/index.html # Sphinx docs/_build # Mypy Cache .mypy_cache/ # Generated by setuptools-scm src/*/_version.py python-lazy-object-proxy-1.10.0/.pre-commit-config.yaml000066400000000000000000000012571453705455200230120ustar00rootroot00000000000000# To install the git pre-commit hooks run: # pre-commit install --install-hooks # To update the versions: # pre-commit autoupdate exclude: '^(\.tox|ci/templates|\.bumpversion\.cfg)(/|$)' # Note the order is intentional to avoid multiple passes of the hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.1.7 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix, --show-fixes] - repo: https://github.com/psf/black rev: 23.12.0 hooks: - id: black - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer - id: debug-statements python-lazy-object-proxy-1.10.0/.readthedocs.yml000066400000000000000000000004321453705455200216110ustar00rootroot00000000000000# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details version: 2 sphinx: configuration: docs/conf.py formats: all build: os: ubuntu-22.04 tools: python: "3" python: install: - requirements: docs/requirements.txt - method: pip path: . python-lazy-object-proxy-1.10.0/AUTHORS.rst000066400000000000000000000005101453705455200203770ustar00rootroot00000000000000 Authors ======= * Ionel Cristian Mărieș - https://blog.ionelmc.ro * Alvin Chow - https://github.com/alvinchow86 * Astrum Kuo - https://github.com/xowenx * Erik M. Bray - https://github.com/embray * Ran Benita - https://github.com/bluetech * "hugovk" - https://github.com/hugovk * Sandro Tosi - https://github.com/sandrotosi python-lazy-object-proxy-1.10.0/CHANGELOG.rst000066400000000000000000000115201453705455200205440ustar00rootroot00000000000000 Changelog ========= 1.10.0 (2023-12-15) ------------------- * Added Python 3.12 wheels. * Dropped support for Python 3.7. * Applied some reformatting and lint fixes using ruff to the codebase (mostly more Python 2 leftover cleanups). 1.9.0 (2023-01-04) ------------------ * Added support for matrix multiplication operator (``@``). * Should have all the wheels now (including the manylinux ones). * Bumped minimum version requirements for setuptools and setuptools-scm. * Switched the default pure python fallback implementation to the "simple" one (when you ``from lazy_object_proxy import Proxy`` and the C extension is not available). Previously the "slots" implementation was used but as it turns out it is slower on Python 3. 1.8.0 (2022-10-26) ------------------ * Cleaned up use of cPickle. Contributed by Sandro Tosi in `#62 `_. * Cleaned up more dead Python 2 code. * Added Python 3.11 wheels. * Dropped support for Python 3.6. 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 `_. 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 `_. * Dropped support for Python 2.6 and 3.3. Contributed by "hugovk" in `#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 `_ 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 `_. 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 `_. 1.0.2 (2015-04-11) ----------------------------------------- * First release on PyPI. python-lazy-object-proxy-1.10.0/CONTRIBUTING.rst000066400000000000000000000045751453705455200212000ustar00rootroot00000000000000============ 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 `_ 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 `_ (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 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 python-lazy-object-proxy-1.10.0/LICENSE000066400000000000000000000024621453705455200175350ustar00rootroot00000000000000BSD 2-Clause License Copyright (c) 2014-2023, 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. python-lazy-object-proxy-1.10.0/README.rst000066400000000000000000000067601453705455200202240ustar00rootroot00000000000000======== Overview ======== .. start-badges .. list-table:: :stub-columns: 1 * - docs - |docs| * - tests - | |github-actions| | |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 .. |coveralls| image:: https://coveralls.io/repos/github/ionelmc/python-lazy-object-proxy/badge.svg?branch=master :alt: Coverage Status :target: https://coveralls.io/github/ionelmc/python-lazy-object-proxy?branch=master .. |codecov| image:: https://codecov.io/gh/ionelmc/python-lazy-object-proxy/branch/master/graphs/badge.svg?branch=master :alt: Coverage Status :target: https://app.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.10.0.svg :alt: Commits since latest release :target: https://github.com/ionelmc/python-lazy-object-proxy/compare/v1.10.0...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 python-lazy-object-proxy-1.10.0/ci/000077500000000000000000000000001453705455200171175ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/ci/bootstrap.py000077500000000000000000000054631453705455200215210ustar00rootroot00000000000000#!/usr/bin/env python import os import pathlib import subprocess import sys base_path: pathlib.Path = pathlib.Path(__file__).resolve().parent.parent templates_path = base_path / 'ci' / 'templates' def check_call(args): print('+', *args) subprocess.check_call(args) def exec_in_env(): env_path = base_path / '.tox' / 'bootstrap' if sys.platform == 'win32': bin_path = env_path / 'Scripts' else: bin_path = env_path / 'bin' if not env_path.exists(): import subprocess print(f'Making bootstrap env in: {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([bin_path / 'pip', 'install', 'jinja2', 'tox']) python_executable = bin_path / 'python' if not python_executable.exists(): python_executable = python_executable.with_suffix('.exe') print(f'Re-executing with: {python_executable}') print('+ exec', python_executable, __file__, '--no-env') os.execv(python_executable, [python_executable, __file__, '--no-env']) def main(): import jinja2 print(f'Project path: {base_path}') jinja = jinja2.Environment( loader=jinja2.FileSystemLoader(str(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 template in templates_path.rglob('*'): if template.is_file(): template_path = template.relative_to(templates_path).as_posix() destination = base_path / template_path destination.parent.mkdir(parents=True, exist_ok=True) destination.write_text(jinja.get_template(template_path).render(tox_environments=tox_environments)) print(f'Wrote {template_path}') print('DONE.') if __name__ == '__main__': args = sys.argv[1:] if args == ['--no-env']: main() elif not args: exec_in_env() else: print(f'Unexpected arguments: {args}', file=sys.stderr) sys.exit(1) python-lazy-object-proxy-1.10.0/ci/requirements.txt000066400000000000000000000001101453705455200223730ustar00rootroot00000000000000virtualenv>=16.6.0 pip>=19.1.1 setuptools>=18.0.1 six>=1.14.0 tox twine python-lazy-object-proxy-1.10.0/ci/templates/000077500000000000000000000000001453705455200211155ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/ci/templates/.github/000077500000000000000000000000001453705455200224555ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/ci/templates/.github/workflows/000077500000000000000000000000001453705455200245125ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/ci/templates/.github/workflows/github-actions.yml000066400000000000000000000106441453705455200301620ustar00rootroot00000000000000name: 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.11' toxpython: 'python3.11' tox_env: 'check' os: 'ubuntu-latest' - name: 'docs' python: '3.11' toxpython: 'python3.11' 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 %} cover: true {% 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@v3 if: matrix.cibw_arch == 'aarch64' with: platforms: arm64 - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: actions/setup-python@v5 with: python-version: {{ '${{ matrix.python }}' }} architecture: {{ '${{ matrix.python_arch }}' }} - name: install dependencies run: | python -mpip install --progress-bar=off 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 - uses: coverallsapp/github-action@v2 if: matrix.cover continue-on-error: true with: parallel: true flag-name: {{ '${{ matrix.tox_env }}' }} - uses: codecov/codecov-action@v3 if: matrix.cover with: verbose: true flags: {{ '${{ matrix.tox_env }}' }} - name: check wheel if: matrix.cibw_build run: twine check wheelhouse/*.whl - name: upload wheel uses: actions/upload-artifact@v3 if: matrix.cibw_build with: path: wheelhouse/*.whl finish: needs: test if: {{ '${{ always() }}' }} runs-on: ubuntu-latest steps: - uses: coverallsapp/github-action@v2 with: parallel-finished: true python-lazy-object-proxy-1.10.0/docs/000077500000000000000000000000001453705455200174545ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/docs/authors.rst000066400000000000000000000000341453705455200216700ustar00rootroot00000000000000.. include:: ../AUTHORS.rst python-lazy-object-proxy-1.10.0/docs/changelog.rst000066400000000000000000000000361453705455200221340ustar00rootroot00000000000000.. include:: ../CHANGELOG.rst python-lazy-object-proxy-1.10.0/docs/conf.py000066400000000000000000000026071453705455200207600ustar00rootroot00000000000000import 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-2023' author = 'Ionel Cristian Mărieș' copyright = f'{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.10.0' 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 = f'{project}-{version}' napoleon_use_ivar = True napoleon_use_rtype = False napoleon_use_param = False python-lazy-object-proxy-1.10.0/docs/contributing.rst000066400000000000000000000000411453705455200227100ustar00rootroot00000000000000.. include:: ../CONTRIBUTING.rst python-lazy-object-proxy-1.10.0/docs/index.rst000066400000000000000000000003411453705455200213130ustar00rootroot00000000000000======== Contents ======== .. toctree:: :maxdepth: 2 readme installation usage contributing authors changelog Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` python-lazy-object-proxy-1.10.0/docs/installation.rst000066400000000000000000000001411453705455200227030ustar00rootroot00000000000000============ Installation ============ At the command line:: pip install lazy-object-proxy python-lazy-object-proxy-1.10.0/docs/readme.rst000066400000000000000000000000331453705455200214370ustar00rootroot00000000000000.. include:: ../README.rst python-lazy-object-proxy-1.10.0/docs/requirements.txt000066400000000000000000000000511453705455200227340ustar00rootroot00000000000000sphinx>=1.3 sphinx-py3doc-enhanced-theme python-lazy-object-proxy-1.10.0/docs/spelling_wordlist.txt000066400000000000000000000001551453705455200237620ustar00rootroot00000000000000builtin builtins classmethod staticmethod classmethods staticmethods args kwargs callstack Changelog Indices python-lazy-object-proxy-1.10.0/docs/usage.rst000066400000000000000000000001261453705455200213110ustar00rootroot00000000000000===== Usage ===== To use lazy-object-proxy in a project:: import lazy_object_proxy python-lazy-object-proxy-1.10.0/pyproject.toml000066400000000000000000000026231453705455200214430ustar00rootroot00000000000000[build-system] requires = [ "setuptools>=64", "setuptools_scm>=8", ] build-backend = "setuptools.build_meta" [tool.setuptools_scm] [tool.ruff.per-file-ignores] "ci/*" = ["S"] [tool.ruff] extend-exclude = ["static", "ci/templates"] ignore = [ "RUF001", # ruff-specific rules ambiguous-unicode-character-string "S101", # flake8-bandit assert "S308", # flake8-bandit suspicious-mark-safe-usage "E501", # pycodestyle line-too-long "DTZ001", "PT011", "PT012", "B004", "S102", ] line-length = 140 select = [ "B", # flake8-bugbear "C4", # flake8-comprehensions "DTZ", # flake8-datetimez "E", # pycodestyle errors "EXE", # flake8-executable "F", # pyflakes "I", # isort "INT", # flake8-gettext "PIE", # flake8-pie "PLC", # pylint convention "PLE", # pylint errors "PT", # flake8-pytest-style "PTH", # flake8-use-pathlib "Q", # flake8-quotes "RSE", # flake8-raise "RUF", # ruff-specific rules "S", # flake8-bandit "UP", # pyupgrade "W", # pycodestyle warnings ] src = ["src", "tests"] target-version = "py38" [tool.ruff.flake8-pytest-style] fixture-parentheses = false mark-parentheses = false [tool.ruff.isort] forced-separate = ["conftest"] force-single-line = true [tool.black] line-length = 140 target-version = ["py38"] skip-string-normalization = true [tool.ruff.flake8-quotes] inline-quotes = "single" python-lazy-object-proxy-1.10.0/pytest.ini000066400000000000000000000020451453705455200205560ustar00rootroot00000000000000[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 # Idea from: https://til.simonwillison.net/pytest/treat-warnings-as-errors filterwarnings = error # You can add exclusions, some examples: # ignore:'lazy_object_proxy' defines default_app_config:PendingDeprecationWarning:: # ignore:The {{% if::: # ignore:Coverage disabled via --no-cov switch! python-lazy-object-proxy-1.10.0/setup.py000077500000000000000000000123641453705455200202470ustar00rootroot00000000000000#!/usr/bin/env python import os import platform import re import sys from pathlib import Path 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 cannot 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 = '' allow_extensions = True if '__pypy__' in sys.builtin_module_names: print('NOTICE: C extensions disabled on PyPy (would be broken)!') allow_extensions = False if os.environ.get('SETUPPY_FORCE_PURE'): print('NOTICE: C extensions disabled (SETUPPY_FORCE_PURE)!') allow_extensions = False 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) 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') def read(*names, **kwargs): with Path(__file__).parent.joinpath(*names).open(encoding=kwargs.get('encoding', 'utf8')) as fh: return fh.read() setup( name='lazy-object-proxy', use_scm_version={ 'local_scheme': 'dirty-tag', 'write_to': 'src/lazy_object_proxy/_version.py', 'fallback_version': '1.10.0', }, license='BSD-2-Clause', description='A fast and thorough lazy object proxy.', long_description='{}\n{}'.format( 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=[path.stem for path in Path('src').glob('*.py')], include_package_data=True, 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', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', # 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.8', install_requires=[ # eg: "aspectlib==1.1.1", "six>=1.7", ], extras_require={ # eg: # "rst": ["docutils>=0.11"], # ":python_version=="2.6"": ["argparse"], }, setup_requires=[ 'setuptools_scm>=3.3.1', ], cmdclass={'build_ext': OptionalBuildExt}, ext_modules=[ Extension( str(path.relative_to('src').with_suffix('')).replace(os.sep, '.'), sources=[str(path)], extra_compile_args=CFLAGS.split(), extra_link_args=LFLAGS.split(), include_dirs=[str(path.parent)], ) for path in Path('src').glob('**/*.c') ] if allow_extensions else [], distclass=BinaryDistribution, ) python-lazy-object-proxy-1.10.0/src/000077500000000000000000000000001453705455200173135ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/src/lazy_object_proxy/000077500000000000000000000000001453705455200230615ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/src/lazy_object_proxy/__init__.py000066400000000000000000000006361453705455200251770ustar00rootroot00000000000000try: 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 .simple import Proxy else: copyreg.constructor(identity) try: from ._version import version as __version__ except ImportError: __version__ = '1.10.0' __all__ = ('Proxy',) python-lazy-object-proxy-1.10.0/src/lazy_object_proxy/cext.c000066400000000000000000001142761453705455200242030ustar00rootroot00000000000000/* ------------------------------------------------------------------------- */ #include "Python.h" #include "structmember.h" #define Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(object) \ if (PyObject_TypeCheck(object, &Proxy_Type)) { \ object = Proxy__ensure_wrapped((ProxyObject *)object); \ if (!object) return NULL; \ } #define Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self) if (!Proxy__ensure_wrapped(self)) return NULL; #define Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self) if (!Proxy__ensure_wrapped(self)) return -1; /* ------------------------------------------------------------------------- */ typedef struct { PyObject_HEAD PyObject *dict; PyObject *wrapped; PyObject *factory; } ProxyObject; PyTypeObject Proxy_Type; /* ------------------------------------------------------------------------- */ static PyObject *identity_ref = NULL; static PyObject *await_ref = NULL; static PyObject * identity(PyObject *self, PyObject *value) { Py_INCREF(value); return value; } /* ------------------------------------------------------------------------- */ PyDoc_STRVAR(identity_doc, "Indentity function: returns the single argument."); static struct PyMethodDef module_functions[] = { {"identity", identity, METH_O, identity_doc}, {NULL, NULL} }; /* ------------------------------------------------------------------------- */ static PyObject *Proxy__ensure_wrapped(ProxyObject *self) { PyObject *wrapped; if (self->wrapped) { return self->wrapped; } else { if (self->factory) { wrapped = PyObject_CallFunctionObjArgs(self->factory, NULL); if (wrapped) { self->wrapped = wrapped; return wrapped; } else { return NULL; } } else { PyErr_SetString(PyExc_ValueError, "Proxy hasn't been initiated: __factory__ is missing."); return NULL; } } } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { ProxyObject *self; self = (ProxyObject *)type->tp_alloc(type, 0); if (!self) return NULL; self->dict = PyDict_New(); self->wrapped = NULL; self->factory = NULL; return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static int Proxy_raw_init(ProxyObject *self, PyObject *factory) { Py_INCREF(factory); Py_XDECREF(self->wrapped); Py_XDECREF(self->factory); self->factory = factory; return 0; } /* ------------------------------------------------------------------------- */ static int Proxy_init(ProxyObject *self, PyObject *args, PyObject *kwds) { PyObject *wrapped = NULL; static char *kwlist[] = { "wrapped", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:ObjectProxy", kwlist, &wrapped)) { return -1; } return Proxy_raw_init(self, wrapped); } /* ------------------------------------------------------------------------- */ static int Proxy_traverse(ProxyObject *self, visitproc visit, void *arg) { Py_VISIT(self->dict); Py_VISIT(self->wrapped); Py_VISIT(self->factory); return 0; } /* ------------------------------------------------------------------------- */ static int Proxy_clear(ProxyObject *self) { Py_CLEAR(self->dict); Py_CLEAR(self->wrapped); Py_CLEAR(self->factory); return 0; } /* ------------------------------------------------------------------------- */ static void Proxy_dealloc(ProxyObject *self) { PyObject_GC_UnTrack(self); Proxy_clear(self); Py_TYPE(self)->tp_free(self); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_repr(ProxyObject *self) { if (self->wrapped) { return PyUnicode_FromFormat("<%s at %p wrapping %R at %p with factory %R>", Py_TYPE(self)->tp_name, self, self->wrapped, self->wrapped, self->factory); } else { return PyUnicode_FromFormat("<%s at %p with factory %R>", Py_TYPE(self)->tp_name, self, self->factory); } } /* ------------------------------------------------------------------------- */ static Py_hash_t Proxy_hash(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); return PyObject_Hash(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_str(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_Str(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_fspath(ProxyObject *self) { PyObject *method = NULL; PyObject *fspath = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); if (PyUnicode_Check(self->wrapped) || PyBytes_Check(self->wrapped)) { Py_INCREF(self->wrapped); return self->wrapped; } method = PyObject_GetAttrString(self->wrapped, "__fspath__"); if (!method) { PyErr_Clear(); Py_INCREF(self->wrapped); return self->wrapped; } fspath = PyObject_CallFunctionObjArgs(method, NULL); Py_DECREF(method); return fspath; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_add(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Add(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_subtract(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Subtract(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_multiply(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Multiply(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_matrix_multiply(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_MatrixMultiply(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_remainder(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Remainder(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_divmod(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Divmod(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_power(PyObject *o1, PyObject *o2, PyObject *modulo) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Power(o1, o2, modulo); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_negative(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyNumber_Negative(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_positive(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyNumber_Positive(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_absolute(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyNumber_Absolute(self->wrapped); } /* ------------------------------------------------------------------------- */ static int Proxy_bool(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); return PyObject_IsTrue(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_invert(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyNumber_Invert(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_lshift(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Lshift(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_rshift(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Rshift(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_and(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_And(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_xor(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Xor(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_or(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_Or(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_long(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyNumber_Long(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_float(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyNumber_Float(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_add(ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceAdd(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_subtract( ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceSubtract(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_multiply( ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceMultiply(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_matrix_multiply( ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceMatrixMultiply(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_remainder( ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceRemainder(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_power(ProxyObject *self, PyObject *other, PyObject *modulo) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlacePower(self->wrapped, other, modulo); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_lshift(ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceLshift(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_rshift(ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceRshift(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_and(ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceAnd(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_xor(ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceXor(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_or(ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceOr(self->wrapped, other); Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_floor_divide(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_FloorDivide(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_true_divide(PyObject *o1, PyObject *o2) { Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o1); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(o2); return PyNumber_TrueDivide(o1, o2); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_floor_divide( ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceFloorDivide(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_inplace_true_divide( ProxyObject *self, PyObject *other) { PyObject *object = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Proxy__WRAPPED_REPLACE_OR_RETURN_NULL(other); object = PyNumber_InPlaceTrueDivide(self->wrapped, other); if (!object) return NULL; Py_DECREF(self->wrapped); self->wrapped = object; Py_INCREF(self); return (PyObject *)self; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_index(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyNumber_Index(self->wrapped); } /* ------------------------------------------------------------------------- */ static Py_ssize_t Proxy_length(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); return PyObject_Length(self->wrapped); } /* ------------------------------------------------------------------------- */ static int Proxy_contains(ProxyObject *self, PyObject *value) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); return PySequence_Contains(self->wrapped, value); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_getitem(ProxyObject *self, PyObject *key) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_GetItem(self->wrapped, key); } /* ------------------------------------------------------------------------- */ static int Proxy_setitem(ProxyObject *self, PyObject *key, PyObject* value) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); if (value == NULL) return PyObject_DelItem(self->wrapped, key); else return PyObject_SetItem(self->wrapped, key, value); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_dir( ProxyObject *self, PyObject *args) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_Dir(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_enter(ProxyObject *self) { PyObject *method = NULL; PyObject *result = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); method = PyObject_GetAttrString(self->wrapped, "__enter__"); if (!method) return NULL; result = PyObject_CallObject(method, NULL); Py_DECREF(method); return result; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_exit( ProxyObject *self, PyObject *args, PyObject *kwds) { PyObject *method = NULL; PyObject *result = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); method = PyObject_GetAttrString(self->wrapped, "__exit__"); if (!method) return NULL; result = PyObject_Call(method, args, kwds); Py_DECREF(method); return result; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_bytes( ProxyObject *self, PyObject *args) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_Bytes(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_reversed( ProxyObject *self, PyObject *args) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_CallFunctionObjArgs((PyObject *)&PyReversed_Type, self->wrapped, NULL); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_reduce( ProxyObject *self, PyObject *args) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return Py_BuildValue("(O(O))", identity_ref, self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_round( ProxyObject *self, PyObject *args) { PyObject *module = NULL; PyObject *dict = NULL; PyObject *round = NULL; PyObject *result = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); module = PyImport_ImportModule("builtins"); if (!module) return NULL; dict = PyModule_GetDict(module); round = PyDict_GetItemString(dict, "round"); if (!round) { Py_DECREF(module); return NULL; } Py_INCREF(round); Py_DECREF(module); result = PyObject_CallFunctionObjArgs(round, self->wrapped, NULL); Py_DECREF(round); return result; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_get_name( ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_GetAttrString(self->wrapped, "__name__"); } /* ------------------------------------------------------------------------- */ static int Proxy_set_name(ProxyObject *self, PyObject *value) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); return PyObject_SetAttrString(self->wrapped, "__name__", value); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_get_qualname( ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_GetAttrString(self->wrapped, "__qualname__"); } /* ------------------------------------------------------------------------- */ static int Proxy_set_qualname(ProxyObject *self, PyObject *value) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); return PyObject_SetAttrString(self->wrapped, "__qualname__", value); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_get_module( ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_GetAttrString(self->wrapped, "__module__"); } /* ------------------------------------------------------------------------- */ static int Proxy_set_module(ProxyObject *self, PyObject *value) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); if (PyObject_SetAttrString(self->wrapped, "__module__", value) == -1) return -1; return PyDict_SetItemString(self->dict, "__module__", value); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_get_doc( ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_GetAttrString(self->wrapped, "__doc__"); } /* ------------------------------------------------------------------------- */ static int Proxy_set_doc(ProxyObject *self, PyObject *value) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); if (PyObject_SetAttrString(self->wrapped, "__doc__", value) == -1) return -1; return PyDict_SetItemString(self->dict, "__doc__", value); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_get_class( ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_GetAttrString(self->wrapped, "__class__"); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_get_annotations( ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_GetAttrString(self->wrapped, "__annotations__"); } /* ------------------------------------------------------------------------- */ static int Proxy_set_annotations(ProxyObject *self, PyObject *value) { Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); return PyObject_SetAttrString(self->wrapped, "__annotations__", value); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_get_resolved( ProxyObject *self) { PyObject *result; result = self->wrapped ? Py_True : Py_False; Py_INCREF(result); return result; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_get_wrapped( ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); Py_INCREF(self->wrapped); return self->wrapped; } /* ------------------------------------------------------------------------- */ static int Proxy_set_wrapped(ProxyObject *self, PyObject *value) { if (value) Py_INCREF(value); Py_XDECREF(self->wrapped); self->wrapped = value; return 0; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_get_factory( ProxyObject *self) { Py_INCREF(self->factory); return self->factory; } /* ------------------------------------------------------------------------- */ static int Proxy_set_factory(ProxyObject *self, PyObject *value) { if (value) Py_INCREF(value); Py_XDECREF(self->factory); self->factory = value; return 0; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_getattro( ProxyObject *self, PyObject *name) { PyObject *object = NULL; PyObject *result = NULL; static PyObject *getattr_str = NULL; object = PyObject_GenericGetAttr((PyObject *)self, name); if (object) return object; PyErr_Clear(); if (!getattr_str) { getattr_str = PyUnicode_InternFromString("__getattr__"); } object = PyObject_GenericGetAttr((PyObject *)self, getattr_str); if (!object) return NULL; result = PyObject_CallFunctionObjArgs(object, name, NULL); Py_DECREF(object); return result; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_getattr( ProxyObject *self, PyObject *args) { PyObject *name = NULL; if (!PyArg_ParseTuple(args, "U:__getattr__", &name)) return NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_GetAttr(self->wrapped, name); } /* ------------------------------------------------------------------------- */ static int Proxy_setattro( ProxyObject *self, PyObject *name, PyObject *value) { if (PyObject_HasAttr((PyObject *)Py_TYPE(self), name)) return PyObject_GenericSetAttr((PyObject *)self, name, value); Proxy__ENSURE_WRAPPED_OR_RETURN_MINUS1(self); return PyObject_SetAttr(self->wrapped, name, value); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_richcompare(ProxyObject *self, PyObject *other, int opcode) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_RichCompare(self->wrapped, other, opcode); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_iter(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_GetIter(self->wrapped); } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_call( ProxyObject *self, PyObject *args, PyObject *kwds) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_Call(self->wrapped, args, kwds); } /* ------------------------------------------------------------------------- */; static PyObject *Proxy_aenter(ProxyObject *self) { PyObject *method = NULL; PyObject *result = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); method = PyObject_GetAttrString(self->wrapped, "__aenter__"); if (!method) return NULL; result = PyObject_CallObject(method, NULL); Py_DECREF(method); return result; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_aexit( ProxyObject *self, PyObject *args, PyObject *kwds) { PyObject *method = NULL; PyObject *result = NULL; Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); method = PyObject_GetAttrString(self->wrapped, "__aexit__"); if (!method) return NULL; result = PyObject_Call(method, args, kwds); Py_DECREF(method); return result; } /* ------------------------------------------------------------------------- */ static PyObject *Proxy_await(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); return PyObject_CallFunctionObjArgs(await_ref, self->wrapped, NULL); } /* ------------------------------------------------------------------------- */; static PyObject *Proxy_aiter(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); unaryfunc meth = NULL; PyObject *wrapped = self->wrapped; PyTypeObject *type = Py_TYPE(wrapped); if (type->tp_as_async != NULL) { meth = type->tp_as_async->am_aiter; } if (meth != NULL) { return (*meth)(wrapped); } PyErr_Format(PyExc_AttributeError, "'%.100s' object has no attribute '__aiter__'", type->tp_name); return NULL; } /* ------------------------------------------------------------------------- */; static PyObject *Proxy_anext(ProxyObject *self) { Proxy__ENSURE_WRAPPED_OR_RETURN_NULL(self); unaryfunc meth = NULL; PyObject *wrapped = self->wrapped; PyTypeObject *type = Py_TYPE(wrapped); if (type->tp_as_async != NULL) { meth = type->tp_as_async->am_anext; } if (meth != NULL) { return (*meth)(wrapped); } PyErr_Format(PyExc_TypeError, "'%.100s' is missing the __anext__ method", type->tp_name); return NULL; } /* ------------------------------------------------------------------------- */; static PyNumberMethods Proxy_as_number = { (binaryfunc)Proxy_add, /*nb_add*/ (binaryfunc)Proxy_subtract, /*nb_subtract*/ (binaryfunc)Proxy_multiply, /*nb_multiply*/ (binaryfunc)Proxy_remainder, /*nb_remainder*/ (binaryfunc)Proxy_divmod, /*nb_divmod*/ (ternaryfunc)Proxy_power, /*nb_power*/ (unaryfunc)Proxy_negative, /*nb_negative*/ (unaryfunc)Proxy_positive, /*nb_positive*/ (unaryfunc)Proxy_absolute, /*nb_absolute*/ (inquiry)Proxy_bool, /*nb_nonzero/nb_bool*/ (unaryfunc)Proxy_invert, /*nb_invert*/ (binaryfunc)Proxy_lshift, /*nb_lshift*/ (binaryfunc)Proxy_rshift, /*nb_rshift*/ (binaryfunc)Proxy_and, /*nb_and*/ (binaryfunc)Proxy_xor, /*nb_xor*/ (binaryfunc)Proxy_or, /*nb_or*/ (unaryfunc)Proxy_long, /*nb_int*/ 0, /*nb_long/nb_reserved*/ (unaryfunc)Proxy_float, /*nb_float*/ (binaryfunc)Proxy_inplace_add, /*nb_inplace_add*/ (binaryfunc)Proxy_inplace_subtract, /*nb_inplace_subtract*/ (binaryfunc)Proxy_inplace_multiply, /*nb_inplace_multiply*/ (binaryfunc)Proxy_inplace_remainder, /*nb_inplace_remainder*/ (ternaryfunc)Proxy_inplace_power, /*nb_inplace_power*/ (binaryfunc)Proxy_inplace_lshift, /*nb_inplace_lshift*/ (binaryfunc)Proxy_inplace_rshift, /*nb_inplace_rshift*/ (binaryfunc)Proxy_inplace_and, /*nb_inplace_and*/ (binaryfunc)Proxy_inplace_xor, /*nb_inplace_xor*/ (binaryfunc)Proxy_inplace_or, /*nb_inplace_or*/ (binaryfunc)Proxy_floor_divide, /*nb_floor_divide*/ (binaryfunc)Proxy_true_divide, /*nb_true_divide*/ (binaryfunc)Proxy_inplace_floor_divide, /*nb_inplace_floor_divide*/ (binaryfunc)Proxy_inplace_true_divide, /*nb_inplace_true_divide*/ (unaryfunc)Proxy_index, /*nb_index*/ (binaryfunc)Proxy_matrix_multiply, /*nb_matrix_multiply*/ (binaryfunc)Proxy_inplace_matrix_multiply, /*nb_inplace_matrix_multiply*/ }; static PySequenceMethods Proxy_as_sequence = { (lenfunc)Proxy_length, /*sq_length*/ 0, /*sq_concat*/ 0, /*sq_repeat*/ 0, /*sq_item*/ 0, /*sq_slice*/ 0, /*sq_ass_item*/ 0, /*sq_ass_slice*/ (objobjproc)Proxy_contains, /* sq_contains */ }; static PyMappingMethods Proxy_as_mapping = { (lenfunc)Proxy_length, /*mp_length*/ (binaryfunc)Proxy_getitem, /*mp_subscript*/ (objobjargproc)Proxy_setitem, /*mp_ass_subscript*/ }; static PyAsyncMethods Proxy_as_async = { (unaryfunc)Proxy_await, /* am_await */ (unaryfunc)Proxy_aiter, /* am_aiter */ (unaryfunc)Proxy_anext, /* am_anext */ }; static PyMethodDef Proxy_methods[] = { { "__dir__", (PyCFunction)Proxy_dir, METH_NOARGS, 0 }, { "__enter__", (PyCFunction)Proxy_enter, METH_NOARGS, 0 }, { "__exit__", (PyCFunction)Proxy_exit, METH_VARARGS | METH_KEYWORDS, 0 }, { "__getattr__", (PyCFunction)Proxy_getattr, METH_VARARGS , 0 }, { "__bytes__", (PyCFunction)Proxy_bytes, METH_NOARGS, 0 }, { "__reversed__", (PyCFunction)Proxy_reversed, METH_NOARGS, 0 }, { "__reduce__", (PyCFunction)Proxy_reduce, METH_NOARGS, 0 }, { "__reduce_ex__", (PyCFunction)Proxy_reduce, METH_O, 0 }, { "__fspath__", (PyCFunction)Proxy_fspath, METH_NOARGS, 0 }, { "__round__", (PyCFunction)Proxy_round, METH_NOARGS, 0 }, { "__aenter__", (PyCFunction)Proxy_aenter, METH_NOARGS, 0 }, { "__aexit__", (PyCFunction)Proxy_aexit, METH_VARARGS | METH_KEYWORDS, 0 }, { NULL, NULL }, }; static PyGetSetDef Proxy_getset[] = { { "__name__", (getter)Proxy_get_name, (setter)Proxy_set_name, 0 }, { "__qualname__", (getter)Proxy_get_qualname, (setter)Proxy_set_qualname, 0 }, { "__module__", (getter)Proxy_get_module, (setter)Proxy_set_module, 0 }, { "__doc__", (getter)Proxy_get_doc, (setter)Proxy_set_doc, 0 }, { "__class__", (getter)Proxy_get_class, NULL, 0 }, { "__annotations__", (getter)Proxy_get_annotations, (setter)Proxy_set_annotations, 0 }, { "__wrapped__", (getter)Proxy_get_wrapped, (setter)Proxy_set_wrapped, 0 }, { "__factory__", (getter)Proxy_get_factory, (setter)Proxy_set_factory, 0 }, { "__resolved__", (getter)Proxy_get_resolved, NULL, 0 }, { NULL }, }; PyTypeObject Proxy_Type = { PyVarObject_HEAD_INIT(NULL, 0) "Proxy", /*tp_name*/ sizeof(ProxyObject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)Proxy_dealloc, /*tp_dealloc*/ 0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ &Proxy_as_async, /* tp_as_async */ (unaryfunc)Proxy_repr, /*tp_repr*/ &Proxy_as_number, /*tp_as_number*/ &Proxy_as_sequence, /*tp_as_sequence*/ &Proxy_as_mapping, /*tp_as_mapping*/ (hashfunc)Proxy_hash, /*tp_hash*/ (ternaryfunc)Proxy_call, /*tp_call*/ (unaryfunc)Proxy_str, /*tp_str*/ (getattrofunc)Proxy_getattro, /*tp_getattro*/ (setattrofunc)Proxy_setattro, /*tp_setattro*/ 0, /*tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ 0, /*tp_doc*/ (traverseproc)Proxy_traverse, /*tp_traverse*/ (inquiry)Proxy_clear, /*tp_clear*/ (richcmpfunc)Proxy_richcompare, /*tp_richcompare*/ 0, /*tp_weaklistoffset*/ (getiterfunc)Proxy_iter, /*tp_iter*/ 0, /*tp_iternext*/ Proxy_methods, /*tp_methods*/ 0, /*tp_members*/ Proxy_getset, /*tp_getset*/ 0, /*tp_base*/ 0, /*tp_dict*/ 0, /*tp_descr_get*/ 0, /*tp_descr_set*/ offsetof(ProxyObject, dict), /*tp_dictoffset*/ (initproc)Proxy_init, /*tp_init*/ PyType_GenericAlloc, /*tp_alloc*/ Proxy_new, /*tp_new*/ PyObject_GC_Del, /*tp_free*/ 0, /*tp_is_gc*/ }; /* ------------------------------------------------------------------------- */ static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "lazy_object_proxy.cext", /* m_name */ NULL, /* m_doc */ -1, /* m_size */ module_functions, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ }; static PyObject * moduleinit(void) { PyObject *module; PyObject *dict; module = PyModule_Create(&moduledef); if (module == NULL) return NULL; if (PyType_Ready(&Proxy_Type) < 0) return NULL; dict = PyModule_GetDict(module); if (dict == NULL) return NULL; identity_ref = PyDict_GetItemString(dict, "identity"); if (identity_ref == NULL) return NULL; Py_INCREF(identity_ref); PyObject *utils_module = PyImport_ImportModule("lazy_object_proxy.utils"); if (utils_module == NULL) return NULL; await_ref = PyObject_GetAttrString(utils_module, "await_"); Py_DECREF(utils_module); if (await_ref == NULL) return NULL; Py_INCREF(&Proxy_Type); PyModule_AddObject(module, "Proxy", (PyObject *)&Proxy_Type); return module; } PyMODINIT_FUNC PyInit_cext(void) { return moduleinit(); } /* ------------------------------------------------------------------------- */ python-lazy-object-proxy-1.10.0/src/lazy_object_proxy/compat.py000066400000000000000000000002241453705455200247140ustar00rootroot00000000000000string_types = str, bytes def with_metaclass(meta, *bases): """Create a base class with a metaclass.""" return meta('NewBase', bases, {}) python-lazy-object-proxy-1.10.0/src/lazy_object_proxy/simple.py000066400000000000000000000207501453705455200247300ustar00rootroot00000000000000import operator 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: # 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) __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 f'<{type(self).__name__} at 0x{id(self):x} with factory {self.__factory__!r}>' 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) __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) __matmul__ = make_proxy_method(operator.matmul) __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 __rmatmul__(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) __imatmul__ = make_proxy_method(operator.imatmul) __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) __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) 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 python-lazy-object-proxy-1.10.0/src/lazy_object_proxy/slots.py000066400000000000000000000276271453705455200246150ustar00rootroot00000000000000import operator from .compat import string_types from .compat import with_metaclass from .utils import await_ from .utils import identity class _ProxyMethods: # 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 as exc: raise ValueError("Proxy hasn't been initiated: __factory__ is missing.") from exc 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 def __class__(self, value): 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__) def __bytes__(self): return bytes(self.__wrapped__) def __repr__(self, __getattr__=object.__getattribute__): try: target = __getattr__(self, '__target__') except AttributeError: return f'<{type(self).__name__} at 0x{id(self):x} with factory {self.__factory__!r}>' else: return f'<{type(self).__name__} at 0x{id(self):x} wrapping {target!r} at 0x{id(target):x} with factory {self.__factory__!r}>' 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__) 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 __matmul__(self, other): return 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 __rmatmul__(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 __imatmul__(self, other): 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__) 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 python-lazy-object-proxy-1.10.0/src/lazy_object_proxy/utils.py000066400000000000000000000022651453705455200246000ustar00rootroot00000000000000from 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) def identity(obj): return obj class cached_property: 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 python-lazy-object-proxy-1.10.0/tests/000077500000000000000000000000001453705455200176665ustar00rootroot00000000000000python-lazy-object-proxy-1.10.0/tests/conftest.py000066400000000000000000000044061453705455200220710ustar00rootroot00000000000000import 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(reason='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 # noqa: B018 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 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 python-lazy-object-proxy-1.10.0/tests/test_async_py3.py000066400000000000000000001164421453705455200232170ustar00rootroot00000000000000# flake8: noqa # test code was mostly copied from stdlib, can't be fixing this mad stuff... import copy import inspect import pickle import re import sys import types import warnings import pytest from lazy_object_proxy.utils import await_ pypyxfail = pytest.mark.xfail('hasattr(sys, "pypy_version_info")') class AsyncYieldFrom: def __init__(self, obj): self.obj = obj def __await__(self): yield from self.obj class AsyncYield: def __init__(self, value): self.value = value def __await__(self): yield self.value def run_async(coro): assert coro.__class__ in {types.GeneratorType, types.CoroutineType} buffer = [] result = None while True: try: buffer.append(coro.send(None)) except StopIteration as ex: result = ex.args[0] if ex.args else None break return buffer, result def run_async__await__(coro): assert coro.__class__ is types.CoroutineType aw = coro.__await__() buffer = [] result = None i = 0 while True: try: if i % 2: buffer.append(next(aw)) else: buffer.append(aw.send(None)) i += 1 except StopIteration as ex: result = ex.args[0] if ex.args else None break return buffer, result async def proxy(ob): # workaround return await ob def test_gen_1(lop): def gen(): yield assert not hasattr(gen, '__await__') def test_func_1(lop): async def foo(): return 10 f = lop.Proxy(foo) assert isinstance(f, types.CoroutineType) assert bool(foo.__code__.co_flags & inspect.CO_COROUTINE) assert not bool(foo.__code__.co_flags & inspect.CO_GENERATOR) assert bool(f.cr_code.co_flags & inspect.CO_COROUTINE) assert not bool(f.cr_code.co_flags & inspect.CO_GENERATOR) assert run_async(f) == ([], 10) assert run_async__await__(foo()) == ([], 10) def bar(): pass assert not bool(bar.__code__.co_flags & inspect.CO_COROUTINE) def test_func_2(lop): async def foo(): raise StopIteration with pytest.raises(RuntimeError, match="coroutine raised StopIteration"): run_async(lop.Proxy(foo)) def test_func_3(lop): async def foo(): raise StopIteration coro = lop.Proxy(foo) assert re.search('^$', str(coro)) coro.close() def test_func_4(lop): async def foo(): raise StopIteration coro = lop.Proxy(foo) check = lambda: pytest.raises(TypeError, match="'coroutine' object is not iterable") with check(): list(coro) with check(): tuple(coro) with check(): sum(coro) with check(): iter(coro) with check(): for i in coro: pass with check(): [i for i in coro] coro.close() def test_func_5(lop): @types.coroutine def bar(): yield 1 async def foo(): await lop.Proxy(bar) check = lambda: pytest.raises(TypeError, match="'coroutine' object is not iterable") coro = lop.Proxy(foo) with check(): for el in coro: pass coro.close() # the following should pass without an error for el in lop.Proxy(bar): assert el == 1 assert [el for el in lop.Proxy(bar)] == [1] assert tuple(lop.Proxy(bar)) == (1,) assert next(iter(lop.Proxy(bar))) == 1 def test_func_6(lop): @types.coroutine def bar(): yield 1 yield 2 async def foo(): await lop.Proxy(bar) f = lop.Proxy(foo) assert f.send(None) == 1 assert f.send(None) == 2 with pytest.raises(StopIteration): f.send(None) def test_func_7(lop): async def bar(): return 10 coro = lop.Proxy(bar) def foo(): yield from coro with pytest.raises( TypeError, match="'coroutine' object is not iterable", # looks like python has some special error rewrapping?! # match="cannot 'yield from' a coroutine object in " # "a non-coroutine generator" ): list(lop.Proxy(foo)) coro.close() def test_func_8(lop): @types.coroutine def bar(): return (yield from coro) async def foo(): return 'spam' coro = await_(lop.Proxy(foo)) # coro = lop.Proxy(foo) assert run_async(lop.Proxy(bar)) == ([], 'spam') coro.close() def test_func_10(lop): N = 0 @types.coroutine def gen(): nonlocal N try: a = yield yield (a**2) except ZeroDivisionError: N += 100 raise finally: N += 1 async def foo(): await lop.Proxy(gen) coro = lop.Proxy(foo) aw = coro.__await__() assert aw is iter(aw) next(aw) assert aw.send(10) == 100 assert N == 0 aw.close() assert N == 1 coro = foo() aw = coro.__await__() next(aw) with pytest.raises(ZeroDivisionError): aw.throw(ZeroDivisionError) assert N == 102 def test_func_11(lop): async def func(): pass coro = lop.Proxy(func) # Test that PyCoro_Type and _PyCoroWrapper_Type types were properly # initialized assert '__await__' in dir(coro) awaitable = coro.__await__() assert '__iter__' in dir(awaitable) assert 'coroutine_wrapper' in str(awaitable) # avoid RuntimeWarnings awaitable.close() coro.close() def test_func_12(lop): async def g(): i = me.send(None) await foo me = lop.Proxy(g) with pytest.raises(ValueError, match="coroutine already executing"): me.send(None) def test_func_13(lop): async def g(): pass coro = lop.Proxy(g) with pytest.raises(TypeError, match="can't send non-None value to a just-started coroutine"): coro.send('spam') coro.close() def test_func_14(lop): @types.coroutine def gen(): yield async def coro(): try: await lop.Proxy(gen) except GeneratorExit: await lop.Proxy(gen) c = lop.Proxy(coro) c.send(None) with pytest.raises(RuntimeError, match="coroutine ignored GeneratorExit"): c.close() def test_func_15(lop): # See http://bugs.python.org/issue25887 for details async def spammer(): return 'spam' async def reader(coro): return await coro spammer_coro = lop.Proxy(spammer) with pytest.raises(StopIteration, match='spam'): reader(spammer_coro).send(None) with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'): reader(spammer_coro).send(None) def test_func_16(lop): # See http://bugs.python.org/issue25887 for details @types.coroutine def nop(): yield async def send(): await nop() return 'spam' async def read(coro): await nop() return await coro spammer = lop.Proxy(send) reader = lop.Proxy(lambda: read(spammer)) reader.send(None) reader.send(None) with pytest.raises(Exception, match='ham'): reader.throw(Exception('ham')) reader = read(spammer) reader.send(None) with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'): reader.send(None) with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'): reader.throw(Exception('wat')) def test_func_17(lop): # See http://bugs.python.org/issue25887 for details async def coroutine(): return 'spam' coro = lop.Proxy(coroutine) with pytest.raises(StopIteration, match='spam'): coro.send(None) with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'): coro.send(None) with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'): coro.throw(Exception('wat')) # Closing a coroutine shouldn't raise any exception even if it's # already closed/exhausted (similar to generators) coro.close() coro.close() def test_func_18(lop): # See http://bugs.python.org/issue25887 for details async def coroutine(): return 'spam' coro = lop.Proxy(coroutine) await_iter = coro.__await__() it = iter(await_iter) with pytest.raises(StopIteration, match='spam'): it.send(None) with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'): it.send(None) with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'): # Although the iterator protocol requires iterators to # raise another StopIteration here, we don't want to do # that. In this particular case, the iterator will raise # a RuntimeError, so that 'yield from' and 'await' # expressions will trigger the error, instead of silently # ignoring the call. next(it) with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'): it.throw(Exception('wat')) with pytest.raises(RuntimeError, match='cannot reuse already awaited coroutine'): it.throw(Exception('wat')) # Closing a coroutine shouldn't raise any exception even if it's # already closed/exhausted (similar to generators) it.close() it.close() def test_func_19(lop): CHK = 0 @types.coroutine def foo(): nonlocal CHK yield try: yield except GeneratorExit: CHK += 1 async def coroutine(): await foo() coro = lop.Proxy(coroutine) coro.send(None) coro.send(None) assert CHK == 0 coro.close() assert CHK == 1 for _ in range(3): # Closing a coroutine shouldn't raise any exception even if it's # already closed/exhausted (similar to generators) coro.close() assert CHK == 1 def test_coro_wrapper_send_tuple(lop): async def foo(): return (10,) result = run_async__await__(lop.Proxy(foo)) assert result == ([], (10,)) def test_coro_wrapper_send_stop_iterator(lop): async def foo(): return StopIteration(10) result = run_async__await__(lop.Proxy(foo)) assert isinstance(result[1], StopIteration) assert result[1].value == 10 def test_cr_await(lop): @types.coroutine def a(): assert inspect.getcoroutinestate(coro_b) == inspect.CORO_RUNNING assert coro_b.cr_await is None yield assert inspect.getcoroutinestate(coro_b) == inspect.CORO_RUNNING assert coro_b.cr_await is None async def c(): await lop.Proxy(a) async def b(): assert coro_b.cr_await is None await lop.Proxy(c) assert coro_b.cr_await is None coro_b = lop.Proxy(b) assert inspect.getcoroutinestate(coro_b) == inspect.CORO_CREATED assert coro_b.cr_await is None coro_b.send(None) assert inspect.getcoroutinestate(coro_b) == inspect.CORO_SUSPENDED with pytest.raises(StopIteration): coro_b.send(None) # complete coroutine assert inspect.getcoroutinestate(coro_b) == inspect.CORO_CLOSED assert coro_b.cr_await is None def test_await_1(lop): async def foo(): await 1 with pytest.raises(TypeError, match="object int can.t.*await"): run_async(lop.Proxy(foo)) def test_await_2(lop): async def foo(): await [] with pytest.raises(TypeError, match="object list can.t.*await"): run_async(lop.Proxy(foo)) def test_await_3(lop): async def foo(): await AsyncYieldFrom([1, 2, 3]) assert run_async(lop.Proxy(foo)) == ([1, 2, 3], None) assert run_async__await__(lop.Proxy(foo)) == ([1, 2, 3], None) def test_await_4(lop): async def bar(): return 42 async def foo(): return await lop.Proxy(bar) assert run_async(lop.Proxy(foo)) == ([], 42) def test_await_5(lop): class Awaitable: def __await__(self): return async def foo(): return await lop.Proxy(Awaitable) with pytest.raises(TypeError, match="__await__.*returned non-iterator of type"): run_async(lop.Proxy(foo)) def test_await_6(lop): class Awaitable: def __await__(self): return iter([52]) async def foo(): return await lop.Proxy(Awaitable) assert run_async(lop.Proxy(foo)) == ([52], None) def test_await_7(lop): class Awaitable: def __await__(self): yield 42 return 100 async def foo(): return await lop.Proxy(Awaitable) assert run_async(lop.Proxy(foo)) == ([42], 100) def test_await_8(lop): class Awaitable: pass async def foo(): return await lop.Proxy(Awaitable) with pytest.raises(TypeError): run_async(lop.Proxy(foo)) def test_await_9(lop): def wrap(): return bar async def bar(): return 42 async def foo(): db = {'b': lambda: wrap} class DB: b = wrap return ( await lop.Proxy(bar) + await lop.Proxy(wrap)() + await lop.Proxy(lambda: db['b']()()()) + await lop.Proxy(bar) * 1000 + await DB.b()() ) async def foo2(): return -await lop.Proxy(bar) assert run_async(lop.Proxy(foo)) == ([], 42168) assert run_async(lop.Proxy(foo2)) == ([], -42) def test_await_10(lop): async def baz(): return 42 async def bar(): return lop.Proxy(baz) async def foo(): return await (await lop.Proxy(bar)) assert run_async(lop.Proxy(foo)) == ([], 42) def test_await_11(lop): def ident(val): return val async def bar(): return 'spam' async def foo(): return ident(val=await lop.Proxy(bar)) async def foo2(): return await lop.Proxy(bar), 'ham' assert run_async(lop.Proxy(foo2)) == ([], ('spam', 'ham')) def test_await_12(lop): async def coro(): return 'spam' c = coro() class Awaitable: def __await__(self): return c async def foo(): return await lop.Proxy(Awaitable) with pytest.raises(TypeError, match=r"__await__\(\) returned a coroutine"): run_async(lop.Proxy(foo)) c.close() def test_await_13(lop): class Awaitable: def __await__(self): return self async def foo(): return await lop.Proxy(Awaitable) with pytest.raises(TypeError, match="__await__.*returned non-iterator of type"): run_async(lop.Proxy(foo)) def test_await_14(lop): class Wrapper: # Forces the interpreter to use CoroutineType.__await__ def __init__(self, coro): assert coro.__class__ is types.CoroutineType self.coro = coro def __await__(self): return self.coro.__await__() class FutureLike: def __await__(self): return (yield) class Marker(Exception): pass async def coro1(): try: return await lop.Proxy(FutureLike) except ZeroDivisionError: raise Marker async def coro2(): return await lop.Proxy(lambda: Wrapper(lop.Proxy(coro1))) c = lop.Proxy(coro2) c.send(None) with pytest.raises(StopIteration, match='spam'): c.send('spam') c = lop.Proxy(coro2) c.send(None) with pytest.raises(Marker): c.throw(ZeroDivisionError) def test_await_15(lop): @types.coroutine def nop(): yield async def coroutine(): await nop() async def waiter(coro): await coro coro = lop.Proxy(coroutine) coro.send(None) with pytest.raises(RuntimeError, match="coroutine is being awaited already"): waiter(coro).send(None) def test_await_16(lop): # See https://bugs.python.org/issue29600 for details. async def f(): return ValueError() async def g(): try: raise KeyError except: return await lop.Proxy(f) _, result = run_async(lop.Proxy(g)) assert result.__context__ is None def test_with_1(lop): class Manager: def __init__(self, name): self.name = name async def __aenter__(self): await AsyncYieldFrom(['enter-1-' + self.name, 'enter-2-' + self.name]) return self async def __aexit__(self, *args): await AsyncYieldFrom(['exit-1-' + self.name, 'exit-2-' + self.name]) if self.name == 'B': return True async def foo(): async with lop.Proxy(lambda: Manager("A")) as a, lop.Proxy(lambda: Manager("B")) as b: await lop.Proxy(lambda: AsyncYieldFrom([('managers', a.name, b.name)])) 1 / 0 f = lop.Proxy(foo) result, _ = run_async(f) assert result == [ 'enter-1-A', 'enter-2-A', 'enter-1-B', 'enter-2-B', ('managers', 'A', 'B'), 'exit-1-B', 'exit-2-B', 'exit-1-A', 'exit-2-A', ] async def foo(): async with lop.Proxy(lambda: Manager("A")) as a, lop.Proxy(lambda: Manager("C")) as c: await lop.Proxy(lambda: AsyncYieldFrom([('managers', a.name, c.name)])) 1 / 0 with pytest.raises(ZeroDivisionError): run_async(lop.Proxy(foo)) def test_with_2(lop): class CM: def __aenter__(self): pass body_executed = False async def foo(): async with lop.Proxy(CM): body_executed = True with pytest.raises(TypeError): run_async(lop.Proxy(foo)) assert not body_executed def test_with_3(lop): class CM: def __aexit__(self): pass body_executed = False async def foo(): async with lop.Proxy(CM): body_executed = True with pytest.raises(AttributeError, match='__aenter__'): run_async(lop.Proxy(foo)) assert not body_executed def test_with_4(lop): class CM: pass body_executed = False async def foo(): async with lop.Proxy(CM): body_executed = True with pytest.raises(AttributeError, match='__aenter__'): run_async(lop.Proxy(foo)) assert not body_executed def test_with_5(lop): # While this test doesn't make a lot of sense, # it's a regression test for an early bug with opcodes # generation class CM: async def __aenter__(self): return self async def __aexit__(self, *exc): pass async def func(): async with lop.Proxy(CM): assert (1,) == 1 with pytest.raises(AssertionError): run_async(lop.Proxy(func)) @pypyxfail def test_with_6(lop): class CM: def __aenter__(self): return 123 def __aexit__(self, *e): return 456 async def foo(): async with lop.Proxy(CM): pass with pytest.raises(TypeError, match="'async with' received an object from __aenter__ " "that does not implement __await__: int"): # it's important that __aexit__ wasn't called run_async(lop.Proxy(foo)) @pypyxfail def test_with_7(lop): class CM: async def __aenter__(self): return self def __aexit__(self, *e): return 444 # Exit with exception async def foo(): async with lop.Proxy(CM): 1 / 0 try: run_async(lop.Proxy(foo)) except TypeError as exc: assert re.search("'async with' received an object from __aexit__ " "that does not implement __await__: int", exc.args[0]) assert exc.__context__ is not None assert isinstance(exc.__context__, ZeroDivisionError) else: pytest.fail('invalid asynchronous context manager did not fail') @pypyxfail def test_with_8(lop): CNT = 0 class CM: async def __aenter__(self): return self def __aexit__(self, *e): return 456 # Normal exit async def foo(): nonlocal CNT async with lop.Proxy(CM): CNT += 1 with pytest.raises(TypeError, match="'async with' received an object from __aexit__ " "that does not implement __await__: int"): run_async(lop.Proxy(foo)) assert CNT == 1 # Exit with 'break' async def foo(): nonlocal CNT for i in range(2): async with lop.Proxy(CM): CNT += 1 break with pytest.raises(TypeError, match="'async with' received an object from __aexit__ " "that does not implement __await__: int"): run_async(lop.Proxy(foo)) assert CNT == 2 # Exit with 'continue' async def foo(): nonlocal CNT for i in range(2): async with lop.Proxy(CM): CNT += 1 continue with pytest.raises(TypeError, match="'async with' received an object from __aexit__ " "that does not implement __await__: int"): run_async(lop.Proxy(foo)) assert CNT == 3 # Exit with 'return' async def foo(): nonlocal CNT async with lop.Proxy(CM): CNT += 1 return with pytest.raises(TypeError, match="'async with' received an object from __aexit__ " "that does not implement __await__: int"): run_async(lop.Proxy(foo)) assert CNT == 4 def test_with_9(lop): CNT = 0 class CM: async def __aenter__(self): return self async def __aexit__(self, *e): 1 / 0 async def foo(): nonlocal CNT async with lop.Proxy(CM): CNT += 1 with pytest.raises(ZeroDivisionError): run_async(lop.Proxy(foo)) assert CNT == 1 def test_with_10(lop): CNT = 0 class CM: async def __aenter__(self): return self async def __aexit__(self, *e): 1 / 0 async def foo(): nonlocal CNT async with lop.Proxy(CM): async with lop.Proxy(CM): raise RuntimeError try: run_async(lop.Proxy(foo)) except ZeroDivisionError as exc: assert exc.__context__ is not None assert isinstance(exc.__context__, ZeroDivisionError) assert isinstance(exc.__context__.__context__, RuntimeError) else: pytest.fail('exception from __aexit__ did not propagate') def test_with_11(lop): CNT = 0 class CM: async def __aenter__(self): raise NotImplementedError async def __aexit__(self, *e): 1 / 0 async def foo(): nonlocal CNT async with lop.Proxy(CM): raise RuntimeError try: run_async(lop.Proxy(foo)) except NotImplementedError as exc: assert exc.__context__ is None else: pytest.fail('exception from __aenter__ did not propagate') def test_with_12(lop): CNT = 0 class CM: async def __aenter__(self): return self async def __aexit__(self, *e): return True async def foo(): nonlocal CNT async with lop.Proxy(CM) as cm: assert cm.__class__ is CM raise RuntimeError run_async(lop.Proxy(foo)) def test_with_13(lop): CNT = 0 class CM: async def __aenter__(self): 1 / 0 async def __aexit__(self, *e): return True async def foo(): nonlocal CNT CNT += 1 async with lop.Proxy(CM): CNT += 1000 CNT += 10000 with pytest.raises(ZeroDivisionError): run_async(lop.Proxy(foo)) assert CNT == 1 def test_for_1(lop): aiter_calls = 0 class AsyncIter: def __init__(self): self.i = 0 def __aiter__(self): nonlocal aiter_calls aiter_calls += 1 return self async def __anext__(self): self.i += 1 if not (self.i % 10): await lop.Proxy(lambda: AsyncYield(self.i * 10)) if self.i > 100: raise StopAsyncIteration return self.i, self.i buffer = [] async def test1(): async for i1, i2 in lop.Proxy(AsyncIter): buffer.append(i1 + i2) yielded, _ = run_async(lop.Proxy(test1)) # Make sure that __aiter__ was called only once assert aiter_calls == 1 assert yielded == [i * 100 for i in range(1, 11)] assert buffer == [i * 2 for i in range(1, 101)] buffer = [] async def test2(): nonlocal buffer async for i in lop.Proxy(AsyncIter): buffer.append(i[0]) if i[0] == 20: break else: buffer.append('what?') buffer.append('end') yielded, _ = run_async(lop.Proxy(test2)) # Make sure that __aiter__ was called only once assert aiter_calls == 2 assert yielded == [100, 200] assert buffer == [i for i in range(1, 21)] + ['end'] buffer = [] async def test3(): nonlocal buffer async for i in lop.Proxy(AsyncIter): if i[0] > 20: continue buffer.append(i[0]) else: buffer.append('what?') buffer.append('end') yielded, _ = run_async(lop.Proxy(test3)) # Make sure that __aiter__ was called only once assert aiter_calls == 3 assert yielded == [i * 100 for i in range(1, 11)] assert buffer == [i for i in range(1, 21)] + ['what?', 'end'] @pypyxfail def test_for_2(lop): tup = (1, 2, 3) refs_before = sys.getrefcount(tup) async def foo(): async for i in lop.Proxy(lambda: tup): print('never going to happen') with pytest.raises(AttributeError, match="'tuple' object has no attribute '__aiter__'"): run_async(lop.Proxy(foo)) assert sys.getrefcount(tup) == refs_before @pypyxfail def test_for_3(lop): class I: def __aiter__(self): return self aiter = lop.Proxy(I) refs_before = sys.getrefcount(aiter) async def foo(): async for i in aiter: print('never going to happen') with pytest.raises(TypeError): run_async(lop.Proxy(foo)) assert sys.getrefcount(aiter) == refs_before @pypyxfail def test_for_4(lop): class I: def __aiter__(self): return self def __anext__(self): return () aiter = lop.Proxy(I) refs_before = sys.getrefcount(aiter) async def foo(): async for i in aiter: print('never going to happen') with pytest.raises(TypeError, match="async for' received an invalid object.*__anext__.*tuple"): run_async(lop.Proxy(foo)) assert sys.getrefcount(aiter) == refs_before @pypyxfail def test_for_6(lop): I = 0 class Manager: async def __aenter__(self): nonlocal I I += 10000 async def __aexit__(self, *args): nonlocal I I += 100000 class Iterable: def __init__(self): self.i = 0 def __aiter__(self): return self async def __anext__(self): if self.i > 10: raise StopAsyncIteration self.i += 1 return self.i ############## manager = lop.Proxy(Manager) iterable = lop.Proxy(Iterable) mrefs_before = sys.getrefcount(manager) irefs_before = sys.getrefcount(iterable) async def main(): nonlocal I async with manager: async for i in iterable: I += 1 I += 1000 with warnings.catch_warnings(): warnings.simplefilter("error") # Test that __aiter__ that returns an asynchronous iterator # directly does not throw any warnings. run_async(main()) assert I == 111011 assert sys.getrefcount(manager) == mrefs_before assert sys.getrefcount(iterable) == irefs_before ############## async def main(): nonlocal I async with lop.Proxy(Manager): async for i in lop.Proxy(Iterable): I += 1 I += 1000 async with lop.Proxy(Manager): async for i in lop.Proxy(Iterable): I += 1 I += 1000 run_async(main()) assert I == 333033 ############## async def main(): nonlocal I async with lop.Proxy(Manager): I += 100 async for i in lop.Proxy(Iterable): I += 1 else: I += 10000000 I += 1000 async with lop.Proxy(Manager): I += 100 async for i in lop.Proxy(Iterable): I += 1 else: I += 10000000 I += 1000 run_async(lop.Proxy(main)) assert I == 20555255 def test_for_7(lop): CNT = 0 class AI: def __aiter__(self): 1 / 0 async def foo(): nonlocal CNT async for i in lop.Proxy(AI): CNT += 1 CNT += 10 with pytest.raises(ZeroDivisionError): run_async(lop.Proxy(foo)) assert CNT == 0 def test_for_8(lop): CNT = 0 class AI: def __aiter__(self): 1 / 0 async def foo(): nonlocal CNT async for i in lop.Proxy(AI): CNT += 1 CNT += 10 with pytest.raises(ZeroDivisionError): with warnings.catch_warnings(): warnings.simplefilter("error") # Test that if __aiter__ raises an exception it propagates # without any kind of warning. run_async(lop.Proxy(foo)) assert CNT == 0 def test_for_11(lop): class F: def __aiter__(self): return self def __anext__(self): return self def __await__(self): 1 / 0 async def main(): async for _ in lop.Proxy(F): pass with pytest.raises(TypeError, match='an invalid object from __anext__') as c: lop.Proxy(main).send(None) err = c.value assert isinstance(err.__cause__, ZeroDivisionError) def test_for_tuple(lop): class Done(Exception): pass class AIter(tuple): i = 0 def __aiter__(self): return self async def __anext__(self): if self.i >= len(self): raise StopAsyncIteration self.i += 1 return self[self.i - 1] result = [] async def foo(): async for i in lop.Proxy(lambda: AIter([42])): result.append(i) raise Done with pytest.raises(Done): lop.Proxy(foo).send(None) assert result == [42] def test_for_stop_iteration(lop): class Done(Exception): pass class AIter(StopIteration): i = 0 def __aiter__(self): return self async def __anext__(self): if self.i: raise StopAsyncIteration self.i += 1 return self.value result = [] async def foo(): async for i in lop.Proxy(lambda: AIter(42)): result.append(i) raise Done with pytest.raises(Done): lop.Proxy(foo).send(None) assert result == [42] def test_comp_1(lop): async def f(i): return i async def run_list(): return [await c for c in [lop.Proxy(lambda: f(1)), lop.Proxy(lambda: f(41))]] async def run_set(): return {await c for c in [lop.Proxy(lambda: f(1)), lop.Proxy(lambda: f(41))]} async def run_dict1(): return {await c: 'a' for c in [lop.Proxy(lambda: f(1)), lop.Proxy(lambda: f(41))]} async def run_dict2(): return {i: await c for i, c in enumerate([lop.Proxy(lambda: f(1)), lop.Proxy(lambda: f(41))])} assert run_async(run_list()) == ([], [1, 41]) assert run_async(run_set()) == ([], {1, 41}) assert run_async(run_dict1()) == ([], {1: 'a', 41: 'a'}) assert run_async(run_dict2()) == ([], {0: 1, 1: 41}) def test_comp_2(lop): async def f(i): return i async def run_list(): return [ s for c in [lop.Proxy(lambda: f('')), lop.Proxy(lambda: f('abc')), lop.Proxy(lambda: f('')), lop.Proxy(lambda: f(['de', 'fg']))] for s in await c ] assert run_async(lop.Proxy(run_list)) == ([], ['a', 'b', 'c', 'de', 'fg']) async def run_set(): return { d for c in [lop.Proxy(lambda: f([lop.Proxy(lambda: f([10, 30])), lop.Proxy(lambda: f([20]))]))] for s in await c for d in await s } assert run_async(lop.Proxy(run_set)) == ([], {10, 20, 30}) async def run_set2(): return {await s for c in [lop.Proxy(lambda: f([lop.Proxy(lambda: f(10)), lop.Proxy(lambda: f(20))]))] for s in await c} assert run_async(lop.Proxy(run_set2)) == ([], {10, 20}) def test_comp_3(lop): async def f(it): for i in it: yield i async def run_list(): return [i + 1 async for i in f([10, 20])] assert run_async(run_list()) == ([], [11, 21]) async def run_set(): return {i + 1 async for i in f([10, 20])} assert run_async(run_set()) == ([], {11, 21}) async def run_dict(): return {i + 1: i + 2 async for i in f([10, 20])} assert run_async(run_dict()) == ([], {11: 12, 21: 22}) async def run_gen(): gen = (i + 1 async for i in f([10, 20])) return [g + 100 async for g in gen] assert run_async(run_gen()) == ([], [111, 121]) def test_comp_4(lop): async def f(it): for i in it: yield i async def run_list(): return [i + 1 async for i in f([10, 20]) if i > 10] assert run_async(run_list()) == ([], [21]) async def run_set(): return {i + 1 async for i in f([10, 20]) if i > 10} assert run_async(run_set()) == ([], {21}) async def run_dict(): return {i + 1: i + 2 async for i in f([10, 20]) if i > 10} assert run_async(run_dict()) == ([], {21: 22}) async def run_gen(): gen = (i + 1 async for i in f([10, 20]) if i > 10) return [g + 100 async for g in gen] assert run_async(run_gen()) == ([], [121]) def test_comp_4_2(lop): async def f(it): for i in it: yield i async def run_list(): return [i + 10 async for i in f(range(5)) if 0 < i < 4] assert run_async(run_list()) == ([], [11, 12, 13]) async def run_set(): return {i + 10 async for i in f(range(5)) if 0 < i < 4} assert run_async(run_set()) == ([], {11, 12, 13}) async def run_dict(): return {i + 10: i + 100 async for i in f(range(5)) if 0 < i < 4} assert run_async(run_dict()) == ([], {11: 101, 12: 102, 13: 103}) async def run_gen(): gen = (i + 10 async for i in f(range(5)) if 0 < i < 4) return [g + 100 async for g in gen] assert run_async(run_gen()) == ([], [111, 112, 113]) def test_comp_5(lop): async def f(it): for i in it: yield i async def run_list(): return [i + 1 for pair in ([10, 20], [30, 40]) if pair[0] > 10 async for i in f(pair) if i > 30] assert run_async(run_list()) == ([], [41]) def test_comp_6(lop): async def f(it): for i in it: yield i async def run_list(): return [i + 1 async for seq in f([(10, 20), (30,)]) for i in seq] assert run_async(run_list()) == ([], [11, 21, 31]) def test_comp_7(lop): async def f(): yield 1 yield 2 raise Exception('aaa') async def run_list(): return [i async for i in f()] with pytest.raises(Exception, match='aaa'): run_async(run_list()) def test_comp_8(lop): async def f(): return [i for i in [1, 2, 3]] assert run_async(f()) == ([], [1, 2, 3]) def test_comp_9(lop): async def gen(): yield 1 yield 2 async def f(): l = [i async for i in gen()] return [i for i in l] assert run_async(f()) == ([], [1, 2]) def test_comp_10(lop): async def f(): xx = {i for i in [1, 2, 3]} return {x: x for x in xx} assert run_async(f()) == ([], {1: 1, 2: 2, 3: 3}) def test_copy(lop): async def func(): pass coro = func() with pytest.raises(TypeError): copy.copy(coro) aw = coro.__await__() try: with pytest.raises(TypeError): copy.copy(aw) finally: aw.close() def test_pickle(lop): async def func(): pass coro = func() for proto in range(pickle.HIGHEST_PROTOCOL + 1): with pytest.raises((TypeError, pickle.PicklingError)): pickle.dumps(coro, proto) aw = coro.__await__() try: for proto in range(pickle.HIGHEST_PROTOCOL + 1): with pytest.raises((TypeError, pickle.PicklingError)): pickle.dumps(aw, proto) finally: aw.close() @pytest.mark.skipif("sys.version_info[1] < 8") def test_for_assign_raising_stop_async_iteration(lop): class BadTarget: def __setitem__(self, key, value): raise StopAsyncIteration(42) tgt = BadTarget() async def source(): yield 10 async def run_for(): with pytest.raises(StopAsyncIteration) as cm: async for tgt[0] in source(): pass assert cm.value.args == (42,) return 'end' assert run_async(run_for()) == ([], 'end') async def run_list(): with pytest.raises(StopAsyncIteration) as cm: return [0 async for tgt[0] in lop.Proxy(source)] assert cm.value.args == (42,) return 'end' assert run_async(run_list()) == ([], 'end') async def run_gen(): gen = (0 async for tgt[0] in lop.Proxy(source)) a = gen.asend(None) with pytest.raises(RuntimeError) as cm: await a assert isinstance(cm.value.__cause__, StopAsyncIteration) assert cm.value.__cause__.args == (42,) return 'end' assert run_async(run_gen()) == ([], 'end') @pytest.mark.skipif("sys.version_info[1] < 8") def test_for_assign_raising_stop_async_iteration_2(lop): class BadIterable: def __iter__(self): raise StopAsyncIteration(42) async def badpairs(): yield BadIterable() async def run_for(): with pytest.raises(StopAsyncIteration) as cm: async for i, j in lop.Proxy(badpairs): pass assert cm.value.args == (42,) return 'end' assert run_async(run_for()) == ([], 'end') async def run_list(): with pytest.raises(StopAsyncIteration) as cm: return [0 async for i, j in badpairs()] assert cm.value.args == (42,) return 'end' assert run_async(run_list()) == ([], 'end') async def run_gen(): gen = (0 async for i, j in badpairs()) a = gen.asend(None) with pytest.raises(RuntimeError) as cm: await a assert isinstance(cm.value.__cause__, StopAsyncIteration) assert cm.value.__cause__.args == (42,) return 'end' assert run_async(run_gen()) == ([], 'end') def test_asyncio_1(lop): import asyncio class MyException(Exception): pass buffer = [] class CM: async def __aenter__(self): buffer.append(1) await lop.Proxy(lambda: asyncio.sleep(0.01)) buffer.append(2) return self async def __aexit__(self, exc_type, exc_val, exc_tb): await lop.Proxy(lambda: asyncio.sleep(0.01)) buffer.append(exc_type.__name__) async def f(): async with lop.Proxy(CM) as c: await lop.Proxy(lambda: asyncio.sleep(0.01)) raise MyException buffer.append('unreachable') loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) try: loop.run_until_complete(f()) except MyException: pass finally: loop.close() asyncio.set_event_loop_policy(None) assert buffer == [1, 2, 'MyException'] python-lazy-object-proxy-1.10.0/tests/test_lazy_object_proxy.py000066400000000000000000001212511453705455200250470ustar00rootroot00000000000000import gc import os import pickle import platform import sys import types import weakref from datetime import date from datetime import datetime from decimal import Decimal from functools import partial import pytest PYPY = '__pypy__' in sys.builtin_module_names OBJECTS_CODE = """ class TargetBaseClass(object): "documentation" class Target(TargetBaseClass): "documentation" def target(): "documentation" pass """ objects = types.ModuleType('objects') exec(OBJECTS_CODE, objects.__dict__, objects.__dict__) def test_round(lop): proxy = lop.Proxy(lambda: 1.2) assert round(proxy) == 1 def test_attributes(lop): def function1(*args, **kwargs): return args, kwargs function2 = lop.Proxy(lambda: function1) assert function2.__wrapped__ == function1 def test_get_wrapped(lop): def function1(*args, **kwargs): return args, kwargs function2 = lop.Proxy(lambda: function1) assert function2.__wrapped__ == function1 function3 = lop.Proxy(lambda: function2) assert function3.__wrapped__ == function1 def test_set_wrapped(lop): def function1(*args, **kwargs): return args, kwargs function2 = lop.Proxy(lambda: function1) assert function2 == function1 assert function2.__wrapped__ is function1 assert function2.__name__ == function1.__name__ assert function2.__qualname__ == function1.__qualname__ function2.__wrapped__ = None assert not hasattr(function1, '__wrapped__') assert function2 == None # noqa assert function2.__wrapped__ is None assert not hasattr(function2, '__name__') assert not hasattr(function2, '__qualname__') def function3(*args, **kwargs): return args, kwargs function2.__wrapped__ = function3 assert function2 == function3 assert function2.__wrapped__ == function3 assert function2.__name__ == function3.__name__ assert function2.__qualname__ == function3.__qualname__ def test_wrapped_attribute(lop): def function1(*args, **kwargs): return args, kwargs function2 = lop.Proxy(lambda: function1) function2.variable = True assert hasattr(function1, 'variable') assert hasattr(function2, 'variable') assert function2.variable is True del function2.variable assert not hasattr(function1, 'variable') assert not hasattr(function2, 'variable') assert getattr(function2, 'variable', None) is None def test_class_object_name(lop): # Test preservation of class __name__ attribute. target = objects.Target wrapper = lop.Proxy(lambda: target) assert wrapper.__name__ == target.__name__ def test_class_object_qualname(lop): # Test preservation of class __qualname__ attribute. target = objects.Target wrapper = lop.Proxy(lambda: target) try: __qualname__ = target.__qualname__ except AttributeError: pass else: assert wrapper.__qualname__ == __qualname__ @pytest.mark.xfail_subclass def test_class_module_name(lop): # Test preservation of class __module__ attribute. target = objects.Target wrapper = lop.Proxy(lambda: target) assert wrapper.__module__ == target.__module__ @pytest.mark.xfail_subclass def test_class_doc_string(lop): # Test preservation of class __doc__ attribute. target = objects.Target wrapper = lop.Proxy(lambda: target) assert wrapper.__doc__ == target.__doc__ @pytest.mark.xfail_subclass def test_instance_module_name(lop): # Test preservation of instance __module__ attribute. target = objects.Target() wrapper = lop.Proxy(lambda: target) assert wrapper.__module__ == target.__module__ @pytest.mark.xfail_subclass def test_instance_doc_string(lop): # Test preservation of instance __doc__ attribute. target = objects.Target() wrapper = lop.Proxy(lambda: target) assert wrapper.__doc__ == target.__doc__ def test_function_object_name(lop): # Test preservation of function __name__ attribute. target = objects.target wrapper = lop.Proxy(lambda: target) assert wrapper.__name__ == target.__name__ def test_function_object_qualname(lop): # Test preservation of function __qualname__ attribute. target = objects.target wrapper = lop.Proxy(lambda: target) try: __qualname__ = target.__qualname__ except AttributeError: pass else: assert wrapper.__qualname__ == __qualname__ @pytest.mark.xfail_subclass def test_function_module_name(lop): # Test preservation of function __module__ attribute. target = objects.target wrapper = lop.Proxy(lambda: target) assert wrapper.__module__ == target.__module__ @pytest.mark.xfail_subclass def test_function_doc_string(lop): # Test preservation of function __doc__ attribute. target = objects.target wrapper = lop.Proxy(lambda: target) assert wrapper.__doc__ == target.__doc__ def test_class_of_class(lop): # Test preservation of class __class__ attribute. target = objects.Target wrapper = lop.Proxy(lambda: target) assert wrapper.__class__ is target.__class__ assert isinstance(wrapper, type(target)) def test_revert_class_proxying(lop): class ProxyWithOldStyleIsInstance(lop.Proxy): __class__ = object.__dict__['__class__'] target = objects.Target() wrapper = ProxyWithOldStyleIsInstance(lambda: target) assert wrapper.__class__ is ProxyWithOldStyleIsInstance assert isinstance(wrapper, ProxyWithOldStyleIsInstance) assert not isinstance(wrapper, objects.Target) assert not isinstance(wrapper, objects.TargetBaseClass) class ProxyWithOldStyleIsInstance2(ProxyWithOldStyleIsInstance): pass wrapper = ProxyWithOldStyleIsInstance2(lambda: target) assert wrapper.__class__ is ProxyWithOldStyleIsInstance2 assert isinstance(wrapper, ProxyWithOldStyleIsInstance2) assert not isinstance(wrapper, objects.Target) assert not isinstance(wrapper, objects.TargetBaseClass) def test_class_of_instance(lop): # Test preservation of instance __class__ attribute. target = objects.Target() wrapper = lop.Proxy(lambda: target) assert wrapper.__class__ is target.__class__ assert isinstance(wrapper, objects.Target) assert isinstance(wrapper, objects.TargetBaseClass) def test_class_of_function(lop): # Test preservation of function __class__ attribute. target = objects.target wrapper = lop.Proxy(lambda: target) assert wrapper.__class__ is target.__class__ assert isinstance(wrapper, type(target)) def test_dir_of_class(lop): # Test preservation of class __dir__ attribute. target = objects.Target wrapper = lop.Proxy(lambda: target) assert dir(wrapper) == dir(target) @pytest.mark.xfail_simple def test_vars_of_class(lop): # Test preservation of class __dir__ attribute. target = objects.Target wrapper = lop.Proxy(lambda: target) assert vars(wrapper) == vars(target) def test_dir_of_instance(lop): # Test preservation of instance __dir__ attribute. target = objects.Target() wrapper = lop.Proxy(lambda: target) assert dir(wrapper) == dir(target) @pytest.mark.xfail_simple def test_vars_of_instance(lop): # Test preservation of instance __dir__ attribute. target = objects.Target() wrapper = lop.Proxy(lambda: target) assert vars(wrapper) == vars(target) def test_dir_of_function(lop): # Test preservation of function __dir__ attribute. target = objects.target wrapper = lop.Proxy(lambda: target) assert dir(wrapper) == dir(target) @pytest.mark.xfail_simple def test_vars_of_function(lop): # Test preservation of function __dir__ attribute. target = objects.target wrapper = lop.Proxy(lambda: target) assert vars(wrapper) == vars(target) def test_function_no_args(lop): _args = () _kwargs = {} def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: function) result = wrapper() assert result == (_args, _kwargs) def test_function_args(lop): _args = (1, 2) _kwargs = {} def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: function) result = wrapper(*_args) assert result == (_args, _kwargs) def test_function_kwargs(lop): _args = () _kwargs = {'one': 1, 'two': 2} def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: function) result = wrapper(**_kwargs) assert result == (_args, _kwargs) def test_function_args_plus_kwargs(lop): _args = (1, 2) _kwargs = {'one': 1, 'two': 2} def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: function) result = wrapper(*_args, **_kwargs) assert result == (_args, _kwargs) def test_instancemethod_no_args(lop): _args = () _kwargs = {} class Class: def function(self, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper() assert result == (_args, _kwargs) def test_instancemethod_args(lop): _args = (1, 2) _kwargs = {} class Class: def function(self, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper(*_args) assert result == (_args, _kwargs) def test_instancemethod_kwargs(lop): _args = () _kwargs = {'one': 1, 'two': 2} class Class: def function(self, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper(**_kwargs) assert result == (_args, _kwargs) def test_instancemethod_args_plus_kwargs(lop): _args = (1, 2) _kwargs = {'one': 1, 'two': 2} class Class: def function(self, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper(*_args, **_kwargs) assert result == (_args, _kwargs) def test_instancemethod_via_class_no_args(lop): _args = () _kwargs = {} class Class: def function(self, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(Class()) assert result == (_args, _kwargs) def test_instancemethod_via_class_args(lop): _args = (1, 2) _kwargs = {} class Class: def function(self, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(Class(), *_args) assert result == (_args, _kwargs) def test_instancemethod_via_class_kwargs(lop): _args = () _kwargs = {'one': 1, 'two': 2} class Class: def function(self, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(Class(), **_kwargs) assert result == (_args, _kwargs) def test_instancemethod_via_class_args_plus_kwargs(lop): _args = (1, 2) _kwargs = {'one': 1, 'two': 2} class Class: def function(self, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(Class(), *_args, **_kwargs) assert result == (_args, _kwargs) def test_classmethod_no_args(lop): _args = () _kwargs = {} class Class: @classmethod def function(cls, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper() assert result == (_args, _kwargs) def test_classmethod_args(lop): _args = (1, 2) _kwargs = {} class Class: @classmethod def function(cls, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper(*_args) assert result == (_args, _kwargs) def test_classmethod_kwargs(lop): _args = () _kwargs = {'one': 1, 'two': 2} class Class: @classmethod def function(cls, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper(**_kwargs) assert result == (_args, _kwargs) def test_classmethod_args_plus_kwargs(lop): _args = (1, 2) _kwargs = {'one': 1, 'two': 2} class Class: @classmethod def function(cls, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper(*_args, **_kwargs) assert result == (_args, _kwargs) def test_classmethod_via_class_no_args(lop): _args = () _kwargs = {} class Class: @classmethod def function(cls, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper() assert result == (_args, _kwargs) def test_classmethod_via_class_args(lop): _args = (1, 2) _kwargs = {} class Class: @classmethod def function(cls, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(*_args) assert result == (_args, _kwargs) def test_classmethod_via_class_kwargs(lop): _args = () _kwargs = {'one': 1, 'two': 2} class Class: @classmethod def function(cls, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(**_kwargs) assert result == (_args, _kwargs) def test_classmethod_via_class_args_plus_kwargs(lop): _args = (1, 2) _kwargs = {'one': 1, 'two': 2} class Class: @classmethod def function(cls, *args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(*_args, **_kwargs) assert result == (_args, _kwargs) def test_staticmethod_no_args(lop): _args = () _kwargs = {} class Class: @staticmethod def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper() assert result == (_args, _kwargs) def test_staticmethod_args(lop): _args = (1, 2) _kwargs = {} class Class: @staticmethod def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper(*_args) assert result == (_args, _kwargs) def test_staticmethod_kwargs(lop): _args = () _kwargs = {'one': 1, 'two': 2} class Class: @staticmethod def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper(**_kwargs) assert result == (_args, _kwargs) def test_staticmethod_args_plus_kwargs(lop): _args = (1, 2) _kwargs = {'one': 1, 'two': 2} class Class: @staticmethod def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class().function) result = wrapper(*_args, **_kwargs) assert result == (_args, _kwargs) def test_staticmethod_via_class_no_args(lop): _args = () _kwargs = {} class Class: @staticmethod def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper() assert result == (_args, _kwargs) def test_staticmethod_via_class_args(lop): _args = (1, 2) _kwargs = {} class Class: @staticmethod def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(*_args) assert result == (_args, _kwargs) def test_staticmethod_via_class_kwargs(lop): _args = () _kwargs = {'one': 1, 'two': 2} class Class: @staticmethod def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(**_kwargs) assert result == (_args, _kwargs) def test_staticmethod_via_class_args_plus_kwargs(lop): _args = (1, 2) _kwargs = {'one': 1, 'two': 2} class Class: @staticmethod def function(*args, **kwargs): return args, kwargs wrapper = lop.Proxy(lambda: Class.function) result = wrapper(*_args, **_kwargs) assert result == (_args, _kwargs) def test_iteration(lop): items = [1, 2] wrapper = lop.Proxy(lambda: items) result = [x for x in wrapper] # noqa: C416 assert result == items with pytest.raises(TypeError): for _ in lop.Proxy(lambda: 1): pass def test_iter_builtin(lop): iter(lop.Proxy(lambda: [1, 2])) pytest.raises(TypeError, iter, lop.Proxy(lambda: 1)) def test_context_manager(lop): class Class: def __enter__(self): return self def __exit__(*args, **kwargs): return instance = Class() wrapper = lop.Proxy(lambda: instance) with wrapper: pass def test_object_hash(lop): def function1(*args, **kwargs): return args, kwargs function2 = lop.Proxy(lambda: function1) assert hash(function2) == hash(function1) def test_mapping_key(lop): def function1(*args, **kwargs): return args, kwargs function2 = lop.Proxy(lambda: function1) table = {function1: True} assert table.get(function2) table = {function2: True} assert table.get(function1) def test_comparison(lop): one = lop.Proxy(lambda: 1) two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert two > 1 assert two >= 1 assert two < 3 assert two <= 3 assert two != 1 assert two == 2 assert two != 3 assert 2 > one assert 2 >= one assert 2 < three assert 2 <= three assert 2 != one assert 2 == two assert 2 != three assert two > one assert two >= one assert two < three assert two <= three assert two != one assert two == two assert two != three def test_nonzero(lop): true = lop.Proxy(lambda: True) false = lop.Proxy(lambda: False) assert true assert not false assert bool(true) assert not bool(false) assert not false assert not not true def test_int(lop): one = lop.Proxy(lambda: 1) assert int(one) == 1 def test_float(lop): one = lop.Proxy(lambda: 1) assert float(one) == 1.0 def test_add(lop): one = lop.Proxy(lambda: 1) two = lop.Proxy(lambda: 2) assert one + two == 1 + 2 assert 1 + two == 1 + 2 assert one + 2 == 1 + 2 def test_sub(lop): one = lop.Proxy(lambda: 1) two = lop.Proxy(lambda: 2) assert one - two == 1 - 2 assert 1 - two == 1 - 2 assert one - 2 == 1 - 2 def test_mul(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert two * three == 2 * 3 assert 2 * three == 2 * 3 assert two * 3 == 2 * 3 def test_matmul(lop): class MatmulClass: def __init__(self, value): self.value = value def __matmul__(self, other): return self.value * other.value def __rmatmul__(self, other): return other + self.value one = MatmulClass(123) two = MatmulClass(234) assert one @ two == 28782 one = lop.Proxy(lambda: MatmulClass(123)) two = lop.Proxy(lambda: MatmulClass(234)) assert one @ two == 28782 one = lop.Proxy(lambda: MatmulClass(123)) two = MatmulClass(234) assert one @ two == 28782 one = 123 two = lop.Proxy(lambda: MatmulClass(234)) assert one @ two == 357 one = lop.Proxy(lambda: 123) two = lop.Proxy(lambda: MatmulClass(234)) assert one @ two == 357 def test_div(lop): # On Python 2 this will pick up div and on Python # 3 it will pick up truediv. two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert two / three == 2 / 3 assert 2 / three == 2 / 3 assert two / 3 == 2 / 3 def test_divdiv(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert three // two == 3 // 2 assert 3 // two == 3 // 2 assert three // 2 == 3 // 2 def test_mod(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert three % two == 3 % 2 assert 3 % two == 3 % 2 assert three % 2 == 3 % 2 def test_divmod(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert divmod(three, two), divmod(3 == 2) assert divmod(3, two), divmod(3 == 2) assert divmod(three, 2), divmod(3 == 2) def test_pow(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert three**two == pow(3, 2) assert 3**two == pow(3, 2) assert pow(3, two) == pow(3, 2) assert three**2 == pow(3, 2) assert pow(three, two) == pow(3, 2) assert pow(3, two) == pow(3, 2) assert pow(three, 2) == pow(3, 2) assert pow(three, 2, 2) == pow(3, 2, 2) @pytest.mark.xfail def test_pow_ternary(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert pow(three, two, 2) == pow(3, 2, 2) @pytest.mark.xfail def test_rpow_ternary(lop): two = lop.Proxy(lambda: 2) assert pow(3, two, 2) == pow(3, 2, 2) def test_lshift(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert three << two == 3 << 2 assert 3 << two == 3 << 2 assert three << 2 == 3 << 2 def test_rshift(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert three >> two == 3 >> 2 assert 3 >> two == 3 >> 2 assert three >> 2 == 3 >> 2 def test_and(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert three & two == 3 & 2 assert 3 & two == 3 & 2 assert three & 2 == 3 & 2 def test_xor(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert three ^ two == 3 ^ 2 assert 3 ^ two == 3 ^ 2 assert three ^ 2 == 3 ^ 2 def test_or(lop): two = lop.Proxy(lambda: 2) three = lop.Proxy(lambda: 3) assert three | two == 3 | 2 assert 3 | two == 3 | 2 assert three | 2 == 3 | 2 def test_iadd(lop): value = lop.Proxy(lambda: 1) one = lop.Proxy(lambda: 1) value += 1 assert value == 2 if lop.kind != 'simple': assert type(value) == lop.Proxy value += one assert value == 3 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_isub(lop): value = lop.Proxy(lambda: 1) one = lop.Proxy(lambda: 1) value -= 1 assert value == 0 if lop.kind != 'simple': assert type(value) == lop.Proxy value -= one assert value == -1 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_imul(lop): value = lop.Proxy(lambda: 2) two = lop.Proxy(lambda: 2) value *= 2 assert value == 4 if lop.kind != 'simple': assert type(value) == lop.Proxy value *= two assert value == 8 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_imatmul(lop): class InplaceMatmul: value = None def __imatmul__(self, other): self.value = other return self value = InplaceMatmul() assert value.value is None value @= 123 assert value.value == 123 value = lop.Proxy(InplaceMatmul) value @= 234 assert value.value == 234 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_idiv(lop): # On Python 2 this will pick up div and on Python # 3 it will pick up truediv. value = lop.Proxy(lambda: 2) two = lop.Proxy(lambda: 2) value /= 2 assert value == 2 / 2 if lop.kind != 'simple': assert type(value) == lop.Proxy value /= two assert value == 2 / 2 / 2 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_ifloordiv(lop): value = lop.Proxy(lambda: 2) two = lop.Proxy(lambda: 2) value //= 2 assert value == 2 // 2 if lop.kind != 'simple': assert type(value) == lop.Proxy value //= two assert value == 2 // 2 // 2 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_imod(lop): value = lop.Proxy(lambda: 10) two = lop.Proxy(lambda: 2) value %= 2 assert value == 10 % 2 if lop.kind != 'simple': assert type(value) == lop.Proxy value %= two assert value == 10 % 2 % 2 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_ipow(lop): value = lop.Proxy(lambda: 10) two = lop.Proxy(lambda: 2) value **= 2 assert value == 10**2 if lop.kind != 'simple': assert type(value) == lop.Proxy value **= two assert value == 10**2**2 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_ilshift(lop): value = lop.Proxy(lambda: 256) two = lop.Proxy(lambda: 2) value <<= 2 assert value == 256 << 2 if lop.kind != 'simple': assert type(value) == lop.Proxy value <<= two assert value == 256 << 2 << 2 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_irshift(lop): value = lop.Proxy(lambda: 2) two = lop.Proxy(lambda: 2) value >>= 2 assert value == 2 >> 2 if lop.kind != 'simple': assert type(value) == lop.Proxy value >>= two assert value == 2 >> 2 >> 2 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_iand(lop): value = lop.Proxy(lambda: 1) two = lop.Proxy(lambda: 2) value &= 2 assert value == 1 & 2 if lop.kind != 'simple': assert type(value) == lop.Proxy value &= two assert value == 1 & 2 & 2 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_ixor(lop): value = lop.Proxy(lambda: 1) two = lop.Proxy(lambda: 2) value ^= 2 assert value == 1 ^ 2 if lop.kind != 'simple': assert type(value) == lop.Proxy value ^= two assert value == 1 ^ 2 ^ 2 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_ior(lop): value = lop.Proxy(lambda: 1) two = lop.Proxy(lambda: 2) value |= 2 assert value == 1 | 2 if lop.kind != 'simple': assert type(value) == lop.Proxy value |= two assert value == 1 | 2 | 2 if lop.kind != 'simple': assert type(value) == lop.Proxy def test_neg(lop): value = lop.Proxy(lambda: 1) assert -value == -1 def test_pos(lop): value = lop.Proxy(lambda: 1) assert +value == 1 def test_abs(lop): value = lop.Proxy(lambda: -1) assert abs(value) == 1 def test_invert(lop): value = lop.Proxy(lambda: 1) assert ~value == ~1 def test_oct(lop): value = lop.Proxy(lambda: 20) assert oct(value) == oct(20) def test_hex(lop): value = lop.Proxy(lambda: 20) assert hex(value) == hex(20) def test_index(lop): class Class: def __index__(self): return 1 value = lop.Proxy(lambda: Class()) items = [0, 1, 2] assert items[value] == items[1] def test_length(lop): value = lop.Proxy(lambda: list(range(3))) assert len(value) == 3 def test_contains(lop): value = lop.Proxy(lambda: list(range(3))) assert 2 in value assert -2 not in value def test_getitem(lop): value = lop.Proxy(lambda: list(range(3))) assert value[1] == 1 def test_setitem(lop): value = lop.Proxy(lambda: list(range(3))) value[1] = -1 assert value[1] == -1 def test_delitem(lop): value = lop.Proxy(lambda: list(range(3))) assert len(value) == 3 del value[1] assert len(value) == 2 assert value[1] == 2 def test_getslice(lop): value = lop.Proxy(lambda: list(range(5))) assert value[1:4] == [1, 2, 3] def test_setslice(lop): value = lop.Proxy(lambda: list(range(5))) value[1:4] = reversed(value[1:4]) assert value[1:4] == [3, 2, 1] def test_delslice(lop): value = lop.Proxy(lambda: list(range(5))) del value[1:4] assert len(value) == 2 assert value == [0, 4] def test_dict_length(lop): value = lop.Proxy(lambda: dict.fromkeys(range(3), False)) assert len(value) == 3 def test_dict_contains(lop): value = lop.Proxy(lambda: dict.fromkeys(range(3), False)) assert 2 in value assert -2 not in value def test_dict_getitem(lop): value = lop.Proxy(lambda: dict.fromkeys(range(3), False)) assert value[1] is False def test_dict_setitem(lop): value = lop.Proxy(lambda: dict.fromkeys(range(3), False)) value[1] = True assert value[1] is True def test_dict_delitem(lop): value = lop.Proxy(lambda: dict.fromkeys(range(3), False)) assert len(value) == 3 del value[1] assert len(value) == 2 def test_str(lop): value = lop.Proxy(lambda: 10) assert str(value) == str(10) value = lop.Proxy(lambda: (10,)) assert str(value) == str((10,)) value = lop.Proxy(lambda: [10]) assert str(value) == str([10]) value = lop.Proxy(lambda: {10: 10}) assert str(value) == str({10: 10}) def test_repr(lop): class Foobar: pass value = lop.Proxy(lambda: Foobar()) str(value) representation = repr(value) print(representation) assert 'Proxy at' in representation assert 'lambda' in representation assert 'Foobar' in representation def test_repr_doesnt_consume(lop): consumed = [] value = lop.Proxy(lambda: consumed.append(1)) print(repr(value)) assert not consumed def test_derived_new(lop): class DerivedObjectProxy(lop.Proxy): def __new__(cls, wrapped): instance = super().__new__(cls) instance.__init__(wrapped) return instance def __init__(self, wrapped): super().__init__(wrapped) def function(): return 123 obj = DerivedObjectProxy(lambda: function) assert obj() == 123 def test_setup_class_attributes(lop): def function(): pass class DerivedObjectProxy(lop.Proxy): pass obj = DerivedObjectProxy(lambda: function) DerivedObjectProxy.ATTRIBUTE = 1 assert obj.ATTRIBUTE == 1 assert not hasattr(function, 'ATTRIBUTE') del DerivedObjectProxy.ATTRIBUTE assert not hasattr(DerivedObjectProxy, 'ATTRIBUTE') assert not hasattr(obj, 'ATTRIBUTE') assert not hasattr(function, 'ATTRIBUTE') def test_override_class_attributes(lop): def function(): pass class DerivedObjectProxy(lop.Proxy): ATTRIBUTE = 1 obj = DerivedObjectProxy(lambda: function) assert DerivedObjectProxy.ATTRIBUTE == 1 assert obj.ATTRIBUTE == 1 obj.ATTRIBUTE = 2 assert DerivedObjectProxy.ATTRIBUTE == 1 assert obj.ATTRIBUTE == 2 assert not hasattr(function, 'ATTRIBUTE') del DerivedObjectProxy.ATTRIBUTE assert not hasattr(DerivedObjectProxy, 'ATTRIBUTE') assert obj.ATTRIBUTE == 2 assert not hasattr(function, 'ATTRIBUTE') def test_attr_functions(lop): def function(): pass proxy = lop.Proxy(lambda: function) assert hasattr(proxy, '__getattr__') assert hasattr(proxy, '__setattr__') assert hasattr(proxy, '__delattr__') def test_override_getattr(lop): def function(): pass accessed = [] class DerivedObjectProxy(lop.Proxy): def __getattr__(self, name): accessed.append(name) try: __getattr__ = super().__getattr__ except AttributeError as e: raise RuntimeError(str(e)) from e return __getattr__(name) function.attribute = 1 proxy = DerivedObjectProxy(lambda: function) assert proxy.attribute == 1 assert 'attribute' in accessed skipcallable = pytest.mark.xfail(reason="Don't know how to make this work. This tests the existence of the __call__ method.") @skipcallable def test_proxy_hasattr_call(lop): proxy = lop.Proxy(lambda: None) assert not callable(proxy) @skipcallable def test_proxy_getattr_call(lop): proxy = lop.Proxy(lambda: None) assert getattr(proxy, '__call__', None) is None @skipcallable def test_proxy_is_callable(lop): proxy = lop.Proxy(lambda: None) assert not callable(proxy) def test_callable_proxy_hasattr_call(lop): proxy = lop.Proxy(lambda: None) assert callable(proxy) @skipcallable def test_callable_proxy_getattr_call(lop): proxy = lop.Proxy(lambda: None) assert getattr(proxy, '__call__', None) is None def test_callable_proxy_is_callable(lop): proxy = lop.Proxy(lambda: None) assert callable(proxy) def test_class_bytes(lop): class Class: def __bytes__(self): return b'BYTES' instance = Class() proxy = lop.Proxy(lambda: instance) assert bytes(instance) == bytes(proxy) def test_str_format(lop): instance = 'abcd' proxy = lop.Proxy(lambda: instance) assert format(instance, ''), format(proxy == '') def test_list_reversed(lop): instance = [1, 2] proxy = lop.Proxy(lambda: instance) assert list(reversed(instance)) == list(reversed(proxy)) def test_decimal_complex(lop): import decimal instance = decimal.Decimal(123) proxy = lop.Proxy(lambda: instance) assert complex(instance) == complex(proxy) def test_fractions_round(lop): import fractions instance = fractions.Fraction('1/2') proxy = lop.Proxy(lambda: instance) assert round(instance) == round(proxy) def test_readonly(lop): proxy = lop.Proxy(lambda: object) assert proxy.__qualname__ == 'object' def test_del_wrapped(lop): foo = object() called = [] def make_foo(): called.append(1) return foo proxy = lop.Proxy(make_foo) str(proxy) assert called == [1] assert proxy.__wrapped__ is foo # print(type(proxy), hasattr(type(proxy), '__wrapped__')) del proxy.__wrapped__ str(proxy) assert called == [1, 1] def test_raise_attribute_error(lop): def foo(): raise AttributeError('boom!') proxy = lop.Proxy(foo) pytest.raises(AttributeError, str, proxy) pytest.raises(AttributeError, lambda: proxy.__wrapped__) assert proxy.__factory__ is foo def test_patching_the_factory(lop): def foo(): raise AttributeError('boom!') proxy = lop.Proxy(foo) pytest.raises(AttributeError, lambda: proxy.__wrapped__) assert proxy.__factory__ is foo proxy.__factory__ = lambda: foo pytest.raises(AttributeError, proxy) assert proxy.__wrapped__ is foo def test_deleting_the_factory(lop): proxy = lop.Proxy(None) assert proxy.__factory__ is None proxy.__factory__ = None assert proxy.__factory__ is None pytest.raises(TypeError, str, proxy) del proxy.__factory__ pytest.raises(ValueError, str, proxy) def test_patching_the_factory_with_none(lop): proxy = lop.Proxy(None) assert proxy.__factory__ is None proxy.__factory__ = None assert proxy.__factory__ is None proxy.__factory__ = None assert proxy.__factory__ is None def foo(): return 1 proxy.__factory__ = foo assert proxy.__factory__ is foo assert proxy.__wrapped__ == 1 assert str(proxy) == '1' def test_new(lop): a = lop.Proxy.__new__(lop.Proxy) b = lop.Proxy.__new__(lop.Proxy) # NOW KISS pytest.raises(ValueError, lambda: a + b) # no segfault, yay pytest.raises(ValueError, lambda: a.__wrapped__) def test_set_wrapped_via_new(lop): obj = lop.Proxy.__new__(lop.Proxy) obj.__wrapped__ = 1 assert str(obj) == '1' assert obj + 1 == 2 def test_set_wrapped_regular(lop): obj = lop.Proxy(None) obj.__wrapped__ = 1 assert str(obj) == '1' assert obj + 1 == 2 @pytest.fixture( params=[ 'pickle', ] ) def pickler(request): return pytest.importorskip(request.param) @pytest.mark.parametrize('obj', [1, 1.2, 'a', ['b', 'c'], {'d': 'e'}, date(2015, 5, 1), datetime(2015, 5, 1), Decimal('1.2')]) @pytest.mark.parametrize('level', range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickling(lop, obj, pickler, level): proxy = lop.Proxy(lambda: obj) dump = pickler.dumps(proxy, protocol=level) result = pickler.loads(dump) assert obj == result @pytest.mark.parametrize('level', range(pickle.HIGHEST_PROTOCOL + 1)) def test_pickling_exception(lop, pickler, level): class BadStuff(Exception): pass def trouble_maker(): raise BadStuff('foo') proxy = lop.Proxy(trouble_maker) pytest.raises(BadStuff, pickler.dumps, proxy, protocol=level) @pytest.mark.skipif(platform.python_implementation() != 'CPython', reason="Interpreter doesn't have reference counting") def test_garbage_collection(lop): leaky = lambda: "foobar" # noqa proxy = lop.Proxy(leaky) leaky.leak = proxy ref = weakref.ref(leaky) assert proxy == 'foobar' del leaky del proxy gc.collect() assert ref() is None @pytest.mark.skipif(platform.python_implementation() != 'CPython', reason="Interpreter doesn't have reference counting") def test_garbage_collection_count(lop): obj = object() count = sys.getrefcount(obj) for _ in range(100): str(lop.Proxy(lambda: obj)) assert count == sys.getrefcount(obj) @pytest.mark.parametrize('name', ['slots', 'cext', 'simple', 'django', 'objproxies']) def test_perf(benchmark, name, lop_loader): implementation = lop_loader(name) obj = 'foobar' proxied = implementation.Proxy(lambda: obj) assert benchmark(partial(str, proxied)) == obj empty = object() @pytest.fixture(scope='module', params=['SimpleProxy', 'LocalsSimpleProxy', 'CachedPropertyProxy', 'LocalsCachedPropertyProxy']) def prototype(request): from lazy_object_proxy.simple import cached_property name = request.param if name == 'SimpleProxy': class SimpleProxy: def __init__(self, factory): self.factory = factory self.object = empty def __str__(self): if self.object is empty: self.object = self.factory() return str(self.object) return SimpleProxy elif name == 'CachedPropertyProxy': class CachedPropertyProxy: def __init__(self, factory): self.factory = factory @cached_property def object(self): return self.factory() def __str__(self): return str(self.object) return CachedPropertyProxy elif name == 'LocalsSimpleProxy': class LocalsSimpleProxy: def __init__(self, factory): self.factory = factory self.object = empty def __str__(self, func=str): if self.object is empty: self.object = self.factory() return func(self.object) return LocalsSimpleProxy elif name == 'LocalsCachedPropertyProxy': class LocalsCachedPropertyProxy: def __init__(self, factory): self.factory = factory @cached_property def object(self): return self.factory() def __str__(self, func=str): return func(self.object) return LocalsCachedPropertyProxy @pytest.mark.benchmark(group='prototypes') def test_proto(benchmark, prototype): obj = 'foobar' proxied = prototype(lambda: obj) assert benchmark(partial(str, proxied)) == obj def test_subclassing_with_local_attr(lop): class Foo: pass called = [] class LazyProxy(lop.Proxy): name = None def __init__(self, func, **lazy_attr): super().__init__(func) for attr, val in lazy_attr.items(): setattr(self, attr, val) proxy = LazyProxy(lambda: called.append(1) or Foo(), name='bar') assert proxy.name == 'bar' assert not called def test_subclassing_dynamic_with_local_attr(lop): if lop.kind == 'cext': pytest.skip('Not possible.') class Foo: pass called = [] class LazyProxy(lop.Proxy): def __init__(self, func, **lazy_attr): super().__init__(func) for attr, val in lazy_attr.items(): object.__setattr__(self, attr, val) proxy = LazyProxy(lambda: called.append(1) or Foo(), name='bar') assert proxy.name == 'bar' assert not called class FSPathMock: def __fspath__(self): return '/foobar' @pytest.mark.skipif(not hasattr(os, 'fspath'), reason='No os.fspath support.') def test_fspath(lop): assert os.fspath(lop.Proxy(lambda: '/foobar')) == '/foobar' assert os.fspath(lop.Proxy(FSPathMock)) == '/foobar' with pytest.raises(TypeError) as excinfo: os.fspath(lop.Proxy(lambda: None)) assert '__fspath__() to return str or bytes, not NoneType' in excinfo.value.args[0] def test_fspath_method(lop): assert lop.Proxy(FSPathMock).__fspath__() == '/foobar' def test_resolved_new(lop): obj = lop.Proxy.__new__(lop.Proxy) assert obj.__resolved__ is False def test_resolved(lop): obj = lop.Proxy(lambda: None) assert obj.__resolved__ is False assert obj.__wrapped__ is None assert obj.__resolved__ is True def test_resolved_str(lop): obj = lop.Proxy(lambda: None) assert obj.__resolved__ is False str(obj) assert obj.__resolved__ is True python-lazy-object-proxy-1.10.0/tox.ini000066400000000000000000000040011453705455200200320ustar00rootroot00000000000000[testenv:bootstrap] deps = jinja2 tox skip_install = true commands = python ci/bootstrap.py --no-env passenv = * ; a generative tox configuration, see: https://tox.wiki/en/latest/user_guide.html#generative-environments [tox] envlist = clean, check, docs, {py38,py39,py310,py311,py312,pypy38,pypy39,pypy310}-{cover,nocov}, report ignore_basepython_conflict = true [testenv] basepython = pypy38: {env:TOXPYTHON:pypy3.8} pypy39: {env:TOXPYTHON:pypy3.9} pypy310: {env:TOXPYTHON:pypy3.10} py38: {env:TOXPYTHON:python3.8} py39: {env:TOXPYTHON:python3.9} py310: {env:TOXPYTHON:python3.10} py311: {env:TOXPYTHON:python3.11} py312: {env:TOXPYTHON:python3.12} {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 deps = pytest pytest-benchmark Django objproxies==0.9.4 hunter setuptools 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 --cov-report=xml -vv} [testenv:check] deps = docutils pre-commit readme-renderer pygments isort setuptools setuptools-scm skip_install = true commands = python setup.py check --strict --metadata --restructuredtext pre-commit run --all-files --show-diff-on-failure [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:report] deps = coverage skip_install = true commands = coverage report coverage html [testenv:clean] commands = coverage erase skip_install = true deps = coverage