]> git.madduck.net Git - etc/vim.git/blob - src/black/mode.py

madduck's git repository

Every one of the projects in this repository is available at the canonical URL git://git.madduck.net/madduck/pub/<projectpath> — see each project's metadata for the exact URL.

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.

SSH access, as well as push access can be individually arranged.

If you use my repositories frequently, consider adding the following snippet to ~/.gitconfig and using the third clone URL listed for each project:

[url "git://git.madduck.net/madduck/"]
  insteadOf = madduck:

Support pytest 7 by fixing broken imports (GH-2705)
[etc/vim.git] / src / black / mode.py
1 """Data structures configuring Black behavior.
2
3 Mostly around Python language feature support per version and Black configuration
4 chosen by the user.
5 """
6
7 import sys
8
9 from dataclasses import dataclass, field
10 from enum import Enum
11 from operator import attrgetter
12 from typing import Dict, Set
13
14 if sys.version_info < (3, 8):
15     from typing_extensions import Final
16 else:
17     from typing import Final
18
19 from black.const import DEFAULT_LINE_LENGTH
20
21
22 class TargetVersion(Enum):
23     PY27 = 2
24     PY33 = 3
25     PY34 = 4
26     PY35 = 5
27     PY36 = 6
28     PY37 = 7
29     PY38 = 8
30     PY39 = 9
31     PY310 = 10
32
33     def is_python2(self) -> bool:
34         return self is TargetVersion.PY27
35
36
37 class Feature(Enum):
38     # All string literals are unicode
39     UNICODE_LITERALS = 1
40     F_STRINGS = 2
41     NUMERIC_UNDERSCORES = 3
42     TRAILING_COMMA_IN_CALL = 4
43     TRAILING_COMMA_IN_DEF = 5
44     # The following two feature-flags are mutually exclusive, and exactly one should be
45     # set for every version of python.
46     ASYNC_IDENTIFIERS = 6
47     ASYNC_KEYWORDS = 7
48     ASSIGNMENT_EXPRESSIONS = 8
49     POS_ONLY_ARGUMENTS = 9
50     RELAXED_DECORATORS = 10
51     PATTERN_MATCHING = 11
52     UNPACKING_ON_FLOW = 12
53     ANN_ASSIGN_EXTENDED_RHS = 13
54     FORCE_OPTIONAL_PARENTHESES = 50
55
56     # __future__ flags
57     FUTURE_ANNOTATIONS = 51
58
59     # temporary for Python 2 deprecation
60     PRINT_STMT = 200
61     EXEC_STMT = 201
62     AUTOMATIC_PARAMETER_UNPACKING = 202
63     COMMA_STYLE_EXCEPT = 203
64     COMMA_STYLE_RAISE = 204
65     LONG_INT_LITERAL = 205
66     OCTAL_INT_LITERAL = 206
67     BACKQUOTE_REPR = 207
68
69
70 FUTURE_FLAG_TO_FEATURE: Final = {
71     "annotations": Feature.FUTURE_ANNOTATIONS,
72 }
73
74
75 VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
76     TargetVersion.PY27: {
77         Feature.ASYNC_IDENTIFIERS,
78         Feature.PRINT_STMT,
79         Feature.EXEC_STMT,
80         Feature.AUTOMATIC_PARAMETER_UNPACKING,
81         Feature.COMMA_STYLE_EXCEPT,
82         Feature.COMMA_STYLE_RAISE,
83         Feature.LONG_INT_LITERAL,
84         Feature.OCTAL_INT_LITERAL,
85         Feature.BACKQUOTE_REPR,
86     },
87     TargetVersion.PY33: {Feature.UNICODE_LITERALS, Feature.ASYNC_IDENTIFIERS},
88     TargetVersion.PY34: {Feature.UNICODE_LITERALS, Feature.ASYNC_IDENTIFIERS},
89     TargetVersion.PY35: {
90         Feature.UNICODE_LITERALS,
91         Feature.TRAILING_COMMA_IN_CALL,
92         Feature.ASYNC_IDENTIFIERS,
93     },
94     TargetVersion.PY36: {
95         Feature.UNICODE_LITERALS,
96         Feature.F_STRINGS,
97         Feature.NUMERIC_UNDERSCORES,
98         Feature.TRAILING_COMMA_IN_CALL,
99         Feature.TRAILING_COMMA_IN_DEF,
100         Feature.ASYNC_IDENTIFIERS,
101     },
102     TargetVersion.PY37: {
103         Feature.UNICODE_LITERALS,
104         Feature.F_STRINGS,
105         Feature.NUMERIC_UNDERSCORES,
106         Feature.TRAILING_COMMA_IN_CALL,
107         Feature.TRAILING_COMMA_IN_DEF,
108         Feature.ASYNC_KEYWORDS,
109         Feature.FUTURE_ANNOTATIONS,
110     },
111     TargetVersion.PY38: {
112         Feature.UNICODE_LITERALS,
113         Feature.F_STRINGS,
114         Feature.NUMERIC_UNDERSCORES,
115         Feature.TRAILING_COMMA_IN_CALL,
116         Feature.TRAILING_COMMA_IN_DEF,
117         Feature.ASYNC_KEYWORDS,
118         Feature.FUTURE_ANNOTATIONS,
119         Feature.ASSIGNMENT_EXPRESSIONS,
120         Feature.POS_ONLY_ARGUMENTS,
121         Feature.UNPACKING_ON_FLOW,
122         Feature.ANN_ASSIGN_EXTENDED_RHS,
123     },
124     TargetVersion.PY39: {
125         Feature.UNICODE_LITERALS,
126         Feature.F_STRINGS,
127         Feature.NUMERIC_UNDERSCORES,
128         Feature.TRAILING_COMMA_IN_CALL,
129         Feature.TRAILING_COMMA_IN_DEF,
130         Feature.ASYNC_KEYWORDS,
131         Feature.FUTURE_ANNOTATIONS,
132         Feature.ASSIGNMENT_EXPRESSIONS,
133         Feature.RELAXED_DECORATORS,
134         Feature.POS_ONLY_ARGUMENTS,
135         Feature.UNPACKING_ON_FLOW,
136         Feature.ANN_ASSIGN_EXTENDED_RHS,
137     },
138     TargetVersion.PY310: {
139         Feature.UNICODE_LITERALS,
140         Feature.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.PATTERN_MATCHING,
152     },
153 }
154
155
156 def supports_feature(target_versions: Set[TargetVersion], feature: Feature) -> bool:
157     return all(feature in VERSION_TO_FEATURES[version] for version in target_versions)
158
159
160 @dataclass
161 class Mode:
162     target_versions: Set[TargetVersion] = field(default_factory=set)
163     line_length: int = DEFAULT_LINE_LENGTH
164     string_normalization: bool = True
165     is_pyi: bool = False
166     is_ipynb: bool = False
167     magic_trailing_comma: bool = True
168     experimental_string_processing: bool = False
169
170     def get_cache_key(self) -> str:
171         if self.target_versions:
172             version_str = ",".join(
173                 str(version.value)
174                 for version in sorted(self.target_versions, key=attrgetter("value"))
175             )
176         else:
177             version_str = "-"
178         parts = [
179             version_str,
180             str(self.line_length),
181             str(int(self.string_normalization)),
182             str(int(self.is_pyi)),
183             str(int(self.is_ipynb)),
184             str(int(self.magic_trailing_comma)),
185             str(int(self.experimental_string_processing)),
186         ]
187         return ".".join(parts)