Skip to content

Commit

Permalink
Merge pull request #113 from twisted/py3
Browse files Browse the repository at this point in the history
Author: hawkowl
Reviewer: rodrigc

Port to Python 3
  • Loading branch information
rodrigc authored Mar 5, 2017
2 parents e2481ed + 999e2b5 commit eeeba97
Show file tree
Hide file tree
Showing 32 changed files with 221 additions and 532 deletions.
3 changes: 0 additions & 3 deletions .bzrignore

This file was deleted.

5 changes: 2 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ sudo: false

matrix:
include:
- python: 2.7
- python: 3.5
env: TOXENV=pyflakes
- python: 2.7
- python: 3.5
env: TOXENV=check-manifest
- python: 2.7
env: TOXENV=py27-tests
allow_failures:
- python: 3.5
env: TOXENV=py35-tests

Expand Down
14 changes: 8 additions & 6 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
setup(
name='twistedchecker',
description='A Twisted coding standard compliance checker.',
version='0.6.0',
version='16.0',
author='Twisted Matrix Laboratories',
author_email='twisted-python@twistedmatrix.com',
url='https://github.com/twisted/twistedchecker',
Expand All @@ -30,22 +30,24 @@
"License :: OSI Approved :: MIT License",
"Programming Language :: Python",
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.6",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5",
"Topic :: Software Development :: Quality Assurance"
],
keywords=[
"twisted", "checker", "compliance", "pep8"
],
install_requires=[
"pylint == 0.26.0",
"logilab-common == 0.62.0",
"pep8 == 1.5.7"
"pylint == 1.5.6",
"logilab-common == 1.2.1",
"pycodestyle == 2.0.0",
],
extras_require = {
'dev': [
'twisted>=15.0.0',
'pyflakes==0.8.1',
'pyflakes',
'coverage'
],
},
long_description=longDescription
Expand Down
9 changes: 8 additions & 1 deletion twistedchecker/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,15 @@
A project of GSoC 2012 to checker for codes of twisted.
"""
import os

import os
import sys

# set the absolute path of TwistedChecker
abspath = os.path.dirname(os.path.abspath(__file__))

version = getattr(sys, "version_info", (0,))
if version < (2, 7):
raise ImportError("TwistedChecker requires Python 2.7 or Python 3.5+ ")
elif version >= (3, 0) and version < (3, 5):
raise ImportError("TwistedChecker on Python 3 requires Python 3.5+")
30 changes: 16 additions & 14 deletions twistedchecker/checkers/comment.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from pylint.interfaces import IASTNGChecker
import re
from pylint.interfaces import IAstroidChecker
from pylint.checkers import BaseChecker
from pylint.checkers.format import COMMENT_RGX


COMMENT_RGX = re.compile(b"#.*$", re.M)

class CommentChecker(BaseChecker):
"""
Expand All @@ -13,11 +13,13 @@ class CommentChecker(BaseChecker):
"""
msgs = {
'W9401': ('Comments should begin with one whitespace',
'Used for checking comment format issues.'),
'Used for checking comment format issues.',
'comments-one-whitespace'),
'W9402': ('The first letter of comment should be capitalized',
'Used for checking comment format issues.')
'Used for checking comment format issues. ',
'comments-capitalized')
}
__implements__ = IASTNGChecker
__implements__ = IAstroidChecker
name = 'comment'
options = ()

Expand All @@ -32,9 +34,9 @@ def visit_module(self, node):
return
isFirstLineOfComment = True
isDocString = False
lines = node.file_stream.readlines()
lines = node.stream().readlines()
for linenum, line in enumerate(lines):
if line.strip().startswith('"""'):
if line.strip().startswith(b'"""'):
# This is a simple assumption than docstring are delimited
# with triple double quotes on a single line.
# Should do the job for Twisted code.
Expand All @@ -49,16 +51,16 @@ def visit_module(self, node):
if isFirstLineOfComment:
# Check for W9401
comment = matchedComment.group()
if (comment.startswith("# ") or
not comment.startswith("# ")):
self.add_message('W9401', line=linenum + 1)
if (comment.startswith(b"# ") or
not comment.startswith(b"# ")):
self.add_message('W9401', line=linenum + 1, node=node)
# Check for W9402
strippedComment = comment.lstrip("#").lstrip()
strippedComment = comment.lstrip(b"#").lstrip()
if strippedComment:
firstLetter = strippedComment[0]
firstLetter = strippedComment[0:1]
if (firstLetter.isalpha() and
not firstLetter.isupper()):
self.add_message('W9402', line=linenum + 1)
self.add_message('W9402', line=linenum + 1, node=node)
isFirstLineOfComment = False
else:
isFirstLineOfComment = True
88 changes: 58 additions & 30 deletions twistedchecker/checkers/docstring.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
"""

import re
import astroid

from logilab.astng import node_classes, scoped_nodes, YES
from logilab.astng.exceptions import InferenceError
from astroid import node_classes, scoped_nodes

from pylint.interfaces import IASTNGChecker
from pylint.checkers.base import DocStringChecker as PylintDocStringChecker
from pylint.checkers.base import NO_REQUIRED_DOC_RGX
from pylint.interfaces import IAstroidChecker, INFERENCE, INFERENCE_FAILURE
from pylint.checkers.base import (DocStringChecker as PylintDocStringChecker,
NO_REQUIRED_DOC_RGX)
from pylint.checkers.utils import has_known_bases


def _isInner(node):
Expand All @@ -29,7 +30,7 @@ class or inner function.
"""
while node:
node = node.parent
if isinstance(node, scoped_nodes.Function):
if isinstance(node, scoped_nodes.FunctionDef):
return True
return False

Expand All @@ -41,18 +42,11 @@ def _getDecoratorsName(node):
@param node: current node of pylint
"""
try:
names = node.decoratornames()
except InferenceError:
# Sometimes astng fails by raising this kind of error.
pass
else:
# Whereas sometimes it fails by returning this magic token.
if YES not in names:
return names
# If pylint's attempt to discover the decorator's names has failed, fall
# back to our own logic.
# For setter properties pylint fails so we use a custom code.
decorators = []
if not node.decorators:
return decorators

for decorator in node.decorators.nodes:
decorators.append(decorator.as_string())
return decorators
Expand All @@ -76,34 +70,37 @@ def _isSetter(node_type, node):
return False


_counter = iter(range(100))


class DocstringChecker(PylintDocStringChecker):
"""
A checker for checking docstrings.
"""
msgs = {
'W9201': ('The opening/closing of docstring should be on a line '
'by themselves',
'Check the opening/closing of a docstring.'),
'Check the opening/closing of a docstring.', 'docstring' + str(next(_counter))),
'W9202': ('Missing epytext markup @param for argument "%s"',
'Check the epytext markup @param.'),
'Check the epytext markup @param.', 'docstring' + str(next(_counter))),
'W9203': ('Missing epytext markup @type for argument "%s"',
'Check the epytext markup @type.'),
'Check the epytext markup @type.', 'docstring' + str(next(_counter))),
'W9204': ('Missing epytext markup @return for return value',
'Check the epytext markup @return.'),
'Check the epytext markup @return.', 'docstring' + str(next(_counter))),
'W9205': ('Missing epytext markup @rtype for return value',
'Check the epytext markup @rtype.'),
'Check the epytext markup @rtype.', 'docstring' + str(next(_counter))),
'W9206': ('Docstring should have consistent indentations',
'Check indentations of docstring.'),
'Check indentations of docstring.', 'docstring' + str(next(_counter))),
'W9207': ('Missing a blank line before epytext markups',
'Check the blank line before epytext markups.'),
'Check the blank line before epytext markups.', 'docstring' + str(next(_counter))),
'W9208': ('Missing docstring',
'Used when a module, function, class or method '
'has no docstring.'),
'has no docstring.', 'docstring' + str(next(_counter))),
'W9209': ('Empty docstring',
'Used when a module, function, class or method '
'has an empty docstring.'),
'has an empty docstring.', 'docstring' + str(next(_counter))),
}
__implements__ = IASTNGChecker
__implements__ = IAstroidChecker
name = 'docstring'
options = ()

Expand Down Expand Up @@ -142,8 +139,39 @@ def _getDocstringLineno(self, node_type, node):
linenoDocstring += 1
return linenoDocstring

def visit_module(self, node):
self._check_docstring('module', node)

def visit_classdef(self, node):
if self.config.no_docstring_rgx.match(node.name) is None:
self._check_docstring('class', node)

def visit_functiondef(self, node):
if self.config.no_docstring_rgx.match(node.name) is None:
ftype = node.is_method() and 'method' or 'function'

if isinstance(node.parent.frame(), astroid.ClassDef):
overridden = False
confidence = (INFERENCE if has_known_bases(node.parent.frame())
else INFERENCE_FAILURE)
# check if node is from a method overridden by its ancestor
for ancestor in node.parent.frame().ancestors():
if node.name in ancestor and \
isinstance(ancestor[node.name], astroid.FunctionDef):
overridden = True
break
self._check_docstring(ftype, node,
report_missing=not overridden,
confidence=confidence)
else:
self._check_docstring(ftype, node)


visit_asyncfunctiondef = visit_functiondef


def _check_docstring(self, node_type, node):
def _check_docstring(self, node_type, node, report_missing=True,
confidence=None):
"""
Check whether the opening and the closing of docstring
on a line by themselves.
Expand Down Expand Up @@ -256,7 +284,7 @@ def _checkEpytext(self, node_type, node, linenoDocstring):
else node.argnames())

if _isSetter(node_type, node):
# For setter methods we remove the `value` argument as it
# For setter methods we remove the `value` argument as it
# does not need to be documented.
try:
argnames.remove('value')
Expand Down Expand Up @@ -284,7 +312,7 @@ def _checkReturnValueEpytext(self, node, linenoDocstring):
"""
# Getter properties don't need to document their return value,
# but then need to have a return value.
if '__builtin__.property' in _getDecoratorsName(node):
if 'property' in _getDecoratorsName(node):
if self._hasReturnValue(node):
# Getter properties don't need a docstring.
return
Expand Down
8 changes: 4 additions & 4 deletions twistedchecker/checkers/formattingoperation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from pylint.interfaces import IASTNGChecker
from pylint.checkers.string_format import StringFormatChecker
from pylint.interfaces import IAstroidChecker
from pylint.checkers.strings import StringFormatChecker



Expand All @@ -11,9 +11,9 @@ class FormattingOperationChecker(StringFormatChecker):
msgs = {
'W9501': ('String formatting operations should always use a tuple '
'for non-mapping values',
'Checking string formatting operations.'),
'Checking string formatting operations.', 'formatting-use-tuple'),
}
__implements__ = IASTNGChecker
__implements__ = IAstroidChecker
name = 'formattingoperation'
options = ()

Expand Down
25 changes: 13 additions & 12 deletions twistedchecker/checkers/header.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import re

from pylint.interfaces import IASTNGChecker
from pylint.interfaces import IAstroidChecker
from pylint.checkers import BaseChecker

from twistedchecker.core.util import isTestModule, moduleNeedsTests
Expand All @@ -18,19 +18,20 @@ class HeaderChecker(BaseChecker):
# -*- test-case-name: <test module> -*-
"""
msgs = {
'W9001': ('Missing copyright header',
'Used when a module of Twisted has no copyright header.'),
'W9002': ('Missing a reference to test module in header',
'Used when a module does not contain a reference'
' to test module.'),
'W9001': ('Missing copyright header',
'Used when a module of Twisted has no copyright header.',
'missing-copyright-header'),
'W9002': ('Missing a reference to test module in header',
'Used when a module does not contain a reference'
' to test module.', 'missing-test-header'),
}
__implements__ = IASTNGChecker
__implements__ = IAstroidChecker
name = 'header'
options = ()
commentsCopyright = (r"# Copyright \(c\) Twisted Matrix Laboratories\.",
r"# See LICENSE for details\.")
patternTestReference = (r"# -\*- test-case-name:"
r" (([a-z_][a-z0-9_]*)\.)*[a-z_][a-z0-9_]* -\*-")
commentsCopyright = (br"# Copyright \(c\) Twisted Matrix Laboratories\.",
br"# See LICENSE for details\.")
patternTestReference = (br"# -\*- test-case-name:"
br" (([a-z_][a-z0-9_]*)\.)*[a-z_][a-z0-9_]* -\*-")


def visit_module(self, node):
Expand All @@ -55,7 +56,7 @@ def _checkCopyright(self, text, node):
@param text: codes of the module
@param node: node of the module
"""
if not re.search(r"%s\s*\n\s*%s" % self.commentsCopyright, text):
if not re.search(br"%s\s*\n\s*%s" % self.commentsCopyright, text):
self.add_message('W9001', node=node)


Expand Down
Loading

0 comments on commit eeeba97

Please sign in to comment.