Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/black/mode.py: 80%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""Data structures configuring Black behavior.
3Mostly around Python language feature support per version and Black configuration
4chosen by the user.
5"""
7from dataclasses import dataclass, field
8from enum import Enum, auto
9from hashlib import sha256
10from operator import attrgetter
11from typing import Final
13from black.const import DEFAULT_LINE_LENGTH
16class TargetVersion(Enum):
17 PY33 = 3
18 PY34 = 4
19 PY35 = 5
20 PY36 = 6
21 PY37 = 7
22 PY38 = 8
23 PY39 = 9
24 PY310 = 10
25 PY311 = 11
26 PY312 = 12
27 PY313 = 13
28 PY314 = 14
29 PY315 = 15
31 def pretty(self) -> str:
32 assert self.name[:2] == "PY"
33 return f"Python {self.name[2]}.{self.name[3:]}"
36class Feature(Enum):
37 F_STRINGS = 2
38 NUMERIC_UNDERSCORES = 3
39 TRAILING_COMMA_IN_CALL = 4
40 TRAILING_COMMA_IN_DEF = 5
41 # The following two feature-flags are mutually exclusive, and exactly one should be
42 # set for every version of python.
43 ASYNC_IDENTIFIERS = 6
44 ASYNC_KEYWORDS = 7
45 ASSIGNMENT_EXPRESSIONS = 8
46 POS_ONLY_ARGUMENTS = 9
47 RELAXED_DECORATORS = 10
48 PATTERN_MATCHING = 11
49 UNPACKING_ON_FLOW = 12
50 ANN_ASSIGN_EXTENDED_RHS = 13
51 EXCEPT_STAR = 14
52 VARIADIC_GENERICS = 15
53 DEBUG_F_STRINGS = 16
54 PARENTHESIZED_CONTEXT_MANAGERS = 17
55 TYPE_PARAMS = 18
56 # FSTRING_PARSING = 19 # unused
57 TYPE_PARAM_DEFAULTS = 20
58 UNPARENTHESIZED_EXCEPT_TYPES = 21
59 T_STRINGS = 22
60 LAZY_IMPORTS = 23
61 UNPACKING_IN_COMPREHENSIONS = 24
62 FORCE_OPTIONAL_PARENTHESES = 50
64 # __future__ flags
65 FUTURE_ANNOTATIONS = 51
68FUTURE_FLAG_TO_FEATURE: Final = {
69 "annotations": Feature.FUTURE_ANNOTATIONS,
70}
73VERSION_TO_FEATURES: dict[TargetVersion, set[Feature]] = {
74 TargetVersion.PY33: {Feature.ASYNC_IDENTIFIERS},
75 TargetVersion.PY34: {Feature.ASYNC_IDENTIFIERS},
76 TargetVersion.PY35: {Feature.TRAILING_COMMA_IN_CALL, Feature.ASYNC_IDENTIFIERS},
77 TargetVersion.PY36: {
78 Feature.F_STRINGS,
79 Feature.NUMERIC_UNDERSCORES,
80 Feature.TRAILING_COMMA_IN_CALL,
81 Feature.TRAILING_COMMA_IN_DEF,
82 Feature.ASYNC_IDENTIFIERS,
83 },
84 TargetVersion.PY37: {
85 Feature.F_STRINGS,
86 Feature.NUMERIC_UNDERSCORES,
87 Feature.TRAILING_COMMA_IN_CALL,
88 Feature.TRAILING_COMMA_IN_DEF,
89 Feature.ASYNC_KEYWORDS,
90 Feature.FUTURE_ANNOTATIONS,
91 },
92 TargetVersion.PY38: {
93 Feature.F_STRINGS,
94 Feature.DEBUG_F_STRINGS,
95 Feature.NUMERIC_UNDERSCORES,
96 Feature.TRAILING_COMMA_IN_CALL,
97 Feature.TRAILING_COMMA_IN_DEF,
98 Feature.ASYNC_KEYWORDS,
99 Feature.FUTURE_ANNOTATIONS,
100 Feature.ASSIGNMENT_EXPRESSIONS,
101 Feature.POS_ONLY_ARGUMENTS,
102 Feature.UNPACKING_ON_FLOW,
103 Feature.ANN_ASSIGN_EXTENDED_RHS,
104 },
105 TargetVersion.PY39: {
106 Feature.F_STRINGS,
107 Feature.DEBUG_F_STRINGS,
108 Feature.NUMERIC_UNDERSCORES,
109 Feature.TRAILING_COMMA_IN_CALL,
110 Feature.TRAILING_COMMA_IN_DEF,
111 Feature.ASYNC_KEYWORDS,
112 Feature.FUTURE_ANNOTATIONS,
113 Feature.ASSIGNMENT_EXPRESSIONS,
114 Feature.RELAXED_DECORATORS,
115 Feature.POS_ONLY_ARGUMENTS,
116 Feature.UNPACKING_ON_FLOW,
117 Feature.ANN_ASSIGN_EXTENDED_RHS,
118 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
119 },
120 TargetVersion.PY310: {
121 Feature.F_STRINGS,
122 Feature.DEBUG_F_STRINGS,
123 Feature.NUMERIC_UNDERSCORES,
124 Feature.TRAILING_COMMA_IN_CALL,
125 Feature.TRAILING_COMMA_IN_DEF,
126 Feature.ASYNC_KEYWORDS,
127 Feature.FUTURE_ANNOTATIONS,
128 Feature.ASSIGNMENT_EXPRESSIONS,
129 Feature.RELAXED_DECORATORS,
130 Feature.POS_ONLY_ARGUMENTS,
131 Feature.UNPACKING_ON_FLOW,
132 Feature.ANN_ASSIGN_EXTENDED_RHS,
133 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
134 Feature.PATTERN_MATCHING,
135 },
136 TargetVersion.PY311: {
137 Feature.F_STRINGS,
138 Feature.DEBUG_F_STRINGS,
139 Feature.NUMERIC_UNDERSCORES,
140 Feature.TRAILING_COMMA_IN_CALL,
141 Feature.TRAILING_COMMA_IN_DEF,
142 Feature.ASYNC_KEYWORDS,
143 Feature.FUTURE_ANNOTATIONS,
144 Feature.ASSIGNMENT_EXPRESSIONS,
145 Feature.RELAXED_DECORATORS,
146 Feature.POS_ONLY_ARGUMENTS,
147 Feature.UNPACKING_ON_FLOW,
148 Feature.ANN_ASSIGN_EXTENDED_RHS,
149 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
150 Feature.PATTERN_MATCHING,
151 Feature.EXCEPT_STAR,
152 Feature.VARIADIC_GENERICS,
153 },
154 TargetVersion.PY312: {
155 Feature.F_STRINGS,
156 Feature.DEBUG_F_STRINGS,
157 Feature.NUMERIC_UNDERSCORES,
158 Feature.TRAILING_COMMA_IN_CALL,
159 Feature.TRAILING_COMMA_IN_DEF,
160 Feature.ASYNC_KEYWORDS,
161 Feature.FUTURE_ANNOTATIONS,
162 Feature.ASSIGNMENT_EXPRESSIONS,
163 Feature.RELAXED_DECORATORS,
164 Feature.POS_ONLY_ARGUMENTS,
165 Feature.UNPACKING_ON_FLOW,
166 Feature.ANN_ASSIGN_EXTENDED_RHS,
167 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
168 Feature.PATTERN_MATCHING,
169 Feature.EXCEPT_STAR,
170 Feature.VARIADIC_GENERICS,
171 Feature.TYPE_PARAMS,
172 },
173 TargetVersion.PY313: {
174 Feature.F_STRINGS,
175 Feature.DEBUG_F_STRINGS,
176 Feature.NUMERIC_UNDERSCORES,
177 Feature.TRAILING_COMMA_IN_CALL,
178 Feature.TRAILING_COMMA_IN_DEF,
179 Feature.ASYNC_KEYWORDS,
180 Feature.FUTURE_ANNOTATIONS,
181 Feature.ASSIGNMENT_EXPRESSIONS,
182 Feature.RELAXED_DECORATORS,
183 Feature.POS_ONLY_ARGUMENTS,
184 Feature.UNPACKING_ON_FLOW,
185 Feature.ANN_ASSIGN_EXTENDED_RHS,
186 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
187 Feature.PATTERN_MATCHING,
188 Feature.EXCEPT_STAR,
189 Feature.VARIADIC_GENERICS,
190 Feature.TYPE_PARAMS,
191 Feature.TYPE_PARAM_DEFAULTS,
192 },
193 TargetVersion.PY314: {
194 Feature.F_STRINGS,
195 Feature.DEBUG_F_STRINGS,
196 Feature.NUMERIC_UNDERSCORES,
197 Feature.TRAILING_COMMA_IN_CALL,
198 Feature.TRAILING_COMMA_IN_DEF,
199 Feature.ASYNC_KEYWORDS,
200 Feature.FUTURE_ANNOTATIONS,
201 Feature.ASSIGNMENT_EXPRESSIONS,
202 Feature.RELAXED_DECORATORS,
203 Feature.POS_ONLY_ARGUMENTS,
204 Feature.UNPACKING_ON_FLOW,
205 Feature.ANN_ASSIGN_EXTENDED_RHS,
206 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
207 Feature.PATTERN_MATCHING,
208 Feature.EXCEPT_STAR,
209 Feature.VARIADIC_GENERICS,
210 Feature.TYPE_PARAMS,
211 Feature.TYPE_PARAM_DEFAULTS,
212 Feature.UNPARENTHESIZED_EXCEPT_TYPES,
213 Feature.T_STRINGS,
214 },
215 TargetVersion.PY315: {
216 Feature.F_STRINGS,
217 Feature.DEBUG_F_STRINGS,
218 Feature.NUMERIC_UNDERSCORES,
219 Feature.TRAILING_COMMA_IN_CALL,
220 Feature.TRAILING_COMMA_IN_DEF,
221 Feature.ASYNC_KEYWORDS,
222 Feature.FUTURE_ANNOTATIONS,
223 Feature.ASSIGNMENT_EXPRESSIONS,
224 Feature.RELAXED_DECORATORS,
225 Feature.POS_ONLY_ARGUMENTS,
226 Feature.UNPACKING_ON_FLOW,
227 Feature.ANN_ASSIGN_EXTENDED_RHS,
228 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
229 Feature.PATTERN_MATCHING,
230 Feature.EXCEPT_STAR,
231 Feature.VARIADIC_GENERICS,
232 Feature.TYPE_PARAMS,
233 Feature.TYPE_PARAM_DEFAULTS,
234 Feature.UNPARENTHESIZED_EXCEPT_TYPES,
235 Feature.T_STRINGS,
236 Feature.LAZY_IMPORTS,
237 Feature.UNPACKING_IN_COMPREHENSIONS,
238 },
239}
242def supports_feature(target_versions: set[TargetVersion], feature: Feature) -> bool:
243 if not target_versions:
244 raise ValueError("At least one target Python version must be specified.")
246 return all(feature in VERSION_TO_FEATURES[version] for version in target_versions)
249class Preview(Enum):
250 """Individual preview style features."""
252 # NOTE: string_processing requires wrap_long_dict_values_in_parens
253 # for https://github.com/psf/black/issues/3117 to be fixed.
254 string_processing = auto()
255 hug_parens_with_braces_and_square_brackets = auto()
256 wrap_comprehension_in = auto()
257 simplify_power_operator_hugging = auto()
258 wrap_long_dict_values_in_parens = auto()
259 fix_if_guard_explosion_in_case_statement = auto()
260 pyi_overload_group_blank_lines = auto()
261 fix_unnecessary_parens_in_indexed_assignment = auto()
262 pyi_blank_line_before_decorated_class = auto()
263 pyi_blank_line_after_function_docstring = auto()
264 hug_comparator = auto()
265 parenthesize_tuple_in_yield = auto()
266 fmt_off_class_blank_lines = auto()
269UNSTABLE_FEATURES: set[Preview] = {
270 # Many issues, see summary in https://github.com/psf/black/issues/4208
271 Preview.string_processing,
272 # See issue #4036 (crash), #4098, #4099 (proposed tweaks)
273 Preview.hug_parens_with_braces_and_square_brackets,
274}
277_MAX_CACHE_KEY_PART_LENGTH: Final = 32
280@dataclass
281class Mode:
282 target_versions: set[TargetVersion] = field(default_factory=set)
283 line_length: int = DEFAULT_LINE_LENGTH
284 string_normalization: bool = True
285 is_pyi: bool = False
286 is_ipynb: bool = False
287 skip_source_first_line: bool = False
288 magic_trailing_comma: bool = True
289 python_cell_magics: set[str] = field(default_factory=set)
290 preview: bool = False
291 unstable: bool = False
292 enabled_features: set[Preview] = field(default_factory=set)
294 def __contains__(self, feature: Preview) -> bool:
295 """
296 Provide `Preview.FEATURE in Mode` syntax that mirrors the ``preview`` flag.
298 In unstable mode, all features are enabled. In preview mode, all features
299 except those in UNSTABLE_FEATURES are enabled. Any features in
300 `self.enabled_features` are also enabled.
301 """
302 if self.unstable:
303 return True
304 if feature in self.enabled_features:
305 return True
306 return self.preview and feature not in UNSTABLE_FEATURES
308 def get_cache_key(self) -> str:
309 if self.target_versions:
310 version_str = ",".join(
311 str(version.value)
312 for version in sorted(self.target_versions, key=attrgetter("value"))
313 )
314 else:
315 version_str = "-"
316 if len(version_str) > _MAX_CACHE_KEY_PART_LENGTH:
317 version_str = sha256(version_str.encode()).hexdigest()[
318 :_MAX_CACHE_KEY_PART_LENGTH
319 ]
320 features_and_magics = (
321 ",".join(sorted(f.name for f in self.enabled_features))
322 + "@"
323 + ",".join(sorted(self.python_cell_magics))
324 )
325 features_and_magics = sha256(features_and_magics.encode()).hexdigest()[
326 :_MAX_CACHE_KEY_PART_LENGTH
327 ]
328 parts = [
329 version_str,
330 str(self.line_length),
331 str(int(self.string_normalization)),
332 str(int(self.is_pyi)),
333 str(int(self.is_ipynb)),
334 str(int(self.skip_source_first_line)),
335 str(int(self.magic_trailing_comma)),
336 str(int(self.preview)),
337 str(int(self.unstable)),
338 features_and_magics,
339 ]
340 return ".".join(parts)
342 def __hash__(self) -> int:
343 return hash((
344 frozenset(self.target_versions),
345 self.line_length,
346 self.string_normalization,
347 self.is_pyi,
348 self.is_ipynb,
349 self.skip_source_first_line,
350 self.magic_trailing_comma,
351 frozenset(self.python_cell_magics),
352 self.preview,
353 self.unstable,
354 frozenset(self.enabled_features),
355 ))