Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-installer for openSUSE:Factory checked in at 2022-12-15 19:24:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-installer (Old) and /work/SRC/openSUSE:Factory/.python-installer.new.1835 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-installer" Thu Dec 15 19:24:11 2022 rev:4 rq:1042890 version:0.6.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-installer/python-installer.changes 2022-06-17 21:23:13.474796528 +0200 +++ /work/SRC/openSUSE:Factory/.python-installer.new.1835/python-installer.changes 2022-12-15 19:24:14.383726719 +0100 @@ -1,0 +2,6 @@ +Tue Dec 13 15:40:26 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to 0.6.0 + * Add support for Python 3.11 + +------------------------------------------------------------------- Old: ---- installer-0.5.1.tar.gz New: ---- installer-0.6.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-installer.spec ++++++ --- /var/tmp/diff_new_pack.QHh1Y1/_old 2022-12-15 19:24:14.951729952 +0100 +++ /var/tmp/diff_new_pack.QHh1Y1/_new 2022-12-15 19:24:14.959729997 +0100 @@ -26,7 +26,7 @@ %bcond_with test %endif Name: python-installer%{pkg_suffix} -Version: 0.5.1 +Version: 0.6.0 Release: 0 Summary: A library for installing Python wheels License: MIT ++++++ installer-0.5.1.tar.gz -> installer-0.6.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/.github/workflows/ci.yml new/installer-0.6.0/.github/workflows/ci.yml --- old/installer-0.5.1/.github/workflows/ci.yml 2022-02-16 20:24:54.870046600 +0100 +++ new/installer-0.6.0/.github/workflows/ci.yml 2022-12-07 03:28:06.838576600 +0100 @@ -4,6 +4,14 @@ push: branches: [main] +concurrency: + # prettier-ignore + group: >- + ${{ github.workflow }}- + ${{ github.ref_type }}- + ${{ github.event.pull_request.number || github.sha }} + cancel-in-progress: true + jobs: tests: name: tests / ${{ matrix.os }} / ${{ matrix.python-version }} @@ -12,17 +20,17 @@ strategy: matrix: os: [Windows, Ubuntu, MacOS] - python-version: ["3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] include: # Only run PyPy jobs, on Ubuntu. - os: Ubuntu python-version: pypy-3.7 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # Get Python to test against - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -34,7 +42,7 @@ id: pip-cache-dir run: echo "::set-output name=dir::$(pip cache dir)" - name: pip cache - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ${{ steps.pip-cache-dir.outputs.dir }} key: pip-v1-${{ runner.os }}-${{ steps.date.outputs.date }} @@ -42,9 +50,11 @@ - run: pip install nox + # prettier-ignore - run: > nox - -s test-${{ matrix.python-version }} doctest-${{ matrix.python-version }} + -s test-${{ matrix.python-version }} + doctest-${{ matrix.python-version }} --error-on-missing-interpreters if: matrix.python-version != 'pypy-3.7' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/.pre-commit-config.yaml new/installer-0.6.0/.pre-commit-config.yaml --- old/installer-0.5.1/.pre-commit-config.yaml 2022-02-16 20:24:54.870880800 +0100 +++ new/installer-0.6.0/.pre-commit-config.yaml 2022-12-07 03:28:06.838862000 +0100 @@ -1,6 +1,6 @@ repos: - repo: https://github.com/psf/black - rev: "22.1.0" + rev: "22.10.0" hooks: - id: black language_version: python3.8 @@ -12,13 +12,19 @@ files: \.py$ - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v0.931" + rev: "v0.991" hooks: - id: mypy exclude: docs/.*|tests/.*|noxfile.py + - repo: https://github.com/pre-commit/mirrors-prettier + rev: "v3.0.0-alpha.4" + hooks: + - id: prettier + args: [--prose-wrap, always] + - repo: https://github.com/pre-commit/pre-commit-hooks - rev: "v4.1.0" + rev: "v4.4.0" hooks: - id: check-builtin-literals - id: check-added-large-files @@ -31,7 +37,7 @@ - id: trailing-whitespace - repo: https://github.com/PyCQA/flake8 - rev: "4.0.1" + rev: "6.0.0" hooks: - id: flake8 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/.readthedocs.yml new/installer-0.6.0/.readthedocs.yml --- old/installer-0.5.1/.readthedocs.yml 2022-02-16 20:39:36.766151700 +0100 +++ new/installer-0.6.0/.readthedocs.yml 2022-03-24 09:42:24.281402800 +0100 @@ -8,3 +8,5 @@ version: 3.8 install: - requirements: docs/requirements.txt + - method: pip + path: . diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/CONTRIBUTING.md new/installer-0.6.0/CONTRIBUTING.md --- old/installer-0.5.1/CONTRIBUTING.md 2021-07-29 01:44:40.748468900 +0200 +++ new/installer-0.6.0/CONTRIBUTING.md 2022-03-13 08:38:01.852072000 +0100 @@ -13,8 +13,8 @@ ## Bugs and Feature Requests If you have found any bugs or would like to request a new feature, please do -check if there is an existing issue already filed for the same, in the -project's GitHub [issue tracker]. If not, please file a new issue. +check if there is an existing issue already filed for the same, in the project's +GitHub [issue tracker]. If not, please file a new issue. If you want to help out by fixing bugs, choose an open issue in the [issue tracker] to work on and claim it by posting a comment saying "I would like to @@ -35,7 +35,7 @@ Checklist: -1. All pull requests *must* be made against the `main` branch. +1. All pull requests _must_ be made against the `main` branch. 2. Include tests for any functionality you implement. Any contributions helping improve existing tests are welcome. 3. Update documentation as necessary and provide documentation for any new @@ -94,8 +94,10 @@ [pytest]: https://docs.pytest.org/en/stable/ [coverage]: https://coverage.readthedocs.io/ -[code coverage isn't everything]: https://bryanpendleton.blogspot.com/2011/02/code-coverage-isnt-everything-but-its.html -[pytest's rich CLI]: https://docs.pytest.org/en/latest/usage.html#specifying-tests-selecting-tests +[code coverage isn't everything]: + https://bryanpendleton.blogspot.com/2011/02/code-coverage-isnt-everything-but-its.html +[pytest's rich cli]: + https://docs.pytest.org/en/latest/usage.html#specifying-tests-selecting-tests ### Documentation @@ -107,4 +109,4 @@ $ nox -s docs ``` -[Sphinx]: https://www.sphinx-doc.org/ +[sphinx]: https://www.sphinx-doc.org/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/PKG-INFO new/installer-0.6.0/PKG-INFO --- old/installer-0.5.1/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 +++ new/installer-0.6.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +1,28 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: installer -Version: 0.5.1 +Version: 0.6.0 Summary: A library for installing Python wheels. -Home-page: None -Author: None Author-email: Pradyun Gedam <pradyu...@gmail.com> +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +Classifier: License :: OSI Approved :: MIT License +Project-URL: GitHub, https://github.com/pypa/installer + +# installer + +<!-- start readme-pitch --> + +This is a low-level library for installing a Python package from a +[wheel distribution](https://packaging.python.org/glossary/#term-Wheel). It +provides basic functionality and abstractions for handling wheels and installing +packages from wheels. + +- Logic for "unpacking" a wheel (i.e. installation). +- Abstractions for various parts of the unpacking process. +- Extensible simple implementations of the abstractions. +- Platform-independent Python script wrapper generation. + +<!-- end readme-pitch --> + +You can read more in the [documentation](https://installer.rtfd.io/). + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/README.md new/installer-0.6.0/README.md --- old/installer-0.5.1/README.md 2021-07-29 01:44:40.748786000 +0200 +++ new/installer-0.6.0/README.md 2022-03-13 08:38:01.852336600 +0100 @@ -3,9 +3,9 @@ <!-- start readme-pitch --> This is a low-level library for installing a Python package from a -[wheel distribution](https://packaging.python.org/glossary/#term-Wheel). -It provides basic functionality and abstractions for handling wheels and -installing packages from wheels. +[wheel distribution](https://packaging.python.org/glossary/#term-Wheel). It +provides basic functionality and abstractions for handling wheels and installing +packages from wheels. - Logic for "unpacking" a wheel (i.e. installation). - Abstractions for various parts of the unpacking process. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/docs/_static/custom.css new/installer-0.6.0/docs/_static/custom.css --- old/installer-0.5.1/docs/_static/custom.css 2021-07-29 01:44:40.749075700 +0200 +++ new/installer-0.6.0/docs/_static/custom.css 2022-03-13 08:38:01.852982300 +0100 @@ -3,7 +3,7 @@ /* Make inline code blocks nicer to look at */ code.literal { border-radius: 0.3em; - padding: 0.0em 0.3em; + padding: 0em 0.3em; } div.highlight pre { @@ -21,8 +21,9 @@ /* Add a tiny dash of color to names of things */ dt > .property { - color: #A02000; + color: #a02000; } -.sig-name, .sig-prename { +.sig-name, +.sig-prename { color: #0066bb; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/docs/changelog.md new/installer-0.6.0/docs/changelog.md --- old/installer-0.5.1/docs/changelog.md 2022-03-11 09:49:14.268968300 +0100 +++ new/installer-0.6.0/docs/changelog.md 2022-12-07 03:29:41.190069000 +0100 @@ -1,5 +1,16 @@ # Changelog +## v0.6.0 (Dec 7, 2022) + +- Add support for Python 3.11 (#154) +- Encode hashes in `RECORD` files correctly (#141) +- Add `py.typed` marker file (#138) +- Implement `--prefix` option (#103) +- Fix the unbound `is_executable` (#115) +- Construct `RECORD` file using `csv.writer` (#118) +- Move away from `import installer.xyz` style imports (#110) +- Improve existing documentation content (typos, formatting) (#109) + ## v0.5.1 (Mar 11, 2022) - Change all names in `installer.__main__` to be underscore prefixed. @@ -38,9 +49,9 @@ {any}`RecordEntry` objects. - Implement {any}`WheelFile`, completing the end-to-end wheel installation pipeline. -- Generate {any}`RecordEntry` for `RECORD` file in the - {any}`installer.install`, instead of requiring every `WheelDestination` - implementation to do the exact same thing. +- Generate {any}`RecordEntry` for `RECORD` file in the {any}`installer.install`, + instead of requiring every `WheelDestination` implementation to do the exact + same thing. ## v0.2.0 (May 3, 2021) @@ -48,9 +59,9 @@ --- -Thank you to [Dan Ryan] and [Tzu-ping Chung] for the project name on -PyPI. The PyPI releases before 0.2.0 come from -<https://github.com/sarugaku/installer> and have been [yanked]. +Thank you to [Dan Ryan] and [Tzu-ping Chung] for the project name on PyPI. The +PyPI releases before 0.2.0 come from <https://github.com/sarugaku/installer> and +have been [yanked]. [dan ryan]: https://github.com/techalchemy [tzu-ping chung]: https://github.com/uranusjr diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/docs/concepts.md new/installer-0.6.0/docs/concepts.md --- old/installer-0.5.1/docs/concepts.md 2021-07-29 01:44:40.750274200 +0200 +++ new/installer-0.6.0/docs/concepts.md 2022-03-13 08:38:01.853547600 +0100 @@ -2,39 +2,37 @@ This library has two main abstractions: -- {any}`WheelSource`: Serves as source of information about a wheel - file. -- {any}`WheelDestination`: Handles all file writing and - post-installation processing. +- {any}`WheelSource`: Serves as source of information about a wheel file. +- {any}`WheelDestination`: Handles all file writing and post-installation + processing. ## WheelSource -These objects represent a wheel file, abstracting away how the actual -file is stored or accessed. +These objects represent a wheel file, abstracting away how the actual file is +stored or accessed. -This allows the core install logic to be used with in-memory wheel -files, or unzipped-on-disk wheel, or with {any}`zipfile.ZipFile` -objects from an on-disk wheel, or something else entirely. - -This protocol/abstraction is designed to be implementable without a -direct dependency on this library. This allows for other libraries in -the Python Packaging ecosystem to provide implementations of the -protocol, allowing for more code reuse opportunities. - -One of the benefits of this fully described interface is the possibility -to decouple the implementation of additional validation on wheels -(such as validating the RECORD entries in a wheel match the actual -contents of the wheel, or enforcing signing requirements) based on what -the specific usecase demands. +This allows the core install logic to be used with in-memory wheel files, or +unzipped-on-disk wheel, or with {any}`zipfile.ZipFile` objects from an on-disk +wheel, or something else entirely. + +This protocol/abstraction is designed to be implementable without a direct +dependency on this library. This allows for other libraries in the Python +packaging ecosystem to provide implementations of the protocol, allowing for +more code reuse opportunities. + +One of the benefits of this fully described interface is the possibility to +decouple the implementation of additional validation on wheels (such as +validating the RECORD entries in a wheel match the actual contents of the wheel, +or enforcing signing requirements) based on what the specific usecase demands. ## WheelDestination These objects are responsible for handling the writing-to-filesystem -interactions, determining RECORD file entries and post-install actions -(like generating .pyc files). While this is a lot of responsibility, -this was explicitly provided to make it possible for custom -`WheelDestination` implementations to be more powerful and flexible. - -Most of these tasks can either be delegated to utilities provided in -this library (eg: script generation), or to the Python standard libary -(eg: generating `.pyc` files). +interactions, determining RECORD file entries and post-install actions (like +generating .pyc files). While this is a lot of responsibility, this was +explicitly provided to make it possible for custom `WheelDestination` +implementations to be more powerful and flexible. + +Most of these tasks can either be delegated to utilities provided in this +library (eg: script generation), or to the Python standard libary (eg: +generating `.pyc` files). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/docs/conf.py new/installer-0.6.0/docs/conf.py --- old/installer-0.5.1/docs/conf.py 2022-02-16 20:41:21.967974400 +0100 +++ new/installer-0.6.0/docs/conf.py 2022-03-24 09:42:34.875664200 +0100 @@ -1,10 +1,6 @@ """A sphinx documentation configuration file. """ -import os -import pathlib -import sys - # -- Project information --------------------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information @@ -44,14 +40,6 @@ # Don't show the class signature with the class name. autodoc_class_signature = "separated" -if "READTHEDOCS" in os.environ: - src_folder = pathlib.Path(__file__).resolve().parent.parent / "src" - sys.path.append(str(src_folder)) - - print("Detected running on ReadTheDocs") - print(f"Added {src_folder} to sys.path") - __import__("installer") - # -- Options for intersphinx ---------------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html#configuration diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/docs/development/design.md new/installer-0.6.0/docs/development/design.md --- old/installer-0.5.1/docs/development/design.md 2021-07-29 01:44:40.750646800 +0200 +++ new/installer-0.6.0/docs/development/design.md 2022-03-13 08:38:01.853908500 +0100 @@ -3,7 +3,7 @@ ## What this is for This project is born out of [this discussion][1]. Effectively, the volunteers -who maintain the Python Packaging toolchain identified a need for a library in +who maintain the Python packaging toolchain identified a need for a library in the ecology that handles the details of "wheel -> installed package". This is that library. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/docs/development/index.md new/installer-0.6.0/docs/development/index.md --- old/installer-0.5.1/docs/development/index.md 2021-07-29 01:44:40.750800400 +0200 +++ new/installer-0.6.0/docs/development/index.md 2022-03-13 08:38:01.854266000 +0100 @@ -3,8 +3,8 @@ Thank you for your interest in installer! ⨠installer is a volunteer maintained open source project, and we welcome -contributions of all forms. This section of installer's documentation -serves as a resource to help you to contribute to the project. +contributions of all forms. This section of installer's documentation serves as +a resource to help you to contribute to the project. ```{toctree} :hidden: @@ -13,6 +13,7 @@ design ``` +<!-- prettier-ignore-start --> [Code of Conduct] : Applies within all community spaces. If you are not familiar with our Code of Conduct, take a minute to read it before starting with your first contribution. @@ -21,5 +22,6 @@ [Design and Scope](./design) : Describes what this project is for, and how that informs the design decisions made. +<!-- prettier-ignore-end --> [code of conduct]: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/docs/development/workflow.md new/installer-0.6.0/docs/development/workflow.md --- old/installer-0.5.1/docs/development/workflow.md 2021-10-13 20:48:27.358275700 +0200 +++ new/installer-0.6.0/docs/development/workflow.md 2022-03-13 08:38:01.854580900 +0100 @@ -1,13 +1,12 @@ # Workflow -This page describes the tooling used during development of this -project. It also serves as a reference for the various commands that -you would use when working on this project. +This page describes the tooling used during development of this project. It also +serves as a reference for the various commands that you would use when working +on this project. ## Overview -This project uses the [GitHub Flow] for collaboration. The codebase -is Python. +This project uses the [GitHub Flow] for collaboration. The codebase is Python. - [flit] is used for automating development tasks. - [nox] is used for automating development tasks. @@ -17,8 +16,7 @@ ## Repository Layout -The repository layout is pretty standard for a modern pure-Python -project. +The repository layout is pretty standard for a modern pure-Python project. - `CODE_OF_CONDUCT.md` - `LICENSE` @@ -67,15 +65,15 @@ nox -s test ``` -Run the tests against all supported Python versions, if an interpreter for -that version is available locally. +Run the tests against all supported Python versions, if an interpreter for that +version is available locally. ```sh nox -s test-3.9 ``` -Run the tests against Python 3.9. It is also possible to specify other -supported Python versions (like `3.7` or `pypy3`). +Run the tests against Python 3.9. It is also possible to specify other supported +Python versions (like `3.7` or `pypy3`). ### Documentation @@ -83,20 +81,20 @@ nox -s docs ``` -Generate the documentation for installer into the `build/docs` folder. -This (mostly) does the same thing as `nox -s docs-live`, except it -invokes `sphinx-build` instead of [sphinx-autobuild]. +Generate the documentation for installer into the `build/docs` folder. This +(mostly) does the same thing as `nox -s docs-live`, except it invokes +`sphinx-build` instead of [sphinx-autobuild]. ```sh nox -s docs-live ``` -Serve this project's documentation locally, using [sphinx-autobuild]. -This will open the generated documentation page in your browser. +Serve this project's documentation locally, using [sphinx-autobuild]. This will +open the generated documentation page in your browser. -The server also watches for changes made to the documentation (`docs/`), -which will trigger a rebuild. Once the build is completed, server will -automagically reload any open pages using livereload. +The server also watches for changes made to the documentation (`docs/`), which +will trigger a rebuild. Once the build is completed, server will automagically +reload any open pages using livereload. ## Release process diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/noxfile.py new/installer-0.6.0/noxfile.py --- old/installer-0.5.1/noxfile.py 2021-10-24 09:42:13.561079500 +0200 +++ new/installer-0.6.0/noxfile.py 2022-12-07 03:28:06.839124200 +0100 @@ -20,7 +20,7 @@ session.run("flit", "install", "--deps=production", *args, silent=True) -@nox.session(python="3.8") +@nox.session(python="3.11") def lint(session): session.install("pre-commit") @@ -34,7 +34,7 @@ session.run("pre-commit", "run", "--all-files", *args) -@nox.session(python=["3.7", "3.8", "3.9", "3.10", "pypy3"]) +@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11", "pypy3"]) def test(session): _install_this_project_with_flit(session, editable=True) session.install("-r", "tests/requirements.txt") @@ -54,7 +54,7 @@ ) -@nox.session(python=["3.7", "3.8", "3.9", "3.10", "pypy3"]) +@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11", "pypy3"]) def doctest(session): session.install(".") session.install("-r", "docs/requirements.txt") @@ -62,7 +62,7 @@ session.run("sphinx-build", "-b", "doctest", "docs/", "build/doctest") -@nox.session(python="3.8", name="update-launchers") +@nox.session(python="3.11", name="update-launchers") def update_launchers(session): session.install("httpx") session.run("python", "tools/update_launchers.py") @@ -71,7 +71,7 @@ # # Documentation # -@nox.session(python="3.8") +@nox.session(python="3.11") def docs(session): _install_this_project_with_flit(session) session.install("-r", "docs/requirements.txt") @@ -80,7 +80,7 @@ session.run("sphinx-build", "-W", "-b", "html", "docs/", "build/docs") -@nox.session(name="docs-live", python="3.8") +@nox.session(name="docs-live", python="3.11") def docs_live(session): _install_this_project_with_flit(session, editable=True) session.install("-r", "docs/requirements.txt") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/setup.py new/installer-0.6.0/setup.py --- old/installer-0.5.1/setup.py 1970-01-01 01:00:00.000000000 +0100 +++ new/installer-0.6.0/setup.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,25 +0,0 @@ -#!/usr/bin/env python -# setup.py generated by flit for tools that don't yet use PEP 517 - -from distutils.core import setup - -packages = \ -['installer', 'installer._scripts'] - -package_data = \ -{'': ['*']} - -package_dir = \ -{'': 'src'} - -setup(name='installer', - version='0.5.1', - description='A library for installing Python wheels.', - author=None, - author_email='Pradyun Gedam <pradyu...@gmail.com>', - url=None, - packages=packages, - package_data=package_data, - package_dir=package_dir, - python_requires='>=3.7', - ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/src/installer/__init__.py new/installer-0.6.0/src/installer/__init__.py --- old/installer-0.5.1/src/installer/__init__.py 2022-03-11 09:50:21.574751100 +0100 +++ new/installer-0.6.0/src/installer/__init__.py 2022-12-07 03:30:07.284015000 +0100 @@ -1,6 +1,6 @@ """A library for installing Python wheels.""" -__version__ = "0.5.1" +__version__ = "0.6.0" __all__ = ["install"] from installer._core import install # noqa diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/src/installer/__main__.py new/installer-0.6.0/src/installer/__main__.py --- old/installer-0.5.1/src/installer/__main__.py 2022-03-11 09:08:15.070507300 +0100 +++ new/installer-0.6.0/src/installer/__main__.py 2022-12-07 03:28:06.839389000 +0100 @@ -24,6 +24,13 @@ help="destination directory (prefix to prepend to each file)", ) parser.add_argument( + "--prefix", + "-p", + metavar="path", + type=str, + help="override prefix to install packages to", + ) + parser.add_argument( "--compile-bytecode", action="append", metavar="level", @@ -39,12 +46,18 @@ return parser -def _get_scheme_dict(distribution_name: str) -> Dict[str, str]: +def _get_scheme_dict( + distribution_name: str, prefix: Optional[str] = None +) -> Dict[str, str]: """Calculate the scheme dictionary for the current Python environment.""" - scheme_dict = sysconfig.get_paths() + vars = {} + if prefix is None: + installed_base = sysconfig.get_config_var("base") + assert installed_base + else: + vars["base"] = vars["platbase"] = installed_base = prefix - installed_base = sysconfig.get_config_var("base") - assert installed_base + scheme_dict = sysconfig.get_paths(vars=vars) # calculate 'headers' path, not currently in sysconfig - see # https://bugs.python.org/issue44445. This is based on what distutils does. @@ -72,7 +85,7 @@ with WheelFile.open(args.wheel) as source: destination = SchemeDictionaryDestination( - scheme_dict=_get_scheme_dict(source.distribution), + scheme_dict=_get_scheme_dict(source.distribution, prefix=args.prefix), interpreter=sys.executable, script_kind=get_launcher_kind(), bytecode_optimization_levels=bytecode_levels, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/src/installer/_core.py new/installer-0.6.0/src/installer/_core.py --- old/installer-0.5.1/src/installer/_core.py 2022-02-16 20:24:54.873332700 +0100 +++ new/installer-0.6.0/src/installer/_core.py 2022-12-07 03:28:06.839731500 +0100 @@ -71,7 +71,7 @@ :param source: wheel to install. :param destination: where to write the wheel. :param additional_metadata: additional metadata files to generate, usually - generated by the installer. + generated by the caller. """ root_scheme = _process_WHEEL_file(source) @@ -123,7 +123,7 @@ scheme=root_scheme, path=path, stream=other_stream, - is_executable=is_executable, + is_executable=False, ) written_records.append((root_scheme, record)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/src/installer/records.py new/installer-0.6.0/src/installer/records.py --- old/installer-0.5.1/src/installer/records.py 2022-02-16 20:24:54.874736500 +0100 +++ new/installer-0.6.0/src/installer/records.py 2022-12-07 03:28:06.840245700 +0100 @@ -103,11 +103,11 @@ self.hash_ = hash_ self.size = size - def to_line(self, path_prefix: Optional[str] = None) -> bytes: - """Convert this into a line that can be written in a RECORD file. + def to_row(self, path_prefix: Optional[str] = None) -> Tuple[str, str, str]: + """Convert this into a 3-element tuple that can be written in a RECORD file. :param path_prefix: A prefix to attach to the path -- must end in `/` - :return: A binary-encoded line, that doesn't contain a newline + :return: a (path, hash, size) row """ if path_prefix is not None: assert path_prefix.endswith("/") @@ -119,13 +119,11 @@ if os.sep == "\\": path = path.replace("\\", "/") # pragma: no cover - entry = ",".join( - [ - (str(elem) if elem is not None else "") - for elem in [path, self.hash_, self.size] - ] + return ( + path, + str(self.hash_ or ""), + str(self.size) if self.size is not None else "", ) - return entry.encode("utf-8") def __repr__(self) -> str: return "RecordEntry(path={!r}, hash_={!r}, size={!r})".format( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/src/installer/sources.py new/installer-0.6.0/src/installer/sources.py --- old/installer-0.5.1/src/installer/sources.py 2022-02-16 20:24:54.875755000 +0100 +++ new/installer-0.6.0/src/installer/sources.py 2022-03-24 09:42:55.220565300 +0100 @@ -7,8 +7,8 @@ from contextlib import contextmanager from typing import BinaryIO, Iterator, List, Tuple, cast -import installer.records -import installer.utils +from installer.records import parse_record_file +from installer.utils import parse_wheel_filename WheelContentElement = Tuple[Tuple[str, str, str], BinaryIO, bool] @@ -109,7 +109,7 @@ assert f.filename basename = os.path.basename(f.filename) - parsed_name = installer.utils.parse_wheel_filename(basename) + parsed_name = parse_wheel_filename(basename) super().__init__( version=parsed_name.version, distribution=parsed_name.distribution, @@ -147,7 +147,7 @@ """ # Convert the record file into a useful mapping record_lines = self.read_dist_info("RECORD").splitlines() - records = installer.records.parse_record_file(record_lines) + records = parse_record_file(record_lines) record_mapping = {record[0]: record for record in records} for item in self._zipfile.infolist(): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/src/installer/utils.py new/installer-0.6.0/src/installer/utils.py --- old/installer-0.5.1/src/installer/utils.py 2022-02-16 20:24:54.876176000 +0100 +++ new/installer-0.6.0/src/installer/utils.py 2022-12-07 03:28:06.840684400 +0100 @@ -1,6 +1,8 @@ """Utilities related to handling / interacting with wheel files.""" +import base64 import contextlib +import csv import hashlib import io import os @@ -129,7 +131,7 @@ dest.write(buf) size += len(buf) - return hasher.hexdigest(), size + return base64.urlsafe_b64encode(hasher.digest()).decode("ascii").rstrip("="), size def get_launcher_kind() -> "LauncherKind": # pragma: no cover @@ -192,11 +194,14 @@ :return: A stream that can be written to file. Must be closed by the caller. """ - stream = io.BytesIO() + stream = io.TextIOWrapper( + io.BytesIO(), encoding="utf-8", write_through=True, newline="" + ) + writer = csv.writer(stream, delimiter=",", quotechar='"', lineterminator="\n") for scheme, record in records: - stream.write(record.to_line(prefix_for_scheme(scheme)) + b"\n") + writer.writerow(record.to_row(prefix_for_scheme(scheme))) stream.seek(0) - return stream + return stream.detach() def parse_entrypoints(text: str) -> Iterable[Tuple[str, str, str, "ScriptSection"]]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/tests/test_core.py new/installer-0.6.0/tests/test_core.py --- old/installer-0.5.1/tests/test_core.py 2022-02-16 20:24:54.876905000 +0100 +++ new/installer-0.6.0/tests/test_core.py 2022-12-07 03:28:06.841139300 +0100 @@ -25,7 +25,6 @@ # A hacky approach to making sure we got the right objects going in. def custom_write_file(scheme, path, stream, is_executable): assert isinstance(stream, BytesIO) - assert is_executable is False return (path, scheme, 0) def custom_write_script(name, module, attr, section): @@ -834,3 +833,73 @@ ) assert "fancy-1.0.0.data/invalid/fancy/invalid.py" in str(ctx.value) + + def test_ensure_non_executable_for_additional_metadata(self, mock_destination): + # Create a fake wheel + source = FakeWheelSource( + distribution="fancy", + version="1.0.0", + regular_files={ + "fancy/__init__.py": b"""\ + # put me in purelib + """, + }, + dist_info_files={ + "top_level.txt": b"""\ + fancy + """, + "WHEEL": b"""\ + Wheel-Version: 1.0 + Generator: magic (1.0.0) + Root-Is-Purelib: true + Tag: py3-none-any + """, + "METADATA": b"""\ + Metadata-Version: 2.1 + Name: fancy + Version: 1.0.0 + Summary: A fancy package + Author: Agendaless Consulting + Author-email: nob...@example.com + License: MIT + Keywords: fancy amazing + Platform: UNKNOWN + Classifier: Intended Audience :: Developers + """, + }, + ) + all_contents = list(source.get_contents()) + source.get_contents = lambda: ( + (*contents, True) for (*contents, _) in all_contents + ) + install( + source=source, + destination=mock_destination, + additional_metadata={ + "fun_file.txt": b"this should be in dist-info!", + }, + ) + + mock_destination.assert_has_calls( + [ + mock.call.write_file( + scheme="purelib", + path="fancy/__init__.py", + stream=mock.ANY, + is_executable=True, + ), + mock.call.write_file( + scheme="purelib", + path="fancy-1.0.0.dist-info/METADATA", + stream=mock.ANY, + is_executable=True, + ), + mock.call.write_file( + scheme="purelib", + path="fancy-1.0.0.dist-info/fun_file.txt", + stream=mock.ANY, + is_executable=False, + ), + ], + any_order=True, + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/tests/test_destinations.py new/installer-0.6.0/tests/test_destinations.py --- old/installer-0.5.1/tests/test_destinations.py 2022-02-16 20:24:54.877523400 +0100 +++ new/installer-0.6.0/tests/test_destinations.py 2022-12-07 03:28:06.841588700 +0100 @@ -124,7 +124,7 @@ "data", destination.write_file( "data", - "my_data3.bin", + "my_data3,my_data4.bin", io.BytesIO(b"my data 3"), is_executable=False, ), @@ -163,11 +163,11 @@ data = f.read() assert data == ( - b"../data/my_data1.bin,sha256=355d00f8ce0e3eea93b078de0fa5ad87ff94aaba40000772a6572eb2d159f2ce,9\n" - b"../data/my_data2.bin,sha256=94fed5f2858baa0c9709b74048d88f76c5288333d466186dffb17c4f96c2dde4,9\n" - b"../data/my_data3.bin,sha256=d7c92baeebb582bd35c7e58cffd0a14804a81efd267d1015ebe0766ddf6cc69a,9\n" - b"../scripts/my_script,sha256=33ad1f5af51230990fb70d9aa54be3596c0e72744f715cbfccee3ee25a47d3ca,9\n" - b"../scripts/my_script2,sha256=93dffdf7b9136d36109bb11714b7255592f59b637df2b53dd105f8e9778cbe36,22\n" - b"../scripts/my_entrypoint,sha256=fe9ffd9f099e21ea0c05f4346a486bd4a6ca9f795a0f2760d09edccb416ce892,216\n" + b"../data/my_data1.bin,sha256=NV0A-M4OPuqTsHjeD6Wth_-UqrpAAAdyplcustFZ8s4,9\n" + b"../data/my_data2.bin,sha256=lP7V8oWLqgyXCbdASNiPdsUogzPUZhht_7F8T5bC3eQ,9\n" + b'"../data/my_data3,my_data4.bin",sha256=18krruu1gr01x-WM_9ChSASoHv0mfRAV6-B2bd9sxpo,9\n' + b"../scripts/my_script,sha256=M60fWvUSMJkPtw2apUvjWWwOcnRPcVy_zO4-4lpH08o,9\n" + b"../scripts/my_script2,sha256=k9_997kTbTYQm7EXFLclVZL1m2N98rU90QX46XeMvjY,22\n" + b"../scripts/my_entrypoint,sha256=_p_9nwmeIeoMBfQ0akhr1KbKn3laDydg0J7cy0Fs6JI,216\n" b"RECORD,,\n" ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/tests/test_main.py new/installer-0.6.0/tests/test_main.py --- old/installer-0.5.1/tests/test_main.py 2022-02-17 02:45:44.163254000 +0100 +++ new/installer-0.6.0/tests/test_main.py 2022-12-07 03:28:06.842462000 +0100 @@ -1,3 +1,5 @@ +import os + from installer.__main__ import _get_scheme_dict as get_scheme_dict from installer.__main__ import _main as main @@ -7,6 +9,14 @@ assert set(d.keys()) >= {"purelib", "platlib", "headers", "scripts", "data"} +def test_get_scheme_dict_prefix(): + d = get_scheme_dict(distribution_name="foo", prefix="/foo") + for key in ("purelib", "platlib", "headers", "scripts", "data"): + assert d[key].startswith( + f"{os.sep}foo" + ), f"{key} does not start with /foo: {d[key]}" + + def test_main(fancy_wheel, tmp_path): destdir = tmp_path / "dest" @@ -17,6 +27,26 @@ assert {f.stem for f in installed_py_files} == {"__init__", "__main__", "data"} installed_pyc_files = destdir.rglob("*.pyc") + assert {f.name.split(".")[0] for f in installed_pyc_files} == { + "__init__", + "__main__", + } + + +def test_main_prefix(fancy_wheel, tmp_path): + destdir = tmp_path / "dest" + + main([str(fancy_wheel), "-d", str(destdir), "-p", "/foo"], "python -m installer") + + installed_py_files = list(destdir.rglob("*.py")) + + for f in installed_py_files: + assert str(f.parent).startswith( + str(destdir / "foo") + ), f"path does not respect destdir+prefix: {f}" + assert {f.stem for f in installed_py_files} == {"__init__", "__main__", "data"} + + installed_pyc_files = destdir.rglob("*.pyc") assert {f.name.split(".")[0] for f in installed_pyc_files} == { "__init__", "__main__", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/tests/test_records.py new/installer-0.6.0/tests/test_records.py --- old/installer-0.5.1/tests/test_records.py 2021-10-24 09:42:13.565047700 +0200 +++ new/installer-0.6.0/tests/test_records.py 2022-12-07 03:28:06.842787300 +0100 @@ -136,10 +136,10 @@ def test_string_representation(self, scheme, elements, data, passes_validation): record = RecordEntry.from_elements(*elements) - expected_string_value = ",".join( + expected_row = tuple( [(str(elem) if elem is not None else "") for elem in elements] ) - assert record.to_line() == expected_string_value.encode() + assert record.to_row() == expected_row @pytest.mark.parametrize( ("scheme", "elements", "data", "passes_validation"), SAMPLE_RECORDS @@ -149,10 +149,13 @@ ): record = RecordEntry.from_elements(*elements) - expected_string_value = "prefix/" + ",".join( - [(str(elem) if elem is not None else "") for elem in elements] + expected_row = tuple( + [ + (str(elem) if elem is not None else "") + for elem in ("prefix/" + elements[0], elements[1], elements[2]) + ] ) - assert record.to_line("prefix/") == expected_string_value.encode() + assert record.to_row("prefix/") == expected_row def test_equality(self): record = RecordEntry.from_elements( @@ -255,3 +258,18 @@ list(parse_record_file(record_lines)) assert "Row Index 3" in str(exc_info.value) + + def test_parse_record_entry_with_comma(self): + record_lines = [ + '"file1,file2.txt",sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI,3144', + "distribution-1.0.dist-info/RECORD,,", + ] + records = list(parse_record_file(record_lines)) + assert records == [ + ( + "file1,file2.txt", + "sha256=AVTFPZpEKzuHr7OvQZmhaU3LvwKz06AJw8mT\\_pNh2yI", + "3144", + ), + ("distribution-1.0.dist-info/RECORD", "", ""), + ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/installer-0.5.1/tests/test_utils.py new/installer-0.6.0/tests/test_utils.py --- old/installer-0.5.1/tests/test_utils.py 2021-10-24 09:42:13.566290900 +0200 +++ new/installer-0.6.0/tests/test_utils.py 2022-12-07 03:28:06.843163700 +0100 @@ -1,6 +1,7 @@ """Tests for installer.utils """ +import base64 import hashlib import textwrap from email.message import Message @@ -96,7 +97,11 @@ class TestCopyFileObjWithHashing: def test_basic_functionality(self): data = b"input data is this" - hash_ = hashlib.sha256(data).hexdigest() + hash_ = ( + base64.urlsafe_b64encode(hashlib.sha256(data).digest()) + .decode("ascii") + .rstrip("=") + ) size = len(data) with BytesIO(data) as source: