Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 198 lines (152 sloc) 6.687 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
#!/usr/bin/python
# twisted_pep8.py - Check Python source code formatting, according to the
# Twisted Coding Standard.
#
# This monkey-patches the pep8 module to replace checks that conflict with the
# Twisted Coding Standard, and uses pep8 to check the Python source code.

"""
Check Python source code formatting, according to the Twisted Coding Standard
(http://twistedmatrix.com/trac/browser/trunk/doc/core/development/policy/coding-standard.xhtml?format=raw)

This script is dependent upon the pep8 module which can be found at:
http://github.com/jcrocholl/pep8
"""

try:
    # Try to import SublimeLinter to guarantee that it runs before we do, so
    # there's something to patch.
    import sublimelinter.modules.python
    sublimelinter
except ImportError:
    pass


import re
import fnmatch
import os

from pep8 import DOCSTRING_REGEX, expand_indent

if 'original_blank_lines' not in globals():
    from pep8 import blank_lines as original_blank_lines



class StyleDeterminer(object):

    def readConfig(self):
        conf = os.path.expanduser("~/.twisted-pep8-paths.txt")
        if os.path.exists(conf):
            with open(conf) as f:
                lines = f.read().split("\n")
            regex = '({0})'.format('|'.join(map(fnmatch.translate, lines)))
            self.regex = re.compile(regex)
        else:
            self.regex = re.compile('.*')


    def isTwistedStyle(self, pathname):
        """
Should this function be PEP style-checked according to Twisted or vanilla
PEP8 style? Attempt to guess based on the file name.
"""
        return self.regex.match(pathname)


determiner = StyleDeterminer()

isTwistedStyle = determiner.isTwistedStyle


def inFunctionBody(line_number, lines):
    """
Return (unfortunately just, an educated guess as to) whether the given line
number in the given list of lines is in a function body (as opposed to a
class body, or some other kind of suite) or not.
"""
    current_indent = expand_indent(lines[line_number])
    for x in xrange(line_number, 0, -1):
        line = lines[x-1]
        if expand_indent(line) < current_indent:
            if line.startswith("def "):
                return True
            if line.startswith("class "):
                return False
    return False



checkingFilename = None
lastLine = None

def twisted_blank_lines(logical_line, blank_lines, indent_level, line_number,
                        previous_logical, previous_indent_level,
                        # Not required by previous implementation:
                        filename, lines):
    r"""
Twisted Coding Standard:

Separate top-level function and class definitions with three blank lines.
Method definitions inside a class are separated by two blank lines.

Extra blank lines may be used (sparingly) to separate groups of related
functions. Blank lines may be omitted between a bunch of related
one-liners (e.g. a set of dummy implementations).

Use blank lines in functions, sparingly, to indicate logical sections.::

Okay: def a():\n pass\n\n\n\ndef b():\n pass
Okay: class A():\n pass\n\n\n\nclass B():\n pass
Okay: def a():\n pass\n\n\n# Foo\n# Bar\n\ndef b():\n pass

E301: class Foo:\n b = 0\n def bar():\n pass
E302: def a():\n pass\n\ndef b(n):\n pass
E303: def a():\n pass\n\n\n\ndef b(n):\n pass
E303: def a():\n\n\n\n pass
E304: @decorator\n\ndef a():\n pass
E305: "comment"\n\n\ndef a():\n pass
E306: variable="value"\ndef a(): pass
"""
    global checkingFilename, lastLine
    if ((checkingFilename is None or lastLine is None or
         checkingFilename != filename or lastLine < line_number)):
        # If we're running a new check, re-read the configuration.
        determiner.readConfig()

    if checkingFilename != filename:
        pass
    # Don't expect blank lines before the first line
    if line_number == 1:
        return

    if not isTwistedStyle(filename):
        for value in original_blank_lines(logical_line, blank_lines,
                                          indent_level, line_number,
                                          previous_logical,
                                          previous_indent_level):
            yield value
        return

    def isClassDefDecorator(thing):
        return (thing.startswith('def ') or
                thing.startswith('class ') or
                thing.startswith('@'))

    previous_is_comment = DOCSTRING_REGEX.match(previous_logical)

    # no blank lines after a decorator
    if previous_logical.startswith('@'):
        if blank_lines:
            yield 0, "E304 blank lines found after function decorator <T>"

    # should not have more than 3 blank lines
    elif blank_lines > 3 or (indent_level and blank_lines > 2):
        yield 0, "E303 too many blank lines (%d) <T>" % blank_lines

    elif isClassDefDecorator(logical_line):
        if indent_level:
            # There should only be 1 line or less between docstrings and
            # the next function
            if previous_is_comment:
                if blank_lines > 1:
                    yield 0, (
                        "E305 too many blank lines after docstring (%d) <T>" %
                        blank_lines)

            # between first level functions, there should be 2 blank lines.
            # any further indended functions can have one or zero lines
            else:
                if not (blank_lines == 2 or
                        indent_level > 4 or
                        previous_indent_level <= indent_level or
                        inFunctionBody(line_number, lines)):
                    yield 0, ("E301 expected 2 blank lines, found %d <T>" %
                              blank_lines)

        # top level, there should be 3 blank lines between class/function
        # definitions (but not necessarily after varable declarations)
        elif previous_indent_level and blank_lines != 3:
            yield 0, "E302 expected 3 blank lines, found %d <T>" % blank_lines

    elif blank_lines > 1 and indent_level:
        yield 0, "E303 too many blank lines, expected (%d) <T>" % blank_lines


try:
    import pep8
    for name in ['blank_lines']:
        setattr(pep8, name, globals()['twisted_'+name])
    pep8._checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
    pep8.init_checks_registry()
except:
    print("Unable to import PEP8.")



def _main():
    try:
        import pep8
        pep8._main()
    except:
        print 'Unable to import pep8'



if __name__ == '__main__':
    _main()
Something went wrong with that request. Please try again.