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 16import os 17import re 18import textwrap 19 20from yapf.yapflib import errors 21from yapf.yapflib import py3compat 22 23 24class StyleConfigError(errors.YapfError): 25 """Raised when there's a problem reading the style configuration.""" 26 pass 27 28 29def Get(setting_name): 30 """Get a style setting.""" 31 return _style[setting_name] 32 33 34def Help(): 35 """Return dict mapping style names to help strings.""" 36 return _STYLE_HELP 37 38 39def SetGlobalStyle(style): 40 """Set a style dict.""" 41 global _style 42 global _GLOBAL_STYLE_FACTORY 43 factory = _GetStyleFactory(style) 44 if factory: 45 _GLOBAL_STYLE_FACTORY = factory 46 _style = style 47 48 49_STYLE_HELP = dict( 50 ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=textwrap.dedent("""\ 51 Align closing bracket with visual indentation."""), 52 ALLOW_MULTILINE_LAMBDAS=textwrap.dedent("""\ 53 Allow lambdas to be formatted on more than one line."""), 54 ALLOW_MULTILINE_DICTIONARY_KEYS=textwrap.dedent("""\ 55 Allow dictionary keys to exist on multiple lines. For example: 56 57 x = { 58 ('this is the first element of a tuple', 59 'this is the second element of a tuple'): 60 value, 61 }"""), 62 ALLOW_SPLIT_BEFORE_DICT_VALUE=textwrap.dedent("""\ 63 Allow splits before the dictionary value."""), 64 BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\ 65 Insert a blank line before a 'def' or 'class' immediately nested 66 within another 'def' or 'class'. For example: 67 68 class Foo: 69 # <------ this blank line 70 def method(): 71 ..."""), 72 BLANK_LINE_BEFORE_CLASS_DOCSTRING=textwrap.dedent("""\ 73 Insert a blank line before a class-level docstring."""), 74 BLANK_LINE_BEFORE_MODULE_DOCSTRING=textwrap.dedent("""\ 75 Insert a blank line before a module docstring."""), 76 BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=textwrap.dedent("""\ 77 Number of blank lines surrounding top-level function and class 78 definitions."""), 79 COALESCE_BRACKETS=textwrap.dedent("""\ 80 Do not split consecutive brackets. Only relevant when 81 dedent_closing_brackets is set. For example: 82 83 call_func_that_takes_a_dict( 84 { 85 'key1': 'value1', 86 'key2': 'value2', 87 } 88 ) 89 90 would reformat to: 91 92 call_func_that_takes_a_dict({ 93 'key1': 'value1', 94 'key2': 'value2', 95 })"""), 96 COLUMN_LIMIT=textwrap.dedent("""\ 97 The column limit."""), 98 CONTINUATION_ALIGN_STYLE=textwrap.dedent("""\ 99 The style for continuation alignment. Possible values are: 100 101 - SPACE: Use spaces for continuation alignment. This is default behavior. 102 - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns 103 (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation 104 alignment. 105 - LESS: Slightly left if cannot vertically align continuation lines with 106 indent characters. 107 - VALIGN-RIGHT: Vertically align continuation lines with indent 108 characters. Slightly right (one more indent character) if cannot 109 vertically align continuation lines with indent characters. 110 111 For options FIXED, and VALIGN-RIGHT are only available when USE_TABS is 112 enabled."""), 113 CONTINUATION_INDENT_WIDTH=textwrap.dedent("""\ 114 Indent width used for line continuations."""), 115 DEDENT_CLOSING_BRACKETS=textwrap.dedent("""\ 116 Put closing brackets on a separate line, dedented, if the bracketed 117 expression can't fit in a single line. Applies to all kinds of brackets, 118 including function definitions and calls. For example: 119 120 config = { 121 'key1': 'value1', 122 'key2': 'value2', 123 } # <--- this bracket is dedented and on a separate line 124 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 DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\ 133 Disable the heuristic which places each list element on a separate line 134 if the list is comma-terminated."""), 135 EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\ 136 Place each dictionary entry onto its own line."""), 137 I18N_COMMENT=textwrap.dedent("""\ 138 The regex for an i18n comment. The presence of this comment stops 139 reformatting of that line, because the comments are required to be 140 next to the string they translate."""), 141 I18N_FUNCTION_CALL=textwrap.dedent("""\ 142 The i18n function call names. The presence of this function stops 143 reformattting on that line, because the string it has cannot be moved 144 away from the i18n comment."""), 145 INDENT_DICTIONARY_VALUE=textwrap.dedent("""\ 146 Indent the dictionary value if it cannot fit on the same line as the 147 dictionary key. For example: 148 149 config = { 150 'key1': 151 'value1', 152 'key2': value1 + 153 value2, 154 }"""), 155 INDENT_WIDTH=textwrap.dedent("""\ 156 The number of columns to use for indentation."""), 157 JOIN_MULTIPLE_LINES=textwrap.dedent("""\ 158 Join short lines into one line. E.g., single line 'if' statements."""), 159 NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=textwrap.dedent("""\ 160 Do not include spaces around selected binary operators. For example: 161 162 1 + 2 * 3 - 4 / 5 163 164 will be formatted as follows when configured with *,/: 165 166 1 + 2*3 - 4/5 167 168 """), 169 SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\ 170 Insert a space between the ending comma and closing bracket of a list, 171 etc."""), 172 SPACES_AROUND_POWER_OPERATOR=textwrap.dedent("""\ 173 Use spaces around the power operator."""), 174 SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=textwrap.dedent("""\ 175 Use spaces around default or named assigns."""), 176 SPACES_BEFORE_COMMENT=textwrap.dedent("""\ 177 The number of spaces required before a trailing comment."""), 178 SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=textwrap.dedent("""\ 179 Split before arguments if the argument list is terminated by a 180 comma."""), 181 SPLIT_ALL_COMMA_SEPARATED_VALUES=textwrap.dedent("""\ 182 Split before arguments"""), 183 SPLIT_BEFORE_BITWISE_OPERATOR=textwrap.dedent("""\ 184 Set to True to prefer splitting before '&', '|' or '^' rather than 185 after."""), 186 SPLIT_BEFORE_CLOSING_BRACKET=textwrap.dedent("""\ 187 Split before the closing bracket if a list or dict literal doesn't fit on 188 a single line."""), 189 SPLIT_BEFORE_DICT_SET_GENERATOR=textwrap.dedent("""\ 190 Split before a dictionary or set generator (comp_for). For example, note 191 the split before the 'for': 192 193 foo = { 194 variable: 'Hello world, have a nice day!' 195 for variable in bar if variable != 42 196 }"""), 197 SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=textwrap.dedent("""\ 198 Split after the opening paren which surrounds an expression if it doesn't 199 fit on a single line. 200 """), 201 SPLIT_BEFORE_FIRST_ARGUMENT=textwrap.dedent("""\ 202 If an argument / parameter list is going to be split, then split before 203 the first argument."""), 204 SPLIT_BEFORE_LOGICAL_OPERATOR=textwrap.dedent("""\ 205 Set to True to prefer splitting before 'and' or 'or' rather than 206 after."""), 207 SPLIT_BEFORE_NAMED_ASSIGNS=textwrap.dedent("""\ 208 Split named assignments onto individual lines."""), 209 SPLIT_COMPLEX_COMPREHENSION=textwrap.dedent("""\ 210 Set to True to split list comprehensions and generators that have 211 non-trivial expressions and multiple clauses before each of these 212 clauses. For example: 213 214 result = [ 215 a_long_var + 100 for a_long_var in xrange(1000) 216 if a_long_var % 10] 217 218 would reformat to something like: 219 220 result = [ 221 a_long_var + 100 222 for a_long_var in xrange(1000) 223 if a_long_var % 10] 224 """), 225 SPLIT_PENALTY_AFTER_OPENING_BRACKET=textwrap.dedent("""\ 226 The penalty for splitting right after the opening bracket."""), 227 SPLIT_PENALTY_AFTER_UNARY_OPERATOR=textwrap.dedent("""\ 228 The penalty for splitting the line after a unary operator."""), 229 SPLIT_PENALTY_BEFORE_IF_EXPR=textwrap.dedent("""\ 230 The penalty for splitting right before an if expression."""), 231 SPLIT_PENALTY_BITWISE_OPERATOR=textwrap.dedent("""\ 232 The penalty of splitting the line around the '&', '|', and '^' 233 operators."""), 234 SPLIT_PENALTY_COMPREHENSION=textwrap.dedent("""\ 235 The penalty for splitting a list comprehension or generator 236 expression."""), 237 SPLIT_PENALTY_EXCESS_CHARACTER=textwrap.dedent("""\ 238 The penalty for characters over the column limit."""), 239 SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent("""\ 240 The penalty incurred by adding a line split to the unwrapped line. The 241 more line splits added the higher the penalty."""), 242 SPLIT_PENALTY_IMPORT_NAMES=textwrap.dedent("""\ 243 The penalty of splitting a list of "import as" names. For example: 244 245 from a_very_long_or_indented_module_name_yada_yad import (long_argument_1, 246 long_argument_2, 247 long_argument_3) 248 249 would reformat to something like: 250 251 from a_very_long_or_indented_module_name_yada_yad import ( 252 long_argument_1, long_argument_2, long_argument_3) 253 """), 254 SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent("""\ 255 The penalty of splitting the line around the 'and' and 'or' 256 operators."""), 257 USE_TABS=textwrap.dedent("""\ 258 Use the Tab character for indentation."""), 259 # BASED_ON_STYLE='Which predefined style this style is based on', 260) 261 262 263def CreatePEP8Style(): 264 return dict( 265 ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=True, 266 ALLOW_MULTILINE_LAMBDAS=False, 267 ALLOW_MULTILINE_DICTIONARY_KEYS=False, 268 ALLOW_SPLIT_BEFORE_DICT_VALUE=True, 269 BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False, 270 BLANK_LINE_BEFORE_CLASS_DOCSTRING=False, 271 BLANK_LINE_BEFORE_MODULE_DOCSTRING=False, 272 BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=2, 273 COALESCE_BRACKETS=False, 274 COLUMN_LIMIT=79, 275 CONTINUATION_ALIGN_STYLE='SPACE', 276 CONTINUATION_INDENT_WIDTH=4, 277 DEDENT_CLOSING_BRACKETS=False, 278 DISABLE_ENDING_COMMA_HEURISTIC=False, 279 EACH_DICT_ENTRY_ON_SEPARATE_LINE=True, 280 I18N_COMMENT='', 281 I18N_FUNCTION_CALL='', 282 INDENT_DICTIONARY_VALUE=False, 283 INDENT_WIDTH=4, 284 JOIN_MULTIPLE_LINES=True, 285 SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True, 286 SPACES_AROUND_POWER_OPERATOR=False, 287 NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(), 288 SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False, 289 SPACES_BEFORE_COMMENT=2, 290 SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False, 291 SPLIT_ALL_COMMA_SEPARATED_VALUES=False, 292 SPLIT_BEFORE_BITWISE_OPERATOR=True, 293 SPLIT_BEFORE_CLOSING_BRACKET=True, 294 SPLIT_BEFORE_DICT_SET_GENERATOR=True, 295 SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=False, 296 SPLIT_BEFORE_FIRST_ARGUMENT=False, 297 SPLIT_BEFORE_LOGICAL_OPERATOR=True, 298 SPLIT_BEFORE_NAMED_ASSIGNS=True, 299 SPLIT_COMPLEX_COMPREHENSION=False, 300 SPLIT_PENALTY_AFTER_OPENING_BRACKET=30, 301 SPLIT_PENALTY_AFTER_UNARY_OPERATOR=10000, 302 SPLIT_PENALTY_BEFORE_IF_EXPR=0, 303 SPLIT_PENALTY_BITWISE_OPERATOR=300, 304 SPLIT_PENALTY_COMPREHENSION=80, 305 SPLIT_PENALTY_EXCESS_CHARACTER=4500, 306 SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30, 307 SPLIT_PENALTY_IMPORT_NAMES=0, 308 SPLIT_PENALTY_LOGICAL_OPERATOR=300, 309 USE_TABS=False, 310 ) 311 312 313def CreateGoogleStyle(): 314 style = CreatePEP8Style() 315 style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False 316 style['BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF'] = True 317 style['COLUMN_LIMIT'] = 80 318 style['INDENT_WIDTH'] = 4 319 style['I18N_COMMENT'] = r'#\..*' 320 style['I18N_FUNCTION_CALL'] = ['N_', '_'] 321 style['SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET'] = False 322 style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False 323 style['SPLIT_BEFORE_DICT_SET_GENERATOR'] = False 324 style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False 325 style['SPLIT_COMPLEX_COMPREHENSION'] = True 326 style['SPLIT_PENALTY_COMPREHENSION'] = 2100 327 return style 328 329 330def CreateChromiumStyle(): 331 style = CreateGoogleStyle() 332 style['ALLOW_MULTILINE_DICTIONARY_KEYS'] = True 333 style['INDENT_DICTIONARY_VALUE'] = True 334 style['INDENT_WIDTH'] = 2 335 style['JOIN_MULTIPLE_LINES'] = False 336 style['SPLIT_BEFORE_BITWISE_OPERATOR'] = True 337 style['SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN'] = True 338 return style 339 340 341def CreateFacebookStyle(): 342 style = CreatePEP8Style() 343 style['ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT'] = False 344 style['COLUMN_LIMIT'] = 80 345 style['DEDENT_CLOSING_BRACKETS'] = True 346 style['INDENT_DICTIONARY_VALUE'] = True 347 style['JOIN_MULTIPLE_LINES'] = False 348 style['SPACES_BEFORE_COMMENT'] = 2 349 style['SPLIT_PENALTY_AFTER_OPENING_BRACKET'] = 0 350 style['SPLIT_PENALTY_BEFORE_IF_EXPR'] = 30 351 style['SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT'] = 30 352 style['SPLIT_BEFORE_LOGICAL_OPERATOR'] = False 353 style['SPLIT_BEFORE_BITWISE_OPERATOR'] = False 354 return style 355 356 357_STYLE_NAME_TO_FACTORY = dict( 358 pep8=CreatePEP8Style, 359 chromium=CreateChromiumStyle, 360 google=CreateGoogleStyle, 361 facebook=CreateFacebookStyle, 362) 363 364_DEFAULT_STYLE_TO_FACTORY = [ 365 (CreateChromiumStyle(), CreateChromiumStyle), 366 (CreateFacebookStyle(), CreateFacebookStyle), 367 (CreateGoogleStyle(), CreateGoogleStyle), 368 (CreatePEP8Style(), CreatePEP8Style), 369] 370 371 372def _GetStyleFactory(style): 373 for def_style, factory in _DEFAULT_STYLE_TO_FACTORY: 374 if style == def_style: 375 return factory 376 return None 377 378 379def _ContinuationAlignStyleStringConverter(s): 380 """Option value converter for a continuation align style string.""" 381 accepted_styles = ('SPACE', 'FIXED', 'VALIGN-RIGHT') 382 if s: 383 r = s.upper() 384 if r not in accepted_styles: 385 raise ValueError('unknown continuation align style: %r' % (s,)) 386 else: 387 r = accepted_styles[0] 388 return r 389 390 391def _StringListConverter(s): 392 """Option value converter for a comma-separated list of strings.""" 393 return [part.strip() for part in s.split(',')] 394 395 396def _StringSetConverter(s): 397 """Option value converter for a comma-separated set of strings.""" 398 return set(part.strip() for part in s.split(',')) 399 400 401def _BoolConverter(s): 402 """Option value converter for a boolean.""" 403 return py3compat.CONFIGPARSER_BOOLEAN_STATES[s.lower()] 404 405 406# Different style options need to have their values interpreted differently when 407# read from the config file. This dict maps an option name to a "converter" 408# function that accepts the string read for the option's value from the file and 409# returns it wrapper in actual Python type that's going to be meaningful to 410# yapf. 411# 412# Note: this dict has to map all the supported style options. 413_STYLE_OPTION_VALUE_CONVERTER = dict( 414 ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=_BoolConverter, 415 ALLOW_MULTILINE_LAMBDAS=_BoolConverter, 416 ALLOW_MULTILINE_DICTIONARY_KEYS=_BoolConverter, 417 ALLOW_SPLIT_BEFORE_DICT_VALUE=_BoolConverter, 418 BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=_BoolConverter, 419 BLANK_LINE_BEFORE_CLASS_DOCSTRING=_BoolConverter, 420 BLANK_LINE_BEFORE_MODULE_DOCSTRING=_BoolConverter, 421 BLANK_LINES_AROUND_TOP_LEVEL_DEFINITION=int, 422 COALESCE_BRACKETS=_BoolConverter, 423 COLUMN_LIMIT=int, 424 CONTINUATION_ALIGN_STYLE=_ContinuationAlignStyleStringConverter, 425 CONTINUATION_INDENT_WIDTH=int, 426 DEDENT_CLOSING_BRACKETS=_BoolConverter, 427 DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter, 428 EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter, 429 I18N_COMMENT=str, 430 I18N_FUNCTION_CALL=_StringListConverter, 431 INDENT_DICTIONARY_VALUE=_BoolConverter, 432 INDENT_WIDTH=int, 433 JOIN_MULTIPLE_LINES=_BoolConverter, 434 NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=_StringSetConverter, 435 SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=_BoolConverter, 436 SPACES_AROUND_POWER_OPERATOR=_BoolConverter, 437 SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=_BoolConverter, 438 SPACES_BEFORE_COMMENT=int, 439 SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=_BoolConverter, 440 SPLIT_ALL_COMMA_SEPARATED_VALUES=_BoolConverter, 441 SPLIT_BEFORE_BITWISE_OPERATOR=_BoolConverter, 442 SPLIT_BEFORE_CLOSING_BRACKET=_BoolConverter, 443 SPLIT_BEFORE_DICT_SET_GENERATOR=_BoolConverter, 444 SPLIT_BEFORE_EXPRESSION_AFTER_OPENING_PAREN=_BoolConverter, 445 SPLIT_BEFORE_FIRST_ARGUMENT=_BoolConverter, 446 SPLIT_BEFORE_LOGICAL_OPERATOR=_BoolConverter, 447 SPLIT_BEFORE_NAMED_ASSIGNS=_BoolConverter, 448 SPLIT_COMPLEX_COMPREHENSION=_BoolConverter, 449 SPLIT_PENALTY_AFTER_OPENING_BRACKET=int, 450 SPLIT_PENALTY_AFTER_UNARY_OPERATOR=int, 451 SPLIT_PENALTY_BEFORE_IF_EXPR=int, 452 SPLIT_PENALTY_BITWISE_OPERATOR=int, 453 SPLIT_PENALTY_COMPREHENSION=int, 454 SPLIT_PENALTY_EXCESS_CHARACTER=int, 455 SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int, 456 SPLIT_PENALTY_IMPORT_NAMES=int, 457 SPLIT_PENALTY_LOGICAL_OPERATOR=int, 458 USE_TABS=_BoolConverter, 459) 460 461 462def CreateStyleFromConfig(style_config): 463 """Create a style dict from the given config. 464 465 Arguments: 466 style_config: either a style name or a file name. The file is expected to 467 contain settings. It can have a special BASED_ON_STYLE setting naming the 468 style which it derives from. If no such setting is found, it derives from 469 the default style. When style_config is None, the _GLOBAL_STYLE_FACTORY 470 config is created. 471 472 Returns: 473 A style dict. 474 475 Raises: 476 StyleConfigError: if an unknown style option was encountered. 477 """ 478 479 def GlobalStyles(): 480 for style, _ in _DEFAULT_STYLE_TO_FACTORY: 481 yield style 482 483 def_style = False 484 if style_config is None: 485 for style in GlobalStyles(): 486 if _style == style: 487 def_style = True 488 break 489 if not def_style: 490 return _style 491 return _GLOBAL_STYLE_FACTORY() 492 if isinstance(style_config, dict): 493 config = _CreateConfigParserFromConfigDict(style_config) 494 elif isinstance(style_config, py3compat.basestring): 495 style_factory = _STYLE_NAME_TO_FACTORY.get(style_config.lower()) 496 if style_factory is not None: 497 return style_factory() 498 if style_config.startswith('{'): 499 # Most likely a style specification from the command line. 500 config = _CreateConfigParserFromConfigString(style_config) 501 else: 502 # Unknown config name: assume it's a file name then. 503 config = _CreateConfigParserFromConfigFile(style_config) 504 return _CreateStyleFromConfigParser(config) 505 506 507def _CreateConfigParserFromConfigDict(config_dict): 508 config = py3compat.ConfigParser() 509 config.add_section('style') 510 for key, value in config_dict.items(): 511 config.set('style', key, str(value)) 512 return config 513 514 515def _CreateConfigParserFromConfigString(config_string): 516 """Given a config string from the command line, return a config parser.""" 517 if config_string[0] != '{' or config_string[-1] != '}': 518 raise StyleConfigError( 519 "Invalid style dict syntax: '{}'.".format(config_string)) 520 config = py3compat.ConfigParser() 521 config.add_section('style') 522 for key, value in re.findall(r'([a-zA-Z0-9_]+)\s*[:=]\s*([a-zA-Z0-9_]+)', 523 config_string): 524 config.set('style', key, value) 525 return config 526 527 528def _CreateConfigParserFromConfigFile(config_filename): 529 """Read the file and return a ConfigParser object.""" 530 if not os.path.exists(config_filename): 531 # Provide a more meaningful error here. 532 raise StyleConfigError( 533 '"{0}" is not a valid style or file path'.format(config_filename)) 534 with open(config_filename) as style_file: 535 config = py3compat.ConfigParser() 536 config.read_file(style_file) 537 if config_filename.endswith(SETUP_CONFIG): 538 if not config.has_section('yapf'): 539 raise StyleConfigError( 540 'Unable to find section [yapf] in {0}'.format(config_filename)) 541 elif config_filename.endswith(LOCAL_STYLE): 542 if not config.has_section('style'): 543 raise StyleConfigError( 544 'Unable to find section [style] in {0}'.format(config_filename)) 545 else: 546 if not config.has_section('style'): 547 raise StyleConfigError( 548 'Unable to find section [style] in {0}'.format(config_filename)) 549 return config 550 551 552def _CreateStyleFromConfigParser(config): 553 """Create a style dict from a configuration file. 554 555 Arguments: 556 config: a ConfigParser object. 557 558 Returns: 559 A style dict. 560 561 Raises: 562 StyleConfigError: if an unknown style option was encountered. 563 """ 564 # Initialize the base style. 565 section = 'yapf' if config.has_section('yapf') else 'style' 566 if config.has_option('style', 'based_on_style'): 567 based_on = config.get('style', 'based_on_style').lower() 568 base_style = _STYLE_NAME_TO_FACTORY[based_on]() 569 elif config.has_option('yapf', 'based_on_style'): 570 based_on = config.get('yapf', 'based_on_style').lower() 571 base_style = _STYLE_NAME_TO_FACTORY[based_on]() 572 else: 573 base_style = _GLOBAL_STYLE_FACTORY() 574 575 # Read all options specified in the file and update the style. 576 for option, value in config.items(section): 577 if option.lower() == 'based_on_style': 578 # Now skip this one - we've already handled it and it's not one of the 579 # recognized style options. 580 continue 581 option = option.upper() 582 if option not in _STYLE_OPTION_VALUE_CONVERTER: 583 raise StyleConfigError('Unknown style option "{0}"'.format(option)) 584 try: 585 base_style[option] = _STYLE_OPTION_VALUE_CONVERTER[option](value) 586 except ValueError: 587 raise StyleConfigError("'{}' is not a valid setting for {}.".format( 588 value, option)) 589 return base_style 590 591 592# The default style - used if yapf is not invoked without specifically 593# requesting a formatting style. 594DEFAULT_STYLE = 'pep8' 595DEFAULT_STYLE_FACTORY = CreatePEP8Style 596_GLOBAL_STYLE_FACTORY = CreatePEP8Style 597 598# The name of the file to use for global style definition. 599GLOBAL_STYLE = ( 600 os.path.join( 601 os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), 'yapf', 602 'style')) 603 604# The name of the file to use for directory-local style definition. 605LOCAL_STYLE = '.style.yapf' 606 607# Alternative place for directory-local style definition. Style should be 608# specified in the '[yapf]' section. 609SETUP_CONFIG = 'setup.cfg' 610 611# TODO(eliben): For now we're preserving the global presence of a style dict. 612# Refactor this so that the style is passed around through yapf rather than 613# being global. 614_style = None 615SetGlobalStyle(_GLOBAL_STYLE_FACTORY()) 616