check-python-versions 0.22.1__tar.gz → 0.24.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/CHANGES.rst +21 -0
  2. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/PKG-INFO +22 -9
  3. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/README.rst +2 -2
  4. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/release.mk +4 -4
  5. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/setup.cfg +0 -6
  6. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/setup.py +3 -6
  7. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/__init__.py +1 -1
  8. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/cli.py +30 -20
  9. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/parsers/classifiers.py +2 -2
  10. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/parsers/ini.py +1 -2
  11. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/parsers/poetry_version_spec.py +6 -12
  12. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/parsers/python.py +5 -6
  13. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/parsers/requires_python.py +6 -12
  14. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/parsers/yaml.py +8 -8
  15. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/appveyor.py +4 -4
  16. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/base.py +7 -7
  17. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/github.py +3 -3
  18. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/pyproject.py +8 -8
  19. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/setup_py.py +6 -6
  20. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/tox.py +6 -6
  21. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/travis.py +3 -5
  22. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/utils.py +6 -16
  23. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/versions.py +7 -7
  24. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions.egg-info/PKG-INFO +22 -9
  25. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions.egg-info/SOURCES.txt +0 -1
  26. check_python_versions-0.24.0/src/check_python_versions.egg-info/requires.txt +2 -0
  27. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/parsers/test_classifiers.py +1 -3
  28. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/parsers/test_poetry_version_spec.py +1 -3
  29. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/parsers/test_requires_python.py +1 -3
  30. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/sources/test_appveyor.py +1 -2
  31. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/sources/test_github.py +1 -2
  32. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/sources/test_manylinux.py +1 -2
  33. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/sources/test_pyproject.py +2 -2
  34. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/sources/test_setup_py.py +1 -2
  35. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/sources/test_tox.py +1 -2
  36. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/sources/test_travis.py +1 -2
  37. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/test_cli.py +33 -4
  38. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tox.ini +2 -2
  39. check-python-versions-0.22.1/appveyor.yml +0 -33
  40. check-python-versions-0.22.1/src/check_python_versions.egg-info/requires.txt +0 -5
  41. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/.coveragerc +0 -0
  42. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/.gitignore +0 -0
  43. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/.pre-commit-hooks.yaml +0 -0
  44. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/CLASSIFIERS +0 -0
  45. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/LICENSE +0 -0
  46. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/MANIFEST.in +0 -0
  47. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/Makefile +0 -0
  48. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/check-python-versions +0 -0
  49. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/pytest.ini +0 -0
  50. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/__main__.py +0 -0
  51. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/parsers/__init__.py +0 -0
  52. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/__init__.py +0 -0
  53. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/all.py +0 -0
  54. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions/sources/manylinux.py +0 -0
  55. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions.egg-info/dependency_links.txt +0 -0
  56. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions.egg-info/entry_points.txt +0 -0
  57. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions.egg-info/not-zip-safe +0 -0
  58. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/src/check_python_versions.egg-info/top_level.txt +0 -0
  59. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/__init__.py +0 -0
  60. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/conftest.py +0 -0
  61. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/parsers/test_ini.py +0 -0
  62. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/parsers/test_python.py +0 -0
  63. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/parsers/test_yaml.py +0 -0
  64. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/test___main__.py +0 -0
  65. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/test_utils.py +0 -0
  66. {check-python-versions-0.22.1 → check_python_versions-0.24.0}/tests/test_versions.py +0 -0
@@ -1,6 +1,27 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ 0.24.0 (2025-11-13)
5
+ -------------------
6
+
7
+ - Drop support for Python 3.8 and 3.9.
8
+
9
+ - Mention the ``--allow-non-packages`` option when showing the error message
10
+ that rejects non-packages.
11
+
12
+ - Add ``--set`` as an alias for ``--update``.
13
+
14
+
15
+ 0.23.0 (2025-10-14)
16
+ -------------------
17
+
18
+ - Add support for Python 3.14: treat it as a released version, run CI tests on
19
+ 3.14.
20
+
21
+ - New option ``--allow-non-packages`` so you can automate tox.ini or GitHub
22
+ workflow updates in projects that are not Python packages.
23
+
24
+
4
25
  0.22.1 (2024-10-09)
5
26
  -------------------
6
27
 
@@ -1,11 +1,11 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: check-python-versions
3
- Version: 0.22.1
3
+ Version: 0.24.0
4
4
  Summary: Compare supported Python versions in setup.py vs tox.ini et al.
5
5
  Home-page: https://github.com/mgedmin/check-python-versions
6
6
  Author: Marius Gedminas
7
7
  Author-email: marius@gedmin.as
8
- License: GPL
8
+ License: GPL-3.0-or-later
9
9
  Project-URL: Changelog, https://github.com/mgedmin/check-python-versions/blob/master/CHANGES.rst
10
10
  Project-URL: Issues, https://github.com/mgedmin/check-python-versions/issues
11
11
  Project-URL: Source Code, https://github.com/mgedmin/check-python-versions
@@ -13,19 +13,32 @@ Keywords: python packaging version checker linter setup.py tox travis appveyor
13
13
  Classifier: Development Status :: 4 - Beta
14
14
  Classifier: Environment :: Console
15
15
  Classifier: Intended Audience :: Developers
16
- Classifier: License :: OSI Approved :: GNU General Public License (GPL)
17
16
  Classifier: Operating System :: OS Independent
18
- Classifier: Programming Language :: Python :: 3.8
19
- Classifier: Programming Language :: Python :: 3.9
20
17
  Classifier: Programming Language :: Python :: 3.10
21
18
  Classifier: Programming Language :: Python :: 3.11
22
19
  Classifier: Programming Language :: Python :: 3.12
23
20
  Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Programming Language :: Python :: 3.14
24
22
  Classifier: Programming Language :: Python :: Implementation :: CPython
25
23
  Classifier: Programming Language :: Python :: Implementation :: PyPy
26
- Requires-Python: >=3.8
24
+ Requires-Python: >=3.10
27
25
  Description-Content-Type: text/x-rst
28
26
  License-File: LICENSE
27
+ Requires-Dist: pyyaml
28
+ Requires-Dist: tomlkit
29
+ Dynamic: author
30
+ Dynamic: author-email
31
+ Dynamic: classifier
32
+ Dynamic: description
33
+ Dynamic: description-content-type
34
+ Dynamic: home-page
35
+ Dynamic: keywords
36
+ Dynamic: license
37
+ Dynamic: license-file
38
+ Dynamic: project-url
39
+ Dynamic: requires-dist
40
+ Dynamic: requires-python
41
+ Dynamic: summary
29
42
 
30
43
  check-python-versions
31
44
  =====================
@@ -38,7 +51,7 @@ check-python-versions
38
51
  :target: https://pypi.org/project/check-python-versions/
39
52
  :alt: Supported Python versions
40
53
 
41
- .. image:: https://github.com/mgedmin/check-python-versions/workflows/build/badge.svg?branch=master
54
+ .. image:: https://github.com/mgedmin/check-python-versions/actions/workflows/build.yml/badge.svg?branch=master
42
55
  :target: https://github.com/mgedmin/check-python-versions/actions
43
56
  :alt: Build status
44
57
 
@@ -413,6 +426,6 @@ Add the following snippet to your ``.pre-commit-config.yaml``.
413
426
 
414
427
  repos:
415
428
  - repo: https://github.com/mgedmin/check-python-versions
416
- rev: "0.22.1"
429
+ rev: "0.24.0"
417
430
  hooks:
418
431
  - id: check-python-versions
@@ -9,7 +9,7 @@ check-python-versions
9
9
  :target: https://pypi.org/project/check-python-versions/
10
10
  :alt: Supported Python versions
11
11
 
12
- .. image:: https://github.com/mgedmin/check-python-versions/workflows/build/badge.svg?branch=master
12
+ .. image:: https://github.com/mgedmin/check-python-versions/actions/workflows/build.yml/badge.svg?branch=master
13
13
  :target: https://github.com/mgedmin/check-python-versions/actions
14
14
  :alt: Build status
15
15
 
@@ -384,6 +384,6 @@ Add the following snippet to your ``.pre-commit-config.yaml``.
384
384
 
385
385
  repos:
386
386
  - repo: https://github.com/mgedmin/check-python-versions
387
- rev: "0.22.1"
387
+ rev: "0.24.0"
388
388
  hooks:
389
389
  - id: check-python-versions
@@ -1,4 +1,4 @@
1
- # release.mk version 2.1 (2021-04-19)
1
+ # release.mk version 2.2.3 (2024-10-10)
2
2
  #
3
3
  # Helpful Makefile rules for releasing Python packages.
4
4
  # https://github.com/mgedmin/python-project-skel
@@ -12,7 +12,7 @@ DISTCHECK_DIFF_OPTS ?= $(DISTCHECK_DIFF_DEFAULT_OPTS)
12
12
 
13
13
  # These should be fine
14
14
  PYTHON ?= python3
15
- PYPI_PUBLISH ?= rm -rf dist && $(PYTHON) setup.py -q sdist bdist_wheel && twine check dist/* && twine upload dist/*
15
+ PYPI_PUBLISH ?= rm -rf dist && $(PYTHON) -m build && twine check dist/* && twine upload dist/*
16
16
  LATEST_RELEASE_MK_URL = https://raw.githubusercontent.com/mgedmin/python-project-skel/master/release.mk
17
17
  DISTCHECK_DIFF_DEFAULT_OPTS = -x PKG-INFO -x setup.cfg -x '*.egg-info' -x .github -I'^\#'
18
18
 
@@ -44,7 +44,7 @@ help:
44
44
 
45
45
  .PHONY: dist
46
46
  dist:
47
- $(PYTHON) setup.py -q sdist bdist_wheel
47
+ $(PYTHON) -m build
48
48
 
49
49
  # Provide a default 'make check' to be the same as 'make test', since that's
50
50
  # what 80% of my projects use, but make it possible to override. Now
@@ -79,7 +79,7 @@ endif
79
79
 
80
80
  .PHONY: distcheck-sdist
81
81
  distcheck-sdist: dist
82
- pkg_and_version=`$(PYTHON) setup.py --name`-`$(PYTHON) setup.py --version` && \
82
+ pkg_and_version=`$(PYTHON) setup.py --name|tr A-Z.- a-z__`-`$(PYTHON) setup.py --version` && \
83
83
  rm -rf tmp && \
84
84
  mkdir tmp && \
85
85
  $(VCS_EXPORT) && \
@@ -1,9 +1,3 @@
1
- [bdist_wheel]
2
- universal = 1
3
-
4
- [metadata]
5
- license_files = LICENSE
6
-
7
1
  [zest.releaser]
8
2
  python-file-with-version = src/check_python_versions/__init__.py
9
3
 
@@ -49,19 +49,17 @@ setup(
49
49
  'Development Status :: 4 - Beta',
50
50
  'Environment :: Console',
51
51
  'Intended Audience :: Developers',
52
- 'License :: OSI Approved :: GNU General Public License (GPL)',
53
52
  'Operating System :: OS Independent',
54
- 'Programming Language :: Python :: 3.8',
55
- 'Programming Language :: Python :: 3.9',
56
53
  'Programming Language :: Python :: 3.10',
57
54
  'Programming Language :: Python :: 3.11',
58
55
  'Programming Language :: Python :: 3.12',
59
56
  'Programming Language :: Python :: 3.13',
57
+ 'Programming Language :: Python :: 3.14',
60
58
  'Programming Language :: Python :: Implementation :: CPython',
61
59
  'Programming Language :: Python :: Implementation :: PyPy',
62
60
  ],
63
- license='GPL',
64
- python_requires=">=3.8",
61
+ license='GPL-3.0-or-later',
62
+ python_requires=">=3.10",
65
63
  packages=find_packages('src'),
66
64
  package_dir={'': 'src'},
67
65
  entry_points={
@@ -72,7 +70,6 @@ setup(
72
70
  install_requires=[
73
71
  'pyyaml',
74
72
  'tomlkit',
75
- 'typing_extensions; python_version < "3.8"',
76
73
  ],
77
74
  zip_safe=False,
78
75
  )
@@ -13,4 +13,4 @@ Makes sure the set of supported Python versions is consistent between
13
13
  """
14
14
 
15
15
  __author__ = 'Marius Gedminas <marius@gedmin.as>'
16
- __version__ = '0.22.1'
16
+ __version__ = '0.24.0'
@@ -12,7 +12,7 @@ import glob
12
12
  import os
13
13
  import sys
14
14
  from io import StringIO
15
- from typing import Callable, Collection, Dict, List, Optional, Tuple
15
+ from typing import Callable, Collection
16
16
 
17
17
  from . import __version__
18
18
  from .sources.all import ALL_SOURCES
@@ -34,7 +34,7 @@ from .versions import (
34
34
  )
35
35
 
36
36
 
37
- def parse_version(v: str) -> Tuple[int, int]:
37
+ def parse_version(v: str) -> tuple[int, int]:
38
38
  """Parse a Python version number.
39
39
 
40
40
  Expects 'MAJOR.MINOR', no more, no less.
@@ -127,6 +127,7 @@ def check_package(where: str = '.', *, print: PrintFn = print) -> bool:
127
127
 
128
128
  if not is_package(where):
129
129
  print("no setup.py or pyproject.toml -- not a Python package?")
130
+ print("you may want to try --allow-non-packages")
130
131
  return False
131
132
 
132
133
  return True
@@ -147,11 +148,11 @@ def check_package(where: str = '.', *, print: PrintFn = print) -> bool:
147
148
  # results, to get back the final results.
148
149
  #
149
150
 
150
- ReplacementDict = Dict[str, FileLines]
151
+ ReplacementDict = dict[str, FileLines]
151
152
 
152
153
 
153
154
  def filename_or_replacement(
154
- pathname: str, replacements: Optional[ReplacementDict]
155
+ pathname: str, replacements: ReplacementDict | None
155
156
  ) -> FileOrFilename:
156
157
  """Look up a file in the replacement dict.
157
158
 
@@ -175,10 +176,10 @@ FilenameSet = Collection[str]
175
176
  def find_sources(
176
177
  where: str = '.',
177
178
  *,
178
- replacements: Optional[ReplacementDict] = None,
179
- only: Optional[FilenameSet] = None,
179
+ replacements: ReplacementDict | None = None,
180
+ only: FilenameSet | None = None,
180
181
  supports_update: bool = False,
181
- ) -> List[SourceFile]:
182
+ ) -> list[SourceFile]:
182
183
  """Find all sources that exist in a given directory.
183
184
 
184
185
  ``replacements`` allows you to check the result of an update (see
@@ -211,9 +212,9 @@ def check_versions(
211
212
  *,
212
213
  print: PrintFn = print,
213
214
  min_width: int = 0,
214
- expect: Optional[VersionList] = None,
215
- replacements: Optional[ReplacementDict] = None,
216
- only: Optional[FilenameSet] = None,
215
+ expect: VersionList | None = None,
216
+ replacements: ReplacementDict | None = None,
217
+ only: FilenameSet | None = None,
217
218
  ) -> bool:
218
219
  """Check Python versions for a single package, located in ``where``.
219
220
 
@@ -251,8 +252,8 @@ def check_versions(
251
252
 
252
253
 
253
254
  def supported_versions_match(
254
- sources: List[SourceFile],
255
- expect: Optional[VersionList] = None,
255
+ sources: list[SourceFile],
256
+ expect: VersionList | None = None,
256
257
  ) -> bool:
257
258
  version_sets = []
258
259
  pypy_version_sets = []
@@ -291,12 +292,12 @@ def supported_versions_match(
291
292
  def update_versions(
292
293
  where: str = '.',
293
294
  *,
294
- add: Optional[VersionList] = None,
295
- drop: Optional[VersionList] = None,
296
- update: Optional[VersionList] = None,
295
+ add: VersionList | None = None,
296
+ drop: VersionList | None = None,
297
+ update: VersionList | None = None,
297
298
  diff: bool = False,
298
299
  dry_run: bool = False,
299
- only: Optional[FilenameSet] = None,
300
+ only: FilenameSet | None = None,
300
301
  ) -> ReplacementDict:
301
302
  """Update Python versions for a single package, located in ``where``.
302
303
 
@@ -370,6 +371,10 @@ def _main() -> None:
370
371
  parser.add_argument('--skip-non-packages', action='store_true',
371
372
  help='skip arguments that are not Python packages'
372
373
  ' without warning about them')
374
+ parser.add_argument('--allow-non-packages', action='store_true',
375
+ help='try to work on directories that are not Python'
376
+ ' packages but have a tox.ini'
377
+ ' or .github/workflows')
373
378
  parser.add_argument('--only', metavar='FILES',
374
379
  help='check only the specified files'
375
380
  ' (comma-separated list, e.g.'
@@ -385,7 +390,8 @@ def _main() -> None:
385
390
  group.add_argument('--drop', metavar='VERSIONS', type=parse_version_list,
386
391
  help='drop these versions from supported ones, e.g'
387
392
  ' --drop 2.6,3.4')
388
- group.add_argument('--update', metavar='VERSIONS', type=parse_version_list,
393
+ group.add_argument('--update', '--set', metavar='VERSIONS',
394
+ type=parse_version_list,
389
395
  help='update the set of supported versions, e.g.'
390
396
  ' --update 2.7,3.5-3.7')
391
397
  group.add_argument('--diff', action='store_true',
@@ -399,6 +405,9 @@ def _main() -> None:
399
405
  parser.error("argument --add: not allowed with argument --update")
400
406
  if args.update and args.drop:
401
407
  parser.error("argument --drop: not allowed with argument --update")
408
+ if args.skip_non_packages and args.allow_non_packages:
409
+ parser.error("use either --skip-non-packages or --allow-non-packages,"
410
+ " not both")
402
411
  if args.diff and not (args.update or args.add or args.drop):
403
412
  parser.error(
404
413
  "argument --diff: not allowed without --update/--add/--drop")
@@ -431,9 +440,10 @@ def _main() -> None:
431
440
  if n:
432
441
  print("\n")
433
442
  print(f"{path}:\n")
434
- if not check_package(path):
435
- mismatches.append(path)
436
- continue
443
+ if not args.allow_non_packages:
444
+ if not check_package(path):
445
+ mismatches.append(path)
446
+ continue
437
447
  replacements = {}
438
448
  if args.add or args.drop or args.update:
439
449
  replacements = update_versions(
@@ -1,7 +1,7 @@
1
1
  """
2
2
  Tools for manipulating PyPI classifiers.
3
3
  """
4
- from typing import List, Sequence
4
+ from typing import Sequence
5
5
 
6
6
  from ..versions import SortedVersionList, Version, expand_pypy
7
7
 
@@ -52,7 +52,7 @@ def get_versions_from_classifiers(
52
52
  def update_classifiers(
53
53
  classifiers: Sequence[str],
54
54
  new_versions: SortedVersionList
55
- ) -> List[str]:
55
+ ) -> list[str]:
56
56
  """Update a list of classifiers with new Python versions."""
57
57
  prefix = 'Programming Language :: Python :: '
58
58
 
@@ -6,7 +6,6 @@ INI parser and serializer.
6
6
  """
7
7
 
8
8
  import re
9
- from typing import List
10
9
 
11
10
  from ..utils import FileLines, get_indent, warn
12
11
 
@@ -55,7 +54,7 @@ def update_ini_setting(
55
54
 
56
55
  end = start + 1
57
56
  comments = []
58
- pending_comments: List[str] = []
57
+ pending_comments: list[str] = []
59
58
  indent = ' '
60
59
  for n, line in lines:
61
60
  if line.startswith(' '):
@@ -6,7 +6,7 @@ https://python-poetry.org/docs/dependency-specification/#version-constraints
6
6
  """
7
7
 
8
8
  import re
9
- from typing import Callable, Dict, List, Optional, Tuple, Union
9
+ from typing import Callable, TypedDict
10
10
 
11
11
  from ..utils import warn
12
12
  from ..versions import (
@@ -17,18 +17,12 @@ from ..versions import (
17
17
  )
18
18
 
19
19
 
20
- try:
21
- from typing import TypedDict
22
- except ImportError: # pragma: nocover
23
- from typing_extensions import TypedDict
24
-
25
-
26
20
  def parse_poetry_version_constraint(
27
21
  s: str,
28
22
  name: str = "tool.poetry.dependencies.python",
29
23
  *,
30
24
  filename: str = 'pyproject.toml',
31
- ) -> Optional[SortedVersionList]:
25
+ ) -> SortedVersionList | None:
32
26
  """Compute Python versions allowed by Poetry version constraints."""
33
27
 
34
28
  rx = re.compile(r'^(|[~^]|==|!=|<=|>=|<|>)\s*(\d+(?:\.\d+)*(?:\.\*)?)$')
@@ -42,7 +36,7 @@ def parse_poetry_version_constraint(
42
36
  # with a possible trailing '*'. PEP 440 calls them "clauses".
43
37
  #
44
38
 
45
- Constraint = Tuple[Union[str, int], ...]
39
+ Constraint = tuple[str | int, ...]
46
40
 
47
41
  #
48
42
  # The we look up a handler for each operartor. This handler takes a
@@ -51,7 +45,7 @@ def parse_poetry_version_constraint(
51
45
  # that version passes its constraint.
52
46
  #
53
47
 
54
- VersionTuple = Tuple[int, int]
48
+ VersionTuple = tuple[int, int]
55
49
  CheckFn = Callable[[VersionTuple], bool]
56
50
  HandlerFn = Callable[[Constraint], CheckFn]
57
51
 
@@ -59,7 +53,7 @@ def parse_poetry_version_constraint(
59
53
  # Here we're defining the handlers for all the operators
60
54
  #
61
55
 
62
- handlers: Dict[str, HandlerFn] = {}
56
+ handlers: dict[str, HandlerFn] = {}
63
57
 
64
58
  def handler(operator: str) -> Callable[[HandlerFn], None]:
65
59
  def decorator(fn: HandlerFn) -> None:
@@ -192,7 +186,7 @@ def parse_poetry_version_constraint(
192
186
  # into checkers (which I also call "constraints", for maximum confusion).
193
187
  #
194
188
 
195
- constraints: List[CheckFn] = []
189
+ constraints: list[CheckFn] = []
196
190
  for specifier in map(str.strip, s.split(',')):
197
191
  m = rx.match(specifier)
198
192
  if not m:
@@ -5,12 +5,11 @@ Tools for manipulating Python files.
5
5
  import ast
6
6
  import re
7
7
  import string
8
- from typing import List, Optional, Tuple, Union
9
8
 
10
9
  from ..utils import FileLines, OneOrMore, get_indent, warn
11
10
 
12
11
 
13
- AstValue = Union[str, List[str], Tuple[str, ...]]
12
+ AstValue = str | list[str] | tuple[str, ...]
14
13
 
15
14
 
16
15
  def to_literal(value: str, quote_style: str = '"') -> str:
@@ -33,7 +32,7 @@ def update_call_arg_in_source(
33
32
  source_lines: FileLines,
34
33
  function: OneOrMore[str],
35
34
  keyword: str,
36
- new_value: Union[str, List[str]],
35
+ new_value: str | list[str],
37
36
  *,
38
37
  filename: str = 'setup.py',
39
38
  ) -> FileLines:
@@ -169,7 +168,7 @@ def find_call_kwarg_in_ast(
169
168
  keyword: str,
170
169
  *,
171
170
  filename: str,
172
- ) -> Optional[ast.AST]:
171
+ ) -> ast.AST | None:
173
172
  """Find the value passed to a function call.
174
173
 
175
174
  ``filename`` is used for error reporting.
@@ -204,7 +203,7 @@ def eval_ast_node(
204
203
  keyword: str,
205
204
  *,
206
205
  filename: str = 'setup.py',
207
- ) -> Optional[AstValue]:
206
+ ) -> AstValue | None:
208
207
  """Partially evaluate an AST node.
209
208
 
210
209
  ``keyword`` is used for error reporting.
@@ -212,7 +211,7 @@ def eval_ast_node(
212
211
  if isinstance(node, ast.Constant) and isinstance(node.value, str):
213
212
  return node.value
214
213
  if isinstance(node, (ast.List, ast.Tuple)):
215
- values: List[str] = []
214
+ values: list[str] = []
216
215
  warned = False
217
216
  for element in node.elts:
218
217
  try:
@@ -2,7 +2,7 @@
2
2
  Tools for manipulating requires-python PyPI classifiers.
3
3
  """
4
4
  import re
5
- from typing import Callable, Dict, List, Optional, Tuple, Union
5
+ from typing import Callable, TypedDict
6
6
 
7
7
  from ..utils import warn
8
8
  from ..versions import (
@@ -13,18 +13,12 @@ from ..versions import (
13
13
  )
14
14
 
15
15
 
16
- try:
17
- from typing import TypedDict
18
- except ImportError: # pragma: nocover
19
- from typing_extensions import TypedDict
20
-
21
-
22
16
  def parse_python_requires(
23
17
  s: str,
24
18
  name: str = "python_requires",
25
19
  *,
26
20
  filename: str = "setup.py",
27
- ) -> Optional[SortedVersionList]:
21
+ ) -> SortedVersionList | None:
28
22
  """Compute Python versions allowed by a python_requires expression."""
29
23
 
30
24
  # https://www.python.org/dev/peps/pep-0440/#version-specifiers
@@ -39,7 +33,7 @@ def parse_python_requires(
39
33
  # with a possible trailing '*'. PEP 440 calls them "clauses".
40
34
  #
41
35
 
42
- Constraint = Tuple[Union[str, int], ...]
36
+ Constraint = tuple[str | int, ...]
43
37
 
44
38
  #
45
39
  # The we look up a handler for each operartor. This handler takes a
@@ -48,7 +42,7 @@ def parse_python_requires(
48
42
  # that version passes its constraint.
49
43
  #
50
44
 
51
- VersionTuple = Tuple[int, int]
45
+ VersionTuple = tuple[int, int]
52
46
  CheckFn = Callable[[VersionTuple], bool]
53
47
  HandlerFn = Callable[[Constraint], CheckFn]
54
48
 
@@ -56,7 +50,7 @@ def parse_python_requires(
56
50
  # Here we're defining the handlers for all the operators
57
51
  #
58
52
 
59
- handlers: Dict[str, HandlerFn] = {}
53
+ handlers: dict[str, HandlerFn] = {}
60
54
 
61
55
  def handler(operator: str) -> Callable[[HandlerFn], None]:
62
56
  def decorator(fn: HandlerFn) -> None:
@@ -172,7 +166,7 @@ def parse_python_requires(
172
166
  # into checkers (which I also call "constraints", for maximum confusion).
173
167
  #
174
168
 
175
- constraints: List[CheckFn] = []
169
+ constraints: list[CheckFn] = []
176
170
  for specifier in map(str.strip, s.split(',')):
177
171
  m = rx.match(specifier)
178
172
  if not m:
@@ -6,7 +6,7 @@ YAML parser and serializer.
6
6
  """
7
7
 
8
8
  import string
9
- from typing import Any, Callable, Dict, List, Optional
9
+ from typing import Any, Callable
10
10
 
11
11
  from ..utils import FileLines, OneOrMore, OneOrTuple, warn
12
12
 
@@ -34,11 +34,11 @@ def quote_string(value: str, quote_style: str = '') -> str:
34
34
  def update_yaml_list(
35
35
  orig_lines: FileLines,
36
36
  key: OneOrTuple[str],
37
- new_value: List[Any],
37
+ new_value: list[Any],
38
38
  *,
39
39
  filename: str,
40
- keep: Optional[Callable[[str], bool]] = None,
41
- replacements: Optional[Dict[str, str]] = None,
40
+ keep: Callable[[str], bool] | None = None,
41
+ replacements: dict[str, str] | None = None,
42
42
  ) -> FileLines:
43
43
  """Update a list of values in a YAML document.
44
44
 
@@ -94,10 +94,10 @@ def update_yaml_list(
94
94
  end = n + 1
95
95
  indent = 2
96
96
  list_indent = None
97
- keep_before: List[str] = []
98
- keep_after: List[str] = []
97
+ keep_before: list[str] = []
98
+ keep_after: list[str] = []
99
99
  lines_to_keep = keep_before
100
- kept_last: Optional[bool] = False
100
+ kept_last: bool | None = False
101
101
  for n, line in lines:
102
102
  stripped = line.lstrip()
103
103
  line_indent = len(line) - len(stripped)
@@ -187,7 +187,7 @@ def add_yaml_node(
187
187
  key: str,
188
188
  value: str,
189
189
  *,
190
- before: Optional[OneOrMore[str]] = None,
190
+ before: OneOrMore[str] | None = None,
191
191
  ) -> FileLines:
192
192
  """Add a value to a YAML document.
193
193
 
@@ -24,7 +24,7 @@ of Tox environments (pyXY).
24
24
 
25
25
  import ast
26
26
  from io import StringIO
27
- from typing import Optional, Set, cast
27
+ from typing import Set, cast
28
28
 
29
29
  import yaml
30
30
 
@@ -61,7 +61,7 @@ def get_appveyor_yml_python_versions(
61
61
  return sorted(cast(Set[Version], set(versions) - {None}))
62
62
 
63
63
 
64
- def appveyor_normalize_py_version(ver: str) -> Optional[Version]:
64
+ def appveyor_normalize_py_version(ver: str) -> Version | None:
65
65
  """Determine Python version from PYTHON environment variable."""
66
66
  ver = str(ver).lower().replace('\\', '/')
67
67
  if ver.startswith('c:/python'):
@@ -78,7 +78,7 @@ def appveyor_normalize_py_version(ver: str) -> Optional[Version]:
78
78
  return None
79
79
 
80
80
 
81
- def appveyor_detect_py_version_pattern(ver: str) -> Optional[str]:
81
+ def appveyor_detect_py_version_pattern(ver: str) -> str | None:
82
82
  """Determine the format of the PYTHON environment variable.
83
83
 
84
84
  Returns a format string suitable for formatting with placeholders
@@ -113,7 +113,7 @@ def escape(s: str) -> str:
113
113
  def update_appveyor_yml_python_versions(
114
114
  filename: FileOrFilename,
115
115
  new_versions: VersionList,
116
- ) -> Optional[FileLines]:
116
+ ) -> FileLines | None:
117
117
  """Update supported Python versions in appveyor.yml.
118
118
 
119
119
  Does not touch the file but returns a list of lines with new file contents.
@@ -1,11 +1,11 @@
1
- from typing import Callable, Optional
1
+ from typing import Callable
2
2
 
3
3
  from ..utils import FileLines, FileOrFilename
4
4
  from ..versions import SortedVersionList
5
5
 
6
6
 
7
- ExtractorFn = Callable[[FileOrFilename], Optional[SortedVersionList]]
8
- UpdaterFn = Callable[[FileOrFilename, SortedVersionList], Optional[FileLines]]
7
+ ExtractorFn = Callable[[FileOrFilename], SortedVersionList | None]
8
+ UpdaterFn = Callable[[FileOrFilename, SortedVersionList], FileLines | None]
9
9
 
10
10
 
11
11
  class Source:
@@ -26,10 +26,10 @@ class Source:
26
26
  def __init__(
27
27
  self,
28
28
  *,
29
- title: Optional[str] = None,
29
+ title: str | None = None,
30
30
  filename: str,
31
31
  extract: ExtractorFn,
32
- update: Optional[UpdaterFn] = None,
32
+ update: UpdaterFn | None = None,
33
33
  check_pypy_consistency: bool,
34
34
  has_upper_bound: bool,
35
35
  ) -> None:
@@ -70,10 +70,10 @@ class SourceFile(Source):
70
70
  def __init__(
71
71
  self,
72
72
  *,
73
- title: Optional[str] = None,
73
+ title: str | None = None,
74
74
  filename: str,
75
75
  extract: ExtractorFn,
76
- update: Optional[UpdaterFn] = None,
76
+ update: UpdaterFn | None = None,
77
77
  check_pypy_consistency: bool,
78
78
  has_upper_bound: bool,
79
79
  pathname: str,