datamodel-code-generator 0.27.2__py3-none-any.whl → 0.28.0__py3-none-any.whl

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.

Potentially problematic release.


This version of datamodel-code-generator might be problematic. Click here for more details.

Files changed (43) hide show
  1. datamodel_code_generator/__init__.py +168 -196
  2. datamodel_code_generator/__main__.py +146 -189
  3. datamodel_code_generator/arguments.py +227 -230
  4. datamodel_code_generator/format.py +77 -129
  5. datamodel_code_generator/http.py +12 -10
  6. datamodel_code_generator/imports.py +59 -65
  7. datamodel_code_generator/model/__init__.py +28 -31
  8. datamodel_code_generator/model/base.py +100 -144
  9. datamodel_code_generator/model/dataclass.py +62 -70
  10. datamodel_code_generator/model/enum.py +34 -30
  11. datamodel_code_generator/model/imports.py +13 -11
  12. datamodel_code_generator/model/msgspec.py +116 -138
  13. datamodel_code_generator/model/pydantic/__init__.py +18 -28
  14. datamodel_code_generator/model/pydantic/base_model.py +121 -140
  15. datamodel_code_generator/model/pydantic/custom_root_type.py +2 -2
  16. datamodel_code_generator/model/pydantic/dataclass.py +6 -4
  17. datamodel_code_generator/model/pydantic/imports.py +35 -33
  18. datamodel_code_generator/model/pydantic/types.py +91 -119
  19. datamodel_code_generator/model/pydantic_v2/__init__.py +21 -18
  20. datamodel_code_generator/model/pydantic_v2/base_model.py +118 -127
  21. datamodel_code_generator/model/pydantic_v2/imports.py +5 -3
  22. datamodel_code_generator/model/pydantic_v2/root_model.py +6 -6
  23. datamodel_code_generator/model/pydantic_v2/types.py +11 -7
  24. datamodel_code_generator/model/rootmodel.py +1 -1
  25. datamodel_code_generator/model/scalar.py +33 -32
  26. datamodel_code_generator/model/typed_dict.py +41 -51
  27. datamodel_code_generator/model/types.py +24 -19
  28. datamodel_code_generator/model/union.py +21 -17
  29. datamodel_code_generator/parser/__init__.py +16 -12
  30. datamodel_code_generator/parser/base.py +327 -515
  31. datamodel_code_generator/parser/graphql.py +87 -119
  32. datamodel_code_generator/parser/jsonschema.py +438 -607
  33. datamodel_code_generator/parser/openapi.py +180 -220
  34. datamodel_code_generator/pydantic_patch.py +8 -9
  35. datamodel_code_generator/reference.py +199 -297
  36. datamodel_code_generator/types.py +149 -215
  37. datamodel_code_generator/util.py +23 -36
  38. {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/METADATA +10 -5
  39. datamodel_code_generator-0.28.0.dist-info/RECORD +59 -0
  40. datamodel_code_generator-0.27.2.dist-info/RECORD +0 -59
  41. {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/WHEEL +0 -0
  42. {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/entry_points.txt +0 -0
  43. {datamodel_code_generator-0.27.2.dist-info → datamodel_code_generator-0.28.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,15 +1,16 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from enum import Enum
4
+ from functools import cached_property
4
5
  from importlib import import_module
5
6
  from pathlib import Path
6
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence
7
+ from typing import TYPE_CHECKING, Any
7
8
  from warnings import warn
8
9
 
9
10
  import black
10
11
  import isort
11
12
 
12
- from datamodel_code_generator.util import cached_property, load_toml
13
+ from datamodel_code_generator.util import load_toml
13
14
 
14
15
  try:
15
16
  import black.mode
@@ -18,64 +19,30 @@ except ImportError: # pragma: no cover
18
19
 
19
20
 
20
21
  class DatetimeClassType(Enum):
21
- Datetime = 'datetime'
22
- Awaredatetime = 'AwareDatetime'
23
- Naivedatetime = 'NaiveDatetime'
22
+ Datetime = "datetime"
23
+ Awaredatetime = "AwareDatetime"
24
+ Naivedatetime = "NaiveDatetime"
24
25
 
25
26
 
26
27
  class PythonVersion(Enum):
27
- PY_36 = '3.6'
28
- PY_37 = '3.7'
29
- PY_38 = '3.8'
30
- PY_39 = '3.9'
31
- PY_310 = '3.10'
32
- PY_311 = '3.11'
33
- PY_312 = '3.12'
34
- PY_313 = '3.13'
35
-
36
- @cached_property
37
- def _is_py_38_or_later(self) -> bool: # pragma: no cover
38
- return self.value not in {self.PY_36.value, self.PY_37.value} # type: ignore
39
-
40
- @cached_property
41
- def _is_py_39_or_later(self) -> bool: # pragma: no cover
42
- return self.value not in {self.PY_36.value, self.PY_37.value, self.PY_38.value} # type: ignore
28
+ PY_39 = "3.9"
29
+ PY_310 = "3.10"
30
+ PY_311 = "3.11"
31
+ PY_312 = "3.12"
32
+ PY_313 = "3.13"
43
33
 
44
34
  @cached_property
45
35
  def _is_py_310_or_later(self) -> bool: # pragma: no cover
46
- return self.value not in {
47
- self.PY_36.value,
48
- self.PY_37.value,
49
- self.PY_38.value,
50
- self.PY_39.value,
51
- } # type: ignore
36
+ return self.value != self.PY_39.value
52
37
 
53
38
  @cached_property
54
39
  def _is_py_311_or_later(self) -> bool: # pragma: no cover
55
- return self.value not in {
56
- self.PY_36.value,
57
- self.PY_37.value,
58
- self.PY_38.value,
59
- self.PY_39.value,
60
- self.PY_310.value,
61
- } # type: ignore
62
-
63
- @property
64
- def has_literal_type(self) -> bool:
65
- return self._is_py_38_or_later
40
+ return self.value not in {self.PY_39.value, self.PY_310.value}
66
41
 
67
42
  @property
68
43
  def has_union_operator(self) -> bool: # pragma: no cover
69
44
  return self._is_py_310_or_later
70
45
 
71
- @property
72
- def has_annotated_type(self) -> bool:
73
- return self._is_py_39_or_later
74
-
75
- @property
76
- def has_typed_dict(self) -> bool:
77
- return self._is_py_38_or_later
78
-
79
46
  @property
80
47
  def has_typed_dict_non_required(self) -> bool:
81
48
  return self._is_py_311_or_later
@@ -85,16 +52,19 @@ class PythonVersion(Enum):
85
52
  return self._is_py_310_or_later
86
53
 
87
54
 
55
+ PythonVersionMin = PythonVersion.PY_39
56
+
88
57
  if TYPE_CHECKING:
58
+ from collections.abc import Sequence
89
59
 
90
60
  class _TargetVersion(Enum): ...
91
61
 
92
- BLACK_PYTHON_VERSION: Dict[PythonVersion, _TargetVersion]
62
+ BLACK_PYTHON_VERSION: dict[PythonVersion, _TargetVersion]
93
63
  else:
94
- BLACK_PYTHON_VERSION: Dict[PythonVersion, black.TargetVersion] = {
95
- v: getattr(black.TargetVersion, f'PY{v.name.split("_")[-1]}')
64
+ BLACK_PYTHON_VERSION: dict[PythonVersion, black.TargetVersion] = {
65
+ v: getattr(black.TargetVersion, f"PY{v.name.split('_')[-1]}")
96
66
  for v in PythonVersion
97
- if hasattr(black.TargetVersion, f'PY{v.name.split("_")[-1]}')
67
+ if hasattr(black.TargetVersion, f"PY{v.name.split('_')[-1]}")
98
68
  }
99
69
 
100
70
 
@@ -104,132 +74,111 @@ def is_supported_in_black(python_version: PythonVersion) -> bool: # pragma: no
104
74
 
105
75
  def black_find_project_root(sources: Sequence[Path]) -> Path:
106
76
  if TYPE_CHECKING:
107
- from typing import Iterable, Tuple, Union
77
+ from collections.abc import Iterable # noqa: PLC0415
108
78
 
109
79
  def _find_project_root(
110
- srcs: Union[Sequence[str], Iterable[str]],
111
- ) -> Union[Tuple[Path, str], Path]: ...
80
+ srcs: Sequence[str] | Iterable[str],
81
+ ) -> tuple[Path, str] | Path: ...
112
82
 
113
83
  else:
114
- from black import find_project_root as _find_project_root
84
+ from black import find_project_root as _find_project_root # noqa: PLC0415
115
85
  project_root = _find_project_root(tuple(str(s) for s in sources))
116
86
  if isinstance(project_root, tuple):
117
87
  return project_root[0]
118
- else: # pragma: no cover
119
- return project_root
88
+ # pragma: no cover
89
+ return project_root
120
90
 
121
91
 
122
92
  class CodeFormatter:
123
- def __init__(
93
+ def __init__( # noqa: PLR0912, PLR0913, PLR0917
124
94
  self,
125
95
  python_version: PythonVersion,
126
- settings_path: Optional[Path] = None,
127
- wrap_string_literal: Optional[bool] = None,
128
- skip_string_normalization: bool = True,
129
- known_third_party: Optional[List[str]] = None,
130
- custom_formatters: Optional[List[str]] = None,
131
- custom_formatters_kwargs: Optional[Dict[str, Any]] = None,
96
+ settings_path: Path | None = None,
97
+ wrap_string_literal: bool | None = None, # noqa: FBT001
98
+ skip_string_normalization: bool = True, # noqa: FBT001, FBT002
99
+ known_third_party: list[str] | None = None,
100
+ custom_formatters: list[str] | None = None,
101
+ custom_formatters_kwargs: dict[str, Any] | None = None,
132
102
  ) -> None:
133
103
  if not settings_path:
134
- settings_path = Path().resolve()
104
+ settings_path = Path.cwd()
135
105
 
136
106
  root = black_find_project_root((settings_path,))
137
- path = root / 'pyproject.toml'
107
+ path = root / "pyproject.toml"
138
108
  if path.is_file():
139
109
  pyproject_toml = load_toml(path)
140
- config = pyproject_toml.get('tool', {}).get('black', {})
110
+ config = pyproject_toml.get("tool", {}).get("black", {})
141
111
  else:
142
112
  config = {}
143
113
 
144
- black_kwargs: Dict[str, Any] = {}
114
+ black_kwargs: dict[str, Any] = {}
145
115
  if wrap_string_literal is not None:
146
116
  experimental_string_processing = wrap_string_literal
117
+ elif black.__version__ < "24.1.0":
118
+ experimental_string_processing = config.get("experimental-string-processing")
147
119
  else:
148
- if black.__version__ < '24.1.0': # type: ignore
149
- experimental_string_processing = config.get(
150
- 'experimental-string-processing'
151
- )
152
- else:
153
- experimental_string_processing = config.get(
154
- 'preview', False
155
- ) and ( # pragma: no cover
156
- config.get('unstable', False)
157
- or 'string_processing' in config.get('enable-unstable-feature', [])
158
- )
120
+ experimental_string_processing = config.get("preview", False) and ( # pragma: no cover
121
+ config.get("unstable", False) or "string_processing" in config.get("enable-unstable-feature", [])
122
+ )
159
123
 
160
124
  if experimental_string_processing is not None: # pragma: no cover
161
- if black.__version__.startswith('19.'): # type: ignore
125
+ if black.__version__.startswith("19."):
162
126
  warn(
163
- f"black doesn't support `experimental-string-processing` option" # type: ignore
164
- f' for wrapping string literal in {black.__version__}'
165
- )
166
- elif black.__version__ < '24.1.0': # type: ignore
167
- black_kwargs['experimental_string_processing'] = (
168
- experimental_string_processing
127
+ f"black doesn't support `experimental-string-processing` option"
128
+ f" for wrapping string literal in {black.__version__}",
129
+ stacklevel=2,
169
130
  )
131
+ elif black.__version__ < "24.1.0":
132
+ black_kwargs["experimental_string_processing"] = experimental_string_processing
170
133
  elif experimental_string_processing:
171
- black_kwargs['preview'] = True
172
- black_kwargs['unstable'] = config.get('unstable', False)
173
- black_kwargs['enabled_features'] = {
174
- black.mode.Preview.string_processing
175
- }
134
+ black_kwargs["preview"] = True
135
+ black_kwargs["unstable"] = config.get("unstable", False)
136
+ black_kwargs["enabled_features"] = {black.mode.Preview.string_processing}
176
137
 
177
138
  if TYPE_CHECKING:
178
139
  self.black_mode: black.FileMode
179
140
  else:
180
141
  self.black_mode = black.FileMode(
181
142
  target_versions={BLACK_PYTHON_VERSION[python_version]},
182
- line_length=config.get('line-length', black.DEFAULT_LINE_LENGTH),
183
- string_normalization=not skip_string_normalization
184
- or not config.get('skip-string-normalization', True),
143
+ line_length=config.get("line-length", black.DEFAULT_LINE_LENGTH),
144
+ string_normalization=not skip_string_normalization or not config.get("skip-string-normalization", True),
185
145
  **black_kwargs,
186
146
  )
187
147
 
188
148
  self.settings_path: str = str(settings_path)
189
149
 
190
- self.isort_config_kwargs: Dict[str, Any] = {}
150
+ self.isort_config_kwargs: dict[str, Any] = {}
191
151
  if known_third_party:
192
- self.isort_config_kwargs['known_third_party'] = known_third_party
152
+ self.isort_config_kwargs["known_third_party"] = known_third_party
193
153
 
194
- if isort.__version__.startswith('4.'):
154
+ if isort.__version__.startswith("4."):
195
155
  self.isort_config = None
196
156
  else:
197
- self.isort_config = isort.Config(
198
- settings_path=self.settings_path, **self.isort_config_kwargs
199
- )
157
+ self.isort_config = isort.Config(settings_path=self.settings_path, **self.isort_config_kwargs)
200
158
 
201
159
  self.custom_formatters_kwargs = custom_formatters_kwargs or {}
202
160
  self.custom_formatters = self._check_custom_formatters(custom_formatters)
203
161
 
204
- def _load_custom_formatter(
205
- self, custom_formatter_import: str
206
- ) -> CustomCodeFormatter:
162
+ def _load_custom_formatter(self, custom_formatter_import: str) -> CustomCodeFormatter:
207
163
  import_ = import_module(custom_formatter_import)
208
164
 
209
- if not hasattr(import_, 'CodeFormatter'):
210
- raise NameError(
211
- f'Custom formatter module `{import_.__name__}` must contains object with name Formatter'
212
- )
165
+ if not hasattr(import_, "CodeFormatter"):
166
+ msg = f"Custom formatter module `{import_.__name__}` must contains object with name Formatter"
167
+ raise NameError(msg)
213
168
 
214
- formatter_class = import_.__getattribute__('CodeFormatter')
169
+ formatter_class = import_.__getattribute__("CodeFormatter") # noqa: PLC2801
215
170
 
216
171
  if not issubclass(formatter_class, CustomCodeFormatter):
217
- raise TypeError(
218
- f'The custom module {custom_formatter_import} must inherit from `datamodel-code-generator`'
219
- )
172
+ msg = f"The custom module {custom_formatter_import} must inherit from `datamodel-code-generator`"
173
+ raise TypeError(msg)
220
174
 
221
175
  return formatter_class(formatter_kwargs=self.custom_formatters_kwargs)
222
176
 
223
- def _check_custom_formatters(
224
- self, custom_formatters: Optional[List[str]]
225
- ) -> List[CustomCodeFormatter]:
177
+ def _check_custom_formatters(self, custom_formatters: list[str] | None) -> list[CustomCodeFormatter]:
226
178
  if custom_formatters is None:
227
179
  return []
228
180
 
229
- return [
230
- self._load_custom_formatter(custom_formatter_import)
231
- for custom_formatter_import in custom_formatters
232
- ]
181
+ return [self._load_custom_formatter(custom_formatter_import) for custom_formatter_import in custom_formatters]
233
182
 
234
183
  def format_code(
235
184
  self,
@@ -253,24 +202,23 @@ class CodeFormatter:
253
202
 
254
203
  def apply_isort(self, code: str) -> str: ...
255
204
 
256
- else:
257
- if isort.__version__.startswith('4.'):
205
+ elif isort.__version__.startswith("4."):
258
206
 
259
- def apply_isort(self, code: str) -> str:
260
- return isort.SortImports(
261
- file_contents=code,
262
- settings_path=self.settings_path,
263
- **self.isort_config_kwargs,
264
- ).output
207
+ def apply_isort(self, code: str) -> str:
208
+ return isort.SortImports(
209
+ file_contents=code,
210
+ settings_path=self.settings_path,
211
+ **self.isort_config_kwargs,
212
+ ).output
265
213
 
266
- else:
214
+ else:
267
215
 
268
- def apply_isort(self, code: str) -> str:
269
- return isort.code(code, config=self.isort_config)
216
+ def apply_isort(self, code: str) -> str:
217
+ return isort.code(code, config=self.isort_config)
270
218
 
271
219
 
272
220
  class CustomCodeFormatter:
273
- def __init__(self, formatter_kwargs: Dict[str, Any]) -> None:
221
+ def __init__(self, formatter_kwargs: dict[str, Any]) -> None:
274
222
  self.formatter_kwargs = formatter_kwargs
275
223
 
276
224
  def apply(self, code: str) -> str:
@@ -1,30 +1,32 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Optional, Sequence, Tuple
3
+ from typing import TYPE_CHECKING
4
+
5
+ if TYPE_CHECKING:
6
+ from collections.abc import Sequence
4
7
 
5
8
  try:
6
9
  import httpx
7
- except ImportError: # pragma: no cover
8
- raise Exception(
9
- "Please run `$pip install 'datamodel-code-generator[http]`' to resolve URL Reference"
10
- )
10
+ except ImportError as exc: # pragma: no cover
11
+ msg = "Please run `$pip install 'datamodel-code-generator[http]`' to resolve URL Reference"
12
+ raise Exception(msg) from exc # noqa: TRY002
11
13
 
12
14
 
13
15
  def get_body(
14
16
  url: str,
15
- headers: Optional[Sequence[Tuple[str, str]]] = None,
16
- ignore_tls: bool = False,
17
- query_parameters: Optional[Sequence[Tuple[str, str]]] = None,
17
+ headers: Sequence[tuple[str, str]] | None = None,
18
+ ignore_tls: bool = False, # noqa: FBT001, FBT002
19
+ query_parameters: Sequence[tuple[str, str]] | None = None,
18
20
  ) -> str:
19
21
  return httpx.get(
20
22
  url,
21
23
  headers=headers,
22
24
  verify=not ignore_tls,
23
25
  follow_redirects=True,
24
- params=query_parameters, # pyright: ignore [reportArgumentType]
26
+ params=query_parameters, # pyright: ignore[reportArgumentType]
25
27
  # TODO: Improve params type
26
28
  ).text
27
29
 
28
30
 
29
- def join_url(url: str, ref: str = '.') -> str:
31
+ def join_url(url: str, ref: str = ".") -> str:
30
32
  return str(httpx.URL(url).join(ref))
@@ -2,86 +2,82 @@ from __future__ import annotations
2
2
 
3
3
  from collections import defaultdict
4
4
  from functools import lru_cache
5
- from typing import DefaultDict, Dict, Iterable, List, Optional, Set, Tuple, Union
5
+ from itertools import starmap
6
+ from typing import TYPE_CHECKING, Optional
6
7
 
7
8
  from datamodel_code_generator.util import BaseModel
8
9
 
10
+ if TYPE_CHECKING:
11
+ from collections.abc import Iterable
12
+
9
13
 
10
14
  class Import(BaseModel):
11
- from_: Optional[str] = None
15
+ from_: Optional[str] = None # noqa: UP045
12
16
  import_: str
13
- alias: Optional[str] = None
14
- reference_path: Optional[str] = None
17
+ alias: Optional[str] = None # noqa: UP045
18
+ reference_path: Optional[str] = None # noqa: UP045
15
19
 
16
20
  @classmethod
17
21
  @lru_cache
18
22
  def from_full_path(cls, class_path: str) -> Import:
19
- split_class_path: List[str] = class_path.split('.')
20
- return Import(
21
- from_='.'.join(split_class_path[:-1]) or None, import_=split_class_path[-1]
22
- )
23
+ split_class_path: list[str] = class_path.split(".")
24
+ return Import(from_=".".join(split_class_path[:-1]) or None, import_=split_class_path[-1])
23
25
 
24
26
 
25
- class Imports(DefaultDict[Optional[str], Set[str]]):
27
+ class Imports(defaultdict[Optional[str], set[str]]):
26
28
  def __str__(self) -> str:
27
29
  return self.dump()
28
30
 
29
- def __init__(self, use_exact: bool = False) -> None:
31
+ def __init__(self, use_exact: bool = False) -> None: # noqa: FBT001, FBT002
30
32
  super().__init__(set)
31
- self.alias: DefaultDict[Optional[str], Dict[str, str]] = defaultdict(dict)
32
- self.counter: Dict[Tuple[Optional[str], str], int] = defaultdict(int)
33
- self.reference_paths: Dict[str, Import] = {}
33
+ self.alias: defaultdict[str | None, dict[str, str]] = defaultdict(dict)
34
+ self.counter: dict[tuple[str | None, str], int] = defaultdict(int)
35
+ self.reference_paths: dict[str, Import] = {}
34
36
  self.use_exact: bool = use_exact
35
37
 
36
- def _set_alias(self, from_: Optional[str], imports: Set[str]) -> List[str]:
38
+ def _set_alias(self, from_: str | None, imports: set[str]) -> list[str]:
37
39
  return [
38
- f'{i} as {self.alias[from_][i]}'
39
- if i in self.alias[from_] and i != self.alias[from_][i]
40
- else i
40
+ f"{i} as {self.alias[from_][i]}" if i in self.alias[from_] and i != self.alias[from_][i] else i
41
41
  for i in sorted(imports)
42
42
  ]
43
43
 
44
- def create_line(self, from_: Optional[str], imports: Set[str]) -> str:
44
+ def create_line(self, from_: str | None, imports: set[str]) -> str:
45
45
  if from_:
46
- return f'from {from_} import {", ".join(self._set_alias(from_, imports))}'
47
- return '\n'.join(f'import {i}' for i in self._set_alias(from_, imports))
46
+ return f"from {from_} import {', '.join(self._set_alias(from_, imports))}"
47
+ return "\n".join(f"import {i}" for i in self._set_alias(from_, imports))
48
48
 
49
49
  def dump(self) -> str:
50
- return '\n'.join(
51
- self.create_line(from_, imports) for from_, imports in self.items()
52
- )
50
+ return "\n".join(starmap(self.create_line, self.items()))
53
51
 
54
- def append(self, imports: Union[Import, Iterable[Import], None]) -> None:
52
+ def append(self, imports: Import | Iterable[Import] | None) -> None:
55
53
  if imports:
56
54
  if isinstance(imports, Import):
57
55
  imports = [imports]
58
56
  for import_ in imports:
59
57
  if import_.reference_path:
60
58
  self.reference_paths[import_.reference_path] = import_
61
- if '.' in import_.import_:
59
+ if "." in import_.import_:
62
60
  self[None].add(import_.import_)
63
- self.counter[(None, import_.import_)] += 1
61
+ self.counter[None, import_.import_] += 1
64
62
  else:
65
63
  self[import_.from_].add(import_.import_)
66
- self.counter[(import_.from_, import_.import_)] += 1
64
+ self.counter[import_.from_, import_.import_] += 1
67
65
  if import_.alias:
68
66
  self.alias[import_.from_][import_.import_] = import_.alias
69
67
 
70
- def remove(self, imports: Union[Import, Iterable[Import]]) -> None:
68
+ def remove(self, imports: Import | Iterable[Import]) -> None:
71
69
  if isinstance(imports, Import): # pragma: no cover
72
70
  imports = [imports]
73
71
  for import_ in imports:
74
- if '.' in import_.import_: # pragma: no cover
75
- self.counter[(None, import_.import_)] -= 1
76
- if self.counter[(None, import_.import_)] == 0: # pragma: no cover
72
+ if "." in import_.import_: # pragma: no cover
73
+ self.counter[None, import_.import_] -= 1
74
+ if self.counter[None, import_.import_] == 0: # pragma: no cover
77
75
  self[None].remove(import_.import_)
78
76
  if not self[None]:
79
77
  del self[None]
80
78
  else:
81
- self.counter[(import_.from_, import_.import_)] -= 1 # pragma: no cover
82
- if (
83
- self.counter[(import_.from_, import_.import_)] == 0
84
- ): # pragma: no cover
79
+ self.counter[import_.from_, import_.import_] -= 1 # pragma: no cover
80
+ if self.counter[import_.from_, import_.import_] == 0: # pragma: no cover
85
81
  self[import_.from_].remove(import_.import_)
86
82
  if not self[import_.from_]:
87
83
  del self[import_.from_]
@@ -95,33 +91,31 @@ class Imports(DefaultDict[Optional[str], Set[str]]):
95
91
  self.remove(self.reference_paths[reference_path])
96
92
 
97
93
 
98
- IMPORT_ANNOTATED = Import.from_full_path('typing.Annotated')
99
- IMPORT_ANNOTATED_BACKPORT = Import.from_full_path('typing_extensions.Annotated')
100
- IMPORT_ANY = Import.from_full_path('typing.Any')
101
- IMPORT_LIST = Import.from_full_path('typing.List')
102
- IMPORT_SET = Import.from_full_path('typing.Set')
103
- IMPORT_UNION = Import.from_full_path('typing.Union')
104
- IMPORT_OPTIONAL = Import.from_full_path('typing.Optional')
105
- IMPORT_LITERAL = Import.from_full_path('typing.Literal')
106
- IMPORT_TYPE_ALIAS = Import.from_full_path('typing.TypeAlias')
107
- IMPORT_LITERAL_BACKPORT = Import.from_full_path('typing_extensions.Literal')
108
- IMPORT_SEQUENCE = Import.from_full_path('typing.Sequence')
109
- IMPORT_FROZEN_SET = Import.from_full_path('typing.FrozenSet')
110
- IMPORT_MAPPING = Import.from_full_path('typing.Mapping')
111
- IMPORT_ABC_SEQUENCE = Import.from_full_path('collections.abc.Sequence')
112
- IMPORT_ABC_SET = Import.from_full_path('collections.abc.Set')
113
- IMPORT_ABC_MAPPING = Import.from_full_path('collections.abc.Mapping')
114
- IMPORT_ENUM = Import.from_full_path('enum.Enum')
115
- IMPORT_ANNOTATIONS = Import.from_full_path('__future__.annotations')
116
- IMPORT_DICT = Import.from_full_path('typing.Dict')
117
- IMPORT_DECIMAL = Import.from_full_path('decimal.Decimal')
118
- IMPORT_DATE = Import.from_full_path('datetime.date')
119
- IMPORT_DATETIME = Import.from_full_path('datetime.datetime')
120
- IMPORT_TIMEDELTA = Import.from_full_path('datetime.timedelta')
121
- IMPORT_PATH = Import.from_full_path('pathlib.Path')
122
- IMPORT_TIME = Import.from_full_path('datetime.time')
123
- IMPORT_UUID = Import.from_full_path('uuid.UUID')
124
- IMPORT_PENDULUM_DATE = Import.from_full_path('pendulum.Date')
125
- IMPORT_PENDULUM_DATETIME = Import.from_full_path('pendulum.DateTime')
126
- IMPORT_PENDULUM_DURATION = Import.from_full_path('pendulum.Duration')
127
- IMPORT_PENDULUM_TIME = Import.from_full_path('pendulum.Time')
94
+ IMPORT_ANNOTATED = Import.from_full_path("typing.Annotated")
95
+ IMPORT_ANY = Import.from_full_path("typing.Any")
96
+ IMPORT_LIST = Import.from_full_path("typing.List")
97
+ IMPORT_SET = Import.from_full_path("typing.Set")
98
+ IMPORT_UNION = Import.from_full_path("typing.Union")
99
+ IMPORT_OPTIONAL = Import.from_full_path("typing.Optional")
100
+ IMPORT_LITERAL = Import.from_full_path("typing.Literal")
101
+ IMPORT_TYPE_ALIAS = Import.from_full_path("typing.TypeAlias")
102
+ IMPORT_SEQUENCE = Import.from_full_path("typing.Sequence")
103
+ IMPORT_FROZEN_SET = Import.from_full_path("typing.FrozenSet")
104
+ IMPORT_MAPPING = Import.from_full_path("typing.Mapping")
105
+ IMPORT_ABC_SEQUENCE = Import.from_full_path("collections.abc.Sequence")
106
+ IMPORT_ABC_SET = Import.from_full_path("collections.abc.Set")
107
+ IMPORT_ABC_MAPPING = Import.from_full_path("collections.abc.Mapping")
108
+ IMPORT_ENUM = Import.from_full_path("enum.Enum")
109
+ IMPORT_ANNOTATIONS = Import.from_full_path("__future__.annotations")
110
+ IMPORT_DICT = Import.from_full_path("typing.Dict")
111
+ IMPORT_DECIMAL = Import.from_full_path("decimal.Decimal")
112
+ IMPORT_DATE = Import.from_full_path("datetime.date")
113
+ IMPORT_DATETIME = Import.from_full_path("datetime.datetime")
114
+ IMPORT_TIMEDELTA = Import.from_full_path("datetime.timedelta")
115
+ IMPORT_PATH = Import.from_full_path("pathlib.Path")
116
+ IMPORT_TIME = Import.from_full_path("datetime.time")
117
+ IMPORT_UUID = Import.from_full_path("uuid.UUID")
118
+ IMPORT_PENDULUM_DATE = Import.from_full_path("pendulum.Date")
119
+ IMPORT_PENDULUM_DATETIME = Import.from_full_path("pendulum.DateTime")
120
+ IMPORT_PENDULUM_DURATION = Import.from_full_path("pendulum.Duration")
121
+ IMPORT_PENDULUM_TIME = Import.from_full_path("pendulum.Time")