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

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

88 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 

29 def pretty(self) -> str: 

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

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

32 

33 

34class Feature(Enum): 

35 F_STRINGS = 2 

36 NUMERIC_UNDERSCORES = 3 

37 TRAILING_COMMA_IN_CALL = 4 

38 TRAILING_COMMA_IN_DEF = 5 

39 # The following two feature-flags are mutually exclusive, and exactly one should be 

40 # set for every version of python. 

41 ASYNC_IDENTIFIERS = 6 

42 ASYNC_KEYWORDS = 7 

43 ASSIGNMENT_EXPRESSIONS = 8 

44 POS_ONLY_ARGUMENTS = 9 

45 RELAXED_DECORATORS = 10 

46 PATTERN_MATCHING = 11 

47 UNPACKING_ON_FLOW = 12 

48 ANN_ASSIGN_EXTENDED_RHS = 13 

49 EXCEPT_STAR = 14 

50 VARIADIC_GENERICS = 15 

51 DEBUG_F_STRINGS = 16 

52 PARENTHESIZED_CONTEXT_MANAGERS = 17 

53 TYPE_PARAMS = 18 

54 FSTRING_PARSING = 19 

55 TYPE_PARAM_DEFAULTS = 20 

56 FORCE_OPTIONAL_PARENTHESES = 50 

57 

58 # __future__ flags 

59 FUTURE_ANNOTATIONS = 51 

60 

61 

62FUTURE_FLAG_TO_FEATURE: Final = { 

63 "annotations": Feature.FUTURE_ANNOTATIONS, 

64} 

65 

66 

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

68 TargetVersion.PY33: {Feature.ASYNC_IDENTIFIERS}, 

69 TargetVersion.PY34: {Feature.ASYNC_IDENTIFIERS}, 

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

71 TargetVersion.PY36: { 

72 Feature.F_STRINGS, 

73 Feature.NUMERIC_UNDERSCORES, 

74 Feature.TRAILING_COMMA_IN_CALL, 

75 Feature.TRAILING_COMMA_IN_DEF, 

76 Feature.ASYNC_IDENTIFIERS, 

77 }, 

78 TargetVersion.PY37: { 

79 Feature.F_STRINGS, 

80 Feature.NUMERIC_UNDERSCORES, 

81 Feature.TRAILING_COMMA_IN_CALL, 

82 Feature.TRAILING_COMMA_IN_DEF, 

83 Feature.ASYNC_KEYWORDS, 

84 Feature.FUTURE_ANNOTATIONS, 

85 }, 

86 TargetVersion.PY38: { 

87 Feature.F_STRINGS, 

88 Feature.DEBUG_F_STRINGS, 

89 Feature.NUMERIC_UNDERSCORES, 

90 Feature.TRAILING_COMMA_IN_CALL, 

91 Feature.TRAILING_COMMA_IN_DEF, 

92 Feature.ASYNC_KEYWORDS, 

93 Feature.FUTURE_ANNOTATIONS, 

94 Feature.ASSIGNMENT_EXPRESSIONS, 

95 Feature.POS_ONLY_ARGUMENTS, 

96 Feature.UNPACKING_ON_FLOW, 

97 Feature.ANN_ASSIGN_EXTENDED_RHS, 

98 }, 

99 TargetVersion.PY39: { 

100 Feature.F_STRINGS, 

101 Feature.DEBUG_F_STRINGS, 

102 Feature.NUMERIC_UNDERSCORES, 

103 Feature.TRAILING_COMMA_IN_CALL, 

104 Feature.TRAILING_COMMA_IN_DEF, 

105 Feature.ASYNC_KEYWORDS, 

106 Feature.FUTURE_ANNOTATIONS, 

107 Feature.ASSIGNMENT_EXPRESSIONS, 

108 Feature.RELAXED_DECORATORS, 

109 Feature.POS_ONLY_ARGUMENTS, 

110 Feature.UNPACKING_ON_FLOW, 

111 Feature.ANN_ASSIGN_EXTENDED_RHS, 

112 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

113 }, 

114 TargetVersion.PY310: { 

115 Feature.F_STRINGS, 

116 Feature.DEBUG_F_STRINGS, 

117 Feature.NUMERIC_UNDERSCORES, 

118 Feature.TRAILING_COMMA_IN_CALL, 

119 Feature.TRAILING_COMMA_IN_DEF, 

120 Feature.ASYNC_KEYWORDS, 

121 Feature.FUTURE_ANNOTATIONS, 

122 Feature.ASSIGNMENT_EXPRESSIONS, 

123 Feature.RELAXED_DECORATORS, 

124 Feature.POS_ONLY_ARGUMENTS, 

125 Feature.UNPACKING_ON_FLOW, 

126 Feature.ANN_ASSIGN_EXTENDED_RHS, 

127 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

128 Feature.PATTERN_MATCHING, 

129 }, 

130 TargetVersion.PY311: { 

131 Feature.F_STRINGS, 

132 Feature.DEBUG_F_STRINGS, 

133 Feature.NUMERIC_UNDERSCORES, 

134 Feature.TRAILING_COMMA_IN_CALL, 

135 Feature.TRAILING_COMMA_IN_DEF, 

136 Feature.ASYNC_KEYWORDS, 

137 Feature.FUTURE_ANNOTATIONS, 

138 Feature.ASSIGNMENT_EXPRESSIONS, 

139 Feature.RELAXED_DECORATORS, 

140 Feature.POS_ONLY_ARGUMENTS, 

141 Feature.UNPACKING_ON_FLOW, 

142 Feature.ANN_ASSIGN_EXTENDED_RHS, 

143 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

144 Feature.PATTERN_MATCHING, 

145 Feature.EXCEPT_STAR, 

146 Feature.VARIADIC_GENERICS, 

147 }, 

148 TargetVersion.PY312: { 

149 Feature.F_STRINGS, 

150 Feature.DEBUG_F_STRINGS, 

151 Feature.NUMERIC_UNDERSCORES, 

152 Feature.TRAILING_COMMA_IN_CALL, 

153 Feature.TRAILING_COMMA_IN_DEF, 

154 Feature.ASYNC_KEYWORDS, 

155 Feature.FUTURE_ANNOTATIONS, 

156 Feature.ASSIGNMENT_EXPRESSIONS, 

157 Feature.RELAXED_DECORATORS, 

158 Feature.POS_ONLY_ARGUMENTS, 

159 Feature.UNPACKING_ON_FLOW, 

160 Feature.ANN_ASSIGN_EXTENDED_RHS, 

161 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

162 Feature.PATTERN_MATCHING, 

163 Feature.EXCEPT_STAR, 

164 Feature.VARIADIC_GENERICS, 

165 Feature.TYPE_PARAMS, 

166 Feature.FSTRING_PARSING, 

167 }, 

168 TargetVersion.PY313: { 

169 Feature.F_STRINGS, 

170 Feature.DEBUG_F_STRINGS, 

171 Feature.NUMERIC_UNDERSCORES, 

172 Feature.TRAILING_COMMA_IN_CALL, 

173 Feature.TRAILING_COMMA_IN_DEF, 

174 Feature.ASYNC_KEYWORDS, 

175 Feature.FUTURE_ANNOTATIONS, 

176 Feature.ASSIGNMENT_EXPRESSIONS, 

177 Feature.RELAXED_DECORATORS, 

178 Feature.POS_ONLY_ARGUMENTS, 

179 Feature.UNPACKING_ON_FLOW, 

180 Feature.ANN_ASSIGN_EXTENDED_RHS, 

181 Feature.PARENTHESIZED_CONTEXT_MANAGERS, 

182 Feature.PATTERN_MATCHING, 

183 Feature.EXCEPT_STAR, 

184 Feature.VARIADIC_GENERICS, 

185 Feature.TYPE_PARAMS, 

186 Feature.FSTRING_PARSING, 

187 Feature.TYPE_PARAM_DEFAULTS, 

188 }, 

189} 

190 

191 

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

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

194 

195 

196class Preview(Enum): 

197 """Individual preview style features.""" 

198 

199 # NOTE: string_processing requires wrap_long_dict_values_in_parens 

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

201 string_processing = auto() 

202 hug_parens_with_braces_and_square_brackets = auto() 

203 wrap_long_dict_values_in_parens = auto() 

204 multiline_string_handling = auto() 

205 always_one_newline_after_import = auto() 

206 fix_fmt_skip_in_one_liners = auto() 

207 

208 

209UNSTABLE_FEATURES: set[Preview] = { 

210 # Many issues, see summary in https://github.com/psf/black/issues/4042 

211 Preview.string_processing, 

212 # See issue #4159 

213 Preview.multiline_string_handling, 

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

215 Preview.hug_parens_with_braces_and_square_brackets, 

216} 

217 

218 

219class Deprecated(UserWarning): 

220 """Visible deprecation warning.""" 

221 

222 

223_MAX_CACHE_KEY_PART_LENGTH: Final = 32 

224 

225 

226@dataclass 

227class Mode: 

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

229 line_length: int = DEFAULT_LINE_LENGTH 

230 string_normalization: bool = True 

231 is_pyi: bool = False 

232 is_ipynb: bool = False 

233 skip_source_first_line: bool = False 

234 magic_trailing_comma: bool = True 

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

236 preview: bool = False 

237 unstable: bool = False 

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

239 

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

241 """ 

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

243 

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

245 except those in UNSTABLE_FEATURES are enabled. Any features in 

246 `self.enabled_features` are also enabled. 

247 """ 

248 if self.unstable: 

249 return True 

250 if feature in self.enabled_features: 

251 return True 

252 return self.preview and feature not in UNSTABLE_FEATURES 

253 

254 def get_cache_key(self) -> str: 

255 if self.target_versions: 

256 version_str = ",".join( 

257 str(version.value) 

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

259 ) 

260 else: 

261 version_str = "-" 

262 if len(version_str) > _MAX_CACHE_KEY_PART_LENGTH: 

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

264 :_MAX_CACHE_KEY_PART_LENGTH 

265 ] 

266 features_and_magics = ( 

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

268 + "@" 

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

270 ) 

271 if len(features_and_magics) > _MAX_CACHE_KEY_PART_LENGTH: 

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

273 :_MAX_CACHE_KEY_PART_LENGTH 

274 ] 

275 parts = [ 

276 version_str, 

277 str(self.line_length), 

278 str(int(self.string_normalization)), 

279 str(int(self.is_pyi)), 

280 str(int(self.is_ipynb)), 

281 str(int(self.skip_source_first_line)), 

282 str(int(self.magic_trailing_comma)), 

283 str(int(self.preview)), 

284 str(int(self.unstable)), 

285 features_and_magics, 

286 ] 

287 return ".".join(parts)