Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/black/mode.py: 83%
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 UNPARENTHESIZED_WALRUS_IN_SETS = 25
63 FORCE_OPTIONAL_PARENTHESES = 50
65 # __future__ flags
66 FUTURE_ANNOTATIONS = 51
69FUTURE_FLAG_TO_FEATURE: Final = {
70 "annotations": Feature.FUTURE_ANNOTATIONS,
71}
74VERSION_TO_FEATURES: dict[TargetVersion, set[Feature]] = {
75 TargetVersion.PY33: {Feature.ASYNC_IDENTIFIERS},
76 TargetVersion.PY34: {Feature.ASYNC_IDENTIFIERS},
77 TargetVersion.PY35: {Feature.TRAILING_COMMA_IN_CALL, Feature.ASYNC_IDENTIFIERS},
78 TargetVersion.PY36: {
79 Feature.F_STRINGS,
80 Feature.NUMERIC_UNDERSCORES,
81 Feature.TRAILING_COMMA_IN_CALL,
82 Feature.TRAILING_COMMA_IN_DEF,
83 Feature.ASYNC_IDENTIFIERS,
84 },
85 TargetVersion.PY37: {
86 Feature.F_STRINGS,
87 Feature.NUMERIC_UNDERSCORES,
88 Feature.TRAILING_COMMA_IN_CALL,
89 Feature.TRAILING_COMMA_IN_DEF,
90 Feature.ASYNC_KEYWORDS,
91 Feature.FUTURE_ANNOTATIONS,
92 },
93 TargetVersion.PY38: {
94 Feature.F_STRINGS,
95 Feature.DEBUG_F_STRINGS,
96 Feature.NUMERIC_UNDERSCORES,
97 Feature.TRAILING_COMMA_IN_CALL,
98 Feature.TRAILING_COMMA_IN_DEF,
99 Feature.ASYNC_KEYWORDS,
100 Feature.FUTURE_ANNOTATIONS,
101 Feature.ASSIGNMENT_EXPRESSIONS,
102 Feature.POS_ONLY_ARGUMENTS,
103 Feature.UNPACKING_ON_FLOW,
104 Feature.ANN_ASSIGN_EXTENDED_RHS,
105 },
106 TargetVersion.PY39: {
107 Feature.F_STRINGS,
108 Feature.DEBUG_F_STRINGS,
109 Feature.NUMERIC_UNDERSCORES,
110 Feature.TRAILING_COMMA_IN_CALL,
111 Feature.TRAILING_COMMA_IN_DEF,
112 Feature.ASYNC_KEYWORDS,
113 Feature.FUTURE_ANNOTATIONS,
114 Feature.ASSIGNMENT_EXPRESSIONS,
115 Feature.RELAXED_DECORATORS,
116 Feature.POS_ONLY_ARGUMENTS,
117 Feature.UNPACKING_ON_FLOW,
118 Feature.ANN_ASSIGN_EXTENDED_RHS,
119 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
120 },
121 TargetVersion.PY310: {
122 Feature.F_STRINGS,
123 Feature.DEBUG_F_STRINGS,
124 Feature.NUMERIC_UNDERSCORES,
125 Feature.TRAILING_COMMA_IN_CALL,
126 Feature.TRAILING_COMMA_IN_DEF,
127 Feature.ASYNC_KEYWORDS,
128 Feature.FUTURE_ANNOTATIONS,
129 Feature.ASSIGNMENT_EXPRESSIONS,
130 Feature.RELAXED_DECORATORS,
131 Feature.POS_ONLY_ARGUMENTS,
132 Feature.UNPACKING_ON_FLOW,
133 Feature.ANN_ASSIGN_EXTENDED_RHS,
134 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
135 Feature.UNPARENTHESIZED_WALRUS_IN_SETS,
136 Feature.PATTERN_MATCHING,
137 },
138 TargetVersion.PY311: {
139 Feature.F_STRINGS,
140 Feature.DEBUG_F_STRINGS,
141 Feature.NUMERIC_UNDERSCORES,
142 Feature.TRAILING_COMMA_IN_CALL,
143 Feature.TRAILING_COMMA_IN_DEF,
144 Feature.ASYNC_KEYWORDS,
145 Feature.FUTURE_ANNOTATIONS,
146 Feature.ASSIGNMENT_EXPRESSIONS,
147 Feature.RELAXED_DECORATORS,
148 Feature.POS_ONLY_ARGUMENTS,
149 Feature.UNPACKING_ON_FLOW,
150 Feature.ANN_ASSIGN_EXTENDED_RHS,
151 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
152 Feature.UNPARENTHESIZED_WALRUS_IN_SETS,
153 Feature.PATTERN_MATCHING,
154 Feature.EXCEPT_STAR,
155 Feature.VARIADIC_GENERICS,
156 },
157 TargetVersion.PY312: {
158 Feature.F_STRINGS,
159 Feature.DEBUG_F_STRINGS,
160 Feature.NUMERIC_UNDERSCORES,
161 Feature.TRAILING_COMMA_IN_CALL,
162 Feature.TRAILING_COMMA_IN_DEF,
163 Feature.ASYNC_KEYWORDS,
164 Feature.FUTURE_ANNOTATIONS,
165 Feature.ASSIGNMENT_EXPRESSIONS,
166 Feature.RELAXED_DECORATORS,
167 Feature.POS_ONLY_ARGUMENTS,
168 Feature.UNPACKING_ON_FLOW,
169 Feature.ANN_ASSIGN_EXTENDED_RHS,
170 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
171 Feature.UNPARENTHESIZED_WALRUS_IN_SETS,
172 Feature.PATTERN_MATCHING,
173 Feature.EXCEPT_STAR,
174 Feature.VARIADIC_GENERICS,
175 Feature.TYPE_PARAMS,
176 },
177 TargetVersion.PY313: {
178 Feature.F_STRINGS,
179 Feature.DEBUG_F_STRINGS,
180 Feature.NUMERIC_UNDERSCORES,
181 Feature.TRAILING_COMMA_IN_CALL,
182 Feature.TRAILING_COMMA_IN_DEF,
183 Feature.ASYNC_KEYWORDS,
184 Feature.FUTURE_ANNOTATIONS,
185 Feature.ASSIGNMENT_EXPRESSIONS,
186 Feature.RELAXED_DECORATORS,
187 Feature.POS_ONLY_ARGUMENTS,
188 Feature.UNPACKING_ON_FLOW,
189 Feature.ANN_ASSIGN_EXTENDED_RHS,
190 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
191 Feature.UNPARENTHESIZED_WALRUS_IN_SETS,
192 Feature.PATTERN_MATCHING,
193 Feature.EXCEPT_STAR,
194 Feature.VARIADIC_GENERICS,
195 Feature.TYPE_PARAMS,
196 Feature.TYPE_PARAM_DEFAULTS,
197 },
198 TargetVersion.PY314: {
199 Feature.F_STRINGS,
200 Feature.DEBUG_F_STRINGS,
201 Feature.NUMERIC_UNDERSCORES,
202 Feature.TRAILING_COMMA_IN_CALL,
203 Feature.TRAILING_COMMA_IN_DEF,
204 Feature.ASYNC_KEYWORDS,
205 Feature.FUTURE_ANNOTATIONS,
206 Feature.ASSIGNMENT_EXPRESSIONS,
207 Feature.RELAXED_DECORATORS,
208 Feature.POS_ONLY_ARGUMENTS,
209 Feature.UNPACKING_ON_FLOW,
210 Feature.ANN_ASSIGN_EXTENDED_RHS,
211 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
212 Feature.UNPARENTHESIZED_WALRUS_IN_SETS,
213 Feature.PATTERN_MATCHING,
214 Feature.EXCEPT_STAR,
215 Feature.VARIADIC_GENERICS,
216 Feature.TYPE_PARAMS,
217 Feature.TYPE_PARAM_DEFAULTS,
218 Feature.UNPARENTHESIZED_EXCEPT_TYPES,
219 Feature.T_STRINGS,
220 },
221 TargetVersion.PY315: {
222 Feature.F_STRINGS,
223 Feature.DEBUG_F_STRINGS,
224 Feature.NUMERIC_UNDERSCORES,
225 Feature.TRAILING_COMMA_IN_CALL,
226 Feature.TRAILING_COMMA_IN_DEF,
227 Feature.ASYNC_KEYWORDS,
228 Feature.FUTURE_ANNOTATIONS,
229 Feature.ASSIGNMENT_EXPRESSIONS,
230 Feature.RELAXED_DECORATORS,
231 Feature.POS_ONLY_ARGUMENTS,
232 Feature.UNPACKING_ON_FLOW,
233 Feature.ANN_ASSIGN_EXTENDED_RHS,
234 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
235 Feature.UNPARENTHESIZED_WALRUS_IN_SETS,
236 Feature.PATTERN_MATCHING,
237 Feature.EXCEPT_STAR,
238 Feature.VARIADIC_GENERICS,
239 Feature.TYPE_PARAMS,
240 Feature.TYPE_PARAM_DEFAULTS,
241 Feature.UNPARENTHESIZED_EXCEPT_TYPES,
242 Feature.T_STRINGS,
243 Feature.LAZY_IMPORTS,
244 Feature.UNPACKING_IN_COMPREHENSIONS,
245 },
246}
249def supports_feature(target_versions: set[TargetVersion], feature: Feature) -> bool:
250 if not target_versions:
251 raise ValueError("At least one target Python version must be specified.")
253 return all(feature in VERSION_TO_FEATURES[version] for version in target_versions)
256class Preview(Enum):
257 """Individual preview style features."""
259 # NOTE: string_processing requires wrap_long_dict_values_in_parens
260 # for https://github.com/psf/black/issues/3117 to be fixed.
261 string_processing = auto()
262 hug_parens_with_braces_and_square_brackets = auto()
263 wrap_comprehension_in = auto()
264 simplify_power_operator_hugging = auto()
265 wrap_long_dict_values_in_parens = auto()
266 fix_if_guard_explosion_in_case_statement = auto()
267 pyi_overload_group_blank_lines = auto()
268 fix_unnecessary_parens_in_indexed_assignment = auto()
269 pyi_blank_line_before_decorated_class = auto()
270 pyi_blank_line_after_function_docstring = auto()
271 hug_comparator = auto()
272 parenthesize_tuple_in_yield = auto()
273 fmt_off_class_blank_lines = auto()
274 remove_redundant_generator_parentheses = auto()
275 symmetric_collection_operations = auto()
276 normalize_tstring_prefix = auto()
277 remove_redundant_list_parentheses = auto()
278 remove_redundant_unpacking_parentheses = auto()
279 remove_redundant_subscript_parentheses = auto()
280 fix_magic_trailing_comma_trailer_split = auto()
281 keep_dict_keys_with_operators = auto()
282 blank_line_after_stub_method = auto()
283 keep_commented_expressions_together = auto()
284 avoid_parens_for_unbreakable_rhs_in_assignments = auto()
285 parenthesize_expressions_with_comments = auto()
286 keep_trailers_on_bracket_comment_overflow = auto()
287 remove_redundant_comparison_parentheses = auto()
288 remove_redundant_top_level_parentheses = auto()
291UNSTABLE_FEATURES: set[Preview] = {
292 # Many issues, see summary in https://github.com/psf/black/issues/4208
293 Preview.string_processing,
294 # See issue #4036 (crash), #4098, #4099 (proposed tweaks)
295 Preview.hug_parens_with_braces_and_square_brackets,
296}
299_MAX_CACHE_KEY_PART_LENGTH: Final = 32
302@dataclass
303class Mode:
304 target_versions: set[TargetVersion] = field(default_factory=set)
305 line_length: int = DEFAULT_LINE_LENGTH
306 string_normalization: bool = True
307 is_pyi: bool = False
308 is_ipynb: bool = False
309 skip_source_first_line: bool = False
310 magic_trailing_comma: bool = True
311 python_cell_magics: set[str] = field(default_factory=set)
312 preview: bool = False
313 unstable: bool = False
314 enabled_features: set[Preview] = field(default_factory=set)
316 def __contains__(self, feature: Preview) -> bool:
317 """
318 Provide `Preview.FEATURE in Mode` syntax that mirrors the ``preview`` flag.
320 In unstable mode, all features are enabled. In preview mode, all features
321 except those in UNSTABLE_FEATURES are enabled. Any features in
322 `self.enabled_features` are also enabled.
323 """
324 if self.unstable:
325 return True
326 if feature in self.enabled_features:
327 return True
328 return self.preview and feature not in UNSTABLE_FEATURES
330 def get_cache_key(self) -> str:
331 if self.target_versions:
332 version_str = ",".join(
333 str(version.value)
334 for version in sorted(self.target_versions, key=attrgetter("value"))
335 )
336 else:
337 version_str = "-"
338 if len(version_str) > _MAX_CACHE_KEY_PART_LENGTH:
339 version_str = sha256(version_str.encode()).hexdigest()[
340 :_MAX_CACHE_KEY_PART_LENGTH
341 ]
342 features_and_magics = (
343 ",".join(sorted(f.name for f in self.enabled_features))
344 + "@"
345 + ",".join(sorted(self.python_cell_magics))
346 )
347 features_and_magics = sha256(features_and_magics.encode()).hexdigest()[
348 :_MAX_CACHE_KEY_PART_LENGTH
349 ]
350 parts = [
351 version_str,
352 str(self.line_length),
353 str(int(self.string_normalization)),
354 str(int(self.is_pyi)),
355 str(int(self.is_ipynb)),
356 str(int(self.skip_source_first_line)),
357 str(int(self.magic_trailing_comma)),
358 str(int(self.preview)),
359 str(int(self.unstable)),
360 features_and_magics,
361 ]
362 return ".".join(parts)
364 def __hash__(self) -> int:
365 return hash((
366 frozenset(self.target_versions),
367 self.line_length,
368 self.string_normalization,
369 self.is_pyi,
370 self.is_ipynb,
371 self.skip_source_first_line,
372 self.magic_trailing_comma,
373 frozenset(self.python_cell_magics),
374 self.preview,
375 self.unstable,
376 frozenset(self.enabled_features),
377 ))