diff options
-rw-r--r-- | dev-requirements.txt | 1 | ||||
-rw-r--r-- | docs/developer.rst | 17 | ||||
-rw-r--r-- | docs/intro.rst | 21 | ||||
-rwxr-xr-x | pycodestyle.py | 47 | ||||
-rw-r--r-- | setup.cfg | 2 | ||||
-rw-r--r-- | testsuite/E10.py | 6 | ||||
-rw-r--r-- | testsuite/test_api.py | 4 | ||||
-rw-r--r-- | testsuite/test_parser.py | 8 | ||||
-rw-r--r-- | testsuite/test_shell.py | 48 | ||||
-rw-r--r-- | tox.ini | 1 |
10 files changed, 96 insertions, 59 deletions
diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..053148f --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1 @@ +tox diff --git a/docs/developer.rst b/docs/developer.rst index 3acf2a6..8be3fe3 100644 --- a/docs/developer.rst +++ b/docs/developer.rst @@ -14,8 +14,8 @@ conditions of the :ref:`Expat license <license>`. Fork away! * `Source code <https://github.com/pycqa/pycodestyle>`_ and `issue tracker <https://github.com/pycqa/pycodestyle/issues>`_ on GitHub. * `Continuous tests <http://travis-ci.org/pycqa/pycodestyle>`_ against Python - 2.6 through 3.4 and PyPy, on `Travis-CI platform - <http://about.travis-ci.org/>`_. + 2.6 through 3.5 as well as the nightly Python build and PyPy, on `Travis-CI + platform <https://docs.travis-ci.com//>`_. .. _available on GitHub: https://github.com/pycqa/pycodestyle @@ -27,7 +27,8 @@ Some high-level aims and directions to bear in mind for contributions: * ``pycodestyle`` is intended to be as fast as possible. Using the ``ast`` module defeats that purpose. - The `pep8-naming <https://github.com/flintwork/pep8-naming>`_ plugin exists for this sort of functionality. + The `pep8-naming <https://github.com/flintwork/pep8-naming>`_ plugin exists + for this sort of functionality. * If you want to provide extensibility / plugins, please see `flake8 <https://gitlab.com/pycqa/flake8>`_ - ``pycodestyle`` doesn't want or need a plugin architecture. @@ -103,6 +104,16 @@ Then be sure to pass the tests:: When contributing to pycodestyle, please observe our `Code of Conduct`_. +To run the Travis CI tests, you'll have to create a build the pycodestyle +package using tox:: + + $ pip install -r dev-requirements.txt + $ tox + +All the tests should pass for all available interpreters, with the summary of:: + + congratulations :) + .. _PEP 8: http://www.python.org/dev/peps/pep-0008/ .. _Code of Conduct: http://meta.pycqa.org/en/latest/code-of-conduct.html diff --git a/docs/intro.rst b/docs/intro.rst index 11b0e0c..982b786 100644 --- a/docs/intro.rst +++ b/docs/intro.rst @@ -167,13 +167,14 @@ Quick help is available on the command line:: --benchmark measure processing speed Configuration: - The project options are read from the [pep8] section of the tox.ini - file or the setup.cfg file located in any parent folder of the path(s) - being processed. Allowed options are: exclude, filename, select, + The project options are read from the [pycodestyle] section of the + tox.ini file or the setup.cfg file located in any parent folder of the + path(s) being processed. Allowed options are: exclude, filename, select, ignore, max-line-length, hang-closing, count, format, quiet, show-pep8, show-source, statistics, verbose. - --config=path user config file location (default: ~/.config/pep8) + --config=path user config file location + (default: ~/.config/pycodestyle) Configuration @@ -184,23 +185,23 @@ The behaviour may be configured at two levels, the user and project levels. At the user level, settings are read from the following locations: If on Windows: - ``~\.pep8`` + ``~\.pycodestyle`` Otherwise, if the :envvar:`XDG_CONFIG_HOME` environment variable is defined: - ``XDG_CONFIG_HOME/pep8`` + ``XDG_CONFIG_HOME/pycodestyle`` Else if :envvar:`XDG_CONFIG_HOME` is not defined: - ``~/.config/pep8`` + ``~/.config/pycodestyle`` Example:: - [pep8] + [pycodestyle] ignore = E226,E302,E41 max-line-length = 160 At the project level, a ``setup.cfg`` file or a ``tox.ini`` file is read if -present. If none of these files have a ``[pep8]`` section, no project specific -configuration is loaded. +present. If none of these files have a ``[pycodestyle]`` section, no project +specific configuration is loaded. Error codes diff --git a/pycodestyle.py b/pycodestyle.py index 11cb879..a5141f2 100755 --- a/pycodestyle.py +++ b/pycodestyle.py @@ -48,33 +48,35 @@ W warnings """ from __future__ import with_statement +import inspect +import keyword import os -import sys import re +import sys import time -import inspect -import keyword import tokenize import warnings -from optparse import OptionParser + from fnmatch import fnmatch +from optparse import OptionParser + try: from configparser import RawConfigParser from io import TextIOWrapper except ImportError: from ConfigParser import RawConfigParser -__version__ = '2.0.0' +__version__ = '2.1.0.dev0' DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox' DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503' try: if sys.platform == 'win32': - USER_CONFIG = os.path.expanduser(r'~\.pep8') + USER_CONFIG = os.path.expanduser(r'~\.pycodestyle') else: USER_CONFIG = os.path.join( os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'), - 'pep8' + 'pycodestyle' ) except ImportError: USER_CONFIG = None @@ -958,22 +960,25 @@ def compound_statements(logical_line): line = logical_line last_char = len(line) - 1 found = line.find(':') + prev_found = 0 + counts = dict((char, 0) for char in '{}[]()') 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(')'))): # (annotation) - lambda_kw = LAMBDA_REGEX.search(before) + update_counts(line[prev_found:found], counts) + if ((counts['{'] <= counts['}'] and # {'a': 1} (dict) + counts['['] <= counts[']'] and # [1:2] (slice) + counts['('] <= counts[')'])): # (annotation) + lambda_kw = LAMBDA_REGEX.search(line, 0, found) if lambda_kw: before = line[:lambda_kw.start()].rstrip() if before[-1:] == '=' and isidentifier(before[:-1].strip()): yield 0, ("E731 do not assign a lambda expression, use a " "def") break - if before.startswith('def '): + if line.startswith('def '): yield 0, "E704 multiple statements on one line (def)" else: yield found, "E701 multiple statements on one line (colon)" + prev_found = found found = line.find(':', found + 1) found = line.find(';') while -1 < found: @@ -1387,8 +1392,18 @@ def filename_match(filename, patterns, default=True): return any(fnmatch(filename, pattern) for pattern in patterns) +def update_counts(s, counts): + r"""Adds one to the counts of each appearance of characters in s, + for characters in counts""" + for char in s: + if char in counts: + counts[char] += 1 + + def _is_eol_token(token): return token[0] in NEWLINE or token[4][token[3][1]:].lstrip() == '\\\n' + + if COMMENT_WITH_NL: def _is_eol_token(token, _eol_token=_is_eol_token): return _eol_token(token) or (token[0] == tokenize.COMMENT and @@ -2006,7 +2021,7 @@ class StyleGuide(object): return sorted(checks) -def get_parser(prog='pep8', version=__version__): +def get_parser(prog='pycodestyle', version=__version__): """Create the parser for the program.""" parser = OptionParser(prog=prog, version=version, usage="%prog [options] input ...") @@ -2074,7 +2089,7 @@ def read_config(options, args, arglist, parser): If a config file is specified on the command line with the "--config" option, then only it is used for configuration. - Otherwise, the user configuration (~/.config/pep8) and any local + Otherwise, the user configuration (~/.config/pycodestyle) and any local configurations in the current directory or above will be merged together (in that order) using the read method of ConfigParser. """ @@ -2142,7 +2157,7 @@ def process_options(arglist=None, parse_argv=False, config_file=None, """Process options passed either via arglist or via command line args. Passing in the ``config_file`` parameter allows other tools, such as flake8 - to specify their own options to be processed in pep8. + to specify their own options to be processed in pycodestyle. """ if not parser: parser = get_parser() @@ -1,7 +1,7 @@ [wheel] universal = 1 -[pep8] +[pycodestyle] select = ignore = E226,E24 max_line_length = 79 diff --git a/testsuite/E10.py b/testsuite/E10.py index cd142e3..7b42594 100644 --- a/testsuite/E10.py +++ b/testsuite/E10.py @@ -38,4 +38,8 @@ def test_keys(self): u'Norrbotten', u'V\xe4sterbotten', ]) -#: +#: E101 W191 +if True: + print(""" + tab at start of this line +""") diff --git a/testsuite/test_api.py b/testsuite/test_api.py index 6549a46..4d8b7b2 100644 --- a/testsuite/test_api.py +++ b/testsuite/test_api.py @@ -138,7 +138,7 @@ class APITestCase(unittest.TestCase): self.reset() def test_styleguide_options(self): - # Instanciate a simple checker + # Instantiate a simple checker pep8style = pycodestyle.StyleGuide(paths=[E11]) # Check style's attributes @@ -172,7 +172,7 @@ class APITestCase(unittest.TestCase): def test_styleguide_ignore_code(self): def parse_argv(argstring): _saved_argv = sys.argv - sys.argv = shlex.split('pep8 %s /dev/null' % argstring) + sys.argv = shlex.split('pycodestyle %s /dev/null' % argstring) try: return pycodestyle.StyleGuide(parse_argv=True) finally: diff --git a/testsuite/test_parser.py b/testsuite/test_parser.py index 26a45fc..0e54623 100644 --- a/testsuite/test_parser.py +++ b/testsuite/test_parser.py @@ -19,7 +19,7 @@ class ParserTestCase(unittest.TestCase): def test_vanilla_ignore_parsing(self): contents = b""" -[pep8] +[pycodestyle] ignore = E226,E24 """ options, args = _process_file(contents) @@ -28,7 +28,7 @@ ignore = E226,E24 def test_multiline_ignore_parsing(self): contents = b""" -[pep8] +[pycodestyle] ignore = E226, E24 @@ -40,7 +40,7 @@ ignore = def test_trailing_comma_ignore_parsing(self): contents = b""" -[pep8] +[pycodestyle] ignore = E226, """ @@ -50,7 +50,7 @@ ignore = E226, def test_multiline_trailing_comma_ignore_parsing(self): contents = b""" -[pep8] +[pycodestyle] ignore = E226, E24, diff --git a/testsuite/test_shell.py b/testsuite/test_shell.py index 760c228..a80c875 100644 --- a/testsuite/test_shell.py +++ b/testsuite/test_shell.py @@ -19,7 +19,7 @@ class ShellTestCase(unittest.TestCase): self._saved_stdin_get_value = pycodestyle.stdin_get_value self._config_filenames = [] self.stdin = '' - sys.argv = ['pep8'] + sys.argv = ['pycodestyle'] sys.stdout = PseudoFile() sys.stderr = PseudoFile() @@ -39,7 +39,7 @@ class ShellTestCase(unittest.TestCase): def stdin_get_value(self): return self.stdin - def pep8(self, *args): + def pycodestyle(self, *args): del sys.stdout[:], sys.stderr[:] sys.argv[1:] = args try: @@ -50,28 +50,30 @@ class ShellTestCase(unittest.TestCase): return sys.stdout.getvalue(), sys.stderr.getvalue(), errorcode def test_print_usage(self): - stdout, stderr, errcode = self.pep8('--help') + stdout, stderr, errcode = self.pycodestyle('--help') self.assertFalse(errcode) self.assertFalse(stderr) - self.assertTrue(stdout.startswith("Usage: pep8 [options] input")) + self.assertTrue(stdout.startswith( + "Usage: pycodestyle [options] input" + )) - stdout, stderr, errcode = self.pep8('--version') + stdout, stderr, errcode = self.pycodestyle('--version') self.assertFalse(errcode) self.assertFalse(stderr) self.assertEqual(stdout.count('\n'), 1) - stdout, stderr, errcode = self.pep8('--obfuscated') + stdout, stderr, errcode = self.pycodestyle('--obfuscated') self.assertEqual(errcode, 2) self.assertEqual(stderr.splitlines(), - ["Usage: pep8 [options] input ...", "", - "pep8: error: no such option: --obfuscated"]) + ["Usage: pycodestyle [options] input ...", "", + "pycodestyle: error: no such option: --obfuscated"]) self.assertFalse(stdout) self.assertFalse(self._config_filenames) def test_check_simple(self): E11 = os.path.join(ROOT_DIR, 'testsuite', 'E11.py') - stdout, stderr, errcode = self.pep8(E11) + stdout, stderr, errcode = self.pycodestyle(E11) stdout = stdout.splitlines() self.assertEqual(errcode, 1) self.assertFalse(stderr) @@ -82,20 +84,20 @@ class ShellTestCase(unittest.TestCase): self.assertEqual(x, str(num)) self.assertEqual(y, str(col)) self.assertTrue(msg.startswith(' E11')) - # Config file read from the pep8's setup.cfg + # Config file read from the pycodestyle's setup.cfg config_filenames = [os.path.basename(p) for p in self._config_filenames] self.assertTrue('setup.cfg' in config_filenames) def test_check_stdin(self): pycodestyle.PROJECT_CONFIG = () - stdout, stderr, errcode = self.pep8('-') + stdout, stderr, errcode = self.pycodestyle('-') self.assertFalse(errcode) self.assertFalse(stderr) self.assertFalse(stdout) self.stdin = 'import os, sys\n' - stdout, stderr, errcode = self.pep8('-') + stdout, stderr, errcode = self.pycodestyle('-') stdout = stdout.splitlines() self.assertEqual(errcode, 1) self.assertFalse(stderr) @@ -104,7 +106,7 @@ class ShellTestCase(unittest.TestCase): def test_check_non_existent(self): self.stdin = 'import os, sys\n' - stdout, stderr, errcode = self.pep8('fictitious.py') + stdout, stderr, errcode = self.pycodestyle('fictitious.py') self.assertEqual(errcode, 1) self.assertFalse(stderr) self.assertTrue(stdout.startswith('fictitious.py:1:1: E902 ')) @@ -112,11 +114,11 @@ class ShellTestCase(unittest.TestCase): def test_check_noarg(self): # issue #170: do not read stdin by default pycodestyle.PROJECT_CONFIG = () - stdout, stderr, errcode = self.pep8() + stdout, stderr, errcode = self.pycodestyle() self.assertEqual(errcode, 2) self.assertEqual(stderr.splitlines(), - ["Usage: pep8 [options] input ...", "", - "pep8: error: input not specified"]) + ["Usage: pycodestyle [options] input ...", "", + "pycodestyle: error: input not specified"]) self.assertFalse(self._config_filenames) def test_check_diff(self): @@ -136,7 +138,7 @@ class ShellTestCase(unittest.TestCase): ] self.stdin = '\n'.join(diff_lines) - stdout, stderr, errcode = self.pep8('--diff') + stdout, stderr, errcode = self.pycodestyle('--diff') stdout = stdout.splitlines() self.assertEqual(errcode, 1) self.assertFalse(stderr) @@ -149,7 +151,7 @@ class ShellTestCase(unittest.TestCase): diff_lines[:2] = ["--- a/testsuite/E11.py 2006-06-01 08:49 +0400", "+++ b/testsuite/E11.py 2008-04-06 17:36 +0400"] self.stdin = '\n'.join(diff_lines) - stdout, stderr, errcode = self.pep8('--diff') + stdout, stderr, errcode = self.pycodestyle('--diff') stdout = stdout.splitlines() self.assertEqual(errcode, 1) self.assertFalse(stderr) @@ -167,7 +169,7 @@ class ShellTestCase(unittest.TestCase): "@@ -5,0 +6 @@ if True:", "+ print"] self.stdin = '\n'.join(diff_lines) - stdout, stderr, errcode = self.pep8('--diff') + stdout, stderr, errcode = self.pycodestyle('--diff') (stdout,) = stdout.splitlines() self.assertEqual(errcode, 1) self.assertFalse(stderr) @@ -175,15 +177,17 @@ class ShellTestCase(unittest.TestCase): # missing '--diff' self.stdin = '\n'.join(diff_lines) - stdout, stderr, errcode = self.pep8() + stdout, stderr, errcode = self.pycodestyle() self.assertEqual(errcode, 2) self.assertFalse(stdout) - self.assertTrue(stderr.startswith('Usage: pep8 [options] input ...')) + self.assertTrue(stderr.startswith( + 'Usage: pycodestyle [options] input ...' + )) # no matching file in the diff diff_lines[3] = "+++ b/testsuite/lost/E11.py" self.stdin = '\n'.join(diff_lines) - stdout, stderr, errcode = self.pep8('--diff') + stdout, stderr, errcode = self.pycodestyle('--diff') self.assertFalse(errcode) self.assertFalse(stdout) self.assertFalse(stderr) @@ -5,6 +5,7 @@ [tox] envlist = py26, py27, py32, py33, py34, py35, pypy, pypy3, jython +skip_missing_interpreters=True [testenv] commands = |