All patches and comments are welcome. Please squash your changes to logical
commits before using git-format-patch and git-send-email to
patches@git.madduck.net.
If you'd read over the Git project's submission guidelines and adhered to them,
I'd be especially grateful.
1 """Data structures configuring Black behavior.
3 Mostly around Python language feature support per version and Black configuration
8 from dataclasses import dataclass, field
9 from enum import Enum, auto
10 from hashlib import sha256
11 from operator import attrgetter
12 from typing import Dict, Set
13 from warnings import warn
15 if sys.version_info < (3, 8):
16 from typing_extensions import Final
18 from typing import Final
20 from black.const import DEFAULT_LINE_LENGTH
23 class TargetVersion(Enum):
37 NUMERIC_UNDERSCORES = 3
38 TRAILING_COMMA_IN_CALL = 4
39 TRAILING_COMMA_IN_DEF = 5
40 # The following two feature-flags are mutually exclusive, and exactly one should be
41 # set for every version of python.
44 ASSIGNMENT_EXPRESSIONS = 8
45 POS_ONLY_ARGUMENTS = 9
46 RELAXED_DECORATORS = 10
48 UNPACKING_ON_FLOW = 12
49 ANN_ASSIGN_EXTENDED_RHS = 13
51 VARIADIC_GENERICS = 15
53 PARENTHESIZED_CONTEXT_MANAGERS = 17
54 FORCE_OPTIONAL_PARENTHESES = 50
57 FUTURE_ANNOTATIONS = 51
60 FUTURE_FLAG_TO_FEATURE: Final = {
61 "annotations": Feature.FUTURE_ANNOTATIONS,
65 VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
66 TargetVersion.PY33: {Feature.ASYNC_IDENTIFIERS},
67 TargetVersion.PY34: {Feature.ASYNC_IDENTIFIERS},
68 TargetVersion.PY35: {Feature.TRAILING_COMMA_IN_CALL, Feature.ASYNC_IDENTIFIERS},
71 Feature.NUMERIC_UNDERSCORES,
72 Feature.TRAILING_COMMA_IN_CALL,
73 Feature.TRAILING_COMMA_IN_DEF,
74 Feature.ASYNC_IDENTIFIERS,
78 Feature.NUMERIC_UNDERSCORES,
79 Feature.TRAILING_COMMA_IN_CALL,
80 Feature.TRAILING_COMMA_IN_DEF,
81 Feature.ASYNC_KEYWORDS,
82 Feature.FUTURE_ANNOTATIONS,
86 Feature.DEBUG_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 Feature.ASSIGNMENT_EXPRESSIONS,
93 Feature.POS_ONLY_ARGUMENTS,
94 Feature.UNPACKING_ON_FLOW,
95 Feature.ANN_ASSIGN_EXTENDED_RHS,
99 Feature.DEBUG_F_STRINGS,
100 Feature.NUMERIC_UNDERSCORES,
101 Feature.TRAILING_COMMA_IN_CALL,
102 Feature.TRAILING_COMMA_IN_DEF,
103 Feature.ASYNC_KEYWORDS,
104 Feature.FUTURE_ANNOTATIONS,
105 Feature.ASSIGNMENT_EXPRESSIONS,
106 Feature.RELAXED_DECORATORS,
107 Feature.POS_ONLY_ARGUMENTS,
108 Feature.UNPACKING_ON_FLOW,
109 Feature.ANN_ASSIGN_EXTENDED_RHS,
110 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
112 TargetVersion.PY310: {
114 Feature.DEBUG_F_STRINGS,
115 Feature.NUMERIC_UNDERSCORES,
116 Feature.TRAILING_COMMA_IN_CALL,
117 Feature.TRAILING_COMMA_IN_DEF,
118 Feature.ASYNC_KEYWORDS,
119 Feature.FUTURE_ANNOTATIONS,
120 Feature.ASSIGNMENT_EXPRESSIONS,
121 Feature.RELAXED_DECORATORS,
122 Feature.POS_ONLY_ARGUMENTS,
123 Feature.UNPACKING_ON_FLOW,
124 Feature.ANN_ASSIGN_EXTENDED_RHS,
125 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
126 Feature.PATTERN_MATCHING,
128 TargetVersion.PY311: {
130 Feature.DEBUG_F_STRINGS,
131 Feature.NUMERIC_UNDERSCORES,
132 Feature.TRAILING_COMMA_IN_CALL,
133 Feature.TRAILING_COMMA_IN_DEF,
134 Feature.ASYNC_KEYWORDS,
135 Feature.FUTURE_ANNOTATIONS,
136 Feature.ASSIGNMENT_EXPRESSIONS,
137 Feature.RELAXED_DECORATORS,
138 Feature.POS_ONLY_ARGUMENTS,
139 Feature.UNPACKING_ON_FLOW,
140 Feature.ANN_ASSIGN_EXTENDED_RHS,
141 Feature.PARENTHESIZED_CONTEXT_MANAGERS,
142 Feature.PATTERN_MATCHING,
144 Feature.VARIADIC_GENERICS,
149 def supports_feature(target_versions: Set[TargetVersion], feature: Feature) -> bool:
150 return all(feature in VERSION_TO_FEATURES[version] for version in target_versions)
154 """Individual preview style features."""
156 annotation_parens = auto()
157 empty_lines_before_class_or_def_with_leading_comments = auto()
158 handle_trailing_commas_in_head = auto()
159 long_docstring_quotes_on_newline = auto()
160 normalize_docstring_quotes_and_prefixes_properly = auto()
161 one_element_subscript = auto()
162 prefer_splitting_right_hand_side_of_assignments = auto()
163 remove_block_trailing_newline = auto()
164 remove_redundant_parens = auto()
165 # NOTE: string_processing requires wrap_long_dict_values_in_parens
166 # for https://github.com/psf/black/issues/3117 to be fixed.
167 string_processing = auto()
168 parenthesize_conditional_expressions = auto()
169 skip_magic_trailing_comma_in_subscript = auto()
170 wrap_long_dict_values_in_parens = auto()
171 wrap_multiple_context_managers_in_parens = auto()
174 class Deprecated(UserWarning):
175 """Visible deprecation warning."""
180 target_versions: Set[TargetVersion] = field(default_factory=set)
181 line_length: int = DEFAULT_LINE_LENGTH
182 string_normalization: bool = True
184 is_ipynb: bool = False
185 skip_source_first_line: bool = False
186 magic_trailing_comma: bool = True
187 experimental_string_processing: bool = False
188 python_cell_magics: Set[str] = field(default_factory=set)
189 preview: bool = False
191 def __post_init__(self) -> None:
192 if self.experimental_string_processing:
195 "`experimental string processing` has been included in `preview`"
196 " and deprecated. Use `preview` instead."
201 def __contains__(self, feature: Preview) -> bool:
203 Provide `Preview.FEATURE in Mode` syntax that mirrors the ``preview`` flag.
205 The argument is not checked and features are not differentiated.
206 They only exist to make development easier by clarifying intent.
208 if feature is Preview.string_processing:
209 return self.preview or self.experimental_string_processing
212 def get_cache_key(self) -> str:
213 if self.target_versions:
214 version_str = ",".join(
216 for version in sorted(self.target_versions, key=attrgetter("value"))
222 str(self.line_length),
223 str(int(self.string_normalization)),
224 str(int(self.is_pyi)),
225 str(int(self.is_ipynb)),
226 str(int(self.skip_source_first_line)),
227 str(int(self.magic_trailing_comma)),
228 str(int(self.experimental_string_processing)),
229 str(int(self.preview)),
230 sha256((",".join(sorted(self.python_cell_magics))).encode()).hexdigest(),
232 return ".".join(parts)