Merge lp:~adiroiban/pocket-lint/1237862-pep-257 into lp:pocket-lint

Proposed by Adi Roiban
Status: Merged
Merged at revision: 443
Proposed branch: lp:~adiroiban/pocket-lint/1237862-pep-257
Merge into: lp:pocket-lint
Diff against target: 180 lines (+120/-1)
2 files modified
pocketlint/formatcheck.py (+28/-1)
pocketlint/tests/test_python.py (+92/-0)
To merge this branch: bzr merge lp:~adiroiban/pocket-lint/1237862-pep-257
Reviewer Review Type Date Requested Status
Curtis Hovey code Approve
Adi Roiban (community) Needs Resubmitting
Review via email: mp+194239@code.launchpad.net

Description of the change

Why
---

pep257 looks like a nice effort in docstring format checking.

Changes
-------

Add optional pep257 check if module is present.

I added pep257 as setup.py dependency, but maybe we should remove it.

pep257 has no errror codes yet (wip: https://github.com/GreenSteam/pep257/pull/53) so the filtering is done on message string.

I also made a drive-by fix for pdb check.

Please let me know if changes make sense.

To post a comment you must log in.
Revision history for this message
Curtis Hovey (sinzui) wrote :

Hi Adi.

The tests don't pass when pep257 is not installed. We don't require the lib so I think the tests should skip.

I am not sure about the requires pep257. It is not packaged in Ubuntu. The dh will report an error when it calls setup to install during the package build. While I can copy the pep257 from someone-else's archive, pocket-lint will be removed from Ubuntu unless someone commits to creating python3-pep257 and possibly python2-pep257. I'd think removing pep257 from requires will prevent regressions.

pocket-lint now wrongly reports that a pdb is left in the code. Unless you know how to update the pdb check to know the string is not a function, this block needs to be restored.
- pdb_call = 'pdb.' + 'set_trace'
- if pdb_call in line:

review: Needs Information (code)
Revision history for this message
Adi Roiban (adiroiban) wrote :

Thanks for the review.

pep257 is still young and unstable so I don't think that it needs to be an Ubuntu package.

I will push a new change removing the install requirement and also skipping the tests when pep257 is not there.

I will also revert the pdb_call variable, but I think that it needs a comment. Otherwise is just triggers a WTF moment.

512. By Adi Roiban <email address hidden>

Fix after review.

Revision history for this message
Adi Roiban (adiroiban) wrote :

Please check latest changes.

Thanks!

review: Needs Resubmitting
Revision history for this message
Adi Roiban (adiroiban) wrote :

When you have time, please check latest changes. Thanks!

513. By Adi Roiban <email address hidden>

Merge branch 'master' into 1237862-pep-257

Revision history for this message
Curtis Hovey (sinzui) wrote :

Thank you Adi.

I am very sorry for ignoring your reviews. I saw you updated the reviews while I was travelling. I was so exhausted when I returned home, I forgot about them. I should have set a reminder.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'pocketlint/formatcheck.py'
2--- pocketlint/formatcheck.py 2013-11-06 15:21:20 +0000
3+++ pocketlint/formatcheck.py 2014-02-05 15:58:01 +0000
4@@ -83,6 +83,13 @@
5 except ImportError:
6 closure_linter = None
7
8+try:
9+ import pep257
10+ # Shut up the linter.
11+ pep257
12+except ImportError:
13+ pep257 = None
14+
15
16 IS_PY3 = True if sys.version_info >= (3,) else False
17
18@@ -627,6 +634,7 @@
19 self.check_text()
20 self.check_flakes()
21 self.check_pep8()
22+ self.check_pep257()
23 self.check_windows_endlines()
24
25 def check_flakes(self):
26@@ -665,6 +673,24 @@
27 message = "%s: %s" % (message, location[3].strip())
28 self.message(location[1], message, icon='error')
29
30+ def check_pep257(self):
31+ """PEP 257 docstring style checker."""
32+ if not pep257:
33+ # PEP257 is not available.
34+ return
35+
36+ ignore_list = getattr(self.options, 'pep257_ignore', [])
37+
38+ results = pep257.check_source(self.text, self.file_path)
39+
40+ for error in results:
41+ # PEP257 message contains the short error as first line from
42+ # the long docstring explanation.
43+ error_message = error.explanation.splitlines()[0]
44+ if error_message in ignore_list:
45+ continue
46+ self.message(error.line, error_message, icon='error')
47+
48 def check_text(self):
49 """Call each line_method for each line in text."""
50 for line_no, line in enumerate(self.text.splitlines()):
51@@ -678,7 +704,8 @@
52 self.check_ascii(line_no, line)
53
54 def check_pdb(self, line_no, line):
55- """Check the length of the line."""
56+ """Check for pdb breakpoints."""
57+ # Set trace call is split so that this file will pass the linter.
58 pdb_call = 'pdb.' + 'set_trace'
59 if pdb_call in line:
60 self.message(
61
62=== modified file 'pocketlint/tests/test_python.py'
63--- pocketlint/tests/test_python.py 2013-02-16 18:03:51 +0000
64+++ pocketlint/tests/test_python.py 2014-02-05 15:58:01 +0000
65@@ -7,10 +7,13 @@
66 unicode_literals,
67 )
68
69+import unittest
70 from tempfile import NamedTemporaryFile
71
72 from pocketlint.formatcheck import (
73 get_option_parser,
74+ # Imported via pocketlint to avoid duplication of conditional import.
75+ pep257,
76 PythonChecker,
77 )
78 from pocketlint.tests import CheckerTestCase
79@@ -82,6 +85,12 @@
80 """
81
82
83+class Bunch(object):
84+ """Collector of a bunch of named stuff."""
85+ def __init__(self, **kwds):
86+ self.__dict__.update(kwds)
87+
88+
89 class TestPyflakes(CheckerTestCase):
90 """Verify pyflakes integration."""
91
92@@ -233,6 +242,89 @@
93 self.reporter.messages)
94
95
96+@unittest.skipIf(pep257 is None, 'pep257 is not available.')
97+class TestPEP257(CheckerTestCase):
98+ """Verify PEP257 integration."""
99+
100+ def setUp(self):
101+ super(TestPEP257, self).setUp()
102+ self.file = NamedTemporaryFile(prefix='pocketlint_')
103+
104+ def tearDown(self):
105+ self.file.close()
106+
107+ def makeChecker(self, content, options=None):
108+ """Create a Python checker with file from `content`."""
109+ # Don't know why multi-line text is interpreted as Unicode.
110+ content = content.encode('utf-8')
111+ return PythonChecker(
112+ self.file.name, content, self.reporter, options=options)
113+
114+ def test_code_without_issues(self):
115+ """No errors are reported if everything has a valid docstring."""
116+ checker = self.makeChecker('''
117+"""Module's docstring."""
118+
119+class SomeClass(object):
120+
121+ """Class with short docstring."""
122+
123+ def method(self):
124+ """Method with short docstring."""
125+
126+ def otherMethod(self):
127+ """
128+ Method with multi.
129+
130+ Line docstring.
131+
132+ """
133+ ''')
134+
135+ checker.check_pep257()
136+
137+ self.assertEqual([], self.reporter.messages)
138+
139+ pep257_without_docstrings = '''
140+def some_function():
141+ """Bad multi line without point"""
142+ '''
143+
144+ def test_code_with_issues(self):
145+ """Errors are reported when docstrings are missing or in bad format.
146+
147+ """
148+ checker = self.makeChecker(self.pep257_without_docstrings)
149+
150+ checker.check_pep257()
151+
152+ self.assertEqual([
153+ (1, 'All modules should have docstrings.'),
154+ (3, 'First line should end with a period.'),
155+ ],
156+ self.reporter.messages,
157+ )
158+
159+ def test_code_with_ignore(self):
160+ """A list with error message which should be ignored can be
161+ provided as `pep257_ignore` option.
162+
163+ Hope that pep257 will add error codes soon.
164+ """
165+ options = Bunch(
166+ pep257_ignore=['First line should end with a period.'])
167+ checker = self.makeChecker(
168+ self.pep257_without_docstrings, options=options)
169+
170+ checker.check_pep257()
171+
172+ self.assertEqual([
173+ (1, 'All modules should have docstrings.'),
174+ ],
175+ self.reporter.messages,
176+ )
177+
178+
179 class TestText(CheckerTestCase, TestAnyTextMixin):
180 """Verify text integration."""
181

Subscribers

People subscribed via source and target branches

to all changes: