88
99import subprocess # noqa: S404
1010from enum import Enum
11- from functools import cached_property
11+ from functools import cached_property , lru_cache
1212from importlib import import_module
1313from pathlib import Path
1414from typing import TYPE_CHECKING , Any
1515from warnings import warn
1616
17- import black
18- import isort
19-
2017from datamodel_code_generator .util import load_toml
2118
2219if TYPE_CHECKING :
2320 from collections .abc import Sequence
24- try :
25- import black .mode
26- except ImportError : # pragma: no cover
27- black .mode = None
21+
22+
23+ @lru_cache (maxsize = 1 )
24+ def _get_black () -> Any :
25+ import black as _black # noqa: PLC0415
26+
27+ return _black
28+
29+
30+ @lru_cache (maxsize = 1 )
31+ def _get_black_mode () -> Any : # pragma: no cover
32+ black = _get_black ()
33+ try :
34+ import black .mode # noqa: PLC0415
35+ except ImportError :
36+ return None
37+ else :
38+ return black .mode
39+
40+
41+ @lru_cache (maxsize = 1 )
42+ def _get_isort () -> Any :
43+ import isort as _isort # noqa: PLC0415
44+
45+ return _isort
2846
2947
3048class DatetimeClassType (Enum ):
@@ -91,16 +109,19 @@ def has_strenum(self) -> bool:
91109PythonVersionMin = PythonVersion .PY_39
92110
93111
94- BLACK_PYTHON_VERSION : dict [PythonVersion , black .TargetVersion ] = {
95- v : getattr (black .TargetVersion , f"PY{ v .name .split ('_' )[- 1 ]} " )
96- for v in PythonVersion
97- if hasattr (black .TargetVersion , f"PY{ v .name .split ('_' )[- 1 ]} " )
98- }
112+ @lru_cache (maxsize = 1 )
113+ def _get_black_python_version_map () -> dict [PythonVersion , Any ]:
114+ black = _get_black ()
115+ return {
116+ v : getattr (black .TargetVersion , f"PY{ v .name .split ('_' )[- 1 ]} " )
117+ for v in PythonVersion
118+ if hasattr (black .TargetVersion , f"PY{ v .name .split ('_' )[- 1 ]} " )
119+ }
99120
100121
101122def is_supported_in_black (python_version : PythonVersion ) -> bool : # pragma: no cover
102123 """Check if a Python version is supported by the installed black version."""
103- return python_version in BLACK_PYTHON_VERSION
124+ return python_version in _get_black_python_version_map ()
104125
105126
106127def black_find_project_root (sources : Sequence [Path ]) -> Path :
@@ -153,6 +174,10 @@ def __init__( # noqa: PLR0912, PLR0913, PLR0917
153174 else :
154175 config = {}
155176
177+ black = _get_black ()
178+ black_mode = _get_black_mode ()
179+ isort = _get_isort ()
180+
156181 black_kwargs : dict [str , Any ] = {}
157182 if wrap_string_literal is not None :
158183 experimental_string_processing = wrap_string_literal
@@ -175,10 +200,10 @@ def __init__( # noqa: PLR0912, PLR0913, PLR0917
175200 elif experimental_string_processing :
176201 black_kwargs ["preview" ] = True
177202 black_kwargs ["unstable" ] = config .get ("unstable" , False )
178- black_kwargs ["enabled_features" ] = {black . mode .Preview .string_processing }
203+ black_kwargs ["enabled_features" ] = {black_mode .Preview .string_processing }
179204
180205 self .black_mode = black .FileMode (
181- target_versions = {BLACK_PYTHON_VERSION [python_version ]},
206+ target_versions = {_get_black_python_version_map () [python_version ]},
182207 line_length = config .get ("line-length" , black .DEFAULT_LINE_LENGTH ),
183208 string_normalization = not skip_string_normalization or not config .get ("skip-string-normalization" , True ),
184209 ** black_kwargs ,
@@ -246,6 +271,7 @@ def format_code(
246271
247272 def apply_black (self , code : str ) -> str :
248273 """Format code using black."""
274+ black = _get_black ()
249275 return black .format_str (
250276 code ,
251277 mode = self .black_mode ,
@@ -271,27 +297,16 @@ def apply_ruff_formatter(self, code: str) -> str:
271297 )
272298 return result .stdout .decode (self .encoding )
273299
274- if TYPE_CHECKING :
275-
276- def apply_isort (self , code : str ) -> str :
277- """Sort imports using isort."""
278- ...
279-
280- elif isort .__version__ .startswith ("4." ):
281-
282- def apply_isort (self , code : str ) -> str :
283- """Sort imports using isort v4."""
300+ def apply_isort (self , code : str ) -> str :
301+ """Sort imports using isort."""
302+ isort = _get_isort ()
303+ if self .isort_config is None : # pragma: no cover
284304 return isort .SortImports (
285305 file_contents = code ,
286306 settings_path = self .settings_path ,
287307 ** self .isort_config_kwargs ,
288308 ).output
289-
290- else :
291-
292- def apply_isort (self , code : str ) -> str :
293- """Sort imports using isort v5+."""
294- return isort .code (code , config = self .isort_config )
309+ return isort .code (code , config = self .isort_config )
295310
296311
297312class CustomCodeFormatter :
0 commit comments