django-codemod 2.0.0__tar.gz → 2.1.1__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.
- {django_codemod-2.0.0 → django_codemod-2.1.1}/PKG-INFO +2 -1
- {django_codemod-2.0.0 → django_codemod-2.1.1}/pyproject.toml +52 -6
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/cli.py +3 -4
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/path_utils.py +8 -4
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/utils/calls.py +6 -8
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/admin.py +1 -1
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/base.py +15 -21
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/crypto.py +1 -1
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/exceptions.py +1 -4
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/models.py +5 -5
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/signals.py +7 -6
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/urls.py +3 -3
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/test_cli.py +8 -6
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_models.py +2 -2
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_signals.py +5 -1
- {django_codemod-2.0.0 → django_codemod-2.1.1}/LICENSE +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/README.md +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/__init__.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/commands.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/constants.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/feature_flags.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/utils/__init__.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/__init__.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/core.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/decorators.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/encoding.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/forms.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/html.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/http.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/lru_cache.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/os_utils.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/paginator.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/postgres_fields.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/shortcuts.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/template_context.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/template_tags.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/timezone.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/translations.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/__init__.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/test_e2e.sh +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/test_path_utils.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/__init__.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/base.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_admin.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_base.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_core.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_crypto.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_decorators.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_encoding.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_exceptions.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_forms.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_html.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_http.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_lru_cache.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_os_utils.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_paginator.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_postgres_fields.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_shortcuts.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_template_context.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_template_tags.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_timezone.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_translations.py +0 -0
- {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_urls.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: django-codemod
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.1
|
|
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
|
|
@@ -18,6 +18,7 @@ Classifier: Programming Language :: Python :: 3.8
|
|
|
18
18
|
Classifier: Programming Language :: Python :: 3.9
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.10
|
|
20
20
|
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
22
|
Classifier: Topic :: Software Development :: Libraries
|
|
22
23
|
Requires-Dist: click (<9)
|
|
23
24
|
Requires-Dist: libcst (==1.0.1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "django-codemod"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.1.1"
|
|
4
4
|
description = "A command line tool to automatically fix Django deprecations."
|
|
5
5
|
authors = ["Bruno Alla <alla.brunoo@gmail.com>"]
|
|
6
6
|
license = "MIT"
|
|
@@ -14,6 +14,7 @@ classifiers = [
|
|
|
14
14
|
"Natural Language :: English",
|
|
15
15
|
"Operating System :: OS Independent",
|
|
16
16
|
"Topic :: Software Development :: Libraries",
|
|
17
|
+
"Programming Language :: Python :: 3.12",
|
|
17
18
|
]
|
|
18
19
|
packages = [
|
|
19
20
|
{ include = "django_codemod", from = "src" },
|
|
@@ -49,21 +50,66 @@ optional = true
|
|
|
49
50
|
[tool.poetry.group.docs.dependencies]
|
|
50
51
|
myst-parser = ">=0.16"
|
|
51
52
|
sphinx = ">=4.0"
|
|
52
|
-
|
|
53
|
+
furo = ">=2023.5.20"
|
|
53
54
|
|
|
54
55
|
[tool.semantic_release]
|
|
55
56
|
branch = "main"
|
|
56
|
-
version_toml = "pyproject.toml:tool.poetry.version"
|
|
57
|
+
version_toml = ["pyproject.toml:tool.poetry.version"]
|
|
57
58
|
version_variable = "src/django_codemod/__init__.py:__version__"
|
|
58
59
|
build_command = "pip install poetry && poetry build"
|
|
59
60
|
|
|
61
|
+
[tool.semantic_release.changelog]
|
|
62
|
+
exclude_commit_patterns = [
|
|
63
|
+
"chore*",
|
|
64
|
+
"ci*",
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
[tool.semantic_release.changelog.environment]
|
|
68
|
+
keep_trailing_newline = true
|
|
69
|
+
|
|
60
70
|
[tool.pytest.ini_options]
|
|
61
71
|
addopts = "-v -Wdefault --cov=django_codemod --cov-report=term-missing:skip-covered"
|
|
62
72
|
pythonpath = ["src"]
|
|
63
73
|
|
|
64
|
-
[tool.
|
|
65
|
-
|
|
66
|
-
|
|
74
|
+
[tool.ruff]
|
|
75
|
+
target-version = "py38"
|
|
76
|
+
line-length = 88
|
|
77
|
+
ignore = [
|
|
78
|
+
"D203", # 1 blank line required before class docstring
|
|
79
|
+
"D212", # Multi-line docstring summary should start at the first line
|
|
80
|
+
"D100", # Missing docstring in public module
|
|
81
|
+
"D101", # Missing docstring in public class
|
|
82
|
+
"D102", # Missing docstring in public method
|
|
83
|
+
"D104", # Missing docstring in public package
|
|
84
|
+
"D107", # Missing docstring in `__init__`
|
|
85
|
+
"D401", # First line of docstring should be in imperative mood
|
|
86
|
+
]
|
|
87
|
+
select = [
|
|
88
|
+
"B", # flake8-bugbear
|
|
89
|
+
"D", # flake8-docstrings
|
|
90
|
+
"C4", # flake8-comprehensions
|
|
91
|
+
"S", # flake8-bandit
|
|
92
|
+
"F", # pyflake
|
|
93
|
+
"E", # pycodestyle
|
|
94
|
+
"W", # pycodestyle
|
|
95
|
+
"UP", # pyupgrade
|
|
96
|
+
"I", # isort
|
|
97
|
+
"RUF", # ruff specific
|
|
98
|
+
]
|
|
99
|
+
[tool.ruff.per-file-ignores]
|
|
100
|
+
"tests/**/*" = [
|
|
101
|
+
"D100",
|
|
102
|
+
"D101",
|
|
103
|
+
"D102",
|
|
104
|
+
"D103",
|
|
105
|
+
"D104",
|
|
106
|
+
"S101",
|
|
107
|
+
]
|
|
108
|
+
"conftest.py" = ["D100"]
|
|
109
|
+
"docs/conf.py" = ["D100"]
|
|
110
|
+
|
|
111
|
+
[tool.ruff.isort]
|
|
112
|
+
known-first-party = ["django_codemod", "tests"]
|
|
67
113
|
|
|
68
114
|
[tool.coverage.run]
|
|
69
115
|
branch = true
|
|
@@ -193,8 +193,8 @@ def call_command(command_instance: BaseCodemodCommand, files: List[Path]):
|
|
|
193
193
|
command_instance,
|
|
194
194
|
files, # type: ignore
|
|
195
195
|
)
|
|
196
|
-
except KeyboardInterrupt:
|
|
197
|
-
raise click.Abort("Interrupted!")
|
|
196
|
+
except KeyboardInterrupt as exc:
|
|
197
|
+
raise click.Abort("Interrupted!") from exc
|
|
198
198
|
|
|
199
199
|
# fancy summary a-la libCST
|
|
200
200
|
total = result.successes + result.skips + result.failures
|
|
@@ -247,8 +247,7 @@ def get_short_description(codemodder: Type[BaseDjCodemodTransformer]) -> str:
|
|
|
247
247
|
if codemodder.__doc__ is None:
|
|
248
248
|
return ""
|
|
249
249
|
for line in codemodder.__doc__.split("\n"):
|
|
250
|
-
description
|
|
251
|
-
if description:
|
|
250
|
+
if description := line.strip():
|
|
252
251
|
return description
|
|
253
252
|
return ""
|
|
254
253
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""
|
|
2
|
+
Some utilities to deal with files.
|
|
2
3
|
|
|
3
4
|
Inspired or taken from black:
|
|
4
5
|
https://github.com/psf/black
|
|
@@ -10,7 +11,8 @@ from pathspec import PathSpec
|
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def get_sources(src: Iterable[str]) -> List[Path]:
|
|
13
|
-
"""
|
|
14
|
+
"""
|
|
15
|
+
Return a list of sources to codemod.
|
|
14
16
|
|
|
15
17
|
Based on a list of paths or files, recursively find python source files,
|
|
16
18
|
ignoring the ones according to `.gitignore`.
|
|
@@ -31,7 +33,8 @@ def get_sources(src: Iterable[str]) -> List[Path]:
|
|
|
31
33
|
|
|
32
34
|
|
|
33
35
|
def find_project_root(sources: Iterable[str]) -> Path:
|
|
34
|
-
"""
|
|
36
|
+
"""
|
|
37
|
+
Return a directory containing .git, .hg, or pyproject.toml.
|
|
35
38
|
|
|
36
39
|
That directory will be a common parent of all files and directories
|
|
37
40
|
passed in `sources`.
|
|
@@ -83,7 +86,8 @@ def gen_python_files(
|
|
|
83
86
|
root: Path,
|
|
84
87
|
gitignore: PathSpec,
|
|
85
88
|
) -> Iterator[Path]:
|
|
86
|
-
"""
|
|
89
|
+
"""
|
|
90
|
+
Generate all files under `paths`.
|
|
87
91
|
|
|
88
92
|
Files listed in .gitignore are not considered.
|
|
89
93
|
"""
|
|
@@ -1,21 +1,18 @@
|
|
|
1
1
|
from typing import Optional, Sequence
|
|
2
2
|
|
|
3
|
-
from libcst import Arg, Call, FunctionDef, Param
|
|
3
|
+
from libcst import Arg, Call, FunctionDef, Param, parse_expression, parse_statement
|
|
4
4
|
from libcst import matchers as m
|
|
5
|
-
from libcst import parse_expression, parse_statement
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
def find_keyword_arg(args: Sequence[Arg], keyword_name: str) -> Optional[Arg]:
|
|
9
8
|
"""Find a kwarg among a sequence of arguments."""
|
|
10
9
|
matcher = m.Arg(keyword=m.Name(keyword_name))
|
|
11
|
-
for arg in args
|
|
12
|
-
if m.matches(arg, matcher):
|
|
13
|
-
return arg
|
|
14
|
-
return None
|
|
10
|
+
return next((arg for arg in args if m.matches(arg, matcher)), None)
|
|
15
11
|
|
|
16
12
|
|
|
17
13
|
def parse_arg(arg_str: str) -> Arg:
|
|
18
|
-
"""
|
|
14
|
+
"""
|
|
15
|
+
Build a `Arg` instance based on its string representation.
|
|
19
16
|
|
|
20
17
|
Instantiating it from scratch is cumbersome, this helper generates a
|
|
21
18
|
function call with the given argument and extract it from the tree.
|
|
@@ -27,7 +24,8 @@ def parse_arg(arg_str: str) -> Arg:
|
|
|
27
24
|
|
|
28
25
|
|
|
29
26
|
def parse_param(arg_str: str) -> Param:
|
|
30
|
-
"""
|
|
27
|
+
"""
|
|
28
|
+
Build a `Param` instance based on its string representation.
|
|
31
29
|
|
|
32
30
|
Instantiating it from scratch is cumbersome, this helper generates a
|
|
33
31
|
function definition with the given param and extract it from the tree.
|
|
@@ -149,7 +149,7 @@ class InlineHasAddPermissionsTransformer(BaseDjCodemodTransformer):
|
|
|
149
149
|
|
|
150
150
|
|
|
151
151
|
class ActionCheckboxNameTransformer(BaseRenameTransformer):
|
|
152
|
-
"""Replace `django.contrib.admin.ACTION_CHECKBOX_NAME` compatibility import"""
|
|
152
|
+
"""Replace `django.contrib.admin.ACTION_CHECKBOX_NAME` compatibility import."""
|
|
153
153
|
|
|
154
154
|
deprecated_in = DJANGO_1_3
|
|
155
155
|
removed_in = DJANGO_3_1
|
|
@@ -28,9 +28,7 @@ from django_codemod.feature_flags import REPLACE_PARENT_MODULE_IMPORTED
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
class IsTryImportProvider(BatchableMetadataProvider[bool]):
|
|
31
|
-
"""
|
|
32
|
-
Marks ImportFrom nodes found inside a try block.
|
|
33
|
-
"""
|
|
31
|
+
"""Marks ImportFrom nodes found inside a try block."""
|
|
34
32
|
|
|
35
33
|
def __init__(self) -> None:
|
|
36
34
|
super().__init__()
|
|
@@ -114,7 +112,6 @@ class BaseRenameTransformer(BaseDjCodemodTransformer, ABC):
|
|
|
114
112
|
self, original_node: ImportFrom, updated_node: ImportFrom
|
|
115
113
|
) -> Union[BaseSmallStatement, RemovalSentinel]:
|
|
116
114
|
"""Update import statements for matching old module name."""
|
|
117
|
-
|
|
118
115
|
return (
|
|
119
116
|
self._check_import_from_exact(original_node, updated_node)
|
|
120
117
|
or self._check_import_from_parent(original_node, updated_node)
|
|
@@ -218,21 +215,21 @@ class BaseRenameTransformer(BaseDjCodemodTransformer, ABC):
|
|
|
218
215
|
add_import_module: Optional[str] = None
|
|
219
216
|
if self.new_parent_module_parts:
|
|
220
217
|
add_import_module = ".".join(self.new_parent_module_parts)
|
|
221
|
-
self.context.scratch[self.ctx_key_add_import_kwargs] =
|
|
222
|
-
context
|
|
223
|
-
module
|
|
224
|
-
obj
|
|
225
|
-
asname
|
|
226
|
-
|
|
218
|
+
self.context.scratch[self.ctx_key_add_import_kwargs] = {
|
|
219
|
+
"context": self.context,
|
|
220
|
+
"module": add_import_module,
|
|
221
|
+
"obj": self.new_parent_name,
|
|
222
|
+
"asname": new_as_name,
|
|
223
|
+
}
|
|
227
224
|
remove_import_module: Optional[str] = None
|
|
228
225
|
if self.old_parent_module_parts:
|
|
229
226
|
remove_import_module = ".".join(self.old_parent_module_parts)
|
|
230
|
-
self.context.scratch[self.ctx_key_remove_import_kwargs] =
|
|
231
|
-
context
|
|
232
|
-
module
|
|
233
|
-
obj
|
|
234
|
-
asname
|
|
235
|
-
|
|
227
|
+
self.context.scratch[self.ctx_key_remove_import_kwargs] = {
|
|
228
|
+
"context": self.context,
|
|
229
|
+
"module": remove_import_module,
|
|
230
|
+
"obj": self.old_parent_name,
|
|
231
|
+
"asname": import_alias.evaluated_alias,
|
|
232
|
+
}
|
|
236
233
|
return updated_node
|
|
237
234
|
|
|
238
235
|
def _check_import_from_child(
|
|
@@ -281,16 +278,13 @@ class BaseRenameTransformer(BaseDjCodemodTransformer, ABC):
|
|
|
281
278
|
|
|
282
279
|
def update_imports(self):
|
|
283
280
|
"""Update import statements if a change is required."""
|
|
284
|
-
remove_import_kwargs
|
|
285
|
-
if remove_import_kwargs:
|
|
281
|
+
if remove_import_kwargs := self.remove_import_kwargs:
|
|
286
282
|
RemoveImportsVisitor.remove_unused_import(**remove_import_kwargs)
|
|
287
|
-
add_import_kwargs
|
|
288
|
-
if add_import_kwargs:
|
|
283
|
+
if add_import_kwargs := self.add_import_kwargs:
|
|
289
284
|
AddImportsVisitor.add_needed_import(**add_import_kwargs)
|
|
290
285
|
|
|
291
286
|
def leave_Name(self, original_node: Name, updated_node: Name) -> BaseExpression:
|
|
292
287
|
"""Rename reference to the imported name."""
|
|
293
|
-
|
|
294
288
|
matcher = self.name_matcher
|
|
295
289
|
if (
|
|
296
290
|
matcher
|
|
@@ -8,7 +8,7 @@ from django_codemod.visitors.base import BaseFuncRenameTransformer
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class GetRandomStringTransformer(BaseFuncRenameTransformer):
|
|
11
|
-
"""Update lengthless uses of get_random_string()"""
|
|
11
|
+
"""Update lengthless uses of get_random_string()."""
|
|
12
12
|
|
|
13
13
|
deprecated_in = DJANGO_3_1
|
|
14
14
|
removed_in = DJANGO_4_0
|
|
@@ -21,10 +21,7 @@ class SqlEmptyResultSetTransformer(BaseRenameTransformer):
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class DatastructuresEmptyResultSetTransformer(BaseRenameTransformer):
|
|
24
|
-
"""
|
|
25
|
-
Replace `django.db.models.sql.datastructures.EmptyResultSet` compatibility
|
|
26
|
-
import.
|
|
27
|
-
"""
|
|
24
|
+
"""Replace `django.db.models.sql.datastructures.EmptyResultSet` import."""
|
|
28
25
|
|
|
29
26
|
deprecated_in = DJANGO_1_11
|
|
30
27
|
removed_in = DJANGO_3_1
|
|
@@ -153,18 +153,18 @@ class ModelsPermalinkTransformer(BaseDjCodemodTransformer):
|
|
|
153
153
|
return super().leave_Return(original_node, updated_node)
|
|
154
154
|
|
|
155
155
|
|
|
156
|
-
def
|
|
156
|
+
def _is_foreign_key(node: Call) -> bool:
|
|
157
157
|
return m.matches(node, m.Call(func=m.Attribute(attr=m.Name(value="ForeignKey"))))
|
|
158
158
|
|
|
159
159
|
|
|
160
|
-
def
|
|
160
|
+
def _is_one_to_one_field(node: Call) -> bool:
|
|
161
161
|
return m.matches(
|
|
162
162
|
node,
|
|
163
163
|
m.Call(func=m.Attribute(attr=m.Name(value="OneToOneField"))),
|
|
164
164
|
)
|
|
165
165
|
|
|
166
166
|
|
|
167
|
-
def
|
|
167
|
+
def _has_on_delete(node: Call) -> bool:
|
|
168
168
|
# if on_delete exists in any kwarg we return True
|
|
169
169
|
if find_keyword_arg(node.args, "on_delete"):
|
|
170
170
|
return True
|
|
@@ -184,8 +184,8 @@ class OnDeleteTransformer(BaseDjCodemodTransformer):
|
|
|
184
184
|
|
|
185
185
|
def leave_Call(self, original_node: Call, updated_node: Call) -> BaseExpression:
|
|
186
186
|
if (
|
|
187
|
-
|
|
188
|
-
) and not
|
|
187
|
+
_is_one_to_one_field(original_node) or _is_foreign_key(original_node)
|
|
188
|
+
) and not _has_on_delete(original_node):
|
|
189
189
|
AddImportsVisitor.add_needed_import(
|
|
190
190
|
context=self.context,
|
|
191
191
|
module="django.db",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from typing import List, Optional
|
|
1
|
+
from typing import ClassVar, List, 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 = [
|
|
18
|
+
builtin_signals: ClassVar[List[str]] = [
|
|
19
19
|
"pre_init",
|
|
20
20
|
"post_init",
|
|
21
21
|
"pre_save",
|
|
@@ -35,9 +35,10 @@ class SignalDisconnectWeakTransformer(BaseDjCodemodTransformer):
|
|
|
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:
|
|
38
|
-
self.context.scratch[
|
|
39
|
-
self.
|
|
40
|
-
|
|
38
|
+
self.context.scratch[self.ctx_key_call_matchers] = [
|
|
39
|
+
*self.disconnect_call_matchers,
|
|
40
|
+
call_matcher,
|
|
41
|
+
]
|
|
41
42
|
|
|
42
43
|
def leave_Module(self, original_node: Module, updated_node: Module) -> Module:
|
|
43
44
|
"""Clear context when leaving module."""
|
|
@@ -81,7 +82,7 @@ class SignalDisconnectWeakTransformer(BaseDjCodemodTransformer):
|
|
|
81
82
|
should_change = False
|
|
82
83
|
last_comma = MaybeSentinel.DEFAULT
|
|
83
84
|
# Keep all arguments except the one with the keyword `weak` (if present)
|
|
84
|
-
for
|
|
85
|
+
for arg in updated_node.args:
|
|
85
86
|
if m.matches(arg, m.Arg(keyword=m.Name("weak"))):
|
|
86
87
|
# An argument with the keyword `weak` was found
|
|
87
88
|
# -> we need to rewrite the statement
|
|
@@ -92,9 +92,9 @@ class URLTransformer(BaseFuncRenameTransformer):
|
|
|
92
92
|
group_name, group_regex = group.split(">", 1)
|
|
93
93
|
try:
|
|
94
94
|
converter = REGEX_TO_CONVERTER[group_regex]
|
|
95
|
-
except KeyError:
|
|
96
|
-
raise PatternNotSupported("No converter found")
|
|
97
|
-
return
|
|
95
|
+
except KeyError as exc:
|
|
96
|
+
raise PatternNotSupported("No converter found") from exc
|
|
97
|
+
return f"{prefix}<{converter}:{group_name}>", left_to_parse
|
|
98
98
|
|
|
99
99
|
@staticmethod
|
|
100
100
|
def check_route(route: str) -> None:
|
|
@@ -198,19 +198,21 @@ class NoDocString:
|
|
|
198
198
|
|
|
199
199
|
|
|
200
200
|
class EmptyDocString:
|
|
201
|
-
""""""
|
|
201
|
+
"""""" # noqa D419
|
|
202
202
|
|
|
203
203
|
pass
|
|
204
204
|
|
|
205
205
|
|
|
206
206
|
class SingleLine:
|
|
207
|
-
"""
|
|
207
|
+
"""The description."""
|
|
208
208
|
|
|
209
209
|
|
|
210
210
|
class MultiLine1:
|
|
211
|
-
"""
|
|
211
|
+
"""
|
|
212
|
+
Some title.
|
|
212
213
|
|
|
213
|
-
This is more details.
|
|
214
|
+
This is more details.
|
|
215
|
+
"""
|
|
214
216
|
|
|
215
217
|
|
|
216
218
|
class MultiLine2:
|
|
@@ -226,8 +228,8 @@ class MultiLine2:
|
|
|
226
228
|
[
|
|
227
229
|
(NoDocString, ""),
|
|
228
230
|
(EmptyDocString, ""),
|
|
229
|
-
(SingleLine, "
|
|
230
|
-
(MultiLine1, "
|
|
231
|
+
(SingleLine, "The description."),
|
|
232
|
+
(MultiLine1, "Some title."),
|
|
231
233
|
(MultiLine2, "Another title."),
|
|
232
234
|
],
|
|
233
235
|
)
|
|
@@ -39,7 +39,7 @@ class TestOnDeleteTransformer(BaseVisitorTest):
|
|
|
39
39
|
self.assertCodemod(before, after)
|
|
40
40
|
|
|
41
41
|
def test_multiple_kwargs_with_on_delete(self) -> None:
|
|
42
|
-
"""Should do nothing"""
|
|
42
|
+
"""Should do nothing."""
|
|
43
43
|
before = """
|
|
44
44
|
from django.db import models
|
|
45
45
|
|
|
@@ -123,7 +123,7 @@ class TestOnDeleteTransformer(BaseVisitorTest):
|
|
|
123
123
|
self.assertCodemod(before, after)
|
|
124
124
|
|
|
125
125
|
def test_positional_args_with_on_delete(self) -> None:
|
|
126
|
-
"""Should do nothing"""
|
|
126
|
+
"""Should do nothing."""
|
|
127
127
|
before = """
|
|
128
128
|
from django.db import models
|
|
129
129
|
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import ClassVar
|
|
4
|
+
|
|
1
5
|
from parameterized import parameterized
|
|
2
6
|
|
|
3
7
|
from django_codemod.visitors import SignalDisconnectWeakTransformer
|
|
@@ -6,7 +10,7 @@ from tests.visitors.base import BaseVisitorTest
|
|
|
6
10
|
|
|
7
11
|
class TestSignalDisconnectWeakTransformer(BaseVisitorTest):
|
|
8
12
|
transformer = SignalDisconnectWeakTransformer
|
|
9
|
-
DJANGO_SIGNAL_NAMES = [
|
|
13
|
+
DJANGO_SIGNAL_NAMES: ClassVar[list[str]] = [
|
|
10
14
|
"pre_init",
|
|
11
15
|
"post_init",
|
|
12
16
|
"pre_save",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/postgres_fields.py
RENAMED
|
File without changes
|
|
File without changes
|
{django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/template_context.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|