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):
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
50 FORCE_OPTIONAL_PARENTHESES = 50
53 FUTURE_ANNOTATIONS = 51
56 FUTURE_FLAG_TO_FEATURE: Final = {
57 "annotations": Feature.FUTURE_ANNOTATIONS,
61 VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
62 TargetVersion.PY33: {Feature.ASYNC_IDENTIFIERS},
63 TargetVersion.PY34: {Feature.ASYNC_IDENTIFIERS},
64 TargetVersion.PY35: {Feature.TRAILING_COMMA_IN_CALL, Feature.ASYNC_IDENTIFIERS},
67 Feature.NUMERIC_UNDERSCORES,
68 Feature.TRAILING_COMMA_IN_CALL,
69 Feature.TRAILING_COMMA_IN_DEF,
70 Feature.ASYNC_IDENTIFIERS,
74 Feature.NUMERIC_UNDERSCORES,
75 Feature.TRAILING_COMMA_IN_CALL,
76 Feature.TRAILING_COMMA_IN_DEF,
77 Feature.ASYNC_KEYWORDS,
78 Feature.FUTURE_ANNOTATIONS,
82 Feature.NUMERIC_UNDERSCORES,
83 Feature.TRAILING_COMMA_IN_CALL,
84 Feature.TRAILING_COMMA_IN_DEF,
85 Feature.ASYNC_KEYWORDS,
86 Feature.FUTURE_ANNOTATIONS,
87 Feature.ASSIGNMENT_EXPRESSIONS,
88 Feature.POS_ONLY_ARGUMENTS,
89 Feature.UNPACKING_ON_FLOW,
90 Feature.ANN_ASSIGN_EXTENDED_RHS,
94 Feature.NUMERIC_UNDERSCORES,
95 Feature.TRAILING_COMMA_IN_CALL,
96 Feature.TRAILING_COMMA_IN_DEF,
97 Feature.ASYNC_KEYWORDS,
98 Feature.FUTURE_ANNOTATIONS,
99 Feature.ASSIGNMENT_EXPRESSIONS,
100 Feature.RELAXED_DECORATORS,
101 Feature.POS_ONLY_ARGUMENTS,
102 Feature.UNPACKING_ON_FLOW,
103 Feature.ANN_ASSIGN_EXTENDED_RHS,
105 TargetVersion.PY310: {
107 Feature.NUMERIC_UNDERSCORES,
108 Feature.TRAILING_COMMA_IN_CALL,
109 Feature.TRAILING_COMMA_IN_DEF,
110 Feature.ASYNC_KEYWORDS,
111 Feature.FUTURE_ANNOTATIONS,
112 Feature.ASSIGNMENT_EXPRESSIONS,
113 Feature.RELAXED_DECORATORS,
114 Feature.POS_ONLY_ARGUMENTS,
115 Feature.UNPACKING_ON_FLOW,
116 Feature.ANN_ASSIGN_EXTENDED_RHS,
117 Feature.PATTERN_MATCHING,
122 def supports_feature(target_versions: Set[TargetVersion], feature: Feature) -> bool:
123 return all(feature in VERSION_TO_FEATURES[version] for version in target_versions)
127 """Individual preview style features."""
129 string_processing = auto()
132 class Deprecated(UserWarning):
133 """Visible deprecation warning."""
138 target_versions: Set[TargetVersion] = field(default_factory=set)
139 line_length: int = DEFAULT_LINE_LENGTH
140 string_normalization: bool = True
142 is_ipynb: bool = False
143 magic_trailing_comma: bool = True
144 experimental_string_processing: bool = False
145 python_cell_magics: Set[str] = field(default_factory=set)
146 preview: bool = False
148 def __post_init__(self) -> None:
149 if self.experimental_string_processing:
151 "`experimental string processing` has been included in `preview`"
152 " and deprecated. Use `preview` instead.",
156 def __contains__(self, feature: Preview) -> bool:
158 Provide `Preview.FEATURE in Mode` syntax that mirrors the ``preview`` flag.
160 The argument is not checked and features are not differentiated.
161 They only exist to make development easier by clarifying intent.
163 if feature is Preview.string_processing:
164 return self.preview or self.experimental_string_processing
165 # TODO: Remove type ignore comment once preview contains more features
167 return self.preview # type: ignore
169 def get_cache_key(self) -> str:
170 if self.target_versions:
171 version_str = ",".join(
173 for version in sorted(self.target_versions, key=attrgetter("value"))
179 str(self.line_length),
180 str(int(self.string_normalization)),
181 str(int(self.is_pyi)),
182 str(int(self.is_ipynb)),
183 str(int(self.magic_trailing_comma)),
184 str(int(self.experimental_string_processing)),
185 str(int(self.preview)),
186 sha256((",".join(sorted(self.python_cell_magics))).encode()).hexdigest(),
188 return ".".join(parts)