Repository: google/yapf
Pull request #268 (2016-06-05 09:39:14)

Added support for tab indentation
Original issue:
https://github.com/google/yapf/issues/244

googlebot: Thanks for your pull request.  It looks like this may be your first contribution to a Google open source project. 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, please reply here (e.g. `I signed it!`) and we'll verify.  Thanks.

---

- If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address.  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/).
- If you signed the CLA as a corporation, please let us know the company's name.

<!-- need_sender_cla -->
coveralls: 
[![Coverage Status](https://coveralls.io/builds/6467552/badge)](https://coveralls.io/builds/6467552)

Coverage increased (+0.002%) to 96.549% when pulling **6ee4f5ac59a27c198d7232715e27460dce29d512 on dracony:tabs** into **d02b59228c1e74ebcaa7bfade3f28a6d31e1e358 on google:master**.

dracony: I signed it
googlebot: CLAs look good, thanks!

<!-- ok -->
gwelymernans: Thank you! Please update the `README.rst` and `CHANGELOG` files and "squash" them into this commit.
coveralls: 
[![Coverage Status](https://coveralls.io/builds/6467712/badge)](https://coveralls.io/builds/6467712)

Coverage increased (+0.002%) to 96.549% when pulling **d81a976fe4ba9c3823671f87f9ace6e8011dfa24 on dracony:tabs** into **d02b59228c1e74ebcaa7bfade3f28a6d31e1e358 on google:master**.

dracony: done =)
gwelymernans: One last thing. It looks like there are some test failures re formatting:

https://travis-ci.org/google/yapf/jobs/135383112
coveralls: 
[![Coverage Status](https://coveralls.io/builds/6471181/badge)](https://coveralls.io/builds/6471181)

Coverage increased (+0.002%) to 96.549% when pulling **e582d63e6cb927bb5445071d124eba396dd5816e on dracony:tabs** into **d02b59228c1e74ebcaa7bfade3f28a6d31e1e358 on google:master**.

dracony: Ah, so it was formatting that was causing the failure. Fixed =)

Patch:
diff --git a/CHANGELOG b/CHANGELOG
index cabc7cc..8d01b5b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,11 +2,14 @@
 # All notable changes to this project will be documented in this file.
 # This project adheres to [Semantic Versioning](http://semver.org/).
 
-## [0.9.1] UNRELEASED
+## [0.10.0] UNRELEASED
+### Added
+- Add a knob, 'USE_TABS', to allow using tabs for indentation.
+  
 ### Changed
 - Performance enhancements.
 
-## Fixed
+### Fixed
 - Don't split an import list if it's not surrounded by parentheses.
 
 ## [0.9.0] 2016-05-29
diff --git a/README.rst b/README.rst
index 0029594..d052af1 100644
--- a/README.rst
+++ b/README.rst
@@ -414,6 +414,9 @@ Knobs
 ``SPLIT_PENALTY_LOGICAL_OPERATOR``
     The penalty of splitting the line around the ``and`` and ``or`` operators.
 
+``USE_TABS``
+    Use the Tab character for indentation.
+
 (Potentially) Frequently Asked Questions
 ========================================
 
diff --git a/yapf/yapflib/format_token.py b/yapf/yapflib/format_token.py
index 35de91e..820cab0 100644
--- a/yapf/yapflib/format_token.py
+++ b/yapf/yapflib/format_token.py
@@ -111,18 +111,19 @@ class FormatToken(object):
       spaces: (int) The number of spaces to place before the token.
       indent_level: (int) The indentation level.
     """
-    spaces_before = (
-        ' ' * indent_level * style.Get('INDENT_WIDTH') + ' ' * spaces)
+    indent_char = "\t" if style.Get('USE_TABS') else ' '
+    indent_before = (
+        indent_char * indent_level * style.Get('INDENT_WIDTH') + ' ' * spaces)
 
     if self.is_comment:
       comment_lines = [s.lstrip() for s in self.value.splitlines()]
-      self.node.value = ('\n' + spaces_before).join(comment_lines)
+      self.node.value = ('\n' + indent_before).join(comment_lines)
 
     if not self.whitespace_prefix:
       self.whitespace_prefix = (
-          '\n' * (self.newlines or newlines_before) + spaces_before)
+          '\n' * (self.newlines or newlines_before) + indent_before)
     else:
-      self.whitespace_prefix += spaces_before
+      self.whitespace_prefix += indent_before
 
   def AdjustNewlinesBefore(self, newlines_before):
     """Change the number of newlines before this token."""
diff --git a/yapf/yapflib/style.py b/yapf/yapflib/style.py
index 6c69c94..35499e8 100644
--- a/yapf/yapflib/style.py
+++ b/yapf/yapflib/style.py
@@ -148,6 +148,8 @@ _STYLE_HELP = dict(
     SPLIT_PENALTY_LOGICAL_OPERATOR=textwrap.dedent("""\
       The penalty of splitting the line around the 'and' and 'or'
       operators."""),
+    USE_TABS=textwrap.dedent("""\
+      Use the Tab character for indentation."""),
     # BASED_ON_STYLE='Which predefined style this style is based on',
 )
 
@@ -181,6 +183,7 @@ def CreatePEP8Style():
       SPLIT_PENALTY_AFTER_OPENING_BRACKET=30,
       SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=30,
       SPLIT_PENALTY_BEFORE_IF_EXPR=0,
+      USE_TABS=False
   )  # yapf: disable
 
 
@@ -271,6 +274,7 @@ _STYLE_OPTION_VALUE_CONVERTER = dict(
     SPLIT_PENALTY_AFTER_OPENING_BRACKET=int,
     SPLIT_PENALTY_FOR_ADDED_LINE_SPLIT=int,
     SPLIT_PENALTY_BEFORE_IF_EXPR=int,
+    USE_TABS=_BoolConverter
 )  # yapf: disable
 
 


Test patch:
diff --git a/yapftests/yapf_test.py b/yapftests/yapf_test.py
index a3872eb..a3fa620 100644
--- a/yapftests/yapf_test.py
+++ b/yapftests/yapf_test.py
@@ -1031,6 +1031,29 @@ second_argument_makes_the_line_too_long):
                              extra_options=['--lines', '1-1', '--style',
                                             'chromium'])
 
+  def testUseTabs(self):
+    unformatted_code = textwrap.dedent(u"""\
+        def foo_function():
+         if True:
+          pass
+        """)
+    expected_formatted_code = textwrap.dedent(u"""\
+        def foo_function():
+        	if True:
+        		pass
+        """)
+    with tempfile.NamedTemporaryFile(dir=self.test_tmpdir, mode='w') as f:
+      f.write(textwrap.dedent('''\
+          [style]
+          based_on_style = chromium
+          USE_TABS = true
+          INDENT_WIDTH=1
+          '''))
+      f.flush()
+      self.assertYapfReformats(unformatted_code,
+                               expected_formatted_code,
+                               extra_options=['--style={0}'.format(f.name)])
+
 
 class BadInputTest(unittest.TestCase):
   """Test yapf's behaviour when passed bad input."""