Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/black/mode.py: 83%

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

118 statements  

1"""Data structures configuring Black behavior. 

2 

3Mostly around Python language feature support per version and Black configuration 

4chosen by the user. 

5""" 

6 

7from dataclasses import dataclass, field 

8from enum import Enum, auto 

9from hashlib import sha256 

10from operator import attrgetter 

11from typing import Final 

12 

13from black.const import DEFAULT_LINE_LENGTH 

14 

15 

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 

28 PY314 = 14 

29 PY315 = 15 

30 

31 def pretty(self) -> str: 

32 assert self.name[:2] == "PY" 

33 return f"Python {self.name[2]}.{self.name[3:]}" 

34 

35 

36class Feature(Enum): 

37 F_STRINGS = 2 

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. 

43 ASYNC_IDENTIFIERS = 6 

44 ASYNC_KEYWORDS = 7 

45 ASSIGNMENT_EXPRESSIONS = 8 

46 POS_ONLY_ARGUMENTS = 9 

47 RELAXED_DECORATORS = 10 

48 PATTERN_MATCHING = 11 

49 UNPACKING_ON_FLOW = 12 

50 ANN_ASSIGN_EXTENDED_RHS = 13 

51 EXCEPT_STAR = 14 

52 VARIADIC_GENERICS = 15 

53 DEBUG_F_STRINGS = 16 

54 PARENTHESIZED_CONTEXT_MANAGERS = 17 

55 TYPE_PARAMS = 18 

56 # FSTRING_PARSING = 19 # unused 

57 TYPE_PARAM_DEFAULTS = 20 

58 UNPARENTHESIZED_EXCEPT_TYPES = 21 

59 T_STRINGS = 22 

60 LAZY_IMPORTS = 23 

61 UNPACKING_IN_COMPREHENSIONS = 24 

62 UNPARENTHESIZED_WALRUS_IN_SETS = 25 

63 FORCE_OPTIONAL_PARENTHESES = 50 

64 

65 # __future__ flags 

66 FUTURE_ANNOTATIONS = 51 

67 

68 

69FUTURE_FLAG_TO_FEATURE: Final = { 

70 "annotations": Feature.FUTURE_ANNOTATIONS, 

71} 

72 

73 

74VERSION_TO_FEATURES: dict[TargetVersion, set[Feature]] = { 

75 TargetVersion.PY33: {Feature.ASYNC_IDENTIFIERS}, 

76 TargetVersion.PY34: {Feature.ASYNC_IDENTIFIERS}, 

77 TargetVersion.PY35: {Feature.TRAILING_COMMA_IN_CALL, Feature.ASYNC_IDENTIFIERS}, 

78 TargetVersion.PY36: { 

79 Feature.F_STRINGS, 

80 Feature.NUMERIC_UNDERSCORES, 

81 Feature.TRAILING_COMMA_IN_CALL, 

82 Feature.TRAILING_COMMA_IN_DEF, 

83 Feature.ASYNC_IDENTIFIERS, 

84 }, 

85 TargetVersion.PY37: { 

86 Feature.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 }, 

93 TargetVersion.PY38: { 

94 Feature.F_STRINGS, 

95 Feature.DEBUG_F_STRINGS, 

96 Feature.NUMERIC_UNDERSCORES, 

97 Feature.TRAILING_COMMA_IN_CALL, 

98 Feature.TRAILING_COMMA_IN_DEF, 

99 Feature.ASYNC_KEYWORDS, 

100 Feature.FUTURE_ANNOTATIONS, 

101 Feature.ASSIGNMENT_EXPRESSIONS, 

102 Feature.POS_ONLY_ARGUMENTS, 

103 Feature.UNPACKING_ON_FLOW, 

104 Feature.ANN_ASSIGN_EXTENDED_RHS, 

105 }, 

106 TargetVersion.PY39: { 

107 Feature.F_STRINGS, 

108 Feature.DEBUG_F_STRINGS, 

109 Feature.NUMERIC_UNDERSCORES, 

110 Feature.TRAILING_COMMA_IN_CALL, 

111 Feature.TRAILING_COMMA_IN_DEF, 

112 Feature.ASYNC_KEYWORDS, 

113 Feature.FUTURE_ANNOTATIONS, 

114 Feature.ASSIGNMENT_EXPRESSIONS, 

115 Feature.RELAXED_DECORATORS, 

116 Feature.POS_ONLY_ARGUMENTS, 

117 Feature.UNPACKING_ON_FLOW, 

118 Feature.ANN_ASSIGN_EXTENDED_RHS, 

119 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

120 }, 

121 TargetVersion.PY310: { 

122 Feature.F_STRINGS, 

123 Feature.DEBUG_F_STRINGS, 

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.PARENTHESIZED_CONTEXT_MANAGERS, 

135 Feature.UNPARENTHESIZED_WALRUS_IN_SETS, 

136 Feature.PATTERN_MATCHING, 

137 }, 

138 TargetVersion.PY311: { 

139 Feature.F_STRINGS, 

140 Feature.DEBUG_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.PARENTHESIZED_CONTEXT_MANAGERS, 

152 Feature.UNPARENTHESIZED_WALRUS_IN_SETS, 

153 Feature.PATTERN_MATCHING, 

154 Feature.EXCEPT_STAR, 

155 Feature.VARIADIC_GENERICS, 

156 }, 

157 TargetVersion.PY312: { 

158 Feature.F_STRINGS, 

159 Feature.DEBUG_F_STRINGS, 

160 Feature.NUMERIC_UNDERSCORES, 

161 Feature.TRAILING_COMMA_IN_CALL, 

162 Feature.TRAILING_COMMA_IN_DEF, 

163 Feature.ASYNC_KEYWORDS, 

164 Feature.FUTURE_ANNOTATIONS, 

165 Feature.ASSIGNMENT_EXPRESSIONS, 

166 Feature.RELAXED_DECORATORS, 

167 Feature.POS_ONLY_ARGUMENTS, 

168 Feature.UNPACKING_ON_FLOW, 

169 Feature.ANN_ASSIGN_EXTENDED_RHS, 

170 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

171 Feature.UNPARENTHESIZED_WALRUS_IN_SETS, 

172 Feature.PATTERN_MATCHING, 

173 Feature.EXCEPT_STAR, 

174 Feature.VARIADIC_GENERICS, 

175 Feature.TYPE_PARAMS, 

176 }, 

177 TargetVersion.PY313: { 

178 Feature.F_STRINGS, 

179 Feature.DEBUG_F_STRINGS, 

180 Feature.NUMERIC_UNDERSCORES, 

181 Feature.TRAILING_COMMA_IN_CALL, 

182 Feature.TRAILING_COMMA_IN_DEF, 

183 Feature.ASYNC_KEYWORDS, 

184 Feature.FUTURE_ANNOTATIONS, 

185 Feature.ASSIGNMENT_EXPRESSIONS, 

186 Feature.RELAXED_DECORATORS, 

187 Feature.POS_ONLY_ARGUMENTS, 

188 Feature.UNPACKING_ON_FLOW, 

189 Feature.ANN_ASSIGN_EXTENDED_RHS, 

190 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

191 Feature.UNPARENTHESIZED_WALRUS_IN_SETS, 

192 Feature.PATTERN_MATCHING, 

193 Feature.EXCEPT_STAR, 

194 Feature.VARIADIC_GENERICS, 

195 Feature.TYPE_PARAMS, 

196 Feature.TYPE_PARAM_DEFAULTS, 

197 }, 

198 TargetVersion.PY314: { 

199 Feature.F_STRINGS, 

200 Feature.DEBUG_F_STRINGS, 

201 Feature.NUMERIC_UNDERSCORES, 

202 Feature.TRAILING_COMMA_IN_CALL, 

203 Feature.TRAILING_COMMA_IN_DEF, 

204 Feature.ASYNC_KEYWORDS, 

205 Feature.FUTURE_ANNOTATIONS, 

206 Feature.ASSIGNMENT_EXPRESSIONS, 

207 Feature.RELAXED_DECORATORS, 

208 Feature.POS_ONLY_ARGUMENTS, 

209 Feature.UNPACKING_ON_FLOW, 

210 Feature.ANN_ASSIGN_EXTENDED_RHS, 

211 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

212 Feature.UNPARENTHESIZED_WALRUS_IN_SETS, 

213 Feature.PATTERN_MATCHING, 

214 Feature.EXCEPT_STAR, 

215 Feature.VARIADIC_GENERICS, 

216 Feature.TYPE_PARAMS, 

217 Feature.TYPE_PARAM_DEFAULTS, 

218 Feature.UNPARENTHESIZED_EXCEPT_TYPES, 

219 Feature.T_STRINGS, 

220 }, 

221 TargetVersion.PY315: { 

222 Feature.F_STRINGS, 

223 Feature.DEBUG_F_STRINGS, 

224 Feature.NUMERIC_UNDERSCORES, 

225 Feature.TRAILING_COMMA_IN_CALL, 

226 Feature.TRAILING_COMMA_IN_DEF, 

227 Feature.ASYNC_KEYWORDS, 

228 Feature.FUTURE_ANNOTATIONS, 

229 Feature.ASSIGNMENT_EXPRESSIONS, 

230 Feature.RELAXED_DECORATORS, 

231 Feature.POS_ONLY_ARGUMENTS, 

232 Feature.UNPACKING_ON_FLOW, 

233 Feature.ANN_ASSIGN_EXTENDED_RHS, 

234 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

235 Feature.UNPARENTHESIZED_WALRUS_IN_SETS, 

236 Feature.PATTERN_MATCHING, 

237 Feature.EXCEPT_STAR, 

238 Feature.VARIADIC_GENERICS, 

239 Feature.TYPE_PARAMS, 

240 Feature.TYPE_PARAM_DEFAULTS, 

241 Feature.UNPARENTHESIZED_EXCEPT_TYPES, 

242 Feature.T_STRINGS, 

243 Feature.LAZY_IMPORTS, 

244 Feature.UNPACKING_IN_COMPREHENSIONS, 

245 }, 

246} 

247 

248 

249def supports_feature(target_versions: set[TargetVersion], feature: Feature) -> bool: 

250 if not target_versions: 

251 raise ValueError("At least one target Python version must be specified.") 

252 

253 return all(feature in VERSION_TO_FEATURES[version] for version in target_versions) 

254 

255 

256class Preview(Enum): 

257 """Individual preview style features.""" 

258 

259 # NOTE: string_processing requires wrap_long_dict_values_in_parens 

260 # for https://github.com/psf/black/issues/3117 to be fixed. 

261 string_processing = auto() 

262 hug_parens_with_braces_and_square_brackets = auto() 

263 wrap_comprehension_in = auto() 

264 simplify_power_operator_hugging = auto() 

265 wrap_long_dict_values_in_parens = auto() 

266 fix_if_guard_explosion_in_case_statement = auto() 

267 pyi_overload_group_blank_lines = auto() 

268 fix_unnecessary_parens_in_indexed_assignment = auto() 

269 pyi_blank_line_before_decorated_class = auto() 

270 pyi_blank_line_after_function_docstring = auto() 

271 hug_comparator = auto() 

272 parenthesize_tuple_in_yield = auto() 

273 fmt_off_class_blank_lines = auto() 

274 remove_redundant_generator_parentheses = auto() 

275 symmetric_collection_operations = auto() 

276 normalize_tstring_prefix = auto() 

277 remove_redundant_list_parentheses = auto() 

278 remove_redundant_unpacking_parentheses = auto() 

279 remove_redundant_subscript_parentheses = auto() 

280 fix_magic_trailing_comma_trailer_split = auto() 

281 keep_dict_keys_with_operators = auto() 

282 blank_line_after_stub_method = auto() 

283 keep_commented_expressions_together = auto() 

284 avoid_parens_for_unbreakable_rhs_in_assignments = auto() 

285 parenthesize_expressions_with_comments = auto() 

286 keep_trailers_on_bracket_comment_overflow = auto() 

287 remove_redundant_comparison_parentheses = auto() 

288 remove_redundant_top_level_parentheses = auto() 

289 

290 

291UNSTABLE_FEATURES: set[Preview] = { 

292 # Many issues, see summary in https://github.com/psf/black/issues/4208 

293 Preview.string_processing, 

294 # See issue #4036 (crash), #4098, #4099 (proposed tweaks) 

295 Preview.hug_parens_with_braces_and_square_brackets, 

296} 

297 

298 

299_MAX_CACHE_KEY_PART_LENGTH: Final = 32 

300 

301 

302@dataclass 

303class Mode: 

304 target_versions: set[TargetVersion] = field(default_factory=set) 

305 line_length: int = DEFAULT_LINE_LENGTH 

306 string_normalization: bool = True 

307 is_pyi: bool = False 

308 is_ipynb: bool = False 

309 skip_source_first_line: bool = False 

310 magic_trailing_comma: bool = True 

311 python_cell_magics: set[str] = field(default_factory=set) 

312 preview: bool = False 

313 unstable: bool = False 

314 enabled_features: set[Preview] = field(default_factory=set) 

315 

316 def __contains__(self, feature: Preview) -> bool: 

317 """ 

318 Provide `Preview.FEATURE in Mode` syntax that mirrors the ``preview`` flag. 

319 

320 In unstable mode, all features are enabled. In preview mode, all features 

321 except those in UNSTABLE_FEATURES are enabled. Any features in 

322 `self.enabled_features` are also enabled. 

323 """ 

324 if self.unstable: 

325 return True 

326 if feature in self.enabled_features: 

327 return True 

328 return self.preview and feature not in UNSTABLE_FEATURES 

329 

330 def get_cache_key(self) -> str: 

331 if self.target_versions: 

332 version_str = ",".join( 

333 str(version.value) 

334 for version in sorted(self.target_versions, key=attrgetter("value")) 

335 ) 

336 else: 

337 version_str = "-" 

338 if len(version_str) > _MAX_CACHE_KEY_PART_LENGTH: 

339 version_str = sha256(version_str.encode()).hexdigest()[ 

340 :_MAX_CACHE_KEY_PART_LENGTH 

341 ] 

342 features_and_magics = ( 

343 ",".join(sorted(f.name for f in self.enabled_features)) 

344 + "@" 

345 + ",".join(sorted(self.python_cell_magics)) 

346 ) 

347 features_and_magics = sha256(features_and_magics.encode()).hexdigest()[ 

348 :_MAX_CACHE_KEY_PART_LENGTH 

349 ] 

350 parts = [ 

351 version_str, 

352 str(self.line_length), 

353 str(int(self.string_normalization)), 

354 str(int(self.is_pyi)), 

355 str(int(self.is_ipynb)), 

356 str(int(self.skip_source_first_line)), 

357 str(int(self.magic_trailing_comma)), 

358 str(int(self.preview)), 

359 str(int(self.unstable)), 

360 features_and_magics, 

361 ] 

362 return ".".join(parts) 

363 

364 def __hash__(self) -> int: 

365 return hash(( 

366 frozenset(self.target_versions), 

367 self.line_length, 

368 self.string_normalization, 

369 self.is_pyi, 

370 self.is_ipynb, 

371 self.skip_source_first_line, 

372 self.magic_trailing_comma, 

373 frozenset(self.python_cell_magics), 

374 self.preview, 

375 self.unstable, 

376 frozenset(self.enabled_features), 

377 ))