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
29 def pretty(self) -> str:
30 assert self.name[:2] == "PY"
31 return f"Python {self.name[2]}.{self.name[3:]}"
34class Feature(Enum):
35 F_STRINGS = 2
36 NUMERIC_UNDERSCORES = 3
37 TRAILING_COMMA_IN_CALL = 4
38 TRAILING_COMMA_IN_DEF = 5
39 # The following two feature-flags are mutually exclusive, and exactly one should be
40 # set for every version of python.
41 ASYNC_IDENTIFIERS = 6
42 ASYNC_KEYWORDS = 7
43 ASSIGNMENT_EXPRESSIONS = 8
44 POS_ONLY_ARGUMENTS = 9
45 RELAXED_DECORATORS = 10
46 PATTERN_MATCHING = 11
47 UNPACKING_ON_FLOW = 12
48 ANN_ASSIGN_EXTENDED_RHS = 13
49 EXCEPT_STAR = 14
50 VARIADIC_GENERICS = 15
51 DEBUG_F_STRINGS = 16
52 PARENTHESIZED_CONTEXT_MANAGERS = 17
53 TYPE_PARAMS = 18
54 FSTRING_PARSING = 19
55 TYPE_PARAM_DEFAULTS = 20
56 FORCE_OPTIONAL_PARENTHESES = 50
58 # __future__ flags
59 FUTURE_ANNOTATIONS = 51
62FUTURE_FLAG_TO_FEATURE: Final = {
63 "annotations": Feature.FUTURE_ANNOTATIONS,
64}
67VERSION_TO_FEATURES: dict[TargetVersion, set[Feature]] = {
68 TargetVersion.PY33: {Feature.ASYNC_IDENTIFIERS},
69 TargetVersion.PY34: {Feature.ASYNC_IDENTIFIERS},
70 TargetVersion.PY35: {Feature.TRAILING_COMMA_IN_CALL, Feature.ASYNC_IDENTIFIERS},
71 TargetVersion.PY36: {
72 Feature.F_STRINGS,
73 Feature.NUMERIC_UNDERSCORES,
74 Feature.TRAILING_COMMA_IN_CALL,
75 Feature.TRAILING_COMMA_IN_DEF,
76 Feature.ASYNC_IDENTIFIERS,
77 },
78 TargetVersion.PY37: {
79 Feature.F_STRINGS,
80 Feature.NUMERIC_UNDERSCORES,
81 Feature.TRAILING_COMMA_IN_CALL,
82 Feature.TRAILING_COMMA_IN_DEF,
83 Feature.ASYNC_KEYWORDS,
84 Feature.FUTURE_ANNOTATIONS,
85 },
86 TargetVersion.PY38: {
87 Feature.F_STRINGS,
88 Feature.DEBUG_F_STRINGS,
89 Feature.NUMERIC_UNDERSCORES,
90 Feature.TRAILING_COMMA_IN_CALL,
91 Feature.TRAILING_COMMA_IN_DEF,
92 Feature.ASYNC_KEYWORDS,
93 Feature.FUTURE_ANNOTATIONS,
94 Feature.ASSIGNMENT_EXPRESSIONS,
95 Feature.POS_ONLY_ARGUMENTS,
96 Feature.UNPACKING_ON_FLOW,
97 Feature.ANN_ASSIGN_EXTENDED_RHS,
98 },
99 TargetVersion.PY39: {
100 Feature.F_STRINGS,
101 Feature.DEBUG_F_STRINGS,
102 Feature.NUMERIC_UNDERSCORES,
103 Feature.TRAILING_COMMA_IN_CALL,
104 Feature.TRAILING_COMMA_IN_DEF,
105 Feature.ASYNC_KEYWORDS,
106 Feature.FUTURE_ANNOTATIONS,
107 Feature.ASSIGNMENT_EXPRESSIONS,
108 Feature.RELAXED_DECORATORS,
109 Feature.POS_ONLY_ARGUMENTS,
110 Feature.UNPACKING_ON_FLOW,
111 Feature.ANN_ASSIGN_EXTENDED_RHS,
112 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
113 },
114 TargetVersion.PY310: {
115 Feature.F_STRINGS,
116 Feature.DEBUG_F_STRINGS,
117 Feature.NUMERIC_UNDERSCORES,
118 Feature.TRAILING_COMMA_IN_CALL,
119 Feature.TRAILING_COMMA_IN_DEF,
120 Feature.ASYNC_KEYWORDS,
121 Feature.FUTURE_ANNOTATIONS,
122 Feature.ASSIGNMENT_EXPRESSIONS,
123 Feature.RELAXED_DECORATORS,
124 Feature.POS_ONLY_ARGUMENTS,
125 Feature.UNPACKING_ON_FLOW,
126 Feature.ANN_ASSIGN_EXTENDED_RHS,
127 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
128 Feature.PATTERN_MATCHING,
129 },
130 TargetVersion.PY311: {
131 Feature.F_STRINGS,
132 Feature.DEBUG_F_STRINGS,
133 Feature.NUMERIC_UNDERSCORES,
134 Feature.TRAILING_COMMA_IN_CALL,
135 Feature.TRAILING_COMMA_IN_DEF,
136 Feature.ASYNC_KEYWORDS,
137 Feature.FUTURE_ANNOTATIONS,
138 Feature.ASSIGNMENT_EXPRESSIONS,
139 Feature.RELAXED_DECORATORS,
140 Feature.POS_ONLY_ARGUMENTS,
141 Feature.UNPACKING_ON_FLOW,
142 Feature.ANN_ASSIGN_EXTENDED_RHS,
143 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
144 Feature.PATTERN_MATCHING,
145 Feature.EXCEPT_STAR,
146 Feature.VARIADIC_GENERICS,
147 },
148 TargetVersion.PY312: {
149 Feature.F_STRINGS,
150 Feature.DEBUG_F_STRINGS,
151 Feature.NUMERIC_UNDERSCORES,
152 Feature.TRAILING_COMMA_IN_CALL,
153 Feature.TRAILING_COMMA_IN_DEF,
154 Feature.ASYNC_KEYWORDS,
155 Feature.FUTURE_ANNOTATIONS,
156 Feature.ASSIGNMENT_EXPRESSIONS,
157 Feature.RELAXED_DECORATORS,
158 Feature.POS_ONLY_ARGUMENTS,
159 Feature.UNPACKING_ON_FLOW,
160 Feature.ANN_ASSIGN_EXTENDED_RHS,
161 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
162 Feature.PATTERN_MATCHING,
163 Feature.EXCEPT_STAR,
164 Feature.VARIADIC_GENERICS,
165 Feature.TYPE_PARAMS,
166 Feature.FSTRING_PARSING,
167 },
168 TargetVersion.PY313: {
169 Feature.F_STRINGS,
170 Feature.DEBUG_F_STRINGS,
171 Feature.NUMERIC_UNDERSCORES,
172 Feature.TRAILING_COMMA_IN_CALL,
173 Feature.TRAILING_COMMA_IN_DEF,
174 Feature.ASYNC_KEYWORDS,
175 Feature.FUTURE_ANNOTATIONS,
176 Feature.ASSIGNMENT_EXPRESSIONS,
177 Feature.RELAXED_DECORATORS,
178 Feature.POS_ONLY_ARGUMENTS,
179 Feature.UNPACKING_ON_FLOW,
180 Feature.ANN_ASSIGN_EXTENDED_RHS,
181 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
182 Feature.PATTERN_MATCHING,
183 Feature.EXCEPT_STAR,
184 Feature.VARIADIC_GENERICS,
185 Feature.TYPE_PARAMS,
186 Feature.FSTRING_PARSING,
187 Feature.TYPE_PARAM_DEFAULTS,
188 },
189}
192def supports_feature(target_versions: set[TargetVersion], feature: Feature) -> bool:
193 return all(feature in VERSION_TO_FEATURES[version] for version in target_versions)
196class Preview(Enum):
197 """Individual preview style features."""
199 # NOTE: string_processing requires wrap_long_dict_values_in_parens
200 # for https://github.com/psf/black/issues/3117 to be fixed.
201 string_processing = auto()
202 hug_parens_with_braces_and_square_brackets = auto()
203 wrap_long_dict_values_in_parens = auto()
204 multiline_string_handling = auto()
205 always_one_newline_after_import = auto()
206 fix_fmt_skip_in_one_liners = auto()
209UNSTABLE_FEATURES: set[Preview] = {
210 # Many issues, see summary in https://github.com/psf/black/issues/4042
211 Preview.string_processing,
212 # See issue #4159
213 Preview.multiline_string_handling,
214 # See issue #4036 (crash), #4098, #4099 (proposed tweaks)
215 Preview.hug_parens_with_braces_and_square_brackets,
216}
219class Deprecated(UserWarning):
220 """Visible deprecation warning."""
223_MAX_CACHE_KEY_PART_LENGTH: Final = 32
226@dataclass
227class Mode:
228 target_versions: set[TargetVersion] = field(default_factory=set)
229 line_length: int = DEFAULT_LINE_LENGTH
230 string_normalization: bool = True
231 is_pyi: bool = False
232 is_ipynb: bool = False
233 skip_source_first_line: bool = False
234 magic_trailing_comma: bool = True
235 python_cell_magics: set[str] = field(default_factory=set)
236 preview: bool = False
237 unstable: bool = False
238 enabled_features: set[Preview] = field(default_factory=set)
240 def __contains__(self, feature: Preview) -> bool:
241 """
242 Provide `Preview.FEATURE in Mode` syntax that mirrors the ``preview`` flag.
244 In unstable mode, all features are enabled. In preview mode, all features
245 except those in UNSTABLE_FEATURES are enabled. Any features in
246 `self.enabled_features` are also enabled.
247 """
248 if self.unstable:
249 return True
250 if feature in self.enabled_features:
251 return True
252 return self.preview and feature not in UNSTABLE_FEATURES
254 def get_cache_key(self) -> str:
255 if self.target_versions:
256 version_str = ",".join(
257 str(version.value)
258 for version in sorted(self.target_versions, key=attrgetter("value"))
259 )
260 else:
261 version_str = "-"
262 if len(version_str) > _MAX_CACHE_KEY_PART_LENGTH:
263 version_str = sha256(version_str.encode()).hexdigest()[
264 :_MAX_CACHE_KEY_PART_LENGTH
265 ]
266 features_and_magics = (
267 ",".join(sorted(f.name for f in self.enabled_features))
268 + "@"
269 + ",".join(sorted(self.python_cell_magics))
270 )
271 if len(features_and_magics) > _MAX_CACHE_KEY_PART_LENGTH:
272 features_and_magics = sha256(features_and_magics.encode()).hexdigest()[
273 :_MAX_CACHE_KEY_PART_LENGTH
274 ]
275 parts = [
276 version_str,
277 str(self.line_length),
278 str(int(self.string_normalization)),
279 str(int(self.is_pyi)),
280 str(int(self.is_ipynb)),
281 str(int(self.skip_source_first_line)),
282 str(int(self.magic_trailing_comma)),
283 str(int(self.preview)),
284 str(int(self.unstable)),
285 features_and_magics,
286 ]
287 return ".".join(parts)