diff options
-rw-r--r-- | .travis.yml | 1 | ||||
-rw-r--r-- | CHANGES.txt | 22 | ||||
-rw-r--r-- | docs/developer.rst | 2 | ||||
-rw-r--r-- | docs/intro.rst | 13 | ||||
-rwxr-xr-x | pep8.py | 57 | ||||
-rw-r--r-- | testsuite/E11.py | 22 | ||||
-rw-r--r-- | testsuite/E22.py | 4 | ||||
-rw-r--r-- | testsuite/E70.py | 19 | ||||
-rw-r--r-- | testsuite/E73.py | 7 | ||||
-rw-r--r-- | testsuite/W29.py | 4 | ||||
-rw-r--r-- | testsuite/W39.py | 11 | ||||
-rw-r--r-- | testsuite/test_api.py | 4 | ||||
-rw-r--r-- | testsuite/test_shell.py | 2 |
13 files changed, 129 insertions, 39 deletions
diff --git a/.travis.yml b/.travis.yml index 432b162..c50362b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,7 @@ python: - 2.7 - 3.2 - 3.3 + - 3.4 - pypy install: - pip install -e . diff --git a/CHANGES.txt b/CHANGES.txt index e44ef4f..e18add4 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,14 +5,32 @@ Changelog 1.x (unreleased) ---------------- -Bug fixes: +* Report E731 for lambda assignment. (Issue #277) -* Skip the traceback on "Broken pipe" signal. (Issue #275) +* Report E704 for one-liner def instead of E701. (Issue #277) + +* Replace codes E111, E112 and E113 with codes E114, E115 and E116 + for wrong indentation of comments. (Issue #274) * Report E266 instead of E265 when the block comment starts with multiple ``#``. (Issue #270) +1.5.7 (2014-05-29) +------------------ + +Bug fixes: + +* Skip the traceback on "Broken pipe" signal. (Issue #275) + +* Do not exit when an option in ``setup.cfg`` or ``tox.ini`` + is not recognized. + +* Check the last line even if it does not end with a newline. (Issue #286) + +* Always open files in universal newlines mode in Python 2. (Issue #288) + + 1.5.6 (2014-04-14) ------------------ diff --git a/docs/developer.rst b/docs/developer.rst index 205d593..7df1734 100644 --- a/docs/developer.rst +++ b/docs/developer.rst @@ -14,7 +14,7 @@ conditions of the :ref:`Expat license <license>`. Fork away! * `Source code <https://github.com/jcrocholl/pep8>`_ and `issue tracker <https://github.com/jcrocholl/pep8/issues>`_ on GitHub. * `Continuous tests <http://travis-ci.org/jcrocholl/pep8>`_ against Python - 2.6 through 3.3 and PyPy, on `Travis-CI platform + 2.6 through 3.4 and PyPy, on `Travis-CI platform <http://about.travis-ci.org/>`_. .. _available on GitHub: https://github.com/jcrocholl/pep8 diff --git a/docs/intro.rst b/docs/intro.rst index c0ed737..88f0000 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -158,7 +158,8 @@ Configuration The behaviour may be configured at two levels. -The user settings are read from the ``~/.config/pep8`` file. +The user settings are read from the ``~/.config/pep8`` file and +for Windows from the ``~\.pep8`` file. Example:: [pep8] @@ -193,6 +194,12 @@ This is the current list of error and warning codes: +----------+----------------------------------------------------------------------+ | E113 | unexpected indentation | +----------+----------------------------------------------------------------------+ +| E114 | indentation is not a multiple of four (comment) | ++----------+----------------------------------------------------------------------+ +| E115 | expected an indented block (comment) | ++----------+----------------------------------------------------------------------+ +| E116 | unexpected indentation (comment) | ++----------+----------------------------------------------------------------------+ +----------+----------------------------------------------------------------------+ | E121 (^) | continuation line under-indented for hanging indent | +----------+----------------------------------------------------------------------+ @@ -306,6 +313,8 @@ This is the current list of error and warning codes: +----------+----------------------------------------------------------------------+ | E703 | statement ends with a semicolon | +----------+----------------------------------------------------------------------+ +| E704 | multiple statements on one line (def) | ++----------+----------------------------------------------------------------------+ | E711 (^) | comparison to None should be 'if cond is None:' | +----------+----------------------------------------------------------------------+ | E712 (^) | comparison to True should be 'if cond is True:' or 'if cond:' | @@ -316,6 +325,8 @@ This is the current list of error and warning codes: +----------+----------------------------------------------------------------------+ | E721 | do not compare types, use 'isinstance()' | +----------+----------------------------------------------------------------------+ +| E731 | do not assign a lambda expression, use a def | ++----------+----------------------------------------------------------------------+ +----------+----------------------------------------------------------------------+ | **E9** | *Runtime* | +----------+----------------------------------------------------------------------+ @@ -46,7 +46,7 @@ W warnings """ from __future__ import with_statement -__version__ = '1.5.7a0' +__version__ = '1.6.0a0' import os import sys @@ -353,20 +353,25 @@ def indentation(logical_line, previous_logical, indent_char, Okay: a = 1 Okay: if a == 0:\n a = 1 E111: a = 1 + E114: # a = 1 Okay: for item in items:\n pass E112: for item in items:\npass + E115: for item in items:\n# Hi\n pass Okay: a = 1\nb = 2 E113: a = 1\n b = 2 + E116: a = 1\n # b = 2 """ - if indent_char == ' ' and indent_level % 4: - yield 0, "E111 indentation is not a multiple of four" + c = 0 if logical_line else 3 + tmpl = "E11%d %s" if logical_line else "E11%d %s (comment)" + if indent_level % 4: + yield 0, tmpl % (1 + c, "indentation is not a multiple of four") indent_expect = previous_logical.endswith(':') if indent_expect and indent_level <= previous_indent_level: - yield 0, "E112 expected an indented block" - if indent_level > previous_indent_level and not indent_expect: - yield 0, "E113 unexpected indentation" + yield 0, tmpl % (2 + c, "expected an indented block") + elif not indent_expect and indent_level > previous_indent_level: + yield 0, tmpl % (3 + c, "unexpected indentation") def continued_indentation(logical_line, tokens, indent_level, hang_closing, @@ -837,6 +842,9 @@ def compound_statements(logical_line): on the same line, never do this for multi-clause statements. Also avoid folding such long lines! + Always use a def statement instead of an assignment statement that + binds a lambda expression directly to a name. + Okay: if foo == 'blah':\n do_blah_thing() Okay: do_one() Okay: do_two() @@ -850,20 +858,26 @@ def compound_statements(logical_line): E701: try: something() E701: finally: cleanup() E701: if foo == 'blah': one(); two(); three() - E702: do_one(); do_two(); do_three() E703: do_four(); # useless semicolon + E704: def f(x): return 2*x + E731: f = lambda x: 2*x """ line = logical_line last_char = len(line) - 1 found = line.find(':') while -1 < found < last_char: before = line[:found] - if (before.count('{') <= before.count('}') and # {'a': 1} (dict) - before.count('[') <= before.count(']') and # [1:2] (slice) - before.count('(') <= before.count(')') and # (Python 3 annotation) - not LAMBDA_REGEX.search(before)): # lambda x: x - yield found, "E701 multiple statements on one line (colon)" + if ((before.count('{') <= before.count('}') and # {'a': 1} (dict) + before.count('[') <= before.count(']') and # [1:2] (slice) + before.count('(') <= before.count(')'))): # (annotation) + if LAMBDA_REGEX.search(before): + yield 0, "E731 do not assign a lambda expression, use a def" + break + if before.startswith('def '): + yield 0, "E704 multiple statements on one line (def)" + else: + yield found, "E701 multiple statements on one line (colon)" found = line.find(':', found + 1) found = line.find(';') while -1 < found: @@ -1040,7 +1054,7 @@ if '' == ''.encode(): # Python 2: implicit encoding. def readlines(filename): """Read the source code.""" - with open(filename) as f: + with open(filename, 'rU') as f: return f.readlines() isidentifier = re.compile(r'[a-zA-Z_]\w*').match stdin_get_value = sys.stdin.read @@ -1370,6 +1384,8 @@ class Checker(object): tokengen = tokenize.generate_tokens(self.readline) try: for token in tokengen: + if token[2][0] > self.total_lines: + return self.maybe_check_physical(token) yield token except (SyntaxError, tokenize.TokenError): @@ -1452,10 +1468,8 @@ class Checker(object): token[3] = (token[2][0], token[2][1] + len(token[1])) self.tokens = [tuple(token)] self.check_logical() - if len(self.tokens) > 1 and (token_type == tokenize.ENDMARKER and - self.tokens[-2][0] not in SKIP_TOKENS): - self.tokens.pop() - self.check_physical(self.tokens[-1][4]) + if self.tokens: + self.check_physical(self.lines[-1]) self.check_logical() return self.report.get_file_results() @@ -1840,12 +1854,11 @@ def read_config(options, args, arglist, parser): # Second, parse the configuration for opt in config.options(pep8_section): + if opt.replace('_', '-') not in parser.config_options: + print(" unknown option '%s' ignored" % opt) + continue if options.verbose > 1: print(" %s = %s" % (opt, config.get(pep8_section, opt))) - if opt.replace('_', '-') not in parser.config_options: - print("Unknown option: '%s'\n not in [%s]" % - (opt, ' '.join(parser.config_options))) - sys.exit(1) normalized_opt = opt.replace('-', '_') opt_type = option_list[normalized_opt] if opt_type in ('int', 'count'): @@ -1921,7 +1934,7 @@ def _main(): # Handle "Broken pipe" gracefully try: signal.signal(signal.SIGPIPE, lambda signum, frame: sys.exit(1)) - except ValueError: + except AttributeError: pass # not supported on Windows pep8style = StyleGuide(parse_argv=True, config_file=True) diff --git a/testsuite/E11.py b/testsuite/E11.py index 98b9431..4ed1096 100644 --- a/testsuite/E11.py +++ b/testsuite/E11.py @@ -10,7 +10,27 @@ print #: E113 print print -#: E111 E113 +#: E114 E116 mimetype = 'application/x-directory' # 'httpd/unix-directory' create_date = False +#: E116 E116 E116 +def start(self): + if True: + self.master.start() + # try: + # self.master.start() + # except MasterExit: + # self.shutdown() + # finally: + # sys.exit() +#: E115 E115 E115 E115 E115 E115 +def start(self): + if True: +# try: +# self.master.start() +# except MasterExit: +# self.shutdown() +# finally: +# sys.exit() + self.master.start() diff --git a/testsuite/E22.py b/testsuite/E22.py index 43a6f3f..56af307 100644 --- a/testsuite/E22.py +++ b/testsuite/E22.py @@ -135,8 +135,8 @@ baz(**kwargs) negative = -1 spam(-1) -negative -lambda *args, **kw: (args, kw) -lambda a, b=h[:], c=0: (a, b, c) +func1(lambda *args, **kw: (args, kw)) +func2(lambda a, b=h[:], c=0: (a, b, c)) if not -5 < x < +5: print >>sys.stderr, "x is out of range." print >> sys.stdout, "x is an integer." diff --git a/testsuite/E70.py b/testsuite/E70.py index 64feefd..85ca666 100644 --- a/testsuite/E70.py +++ b/testsuite/E70.py @@ -1,13 +1,20 @@ -#: E701 +#: E701:1:5 if a: a = False -#: E701 +#: E701:1:40 if not header or header[:6] != 'bytes=': return -#: E702 +#: E702:1:10 a = False; b = True -#: E702 +#: E702:1:17 import bdist_egg; bdist_egg.write_safety_flag(cmd.egg_info, safe) -#: E703 +#: E703:1:13 import shlex; -#: E702 E703 +#: E702:1:9 E703:1:23 del a[:]; a.append(42); +#: E704:1:1 +def f(x): return 2 +#: E704:1:1 E226:1:19 +def f(x): return 2*x +#: E704:2:5 E226:2:23 +while all is round: + def f(x): return 2*x #: diff --git a/testsuite/E73.py b/testsuite/E73.py new file mode 100644 index 0000000..0673e0f --- /dev/null +++ b/testsuite/E73.py @@ -0,0 +1,7 @@ +#: E731:1:1 +f = lambda x: 2 * x +#: E731:1:1 E226:1:16 +f = lambda x: 2*x +#: E731:2:5 +while False: + this = lambda y, z: 2 * x diff --git a/testsuite/W29.py b/testsuite/W29.py index 688667f..4050c2f 100644 --- a/testsuite/W29.py +++ b/testsuite/W29.py @@ -15,3 +15,7 @@ string with trailing whitespace''' 1+ 1 #: W292:1:27 E261:1:12 noeol import this # no line feed +#: W292:3:22 noeol +class Test(object): + def __repr__(self): + return 'test' diff --git a/testsuite/W39.py b/testsuite/W39.py index 554814c..68f886b 100644 --- a/testsuite/W39.py +++ b/testsuite/W39.py @@ -1,6 +1,15 @@ -#: W391 +#: W391:2:1 # The next line is blank +#: W391:3:1 +# Two additional empty lines + + +#: W391:4:1 W293:3:1 W293:4:1 noeol +# The last lines contain space + + + #: Okay '''there is nothing wrong with a multiline string at EOF diff --git a/testsuite/test_api.py b/testsuite/test_api.py index fba27c7..980fe9e 100644 --- a/testsuite/test_api.py +++ b/testsuite/test_api.py @@ -124,7 +124,7 @@ class APITestCase(unittest.TestCase): report = pep8.StyleGuide().check_files([E11]) stdout = sys.stdout.getvalue().splitlines() self.assertEqual(len(stdout), report.total_errors) - self.assertEqual(report.total_errors, 6) + self.assertEqual(report.total_errors, 17) self.assertFalse(sys.stderr) self.reset() @@ -132,7 +132,7 @@ class APITestCase(unittest.TestCase): report = pep8.StyleGuide(paths=[E11]).check_files() stdout = sys.stdout.getvalue().splitlines() self.assertEqual(len(stdout), report.total_errors) - self.assertEqual(report.total_errors, 6) + self.assertEqual(report.total_errors, 17) self.assertFalse(sys.stderr) self.reset() diff --git a/testsuite/test_shell.py b/testsuite/test_shell.py index e1205cc..e536852 100644 --- a/testsuite/test_shell.py +++ b/testsuite/test_shell.py @@ -75,7 +75,7 @@ class ShellTestCase(unittest.TestCase): stdout = stdout.splitlines() self.assertEqual(errcode, 1) self.assertFalse(stderr) - self.assertEqual(len(stdout), 6) + self.assertEqual(len(stdout), 17) for line, num, col in zip(stdout, (3, 6, 9, 12), (3, 6, 1, 5)): path, x, y, msg = line.split(':') self.assertTrue(path.endswith(E11)) |