Merge lp:~adiroiban/pocket-lint/pep-options into lp:pocket-lint

Proposed by Adi Roiban
Status: Merged
Merged at revision: 447
Proposed branch: lp:~adiroiban/pocket-lint/pep-options
Merge into: lp:pocket-lint
Diff against target: 302 lines (+113/-52)
4 files modified
NEWS (+7/-0)
pocketlint/formatcheck.py (+57/-36)
pocketlint/tests/test_javascript.py (+37/-16)
pocketlint/tests/test_python.py (+12/-0)
To merge this branch: bzr merge lp:~adiroiban/pocket-lint/pep-options
Reviewer Review Type Date Requested Status
Curtis Hovey code Approve
Review via email: mp+204911@code.launchpad.net

Description of the change

Description
-----------

PEP8 has now at least one controversion option... but users might want to ignore some pep8 messages.

Changes
-------

I have created a dedicated (more complex) object to hold all pocket-lint options.
It can extend the command line options.

The current code was done to minimize changes and provide backward compatibility.

I have done a refactored the UniversalChecker to use the init from BaseClass.

I have also updated the NEWS file. I find it easier to check latest changes in a single file, rather than look into VC history.

Test
----

I have run the tests on py2.7 ... looking forward for travis-ci integration to land on master and then we can see a neutral results on both 2.7 and 3.3

Please review the changes.

Thanks!

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

Thank you.

I reconciled some changes/tests with the previous branches I just merged. I am going to extend PocketLintOptions
in a moment to support PEP8's options.hang_closing so that I can stop contradicting python's rule that continuations
are indented.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'NEWS'
--- NEWS 2010-07-02 19:16:39 +0000
+++ NEWS 2014-02-05 13:36:41 +0000
@@ -1,3 +1,10 @@
1pocket-lint-0.5.0: No Release Date
2==================================
3
4 * Add support for setting pep8 options using the new PocketLintOptions.
5 * By default disable closure-linter.
6
7
1pocket-lint-0.3: The first release8pocket-lint-0.3: The first release
2==================================9==================================
310
411
=== modified file 'pocketlint/formatcheck.py'
--- pocketlint/formatcheck.py 2013-11-06 15:21:20 +0000
+++ pocketlint/formatcheck.py 2014-02-05 13:36:41 +0000
@@ -254,6 +254,41 @@
254 return Language.get_language(file_path) is not None254 return Language.get_language(file_path) is not None
255255
256256
257class PocketLintOptions(object):
258 """Default options used by pocketlint"""
259
260 def __init__(self, command_options=None):
261 self.max_line_length = 0
262
263 self.jslint = {
264 'enabled': True,
265 }
266
267 self.closure_linter = {
268 # Disabled by default, since jslint is the default linter.
269 'enabled': False,
270 # List of Google Closure Errors to ignore.
271 # Ex 110 is line to long which is already provided by pocket-lint.
272 'ignore': [110],
273 }
274
275 # See pep8.StyleGuide for available options.
276 self.pep8 = {
277 'max_line_length': pep8.MAX_LINE_LENGTH,
278 }
279
280 if command_options:
281 self._updateFromCommandLineOptions(command_options)
282
283 def _updateFromCommandLineOptions(self, options):
284 """
285 Update with options received from command line.
286 """
287 # Update maximum line length.
288 self.max_line_length = options.max_line_length
289 self.pep8['max_line_length'] = options.max_line_length - 1
290
291
257class BaseChecker(object):292class BaseChecker(object):
258 """Common rules for checkers.293 """Common rules for checkers.
259294
@@ -269,7 +304,13 @@
269 if self.REENCODE:304 if self.REENCODE:
270 self.text = u(text)305 self.text = u(text)
271 self.set_reporter(reporter=reporter)306 self.set_reporter(reporter=reporter)
272 self.options = options307
308 if options is None:
309 self.options = PocketLintOptions()
310 elif not isinstance(options, PocketLintOptions):
311 self.options = PocketLintOptions(command_options=options)
312 else:
313 self.options = options
273314
274 def set_reporter(self, reporter=None):315 def set_reporter(self, reporter=None):
275 """Set the reporter for messages."""316 """Set the reporter for messages."""
@@ -295,7 +336,7 @@
295 @property336 @property
296 def check_length_filter(self):337 def check_length_filter(self):
297 '''Default filter used by default for checking line length.'''338 '''Default filter used by default for checking line length.'''
298 if self.options:339 if self.options.max_line_length:
299 return self.options.max_line_length340 return self.options.max_line_length
300 else:341 else:
301 return DEFAULT_MAX_LENGTH342 return DEFAULT_MAX_LENGTH
@@ -306,13 +347,13 @@
306347
307 def __init__(self, file_path, text,348 def __init__(self, file_path, text,
308 language=None, reporter=None, options=None):349 language=None, reporter=None, options=None):
309 self.file_path = file_path350 super(UniversalChecker, self).__init__(
310 self.base_dir = os.path.dirname(file_path)351 file_path=file_path,
311 self.file_name = os.path.basename(file_path)352 text=text,
312 self.text = text353 reporter=reporter,
313 self.set_reporter(reporter=reporter)354 options=options,
355 )
314 self.language = language356 self.language = language
315 self.options = options
316 self.file_lines_view = None357 self.file_lines_view = None
317358
318 def check(self):359 def check(self):
@@ -649,8 +690,7 @@
649690
650 def check_pep8(self):691 def check_pep8(self):
651 """Check style."""692 """Check style."""
652 style_options = pep8.StyleGuide(693 style_options = pep8.StyleGuide(**self.options.pep8)
653 max_line_length=self.check_length_filter)
654 options = style_options.options694 options = style_options.options
655 pep8_report = PEP8Report(options, self.message)695 pep8_report = PEP8Report(options, self.message)
656 try:696 try:
@@ -687,7 +727,7 @@
687 @property727 @property
688 def check_length_filter(self):728 def check_length_filter(self):
689 # The pep8 lib counts from 0.729 # The pep8 lib counts from 0.
690 if self.options:730 if self.options.max_line_length:
691 return self.options.max_line_length - 1731 return self.options.max_line_length - 1
692 else:732 else:
693 return pep8.MAX_LINE_LENGTH733 return pep8.MAX_LINE_LENGTH
@@ -711,20 +751,16 @@
711 FULLJSLINT = os.path.join(HERE, 'contrib/fulljslint.js')751 FULLJSLINT = os.path.join(HERE, 'contrib/fulljslint.js')
712 JSREPORTER = os.path.join(HERE, 'jsreporter.js')752 JSREPORTER = os.path.join(HERE, 'jsreporter.js')
713753
714 # List of Google Closure Errors to ignore.
715 # Ex 110 is line to long which is already provided by pocket-lint.
716 GOOGLE_CLOSURE_IGNORE = [110]
717
718 def check(self):754 def check(self):
719 """Check the syntax of the JavaScript code."""755 """Check the syntax of the JavaScript code."""
720 self.check_jslint()756 self.check_jslint()
721 self.check_google_closure()757 self.check_closure_linter()
722 self.check_text()758 self.check_text()
723 self.check_windows_endlines()759 self.check_windows_endlines()
724760
725 def check_jslint(self):761 def check_jslint(self):
726 """Check file using jslint."""762 """Check file using jslint."""
727 if JS is None or self.text == '':763 if JS is None or self.text == '' or not self.options.jslint['enabled']:
728 return764 return
729 args = [JS, self.JSREPORTER, self.FULLJSLINT, self.file_path]765 args = [JS, self.JSREPORTER, self.FULLJSLINT, self.file_path]
730 jslint = subprocess.Popen(766 jslint = subprocess.Popen(
@@ -738,9 +774,9 @@
738 line_no -= 1774 line_no -= 1
739 self.message(line_no, message, icon='error')775 self.message(line_no, message, icon='error')
740776
741 def check_google_closure(self):777 def check_closure_linter(self):
742 """Check file using Google Closure Linter."""778 """Check file using Google Closure Linter."""
743 if not closure_linter:779 if not self.options.closure_linter['enabled']:
744 return780 return
745781
746 from closure_linter import runner782 from closure_linter import runner
@@ -749,28 +785,13 @@
749 error_handler = erroraccumulator.ErrorAccumulator()785 error_handler = erroraccumulator.ErrorAccumulator()
750 runner.Run(self.file_path, error_handler)786 runner.Run(self.file_path, error_handler)
751 for error in error_handler.GetErrors():787 for error in error_handler.GetErrors():
752 if error.code in self.google_closure_ignore:788 if error.code in self.options.closure_linter['ignore']:
753 continue789 continue
754 # Use a similar format as default Google Closure Linter formatter.790 # Use a similar format as default Google Closure Linter formatter.
755 # Line 12, E:0010: Missing semicolon at end of line791 # Line 12, E:0010: Missing semicolon at end of line
756 message = 'E:%04d: %s' % (error.code, error.message)792 message = 'E:%04d: %s' % (error.code, error.message)
757 self.message(error.token.line_number, message, icon='error')793 self.message(error.token.line_number, message, icon='error')
758794
759 @property
760 def google_closure_ignore(self):
761 """
762 Return the list of ignored errors for Google Closure Linter.
763
764 Return either the default list or the list specified as options.
765 """
766 if not self.options:
767 return self.GOOGLE_CLOSURE_IGNORE
768 ignore_list = getattr(self.options, 'google_closure_ignore', None)
769 if ignore_list is None:
770 return self.GOOGLE_CLOSURE_IGNORE
771 else:
772 return ignore_list
773
774 def check_debugger(self, line_no, line):795 def check_debugger(self, line_no, line):
775 """Check the length of the line."""796 """Check the length of the line."""
776 debugger_call = 'debugger;'797 debugger_call = 'debugger;'
@@ -1063,7 +1084,7 @@
1063 @property1084 @property
1064 def check_length_filter(self):1085 def check_length_filter(self):
1065 # Go land standards don't have a max length; it suggests common sense.1086 # Go land standards don't have a max length; it suggests common sense.
1066 if self.options:1087 if self.options.max_line_length:
1067 return self.options.max_line_length - 11088 return self.options.max_line_length - 1
1068 else:1089 else:
1069 return 1601090 return 160
10701091
=== modified file 'pocketlint/tests/test_javascript.py'
--- pocketlint/tests/test_javascript.py 2013-10-09 12:22:58 +0000
+++ pocketlint/tests/test_javascript.py 2014-02-05 13:36:41 +0000
@@ -14,7 +14,7 @@
14 JavascriptChecker,14 JavascriptChecker,
15 JS15 JS
16)16)
17from pocketlint.tests import Bunch, CheckerTestCase17from pocketlint.tests import CheckerTestCase
18from pocketlint.tests.test_text import TestAnyTextMixin18from pocketlint.tests.test_text import TestAnyTextMixin
1919
20try:20try:
@@ -61,14 +61,21 @@
61 [(1, "Expected ';' and instead saw '(end)'.")],61 [(1, "Expected ';' and instead saw '(end)'.")],
62 self.reporter.messages)62 self.reporter.messages)
6363
64 def test_google_closure(self):64 closure_linter_trigger = (
65 'var test = 1+ 1;\n'
66 )
67
68 def test_closure_linter(self):
65 if closure_linter is None:69 if closure_linter is None:
66 raise unittest.SkipTest('Google Closure Linter not available.')70 raise unittest.SkipTest('Google Closure Linter not available.')
67 google_closure_trigger = (71
68 'var test = 1+ 1;\n'72 self.write_to_file(self.file, self.closure_linter_trigger)
69 )73 checker = JavascriptChecker(
70 self.write_to_file(self.file, google_closure_trigger)74 self.file.name, invalid_js, self.reporter)
71 checker = JavascriptChecker(self.file.name, invalid_js, self.reporter)75 checker.options.closure_linter.update({
76 'enabled': True,
77 'ignore': [],
78 })
7279
73 checker.check()80 checker.check()
7481
@@ -76,17 +83,31 @@
76 [(1, u'E:0002: Missing space before "+"')],83 [(1, u'E:0002: Missing space before "+"')],
77 self.reporter.messages)84 self.reporter.messages)
7885
79 def test_google_closure_ignore(self):86 def test_closure_linter_ignore(self):
80 if closure_linter is None:87 if closure_linter is None:
81 raise unittest.SkipTest('Google Closure Linter not available.')88 raise unittest.SkipTest('Google Closure Linter not available.')
82 google_closure_trigger = (89
83 'var test = 1+ 1;\n'90 self.write_to_file(self.file, self.closure_linter_trigger)
84 )91 checker = JavascriptChecker(
85 self.write_to_file(self.file, google_closure_trigger)92 self.file.name, invalid_js, self.reporter)
86 options = Bunch(93 checker.options.closure_linter.update({
87 google_closure_ignore=[2], max_line_length=80)94 'enabled': True,
88 checker = JavascriptChecker(95 'ignore': [2],
89 self.file.name, invalid_js, self.reporter, options)96 })
97
98 checker.check()
99
100 self.assertEqual([], self.reporter.messages)
101
102 def test_closure_linter_disabled(self):
103 """No errors are reported when closure linter is disabled."""
104 self.write_to_file(self.file, self.closure_linter_trigger)
105 checker = JavascriptChecker(
106 self.file.name, invalid_js, self.reporter)
107 checker.options.closure_linter.update({
108 'enabled': False,
109 'ignore': [],
110 })
90111
91 checker.check()112 checker.check()
92113
93114
=== modified file 'pocketlint/tests/test_python.py'
--- pocketlint/tests/test_python.py 2013-02-16 18:03:51 +0000
+++ pocketlint/tests/test_python.py 2014-02-05 13:36:41 +0000
@@ -232,6 +232,18 @@
232 [(1, 'E501 line too long (70 > 59 characters)')],232 [(1, 'E501 line too long (70 > 59 characters)')],
233 self.reporter.messages)233 self.reporter.messages)
234234
235 def test_pep8_options(self):
236 """It can set PEP8 options."""
237 long_line = '1234 56189' * 7 + '\n'
238 self.write_to_file(self.file, long_line)
239 checker = PythonChecker(self.file.name, long_line, self.reporter)
240 checker.options.pep8['ignore'] = ['E501']
241 checker.options.pep8['max_line_length'] = 60
242
243 checker.check_pep8()
244
245 self.assertEqual([], self.reporter.messages)
246
235247
236class TestText(CheckerTestCase, TestAnyTextMixin):248class TestText(CheckerTestCase, TestAnyTextMixin):
237 """Verify text integration."""249 """Verify text integration."""

Subscribers

People subscribed via source and target branches

to all changes: