style.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858
  1. # Copyright 2015 Google Inc. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Python formatting style settings."""
  15. import os
  16. import re
  17. import textwrap
  18. from configparser import ConfigParser
  19. from yapf.yapflib import errors
  20. class StyleConfigError(errors.YapfError):
  21. """Raised when there's a problem reading the style configuration."""
  22. pass
  23. def Get(setting_name):
  24. """Get a style setting."""
  25. return _style[setting_name]
  26. def GetOrDefault(setting_name, default_value):
  27. """Get a style setting or default value if the setting does not exist."""
  28. return _style.get(setting_name, default_value)
  29. def Help():
  30. """Return dict mapping style names to help strings."""
  31. return _STYLE_HELP
  32. def SetGlobalStyle(style):
  33. """Set a style dict."""
  34. global _style
  35. global _GLOBAL_STYLE_FACTORY
  36. factory = _GetStyleFactory(style)
  37. if factory:
  38. _GLOBAL_STYLE_FACTORY = factory
  39. _style = style
  40. _STYLE_HELP = dict(
  41. ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent("""\
  42. Align closing bracket with visual indentation."""),
  43. ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\
  44. Allow lambdas to be formatted on more than one line."""),
  45. ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\
  46. Allow dictionary keys to exist on multiple lines. For example:
  47. x = {
  48. ('this is the first element of a tuple',
  49. 'this is the second element of a tuple'):
  50. value,
  51. }"""),
  52. ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=textwrap.dedent("""\
  53. Allow splitting before a default / named assignment in an argument list.
  54. """),
  55. ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent("""\
  56. Allow splits before the dictionary value."""),
  57. ARITHMETIC_PRECEDENCE_INDICATION=textwrap.dedent("""\
  58. Let spacing indicate operator precedence. For example:
  59. a = 1 * 2 + 3 / 4
  60. b = 1 / 2 - 3 * 4
  61. c = (1 + 2) * (3 - 4)
  62. d = (1 - 2) / (3 + 4)
  63. e = 1 * 2 - 3
  64. f = 1 + 2 + 3 + 4
  65. will be formatted as follows to indicate precedence:
  66. a = 1*2 + 3/4
  67. b = 1/2 - 3*4
  68. c = (1+2) * (3-4)
  69. d = (1-2) / (3+4)
  70. e = 1*2 - 3
  71. f = 1 + 2 + 3 + 4
  72. """),
  73. BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\
  74. Insert a blank line before a 'def' or 'class' immediately nested
  75. within another 'def' or 'class'. For example:
  76. class Foo:
  77. # <------ this blank line
  78. def method():
  79. ..."""),
  80. BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\
  81. Insert a blank line before a class-level docstring."""),
  82. BLANK_LINE_BEFORE_MODULE_DOCSTRING=textwrap.dedent("""\
  83. Insert a blank line before a module docstring."""),
  84. BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent("""\
  85. Number of blank lines surrounding top-level function and class
  86. definitions."""),
  87. BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=textwrap.dedent("""\
  88. Number of blank lines between top-level imports and variable
  89. definitions."""),
  90. COALESCE_BRACKETS=textwrap.dedent("""\
  91. Do not split consecutive brackets. Only relevant when
  92. dedent_closing_brackets is set. For example:
  93. call_func_that_takes_a_dict(
  94. {
  95. 'key1': 'value1',
  96. 'key2': 'value2',
  97. }
  98. )
  99. would reformat to:
  100. call_func_that_takes_a_dict({
  101. 'key1': 'value1',
  102. 'key2': 'value2',
  103. })"""),
  104. COLUMN_LIMIT=textwrap.dedent("""\
  105. The column limit."""),
  106. CONTINUATION_ALIGN_STYLE=textwrap.dedent("""\
  107. The style for continuation alignment. Possible values are:
  108. - SPACE: Use spaces for continuation alignment. This is default behavior.
  109. - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns
  110. (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs or
  111. CONTINUATION_INDENT_WIDTH spaces) for continuation alignment.
  112. - VALIGN-RIGHT: Vertically align continuation lines to multiple of
  113. INDENT_WIDTH columns. Slightly right (one tab or a few spaces) if
  114. cannot vertically align continuation lines with indent characters."""),
  115. CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\
  116. Indent width used for line continuations."""),
  117. DEDENT_CLOSING_BRACKETS=textwrap.dedent("""\
  118. Put closing brackets on a separate line, dedented, if the bracketed
  119. expression can't fit in a single line. Applies to all kinds of brackets,
  120. including function definitions and calls. For example:
  121. config = {
  122. 'key1': 'value1',
  123. 'key2': 'value2',
  124. } # <--- this bracket is dedented and on a separate line
  125. time_series = self.remote_client.query_entity_counters(
  126. entity='dev3246.region1',
  127. key='dns.query_latency_tcp',
  128. transform=Transformation.AVERAGE(window=timedelta(seconds=60)),
  129. start_ts=now()-timedelta(days=3),
  130. end_ts=now(),
  131. ) # <--- this bracket is dedented and on a separate line
  132. """),
  133. DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\
  134. Disable the heuristic which places each list element on a separate line
  135. if the list is comma-terminated."""),
  136. EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\
  137. Place each dictionary entry onto its own line."""),
  138. FORCE_MULTILINE_DICT=textwrap.dedent("""\
  139. Require multiline dictionary even if it would normally fit on one line.
  140. For example:
  141. config = {
  142. 'key1': 'value1'
  143. }"""),
  144. I18N_COMMENT=textwrap.dedent("""\
  145. The regex for an i18n comment. The presence of this comment stops
  146. reformatting of that line, because the comments are required to be
  147. next to the string they translate."""),
  148. I18N_FUNCTION_CALL=textwrap.dedent("""\
  149. The i18n function call names. The presence of this function stops
  150. reformattting on that line, because the string it has cannot be moved
  151. away from the i18n comment."""),
  152. INDENT_CLOSING_BRACKETS=textwrap.dedent("""\
  153. Put closing brackets on a separate line, indented, if the bracketed
  154. expression can't fit in a single line. Applies to all kinds of brackets,
  155. including function definitions and calls. For example:
  156. config = {
  157. 'key1': 'value1',
  158. 'key2': 'value2',
  159. } # <--- this bracket is indented and on a separate line
  160. time_series = self.remote_client.query_entity_counters(
  161. entity='dev3246.region1',
  162. key='dns.query_latency_tcp',
  163. transform=Transformation.AVERAGE(window=timedelta(seconds=60)),
  164. start_ts=now()-timedelta(days=3),
  165. end_ts=now(),
  166. ) # <--- this bracket is indented and on a separate line
  167. """),
  168. INDENT_DICTIONARY_VALUE=textwrap.dedent("""\
  169. Indent the dictionary value if it cannot fit on the same line as the
  170. dictionary key. For example:
  171. config = {
  172. 'key1':
  173. 'value1',
  174. 'key2': value1 +
  175. value2,
  176. }
  177. """),
  178. INDENT_WIDTH=textwrap.dedent("""\
  179. The number of columns to use for indentation."""),
  180. INDENT_BLANK_LINES=textwrap.dedent("""\
  181. Indent blank lines."""),
  182. JOIN_MULTIPLE_LINES=textwrap.dedent("""\
  183. Join short lines into one line. E.g., single line 'if' statements."""),
  184. NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent("""\
  185. Do not include spaces around selected binary operators. For example:
  186. 1 + 2 * 3 - 4 / 5
  187. will be formatted as follows when configured with "*,/":
  188. 1 + 2*3 - 4/5
  189. """),
  190. SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\
  191. Insert a space between the ending comma and closing bracket of a list,
  192. etc."""),
  193. SPACE_INSIDE_BRACKETS=textwrap.dedent("""\
  194. Use spaces inside brackets, braces, and parentheses. For example:
  195. method_call( 1 )
  196. my_dict[ 3 ][ 1 ][ get_index( *args, **kwargs ) ]
  197. my_set = { 1, 2, 3 }
  198. """),
  199. SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\
  200. Use spaces around the power operator."""),
  201. SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\
  202. Use spaces around default or named assigns."""),
  203. SPACES_AROUND_DICT_DELIMITERS=textwrap.dedent("""\
  204. Adds a space after the opening '{' and before the ending '}' dict
  205. delimiters.
  206. {1: 2}
  207. will be formatted as:
  208. { 1: 2 }
  209. """),
  210. SPACES_AROUND_LIST_DELIMITERS=textwrap.dedent("""\
  211. Adds a space after the opening '[' and before the ending ']' list
  212. delimiters.
  213. [1, 2]
  214. will be formatted as:
  215. [ 1, 2 ]
  216. """),
  217. SPACES_AROUND_SUBSCRIPT_COLON=textwrap.dedent("""\
  218. Use spaces around the subscript / slice operator. For example:
  219. my_list[1 : 10 : 2]
  220. """),
  221. SPACES_AROUND_TUPLE_DELIMITERS=textwrap.dedent("""\
  222. Adds a space after the opening '(' and before the ending ')' tuple
  223. delimiters.
  224. (1, 2, 3)
  225. will be formatted as:
  226. ( 1, 2, 3 )
  227. """),
  228. SPACES_BEFORE_COMMENT=textwrap.dedent("""\
  229. The number of spaces required before a trailing comment.
  230. This can be a single value (representing the number of spaces
  231. before each trailing comment) or list of values (representing
  232. alignment column values; trailing comments within a block will
  233. be aligned to the first column value that is greater than the maximum
  234. line length within the block). For example:
  235. With spaces_before_comment=5:
  236. 1 + 1 # Adding values
  237. will be formatted as:
  238. 1 + 1 # Adding values <-- 5 spaces between the end of the
  239. # statement and comment
  240. With spaces_before_comment=15, 20:
  241. 1 + 1 # Adding values
  242. two + two # More adding
  243. longer_statement # This is a longer statement
  244. short # This is a shorter statement
  245. a_very_long_statement_that_extends_beyond_the_final_column # Comment
  246. short # This is a shorter statement
  247. will be formatted as:
  248. 1 + 1 # Adding values <-- end of line comments in block
  249. # aligned to col 15
  250. two + two # More adding
  251. longer_statement # This is a longer statement <-- end of line
  252. # comments in block aligned to col 20
  253. short # This is a shorter statement
  254. a_very_long_statement_that_extends_beyond_the_final_column # Comment <-- the end of line comments are aligned based on the line length
  255. short # This is a shorter statement
  256. """), # noqa
  257. SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\
  258. Split before arguments if the argument list is terminated by a
  259. comma."""),
  260. SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\
  261. Split before arguments"""),
  262. SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\
  263. Split before arguments, but do not split all subexpressions recursively
  264. (unless needed)."""),
  265. SPLIT_BEFORE_ARITHMETIC_OPERATOR=textwrap.dedent("""\
  266. Set to True to prefer splitting before '+', '-', '*', '/', '//', or '@'
  267. rather than after."""),
  268. SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\
  269. Set to True to prefer splitting before '&', '|' or '^' rather than
  270. after."""),
  271. SPLIT_BEFORE_CLOSING_BRACKET=textwrap.dedent("""\
  272. Split before the closing bracket if a list or dict literal doesn't fit on
  273. a single line."""),
  274. SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent("""\
  275. Split before a dictionary or set generator (comp_for). For example, note
  276. the split before the 'for':
  277. foo = {
  278. variable: 'Hello world, have a nice day!'
  279. for variable in bar if variable != 42
  280. }"""),
  281. SPLIT_BEFORE_DOT=textwrap.dedent("""\
  282. Split before the '.' if we need to split a longer expression:
  283. foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d))
  284. would reformat to something like:
  285. foo = ('This is a really long string: {}, {}, {}, {}'
  286. .format(a, b, c, d))
  287. """), # noqa
  288. SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\
  289. Split after the opening paren which surrounds an expression if it doesn't
  290. fit on a single line.
  291. """),
  292. SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent("""\
  293. If an argument / parameter list is going to be split, then split before
  294. the first argument."""),
  295. SPLIT_BEFORE_LOGICAL_OPERATOR=textwrap.dedent("""\
  296. Set to True to prefer splitting before 'and' or 'or' rather than
  297. after."""),
  298. SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent("""\
  299. Split named assignments onto individual lines."""),
  300. SPLIT_COMPLEX_COMPREHENSION=textwrap.dedent("""\
  301. Set to True to split list comprehensions and generators that have
  302. non-trivial expressions and multiple clauses before each of these
  303. clauses. For example:
  304. result = [
  305. a_long_var + 100 for a_long_var in xrange(1000)
  306. if a_long_var % 10]
  307. would reformat to something like:
  308. result = [
  309. a_long_var + 100
  310. for a_long_var in xrange(1000)
  311. if a_long_var % 10]
  312. """),
  313. SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent("""\
  314. The penalty for splitting right after the opening bracket."""),
  315. SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent("""\
  316. The penalty for splitting the line after a unary operator."""),
  317. SPLIT_PENALTY_ARITHMETIC_OPERATOR=textwrap.dedent("""\
  318. The penalty of splitting the line around the '+', '-', '*', '/', '//',
  319. ``%``, and '@' operators."""),
  320. SPLIT_PENALTY_BEFORE_IF_EXPR=textwrap.dedent("""\
  321. The penalty for splitting right before an if expression."""),
  322. SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent("""\
  323. The penalty of splitting the line around the '&', '|', and '^'
  324. operators."""),
  325. SPLIT_PENALTY_COMPREHENSION=textwrap.dedent("""\
  326. The penalty for splitting a list comprehension or generator
  327. expression."""),
  328. SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent("""\
  329. The penalty for characters over the column limit."""),
  330. SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent("""\
  331. The penalty incurred by adding a line split to the logical line. The
  332. more line splits added the higher the penalty."""),
  333. SPLIT_PENALTY_IMPORT_NAMES=textwrap.dedent("""\
  334. The penalty of splitting a list of "import as" names. For example:
  335. from a_very_long_or_indented_module_name_yada_yad import (long_argument_1,
  336. long_argument_2,
  337. long_argument_3)
  338. would reformat to something like:
  339. from a_very_long_or_indented_module_name_yada_yad import (
  340. long_argument_1, long_argument_2, long_argument_3)
  341. """), # noqa
  342. SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent("""\
  343. The penalty of splitting the line around the 'and' and 'or'
  344. operators."""),
  345. USE_TABS=textwrap.dedent("""\
  346. Use the Tab character for indentation."""),
  347. # BASED_ON_STYLE='Which predefined style this style is based on',
  348. )
  349. def CreatePEP8Style():
  350. """Create the PEP8 formatting style."""
  351. return dict(
  352. ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True,
  353. ALLOW_MULTILINE_LAMBDAS=False,
  354. ALLOW_MULTILINE_DICTIONARY_KEYS=False,
  355. ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=True,
  356. ALLOW_SPLIT_BEFORE_DICT_VALUE=True,
  357. ARITHMETIC_PRECEDENCE_INDICATION=False,
  358. BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=True,
  359. BLANK_LINE_BEFORE_CLASS_DOCSTRING=False,
  360. BLANK_LINE_BEFORE_MODULE_DOCSTRING=False,
  361. BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2,
  362. BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=1,
  363. COALESCE_BRACKETS=False,
  364. COLUMN_LIMIT=79,
  365. CONTINUATION_ALIGN_STYLE='SPACE',
  366. CONTINUATION_INDENT_WIDTH=4,
  367. DEDENT_CLOSING_BRACKETS=False,
  368. INDENT_CLOSING_BRACKETS=False,
  369. DISABLE_ENDING_COMMA_HEURISTIC=False,
  370. EACH_DICT_ENTRY_ON_SEPARATE_LINE=True,
  371. FORCE_MULTILINE_DICT=False,
  372. I18N_COMMENT='',
  373. I18N_FUNCTION_CALL='',
  374. INDENT_DICTIONARY_VALUE=False,
  375. INDENT_WIDTH=4,
  376. INDENT_BLANK_LINES=False,
  377. JOIN_MULTIPLE_LINES=True,
  378. NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(),
  379. SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True,
  380. SPACE_INSIDE_BRACKETS=False,
  381. SPACES_AROUND_POWER_OPERATOR=False,
  382. SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False,
  383. SPACES_AROUND_DICT_DELIMITERS=False,
  384. SPACES_AROUND_LIST_DELIMITERS=False,
  385. SPACES_AROUND_SUBSCRIPT_COLON=False,
  386. SPACES_AROUND_TUPLE_DELIMITERS=False,
  387. SPACES_BEFORE_COMMENT=2,
  388. SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False,
  389. SPLIT_ALL_COMMA_SEPARATED_VALUES=False,
  390. SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=False,
  391. SPLIT_BEFORE_ARITHMETIC_OPERATOR=False,
  392. SPLIT_BEFORE_BITWISE_OPERATOR=True,
  393. SPLIT_BEFORE_CLOSING_BRACKET=True,
  394. SPLIT_BEFORE_DICT_SET_GENERATOR=True,
  395. SPLIT_BEFORE_DOT=False,
  396. SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=False,
  397. SPLIT_BEFORE_FIRST_ARGUMENT=False,
  398. SPLIT_BEFORE_LOGICAL_OPERATOR=True,
  399. SPLIT_BEFORE_NAMED_ASSIGNS=True,
  400. SPLIT_COMPLEX_COMPREHENSION=False,
  401. SPLIT_PENALTY_AFTER_OPENING_BRACKET=300,
  402. SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000,
  403. SPLIT_PENALTY_ARITHMETIC_OPERATOR=300,
  404. SPLIT_PENALTY_BEFORE_IF_EXPR=0,
  405. SPLIT_PENALTY_BITWISE_OPERATOR=300,
  406. SPLIT_PENALTY_COMPREHENSION=80,
  407. SPLIT_PENALTY_EXCESS_CHARACTER=7000,
  408. SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30,
  409. SPLIT_PENALTY_IMPORT_NAMES=0,
  410. SPLIT_PENALTY_LOGICAL_OPERATOR=300,
  411. USE_TABS=False,
  412. )
  413. def CreateGoogleStyle():
  414. """Create the Google formatting style."""
  415. style = CreatePEP8Style()
  416. style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False
  417. style['COLUMN_LIMIT'] = 80
  418. style['INDENT_DICTIONARY_VALUE'] = True
  419. style['INDENT_WIDTH'] = 4
  420. style['I18N_COMMENT'] = r'#\..*'
  421. style['I18N_FUNCTION_CALL'] = ['N_', '_']
  422. style['JOIN_MULTIPLE_LINES'] = False
  423. style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False
  424. style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False
  425. style['SPLIT_BEFORE_DICT_SET_GENERATOR'] = False
  426. style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False
  427. style['SPLIT_COMPLEX_COMPREHENSION'] = True
  428. style['SPLIT_PENALTY_COMPREHENSION'] = 2100
  429. return style
  430. def CreateYapfStyle():
  431. """Create the YAPF formatting style."""
  432. style = CreateGoogleStyle()
  433. style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True
  434. style['ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS'] = False
  435. style['INDENT_WIDTH'] = 2
  436. style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True
  437. style['SPLIT_BEFORE_DOT'] = True
  438. style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True
  439. return style
  440. def CreateFacebookStyle():
  441. """Create the Facebook formatting style."""
  442. style = CreatePEP8Style()
  443. style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False
  444. style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = False
  445. style['COLUMN_LIMIT'] = 80
  446. style['DEDENT_CLOSING_BRACKETS'] = True
  447. style['INDENT_CLOSING_BRACKETS'] = False
  448. style['INDENT_DICTIONARY_VALUE'] = True
  449. style['JOIN_MULTIPLE_LINES'] = False
  450. style['SPACES_BEFORE_COMMENT'] = 2
  451. style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0
  452. style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30
  453. style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30
  454. style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False
  455. style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False
  456. return style
  457. _STYLE_NAME_TO_FACTORY = dict(
  458. pep8=CreatePEP8Style,
  459. google=CreateGoogleStyle,
  460. facebook=CreateFacebookStyle,
  461. yapf=CreateYapfStyle,
  462. )
  463. _DEFAULT_STYLE_TO_FACTORY = [
  464. (CreateFacebookStyle(), CreateFacebookStyle),
  465. (CreateGoogleStyle(), CreateGoogleStyle),
  466. (CreatePEP8Style(), CreatePEP8Style),
  467. (CreateYapfStyle(), CreateYapfStyle),
  468. ]
  469. def _GetStyleFactory(style):
  470. for def_style, factory in _DEFAULT_STYLE_TO_FACTORY:
  471. if style == def_style:
  472. return factory
  473. return None
  474. def _ContinuationAlignStyleStringConverter(s):
  475. """Option value converter for a continuation align style string."""
  476. accepted_styles = ('SPACE', 'FIXED', 'VALIGN-RIGHT')
  477. if s:
  478. r = s.strip('"\'').replace('_', '-').upper()
  479. if r not in accepted_styles:
  480. raise ValueError('unknown continuation align style: %r' % (s,))
  481. else:
  482. r = accepted_styles[0]
  483. return r
  484. def _StringListConverter(s):
  485. """Option value converter for a comma-separated list of strings."""
  486. return [part.strip() for part in s.split(',')]
  487. def _StringSetConverter(s):
  488. """Option value converter for a comma-separated set of strings."""
  489. if len(s) > 2 and s[0] in '"\'':
  490. s = s[1:-1]
  491. return {part.strip() for part in s.split(',')}
  492. def _BoolConverter(s):
  493. """Option value converter for a boolean."""
  494. return ConfigParser.BOOLEAN_STATES[s.lower()]
  495. def _IntListConverter(s):
  496. """Option value converter for a comma-separated list of integers."""
  497. s = s.strip()
  498. if s.startswith('[') and s.endswith(']'):
  499. s = s[1:-1]
  500. return [int(part.strip()) for part in s.split(',') if part.strip()]
  501. def _IntOrIntListConverter(s):
  502. """Option value converter for an integer or list of integers."""
  503. if len(s) > 2 and s[0] in '"\'':
  504. s = s[1:-1]
  505. return _IntListConverter(s) if ',' in s else int(s)
  506. # Different style options need to have their values interpreted differently when
  507. # read from the config file. This dict maps an option name to a "converter"
  508. # function that accepts the string read for the option's value from the file and
  509. # returns it wrapper in actual Python type that's going to be meaningful to
  510. # yapf.
  511. #
  512. # Note: this dict has to map all the supported style options.
  513. _STYLE_OPTION_VALUE_CONVERTER = dict(
  514. ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter,
  515. ALLOW_MULTILINE_LAMBDAS=_BoolConverter,
  516. ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter,
  517. ALLOW_SPLIT_BEFORE_DEFAULT_OR_NAMED_ASSIGNS=_BoolConverter,
  518. ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter,
  519. ARITHMETIC_PRECEDENCE_INDICATION=_BoolConverter,
  520. BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter,
  521. BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter,
  522. BLANK_LINE_BEFORE_MODULE_DOCSTRING=_BoolConverter,
  523. BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=int,
  524. BLANK_LINES_BETWEEN_TOP_LEVEL_IMPORTS_AND_VARIABLES=int,
  525. COALESCE_BRACKETS=_BoolConverter,
  526. COLUMN_LIMIT=int,
  527. CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter,
  528. CONTINUATION_INDENT_WIDTH=int,
  529. DEDENT_CLOSING_BRACKETS=_BoolConverter,
  530. INDENT_CLOSING_BRACKETS=_BoolConverter,
  531. DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter,
  532. EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter,
  533. FORCE_MULTILINE_DICT=_BoolConverter,
  534. I18N_COMMENT=str,
  535. I18N_FUNCTION_CALL=_StringListConverter,
  536. INDENT_DICTIONARY_VALUE=_BoolConverter,
  537. INDENT_WIDTH=int,
  538. INDENT_BLANK_LINES=_BoolConverter,
  539. JOIN_MULTIPLE_LINES=_BoolConverter,
  540. NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=_StringSetConverter,
  541. SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter,
  542. SPACE_INSIDE_BRACKETS=_BoolConverter,
  543. SPACES_AROUND_POWER_OPERATOR=_BoolConverter,
  544. SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter,
  545. SPACES_AROUND_DICT_DELIMITERS=_BoolConverter,
  546. SPACES_AROUND_LIST_DELIMITERS=_BoolConverter,
  547. SPACES_AROUND_SUBSCRIPT_COLON=_BoolConverter,
  548. SPACES_AROUND_TUPLE_DELIMITERS=_BoolConverter,
  549. SPACES_BEFORE_COMMENT=_IntOrIntListConverter,
  550. SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter,
  551. SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter,
  552. SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES=_BoolConverter,
  553. SPLIT_BEFORE_ARITHMETIC_OPERATOR=_BoolConverter,
  554. SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter,
  555. SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter,
  556. SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter,
  557. SPLIT_BEFORE_DOT=_BoolConverter,
  558. SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=_BoolConverter,
  559. SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter,
  560. SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter,
  561. SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter,
  562. SPLIT_COMPLEX_COMPREHENSION=_BoolConverter,
  563. SPLIT_PENALTY_AFTER_OPENING_BRACKET=int,
  564. SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int,
  565. SPLIT_PENALTY_ARITHMETIC_OPERATOR=int,
  566. SPLIT_PENALTY_BEFORE_IF_EXPR=int,
  567. SPLIT_PENALTY_BITWISE_OPERATOR=int,
  568. SPLIT_PENALTY_COMPREHENSION=int,
  569. SPLIT_PENALTY_EXCESS_CHARACTER=int,
  570. SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int,
  571. SPLIT_PENALTY_IMPORT_NAMES=int,
  572. SPLIT_PENALTY_LOGICAL_OPERATOR=int,
  573. USE_TABS=_BoolConverter,
  574. )
  575. def CreateStyleFromConfig(style_config):
  576. """Create a style dict from the given config.
  577. Arguments:
  578. style_config: either a style name or a file name. The file is expected to
  579. contain settings. It can have a special BASED_ON_STYLE setting naming the
  580. style which it derives from. If no such setting is found, it derives from
  581. the default style. When style_config is None, the _GLOBAL_STYLE_FACTORY
  582. config is created.
  583. Returns:
  584. A style dict.
  585. Raises:
  586. StyleConfigError: if an unknown style option was encountered.
  587. """
  588. def GlobalStyles():
  589. for style, _ in _DEFAULT_STYLE_TO_FACTORY:
  590. yield style
  591. def_style = False
  592. if style_config is None:
  593. for style in GlobalStyles():
  594. if _style == style:
  595. def_style = True
  596. break
  597. if not def_style:
  598. return _style
  599. return _GLOBAL_STYLE_FACTORY()
  600. if isinstance(style_config, dict):
  601. config = _CreateConfigParserFromConfigDict(style_config)
  602. elif isinstance(style_config, str):
  603. style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower())
  604. if style_factory is not None:
  605. return style_factory()
  606. if style_config.startswith('{'):
  607. # Most likely a style specification from the command line.
  608. config = _CreateConfigParserFromConfigString(style_config)
  609. else:
  610. # Unknown config name: assume it's a file name then.
  611. config = _CreateConfigParserFromConfigFile(style_config)
  612. return _CreateStyleFromConfigParser(config)
  613. def _CreateConfigParserFromConfigDict(config_dict):
  614. config = ConfigParser()
  615. config.add_section('style')
  616. for key, value in config_dict.items():
  617. config.set('style', key, str(value))
  618. return config
  619. def _CreateConfigParserFromConfigString(config_string):
  620. """Given a config string from the command line, return a config parser."""
  621. if config_string[0] != '{' or config_string[-1] != '}':
  622. raise StyleConfigError(
  623. "Invalid style dict syntax: '{}'.".format(config_string))
  624. config = ConfigParser()
  625. config.add_section('style')
  626. for key, value, _ in re.findall(
  627. r'([a-zA-Z0-9_]+)\s*[:=]\s*'
  628. r'(?:'
  629. r'((?P<quote>[\'"]).*?(?P=quote)|'
  630. r'[a-zA-Z0-9_]+)'
  631. r')', config_string): # yapf: disable
  632. config.set('style', key, value)
  633. return config
  634. def _CreateConfigParserFromConfigFile(config_filename):
  635. """Read the file and return a ConfigParser object."""
  636. if not os.path.exists(config_filename):
  637. # Provide a more meaningful error here.
  638. raise StyleConfigError(
  639. '"{0}" is not a valid style or file path'.format(config_filename))
  640. config = ConfigParser()
  641. if config_filename.endswith(PYPROJECT_TOML):
  642. try:
  643. import tomli as tomllib
  644. except ImportError:
  645. raise errors.YapfError(
  646. 'tomli package is needed for using pyproject.toml as a '
  647. 'configuration file')
  648. with open(config_filename, 'rb') as style_file:
  649. pyproject_toml = tomllib.load(style_file)
  650. style_dict = pyproject_toml.get('tool', {}).get('yapf', None)
  651. if style_dict is None:
  652. raise StyleConfigError(
  653. 'Unable to find section [tool.yapf] in {0}'.format(config_filename))
  654. config.add_section('style')
  655. for k, v in style_dict.items():
  656. config.set('style', k, str(v))
  657. return config
  658. with open(config_filename) as style_file:
  659. config.read_file(style_file)
  660. if config_filename.endswith(SETUP_CONFIG):
  661. if not config.has_section('yapf'):
  662. raise StyleConfigError(
  663. 'Unable to find section [yapf] in {0}'.format(config_filename))
  664. return config
  665. if config_filename.endswith(LOCAL_STYLE):
  666. if not config.has_section('style'):
  667. raise StyleConfigError(
  668. 'Unable to find section [style] in {0}'.format(config_filename))
  669. return config
  670. if not config.has_section('style'):
  671. raise StyleConfigError(
  672. 'Unable to find section [style] in {0}'.format(config_filename))
  673. return config
  674. def _CreateStyleFromConfigParser(config):
  675. """Create a style dict from a configuration file.
  676. Arguments:
  677. config: a ConfigParser object.
  678. Returns:
  679. A style dict.
  680. Raises:
  681. StyleConfigError: if an unknown style option was encountered.
  682. """
  683. # Initialize the base style.
  684. section = 'yapf' if config.has_section('yapf') else 'style'
  685. if config.has_option('style', 'based_on_style'):
  686. based_on = config.get('style', 'based_on_style').lower()
  687. base_style = _STYLE_NAME_TO_FACTORY[based_on]()
  688. elif config.has_option('yapf', 'based_on_style'):
  689. based_on = config.get('yapf', 'based_on_style').lower()
  690. base_style = _STYLE_NAME_TO_FACTORY[based_on]()
  691. else:
  692. base_style = _GLOBAL_STYLE_FACTORY()
  693. # Read all options specified in the file and update the style.
  694. for option, value in config.items(section):
  695. if option.lower() == 'based_on_style':
  696. # Now skip this one - we've already handled it and it's not one of the
  697. # recognized style options.
  698. continue
  699. option = option.upper()
  700. if option not in _STYLE_OPTION_VALUE_CONVERTER:
  701. raise StyleConfigError('Unknown style option "{0}"'.format(option))
  702. try:
  703. base_style[option] = _STYLE_OPTION_VALUE_CONVERTER[option](value)
  704. except ValueError:
  705. raise StyleConfigError("'{}' is not a valid setting for {}.".format(
  706. value, option))
  707. return base_style
  708. # The default style - used if yapf is not invoked without specifically
  709. # requesting a formatting style.
  710. DEFAULT_STYLE = 'pep8'
  711. DEFAULT_STYLE_FACTORY = CreatePEP8Style
  712. _GLOBAL_STYLE_FACTORY = CreatePEP8Style
  713. # The name of the file to use for global style definition.
  714. GLOBAL_STYLE = (
  715. os.path.join(
  716. os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'yapf',
  717. 'style'))
  718. # The name of the file to use for directory-local style definition.
  719. LOCAL_STYLE = '.style.yapf'
  720. # Alternative place for directory-local style definition. Style should be
  721. # specified in the '[yapf]' section.
  722. SETUP_CONFIG = 'setup.cfg'
  723. # Style definition by local pyproject.toml file. Style should be specified
  724. # in the '[tool.yapf]' section.
  725. PYPROJECT_TOML = 'pyproject.toml'
  726. # TODO(eliben): For now we're preserving the global presence of a style dict.
  727. # Refactor this so that the style is passed around through yapf rather than
  728. # being global.
  729. _style = None
  730. SetGlobalStyle(_GLOBAL_STYLE_FACTORY())