Repository: google/yapf
Pull request #102 (2015-04-14 11:02:50)

add --style-help cli, show style's settings and setting docstrings
Adds style-help cli, shows the passed style's settings (or the default), along with the docstrings of each of these options.

This seems a much better alternative to #99, cc #93.

```
% python yapf/__init__.py --style-help --style=yapf
ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=False
   Align closing bracket with visual indentation.

BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=True
   Insert a blank line before a 'def' or 'class' immediately nested
   within another 'def' or 'class'.

   For example:

   class Foo:
                      # <------ this blank line
     def method():
       ...

COLUMN_LIMIT=80
   The column limit.

CONTINUATION_INDENT_WIDTH=4
   Indent width used for line continuations.

I18N_COMMENT=#\..*
   The regex for an i18n comment. The presence of this comment stops
   reformatting of that line, because the comments are required to be
   next to the string they translate.

I18N_FUNCTION_CALL=['N_', '_']
   The i18n function call names. The presence of this function stops
   reformattting on that line, because the string it has cannot be moved
   away from the i18n comment.

INDENT_WIDTH=2
   The number of columns to use for indentation.
  ...
```

Note: there will be merge conflicts with #81.


Patch:
diff --git a/yapf/__init__.py b/yapf/__init__.py
index bddfdf1..b9d219f 100644
--- a/yapf/__init__.py
+++ b/yapf/__init__.py
@@ -26,12 +26,15 @@ formatting decisions based on what's the best format for each line.
 If no filenames are specified, YAPF reads the code from stdin.
 """
 
+from __future__ import print_function
+
 import argparse
 import logging
 import sys
 
 from yapf.yapflib import file_resources
 from yapf.yapflib import py3compat
+from yapf.yapflib import style
 from yapf.yapflib import yapf_api
 
 __version__ = '0.1.5'
@@ -54,7 +57,10 @@ def main(argv):
   parser = argparse.ArgumentParser(description='Formatter for Python code.')
   parser.add_argument('--version',
                       action='store_true',
-                      help='print version number and exit')
+                      help='show version number and exit')
+  parser.add_argument('--style-help',
+                      action='store_true',
+                      help='show style settings and exit')
   parser.add_argument(
       '--style',
       action='store',
@@ -91,6 +97,15 @@ def main(argv):
     print('yapf {}'.format(__version__))
     return 0
 
+  if args.style_help:
+    style.SetGlobalStyle(style.CreateStyleFromConfig(args.style))
+    for option, docstring in sorted(style.Help().items()):
+      print(option, "=", style.Get(option), sep='')
+      for line in docstring.splitlines():
+        print('  ', line)
+      print()
+    return 0
+
   if args.lines and len(args.files) > 1:
     parser.error('cannot use -l/--lines with more than one file')
 
diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py
index 838a42a..7d34b30 100644
--- a/yapf/yapflib/style.py
+++ b/yapf/yapflib/style.py
@@ -15,6 +15,7 @@
 
 import os
 import re
+import textwrap
 
 from yapf.yapflib import py3compat
 
@@ -33,82 +34,87 @@ def Get(setting_name):
   return _style[setting_name]
 
 
+def Help():
+  """Return all style settings."""
+  return _STYLE_HELP
+
+
 def SetGlobalStyle(style):
   """Set a style dict."""
   global _style
   _style = style
 
 
+_STYLE_HELP = dict(
+    ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT=
+    'Align closing bracket with visual indentation.',
+    COLUMN_LIMIT='The column limit.',
+    I18N_COMMENT=textwrap.dedent("""\
+      The regex for an i18n comment. The presence of this comment stops
+      reformatting of that line, because the comments are required to be
+      next to the string they translate."""),
+    I18N_FUNCTION_CALL=textwrap.dedent("""\
+      The i18n function call names. The presence of this function stops
+      reformattting on that line, because the string it has cannot be moved
+      away from the i18n comment."""),
+    INDENT_WIDTH='The number of columns to use for indentation.',
+    CONTINUATION_INDENT_WIDTH='Indent width used for line continuations.',
+    BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=textwrap.dedent("""\
+      Insert a blank line before a 'def' or 'class' immediately nested
+      within another 'def' or 'class'.
+
+      For example:
+
+      class Foo:
+                         # <------ this blank line
+        def method():
+          ..."""),
+    SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=textwrap.dedent("""\
+      Insert a space between the ending comma and closing bracket of a list,
+      etc."""),
+    SPACES_BEFORE_COMMENT=(
+        'The number of spaces required before a trailing comment.'),
+    SPLIT_BEFORE_LOGICAL_OPERATOR=
+    "Set to True to prefer splitting before 'and' or 'or' rather than after.",
+    SPLIT_BEFORE_NAMED_ASSIGNS='Split named assignments onto individual lines.',
+    SPLIT_PENALTY_AFTER_UNARY_OPERATOR=
+    'The penalty for splitting the line after a unary operator.',
+    SPLIT_PENALTY_EXCESS_CHARACTER=
+    'The penalty for characters over the column limit.',
+    SPLIT_PENALTY_LOGICAL_OPERATOR=
+    "The penalty of splitting the line around the 'and' and 'or' operators.",
+    SPLIT_PENALTY_MATCHING_BRACKET=textwrap.dedent("""\
+      The penalty for not matching the splitting decision for the matching
+      bracket tokens. For instance, if there is a newline after the opening
+      bracket, we would tend to expect one before the closing bracket, and
+      vice versa."""),
+    SPLIT_PENALTY_AFTER_OPENING_BRACKET=
+    'The penalty for splitting right after the opening bracket.',
+    SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=textwrap.dedent("""\
+      The penalty incurred by adding a line split to the unwrapped line. The
+      more line splits added the higher the penalty."""),
+    #BASED_ON_STYLE='Which predefined style this style is based on',
+)
+
+
 def CreatePEP8Style():
   return dict(
-      # Align closing bracket with visual indentation.
       ALIGN_CLOSING_BRACKET_WITH_VISUAL_INDENT = True,
-
-      # The column limit.
       COLUMN_LIMIT=79,
-
-      # The regex for an i18n comment. The presence of this comment stops
-      # reformatting of that line, because the comments are required to be
-      # next to the string they translate.
       I18N_COMMENT='',
-
-      # The i18n function call names. The presence of this function stops
-      # reformattting on that line, because the string it has cannot be moved
-      # away from the i18n comment.
       I18N_FUNCTION_CALL='',
-
-      # The number of columns to use for indentation.
       INDENT_WIDTH=4,
-
-      # Indent width for line continuations.
       CONTINUATION_INDENT_WIDTH=4,
-
-      # Insert a blank line before a 'def' or 'class' immediately nested within
-      # another 'def' or 'class'.
-      #
-      # For example:
-      #
-      # class Foo:
-      #                    # <------ this blank line
-      #   def method():
-      #     ...
-      #
       BLANK_LINE_BEFORE_NESTED_CLASS_OR_DEF=False,
-
-      # Insert a space between the ending comma and closing bracket of a list,
-      # etc.
       SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True,
-
-      # The number of spaces required before a trailing comment.
       SPACES_BEFORE_COMMENT=2,
-
-      # Set to True to prefer splitting before 'and' or 'or' rather than
-      # after.
       SPLIT_BEFORE_LOGICAL_OPERATOR=False,
-
-      # Split named assignments onto individual lines.
       SPLIT_BEFORE_NAMED_ASSIGNS=True,
-
-      # The penalty for splitting the line after a unary operator.
       SPLIT_PENALTY_AFTER_UNARY_OPERATOR=100,
-
-      # The penalty for characters over the column limit.
       SPLIT_PENALTY_EXCESS_CHARACTER=200,
-
-      # The penalty of splitting the line around the 'and' and 'or' operators.
       SPLIT_PENALTY_LOGICAL_OPERATOR=30,
-
-      # The penalty for not matching the splitting decision for the matching
-      # bracket tokens. For instance, if there is a newline after the opening
-      # bracket, we would tend to expect one before the closing bracket, and
-      # vice versa.
       SPLIT_PENALTY_MATCHING_BRACKET=50,
-
-      # The penalty for splitting right after the opening bracket.
       SPLIT_PENALTY_AFTER_OPENING_BRACKET=30,
-
-      # The penalty incurred by adding a line split to the unwrapped line. The
-      # more line splits added the higher the penalty.
       SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30,
   )  # yapf: disable
 


Test patch:
diff --git a/yapftests/style_test.py b/yapftests/style_test.py
index c0bc958..091c965 100644
--- a/yapftests/style_test.py
+++ b/yapftests/style_test.py
@@ -195,5 +195,13 @@ class StyleFromCommandLine(unittest.TestCase):
     self.assertEqual(cfg['INDENT_WIDTH'], 2)
 
 
+class StyleHelp(unittest.TestCase):
+
+  def testHelpKeys(self):
+    settings = sorted(style.Help())
+    expected = sorted(style._style)
+    self.assertListEqual(settings, expected)
+
+
 if __name__ == '__main__':
   unittest.main()