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
7 from hashlib import sha256
10 from dataclasses import dataclass, field
11 from enum import Enum, auto
12 from operator import attrgetter
13 from typing import Dict, Set
14 from warnings import warn
16 if sys.version_info < (3, 8):
17 from typing_extensions import Final
19 from typing import Final
21 from black.const import DEFAULT_LINE_LENGTH
24 class TargetVersion(Enum):
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.
45 ASSIGNMENT_EXPRESSIONS = 8
46 POS_ONLY_ARGUMENTS = 9
47 RELAXED_DECORATORS = 10
49 UNPACKING_ON_FLOW = 12
50 ANN_ASSIGN_EXTENDED_RHS = 13
52 VARIADIC_GENERICS = 15
53 FORCE_OPTIONAL_PARENTHESES = 50
56 FUTURE_ANNOTATIONS = 51
59 FUTURE_FLAG_TO_FEATURE: Final = {
60 "annotations": Feature.FUTURE_ANNOTATIONS,
64 VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
65 TargetVersion.PY33: {Feature.ASYNC_IDENTIFIERS},
66 TargetVersion.PY34: {Feature.ASYNC_IDENTIFIERS},
67 TargetVersion.PY35: {Feature.TRAILING_COMMA_IN_CALL, Feature.ASYNC_IDENTIFIERS},
70 Feature.NUMERIC_UNDERSCORES,
71 Feature.TRAILING_COMMA_IN_CALL,
72 Feature.TRAILING_COMMA_IN_DEF,
73 Feature.ASYNC_IDENTIFIERS,
77 Feature.NUMERIC_UNDERSCORES,
78 Feature.TRAILING_COMMA_IN_CALL,
79 Feature.TRAILING_COMMA_IN_DEF,
80 Feature.ASYNC_KEYWORDS,
81 Feature.FUTURE_ANNOTATIONS,
85 Feature.NUMERIC_UNDERSCORES,
86 Feature.TRAILING_COMMA_IN_CALL,
87 Feature.TRAILING_COMMA_IN_DEF,
88 Feature.ASYNC_KEYWORDS,
89 Feature.FUTURE_ANNOTATIONS,
90 Feature.ASSIGNMENT_EXPRESSIONS,
91 Feature.POS_ONLY_ARGUMENTS,
92 Feature.UNPACKING_ON_FLOW,
93 Feature.ANN_ASSIGN_EXTENDED_RHS,
97 Feature.NUMERIC_UNDERSCORES,
98 Feature.TRAILING_COMMA_IN_CALL,
99 Feature.TRAILING_COMMA_IN_DEF,
100 Feature.ASYNC_KEYWORDS,
101 Feature.FUTURE_ANNOTATIONS,
102 Feature.ASSIGNMENT_EXPRESSIONS,
103 Feature.RELAXED_DECORATORS,
104 Feature.POS_ONLY_ARGUMENTS,
105 Feature.UNPACKING_ON_FLOW,
106 Feature.ANN_ASSIGN_EXTENDED_RHS,
108 TargetVersion.PY310: {
110 Feature.NUMERIC_UNDERSCORES,
111 Feature.TRAILING_COMMA_IN_CALL,
112 Feature.TRAILING_COMMA_IN_DEF,
113 Feature.ASYNC_KEYWORDS,
114 Feature.FUTURE_ANNOTATIONS,
115 Feature.ASSIGNMENT_EXPRESSIONS,
116 Feature.RELAXED_DECORATORS,
117 Feature.POS_ONLY_ARGUMENTS,
118 Feature.UNPACKING_ON_FLOW,
119 Feature.ANN_ASSIGN_EXTENDED_RHS,
120 Feature.PATTERN_MATCHING,
122 TargetVersion.PY311: {
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.PATTERN_MATCHING,
136 Feature.VARIADIC_GENERICS,
141 def supports_feature(target_versions: Set[TargetVersion], feature: Feature) -> bool:
142 return all(feature in VERSION_TO_FEATURES[version] for version in target_versions)
146 """Individual preview style features."""
148 annotation_parens = auto()
149 long_docstring_quotes_on_newline = auto()
150 normalize_docstring_quotes_and_prefixes_properly = auto()
151 one_element_subscript = auto()
152 remove_block_trailing_newline = auto()
153 remove_redundant_parens = auto()
154 string_processing = auto()
157 class Deprecated(UserWarning):
158 """Visible deprecation warning."""
163 target_versions: Set[TargetVersion] = field(default_factory=set)
164 line_length: int = DEFAULT_LINE_LENGTH
165 string_normalization: bool = True
167 is_ipynb: bool = False
168 magic_trailing_comma: bool = True
169 experimental_string_processing: bool = False
170 python_cell_magics: Set[str] = field(default_factory=set)
171 preview: bool = False
173 def __post_init__(self) -> None:
174 if self.experimental_string_processing:
176 "`experimental string processing` has been included in `preview`"
177 " and deprecated. Use `preview` instead.",
181 def __contains__(self, feature: Preview) -> bool:
183 Provide `Preview.FEATURE in Mode` syntax that mirrors the ``preview`` flag.
185 The argument is not checked and features are not differentiated.
186 They only exist to make development easier by clarifying intent.
188 if feature is Preview.string_processing:
189 return self.preview or self.experimental_string_processing
192 def get_cache_key(self) -> str:
193 if self.target_versions:
194 version_str = ",".join(
196 for version in sorted(self.target_versions, key=attrgetter("value"))
202 str(self.line_length),
203 str(int(self.string_normalization)),
204 str(int(self.is_pyi)),
205 str(int(self.is_ipynb)),
206 str(int(self.magic_trailing_comma)),
207 str(int(self.experimental_string_processing)),
208 str(int(self.preview)),
209 sha256((",".join(sorted(self.python_cell_magics))).encode()).hexdigest(),
211 return ".".join(parts)