From 69d599873d8a8d8a660bac3894872e3017f96bbe Mon Sep 17 00:00:00 2001 From: 5j9 <5j9@users.noreply.github.com> Date: Fri, 7 Jul 2023 05:31:27 +0330 Subject: [PATCH 01/54] Use '.' as the default value for Path constructor closes #212 --- path/__init__.py | 4 +++- test_path.py | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/path/__init__.py b/path/__init__.py index 7d46d1d2..c8ef6a4b 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -141,8 +141,10 @@ class Path(str): .. seealso:: :mod:`os.path` """ + def __new__(cls, /, object='.'): + return super().__new__(cls, object) - def __init__(self, other=''): + def __init__(self, other='.'): if other is None: raise TypeError("Invalid initial value for path: None") with contextlib.suppress(AttributeError): diff --git a/test_path.py b/test_path.py index d1053692..0bd3ffd1 100644 --- a/test_path.py +++ b/test_path.py @@ -78,6 +78,12 @@ def test_relpath(self): d = Path('D:\\') assert d.relpathto(boz) == boz + def test_construction_without_args(self): + """ + Path class will construct a path to current directory when called with no arguments. + """ + assert Path() == '.' + def test_construction_from_none(self): """ """ with pytest.raises(TypeError): @@ -432,7 +438,7 @@ def test_startfile(monkeypatch): results = [] monkeypatch.setattr(os, 'startfile', results.append) Path().startfile() - assert results == [''] + assert results == ['.'] class TestScratchDir: From 69346dd1cc0ea32999d643d4df7df8a6ac66df99 Mon Sep 17 00:00:00 2001 From: 5j9 <5j9@users.noreply.github.com> Date: Fri, 7 Jul 2023 05:50:02 +0330 Subject: [PATCH 02/54] Use `other` instead of `object` (a built-in name) --- path/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/path/__init__.py b/path/__init__.py index c8ef6a4b..c0c15ac8 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -141,8 +141,8 @@ class Path(str): .. seealso:: :mod:`os.path` """ - def __new__(cls, /, object='.'): - return super().__new__(cls, object) + def __new__(cls, /, other='.'): + return super().__new__(cls, other) def __init__(self, other='.'): if other is None: From 79e9c94026a0667da4507962f99cd43ac47f675e Mon Sep 17 00:00:00 2001 From: 5j9 <5j9@users.noreply.github.com> Date: Fri, 7 Jul 2023 19:17:51 +0330 Subject: [PATCH 03/54] Remove unnecessary usage of positional-only syntax --- path/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/path/__init__.py b/path/__init__.py index c0c15ac8..bd35acf5 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -141,7 +141,7 @@ class Path(str): .. seealso:: :mod:`os.path` """ - def __new__(cls, /, other='.'): + def __new__(cls, other='.'): return super().__new__(cls, other) def __init__(self, other='.'): From a7310562fad7a8834c9810c1edd8e00b03e1394b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 7 Jul 2023 21:48:23 -0400 Subject: [PATCH 04/54] Increase visibility of security policy. (#4) * Create SECURITY.md Signed-off-by: Joyce * Remove the security contact from the README, as it's now redundant. Closes jaraco/tidelift#3. --------- Signed-off-by: Joyce Co-authored-by: Joyce --- README.rst | 7 ------- SECURITY.md | 3 +++ 2 files changed, 3 insertions(+), 7 deletions(-) create mode 100644 SECURITY.md diff --git a/README.rst b/README.rst index 7b317c71..087365cd 100644 --- a/README.rst +++ b/README.rst @@ -9,10 +9,3 @@ Available as part of the Tidelift Subscription. This project and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. `Learn more `_. - -Security Contact -================ - -To report a security vulnerability, please use the -`Tidelift security contact `_. -Tidelift will coordinate the fix and disclosure. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..54f99acb --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +# Security Contact + +To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security). Tidelift will coordinate the fix and disclosure. From c43962adf34c28c22573093419e5e98b2e57cc07 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 10 Jul 2023 23:34:53 -0400 Subject: [PATCH 05/54] Remove TOX_WORK_DIR workaround, no longer necessary with tox 4. Ref tox-dev/tox#3050. --- tox.ini | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tox.ini b/tox.ini index 1093e028..e51d652d 100644 --- a/tox.ini +++ b/tox.ini @@ -1,7 +1,3 @@ -[tox] -toxworkdir={env:TOX_WORK_DIR:.tox} - - [testenv] deps = setenv = From 0e2032c4754c598ba75e467c64009ba4490ddea9 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 31 Aug 2023 18:42:14 -0400 Subject: [PATCH 06/54] Pin against sphinx 7.2.5 as workaround for sphinx/sphinx-doc#11662. Closes jaraco/skeleton#88. --- setup.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.cfg b/setup.cfg index 46f7bdf7..4f184c7e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -45,6 +45,8 @@ testing = docs = # upstream sphinx >= 3.5 + # workaround for sphinx/sphinx-doc#11662 + sphinx < 7.2.5 jaraco.packaging >= 9.3 rst.linker >= 1.9 furo From 92d2d8e1aff997f3877239230c9490ed9cdd1222 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 1 Sep 2023 18:46:27 -0400 Subject: [PATCH 07/54] Allow GITHUB_* settings to pass through to tests. --- .github/workflows/main.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b8224099..67d9d3bc 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,6 +36,10 @@ env: # Must be "1". TOX_PARALLEL_NO_SPINNER: 1 + # Ensure tests can sense settings about the environment + TOX_OVERRIDE: >- + testenv.pass_env+=GITHUB_* + jobs: test: From f3dc1f4776c94a9a4a7c0e8c5b49c532b0a7d411 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 1 Sep 2023 18:49:13 -0400 Subject: [PATCH 08/54] Remove spinner disablement. If it's not already fixed upstream, that's where it should be fixed. --- .github/workflows/main.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 67d9d3bc..30c9615d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,10 +32,6 @@ env: PIP_NO_PYTHON_VERSION_WARNING: 'true' PIP_NO_WARN_SCRIPT_LOCATION: 'true' - # Disable the spinner, noise in GHA; TODO(webknjaz): Fix this upstream - # Must be "1". - TOX_PARALLEL_NO_SPINNER: 1 - # Ensure tests can sense settings about the environment TOX_OVERRIDE: >- testenv.pass_env+=GITHUB_* From 0484daa8a6f72c9ad4e1784f9181c2488a191d8e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 1 Sep 2023 18:53:55 -0400 Subject: [PATCH 09/54] Clean up 'color' environment variables. The TOX_TESTENV_PASSENV hasn't been useful for some time and by its mere presence wasted a lot of time today under the assumption that it's doing something. Instead, just rely on one variable FORCE_COLOR. If it's not honored, then that should be the fix upstream. --- .github/workflows/main.yml | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 30c9615d..f3028549 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -6,26 +6,8 @@ permissions: contents: read env: - # Environment variables to support color support (jaraco/skeleton#66): - # Request colored output from CLI tools supporting it. Different tools - # interpret the value differently. For some, just being set is sufficient. - # For others, it must be a non-zero integer. For yet others, being set - # to a non-empty value is sufficient. For tox, it must be one of - # , 0, 1, false, no, off, on, true, yes. The only enabling value - # in common is "1". + # Environment variable to support color support (jaraco/skeleton#66) FORCE_COLOR: 1 - # MyPy's color enforcement (must be a non-zero number) - MYPY_FORCE_COLOR: -42 - # Recognized by the `py` package, dependency of `pytest` (must be "1") - PY_COLORS: 1 - # Make tox-wrapped tools see color requests - TOX_TESTENV_PASSENV: >- - FORCE_COLOR - MYPY_FORCE_COLOR - NO_COLOR - PY_COLORS - PYTEST_THEME - PYTEST_THEME_MODE # Suppress noisy pip warnings PIP_DISABLE_PIP_VERSION_CHECK: 'true' From b02bf32bae729d53bdb7c9649d6ec36afdb793ee Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 10 Sep 2023 13:27:03 -0400 Subject: [PATCH 10/54] Add diff-cover check to Github Actions CI. Closes jaraco/skeleton#90. --- .github/workflows/main.yml | 18 ++++++++++++++++++ tox.ini | 8 ++++++++ 2 files changed, 26 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f3028549..fa326a26 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -53,6 +53,24 @@ jobs: - name: Run run: tox + diffcov: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: 3.x + - name: Install tox + run: | + python -m pip install tox + - name: Evaluate coverage + run: tox + env: + TOXENV: diffcov + docs: runs-on: ubuntu-latest env: diff --git a/tox.ini b/tox.ini index e51d652d..3b4414b4 100644 --- a/tox.ini +++ b/tox.ini @@ -8,6 +8,14 @@ usedevelop = True extras = testing +[testenv:diffcov] +deps = + diff-cover +commands = + pytest {posargs} --cov-report xml + diff-cover coverage.xml --compare-branch=origin/main --html-report diffcov.html + diff-cover coverage.xml --compare-branch=origin/main --fail-under=100 + [testenv:docs] extras = docs From a6256e2935468b72a61aa7fda1e036faef3bfb3d Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 10 Sep 2023 13:59:47 -0400 Subject: [PATCH 11/54] Add descriptions to the tox environments. Closes jaraco/skeleton#91. --- tox.ini | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tox.ini b/tox.ini index 3b4414b4..1950b4ef 100644 --- a/tox.ini +++ b/tox.ini @@ -1,4 +1,5 @@ [testenv] +description = perform primary checks (tests, style, types, coverage) deps = setenv = PYTHONWARNDEFAULTENCODING = 1 @@ -9,6 +10,7 @@ extras = testing [testenv:diffcov] +description = run tests and check that diff from main is covered deps = diff-cover commands = @@ -17,6 +19,7 @@ commands = diff-cover coverage.xml --compare-branch=origin/main --fail-under=100 [testenv:docs] +description = build the documentation extras = docs testing @@ -26,6 +29,7 @@ commands = python -m sphinxlint [testenv:finalize] +description = assemble changelog and tag a release skip_install = True deps = towncrier @@ -36,6 +40,7 @@ commands = [testenv:release] +description = publish the package to PyPI and GitHub skip_install = True deps = build From 928e9a86d61d3a660948bcba7689f90216cc8243 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 10 Sep 2023 14:10:31 -0400 Subject: [PATCH 12/54] Add FORCE_COLOR to the TOX_OVERRIDE for GHA. Requires tox 4.11.1. Closes jaraco/skeleton#89. --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index fa326a26..28e36786 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,7 +16,7 @@ env: # Ensure tests can sense settings about the environment TOX_OVERRIDE: >- - testenv.pass_env+=GITHUB_* + testenv.pass_env+=GITHUB_*,FORCE_COLOR jobs: From ca1831c2148fe5ddbffd001de76ff5f6005f812c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 18 Sep 2023 11:05:36 -0400 Subject: [PATCH 13/54] Prefer ``pass_env`` in tox config. Preferred failure mode for tox-dev/tox#3127 and closes jaraco/skeleton#92. --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index 1950b4ef..33da3deb 100644 --- a/tox.ini +++ b/tox.ini @@ -34,7 +34,7 @@ skip_install = True deps = towncrier jaraco.develop >= 7.23 -passenv = * +pass_env = * commands = python -m jaraco.develop.finalize @@ -46,7 +46,7 @@ deps = build twine>=3 jaraco.develop>=7.1 -passenv = +pass_env = TWINE_PASSWORD GITHUB_TOKEN setenv = From 03f03e7802b0842b41f70b2b1c17ab26551a7533 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 5 Nov 2023 09:43:46 -0500 Subject: [PATCH 14/54] Limit sphinxlint jobs to 1. Workaround for sphinx-contrib/sphinx-lint#83. --- tox.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 33da3deb..331eeed9 100644 --- a/tox.ini +++ b/tox.ini @@ -26,7 +26,9 @@ extras = changedir = docs commands = python -m sphinx -W --keep-going . {toxinidir}/build/html - python -m sphinxlint + python -m sphinxlint \ + # workaround for sphinx-contrib/sphinx-lint#83 + --jobs 1 [testenv:finalize] description = assemble changelog and tag a release From 75d9cc1b7cb6f84e7a16a83ec3abb9a478fdb130 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 15 Nov 2023 19:57:45 +0600 Subject: [PATCH 15/54] Upgrade GitHub Actions checkout (jaraco/skeleton#94) Also, upgrade from `pypy3.9` to `pypy3.10` and remove the `continue-on-error` for Python 3.12. As recommended at jaraco/cssutils#41 --- .github/workflows/main.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 28e36786..10828667 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -36,12 +36,12 @@ jobs: platform: ubuntu-latest - python: "3.10" platform: ubuntu-latest - - python: pypy3.9 + - python: pypy3.10 platform: ubuntu-latest runs-on: ${{ matrix.platform }} - continue-on-error: ${{ matrix.python == '3.12' }} + continue-on-error: ${{ matrix.python == '3.13' }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 with: @@ -56,7 +56,7 @@ jobs: diffcov: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Python @@ -76,7 +76,7 @@ jobs: env: TOXENV: docs steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 - name: Install tox @@ -109,7 +109,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v4 with: From 5732ebeeaa9480f8cd80c96a3183d7b247f27214 Mon Sep 17 00:00:00 2001 From: Christian Clauss Date: Wed, 15 Nov 2023 20:08:10 +0600 Subject: [PATCH 16/54] GitHub Actions: Combine tox jobs diffcov and docs (jaraco/skeleton#95) Code reuse Co-authored-by: Jason R. Coombs --- .github/workflows/main.yml | 37 +++++++++++-------------------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 10828667..9682985c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -48,12 +48,15 @@ jobs: python-version: ${{ matrix.python }} allow-prereleases: true - name: Install tox - run: | - python -m pip install tox + run: python -m pip install tox - name: Run run: tox - diffcov: + collateral: + strategy: + fail-fast: false + matrix: + job: [diffcov, docs] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -64,33 +67,16 @@ jobs: with: python-version: 3.x - name: Install tox - run: | - python -m pip install tox - - name: Evaluate coverage - run: tox - env: - TOXENV: diffcov - - docs: - runs-on: ubuntu-latest - env: - TOXENV: docs - steps: - - uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@v4 - - name: Install tox - run: | - python -m pip install tox - - name: Run - run: tox + run: python -m pip install tox + - name: Eval ${{ matrix.job }} + run: tox -e ${{ matrix.job }} check: # This job does nothing and is only used for the branch protection if: always() needs: - test - - docs + - collateral runs-on: ubuntu-latest @@ -115,8 +101,7 @@ jobs: with: python-version: 3.x - name: Install tox - run: | - python -m pip install tox + run: python -m pip install tox - name: Run run: tox -e release env: From 26f420a97e73a2ab695023f6cc21f5c786d2b289 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 28 Nov 2023 11:43:20 -0500 Subject: [PATCH 17/54] Remove news fragment after allowing time to be processed downstream. --- newsfragments/+drop-py37.feature.rst | 1 - 1 file changed, 1 deletion(-) delete mode 100644 newsfragments/+drop-py37.feature.rst diff --git a/newsfragments/+drop-py37.feature.rst b/newsfragments/+drop-py37.feature.rst deleted file mode 100644 index ccabdaa3..00000000 --- a/newsfragments/+drop-py37.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Require Python 3.8 or later. From 33dd01267b6a886217bae3ebd5df5b689e2ab722 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 29 Nov 2023 13:21:17 -0500 Subject: [PATCH 18/54] Suppress deprecation warning in dateutil. Workaround for dateutil/dateutil#1284. --- pytest.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pytest.ini b/pytest.ini index d9a15ed1..f9533b57 100644 --- a/pytest.ini +++ b/pytest.ini @@ -24,4 +24,7 @@ filterwarnings= # pypa/build#615 ignore:'encoding' argument not specified::build.env + # dateutil/dateutil#1284 + ignore:datetime.datetime.utcfromtimestamp:DeprecationWarning:dateutil.tz.tz + ## end upstream From 54215092dd970c667c7234c6da5bfa0e3ad7ab89 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 4 Dec 2023 13:57:37 -0500 Subject: [PATCH 19/54] Update README to reflect retirement of Python 3.5 and earlier. --- README.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index cf45a7fc..63baa187 100644 --- a/README.rst +++ b/README.rst @@ -63,6 +63,8 @@ based on ``path``. Advantages ========== +Path pie provides a superior experience to similar offerings. + Python 3.4 introduced `pathlib `_, which shares many characteristics with ``path``. In particular, @@ -75,9 +77,9 @@ has several advantages over ``pathlib``: - ``path`` implements ``Path`` objects as a subclass of ``str``, and as a result these ``Path`` objects may be passed directly to other APIs that expect simple text representations of paths, whereas with ``pathlib``, one - must first cast values to strings before passing them to APIs unaware of - ``pathlib``. This shortcoming was somewhat `mitigated by PEP 519 - `_, in Python 3.6. + must first cast values to strings before passing them to APIs that do + not honor `PEP 519 `_ + ``PathLike`` interface. - ``path`` give quality of life features beyond exposing basic functionality of a path. ``path`` provides methods like ``rmtree`` (from shlib) and ``remove_p`` (remove a file if it exists), properties like ``.permissions``, @@ -85,16 +87,19 @@ has several advantages over ``pathlib``: - As a PyPI-hosted package, ``path`` is free to iterate faster than a stdlib package. Contributions are welcome and encouraged. -- ``path`` provides a uniform abstraction over its Path object, +- ``path`` provides superior portability using a uniform abstraction + over its single Path object, freeing the implementer to subclass it readily. One cannot subclass a ``pathlib.Path`` to add functionality, but must subclass ``Path``, ``PosixPath``, and ``WindowsPath``, even - if one only wishes to add a ``__dict__`` to the subclass + to do something as simple as to add a ``__dict__`` to the subclass instances. ``path`` instead allows the ``Path.module`` object to be overridden by subclasses, defaulting to the ``os.path``. Even advanced uses of ``path.Path`` that subclass the model do not need to be concerned with - OS-specific nuances. + OS-specific nuances. ``path.Path`` objects are inherently "pure", + not requiring the author to distinguish between pure and non-pure + variants. This path project has the explicit aim to provide compatibility with ``pathlib`` objects where possible, such that a ``path.Path`` From 3f33a116746d3f7ede82b6a8f5928640921d99df Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 4 Dec 2023 14:50:02 -0500 Subject: [PATCH 20/54] =?UTF-8?q?=E2=9A=AB=20Fade=20to=20black.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- path/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/path/__init__.py b/path/__init__.py index bd35acf5..2283175c 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -141,6 +141,7 @@ class Path(str): .. seealso:: :mod:`os.path` """ + def __new__(cls, other='.'): return super().__new__(cls, other) From 7c6f16c4ffd0c2d7e595b0456369e9e94fad1675 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 4 Dec 2023 14:50:42 -0500 Subject: [PATCH 21/54] Use the empty path in test_chroot and test_startfile. --- test_path.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test_path.py b/test_path.py index 0bd3ffd1..0bc0440d 100644 --- a/test_path.py +++ b/test_path.py @@ -430,7 +430,7 @@ def test_chroot(monkeypatch): results = [] monkeypatch.setattr(os, 'chroot', results.append) Path().chroot() - assert results == [''] + assert results == [Path()] @pytest.mark.skipif("not hasattr(Path, 'startfile')") @@ -438,7 +438,7 @@ def test_startfile(monkeypatch): results = [] monkeypatch.setattr(os, 'startfile', results.append) Path().startfile() - assert results == ['.'] + assert results == [Path()] class TestScratchDir: From 42c4778a7167e08915ab6e7dd6fa14b41a6039f8 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 4 Dec 2023 14:53:46 -0500 Subject: [PATCH 22/54] Add news fragment. --- newsfragments/216.feature.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 newsfragments/216.feature.rst diff --git a/newsfragments/216.feature.rst b/newsfragments/216.feature.rst new file mode 100644 index 00000000..ffa5f9df --- /dev/null +++ b/newsfragments/216.feature.rst @@ -0,0 +1 @@ +Use '.' as the default path. \ No newline at end of file From f1d623caff29bde754c5a0eca7a766d6959f7782 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 4 Dec 2023 14:59:31 -0500 Subject: [PATCH 23/54] Finalize --- NEWS.rst | 9 +++++++++ newsfragments/216.feature.rst | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) delete mode 100644 newsfragments/216.feature.rst diff --git a/NEWS.rst b/NEWS.rst index 4efbedb5..ab878406 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1,3 +1,12 @@ +v16.8.0 +======= + +Features +-------- + +- Use '.' as the default path. (#216) + + v16.7.1 ======= diff --git a/newsfragments/216.feature.rst b/newsfragments/216.feature.rst deleted file mode 100644 index ffa5f9df..00000000 --- a/newsfragments/216.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Use '.' as the default path. \ No newline at end of file From 8565be1a1faae95be4606a1b924b59a25bedb9c9 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 4 Dec 2023 15:21:36 -0500 Subject: [PATCH 24/54] Added Path.iterdir() and deprecated Path.listdir(). Ref #214 --- newsfragments/214.feature.rst | 1 + path/__init__.py | 26 +++++++++------ path/matchers.py | 2 +- setup.cfg | 1 + test_path.py | 61 +++++++++++++++++++---------------- 5 files changed, 53 insertions(+), 38 deletions(-) create mode 100644 newsfragments/214.feature.rst diff --git a/newsfragments/214.feature.rst b/newsfragments/214.feature.rst new file mode 100644 index 00000000..904897f8 --- /dev/null +++ b/newsfragments/214.feature.rst @@ -0,0 +1 @@ +Added Path.iterdir() and deprecated Path.listdir(). Ref #214. \ No newline at end of file diff --git a/path/__init__.py b/path/__init__.py index 2283175c..250a7e20 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -475,8 +475,8 @@ def relpathto(self, dest): # --- Listing, searching, walking, and matching - def listdir(self, match=None): - """List of items in this directory. + def iterdir(self, match=None): + """Yields items in this directory. Use :meth:`files` or :meth:`dirs` instead if you want a listing of just files or just subdirectories. @@ -489,7 +489,15 @@ def listdir(self, match=None): .. seealso:: :meth:`files`, :meth:`dirs` """ match = matchers.load(match) - return list(filter(match, (self / child for child in os.listdir(self)))) + return filter(match, (self / child for child in os.listdir(self))) + + def listdir(self, match=None): + warnings.warn( + ".listdir is deprecated; use iterdir", + DeprecationWarning, + stacklevel=2, + ) + return list(self.iterdir(match=match)) def dirs(self, *args, **kwargs): """List of this directory's subdirectories. @@ -498,9 +506,9 @@ def dirs(self, *args, **kwargs): This does not walk recursively into subdirectories (but see :meth:`walkdirs`). - Accepts parameters to :meth:`listdir`. + Accepts parameters to :meth:`iterdir`. """ - return [p for p in self.listdir(*args, **kwargs) if p.isdir()] + return [p for p in self.iterdir(*args, **kwargs) if p.isdir()] def files(self, *args, **kwargs): """List of the files in self. @@ -508,10 +516,10 @@ def files(self, *args, **kwargs): The elements of the list are Path objects. This does not walk into subdirectories (see :meth:`walkfiles`). - Accepts parameters to :meth:`listdir`. + Accepts parameters to :meth:`iterdir`. """ - return [p for p in self.listdir(*args, **kwargs) if p.isfile()] + return [p for p in self.iterdir(*args, **kwargs) if p.isfile()] def walk(self, match=None, errors='strict'): """Iterator over files and subdirs, recursively. @@ -534,7 +542,7 @@ def walk(self, match=None, errors='strict'): match = matchers.load(match) try: - childList = self.listdir() + childList = self.iterdir() except Exception as exc: errors(f"Unable to list directory '{self}': {exc}") return @@ -1336,7 +1344,7 @@ def merge_tree( dst = self._next_class(dst) dst.makedirs_p() - sources = self.listdir() + sources = list(self.iterdir()) _ignored = ignore(self, [item.name for item in sources]) def ignored(item): diff --git a/path/matchers.py b/path/matchers.py index 63ca218a..79636d65 100644 --- a/path/matchers.py +++ b/path/matchers.py @@ -46,7 +46,7 @@ def __call__(self, path): class CaseInsensitive(Pattern): """ A Pattern with a ``'normcase'`` property, suitable for passing to - :meth:`listdir`, :meth:`dirs`, :meth:`files`, :meth:`walk`, + :meth:`iterdir`, :meth:`dirs`, :meth:`files`, :meth:`walk`, :meth:`walkdirs`, or :meth:`walkfiles` to match case-insensitive. For example, to get all files ending in .py, .Py, .pY, or .PY in the diff --git a/setup.cfg b/setup.cfg index 722ffe7d..c21a3772 100644 --- a/setup.cfg +++ b/setup.cfg @@ -48,6 +48,7 @@ testing = appdirs packaging pywin32; platform_system == "Windows" and python_version < "3.12" + more_itertools # required for checkdocs on README.rst pygments diff --git a/test_path.py b/test_path.py index 0bc0440d..34804de1 100644 --- a/test_path.py +++ b/test_path.py @@ -30,6 +30,7 @@ import stat import pytest +from more_itertools import ilen import path from path import Path @@ -512,7 +513,7 @@ def test_touch(self, tmpdir): def test_listing(self, tmpdir): d = Path(tmpdir) - assert d.listdir() == [] + assert list(d.iterdir()) == [] f = 'testfile.txt' af = d / f @@ -521,7 +522,7 @@ def test_listing(self, tmpdir): try: assert af.exists() - assert d.listdir() == [af] + assert list(d.iterdir()) == [af] # .glob() assert d.glob('testfile.txt') == [af] @@ -545,7 +546,7 @@ def test_listing(self, tmpdir): with open(f, 'w', encoding='utf-8') as fobj: fobj.write('some text\n') try: - files2 = d.listdir() + files2 = list(d.iterdir()) files.sort() files2.sort() assert files == files2 @@ -565,17 +566,17 @@ def bytes_filename(self, tmpdir): raise pytest.skip(f"Invalid encodings disallowed {exc}") return name - def test_listdir_other_encoding(self, tmpdir, bytes_filename): # pragma: nocover + def test_iterdir_other_encoding(self, tmpdir, bytes_filename): # pragma: nocover """ Some filesystems allow non-character sequences in path names. - ``.listdir`` should still function in this case. + ``.iterdir`` should still function in this case. See issue #61 for details. """ # first demonstrate that os.listdir works assert os.listdir(str(tmpdir).encode('ascii')) # now try with path - results = Path(tmpdir).listdir() + results = Path(tmpdir).iterdir() (res,) = results assert isinstance(res, Path) assert len(res.basename()) == len(bytes_filename) @@ -663,7 +664,7 @@ def test_shutil(self, tmpdir): testA.copytree(testC) assert testC.isdir() self.assertSetsEqual( - testC.listdir(), + testC.iterdir(), [testC / testCopy.name, testC / testFile.name, testCopyOfLink], ) assert not testCopyOfLink.islink() @@ -676,7 +677,7 @@ def test_shutil(self, tmpdir): testA.copytree(testC, True) assert testC.isdir() self.assertSetsEqual( - testC.listdir(), + testC.iterdir(), [testC / testCopy.name, testC / testFile.name, testCopyOfLink], ) if hasattr(os, 'symlink'): @@ -686,7 +687,7 @@ def test_shutil(self, tmpdir): # Clean up. testDir.rmtree() assert not testDir.exists() - self.assertList(d.listdir(), []) + self.assertList(d.iterdir(), []) def assertList(self, listing, expected): assert sorted(listing) == sorted(expected) @@ -702,7 +703,7 @@ def test_patterns(self, tmpdir): for name in names: (e / name).touch() - self.assertList(d.listdir('*.tmp'), [d / 'x.tmp', d / 'xdir.tmp']) + self.assertList(d.iterdir('*.tmp'), [d / 'x.tmp', d / 'xdir.tmp']) self.assertList(d.files('*.tmp'), [d / 'x.tmp']) self.assertList(d.dirs('*.tmp'), [d / 'xdir.tmp']) self.assertList( @@ -922,7 +923,7 @@ def test_with_nonexisting_dst_kwargs(self): self.subdir_b / self.test_file.name, self.subdir_b / self.test_link.name, } - assert set(self.subdir_b.listdir()) == expected + assert set(self.subdir_b.iterdir()) == expected self.check_link() def test_with_nonexisting_dst_args(self): @@ -932,7 +933,7 @@ def test_with_nonexisting_dst_args(self): self.subdir_b / self.test_file.name, self.subdir_b / self.test_link.name, } - assert set(self.subdir_b.listdir()) == expected + assert set(self.subdir_b.iterdir()) == expected self.check_link() def test_with_existing_dst(self): @@ -953,7 +954,7 @@ def test_with_existing_dst(self): self.subdir_b / self.test_link.name, self.subdir_b / test_new.name, } - assert set(self.subdir_b.listdir()) == expected + assert set(self.subdir_b.iterdir()) == expected self.check_link() assert len(Path(self.subdir_b / self.test_file.name).bytes()) == 5000 @@ -965,7 +966,7 @@ def test_copytree_parameters(self): self.subdir_a.merge_tree(self.subdir_b, ignore=ignore) assert self.subdir_b.isdir() - assert self.subdir_b.listdir() == [self.subdir_b / self.test_file.name] + assert list(self.subdir_b.iterdir()) == [self.subdir_b / self.test_file.name] def test_only_newer(self): """ @@ -985,6 +986,10 @@ def test_nested(self): self.subdir_a.merge_tree(self.subdir_b) assert self.subdir_b.joinpath('subsub').isdir() + def test_listdir(self): + with pytest.deprecated_call(): + Path().listdir() + class TestChdir: def test_chdir_or_cd(self, tmpdir): @@ -1111,22 +1116,22 @@ def normcase(path): assert p.fnmatch('foobar', normcase=normcase) assert p.fnmatch('FOO[ABC]AR', normcase=normcase) - def test_listdir_simple(self): + def test_iterdir_simple(self): p = Path('.') - assert len(p.listdir()) == len(os.listdir('.')) + assert ilen(p.iterdir()) == len(os.listdir('.')) - def test_listdir_empty_pattern(self): + def test_iterdir_empty_pattern(self): p = Path('.') - assert p.listdir('') == [] + assert list(p.iterdir('')) == [] - def test_listdir_patterns(self, tmpdir): + def test_iterdir_patterns(self, tmpdir): p = Path(tmpdir) (p / 'sub').mkdir() (p / 'File').touch() - assert p.listdir('s*') == [p / 'sub'] - assert len(p.listdir('*')) == 2 + assert list(p.iterdir('s*')) == [p / 'sub'] + assert ilen(p.iterdir('*')) == 2 - def test_listdir_custom_module(self, tmpdir): + def test_iterdir_custom_module(self, tmpdir): """ Listdir patterns should honor the case sensitivity of the path module used by that Path class. @@ -1135,14 +1140,14 @@ def test_listdir_custom_module(self, tmpdir): p = always_unix(tmpdir) (p / 'sub').mkdir() (p / 'File').touch() - assert p.listdir('S*') == [] + assert list(p.iterdir('S*')) == [] always_win = Path.using_module(ntpath) p = always_win(tmpdir) - assert p.listdir('S*') == [p / 'sub'] - assert p.listdir('f*') == [p / 'File'] + assert list(p.iterdir('S*')) == [p / 'sub'] + assert list(p.iterdir('f*')) == [p / 'File'] - def test_listdir_case_insensitive(self, tmpdir): + def test_iterdir_case_insensitive(self, tmpdir): """ Listdir patterns should honor the case sensitivity of the path module used by that Path class. @@ -1150,8 +1155,8 @@ def test_listdir_case_insensitive(self, tmpdir): p = Path(tmpdir) (p / 'sub').mkdir() (p / 'File').touch() - assert p.listdir(matchers.CaseInsensitive('S*')) == [p / 'sub'] - assert p.listdir(matchers.CaseInsensitive('f*')) == [p / 'File'] + assert list(p.iterdir(matchers.CaseInsensitive('S*'))) == [p / 'sub'] + assert list(p.iterdir(matchers.CaseInsensitive('f*'))) == [p / 'File'] assert p.files(matchers.CaseInsensitive('S*')) == [] assert p.dirs(matchers.CaseInsensitive('f*')) == [] From 188538156d6cc77cfcb8e18a40dbca1def87dc54 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 4 Dec 2023 15:26:09 -0500 Subject: [PATCH 25/54] Finalize --- NEWS.rst | 9 +++++++++ newsfragments/214.feature.rst | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) delete mode 100644 newsfragments/214.feature.rst diff --git a/NEWS.rst b/NEWS.rst index ab878406..702d3d60 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1,3 +1,12 @@ +v16.9.0 +======= + +Features +-------- + +- Added Path.iterdir() and deprecated Path.listdir(). Ref #214. (#214) + + v16.8.0 ======= diff --git a/newsfragments/214.feature.rst b/newsfragments/214.feature.rst deleted file mode 100644 index 904897f8..00000000 --- a/newsfragments/214.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Added Path.iterdir() and deprecated Path.listdir(). Ref #214. \ No newline at end of file From 6a6db4d46ffb27b7b84be883bc2d0a427885e156 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 4 Dec 2023 15:45:19 -0500 Subject: [PATCH 26/54] Clean up NEWS. --- NEWS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.rst b/NEWS.rst index 702d3d60..c4630123 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -4,7 +4,7 @@ v16.9.0 Features -------- -- Added Path.iterdir() and deprecated Path.listdir(). Ref #214. (#214) +- Added ``.iterdir()`` and deprecated ``.listdir()``. (#214) v16.8.0 From 97a5f44787ac5a928534cdf724210c429621435c Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 4 Dec 2023 15:53:37 -0500 Subject: [PATCH 27/54] Update Github Actions badge per actions/starter-workflows#1525. --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index b703d490..41bcfbe8 100644 --- a/README.rst +++ b/README.rst @@ -3,7 +3,7 @@ .. image:: https://img.shields.io/pypi/pyversions/PROJECT.svg -.. image:: https://github.com/PROJECT_PATH/workflows/tests/badge.svg +.. image:: https://github.com/PROJECT_PATH/actions/workflows/main.yml/badge.svg :target: https://github.com/PROJECT_PATH/actions?query=workflow%3A%22tests%22 :alt: tests From 8bff8b034a0bbf0273a38f0a0cc41e3a52b26864 Mon Sep 17 00:00:00 2001 From: Sviatoslav Sydorenko Date: Tue, 5 Dec 2023 15:48:52 +0100 Subject: [PATCH 28/54] Enable testing merge queues @ GitHub Actions CI/CD (jaraco/skeleton#93) This allows org-hosted projects to start enabling merge queues in the repository settings. With that, GitHub would trigger a separate event against a merge commit derived from merging several pull requests with the target branch. --- .github/workflows/main.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9682985c..387d01aa 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,6 +1,11 @@ name: tests -on: [push, pull_request] +on: + merge_group: + push: + branches-ignore: + - gh-readonly-queue/** # Temporary merge queue-related GH-made branches + pull_request: permissions: contents: read From e4bd6091a1fbe26fe113051f0f47875d627c7ed2 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 11 Dec 2023 10:46:32 -0500 Subject: [PATCH 29/54] Separate collateral jobs on different lines for easier override/extension. --- .github/workflows/main.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 387d01aa..a079bbfb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -61,7 +61,9 @@ jobs: strategy: fail-fast: false matrix: - job: [diffcov, docs] + job: + - diffcov + - docs runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 From 596e6834c8a037c935338afe92e0b9c5ffa1768f Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 19 Dec 2023 18:29:16 -0500 Subject: [PATCH 30/54] Drop minimum requirement on pytest-mypy as most environments are already running much later. Closes jaraco/skeleton#96. --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 4f184c7e..20c5dd76 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,7 +34,7 @@ testing = # workaround for jaraco/skeleton#22 python_implementation != "PyPy" pytest-cov - pytest-mypy >= 0.9.1; \ + pytest-mypy; \ # workaround for jaraco/skeleton#22 python_implementation != "PyPy" pytest-enabler >= 2.2 From b8c6c1530ef937521b60aabb0ecd98a8b5dca761 Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Sat, 23 Dec 2023 00:25:02 +0100 Subject: [PATCH 31/54] Use the ruff formatter (jaraco/skeleton#99) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Use the ruff formatter, instead of black Based on: - ruff-pre-commit README.md | Using Ruff with pre-commit https://github.com/astral-sh/ruff-pre-commit/blob/main/README.md - The Ruff Formatter | Conflicting lint rules https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules Support for the ruff formatter was added to pytest-ruff by commits from October 2023, released the same day as versions 0.2 and 0.2.1. Hence, it makes sense to require pytest-ruff ≥ 0.2.1 now. Support for `quote-style = "preserve"` was added to ruff in the last couple of weeks, therefore require the latest version, ruff ≥ 0.1.8. This option is equivalent to `skip-string-normalization` in black. Closes jaraco/skeleton#101. --------- Co-authored-by: Jason R. Coombs --- .pre-commit-config.yaml | 7 ++++--- README.rst | 4 ---- pyproject.toml | 3 --- pytest.ini | 8 -------- ruff.toml | 22 ++++++++++++++++++++++ setup.cfg | 5 +---- 6 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 ruff.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index af502010..5a4a7e91 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,6 @@ repos: -- repo: https://github.com/psf/black - rev: 22.6.0 +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.1.8 hooks: - - id: black + - id: ruff + - id: ruff-format diff --git a/README.rst b/README.rst index 41bcfbe8..2fabcf33 100644 --- a/README.rst +++ b/README.rst @@ -11,10 +11,6 @@ :target: https://github.com/astral-sh/ruff :alt: Ruff -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code style: Black - .. .. image:: https://readthedocs.org/projects/PROJECT_RTD/badge/?version=latest .. :target: https://PROJECT_RTD.readthedocs.io/en/latest/?badge=latest diff --git a/pyproject.toml b/pyproject.toml index dce944df..a853c578 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,4 @@ requires = ["setuptools>=56", "setuptools_scm[toml]>=3.4.1"] build-backend = "setuptools.build_meta" -[tool.black] -skip-string-normalization = true - [tool.setuptools_scm] diff --git a/pytest.ini b/pytest.ini index f9533b57..022a723e 100644 --- a/pytest.ini +++ b/pytest.ini @@ -7,14 +7,6 @@ filterwarnings= # Ensure ResourceWarnings are emitted default::ResourceWarning - # shopkeep/pytest-black#55 - ignore: is not using a cooperative constructor:pytest.PytestDeprecationWarning - ignore:The \(fspath. py.path.local\) argument to BlackItem is deprecated.:pytest.PytestDeprecationWarning - ignore:BlackItem is an Item subclass and should not be a collector:pytest.PytestWarning - - # shopkeep/pytest-black#67 - ignore:'encoding' argument not specified::pytest_black - # realpython/pytest-mypy#152 ignore:'encoding' argument not specified::pytest_mypy diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 00000000..7ed133b7 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,22 @@ +[lint] +extend-ignore = [ + # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules + "W191", + "E111", + "E114", + "E117", + "D206", + "D300", + "Q000", + "Q001", + "Q002", + "Q003", + "COM812", + "COM819", + "ISC001", + "ISC002", +] + +[format] +# https://docs.astral.sh/ruff/settings/#format-quote-style +quote-style = "preserve" diff --git a/setup.cfg b/setup.cfg index 20c5dd76..1d2729be 100644 --- a/setup.cfg +++ b/setup.cfg @@ -30,15 +30,12 @@ testing = # upstream pytest >= 6 pytest-checkdocs >= 2.4 - pytest-black >= 0.3.7; \ - # workaround for jaraco/skeleton#22 - python_implementation != "PyPy" pytest-cov pytest-mypy; \ # workaround for jaraco/skeleton#22 python_implementation != "PyPy" pytest-enabler >= 2.2 - pytest-ruff + pytest-ruff >= 0.2.1 # local From a9c5dd5a4eab9f4132d62344cdbad24e077c650e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 24 Dec 2023 12:08:46 -0500 Subject: [PATCH 32/54] Remove sole entry for branches-ignore. Workaround for and closes jaraco/skeleton#103. --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a079bbfb..cf94f7d8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,7 +4,8 @@ on: merge_group: push: branches-ignore: - - gh-readonly-queue/** # Temporary merge queue-related GH-made branches + # disabled for jaraco/skeleton#103 + # - gh-readonly-queue/** # Temporary merge queue-related GH-made branches pull_request: permissions: From db0d581685d4fc2a16d392d4dedffe622e9a355c Mon Sep 17 00:00:00 2001 From: Dimitri Papadopoulos Orfanos <3234522+DimitriPapadopoulos@users.noreply.github.com> Date: Tue, 26 Dec 2023 15:58:23 +0100 Subject: [PATCH 33/54] =?UTF-8?q?ruff:=20extended-ignore=20=E2=86=92=20ign?= =?UTF-8?q?ore=20(jaraco/skeleton#105)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applies Repo-Review suggestion: RF201: Avoid using deprecated config settings extend-ignore deprecated, use ignore instead (identical) --- ruff.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruff.toml b/ruff.toml index 7ed133b7..795cca16 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,5 +1,5 @@ [lint] -extend-ignore = [ +ignore = [ # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules "W191", "E111", From f6d9e107365ca270ec843898c05bb8e43dc6987a Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 2 Jan 2024 17:56:53 -0500 Subject: [PATCH 34/54] Bump year on badge --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 2fabcf33..efabeee4 100644 --- a/README.rst +++ b/README.rst @@ -14,5 +14,5 @@ .. .. image:: https://readthedocs.org/projects/PROJECT_RTD/badge/?version=latest .. :target: https://PROJECT_RTD.readthedocs.io/en/latest/?badge=latest -.. image:: https://img.shields.io/badge/skeleton-2023-informational +.. image:: https://img.shields.io/badge/skeleton-2024-informational :target: https://blog.jaraco.com/skeleton From dbcb0747110d074112f27e2699856acfc4ba8ea3 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 6 Jan 2024 20:09:59 -0500 Subject: [PATCH 35/54] Remove build and dist from excludes. It appears they are not needed and their presence blocks the names of packages like 'builder' and 'distutils'. Ref pypa/distutils#224. --- setup.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index 1d2729be..c2e82875 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,8 +20,6 @@ install_requires = [options.packages.find] exclude = - build* - dist* docs* tests* From d27890573088a6a0292139c5e30466debd7dc1dd Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 7 Jan 2024 12:26:16 -0500 Subject: [PATCH 36/54] Exclude docs and tests directories properly per Setuptools behavior. --- setup.cfg | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index c2e82875..c5aa1af9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,8 +20,11 @@ install_requires = [options.packages.find] exclude = - docs* - tests* + # duplicate exclusions for pypa/setuptools#2688 + docs + docs.* + tests + tests.* [options.extras_require] testing = From 63535c6efd3516a7ef35c862c24ef5b6d43c8494 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 7 Jan 2024 12:49:05 -0500 Subject: [PATCH 37/54] Rely on default discovery for good heuristics for finding packages. --- setup.cfg | 9 --------- 1 file changed, 9 deletions(-) diff --git a/setup.cfg b/setup.cfg index c5aa1af9..fe99eaf6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -13,19 +13,10 @@ classifiers = Programming Language :: Python :: 3 :: Only [options] -packages = find_namespace: include_package_data = true python_requires = >=3.8 install_requires = -[options.packages.find] -exclude = - # duplicate exclusions for pypa/setuptools#2688 - docs - docs.* - tests - tests.* - [options.extras_require] testing = # upstream From b14a1c333569e879ad400e1829072a5148eb36a4 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 3 Feb 2024 22:32:24 -0500 Subject: [PATCH 38/54] Prefer .suffix to .ext and deprecate .ext. --- newsfragments/+50114b5a.feature.rst | 1 + path/__init__.py | 15 ++++++++++++--- test_path.py | 6 +++--- 3 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 newsfragments/+50114b5a.feature.rst diff --git a/newsfragments/+50114b5a.feature.rst b/newsfragments/+50114b5a.feature.rst new file mode 100644 index 00000000..3fbfc68e --- /dev/null +++ b/newsfragments/+50114b5a.feature.rst @@ -0,0 +1 @@ +Prefer .suffix to .ext and deprecate .ext. \ No newline at end of file diff --git a/path/__init__.py b/path/__init__.py index 250a7e20..2525af2d 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -278,10 +278,19 @@ def stem(self): return base @property - def ext(self): + def suffix(self): """The file extension, for example ``'.py'``.""" - f, ext = self.module.splitext(self) - return ext + f, suffix = self.module.splitext(self) + return suffix + + @property + def ext(self): + warnings.warn( + ".ext is deprecated; use suffix", + DeprecationWarning, + stacklevel=2, + ) + return self.suffix def with_suffix(self, suffix): """Return a new path with the file suffix changed (or added, if none) diff --git a/test_path.py b/test_path.py index 34804de1..8bc4dc9c 100644 --- a/test_path.py +++ b/test_path.py @@ -131,9 +131,9 @@ def test_properties(self): assert f.name == 'xyzzy.py' assert f.parent.name == os_choose(nt='Lib', posix='lib') - # .ext - assert f.ext == '.py' - assert f.parent.ext == '' + # .suffix + assert f.suffix == '.py' + assert f.parent.suffix == '' # .drive assert f.drive == os_choose(nt='C:', posix='') From b84c47dbe8eee8ec9fff12b30aa43af2193eb6c7 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 3 Feb 2024 22:38:58 -0500 Subject: [PATCH 39/54] Added .with_name and .with_stem. --- newsfragments/+ceb93420.feature.rst | 1 + path/__init__.py | 17 +++++++++++++++++ path/compat/py38.py | 13 +++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 newsfragments/+ceb93420.feature.rst create mode 100644 path/compat/py38.py diff --git a/newsfragments/+ceb93420.feature.rst b/newsfragments/+ceb93420.feature.rst new file mode 100644 index 00000000..ed853ad8 --- /dev/null +++ b/newsfragments/+ceb93420.feature.rst @@ -0,0 +1 @@ +Added .with_name and .with_stem. \ No newline at end of file diff --git a/path/__init__.py b/path/__init__.py index 2525af2d..61e0237a 100644 --- a/path/__init__.py +++ b/path/__init__.py @@ -52,6 +52,7 @@ from . import matchers from . import masks from . import classes +from .compat.py38 import removesuffix __all__ = ['Path', 'TempDir'] @@ -277,6 +278,14 @@ def stem(self): base, ext = self.module.splitext(self.name) return base + def with_stem(self, stem): + """Return a new path with the stem changed. + + >>> Path('/home/guido/python.tar.gz').with_stem("foo") + Path('/home/guido/foo.gz') + """ + return self.with_name(stem + self.suffix) + @property def suffix(self): """The file extension, for example ``'.py'``.""" @@ -347,6 +356,14 @@ def drive(self): """, ) + def with_name(self, name): + """Return a new path with the name changed. + + >>> Path('/home/guido/python.tar.gz').with_name("foo.zip") + Path('/home/guido/foo.zip') + """ + return self._next_class(removesuffix(self, self.name) + name) + def splitpath(self): """Return two-tuple of ``.parent``, ``.name``. diff --git a/path/compat/py38.py b/path/compat/py38.py new file mode 100644 index 00000000..84f45036 --- /dev/null +++ b/path/compat/py38.py @@ -0,0 +1,13 @@ +import sys + + +if sys.version_info < (3, 9): + def removesuffix(self, suffix): + # suffix='' should not call self[:-0]. + if suffix and self.endswith(suffix): + return self[:-len(suffix)] + else: + return self[:] +else: + def removesuffix(self, suffix): + return self.removesuffix(suffix) From 5f6532fe187c582cdff1afdeec1d926ef692a3ce Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 3 Feb 2024 22:47:29 -0500 Subject: [PATCH 40/54] Finalize --- NEWS.rst | 10 ++++++++++ newsfragments/+50114b5a.feature.rst | 1 - newsfragments/+ceb93420.feature.rst | 1 - 3 files changed, 10 insertions(+), 2 deletions(-) delete mode 100644 newsfragments/+50114b5a.feature.rst delete mode 100644 newsfragments/+ceb93420.feature.rst diff --git a/NEWS.rst b/NEWS.rst index c4630123..430681b1 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -1,3 +1,13 @@ +v16.10.0 +======== + +Features +-------- + +- Added .with_name and .with_stem. +- Prefer .suffix to .ext and deprecate .ext. + + v16.9.0 ======= diff --git a/newsfragments/+50114b5a.feature.rst b/newsfragments/+50114b5a.feature.rst deleted file mode 100644 index 3fbfc68e..00000000 --- a/newsfragments/+50114b5a.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Prefer .suffix to .ext and deprecate .ext. \ No newline at end of file diff --git a/newsfragments/+ceb93420.feature.rst b/newsfragments/+ceb93420.feature.rst deleted file mode 100644 index ed853ad8..00000000 --- a/newsfragments/+ceb93420.feature.rst +++ /dev/null @@ -1 +0,0 @@ -Added .with_name and .with_stem. \ No newline at end of file From 29e5d34af962e59e92c501ebb988dcaf192b114e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 4 Feb 2024 10:15:04 -0500 Subject: [PATCH 41/54] Enable preview to enable preserving quotes. --- ruff.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruff.toml b/ruff.toml index 795cca16..e61ca8b0 100644 --- a/ruff.toml +++ b/ruff.toml @@ -18,5 +18,7 @@ ignore = [ ] [format] +# Enable preview, required for quote-style = "preserve" +preview = true # https://docs.astral.sh/ruff/settings/#format-quote-style quote-style = "preserve" From dc9ce1b62c28604eafc4410bb65d336e3529a102 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 4 Feb 2024 10:28:54 -0500 Subject: [PATCH 42/54] =?UTF-8?q?=F0=9F=91=B9=20Feed=20the=20hobgoblins=20?= =?UTF-8?q?(delint).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- path/compat/py38.py | 14 ++++++++------ test_path.py | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/path/compat/py38.py b/path/compat/py38.py index 84f45036..a5f0fc1c 100644 --- a/path/compat/py38.py +++ b/path/compat/py38.py @@ -2,12 +2,14 @@ if sys.version_info < (3, 9): - def removesuffix(self, suffix): - # suffix='' should not call self[:-0]. - if suffix and self.endswith(suffix): - return self[:-len(suffix)] - else: - return self[:] + + def removesuffix(self, suffix): + # suffix='' should not call self[:-0]. + if suffix and self.endswith(suffix): + return self[: -len(suffix)] + else: + return self[:] else: + def removesuffix(self, suffix): return self.removesuffix(suffix) diff --git a/test_path.py b/test_path.py index 8bc4dc9c..6dbe143b 100644 --- a/test_path.py +++ b/test_path.py @@ -557,7 +557,7 @@ def test_listing(self, tmpdir): @pytest.fixture def bytes_filename(self, tmpdir): - name = br'r\xe9\xf1emi' + name = rb'r\xe9\xf1emi' base = str(tmpdir).encode('ascii') try: with open(os.path.join(base, name), 'wb'): From 2a402a39f154d9a6cf4621e8c5d22bace749b55e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20S=C5=82awecki?= Date: Tue, 6 Feb 2024 23:01:32 +0100 Subject: [PATCH 43/54] Tweak coverage configuration for type checking (jaraco/skeleton#97) * Tweak coverage configuration for type checking * Use `exclude_also` instead of `exclude_lines` Co-authored-by: Sviatoslav Sydorenko * Add reference to the issue. --------- Co-authored-by: Sviatoslav Sydorenko Co-authored-by: Jason R. Coombs --- .coveragerc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.coveragerc b/.coveragerc index 02879483..35b98b1d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -7,3 +7,7 @@ disable_warnings = [report] show_missing = True +exclude_also = + # jaraco/skeleton#97 + @overload + if TYPE_CHECKING: From 68ac292eb37ce92e992e6fab05a44ad86f32e8f1 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Tue, 6 Feb 2024 16:53:46 -0500 Subject: [PATCH 44/54] Use latest versions in RTD boilerplate. --- .readthedocs.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 053c7287..68489063 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,6 +7,6 @@ python: # required boilerplate readthedocs/readthedocs.org#10401 build: - os: ubuntu-22.04 + os: ubuntu-lts-latest tools: - python: "3" + python: latest From 178d254379ed260eb537f48722703f819eaa8235 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Mon, 12 Feb 2024 16:02:29 -0500 Subject: [PATCH 45/54] Remove Sphinx pin. Ref sphinx-doc/sphinx#11662. --- setup.cfg | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup.cfg b/setup.cfg index fe99eaf6..400a72a5 100644 --- a/setup.cfg +++ b/setup.cfg @@ -34,8 +34,6 @@ testing = docs = # upstream sphinx >= 3.5 - # workaround for sphinx/sphinx-doc#11662 - sphinx < 7.2.5 jaraco.packaging >= 9.3 rst.linker >= 1.9 furo From 779219ce3ecbf4477da062658a1d0b2d5bf4f77f Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 18 Feb 2024 10:38:06 -0500 Subject: [PATCH 46/54] Include deps from the base config in diffcov. --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index 331eeed9..4c39a5b1 100644 --- a/tox.ini +++ b/tox.ini @@ -12,6 +12,7 @@ extras = [testenv:diffcov] description = run tests and check that diff from main is covered deps = + {[testenv]deps} diff-cover commands = pytest {posargs} --cov-report xml From d1c5444126aeacefee3949b30136446ab99979d8 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 2 Mar 2024 10:33:21 -0500 Subject: [PATCH 47/54] Enable complexity check and pycodestyle warnings. Closes jaraco/skeleton#110. --- ruff.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ruff.toml b/ruff.toml index e61ca8b0..6c5b0009 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,4 +1,8 @@ [lint] +select = [ + "C901", + "W", +] ignore = [ # https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules "W191", From b434f69238b4ee517ae20978afa19f3cd1ed8f1f Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 2 Mar 2024 14:05:46 -0500 Subject: [PATCH 48/54] Use 'extend-select' to avoid disabling the default config. Ref jaraco/skeleton#110. --- ruff.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruff.toml b/ruff.toml index 6c5b0009..70612985 100644 --- a/ruff.toml +++ b/ruff.toml @@ -1,5 +1,5 @@ [lint] -select = [ +extend-select = [ "C901", "W", ] From a0d0c4b7e87fbfd04cee2546ba452858587516fd Mon Sep 17 00:00:00 2001 From: Avasam Date: Thu, 21 Mar 2024 15:34:23 -0400 Subject: [PATCH 49/54] Allow mypy on PyPy (jaraco/skeleton#111) https://github.com/pypa/setuptools/pull/4257 shows that mypy now works with PyPy --- setup.cfg | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index 400a72a5..6fa73b6a 100644 --- a/setup.cfg +++ b/setup.cfg @@ -23,9 +23,7 @@ testing = pytest >= 6 pytest-checkdocs >= 2.4 pytest-cov - pytest-mypy; \ - # workaround for jaraco/skeleton#22 - python_implementation != "PyPy" + pytest-mypy pytest-enabler >= 2.2 pytest-ruff >= 0.2.1 From c9a7f97ba83be124e173713f5c24564c2b6dd49e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 21 Mar 2024 15:49:52 -0400 Subject: [PATCH 50/54] Re-enable ignoring of temporary merge queue branches. Closes jaraco/skeleton#103. --- .github/workflows/main.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cf94f7d8..143b0984 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,8 +4,11 @@ on: merge_group: push: branches-ignore: - # disabled for jaraco/skeleton#103 - # - gh-readonly-queue/** # Temporary merge queue-related GH-made branches + # temporary GH branches relating to merge queues (jaraco/skeleton#93) + - gh-readonly-queue/** + tags: + # required if branches-ignore is supplied (jaraco/skeleton#103) + - '**' pull_request: permissions: From d72c6a081b67ce18eae654bf3c8d2d627af6939e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sat, 23 Mar 2024 13:46:21 -0400 Subject: [PATCH 51/54] Fetch unshallow clones in readthedocs. Closes jaraco/skeleton#114. --- .readthedocs.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 68489063..85dfea9d 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -10,3 +10,7 @@ build: os: ubuntu-lts-latest tools: python: latest + # post-checkout job to ensure the clone isn't shallow jaraco/skeleton#114 + jobs: + post_checkout: + - git fetch --unshallow || true From 3fc7a935dfc0e5c8e330a29efc5518c464795cf8 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Fri, 29 Mar 2024 21:11:46 -0400 Subject: [PATCH 52/54] Move Python 3.11 out of the test matrix. Probably should have done this when moving continue-on-error to Python 3.13. --- .github/workflows/main.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 143b0984..a15c74a6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,7 +34,6 @@ jobs: matrix: python: - "3.8" - - "3.11" - "3.12" platform: - ubuntu-latest @@ -45,6 +44,8 @@ jobs: platform: ubuntu-latest - python: "3.10" platform: ubuntu-latest + - python: "3.11" + platform: ubuntu-latest - python: pypy3.10 platform: ubuntu-latest runs-on: ${{ matrix.platform }} From 6ff02e0eefcd90e271cefd326b460ecfa0e3eb9e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Sun, 31 Mar 2024 04:27:11 -0400 Subject: [PATCH 53/54] Configure pytest to support namespace packages. Ref pytest-dev/pytest#12112. --- pytest.ini | 5 ++++- setup.cfg | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pytest.ini b/pytest.ini index 022a723e..9a0f3bce 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,6 +1,9 @@ [pytest] norecursedirs=dist build .tox .eggs -addopts=--doctest-modules +addopts= + --doctest-modules + --import-mode importlib +consider_namespace_packages=true filterwarnings= ## upstream diff --git a/setup.cfg b/setup.cfg index 6fa73b6a..f46b6cbf 100644 --- a/setup.cfg +++ b/setup.cfg @@ -20,7 +20,7 @@ install_requires = [options.extras_require] testing = # upstream - pytest >= 6 + pytest >= 6, != 8.1.1 pytest-checkdocs >= 2.4 pytest-cov pytest-mypy From 0eddf59bd4d52d4f2e0925c27434d4bf58191663 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Thu, 4 Apr 2024 05:11:23 -0400 Subject: [PATCH 54/54] Add type annotation for iterdir. Closes #220. --- newsfragments/220.bugfix.rst | 1 + path/__init__.pyi | 1 + 2 files changed, 2 insertions(+) create mode 100644 newsfragments/220.bugfix.rst diff --git a/newsfragments/220.bugfix.rst b/newsfragments/220.bugfix.rst new file mode 100644 index 00000000..5b04804e --- /dev/null +++ b/newsfragments/220.bugfix.rst @@ -0,0 +1 @@ +Add type annotation for iterdir. diff --git a/path/__init__.pyi b/path/__init__.pyi index 1031f3e2..99642a8e 100644 --- a/path/__init__.pyi +++ b/path/__init__.pyi @@ -113,6 +113,7 @@ class Path(str): def relpath(self: Self, start: str = ...) -> Self: ... def relpathto(self: Self, dest: str) -> Self: ... # --- Listing, searching, walking, and matching + def iterdir(self: Self) -> Iterator[Self]: ... def listdir(self: Self, match: _Match = ...) -> List[Self]: ... def dirs(self: Self, match: _Match = ...) -> List[Self]: ... def files(self: Self, match: _Match = ...) -> List[Self]: ...