Skip to content

perf: make Version a little faster#987

Merged
henryiii merged 1 commit intopypa:mainfrom
henryiii:henryiii/fix/fasterversion
Nov 25, 2025
Merged

perf: make Version a little faster#987
henryiii merged 1 commit intopypa:mainfrom
henryiii:henryiii/fix/fasterversion

Conversation

@henryiii
Copy link
Copy Markdown
Contributor

@henryiii henryiii commented Nov 24, 2025

I made a quick benchmark with ChatGPT's help:

tasks/benchmark_version.py:
import timeit
from packaging.version import Version

TEST_VERSIONS = [
    "1.0.0",
    "2.7",
    "1.2.3rc1",
    "0.9.0.dev4",
    "10.5.1.post2",
    "1!2.3.4",
    "1.0+abc.1",
    "2025.11.24",
    "3.4.5-preview.8",
    "v1.0.0",
] * 10_000


def bench():
    for v in TEST_VERSIONS:
        Version(v)


if __name__ == "__main__":
    t = timeit.timeit("bench()", globals=globals(), number=5)
    print(f"Time: {t:.4f} seconds")
    print(f"Per version: {1_000_000 * t / len(TEST_VERSIONS) / 5:.9f} µs")

Then ran Python 3.15's sampling profiler:

$ sudo -E uv run --python 3.15 python -m profiling.sampling tasks/benchmark_version.py
Time: 1.3528 seconds
Per version: 2.705616084 µs
Captured 13646 samples in 1.36 seconds
Sample rate: 10000.01 samples/sec
Error rate: 20.57%
Profile Stats:
       nsamples   sample%  tottime (ms)    cumul%   cumtime (s)  filename:lineno(function)
        1/10703       0.0         0.100      99.4         1.070  _sync_coordinator.py:193(_execute_script)
        0/10703       0.0         0.000      99.4         1.070  _sync_coordinator.py:234(main)
        0/10703       0.0         0.000      99.4         1.070  _sync_coordinator.py:251(<module>)
        0/10703       0.0         0.000      99.4         1.070  <frozen runpy>:88(_run_code)
        0/10703       0.0         0.000      99.4         1.070  <frozen runpy>:198(_run_module_as_main)
        0/10661       0.0         0.000      99.0         1.066  <timeit-src>:6(inner)
        0/10661       0.0         0.000      99.0         1.066  timeit.py:183(Timer.timeit)
        0/10661       0.0         0.000      99.0         1.066  timeit.py:240(timeit)
        0/10661       0.0         0.000      99.0         1.066  benchmark_version.py:25(<module>)
      670/10660       6.2        67.000      99.0         1.066  benchmark_version.py:21(bench)
        82/9990       0.8         8.200      92.7         0.999  __init__:0(__init__)
      2613/2623      24.3       261.300      24.4         0.262  version.py:201(Version.__init__)
       951/2106       8.8        95.100      19.6         0.211  version.py:218(Version.__init__)
      1660/1813      15.4       166.000      16.8         0.181  version.py:208(Version.__init__)
      1068/1151       9.9       106.800      10.7         0.115  version.py:206(Version.__init__)

Legend:
  nsamples: Direct/Cumulative samples (direct executing / on call stack)
  sample%: Percentage of total samples this function was directly executing
  tottime: Estimated total time spent directly in this function
  cumul%: Percentage of total samples when this function was on the call stack
  cumtime: Estimated cumulative time (including time in called functions)
  filename:lineno(function): Function location and name

Summary of Interesting Functions:

Functions with Highest Direct/Cumulative Ratio (Hot Spots):
  0.818 direct/cumulative ratio, 58.4% direct samples: version.py:(Version.__init__)
  0.063 direct/cumulative ratio, 6.2% direct samples: benchmark_version.py:(bench)
  0.008 direct/cumulative ratio, 0.8% direct samples: __init__:(__init__)

Functions with Highest Call Frequency (Indirect Calls):
  10703 indirect calls, 99.4% total stack presence: _sync_coordinator.py:(main)
  10703 indirect calls, 99.4% total stack presence: _sync_coordinator.py:(<module>)
  10703 indirect calls, 99.4% total stack presence: <frozen runpy>:(_run_code)

Functions with Highest Call Magnification (Cumulative/Direct):
  10703.0x call magnification, 10702 indirect calls from 1 direct: _sync_coordinator.py:(_execute_script)
  121.8x call magnification, 9908 indirect calls from 82 direct: __init__:(__init__)
  15.9x call magnification, 9990 indirect calls from 670 direct: benchmark_version.py:(bench)

python-performance-flamegraph

Looking at the result, I was surprised to find re wasn't dominating as heavily as I expected it to. This also explained why playing with the regex to add 3.11 atomic features wasn't measurable. Looking at the slow functions, I noticed a line making lists and tuples unnecessarily, so I replaced it with a ~20x more performant function and that cut the amount of time this line (218 above/217 below) took nearly in half, with around a 10% overall improvement.

$ sudo -E uv run --python 3.15 python -m profiling.sampling tasks/benchmark_version.py
Time: 1.2303 seconds
Per version: 2.460599834 µs
Captured 12417 samples in 1.24 seconds
Sample rate: 10000.01 samples/sec
Error rate: 22.82%
Profile Stats:
       nsamples   sample%  tottime (ms)    cumul%  cumtime (ms)  filename:lineno(function)
         0/9481       0.0         0.000      99.7       948.100  _sync_coordinator.py:193(_execute_script)
         0/9481       0.0         0.000      99.7       948.100  _sync_coordinator.py:234(main)
         0/9481       0.0         0.000      99.7       948.100  _sync_coordinator.py:251(<module>)
         0/9481       0.0         0.000      99.7       948.100  <frozen runpy>:88(_run_code)
         0/9481       0.0         0.000      99.7       948.100  <frozen runpy>:198(_run_module_as_main)
         0/9449       0.0         0.000      99.3       944.900  timeit.py:240(timeit)
         0/9449       0.0         0.000      99.3       944.900  benchmark_version.py:25(<module>)
         0/9448       0.0         0.000      99.3       944.800  <timeit-src>:6(inner)
         0/9448       0.0         0.000      99.3       944.800  timeit.py:183(Timer.timeit)
       623/9446       6.5        62.300      99.3       944.600  benchmark_version.py:21(bench)
        76/8823       0.8         7.600      92.7       882.300  __init__:0(__init__)
      2133/2133      22.4       213.300      22.4       213.300  version.py:200(Version.__init__)
      1848/1889      19.4       184.800      19.9       188.900  version.py:207(Version.__init__)
       932/1237       9.8        93.200      13.0       123.700  version.py:217(Version.__init__)
      1070/1099      11.2       107.000      11.6       109.900  version.py:205(Version.__init__)

Legend:
  nsamples: Direct/Cumulative samples (direct executing / on call stack)
  sample%: Percentage of total samples this function was directly executing
  tottime: Estimated total time spent directly in this function
  cumul%: Percentage of total samples when this function was on the call stack
  cumtime: Estimated cumulative time (including time in called functions)
  filename:lineno(function): Function location and name

Summary of Interesting Functions:

Functions with Highest Direct/Cumulative Ratio (Hot Spots):
  0.941 direct/cumulative ratio, 62.9% direct samples: version.py:(Version.__init__)
  0.066 direct/cumulative ratio, 6.5% direct samples: benchmark_version.py:(bench)
  0.009 direct/cumulative ratio, 0.8% direct samples: __init__:(__init__)

Functions with Highest Call Frequency (Indirect Calls):
  9481 indirect calls, 99.7% total stack presence: _sync_coordinator.py:(_execute_script)
  9481 indirect calls, 99.7% total stack presence: _sync_coordinator.py:(main)
  9481 indirect calls, 99.7% total stack presence: _sync_coordinator.py:(<module>)

Functions with Highest Call Magnification (Cumulative/Direct):
  116.1x call magnification, 8747 indirect calls from 76 direct: __init__:(__init__)
  15.2x call magnification, 8823 indirect calls from 623 direct: benchmark_version.py:(bench)

Inspired by the caching in #986 and #985.

@henryiii henryiii changed the title fix: make Version a little faster perf: make Version a little faster Nov 24, 2025
Signed-off-by: Henry Schreiner <[email protected]>
@henryiii henryiii force-pushed the henryiii/fix/fasterversion branch from d393893 to 8337faf Compare November 25, 2025 02:23
@notatallshaw
Copy link
Copy Markdown
Member

I think the impact improving Version performance will be very dependent on the versions tested against.

I ran this via my recent pip benchmark I've been using to find hotspots, to see a real world use, here are the results (there's some slight randomness in pip which is why there isn't an identical number of calls to Version.__init__):

Before this PR:

image

After this PR:

image

We can see that the time spent in _cmpkey reduces by ~40% during __init__.

But I do wonder, why eagerly calculate _cmpkey? Once I have a moment I think I will see if making calculating it lazily saves any time for pip.

@notatallshaw
Copy link
Copy Markdown
Member

notatallshaw commented Nov 25, 2025

Worth noting, the above diagrams are constructed with the cprofiler, and that can cause different parts of the code to be affected differently in how long they take to execute.

But the relative improvement in _cmpkey seems big enough that it's likely and matches your bench marking.

@henryiii
Copy link
Copy Markdown
Contributor Author

Yes, looks similar to the statistical profile I took, the whole function (_cmpkey) spends time doing some other things, so it's a little less than 50% faster.

I got the regex rework working so I'll make a draft PR for that in a minute.

@henryiii henryiii merged commit 28294b6 into pypa:main Nov 25, 2025
72 of 74 checks passed
@henryiii henryiii deleted the henryiii/fix/fasterversion branch November 25, 2025 02:58
radermacher-iits pushed a commit to kubara-io/kubara that referenced this pull request Feb 19, 2026
This PR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [packaging](https://github.com/pypa/packaging) | packages | major | `==25.0` → `==26.0` |

---

### Release Notes

<details>
<summary>pypa/packaging (packaging)</summary>

### [`v26.0`](https://github.com/pypa/packaging/releases/tag/26.0)

[Compare Source](pypa/packaging@25.0...26.0)

Read about the performance improvements here: <https://iscinumpy.dev/post/packaging-faster>.

#### What's Changed

Features:

- PEP 751: support pylock by [@&#8203;sbidoul](https://github.com/sbidoul) in [#&#8203;900](pypa/packaging#900)
- PEP 794: import name metadata by [@&#8203;brettcannon](https://github.com/brettcannon) in [#&#8203;948](pypa/packaging#948)
- Support writing metadata by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;846](pypa/packaging#846)
- Support `__replace__` for `Version` by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1003](pypa/packaging#1003)
- Support positional pattern matching for `Version` and `Specifier` by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1004](pypa/packaging#1004)

Behavior adaptations:

- PEP 440 handling of prereleases for `Specifier.contains`, `SpecifierSet.contains`, and `SpecifierSet.filter` by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;897](pypa/packaging#897)
- Handle PEP 440 edge case in `SpecifierSet.filter` by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;942](pypa/packaging#942)
- Adjust arbitrary equality intersection preservation in `SpecifierSet` by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;951](pypa/packaging#951)
- Return `False` instead of raising for `.contains` with invalid version by [@&#8203;Liam-DeVoe](https://github.com/Liam-DeVoe) in [#&#8203;932](pypa/packaging#932)
- Support arbitrary equality on arbitrary strings for `Specifier` and `SpecifierSet`'s `filter` and `contains` method. by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;954](pypa/packaging#954)
- Only try to parse as `Version` on certain marker keys, return `False` on unequal ordered comparsions by [@&#8203;JP-Ellis](https://github.com/JP-Ellis) in [#&#8203;939](pypa/packaging#939)

Fixes:

- Update `_hash` when unpickling `Tag()` by [@&#8203;dholth](https://github.com/dholth) in [#&#8203;860](pypa/packaging#860)
- Correct comment and simplify implicit prerelease handling in `Specifier.prereleases` by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;896](pypa/packaging#896)
- Use explicit `_GLibCVersion` `NamedTuple` in `_manylinux` by [@&#8203;cthoyt](https://github.com/cthoyt) in [#&#8203;868](pypa/packaging#868)
- Detect invalid license expressions containing `()` by [@&#8203;bwoodsend](https://github.com/bwoodsend) in [#&#8203;879](pypa/packaging#879)
- Correct regex for metadata `'name'` format by [@&#8203;di](https://github.com/di) in [#&#8203;925](pypa/packaging#925)
- Improve the message around expecting a semicolon by [@&#8203;pradyunsg](https://github.com/pradyunsg) in [#&#8203;833](pypa/packaging#833)
- Support nested parens in license expressions by [@&#8203;Liam-DeVoe](https://github.com/Liam-DeVoe) in [#&#8203;931](pypa/packaging#931)
- Add space before at symbol in `Requirements` string by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;953](pypa/packaging#953)
- A root logger use found by ruff LOG, use `packaging` logger instead by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;965](pypa/packaging#965)
- Better support for subclassing `Marker` and `Requirement` by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1022](pypa/packaging#1022)
- Normalize all extras, not just if it comes first by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1024](pypa/packaging#1024)
- Don't produce a broken repr if `Marker` fails to construct by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1033](pypa/packaging#1033)

Performance:

- Avoid recompiling regexes in the tokenizer for a 3x speedup by [@&#8203;hauntsaninja](https://github.com/hauntsaninja) in [#&#8203;1019](pypa/packaging#1019)
- Improve performance in `_manylinux.py` by [@&#8203;cthoyt](https://github.com/cthoyt) in [#&#8203;869](pypa/packaging#869)
- Minor cleanups to `Version` by [@&#8203;bearomorphism](https://github.com/bearomorphism) in [#&#8203;913](pypa/packaging#913)
- Skip redundant creation of `Version`s in specifier comparison by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;986](pypa/packaging#986)
- Cache `Specifier`'s Version by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;985](pypa/packaging#985)
- Make `Version` a little faster by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;987](pypa/packaging#987)
- Minor `Version` regex cleanup by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;990](pypa/packaging#990)
- Faster regex on Python 3.11.5+ by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;988](pypa/packaging#988) and [#&#8203;1055](pypa/packaging#1055)
- Lazily calculate `_key` in `Version` by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;989](pypa/packaging#989) and regression for `packaging_legacy` fixed by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1048](pypa/packaging#1048)
- Faster `canonicalize_version` by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;993](pypa/packaging#993)
- Use `fullmatch` in a couple more places by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;992](pypa/packaging#992)
- Use `fullmatch` for markers too by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1029](pypa/packaging#1029)
- Use `map` instead of generator by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;996](pypa/packaging#996)
- Deprecate `._version` (`_Version`, a `NamedTuple`) by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;995](pypa/packaging#995) and [#&#8203;1062](pypa/packaging#1062)
- Avoid duplicate `Version` creation in `canonicalize_version` by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;994](pypa/packaging#994)
- Add `__slots__` to `Version` by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1001](pypa/packaging#1001)
- Add `__slots__` to `Specifier`s by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1002](pypa/packaging#1002)
- Add `__slots__` to `Node`s by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1032](pypa/packaging#1032)
- Use `version.__replace__` in specifier comparison by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;999](pypa/packaging#999)
- Use `_get_spec_version` in more places in `Specifier` by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;1005](pypa/packaging#1005)
- Pull `set` construction out of function by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1012](pypa/packaging#1012)
- Letter normalization dict for prereleases and the like by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1014](pypa/packaging#1014)
- Avoid normalizing extras again when comparing by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1028](pypa/packaging#1028)
- Speed up `Version.__str__` by about 10% by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;997](pypa/packaging#997)
- Increase the performance of `canonicalize_name` by avoiding a regex by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1030](pypa/packaging#1030), [#&#8203;1047](pypa/packaging#1047), and [#&#8203;1064](pypa/packaging#1064)
- Faster zero stripping by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1058](pypa/packaging#1058)

Type annotations:

- Fix a type annotation by [@&#8203;brettcannon](https://github.com/brettcannon) in [#&#8203;907](pypa/packaging#907)
- Fix tags return type in `parse_wheel_filename` docs by [@&#8203;ncoghlan](https://github.com/ncoghlan) in [#&#8203;973](pypa/packaging#973)
- Add type hint for `_version` in `.version.Version` by [@&#8203;brettcannon](https://github.com/brettcannon) in [#&#8203;927](pypa/packaging#927)
- Changed static type annotations in prereleases setter method in `specifier.py` by [@&#8203;subhajitsaha01](https://github.com/subhajitsaha01) in [#&#8203;930](pypa/packaging#930)
- Statically type the tests by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;982](pypa/packaging#982)

Internal:

- Test and declare support Python 3.14 by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;901](pypa/packaging#901)
- Modernize and speed up tests on Python 3.14 by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;903](pypa/packaging#903)
- Change our license metadata to use an SPDX license expression by [@&#8203;cdce8p](https://github.com/cdce8p) in [#&#8203;881](pypa/packaging#881)
- No need for `license-files` by [@&#8203;DimitriPapadopoulos](https://github.com/DimitriPapadopoulos) in [#&#8203;924](pypa/packaging#924)
- Update mypy by [@&#8203;hauntsaninja](https://github.com/hauntsaninja) in [#&#8203;891](pypa/packaging#891)
- Some config updates by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;902](pypa/packaging#902)
- Add spell check and rst check by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;904](pypa/packaging#904)
- Clean up ruff ignores by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;905](pypa/packaging#905)
- Update example for env marker `python_version` by [@&#8203;trim21](https://github.com/trim21) in [#&#8203;908](pypa/packaging#908)
- Move codespell configuration into pyproject.toml by [@&#8203;yarikoptic](https://github.com/yarikoptic) in [#&#8203;910](pypa/packaging#910)
- Check warning a little more precisely by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;837](pypa/packaging#837)
- Speed up mypy a little by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;836](pypa/packaging#836)
- Apply ruff/flake8-pyi rules (PYI) by [@&#8203;DimitriPapadopoulos](https://github.com/DimitriPapadopoulos) in [#&#8203;835](pypa/packaging#835)
- Better local runs for codespell by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;911](pypa/packaging#911)
- Remove outdated/confusing Gist link by [@&#8203;stefan6419846](https://github.com/stefan6419846) in [#&#8203;921](pypa/packaging#921)
- Fix docs and docs ci after [#&#8203;897](pypa/packaging#897) landed by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;926](pypa/packaging#926)
- Run twine-check on push in CI by [@&#8203;EpicWink](https://github.com/EpicWink) in [#&#8203;922](pypa/packaging#922)
- `ruff` was renamed `ruff-check` in pre-commit by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;933](pypa/packaging#933)
- Fix incorrectly implicitly concatenated string in specifiers test by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;946](pypa/packaging#946)
- Simplify conditional by [@&#8203;ofek](https://github.com/ofek) in [#&#8203;949](pypa/packaging#949)
- Modernize nox, use dependency-groups for tests by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;952](pypa/packaging#952)
- Add more checks that don't affect anything by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;957](pypa/packaging#957)
- Enable Ruff ISC rule by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;959](pypa/packaging#959)
- Ruff code FLY by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;963](pypa/packaging#963)
- pytest `log_level` is better than `log_cli_level` by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;956](pypa/packaging#956)
- Ruff code TRY by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;961](pypa/packaging#961)
- Add the ruff PL checks by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;964](pypa/packaging#964)
- Enable Ruff ARG rules by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;958](pypa/packaging#958)
- Ruff PT code (pytest) by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;960](pypa/packaging#960)
- Add ruff DTZ by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;968](pypa/packaging#968)
- Add ruff BLE by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;967](pypa/packaging#967)
- Add the ruff SIM checks by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;966](pypa/packaging#966)
- Adding ruff PERF by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;969](pypa/packaging#969)
- Move some config into coverage config by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;971](pypa/packaging#971)
- Check ruff C4 by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;962](pypa/packaging#962)
- Adding ruff T20 by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;972](pypa/packaging#972)
- Add a tests pass job by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;977](pypa/packaging#977)
- Add ruff TC by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;980](pypa/packaging#980)
- Adding part of ruff RET by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;979](pypa/packaging#979)
- Reorder mypy check by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;983](pypa/packaging#983)
- Enable ruff ALL by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;984](pypa/packaging#984)
- Link back to repo/source in furo by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;991](pypa/packaging#991)
- Add case insensitivity tests for arbitrary equality by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;975](pypa/packaging#975)
- Synchronize documentation and code for markers by [@&#8203;zahlman](https://github.com/zahlman) in [#&#8203;1008](pypa/packaging#1008)
- Use `partition` in `_parse_project_urls` by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1013](pypa/packaging#1013)
- auto-skip the dependabot PRs in the release changelog generation by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1016](pypa/packaging#1016)
- Update unreleased section in changelog by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1017](pypa/packaging#1017)
- Fix PR role to match extlinks by [@&#8203;hugovk](https://github.com/hugovk) in [#&#8203;1020](pypa/packaging#1020)
- Mention new parts in README by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1023](pypa/packaging#1023)
- Replace a couple of asserts with else by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1027](pypa/packaging#1027)
- Simplify and/or check a little more by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1031](pypa/packaging#1031)
- Use slim runner for all check by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1021](pypa/packaging#1021)
- Use typos instead of codespell by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1015](pypa/packaging#1015)
- Update changelog with recent additions by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1034](pypa/packaging#1034)
- Publish to PyPI via GitHub CI by [@&#8203;EpicWink](https://github.com/EpicWink) in [#&#8203;893](pypa/packaging#893)
- Use prek for faster pre-commit lint step by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1037](pypa/packaging#1037)
- Add help text to noxfile by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1038](pypa/packaging#1038)
- Update licenses to 3.27 by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1036](pypa/packaging#1036)
- Use relative import in `packaging.licenses` by [@&#8203;notatallshaw](https://github.com/notatallshaw) in [#&#8203;1039](pypa/packaging#1039)
- Add zizmor and tighten up CI by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1035](pypa/packaging#1035)
- Fix release script by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1040](pypa/packaging#1040)
- Fix using a dev version (again) by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1041](pypa/packaging#1041)
- Fix type hint of function used with `contextlib.contextmanager` by [@&#8203;SpecLad](https://github.com/SpecLad) in [#&#8203;1046](pypa/packaging#1046)
- Always run tests by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1044](pypa/packaging#1044)
- Fix a changelog number by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1042](pypa/packaging#1042)
- Fix the publish job by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1043](pypa/packaging#1043)
- Get the correct tag on publish by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1045](pypa/packaging#1045)
- Test on first public release of CPython 3.11 and newer by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1056](pypa/packaging#1056)
- Fix publication job (again) by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1051](pypa/packaging#1051)
- Use `actionlint` to check CI workflows by [@&#8203;miketheman](https://github.com/miketheman) in [#&#8203;1052](pypa/packaging#1052)
- Fix formatting of distribution types in metadata.rst by [@&#8203;brettcannon](https://github.com/brettcannon) in [#&#8203;1053](pypa/packaging#1053)

#### New Contributors

- [@&#8203;cdce8p](https://github.com/cdce8p) made their first contribution in [#&#8203;881](pypa/packaging#881)
- [@&#8203;dholth](https://github.com/dholth) made their first contribution in [#&#8203;860](pypa/packaging#860)
- [@&#8203;trim21](https://github.com/trim21) made their first contribution in [#&#8203;908](pypa/packaging#908)
- [@&#8203;yarikoptic](https://github.com/yarikoptic) made their first contribution in [#&#8203;910](pypa/packaging#910)
- [@&#8203;cthoyt](https://github.com/cthoyt) made their first contribution in [#&#8203;868](pypa/packaging#868)
- [@&#8203;bwoodsend](https://github.com/bwoodsend) made their first contribution in [#&#8203;879](pypa/packaging#879)
- [@&#8203;stefan6419846](https://github.com/stefan6419846) made their first contribution in [#&#8203;921](pypa/packaging#921)
- [@&#8203;bearomorphism](https://github.com/bearomorphism) made their first contribution in [#&#8203;913](pypa/packaging#913)
- [@&#8203;EpicWink](https://github.com/EpicWink) made their first contribution in [#&#8203;922](pypa/packaging#922)
- [@&#8203;Liam-DeVoe](https://github.com/Liam-DeVoe) made their first contribution in [#&#8203;932](pypa/packaging#932)
- [@&#8203;subhajitsaha01](https://github.com/subhajitsaha01) made their first contribution in [#&#8203;930](pypa/packaging#930)
- [@&#8203;ncoghlan](https://github.com/ncoghlan) made their first contribution in [#&#8203;973](pypa/packaging#973)
- [@&#8203;zahlman](https://github.com/zahlman) made their first contribution in [#&#8203;1008](pypa/packaging#1008)
- [@&#8203;JP-Ellis](https://github.com/JP-Ellis) made their first contribution in [#&#8203;939](pypa/packaging#939)

#### Since last RC

Fixes:

- Restore `._version` as a compat shim by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1062](pypa/packaging#1062)

Performance:

- Dual replace by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1064](pypa/packaging#1064)

Documentaiton:

- Prepare for 26.0 final by [@&#8203;henryiii](https://github.com/henryiii) in [#&#8203;1063](pypa/packaging#1063)

**Full Changelog**: <pypa/packaging@26.0rc3...26.0>

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4zLjYiLCJ1cGRhdGVkSW5WZXIiOiI0My4zLjYiLCJ0YXJnZXRCcmFuY2giOiJtYXN0ZXIiLCJsYWJlbHMiOltdfQ==-->

Reviewed-on: https://kubara.git.onstackit.cloud/STACKIT/kubara/pulls/280
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants