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.
Files changed (63) hide show
  1. {django_codemod-2.0.0 → django_codemod-2.1.1}/PKG-INFO +2 -1
  2. {django_codemod-2.0.0 → django_codemod-2.1.1}/pyproject.toml +52 -6
  3. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/cli.py +3 -4
  4. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/path_utils.py +8 -4
  5. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/utils/calls.py +6 -8
  6. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/admin.py +1 -1
  7. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/base.py +15 -21
  8. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/crypto.py +1 -1
  9. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/exceptions.py +1 -4
  10. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/models.py +5 -5
  11. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/signals.py +7 -6
  12. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/urls.py +3 -3
  13. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/test_cli.py +8 -6
  14. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_models.py +2 -2
  15. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_signals.py +5 -1
  16. {django_codemod-2.0.0 → django_codemod-2.1.1}/LICENSE +0 -0
  17. {django_codemod-2.0.0 → django_codemod-2.1.1}/README.md +0 -0
  18. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/__init__.py +0 -0
  19. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/commands.py +0 -0
  20. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/constants.py +0 -0
  21. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/feature_flags.py +0 -0
  22. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/utils/__init__.py +0 -0
  23. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/__init__.py +0 -0
  24. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/core.py +0 -0
  25. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/decorators.py +0 -0
  26. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/encoding.py +0 -0
  27. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/forms.py +0 -0
  28. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/html.py +0 -0
  29. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/http.py +0 -0
  30. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/lru_cache.py +0 -0
  31. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/os_utils.py +0 -0
  32. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/paginator.py +0 -0
  33. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/postgres_fields.py +0 -0
  34. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/shortcuts.py +0 -0
  35. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/template_context.py +0 -0
  36. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/template_tags.py +0 -0
  37. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/timezone.py +0 -0
  38. {django_codemod-2.0.0 → django_codemod-2.1.1}/src/django_codemod/visitors/translations.py +0 -0
  39. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/__init__.py +0 -0
  40. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/test_e2e.sh +0 -0
  41. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/test_path_utils.py +0 -0
  42. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/__init__.py +0 -0
  43. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/base.py +0 -0
  44. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_admin.py +0 -0
  45. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_base.py +0 -0
  46. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_core.py +0 -0
  47. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_crypto.py +0 -0
  48. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_decorators.py +0 -0
  49. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_encoding.py +0 -0
  50. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_exceptions.py +0 -0
  51. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_forms.py +0 -0
  52. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_html.py +0 -0
  53. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_http.py +0 -0
  54. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_lru_cache.py +0 -0
  55. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_os_utils.py +0 -0
  56. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_paginator.py +0 -0
  57. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_postgres_fields.py +0 -0
  58. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_shortcuts.py +0 -0
  59. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_template_context.py +0 -0
  60. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_template_tags.py +0 -0
  61. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_timezone.py +0 -0
  62. {django_codemod-2.0.0 → django_codemod-2.1.1}/tests/visitors/test_translations.py +0 -0
  63. {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.0.0
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.0.0"
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
- sphinx-rtd-theme = ">=1.0"
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.isort]
65
- profile = "black"
66
- known_first_party = ["django_codemod", "tests"]
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 = line.strip()
251
- if description:
250
+ if description := line.strip():
252
251
  return description
253
252
  return ""
254
253
 
@@ -1,4 +1,5 @@
1
- """Some utilities to deal with files.
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
- """Return a list of sources to codemod.
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
- """Return a directory containing .git, .hg, or pyproject.toml.
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
- """Generate all files under `paths`.
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
- """Build a `Arg` instance based on its string representation.
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
- """Build a `Param` instance based on its string representation.
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] = dict(
222
- context=self.context,
223
- module=add_import_module,
224
- obj=self.new_parent_name,
225
- asname=new_as_name,
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] = dict(
231
- context=self.context,
232
- module=remove_import_module,
233
- obj=self.old_parent_name,
234
- asname=import_alias.evaluated_alias,
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 = self.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 = self.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 is_foreign_key(node: Call) -> bool:
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 is_one_to_one_field(node: Call) -> bool:
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 has_on_delete(node: Call) -> bool:
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
- is_one_to_one_field(original_node) or is_foreign_key(original_node)
188
- ) and not has_on_delete(original_node):
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.ctx_key_call_matchers
40
- ] = self.disconnect_call_matchers + [call_matcher]
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 index, arg in enumerate(updated_node.args):
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 prefix + f"<{converter}:{group_name}>", left_to_parse
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
- """This is the description."""
207
+ """The description."""
208
208
 
209
209
 
210
210
  class MultiLine1:
211
- """This is the title.
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, "This is the description."),
230
- (MultiLine1, "This is the title."),
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