django-codemod 2.1.10__tar.gz → 2.2.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 (64) hide show
  1. {django_codemod-2.1.10 → django_codemod-2.2.0}/PKG-INFO +6 -6
  2. {django_codemod-2.1.10 → django_codemod-2.2.0}/README.md +3 -3
  3. {django_codemod-2.1.10 → django_codemod-2.2.0}/pyproject.toml +77 -78
  4. django_codemod-2.2.0/src/django_codemod/__init__.py +1 -0
  5. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/cli.py +17 -16
  6. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/commands.py +1 -2
  7. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/path_utils.py +5 -4
  8. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/utils/calls.py +2 -1
  9. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/base.py +6 -5
  10. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/crypto.py +1 -1
  11. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/models.py +4 -2
  12. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/shortcuts.py +1 -1
  13. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/signals.py +3 -3
  14. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/template_tags.py +2 -1
  15. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/timezone.py +1 -1
  16. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/urls.py +2 -2
  17. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/base.py +1 -3
  18. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_admin.py +3 -9
  19. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_base.py +6 -18
  20. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_http.py +3 -9
  21. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_models.py +3 -9
  22. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_paginator.py +1 -3
  23. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_postgres_fields.py +3 -9
  24. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_signals.py +2 -6
  25. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_template_tags.py +4 -12
  26. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_timezone.py +2 -6
  27. django_codemod-2.1.10/src/django_codemod/__init__.py +0 -1
  28. {django_codemod-2.1.10 → django_codemod-2.2.0}/LICENSE +0 -0
  29. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/constants.py +0 -0
  30. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/feature_flags.py +0 -0
  31. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/utils/__init__.py +0 -0
  32. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/__init__.py +0 -0
  33. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/admin.py +0 -0
  34. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/core.py +0 -0
  35. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/decorators.py +0 -0
  36. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/encoding.py +0 -0
  37. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/exceptions.py +0 -0
  38. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/forms.py +0 -0
  39. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/html.py +0 -0
  40. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/http.py +0 -0
  41. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/lru_cache.py +0 -0
  42. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/os_utils.py +0 -0
  43. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/paginator.py +0 -0
  44. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/postgres_fields.py +0 -0
  45. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/template_context.py +0 -0
  46. {django_codemod-2.1.10 → django_codemod-2.2.0}/src/django_codemod/visitors/translations.py +0 -0
  47. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/__init__.py +0 -0
  48. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/test_cli.py +0 -0
  49. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/test_e2e.sh +0 -0
  50. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/test_path_utils.py +0 -0
  51. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/__init__.py +0 -0
  52. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_core.py +0 -0
  53. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_crypto.py +0 -0
  54. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_decorators.py +0 -0
  55. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_encoding.py +0 -0
  56. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_exceptions.py +0 -0
  57. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_forms.py +0 -0
  58. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_html.py +0 -0
  59. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_lru_cache.py +0 -0
  60. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_os_utils.py +0 -0
  61. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_shortcuts.py +0 -0
  62. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_template_context.py +0 -0
  63. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_translations.py +0 -0
  64. {django_codemod-2.1.10 → django_codemod-2.2.0}/tests/visitors/test_urls.py +0 -0
@@ -1,24 +1,24 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: django-codemod
3
- Version: 2.1.10
3
+ Version: 2.2.0
4
4
  Summary: A command line tool to automatically fix Django deprecations.
5
5
  Home-page: https://github.com/browniebroke/django-codemod
6
6
  License: MIT
7
7
  Keywords: django,codemod,libCST
8
8
  Author: Bruno Alla
9
9
  Author-email: alla.brunoo@gmail.com
10
- Requires-Python: >=3.8,<4.0
10
+ Requires-Python: >=3.9,<4.0
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Developers
13
13
  Classifier: License :: OSI Approved :: MIT License
14
14
  Classifier: Natural Language :: English
15
15
  Classifier: Operating System :: OS Independent
16
16
  Classifier: Programming Language :: Python :: 3
17
- Classifier: Programming Language :: Python :: 3.8
18
17
  Classifier: Programming Language :: Python :: 3.9
19
18
  Classifier: Programming Language :: Python :: 3.10
20
19
  Classifier: Programming Language :: Python :: 3.11
21
20
  Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
22
  Classifier: Topic :: Software Development :: Libraries
23
23
  Requires-Dist: click (<9)
24
24
  Requires-Dist: libcst (==1.1.0)
@@ -53,10 +53,10 @@ Description-Content-Type: text/markdown
53
53
  </p>
54
54
  <p align="center">
55
55
  <a href="https://python-poetry.org/">
56
- <img src="https://img.shields.io/badge/packaging-poetry-299bd7?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAASCAYAAABrXO8xAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJJSURBVHgBfZLPa1NBEMe/s7tNXoxW1KJQKaUHkXhQvHgW6UHQQ09CBS/6V3hKc/AP8CqCrUcpmop3Cx48eDB4yEECjVQrlZb80CRN8t6OM/teagVxYZi38+Yz853dJbzoMV3MM8cJUcLMSUKIE8AzQ2PieZzFxEJOHMOgMQQ+dUgSAckNXhapU/NMhDSWLs1B24A8sO1xrN4NECkcAC9ASkiIJc6k5TRiUDPhnyMMdhKc+Zx19l6SgyeW76BEONY9exVQMzKExGKwwPsCzza7KGSSWRWEQhyEaDXp6ZHEr416ygbiKYOd7TEWvvcQIeusHYMJGhTwF9y7sGnSwaWyFAiyoxzqW0PM/RjghPxF2pWReAowTEXnDh0xgcLs8l2YQmOrj3N7ByiqEoH0cARs4u78WgAVkoEDIDoOi3AkcLOHU60RIg5wC4ZuTC7FaHKQm8Hq1fQuSOBvX/sodmNJSB5geaF5CPIkUeecdMxieoRO5jz9bheL6/tXjrwCyX/UYBUcjCaWHljx1xiX6z9xEjkYAzbGVnB8pvLmyXm9ep+W8CmsSHQQY77Zx1zboxAV0w7ybMhQmfqdmmw3nEp1I0Z+FGO6M8LZdoyZnuzzBdjISicKRnpxzI9fPb+0oYXsNdyi+d3h9bm9MWYHFtPeIZfLwzmFDKy1ai3p+PDls1Llz4yyFpferxjnyjJDSEy9CaCx5m2cJPerq6Xm34eTrZt3PqxYO1XOwDYZrFlH1fWnpU38Y9HRze3lj0vOujZcXKuuXm3jP+s3KbZVra7y2EAAAAAASUVORK5CYII=" alt="Poetry">
56
+ <img src="https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json" alt="Poetry">
57
57
  </a>
58
- <a href="https://github.com/ambv/black">
59
- <img src="https://img.shields.io/badge/code%20style-black-000000.svg?amp;style=flat-square" alt="black">
58
+ <a href="https://github.com/astral-sh/ruff">
59
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
60
60
  </a>
61
61
  <a href="https://github.com/pre-commit/pre-commit">
62
62
  <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">
@@ -18,10 +18,10 @@
18
18
  </p>
19
19
  <p align="center">
20
20
  <a href="https://python-poetry.org/">
21
- <img src="https://img.shields.io/badge/packaging-poetry-299bd7?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAASCAYAAABrXO8xAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAJJSURBVHgBfZLPa1NBEMe/s7tNXoxW1KJQKaUHkXhQvHgW6UHQQ09CBS/6V3hKc/AP8CqCrUcpmop3Cx48eDB4yEECjVQrlZb80CRN8t6OM/teagVxYZi38+Yz853dJbzoMV3MM8cJUcLMSUKIE8AzQ2PieZzFxEJOHMOgMQQ+dUgSAckNXhapU/NMhDSWLs1B24A8sO1xrN4NECkcAC9ASkiIJc6k5TRiUDPhnyMMdhKc+Zx19l6SgyeW76BEONY9exVQMzKExGKwwPsCzza7KGSSWRWEQhyEaDXp6ZHEr416ygbiKYOd7TEWvvcQIeusHYMJGhTwF9y7sGnSwaWyFAiyoxzqW0PM/RjghPxF2pWReAowTEXnDh0xgcLs8l2YQmOrj3N7ByiqEoH0cARs4u78WgAVkoEDIDoOi3AkcLOHU60RIg5wC4ZuTC7FaHKQm8Hq1fQuSOBvX/sodmNJSB5geaF5CPIkUeecdMxieoRO5jz9bheL6/tXjrwCyX/UYBUcjCaWHljx1xiX6z9xEjkYAzbGVnB8pvLmyXm9ep+W8CmsSHQQY77Zx1zboxAV0w7ybMhQmfqdmmw3nEp1I0Z+FGO6M8LZdoyZnuzzBdjISicKRnpxzI9fPb+0oYXsNdyi+d3h9bm9MWYHFtPeIZfLwzmFDKy1ai3p+PDls1Llz4yyFpferxjnyjJDSEy9CaCx5m2cJPerq6Xm34eTrZt3PqxYO1XOwDYZrFlH1fWnpU38Y9HRze3lj0vOujZcXKuuXm3jP+s3KbZVra7y2EAAAAAASUVORK5CYII=" alt="Poetry">
21
+ <img src="https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json" alt="Poetry">
22
22
  </a>
23
- <a href="https://github.com/ambv/black">
24
- <img src="https://img.shields.io/badge/code%20style-black-000000.svg?amp;style=flat-square" alt="black">
23
+ <a href="https://github.com/astral-sh/ruff">
24
+ <img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json" alt="Ruff">
25
25
  </a>
26
26
  <a href="https://github.com/pre-commit/pre-commit">
27
27
  <img src="https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white&style=flat-square" alt="pre-commit">
@@ -1,24 +1,28 @@
1
+ [build-system]
2
+ build-backend = "poetry.core.masonry.api"
3
+ requires = [ "poetry-core>=1" ]
4
+
1
5
  [tool.poetry]
2
6
  name = "django-codemod"
3
- version = "2.1.10"
7
+ version = "2.2.0"
4
8
  description = "A command line tool to automatically fix Django deprecations."
5
- authors = ["Bruno Alla <alla.brunoo@gmail.com>"]
9
+ authors = [ "Bruno Alla <alla.brunoo@gmail.com>" ]
6
10
  license = "MIT"
7
11
  readme = "README.md"
8
- keywords = ["django", "codemod", "libCST"]
12
+ keywords = [ "django", "codemod", "libCST" ]
9
13
  repository = "https://github.com/browniebroke/django-codemod"
10
14
  documentation = "https://django-codemod.readthedocs.io"
11
15
  classifiers = [
12
- "Development Status :: 5 - Production/Stable",
13
- "Intended Audience :: Developers",
14
- "Natural Language :: English",
15
- "Operating System :: OS Independent",
16
- "Topic :: Software Development :: Libraries",
17
- "Programming Language :: Python :: 3.12",
16
+ "Development Status :: 5 - Production/Stable",
17
+ "Intended Audience :: Developers",
18
+ "Natural Language :: English",
19
+ "Operating System :: OS Independent",
20
+ "Topic :: Software Development :: Libraries",
21
+ "Programming Language :: Python :: 3.12",
18
22
  ]
19
23
  packages = [
20
- { include = "django_codemod", from = "src" },
21
- { include = "tests", format = "sdist" },
24
+ { include = "django_codemod", from = "src" },
25
+ { include = "tests", format = "sdist" },
22
26
  ]
23
27
 
24
28
  [tool.poetry.urls]
@@ -31,7 +35,7 @@ packages = [
31
35
  djcodemod = "django_codemod.cli:djcodemod"
32
36
 
33
37
  [tool.poetry.dependencies]
34
- python = "^3.8"
38
+ python = "^3.9"
35
39
  click = "<9"
36
40
  libcst = "==1.1.0"
37
41
  pathspec = ">=0.6,<1"
@@ -52,81 +56,56 @@ myst-parser = { version = ">=0.16", python = ">=3.11" }
52
56
  sphinx = { version = ">=4.0", python = ">=3.11" }
53
57
  furo = { version = ">=2023.5.20", python = ">=3.11" }
54
58
 
55
- [tool.semantic_release]
56
- version_toml = ["pyproject.toml:tool.poetry.version"]
57
- version_variables = [
58
- "src/django_codemod/__init__.py:__version__",
59
- ]
60
- build_command = "pip install poetry && poetry build"
61
-
62
- [tool.semantic_release.changelog]
63
- exclude_commit_patterns = [
64
- "chore*",
65
- "ci*",
66
- ]
67
-
68
- [tool.semantic_release.changelog.environment]
69
- keep_trailing_newline = true
70
-
71
- [tool.semantic_release.branches.main]
72
- match = "main"
73
-
74
- [tool.semantic_release.branches.noop]
75
- match = "(?!main$)"
76
- prerelease = true
77
-
78
- [tool.pytest.ini_options]
79
- addopts = "-v -Wdefault --cov=django_codemod --cov-report=term-missing:skip-covered"
80
- pythonpath = ["src"]
81
-
82
59
  [tool.ruff]
83
- target-version = "py38"
60
+ target-version = "py39"
84
61
  line-length = 88
85
- ignore = [
86
- "D203", # 1 blank line required before class docstring
87
- "D212", # Multi-line docstring summary should start at the first line
88
- "D100", # Missing docstring in public module
89
- "D101", # Missing docstring in public class
90
- "D102", # Missing docstring in public method
91
- "D104", # Missing docstring in public package
92
- "D107", # Missing docstring in `__init__`
93
- "D401", # First line of docstring should be in imperative mood
62
+
63
+ lint.select = [
64
+ "B", # flake8-bugbear
65
+ "C4", # flake8-comprehensions
66
+ "D", # flake8-docstrings
67
+ "E", # pycodestyle
68
+ "F", # pyflake
69
+ "I", # isort
70
+ "RUF", # ruff specific
71
+ "S", # flake8-bandit
72
+ "UP", # pyupgrade
73
+ "W", # pycodestyle
94
74
  ]
95
- select = [
96
- "B", # flake8-bugbear
97
- "D", # flake8-docstrings
98
- "C4", # flake8-comprehensions
99
- "S", # flake8-bandit
100
- "F", # pyflake
101
- "E", # pycodestyle
102
- "W", # pycodestyle
103
- "UP", # pyupgrade
104
- "I", # isort
105
- "RUF", # ruff specific
75
+ lint.ignore = [
76
+ "D100", # Missing docstring in public module
77
+ "D101", # Missing docstring in public class
78
+ "D102", # Missing docstring in public method
79
+ "D104", # Missing docstring in public package
80
+ "D107", # Missing docstring in `__init__`
81
+ "D203", # 1 blank line required before class docstring
82
+ "D212", # Multi-line docstring summary should start at the first line
83
+ "D401", # First line of docstring should be in imperative mood
106
84
  ]
107
- [tool.ruff.per-file-ignores]
108
- "tests/**/*" = [
109
- "D100",
110
- "D101",
111
- "D102",
112
- "D103",
113
- "D104",
114
- "S101",
85
+ lint.per-file-ignores."conftest.py" = [ "D100" ]
86
+ lint.per-file-ignores."docs/conf.py" = [ "D100" ]
87
+ lint.per-file-ignores."tests/**/*" = [
88
+ "D100",
89
+ "D101",
90
+ "D102",
91
+ "D103",
92
+ "D104",
93
+ "S101",
115
94
  ]
116
- "conftest.py" = ["D100"]
117
- "docs/conf.py" = ["D100"]
95
+ lint.isort.known-first-party = [ "django_codemod", "tests" ]
118
96
 
119
- [tool.ruff.isort]
120
- known-first-party = ["django_codemod", "tests"]
97
+ [tool.pytest.ini_options]
98
+ addopts = "-v -Wdefault --cov=django_codemod --cov-report=term-missing:skip-covered"
99
+ pythonpath = [ "src" ]
121
100
 
122
101
  [tool.coverage.run]
123
102
  branch = true
124
103
 
125
104
  [tool.coverage.report]
126
105
  exclude_lines = [
127
- "pragma: no cover",
128
- "raise AssertionError",
129
- "raise NotImplementedError",
106
+ "pragma: no cover",
107
+ "raise AssertionError",
108
+ "raise NotImplementedError",
130
109
  ]
131
110
 
132
111
  [tool.mypy]
@@ -140,6 +119,26 @@ warn_no_return = true
140
119
 
141
120
  show_error_codes = true
142
121
 
143
- [build-system]
144
- requires = ["poetry-core>=1.0.0"]
145
- build-backend = "poetry.core.masonry.api"
122
+ [tool.semantic_release]
123
+ version_toml = [ "pyproject.toml:tool.poetry.version" ]
124
+ version_variables = [
125
+ "src/django_codemod/__init__.py:__version__",
126
+ ]
127
+ build_command = "pip install poetry && poetry build"
128
+
129
+ [tool.semantic_release.changelog]
130
+ exclude_commit_patterns = [
131
+ "chore.*",
132
+ "ci.*",
133
+ "Merge pull request .*",
134
+ ]
135
+
136
+ [tool.semantic_release.changelog.environment]
137
+ keep_trailing_newline = true
138
+
139
+ [tool.semantic_release.branches.main]
140
+ match = "main"
141
+
142
+ [tool.semantic_release.branches.noop]
143
+ match = "(?!main$)"
144
+ prerelease = true
@@ -0,0 +1 @@
1
+ __version__ = "2.2.0"
@@ -1,8 +1,9 @@
1
1
  import inspect
2
2
  from collections import defaultdict
3
+ from collections.abc import Generator
3
4
  from operator import attrgetter
4
5
  from pathlib import Path
5
- from typing import Callable, Dict, Generator, List, Optional, Tuple, Type
6
+ from typing import Callable, Optional
6
7
 
7
8
  import rich_click as click
8
9
  from libcst.codemod import CodemodContext, parallel_exec_transform_with_prettyprint
@@ -16,7 +17,7 @@ from django_codemod.path_utils import get_sources
16
17
  from django_codemod.visitors.base import BaseDjCodemodTransformer
17
18
 
18
19
 
19
- def index_codemodders(version_getter: Callable) -> Dict[Tuple[int, int], List]:
20
+ def index_codemodders(version_getter: Callable) -> dict[tuple[int, int], list]:
20
21
  """
21
22
  Index codemodders by version.
22
23
 
@@ -29,7 +30,7 @@ def index_codemodders(version_getter: Callable) -> Dict[Tuple[int, int], List]:
29
30
  return dict(codemodders_index)
30
31
 
31
32
 
32
- def iter_codemodders() -> Generator[Type[BaseDjCodemodTransformer], None, None]:
33
+ def iter_codemodders() -> Generator[type[BaseDjCodemodTransformer], None, None]:
33
34
  """Iterator of all the codemodders classes."""
34
35
  for object_name in dir(visitors):
35
36
  try:
@@ -61,15 +62,15 @@ class VersionParamType(click.ParamType):
61
62
  " e.g. '2.2' or '2.2.10'"
62
63
  )
63
64
 
64
- def __init__(self, version_index: Dict[Tuple[int, int], List]) -> None:
65
- self.valid_versions: List[Tuple[int, int]] = list(version_index.keys())
65
+ def __init__(self, version_index: dict[tuple[int, int], list]) -> None:
66
+ self.valid_versions: list[tuple[int, int]] = list(version_index.keys())
66
67
 
67
68
  def convert( # type: ignore[return]
68
69
  self,
69
70
  value: str,
70
71
  param: Optional[click.Parameter],
71
72
  ctx: Optional[click.Context],
72
- ) -> Tuple[int, int]:
73
+ ) -> tuple[int, int]:
73
74
  """Parse version to keep only major an minor digits."""
74
75
  try:
75
76
  return self._parse_unsafe(value, param, ctx)
@@ -85,7 +86,7 @@ class VersionParamType(click.ParamType):
85
86
  value: str,
86
87
  param: Optional[click.Parameter],
87
88
  ctx: Optional[click.Context],
88
- ) -> Tuple[int, int]:
89
+ ) -> tuple[int, int]:
89
90
  """Parse version and validate it's a supported one."""
90
91
  parsed_version = self._split_digits(value, param, ctx)
91
92
  if parsed_version not in self.valid_versions:
@@ -106,7 +107,7 @@ class VersionParamType(click.ParamType):
106
107
  value: str,
107
108
  param: Optional[click.Parameter],
108
109
  ctx: Optional[click.Context],
109
- ) -> Tuple[int, int]:
110
+ ) -> tuple[int, int]:
110
111
  """Split version into 2-tuple of digits, ignoring patch digit."""
111
112
  values_parts = tuple(int(v) for v in value.split("."))
112
113
  if len(values_parts) < 2:
@@ -155,10 +156,10 @@ def djcodemod():
155
156
  multiple=True,
156
157
  )
157
158
  def run(
158
- removed_in: List[Tuple[int, int]],
159
- deprecated_in: List[Tuple[int, int]],
160
- codemod: List[str],
161
- src: Tuple[str, ...],
159
+ removed_in: list[tuple[int, int]],
160
+ deprecated_in: list[tuple[int, int]],
161
+ codemod: list[str],
162
+ src: tuple[str, ...],
162
163
  ) -> None:
163
164
  """
164
165
  Automatically fixes deprecations removed Django deprecations.
@@ -185,7 +186,7 @@ def run(
185
186
  call_command(command_instance, files)
186
187
 
187
188
 
188
- def call_command(command_instance: BaseCodemodCommand, files: List[Path]):
189
+ def call_command(command_instance: BaseCodemodCommand, files: list[Path]):
189
190
  """Call libCST with our customized command."""
190
191
  try:
191
192
  # Super simplified call
@@ -228,7 +229,7 @@ def list_() -> None:
228
229
  console.print(table)
229
230
 
230
231
 
231
- def generate_rows() -> Generator[Tuple[str, str, str, str], None, None]:
232
+ def generate_rows() -> Generator[tuple[str, str, str, str], None, None]:
232
233
  """Build up the rows for the table of codemodders."""
233
234
  codemodders_list = sorted(
234
235
  iter_codemodders(), key=lambda obj: (obj.deprecated_in, obj.removed_in)
@@ -242,7 +243,7 @@ def generate_rows() -> Generator[Tuple[str, str, str, str], None, None]:
242
243
  )
243
244
 
244
245
 
245
- def get_short_description(codemodder: Type[BaseDjCodemodTransformer]) -> str:
246
+ def get_short_description(codemodder: type[BaseDjCodemodTransformer]) -> str:
246
247
  """Get a one line description of the codemodder from its docstring."""
247
248
  if codemodder.__doc__ is None:
248
249
  return ""
@@ -252,6 +253,6 @@ def get_short_description(codemodder: Type[BaseDjCodemodTransformer]) -> str:
252
253
  return ""
253
254
 
254
255
 
255
- def version_str(version_parts: Tuple[int, int]) -> str:
256
+ def version_str(version_parts: tuple[int, int]) -> str:
256
257
  """Format the version tuple as string."""
257
258
  return ".".join(str(d) for d in version_parts)
@@ -1,5 +1,4 @@
1
1
  from abc import ABC
2
- from typing import List, Type
3
2
 
4
3
  import libcst as cst
5
4
  from libcst.codemod import (
@@ -12,7 +11,7 @@ from libcst.codemod import (
12
11
  class BaseCodemodCommand(VisitorBasedCodemodCommand, ABC):
13
12
  """Base class for our commands."""
14
13
 
15
- transformers: List[Type[ContextAwareTransformer]]
14
+ transformers: list[type[ContextAwareTransformer]]
16
15
 
17
16
  def __init__(self, transformers, context: CodemodContext) -> None:
18
17
  self.transformers = transformers
@@ -5,13 +5,14 @@ Inspired or taken from black:
5
5
  https://github.com/psf/black
6
6
  """
7
7
 
8
+ from collections.abc import Iterable, Iterator
8
9
  from pathlib import Path
9
- from typing import Iterable, Iterator, List, Optional, Set
10
+ from typing import Optional
10
11
 
11
12
  from pathspec import PathSpec
12
13
 
13
14
 
14
- def get_sources(src: Iterable[str]) -> List[Path]:
15
+ def get_sources(src: Iterable[str]) -> list[Path]:
15
16
  """
16
17
  Return a list of sources to codemod.
17
18
 
@@ -20,7 +21,7 @@ def get_sources(src: Iterable[str]) -> List[Path]:
20
21
  """
21
22
  root = find_project_root(src)
22
23
  gitignore = get_gitignore(root)
23
- sources: Set[Path] = set()
24
+ sources: set[Path] = set()
24
25
  for s in src:
25
26
  p = Path(s)
26
27
  paths: Iterable[Path] = []
@@ -75,7 +76,7 @@ def find_project_root(sources: Iterable[str]) -> Path:
75
76
  def get_gitignore(root: Path) -> PathSpec:
76
77
  """Return a PathSpec matching gitignore content if present."""
77
78
  gitignore = root / ".gitignore"
78
- lines: List[str] = []
79
+ lines: list[str] = []
79
80
  if gitignore.is_file():
80
81
  with gitignore.open() as gf:
81
82
  lines = gf.readlines()
@@ -1,4 +1,5 @@
1
- from typing import Optional, Sequence
1
+ from collections.abc import Sequence
2
+ from typing import Optional
2
3
 
3
4
  from libcst import Arg, Call, FunctionDef, Param, parse_expression, parse_statement
4
5
  from libcst import matchers as m
@@ -1,7 +1,8 @@
1
1
  """Module to implement base functionality."""
2
2
 
3
3
  from abc import ABC
4
- from typing import List, Optional, Sequence, Tuple, Union
4
+ from collections.abc import Sequence
5
+ from typing import Optional, Union
5
6
 
6
7
  from libcst import (
7
8
  Arg,
@@ -46,8 +47,8 @@ class IsTryImportProvider(BatchableMetadataProvider[bool]):
46
47
 
47
48
 
48
49
  class BaseDjCodemodTransformer(ContextAwareTransformer, ABC):
49
- deprecated_in: Tuple[int, int]
50
- removed_in: Tuple[int, int]
50
+ deprecated_in: tuple[int, int]
51
+ removed_in: tuple[int, int]
51
52
 
52
53
 
53
54
  def module_matcher(
@@ -334,8 +335,8 @@ class BaseRenameTransformer(BaseDjCodemodTransformer, ABC):
334
335
 
335
336
 
336
337
  def clean_new_import_aliases(
337
- import_aliases: List[ImportAlias],
338
- ) -> List[ImportAlias]:
338
+ import_aliases: list[ImportAlias],
339
+ ) -> list[ImportAlias]:
339
340
  """Clean up a list of import aliases."""
340
341
  # Sort them
341
342
  cleaned_import_aliases = sorted(import_aliases, key=lambda n: n.evaluated_name)
@@ -1,4 +1,4 @@
1
- from typing import Sequence
1
+ from collections.abc import Sequence
2
2
 
3
3
  from libcst import Arg, Call, Integer
4
4
 
@@ -1,4 +1,5 @@
1
- from typing import Optional, Sequence, Union
1
+ from collections.abc import Sequence
2
+ from typing import Optional, Union
2
3
 
3
4
  from libcst import (
4
5
  Arg,
@@ -139,7 +140,8 @@ class ModelsPermalinkTransformer(BaseDjCodemodTransformer):
139
140
  BaseSmallStatement, FlattenSentinel[BaseSmallStatement], RemovalSentinel
140
141
  ]:
141
142
  if self.visiting_permalink_method and m.matches(
142
- updated_node.value, m.Tuple() # type: ignore
143
+ updated_node.value,
144
+ m.Tuple(), # type: ignore
143
145
  ):
144
146
  elem_0, *elem_1_3 = updated_node.value.elements[:3] # type: ignore
145
147
  args = (
@@ -1,4 +1,4 @@
1
- from typing import Sequence
1
+ from collections.abc import Sequence
2
2
 
3
3
  from libcst import Arg, Call, Name
4
4
 
@@ -1,4 +1,4 @@
1
- from typing import ClassVar, List, Optional
1
+ from typing import ClassVar, Optional
2
2
 
3
3
  from libcst import BaseExpression, Call, ImportFrom, ImportStar, MaybeSentinel, Module
4
4
  from libcst import matchers as m
@@ -15,7 +15,7 @@ class SignalDisconnectWeakTransformer(BaseDjCodemodTransformer):
15
15
 
16
16
  ctx_key_prefix = "SignalDisconnectWeakTransformer"
17
17
  ctx_key_call_matchers = f"{ctx_key_prefix}-call_matchers"
18
- builtin_signals: ClassVar[List[str]] = [
18
+ builtin_signals: ClassVar[list[str]] = [
19
19
  "pre_init",
20
20
  "post_init",
21
21
  "pre_save",
@@ -31,7 +31,7 @@ class SignalDisconnectWeakTransformer(BaseDjCodemodTransformer):
31
31
  )
32
32
 
33
33
  @property
34
- def disconnect_call_matchers(self) -> List[m.Call]:
34
+ def disconnect_call_matchers(self) -> list[m.Call]:
35
35
  return self.context.scratch.get(self.ctx_key_call_matchers, [])
36
36
 
37
37
  def add_disconnect_call_matcher(self, call_matcher: m.Call) -> None:
@@ -1,4 +1,5 @@
1
- from typing import Generator, Optional, Sequence, Union
1
+ from collections.abc import Generator, Sequence
2
+ from typing import Optional, Union
2
3
 
3
4
  from libcst import (
4
5
  Assign,
@@ -1,4 +1,4 @@
1
- from typing import Sequence
1
+ from collections.abc import Sequence
2
2
 
3
3
  from libcst import Arg, Call, Integer, parse_expression
4
4
  from libcst.codemod.visitors import AddImportsVisitor
@@ -1,4 +1,4 @@
1
- from typing import Sequence, Tuple
1
+ from collections.abc import Sequence
2
2
 
3
3
  from libcst import Arg, BaseExpression, Call, Name, SimpleString
4
4
  from libcst import matchers as m
@@ -85,7 +85,7 @@ class URLTransformer(BaseFuncRenameTransformer):
85
85
  return route
86
86
 
87
87
  @staticmethod
88
- def parse_next_group(left_to_parse: str) -> Tuple[str, str]:
88
+ def parse_next_group(left_to_parse: str) -> tuple[str, str]:
89
89
  """Extract captured group info."""
90
90
  prefix, rest = left_to_parse.split("(?P<", 1)
91
91
  group, left_to_parse = rest.split(")", 1)
@@ -1,5 +1,3 @@
1
- from typing import Type
2
-
3
1
  from libcst.codemod import CodemodTest
4
2
 
5
3
  from django_codemod.commands import BaseCodemodCommand
@@ -9,7 +7,7 @@ from django_codemod.visitors.base import BaseDjCodemodTransformer
9
7
  class BaseVisitorTest(CodemodTest):
10
8
  """Base test to use in all visitors tests."""
11
9
 
12
- transformer: Type[BaseDjCodemodTransformer]
10
+ transformer: type[BaseDjCodemodTransformer]
13
11
 
14
12
  def TRANSFORM(self, context):
15
13
  """Create a command for the transformer under test."""
@@ -19,9 +19,7 @@ class TestInlineHasAddPermissionsTransformer(BaseVisitorTest):
19
19
  ]
20
20
  )
21
21
  def test_noop_import_star(self, import_line: str, base_class: str) -> None:
22
- before = (
23
- after
24
- ) = f"""
22
+ before = after = f"""
25
23
  {import_line}
26
24
 
27
25
  class MyInlineInline(InlineMixin, {base_class}):
@@ -35,9 +33,7 @@ class TestInlineHasAddPermissionsTransformer(BaseVisitorTest):
35
33
 
36
34
  def test_model_admin_base_class(self) -> None:
37
35
  """Doesn't modify if base class doesn't match."""
38
- before = (
39
- after
40
- ) = """
36
+ before = after = """
41
37
  from django.contrib import admin
42
38
 
43
39
  class MyAdmin(admin.ModelAdmin):
@@ -51,9 +47,7 @@ class TestInlineHasAddPermissionsTransformer(BaseVisitorTest):
51
47
 
52
48
  def test_no_base_class(self) -> None:
53
49
  """Doesn't modify if there is no base class."""
54
- before = (
55
- after
56
- ) = """
50
+ before = after = """
57
51
  from django.contrib import admin
58
52
 
59
53
  class MyCustomStuff:
@@ -278,9 +278,7 @@ class TestFuncRenameTransformer(BaseVisitorTest):
278
278
  self.assertCodemod(before, after)
279
279
 
280
280
  def test_avoid_try_import(self) -> None:
281
- before = (
282
- after
283
- ) = """
281
+ before = after = """
284
282
  try:
285
283
  from django.dummy.module import func
286
284
  except:
@@ -293,9 +291,7 @@ class TestFuncRenameTransformer(BaseVisitorTest):
293
291
 
294
292
  @pytest.mark.usefixtures("parent_module_import_enabled")
295
293
  def test_avoid_try_import_parent(self) -> None:
296
- before = (
297
- after
298
- ) = """
294
+ before = after = """
299
295
  try:
300
296
  from django.dummy import module
301
297
  except:
@@ -308,9 +304,7 @@ class TestFuncRenameTransformer(BaseVisitorTest):
308
304
 
309
305
  @pytest.mark.usefixtures("parent_module_import_enabled")
310
306
  def test_parent_import_star(self) -> None:
311
- before = (
312
- after
313
- ) = """
307
+ before = after = """
314
308
  from django.dummy import *
315
309
 
316
310
  result = module.func()
@@ -319,9 +313,7 @@ class TestFuncRenameTransformer(BaseVisitorTest):
319
313
 
320
314
  @pytest.mark.usefixtures("parent_module_import_enabled")
321
315
  def test_parent_import_not_matches(self) -> None:
322
- before = (
323
- after
324
- ) = """
316
+ before = after = """
325
317
  from django.ymmud import other_module
326
318
 
327
319
  result = other_module.other_func()
@@ -415,9 +407,7 @@ class TestOtherModuleFuncRenameTransformer(BaseVisitorTest):
415
407
  @pytest.mark.usefixtures("parent_module_import_enabled")
416
408
  def test_parent_module_noop(self) -> None:
417
409
  """Parent module imported, but other function used."""
418
- before = (
419
- after
420
- ) = """
410
+ before = after = """
421
411
  from django.dummy import module
422
412
 
423
413
  result = module.other_func()
@@ -476,9 +466,7 @@ class TestModuleRenameTransformer(BaseVisitorTest):
476
466
  self.assertCodemod(before, after)
477
467
 
478
468
  def test_avoid_try_import(self) -> None:
479
- before = (
480
- after
481
- ) = """
469
+ before = after = """
482
470
  try:
483
471
  from django.dummy.module import func
484
472
  except:
@@ -102,9 +102,7 @@ class TestHttpRequestXReadLinesTransformer(BaseVisitorTest):
102
102
 
103
103
  def test_noop_wrong_name(self) -> None:
104
104
  """Don't replace calls for name other than `request` or `req`."""
105
- before = (
106
- after
107
- ) = """
105
+ before = after = """
108
106
  for line in r.xreadlines():
109
107
  print(line)
110
108
  """
@@ -112,9 +110,7 @@ class TestHttpRequestXReadLinesTransformer(BaseVisitorTest):
112
110
 
113
111
  def test_noop_function_call(self) -> None:
114
112
  """Don't replace calls for name other than `request` or `req`."""
115
- before = (
116
- after
117
- ) = """
113
+ before = after = """
118
114
  for line in xreadlines(r):
119
115
  print(line)
120
116
  """
@@ -173,9 +169,7 @@ class TestCookieDateTransformer(BaseVisitorTest):
173
169
  transformer = CookieDateTransformer
174
170
 
175
171
  def test_noop(self):
176
- before = (
177
- after
178
- ) = """
172
+ before = after = """
179
173
  from django.utils.http import http_date
180
174
 
181
175
  http_date(12345)
@@ -218,9 +218,7 @@ class TestAvailableAttrsTransformer(BaseVisitorTest):
218
218
  )
219
219
  def test_noop_import_star(self, import_str: str) -> None:
220
220
  """Should not try to replace if import star is used."""
221
- before = (
222
- after
223
- ) = f"""
221
+ before = after = f"""
224
222
  {import_str}
225
223
 
226
224
  class MyModel(models.Model):
@@ -352,9 +350,7 @@ class TestNullBooleanFieldTransformer(BaseVisitorTest):
352
350
  transformer = NullBooleanFieldTransformer
353
351
 
354
352
  def test_noop_models(self) -> None:
355
- before = (
356
- after
357
- ) = """
353
+ before = after = """
358
354
  from django.db import models
359
355
 
360
356
  class MyThing(models.Model):
@@ -363,9 +359,7 @@ class TestNullBooleanFieldTransformer(BaseVisitorTest):
363
359
  self.assertCodemod(before, after)
364
360
 
365
361
  def test_noop_fields(self) -> None:
366
- before = (
367
- after
368
- ) = """
362
+ before = after = """
369
363
  from django.db.models import BooleanField, Model
370
364
 
371
365
  class MyThing(Model):
@@ -7,9 +7,7 @@ class TestQuerySetPaginatorTransformer(BaseVisitorTest):
7
7
 
8
8
  def test_noop(self) -> None:
9
9
  """Test when nothing should change."""
10
- before = (
11
- after
12
- ) = """
10
+ before = after = """
13
11
  from django.core.paginator import Paginator
14
12
 
15
13
  paginator_instance = Paginator([], 5)
@@ -11,9 +11,7 @@ class TestFloatRangeModelFieldTransformer(BaseVisitorTest):
11
11
 
12
12
  def test_noop(self) -> None:
13
13
  """Test when nothing should change."""
14
- before = (
15
- after
16
- ) = """
14
+ before = after = """
17
15
  from django.contrib.postgres.fields import DecimalRangeField
18
16
 
19
17
  some_range = DecimalRangeField()
@@ -42,9 +40,7 @@ class TestFloatRangeFormFieldTransformer(BaseVisitorTest):
42
40
 
43
41
  def test_noop(self) -> None:
44
42
  """Test when nothing should change."""
45
- before = (
46
- after
47
- ) = """
43
+ before = after = """
48
44
  from django.contrib.postgres.forms import DecimalRangeField
49
45
 
50
46
  some_range = DecimalRangeField()
@@ -73,9 +69,7 @@ class TestJSONModelFieldTransformer(BaseVisitorTest):
73
69
 
74
70
  def test_noop(self) -> None:
75
71
  """Test when nothing should change."""
76
- before = (
77
- after
78
- ) = """
72
+ before = after = """
79
73
  from django.db.models import JSONField
80
74
 
81
75
  field = JSONField()
@@ -24,9 +24,7 @@ class TestSignalDisconnectWeakTransformer(BaseVisitorTest):
24
24
 
25
25
  @parameterized.expand(DJANGO_SIGNAL_NAMES)
26
26
  def test_noop(self, signal_name):
27
- before = (
28
- after
29
- ) = f"""
27
+ before = after = f"""
30
28
  from django.db.models.signals import {signal_name}
31
29
 
32
30
  {signal_name}.disconnect(
@@ -40,9 +38,7 @@ class TestSignalDisconnectWeakTransformer(BaseVisitorTest):
40
38
 
41
39
  @parameterized.expand(DJANGO_SIGNAL_NAMES)
42
40
  def test_noop_import_star(self, signal_name):
43
- before = (
44
- after
45
- ) = f"""
41
+ before = after = f"""
46
42
  from django.db.models.signals import *
47
43
 
48
44
  {signal_name}.disconnect(receiver=some_handler, sender=MyModel, weak=True)
@@ -9,9 +9,7 @@ class TestAssignmentTagTransformer(BaseVisitorTest):
9
9
 
10
10
  def test_noop(self) -> None:
11
11
  """Test when nothing should change."""
12
- before = (
13
- after
14
- ) = """
12
+ before = after = """
15
13
  from django import template
16
14
 
17
15
  register = template.Library()
@@ -32,9 +30,7 @@ class TestAssignmentTagTransformer(BaseVisitorTest):
32
30
  )
33
31
  def test_noop_not_imported(self, import_line: str) -> None:
34
32
  """Test when import is missing."""
35
- before = (
36
- after
37
- ) = f"""
33
+ before = after = f"""
38
34
  {import_line}
39
35
 
40
36
  @register.assignment_tag
@@ -46,9 +42,7 @@ class TestAssignmentTagTransformer(BaseVisitorTest):
46
42
 
47
43
  def test_noop_import_star(self) -> None:
48
44
  """Test when imported as star import."""
49
- before = (
50
- after
51
- ) = """
45
+ before = after = """
52
46
  from django import *
53
47
 
54
48
  register = template.Library()
@@ -138,9 +132,7 @@ class TestAssignmentTagTransformer(BaseVisitorTest):
138
132
 
139
133
  def test_noop_content_star_import(self) -> None:
140
134
  """Test when Library class is imported as star import."""
141
- before = (
142
- after
143
- ) = """
135
+ before = after = """
144
136
  from django.template import *
145
137
 
146
138
  register = Library()
@@ -7,9 +7,7 @@ class TestFixedOffsetTransformer(BaseVisitorTest):
7
7
 
8
8
  def test_noop(self) -> None:
9
9
  """Test when nothing should change."""
10
- before = (
11
- after
12
- ) = """
10
+ before = after = """
13
11
  from datetime import timedelta, timezone
14
12
 
15
13
  timezone(offset=timedelta(minutes=60))
@@ -78,9 +76,7 @@ class TestFixedOffsetTransformer(BaseVisitorTest):
78
76
  self.assertCodemod(before, after)
79
77
 
80
78
  def test_issue_421(self) -> None:
81
- before = (
82
- after
83
- ) = """
79
+ before = after = """
84
80
  from django.utils import timezone
85
81
 
86
82
  now = timezone.now()
@@ -1 +0,0 @@
1
- __version__ = "2.1.10"
File without changes