From e794dcc35b0e39c1a86305d383e75d183cd8164a Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 5 Sep 2013 10:30:44 +0300 Subject: Fixing various tests for other platforms (Windows). --- ...c_noerror_defined_and_used_on_same_line_py27.py | 2 + test/test_misc.py | 46 ++++++++++++---------- test/unittest_lint.py | 23 ++++++----- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/test/input/func_noerror_defined_and_used_on_same_line_py27.py b/test/input/func_noerror_defined_and_used_on_same_line_py27.py index 5a75722..11b1a2d 100644 --- a/test/input/func_noerror_defined_and_used_on_same_line_py27.py +++ b/test/input/func_noerror_defined_and_used_on_same_line_py27.py @@ -1,5 +1,7 @@ #pylint: disable=C0111,C0321 """pylint complains about 'index' being used before definition""" +__revision__ = 1 + with open('f') as f, open(f.read()) as g: print g.read() diff --git a/test/test_misc.py b/test/test_misc.py index 68f3e4a..b903161 100644 --- a/test/test_misc.py +++ b/test/test_misc.py @@ -17,44 +17,48 @@ Tests for the misc checker. """ import tempfile +import os +import contextlib from logilab.common.testlib import unittest_main from astroid import test_utils from pylint.checkers import misc from pylint.testutils import CheckerTestCase, Message +@contextlib.contextmanager +def create_file_backed_module(code): + fd, tmp = tempfile.mkstemp() + os.close(fd) + with open(tmp, 'w') as stream: + stream.write(code) + + try: + module = test_utils.build_module(code) + module.file = tmp + yield module + finally: + os.remove(tmp) + class FixmeTest(CheckerTestCase): CHECKER_CLASS = misc.EncodingChecker - def create_file_backed_module(self, code): - tmp = tempfile.NamedTemporaryFile() - tmp.write(code) - tmp.flush() - module = test_utils.build_module(code) - module.file = tmp.name - # Just make sure to keep a reference to the file - # so it isn't deleted. - module._tmpfile = tmp - return module - def test_fixme(self): - module = self.create_file_backed_module( + with create_file_backed_module( """a = 1 - # FIXME - """) - with self.assertAddsMessages( - Message(msg_id='W0511', line=2, args=u'FIXME')): - self.checker.process_module(module) + # FIXME """) as module: + with self.assertAddsMessages( + Message(msg_id='W0511', line=2, args=u'FIXME')): + self.checker.process_module(module) def test_emtpy_fixme_regex(self): self.checker.config.notes = [] - module = self.create_file_backed_module( + with create_file_backed_module( """a = 1 # fixme - """) - with self.assertNoMessages(): - self.checker.process_module(module) + """) as module: + with self.assertNoMessages(): + self.checker.process_module(module) if __name__ == '__main__': diff --git a/test/unittest_lint.py b/test/unittest_lint.py index a65eb01..cec1551 100644 --- a/test/unittest_lint.py +++ b/test/unittest_lint.py @@ -32,6 +32,11 @@ from pylint.testutils import TestReporter from pylint.reporters import text from pylint import checkers +if sys.platform == 'win32': + HOME = 'USERPROFILE' +else: + HOME = 'HOME' + class SortMessagesTC(TestCase): def test(self): @@ -369,9 +374,9 @@ class ConfigTC(TestCase): def test_pylintrc(self): fake_home = tempfile.mkdtemp('fake-home') - home = os.environ['HOME'] + home = os.environ[HOME] try: - os.environ['HOME'] = fake_home + os.environ[HOME] = fake_home self.assertEqual(config.find_pylintrc(), None) os.environ['PYLINTRC'] = join(tempfile.gettempdir(), '.pylintrc') self.assertEqual(config.find_pylintrc(), None) @@ -379,7 +384,7 @@ class ConfigTC(TestCase): self.assertEqual(config.find_pylintrc(), None) finally: os.environ.pop('PYLINTRC', '') - os.environ['HOME'] = home + os.environ[HOME] = home rmtree(fake_home, ignore_errors=True) reload(config) @@ -397,12 +402,12 @@ class ConfigTC(TestCase): 'a/b/c/__init__.py', 'a/b/c/d/__init__.py'], chroot) os.chdir(chroot) fake_home = tempfile.mkdtemp('fake-home') - home = os.environ['HOME'] + home = os.environ[HOME] try: - os.environ['HOME'] = fake_home + os.environ[HOME] = fake_home self.assertEqual(config.find_pylintrc(), None) finally: - os.environ['HOME'] = home + os.environ[HOME] = home os.rmdir(fake_home) results = {'a' : join(chroot, 'a', 'pylintrc'), 'a/b' : join(chroot, 'a', 'b', 'pylintrc'), @@ -427,8 +432,8 @@ class ConfigTC(TestCase): chdir(cdir) fake_home = tempfile.mkdtemp('fake-home') - home = os.environ['HOME'] - os.environ['HOME'] = fake_home + home = os.environ[HOME] + os.environ[HOME] = fake_home try: create_files(['a/pylintrc', 'a/b/pylintrc', 'a/b/c/d/__init__.py'], chroot) os.chdir(chroot) @@ -442,7 +447,7 @@ class ConfigTC(TestCase): os.chdir(join(chroot, basedir)) self.assertEqual(config.find_pylintrc(), expected) finally: - os.environ['HOME'] = home + os.environ[HOME] = home rmtree(fake_home, ignore_errors=True) os.chdir(HERE) rmtree(chroot) -- cgit v1.2.1 From 7bb05cb3ae87f834c5a6864f38c20c4f544dcb8a Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 5 Sep 2013 11:23:39 +0300 Subject: Write to the same fd. --- test/test_misc.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/test_misc.py b/test/test_misc.py index b903161..ff6815d 100644 --- a/test/test_misc.py +++ b/test/test_misc.py @@ -28,15 +28,14 @@ from pylint.testutils import CheckerTestCase, Message @contextlib.contextmanager def create_file_backed_module(code): fd, tmp = tempfile.mkstemp() - os.close(fd) - with open(tmp, 'w') as stream: - stream.write(code) + os.write(fd, code) try: module = test_utils.build_module(code) module.file = tmp yield module finally: + os.close(fd) os.remove(tmp) -- cgit v1.2.1 From f628a570c3b99706012df53125ff6aa5fa2fde36 Mon Sep 17 00:00:00 2001 From: cpopa Date: Fri, 6 Sep 2013 09:43:40 +0300 Subject: Add comment regarding NamedTemporaryFile. --- test/test_misc.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/test_misc.py b/test/test_misc.py index ff6815d..d2c03c0 100644 --- a/test/test_misc.py +++ b/test/test_misc.py @@ -27,6 +27,9 @@ from pylint.testutils import CheckerTestCase, Message @contextlib.contextmanager def create_file_backed_module(code): + # Can't use tempfile.NamedTemporaryFile here + # because on Windows the file must be closed before writing to it, + # see http://bugs.python.org/issue14243 fd, tmp = tempfile.mkstemp() os.write(fd, code) -- cgit v1.2.1 From dd83797bf979ebddf8f85920ae7e7189eb1077fe Mon Sep 17 00:00:00 2001 From: anatoly techtonik Date: Sun, 22 Sep 2013 12:06:37 +0300 Subject: Run as a python module 'python -m pylint'. Convenience feature on Windows, where Python scripts are never added to %PATH% directories by default. python -m pip install pylint python -m pylint --- ChangeLog | 2 ++ __main__.py | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 __main__.py diff --git a/ChangeLog b/ChangeLog index 3662602..c7a65af 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ ChangeLog for Pylint ==================== -- + * Run pylint as a python module 'python -m pylint' (anatoly techtonik) + * Check for non-exception classes inside an except clause * epylint support options to give to pylint after the file to analyze and diff --git a/__main__.py b/__main__.py new file mode 100644 index 0000000..7716361 --- /dev/null +++ b/__main__.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python +import pylint +pylint.run_pylint() -- cgit v1.2.1 From 27a2d1f7cea1dab7837d9aaaca3ef63a0b51b645 Mon Sep 17 00:00:00 2001 From: James Broadhead Date: Tue, 24 Sep 2013 10:06:36 +0100 Subject: Update help docs for msg-format to include {msg_id} --- doc/output.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/doc/output.rst b/doc/output.rst index 6617ac4..e698271 100644 --- a/doc/output.rst +++ b/doc/output.rst @@ -24,8 +24,10 @@ obj object within the module (if any) msg text of the message +msg_id + the message code (eg. I0011) symbol - symbolic name of the message + symbolic name of the message (eg. locally-disabled) C one letter indication of the message category category @@ -33,11 +35,11 @@ category For exemple the default format can be obtained with:: - pylint --msg-template='{sigle}:{line:3d},{column}: {obj}: {msg}' + pylint --msg-template='{msg_id}:{line:3d},{column}: {obj}: {msg}' and a Visual Studio compatible format can be obtained with:: - pylint --msg-template='{path}({line}): [{sigle}{obj}] {msg}' + pylint --msg-template='{path}({line}): [{msg_id}{obj}] {msg}' .. _Python new format syntax: http://docs.python.org/2/library/string.html#formatstrings -- cgit v1.2.1 From f6ed000d05fb3717ef23c9a05bdb233b0b47dbe4 Mon Sep 17 00:00:00 2001 From: Sylvain Th?nault Date: Wed, 25 Sep 2013 08:13:10 +0200 Subject: cleanup unittest_reporting --- test/unittest_reporting.py | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/test/unittest_reporting.py b/test/unittest_reporting.py index d338670..8fda31d 100644 --- a/test/unittest_reporting.py +++ b/test/unittest_reporting.py @@ -1,4 +1,4 @@ -# Copyright (c) 2003-2012 LOGILAB S.A. (Paris, FRANCE). +# Copyright (c) 2003-2013 LOGILAB S.A. (Paris, FRANCE). # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 2 of the License, or (at your option) any later @@ -12,23 +12,13 @@ # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -import sys import os -import tempfile -from shutil import rmtree -from os import getcwd, chdir -from os.path import join, basename, dirname, isdir, abspath +from os.path import join, dirname, abspath from cStringIO import StringIO -from logilab.common.testlib import TestCase, unittest_main, create_files -from logilab.common.compat import reload +from logilab.common.testlib import TestCase, unittest_main -from pylint import config -from pylint.lint import PyLinter, Run, UnknownMessage, preprocess_options, \ - ArgumentPreprocessingError -from pylint.utils import sort_msgs, PyLintASTWalker, MSG_STATE_SCOPE_CONFIG, \ - MSG_STATE_SCOPE_MODULE, tokenize_module -from pylint.testutils import TestReporter +from pylint.lint import PyLinter from pylint import checkers from pylint.reporters.text import TextReporter @@ -46,12 +36,6 @@ class PyLinterTC(TestCase): os.environ.pop('PYLINTRC', None) def test_template_option(self): - # self.linter.set_reporter(TextReporter()) - expected = ( '************* Module 0123\n' - 'C0301:001\n' - 'C0301:002\n' - ) - output = StringIO() self.linter.reporter.set_output(output) self.linter.set_option('msg-template', '{msg_id}:{line:03d}') @@ -59,7 +43,10 @@ class PyLinterTC(TestCase): self.linter.set_current_module('0123') self.linter.add_message('C0301', line=1, args=(1, 2)) self.linter.add_message('line-too-long', line=2, args=(3, 4)) - self.assertMultiLineEqual(output.getvalue(), expected) + self.assertMultiLineEqual(output.getvalue(), + '************* Module 0123\n' + 'C0301:001\n' + 'C0301:002\n') if __name__ == '__main__': -- cgit v1.2.1 From 73ec3c5e3a4870edc8e5c75b518b215e488a1274 Mon Sep 17 00:00:00 2001 From: Sylvain Th?nault Date: Wed, 25 Sep 2013 08:45:38 +0200 Subject: [message handling]?refactor MessageDefinition instantiation --- utils.py | 89 ++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 47 insertions(+), 42 deletions(-) diff --git a/utils.py b/utils.py index 1895a75..1f51bdf 100644 --- a/utils.py +++ b/utils.py @@ -20,8 +20,8 @@ main pylint class import re import sys import tokenize -from warnings import warn import os +from warnings import warn from os.path import dirname, basename, splitext, exists, isdir, join, normpath from logilab.common.interface import implements @@ -43,7 +43,6 @@ class EmptyReport(Exception): """raised when a report is empty and so should not be displayed""" - MSG_TYPES = { 'I' : 'info', 'C' : 'convention', @@ -122,18 +121,49 @@ def tokenize_module(module): return list(tokenize.generate_tokens(readline)) return list(tokenize.tokenize(readline)) +def build_message_def(checker, msgid, msg_tuple): + if implements(checker, (IRawChecker, ITokenChecker)): + default_scope = WarningScope.LINE + else: + default_scope = WarningScope.NODE + options = {} + if len(msg_tuple) > 3: + (msg, symbol, descr, options) = msg_tuple + elif len(msg_tuple) > 2: + (msg, symbol, descr) = msg_tuple[:3] + else: + # messages should have a symbol, but for backward compatibility + # they may not. + (msg, descr) = msg_tuple + warn("[pylint 0.26] description of message %s doesn't include " + "a symbolic name" % msgid, DeprecationWarning) + symbol = None + options.setdefault('scope', default_scope) + return MessageDefinition(checker, msgid, msg, descr, symbol, **options) + class MessageDefinition(object): - def __init__(self, checker, msgid, msg, descr, symbol, scope): + def __init__(self, checker, msgid, msg, descr, symbol, scope, + minversion=None, maxversion=None): + self.checker = checker assert len(msgid) == 5, 'Invalid message id %s' % msgid assert msgid[0] in MSG_TYPES, \ 'Bad message type %s in %r' % (msgid[0], msgid) self.msgid = msgid self.msg = msg self.descr = descr - self.checker = checker self.symbol = symbol self.scope = scope + self.minversion = minversion + self.maxversion = maxversion + + def may_be_emitted(self): + """return True if message may be emitted using the current interpreter""" + if self.minversion is not None and self.minversion > sys.version_info: + return False + if self.maxversion is not None and self.maxversion <= sys.version_info: + return False + return True class MessagesHandlerMixIn(object): """a mix-in class containing all the messages related methods for the main @@ -162,48 +192,23 @@ class MessagesHandlerMixIn(object): message ids should be a string of len 4, where the two first characters are the checker id and the two last the message id in this checker """ - msgs_dict = checker.msgs chkid = None - - for msgid, msg_tuple in msgs_dict.iteritems(): - if implements(checker, (IRawChecker, ITokenChecker)): - scope = WarningScope.LINE - else: - scope = WarningScope.NODE - if len(msg_tuple) > 2: - (msg, msgsymbol, msgdescr) = msg_tuple[:3] - assert msgsymbol not in self._messages_by_symbol, \ - 'Message symbol %r is already defined' % msgsymbol - if len(msg_tuple) > 3: - if 'scope' in msg_tuple[3]: - scope = msg_tuple[3]['scope'] - if 'minversion' in msg_tuple[3]: - minversion = msg_tuple[3]['minversion'] - if minversion > sys.version_info: - self._msgs_state[msgid] = False - continue - if 'maxversion' in msg_tuple[3]: - maxversion = msg_tuple[3]['maxversion'] - if maxversion <= sys.version_info: - self._msgs_state[msgid] = False - continue - else: - # messages should have a symbol, but for backward compatibility - # they may not. - (msg, msgdescr) = msg_tuple - warn("[pylint 0.26] description of message %s doesn't include " - "a symbolic name" % msgid, DeprecationWarning) - msgsymbol = None + for msgid, msg_tuple in checker.msgs.iteritems(): + msg = build_message_def(checker, msgid, msg_tuple) + assert msg.symbol not in self._messages_by_symbol, \ + 'Message symbol %r is already defined' % msg.symbol # avoid duplicate / malformed ids - assert msgid not in self._messages, \ + assert msg.msgid not in self._messages, \ 'Message id %r is already defined' % msgid - assert chkid is None or chkid == msgid[1:3], \ + assert chkid is None or chkid == msg.msgid[1:3], \ 'Inconsistent checker part in message id %r' % msgid - chkid = msgid[1:3] - msg = MessageDefinition(checker, msgid, msg, msgdescr, msgsymbol, scope) - self._messages[msgid] = msg - self._messages_by_symbol[msgsymbol] = msg - self._msgs_by_category.setdefault(msgid[0], []).append(msgid) + chkid = msg.msgid[1:3] + if not msg.may_be_emitted(): + self._msgs_state[msg.msgid] = False + continue + self._messages[msg.msgid] = msg + self._messages_by_symbol[msg.symbol] = msg + self._msgs_by_category.setdefault(msg.msgid[0], []).append(msg.msgid) def get_message_help(self, msgid, checkerref=False): """return the help string for the given message id""" -- cgit v1.2.1 From 7a190584cf6e783ae908cc2683a0e23212406493 Mon Sep 17 00:00:00 2001 From: Sylvain Th?nault Date: Wed, 25 Sep 2013 08:47:05 +0200 Subject: [message handling] kill sort_msgs function, use sorted with key instead --- test/unittest_lint.py | 10 ---------- utils.py | 14 ++------------ 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/test/unittest_lint.py b/test/unittest_lint.py index a65eb01..2f388fd 100644 --- a/test/unittest_lint.py +++ b/test/unittest_lint.py @@ -32,16 +32,6 @@ from pylint.testutils import TestReporter from pylint.reporters import text from pylint import checkers -class SortMessagesTC(TestCase): - - def test(self): - l = ['E0501', 'E0503', 'F0002', 'I0201', 'W0540', - 'R0202', 'F0203', 'R0220', 'W0321', 'I0001'] - self.assertEqual(sort_msgs(l), ['E0501', 'E0503', - 'W0321', 'W0540', - 'R0202', 'R0220', - 'I0001', 'I0201', - 'F0002', 'F0203',]) class GetNoteMessageTC(TestCase): def test(self): diff --git a/utils.py b/utils.py index 1f51bdf..c9104cc 100644 --- a/utils.py +++ b/utils.py @@ -76,17 +76,6 @@ class WarningScope(object): NODE = 'node-based-msg' -def sort_msgs(msgids): - """sort message identifiers according to their category first""" - msgs = {} - for msg in msgids: - msgs.setdefault(msg[0], []).append(msg) - result = [] - for m_id in _MSG_ORDER: - if m_id in msgs: - result.extend( sorted(msgs[m_id]) ) - return result - def get_module_and_frameid(node): """return the module name and the frame id in the module""" frame = node.frame() @@ -472,7 +461,8 @@ class MessagesHandlerMixIn(object): title = ('%smessages' % prefix).capitalize() print title print '~' * len(title) - for msgid in sort_msgs(msgs.iterkeys()): + for msgid in sorted(msgs.itervalues(), + key=lambda k: (_MSG_ORDER.index(k[0]), k)): print self.get_message_help(msgid, False) print if reports: -- cgit v1.2.1 From db0b5edc96b3013ca29d272949c5359099ec2c06 Mon Sep 17 00:00:00 2001 From: Sylvain Th?nault Date: Wed, 25 Sep 2013 08:44:31 +0200 Subject: [message handling] MessageDefinition grew a new format_help method to use instead of linter.get_message_help. Along with previous refactoring, this allows to close bitbucket issue #74. Also, message help now include its min/max python version. --- test/unittest_lint.py | 41 ++++++++++++++++++++++++++++++------ utils.py | 57 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 70 insertions(+), 28 deletions(-) diff --git a/test/unittest_lint.py b/test/unittest_lint.py index 2f388fd..0b847c2 100644 --- a/test/unittest_lint.py +++ b/test/unittest_lint.py @@ -26,8 +26,8 @@ from logilab.common.compat import reload from pylint import config from pylint.lint import PyLinter, Run, UnknownMessage, preprocess_options, \ ArgumentPreprocessingError -from pylint.utils import sort_msgs, PyLintASTWalker, MSG_STATE_SCOPE_CONFIG, \ - MSG_STATE_SCOPE_MODULE, tokenize_module +from pylint.utils import MSG_STATE_SCOPE_CONFIG, MSG_STATE_SCOPE_MODULE, \ + PyLintASTWalker, MessageDefinition, build_message_def, tokenize_module from pylint.testutils import TestReporter from pylint.reporters import text from pylint import checkers @@ -73,11 +73,40 @@ class PyLinterTC(TestCase): checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) + def test_check_message_id(self): + self.assertIsInstance(self.linter.check_message_id('F0001'), + MessageDefinition) + self.assertRaises(UnknownMessage, + self.linter.check_message_id, 'YB12') + def test_message_help(self): - msg = self.linter.get_message_help('F0001', checkerref=True) - expected = ':F0001 (fatal):\n Used when an error occurred preventing the analysis of a module (unable to\n find it for instance). This message belongs to the master checker.' - self.assertMultiLineEqual(msg, expected) - self.assertRaises(UnknownMessage, self.linter.get_message_help, 'YB12') + msg = self.linter.check_message_id('F0001') + self.assertMultiLineEqual( + ''':F0001 (fatal): + Used when an error occurred preventing the analysis of a module (unable to + find it for instance). This message belongs to the master checker.''', + msg.format_help(checkerref=True)) + self.assertMultiLineEqual( + ''':F0001 (fatal): + Used when an error occurred preventing the analysis of a module (unable to + find it for instance).''', + msg.format_help(checkerref=False)) + + def test_message_help_minmax(self): + # build the message manually to be python version independant + msg = build_message_def(self.linter._checkers['typecheck'][0], + 'E1122', checkers.typecheck.MSGS['E1122']) + self.assertMultiLineEqual( + ''':E1122 (duplicate-keyword-arg): *Duplicate keyword argument %r in function call* + Used when a function call passes the same keyword argument multiple times. + This message belongs to the typecheck checker. It can't be emitted when using + Python >= 2.6.''', + msg.format_help(checkerref=True)) + self.assertMultiLineEqual( + ''':E1122 (duplicate-keyword-arg): *Duplicate keyword argument %r in function call* + Used when a function call passes the same keyword argument multiple times. + This message can't be emitted when using Python >= 2.6.''', + msg.format_help(checkerref=False)) def test_enable_message(self): linter = self.linter diff --git a/utils.py b/utils.py index c9104cc..3dc8410 100644 --- a/utils.py +++ b/utils.py @@ -154,6 +154,35 @@ class MessageDefinition(object): return False return True + def format_help(self, checkerref=False): + """return the help string for the given message id""" + desc = self.descr + if checkerref: + desc += ' This message belongs to the %s checker.' % \ + self.checker.name + title = self.msg + if self.symbol: + symbol_part = ' (%s)' % self.symbol + else: + symbol_part = '' + if self.minversion or self.maxversion: + restr = [] + if self.minversion: + restr.append('< %s' % '.'.join([str(n) for n in self.minversion])) + if self.maxversion: + restr.append('>= %s' % '.'.join([str(n) for n in self.maxversion])) + restr = ' or '.join(restr) + if checkerref: + desc += " It can't be emitted when using Python %s." % restr + else: + desc += " This message can't be emitted when using Python %s." % restr + desc = normalize_text(' '.join(desc.split()), indent=' ') + if title != '%s': + title = title.splitlines()[0] + return ':%s%s: *%s*\n%s' % (self.msgid, symbol_part, title, desc) + return ':%s%s:\n%s' % (self.msgid, symbol_part, desc) + + class MessagesHandlerMixIn(object): """a mix-in class containing all the messages related methods for the main lint class @@ -199,23 +228,6 @@ class MessagesHandlerMixIn(object): self._messages_by_symbol[msg.symbol] = msg self._msgs_by_category.setdefault(msg.msgid[0], []).append(msg.msgid) - def get_message_help(self, msgid, checkerref=False): - """return the help string for the given message id""" - msg = self.check_message_id(msgid) - desc = normalize_text(' '.join(msg.descr.split()), indent=' ') - if checkerref: - desc += ' This message belongs to the %s checker.' % \ - msg.checker.name - title = msg.msg - if msg.symbol: - symbol_part = ' (%s)' % msg.symbol - else: - symbol_part = '' - if title != '%s': - title = title.splitlines()[0] - return ':%s%s: *%s*\n%s' % (msg.msgid, symbol_part, title, desc) - return ':%s%s:\n%s' % (msg.msgid, symbol_part, desc) - def disable(self, msgid, scope='package', line=None): """don't output message of the given id""" assert scope in ('package', 'module') @@ -411,7 +423,7 @@ class MessagesHandlerMixIn(object): """display help messages for the given message identifiers""" for msgid in msgids: try: - print self.get_message_help(msgid, True) + print self.check_message_id(msgid).format_help(checkerref=True) print except UnknownMessage, ex: print ex @@ -461,9 +473,10 @@ class MessagesHandlerMixIn(object): title = ('%smessages' % prefix).capitalize() print title print '~' * len(title) - for msgid in sorted(msgs.itervalues(), - key=lambda k: (_MSG_ORDER.index(k[0]), k)): - print self.get_message_help(msgid, False) + for msgid, msg in sorted(msgs.iteritems(), + key=lambda (k,v): (_MSG_ORDER.index(k[0]), k)): + msg = build_message_def(checker, msgid, msg) + print msg.format_help(checkerref=False) print if reports: title = ('%sreports' % prefix).capitalize() @@ -481,7 +494,7 @@ class MessagesHandlerMixIn(object): msgids.append(msgid) msgids.sort() for msgid in msgids: - print self.get_message_help(msgid, False) + print self.check_message_id(msgid).format_help(checkerref=False) print -- cgit v1.2.1 From 958850781e5a9ec899f8627d4e4329c45ce9e938 Mon Sep 17 00:00:00 2001 From: Sylvain Th?nault Date: Wed, 25 Sep 2013 08:53:36 +0200 Subject: [doc] enhance description of new output format a bit --- doc/output.rst | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/doc/output.rst b/doc/output.rst index e698271..3a87547 100644 --- a/doc/output.rst +++ b/doc/output.rst @@ -33,13 +33,25 @@ C category fullname of the message category -For exemple the default format can be obtained with:: +For exemple the former (pre 1.0) default format can be obtained with:: pylint --msg-template='{msg_id}:{line:3d},{column}: {obj}: {msg}' -and a Visual Studio compatible format can be obtained with:: +A few other examples: + +* the new default format:: + + {C}:{line:3d},{column:2d}: {msg} ({symbol}) + +* Visual Studio compatible format (former 'msvs' output format):: + + {path}({line}): [{msg_id}{obj}] {msg} + +* Parseable (Emacs and all, former 'parseable' output format) format:: + + {path}:{line}: [{msg_id}({symbol}), {obj}] {msg} + - pylint --msg-template='{path}({line}): [{msg_id}{obj}] {msg}' .. _Python new format syntax: http://docs.python.org/2/library/string.html#formatstrings -- cgit v1.2.1 From ed12c11d8c88c029d05e86433655e8e626536a3b Mon Sep 17 00:00:00 2001 From: Sylvain Th?nault Date: Wed, 25 Sep 2013 08:54:02 +0200 Subject: [doc] fix makefile to ensure features.rst is systemactically regenerated --- doc/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 8b8b3ec..98076a6 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -37,7 +37,7 @@ clean: -rm -rf $(BUILDDIR)/* -rm -f features.rst -html: features.rst +html: features $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." @@ -131,7 +131,7 @@ doctest: "results in $(BUILDDIR)/doctest/output.txt." -features.rst: +features: rm -f features.rst echo "Pylint features" > features.rst echo "===============" >> features.rst -- cgit v1.2.1 From ceeb3a7eefc0aa42f964a4def144abbe04cba3c2 Mon Sep 17 00:00:00 2001 From: cpopa Date: Wed, 25 Sep 2013 10:28:28 +0300 Subject: Proper merge. --- test/unittest_lint.py | 52 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/test/unittest_lint.py b/test/unittest_lint.py index cec1551..7612ef4 100644 --- a/test/unittest_lint.py +++ b/test/unittest_lint.py @@ -26,8 +26,8 @@ from logilab.common.compat import reload from pylint import config from pylint.lint import PyLinter, Run, UnknownMessage, preprocess_options, \ ArgumentPreprocessingError -from pylint.utils import sort_msgs, PyLintASTWalker, MSG_STATE_SCOPE_CONFIG, \ - MSG_STATE_SCOPE_MODULE, tokenize_module +from pylint.utils import MSG_STATE_SCOPE_CONFIG, MSG_STATE_SCOPE_MODULE, \ + PyLintASTWalker, MessageDefinition, build_message_def, tokenize_module from pylint.testutils import TestReporter from pylint.reporters import text from pylint import checkers @@ -37,17 +37,6 @@ if sys.platform == 'win32': else: HOME = 'HOME' -class SortMessagesTC(TestCase): - - def test(self): - l = ['E0501', 'E0503', 'F0002', 'I0201', 'W0540', - 'R0202', 'F0203', 'R0220', 'W0321', 'I0001'] - self.assertEqual(sort_msgs(l), ['E0501', 'E0503', - 'W0321', 'W0540', - 'R0202', 'R0220', - 'I0001', 'I0201', - 'F0002', 'F0203',]) - class GetNoteMessageTC(TestCase): def test(self): msg = None @@ -88,11 +77,40 @@ class PyLinterTC(TestCase): checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) + def test_check_message_id(self): + self.assertIsInstance(self.linter.check_message_id('F0001'), + MessageDefinition) + self.assertRaises(UnknownMessage, + self.linter.check_message_id, 'YB12') + def test_message_help(self): - msg = self.linter.get_message_help('F0001', checkerref=True) - expected = ':F0001 (fatal):\n Used when an error occurred preventing the analysis of a module (unable to\n find it for instance). This message belongs to the master checker.' - self.assertMultiLineEqual(msg, expected) - self.assertRaises(UnknownMessage, self.linter.get_message_help, 'YB12') + msg = self.linter.check_message_id('F0001') + self.assertMultiLineEqual( + ''':F0001 (fatal): + Used when an error occurred preventing the analysis of a module (unable to + find it for instance). This message belongs to the master checker.''', + msg.format_help(checkerref=True)) + self.assertMultiLineEqual( + ''':F0001 (fatal): + Used when an error occurred preventing the analysis of a module (unable to + find it for instance).''', + msg.format_help(checkerref=False)) + + def test_message_help_minmax(self): + # build the message manually to be python version independant + msg = build_message_def(self.linter._checkers['typecheck'][0], + 'E1122', checkers.typecheck.MSGS['E1122']) + self.assertMultiLineEqual( + ''':E1122 (duplicate-keyword-arg): *Duplicate keyword argument %r in function call* + Used when a function call passes the same keyword argument multiple times. + This message belongs to the typecheck checker. It can't be emitted when using + Python >= 2.6.''', + msg.format_help(checkerref=True)) + self.assertMultiLineEqual( + ''':E1122 (duplicate-keyword-arg): *Duplicate keyword argument %r in function call* + Used when a function call passes the same keyword argument multiple times. + This message can't be emitted when using Python >= 2.6.''', + msg.format_help(checkerref=False)) def test_enable_message(self): linter = self.linter -- cgit v1.2.1 From aaad46a5aa6f2894093935125a373ace6c22f425 Mon Sep 17 00:00:00 2001 From: Sylvain Th?nault Date: Wed, 25 Sep 2013 09:34:12 +0200 Subject: [output] use more symbol instead of msgid: use them in message occurences report and revert order in message help --- utils.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/utils.py b/utils.py index 3dc8410..875ac10 100644 --- a/utils.py +++ b/utils.py @@ -162,9 +162,9 @@ class MessageDefinition(object): self.checker.name title = self.msg if self.symbol: - symbol_part = ' (%s)' % self.symbol + msgid = '%s (%s)' % (self.symbol, self.msgid) else: - symbol_part = '' + msgid = self.msgid if self.minversion or self.maxversion: restr = [] if self.minversion: @@ -179,8 +179,8 @@ class MessageDefinition(object): desc = normalize_text(' '.join(desc.split()), indent=' ') if title != '%s': title = title.splitlines()[0] - return ':%s%s: *%s*\n%s' % (self.msgid, symbol_part, title, desc) - return ':%s%s:\n%s' % (self.msgid, symbol_part, desc) + return ':%s: *%s*\n%s' % (msgid, title, desc) + return ':%s:\n%s' % (msgid, desc) class MessagesHandlerMixIn(object): @@ -402,9 +402,9 @@ class MessagesHandlerMixIn(object): self.stats[msg_cat] += 1 self.stats['by_module'][self.current_name][msg_cat] += 1 try: - self.stats['by_msg'][msgid] += 1 + self.stats['by_msg'][msg_info.symbol] += 1 except KeyError: - self.stats['by_msg'][msgid] = 1 + self.stats['by_msg'][msg_info.symbol] = 1 # expand message ? msg = msg_info.msg if args: -- cgit v1.2.1 From 2773ad46b079cea4aa4b9be461d09964d01c42ab Mon Sep 17 00:00:00 2001 From: Sylvain Th?nault Date: Wed, 25 Sep 2013 09:35:13 +0200 Subject: [doc] update documentation outputs and options. Closes #66 --- doc/run.rst | 17 +++----- doc/tutorial.rst | 123 ++++++++++++++++++++++++------------------------------- 2 files changed, 59 insertions(+), 81 deletions(-) diff --git a/doc/run.rst b/doc/run.rst index 7360c3e..5a9085b 100644 --- a/doc/run.rst +++ b/doc/run.rst @@ -97,18 +97,13 @@ hand tune the configuration. Other useful global options include: ---zope Initialize Zope products before starting ---ignore=file Add (may be a directory) to the black - list. It should be a base name, not a path. - You may set this option multiple times. ---statistics=y_or_n Compute statistics on collected data. ---persistent=y_or_n Pickle collected data for later comparisons. ---comment=y_or_n Add a comment according to your evaluation note. ---parseable=y_or_n Use a parseable output format. ---html=y_or_n Use HTML as output format instead of text. +--ignore=file Add (may be a directory) to the black + list. It should be a base name, not a path. + You may set this option multiple times. +--persistent=y_or_n Pickle collected data for later comparisons. +--output-format= Select output format (text, html, custom). +--msg-template=