Repository: google/yapf
Pull request #599 (2018-08-17 21:07:30)

Don't add space between '.' and print
To be honest, not sure we should ever be adding a space here, as
we can end up with class members that are keywords.

Also, I suspect that the existing logic is wrong, and should also be
checking rval, even if we don't want to add print to the checks.

googlebot: 
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project (if not, look below for help). Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

:memo: **Please visit <https://cla.developers.google.com/> to sign.**

Once you've signed (or fixed any issues), please reply here (e.g. `I signed it!`) and we'll verify it.

----

#### What to do if you already signed the CLA

##### Individual signers

*   It's possible we don't have your GitHub username or you're using a different email address on your commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).

##### Corporate signers

*   Your company has a Point of Contact who decides which employees are authorized to participate. Ask your POC to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the Google project maintainer to [go/cla#troubleshoot](http://go/cla#troubleshoot) ([Public version](https://opensource.google.com/docs/cla/#troubleshoot)).
*   The email used to register you as an authorized contributor must be the email used for the Git commit. Check [your existing CLA data](https://cla.developers.google.com/clas) and verify that your [email is set on your git commits](https://help.github.com/articles/setting-your-email-in-git/).
*   The email used to register you as an authorized contributor must also be [attached to your GitHub account](https://github.com/settings/emails).
		

<!-- need_sender_cla -->

Patch:
diff --git a/CHANGELOG b/CHANGELOG
index 283a8e3..4693f03 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -11,10 +11,6 @@
   use lib2to3 to fail if called from YAPF.
 - Change the exception message instead of creating a new one that's just a
   clone.
-- Make sure not to reformat when a line is disabled even if the --lines option
-  is specified.
-- The "no spaces around operators" flag wasn't correctly converting strings to
-  sets. Changed the regexp to handle it better.
 
 ## [0.22.0] 2018-05-15
 ### Added
diff --git a/README.rst b/README.rst
index ddd3ffe..19ef0c2 100644
--- a/README.rst
+++ b/README.rst
@@ -451,6 +451,9 @@ Knobs
 ``JOIN_MULTIPLE_LINES``
     Join short lines into one line. E.g., single line ``if`` statements.
 
+``SPACES_AROUND_POWER_OPERATOR``
+    Set to ``True`` to prefer using spaces around ``**``.
+
 ``NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS``
     Do not include spaces around selected binary operators. For example:
 
@@ -458,15 +461,12 @@ Knobs
 
         1 + 2 * 3 - 4 / 5
 
-    will be formatted as follows when configured with ``"*/"``:
+    will be formatted as follows when configured with ``*,/``:
 
     .. code-block:: python
 
         1 + 2*3 - 4/5
 
-``SPACES_AROUND_POWER_OPERATOR``
-    Set to ``True`` to prefer using spaces around ``**``.
-
 ``SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN``
     Set to ``True`` to prefer spaces around the assignment operator for default
     or keyword arguments.
diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py
index f1ca499..79dced4 100644
--- a/yapf/yapflib/format_token.py
+++ b/yapf/yapflib/format_token.py
@@ -223,8 +223,7 @@ class FormatToken(object):
     return self.value in pytree_utils.CLOSING_BRACKETS
 
   def __repr__(self):
-    msg = 'FormatToken(name={0}, value={1}, lineno={2}'.format(
-        self.name, self.value, self.lineno)
+    msg = 'FormatToken(name={0}, value={1}'.format(self.name, self.value)
     msg += ', pseudo)' if self.is_pseudo_paren else ')'
     return msg
 
diff --git a/yapf/yapflib/reformatter.py b/yapf/yapflib/reformatter.py
index ebbff56..6539e68 100644
--- a/yapf/yapflib/reformatter.py
+++ b/yapf/yapflib/reformatter.py
@@ -142,8 +142,6 @@ def _RetainRequiredVerticalSpacingBetweenTokens(cur_tok, prev_tok, lines):
     pass
   elif lines and (cur_lineno in lines or prev_lineno in lines):
     desired_newlines = cur_tok.whitespace_prefix.count('\n')
-    if desired_newlines < required_newlines:
-      desired_newlines = required_newlines
     whitespace_lines = range(prev_lineno + 1, cur_lineno)
     deletable_lines = len(lines.intersection(whitespace_lines))
     required_newlines = max(required_newlines - deletable_lines,
@@ -175,6 +173,7 @@ def _EmitLineUnformatted(state):
     state: (format_decision_state.FormatDecisionState) The format decision
       state.
   """
+  prev_lineno = None
   while state.next_token:
     previous_token = state.next_token.previous_token
     previous_lineno = previous_token.lineno
@@ -185,8 +184,10 @@ def _EmitLineUnformatted(state):
     if previous_token.is_continuation:
       newline = False
     else:
-      newline = state.next_token.lineno > previous_lineno
+      newline = (
+          prev_lineno is not None and state.next_token.lineno > previous_lineno)
 
+    prev_lineno = state.next_token.lineno
     state.AddTokenToState(newline=newline, dry_run=False)
 
 
diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py
index b9e8b69..6144246 100644
--- a/yapf/yapflib/style.py
+++ b/yapf/yapflib/style.py
@@ -282,9 +282,9 @@ def CreatePEP8Style():
       INDENT_DICTIONARY_VALUE=False,
       INDENT_WIDTH=4,
       JOIN_MULTIPLE_LINES=True,
-      NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(),
       SPACE_BETWEEN_ENDING_COMMA_AND_CLOSING_BRACKET=True,
       SPACES_AROUND_POWER_OPERATOR=False,
+      NO_SPACES_AROUND_SELECTED_BINARY_OPERATORS=set(),
       SPACES_AROUND_DEFAULT_OR_NAMED_ASSIGN=False,
       SPACES_BEFORE_COMMENT=2,
       SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED=False,
@@ -390,18 +390,12 @@ def _ContinuationAlignStyleStringConverter(s):
 
 def _StringListConverter(s):
   """Option value converter for a comma-separated list of strings."""
-  if len(s) > 2 and s[0] in '"\'':
-    s = s[1:-1]
   return [part.strip() for part in s.split(',')]
 
 
 def _StringSetConverter(s):
   """Option value converter for a comma-separated set of strings."""
-  if len(s) > 2 and s[0] in '"\'':
-    s = s[1:-1]
-  if ',' in s:
-    return set(part.strip() for part in s.split(','))
-  return set(s.strip())
+  return set(part.strip() for part in s.split(','))
 
 
 def _BoolConverter(s):
@@ -495,7 +489,6 @@ def CreateStyleFromConfig(style_config):
     if not def_style:
       return _style
     return _GLOBAL_STYLE_FACTORY()
-
   if isinstance(style_config, dict):
     config = _CreateConfigParserFromConfigDict(style_config)
   elif isinstance(style_config, py3compat.basestring):
@@ -526,12 +519,8 @@ def _CreateConfigParserFromConfigString(config_string):
         "Invalid style dict syntax: '{}'.".format(config_string))
   config = py3compat.ConfigParser()
   config.add_section('style')
-  for key, value, _ in re.findall(
-      r'([a-zA-Z0-9_]+)\s*[:=]\s*' +
-      r'(?:' +
-      r'((?P<quote>[\'"]).*?(?P=quote)|' +
-      r'[a-zA-Z0-9_]+)' +
-      r')', config_string):  # yapf: disable
+  for key, value in re.findall(r'([a-zA-Z0-9_]+)\s*[:=]\s*([a-zA-Z0-9_]+)',
+                               config_string):
     config.set('style', key, value)
   return config
 
diff --git a/yapf/yapflib/subtype_assigner.py b/yapf/yapflib/subtype_assigner.py
index 8009ddc..8bf3d8d 100644
--- a/yapf/yapflib/subtype_assigner.py
+++ b/yapf/yapflib/subtype_assigner.py
@@ -195,7 +195,7 @@ class _SubtypeAssigner(pytree_visitor.PyTreeVisitor):
     for child in node.children:
       self.Visit(child)
       if (isinstance(child, pytree.Leaf) and
-          child.value in {'*', '/', '%', '//', '@'}):
+          child.value in {'*', '/', '%', '//'}):
         _AppendTokenSubtype(child, format_token.Subtype.BINARY_OPERATOR)
 
   def Visit_factor(self, node):  # pylint: disable=invalid-name
diff --git a/yapf/yapflib/unwrapped_line.py b/yapf/yapflib/unwrapped_line.py
index b063100..d4c7429 100644
--- a/yapf/yapflib/unwrapped_line.py
+++ b/yapf/yapflib/unwrapped_line.py
@@ -317,9 +317,12 @@ def _SpaceRequiredBetween(left, right):
   if lval == '@' and format_token.Subtype.DECORATOR in left.subtypes:
     # Decorators shouldn't be separated from the 'at' sign.
     return False
-  if left.is_keyword and rval == '.' or lval == '.' and right.is_keyword:
+  if left.is_keyword and rval == '.':
     # Add space between keywords and dots.
-    return lval != 'None'
+    return lval != 'None' and lval != 'print'
+  if lval == '.' and right.is_keyword:
+    # Add space between keywords and dots.
+    return rval != 'None' and rval != 'print'
   if lval == '.' or rval == '.':
     # Don't place spaces between dots.
     return False
@@ -460,7 +463,7 @@ def IsSurroundedByBrackets(tok):
 
 _LOGICAL_OPERATORS = frozenset({'and', 'or'})
 _BITWISE_OPERATORS = frozenset({'&', '|', '^'})
-_TERM_OPERATORS = frozenset({'*', '/', '%', '//', '@'})
+_TERM_OPERATORS = frozenset({'*', '/', '%', '//'})
 
 
 def _SplitPenalty(prev_token, cur_token):


Test patch:
diff --git a/yapftests/format_token_test.py b/yapftests/format_token_test.py
index 2f6f973..7dfb82a 100644
--- a/yapftests/format_token_test.py
+++ b/yapftests/format_token_test.py
@@ -67,13 +67,11 @@ class FormatTokenTest(unittest.TestCase):
 
   def testSimple(self):
     tok = format_token.FormatToken(pytree.Leaf(token.STRING, "'hello world'"))
-    self.assertEqual("FormatToken(name=STRING, value='hello world', lineno=0)",
-                     str(tok))
+    self.assertEqual("FormatToken(name=STRING, value='hello world')", str(tok))
     self.assertTrue(tok.is_string)
 
     tok = format_token.FormatToken(pytree.Leaf(token.COMMENT, '# A comment'))
-    self.assertEqual('FormatToken(name=COMMENT, value=# A comment, lineno=0)',
-                     str(tok))
+    self.assertEqual('FormatToken(name=COMMENT, value=# A comment)', str(tok))
     self.assertTrue(tok.is_comment)
 
   def testIsMultilineString(self):
diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py
index 34004dc..0d30735 100644
--- a/yapftests/yapf_test.py
+++ b/yapftests/yapf_test.py
@@ -59,6 +59,11 @@ class FormatCodeTest(unittest.TestCase):
         """)
     self._Check(unformatted_code, expected_formatted_code)
 
+  def testPrintAfterPeriod(self):
+    unformatted_code = textwrap.dedent("""a.print\n""")
+    expected_formatted_code = textwrap.dedent("""a.print\n""")
+    self._Check(unformatted_code, expected_formatted_code)
+
 
 class FormatFileTest(unittest.TestCase):
 
@@ -1345,23 +1350,6 @@ CONTINUATION_ALIGN_STYLE = valign-right
         expected_formatted_code,
         extra_options=['--style', 'chromium', '--lines', '1-1'])
 
-  @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6')
-  def testNoSpacesAroundBinaryOperators(self):
-    unformatted_code = """\
-a = 4-b/c@d**37
-"""
-    expected_formatted_code = """\
-a = 4-b / c@d**37
-"""
-    self.assertYapfReformats(
-        unformatted_code,
-        expected_formatted_code,
-        extra_options=[
-            '--style',
-            '{based_on_style: pep8, ' +
-            'no_spaces_around_selected_binary_operators: "@,**,-"}',
-        ])
-
   @unittest.skipUnless(py3compat.PY36, 'Requires Python 3.6')
   def testCP936Encoding(self):
     unformatted_code = 'print("中文")\n'
@@ -1371,30 +1359,6 @@ a = 4-b / c@d**37
         expected_formatted_code,
         env={'PYTHONIOENCODING': 'cp936'})
 
-  def testDisableWithLineRanges(self):
-    unformatted_code = """\
-# yapf: disable
-a = [
-    1,
-    2,
-
-    3
-]
-"""
-    expected_formatted_code = """\
-# yapf: disable
-a = [
-    1,
-    2,
-
-    3
-]
-"""
-    self.assertYapfReformats(
-        unformatted_code,
-        expected_formatted_code,
-        extra_options=['--style', 'chromium', '--lines', '1-100'])
-
 
 class BadInputTest(unittest.TestCase):
   """Test yapf's behaviour when passed bad input."""