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:

Reply via email to