def linter(): linter = PyLinter() linter.set_reporter(MinimalTestReporter()) checkers.initialize(linter) linter.register_checker(OverlappingExceptionsChecker(linter)) linter.disable('I') return linter
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter(reporter=TextReporter()) self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) 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}') self.linter.open() 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)
def linter(): linter = PyLinter() linter.set_reporter(MinimalTestReporter()) checkers.initialize(linter) linter.register_checker(MultipleTypesChecker(linter)) linter.disable('I') return linter
def linter(): linter = PyLinter() linter.set_reporter(MinimalTestReporter()) checkers.initialize(linter) linter.register_checker(BadBuiltinChecker(linter)) linter.disable('I') return linter
def linter(): linter = PyLinter() linter.disable('I') linter.config.persistent = 0 # register checkers checkers.initialize(linter) linter.set_reporter(testutils.TestReporter()) return linter
def linter(): linter = PyLinter(reporter=TextReporter()) linter.disable('I') linter.config.persistent = 0 # register checkers checkers.initialize(linter) os.environ.pop('PYLINTRC', None) return linter
def linter(): linter = PyLinter() linter.set_reporter(MinimalTestReporter()) checkers.initialize(linter) register(linter) linter.disable('all') linter.enable('too-complex') return linter
def linter(): linter = PyLinter() linter.disable('I') linter.config.persistent = 0 # register checkers checkers.initialize(linter) linter.set_reporter(testutils.TestReporter()) return linter
def linter(): linter = PyLinter() linter.set_reporter(MinimalTestReporter()) checkers.initialize(linter) register(linter) linter.disable('all') linter.enable('too-complex') return linter
def __init__(self, options: Optional[dict] = None): options = options or {} checker = PyLinter(reporter=CollectingReporter()) checkers.initialize(checker) checker.disable("I") # suppress info messages for k, v in options.items(): checker.global_set_option(k, v) self._inner = checker
def linter(): linter = PyLinter() linter.set_reporter(InMemReporter()) checkers.initialize(linter) register(linter) linter.disable('all') linter.enable(SentryStackChecker.ADD_EXC_INFO) linter.enable(SentryStackChecker.CHANGE_TO_EXC_INFO) return linter
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter(reporter=TextReporter()) self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) os.environ.pop('PYLINTRC', None) def test_template_option(self): output = six.StringIO() self.linter.reporter.set_output(output) self.linter.set_option('msg-template', '{msg_id}:{line:03d}') self.linter.open() 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(), '************* Module 0123\n' 'C0301:001\n' 'C0301:002\n') def test_parseable_output_deprecated(self): with warnings.catch_warnings(record=True) as cm: warnings.simplefilter("always") ParseableTextReporter() self.assertEqual(len(cm), 1) self.assertIsInstance(cm[0].message, DeprecationWarning) def test_parseable_output_regression(self): output = six.StringIO() with warnings.catch_warnings(record=True): linter = PyLinter(reporter=ParseableTextReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.set_option('output-format', 'parseable') linter.open() linter.set_current_module('0123') linter.add_message('line-too-long', line=1, args=(1, 2)) self.assertMultiLineEqual(output.getvalue(), '************* Module 0123\n' '0123:1: [C0301(line-too-long), ] ' 'Line too long (1/2)\n') def test_display_results_is_renamed(self): class CustomReporter(TextReporter): def _display(self, layout): return None reporter = CustomReporter() with self.assertRaises(AttributeError): reporter.display_results
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter(reporter=TextReporter()) self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) os.environ.pop('PYLINTRC', None) def test_template_option(self): output = six.StringIO() self.linter.reporter.set_output(output) self.linter.set_option('msg-template', '{msg_id}:{line:03d}') self.linter.open() 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(), '************* Module 0123\n' 'C0301:001\n' 'C0301:002\n') def test_parseable_output_deprecated(self): with warnings.catch_warnings(record=True) as cm: warnings.simplefilter("always") ParseableTextReporter() self.assertEqual(len(cm), 1) self.assertIsInstance(cm[0].message, DeprecationWarning) def test_parseable_output_regression(self): output = six.StringIO() with warnings.catch_warnings(record=True): linter = PyLinter(reporter=ParseableTextReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.set_option('output-format', 'parseable') linter.open() linter.set_current_module('0123') linter.add_message('line-too-long', line=1, args=(1, 2)) self.assertMultiLineEqual( output.getvalue(), '************* Module 0123\n' '0123:1: [C0301(line-too-long), ] ' 'Line too long (1/2)\n') def test_display_results_is_renamed(self): class CustomReporter(TextReporter): def _display(self, layout): return None reporter = CustomReporter() with self.assertRaises(AttributeError): reporter.display_results
def py3(check): """Verify if a custom check or integration can run on python 3. CHECK can be an integration name or a valid path to a Python module or package folder. """ root = get_root() if check == 'datadog_checks_base': path_to_module = os.path.join(root, check, 'datadog_checks', 'base') elif check in get_valid_checks() and check not in NOT_CHECKS: path_to_module = os.path.join(root, check, 'datadog_checks', check) else: path_to_module = check if not os.path.exists(path_to_module): abort("{} does not exist.".format(path_to_module)) echo_info("Validating python3 compatibility of {}...".format(check)) with closing(StringIO()) as out: linter = PyLinter(reporter=JSONReporter(output=out)) linter.load_default_plugins() linter.python3_porting_mode() # Disable `no-absolute-import`, which checks for a behaviour that's already part of python 2.7 # cf https://www.python.org/dev/peps/pep-0328/ linter.disable("no-absolute-import") with fix_import_path([path_to_module]): linter.check(path_to_module) linter.generate_reports() results = json.loads(out.getvalue() or "{}") if results: echo_failure("Incompatibilities were found for {}:".format(check)) current_path = None for problem in sorted(results, key=itemgetter("path")): # An issue found by pylint is a dict like # { # "message": "Calling a dict.iter*() method", # "obj": "OpenFilesCheck.check", # "column": 27, # "path": "/path/to/file.py", # "line": 235, # "message-id": "W1620", # "type": "warning", # "symbol": "dict-iter-method", # "module": "file" # } path = problem["path"] if current_path is None or path != current_path: echo_info("File {}:".format(path)) echo_failure(" Line {}, column {}: {}".format( problem["line"], problem["column"], problem["message"])) current_path = path abort() else: echo_success("{} is compatible with python3".format(check))
def linter(register, enable, disable): _linter = PyLinter() _linter.set_reporter(MinimalTestReporter()) checkers.initialize(_linter) if register: register(_linter) if disable: for msg in disable: _linter.disable(msg) if enable: for msg in enable: _linter.enable(msg) return _linter
def run_linter(files=None): if files is None: return logger.info('Linting {}'.format(', '.join(files))) rep = ColorizedTextReporter() linter = PyLinter(reporter=rep, pylintrc=find_pylintrc()) linter.load_default_plugins() linter.disable('I') linter.enable('c-extension-no-member') linter.read_config_file() linter.load_config_file() linter.check(files) linter.generate_reports()
def linter(checker, register, enable, disable, reporter): _linter = PyLinter() _linter.set_reporter(reporter()) checkers.initialize(_linter) if register: register(_linter) if checker: _linter.register_checker(checker(_linter)) if disable: for msg in disable: _linter.disable(msg) if enable: for msg in enable: _linter.enable(msg) os.environ.pop("PYLINTRC", None) return _linter
def linter(checker, register, enable, disable, reporter): _linter = PyLinter() _linter.set_reporter(reporter()) checkers.initialize(_linter) if register: register(_linter) if checker: _linter.register_checker(checker(_linter)) if disable: for msg in disable: _linter.disable(msg) if enable: for msg in enable: _linter.enable(msg) os.environ.pop("PYLINTRC", None) return _linter
def validate_py3(path_to_module): """ Run pylint python3 validation on the python module/package provided """ with closing(StringIO()) as out: linter = PyLinter(reporter=JSONReporter(output=out)) linter.load_default_plugins() linter.python3_porting_mode() # Disable `no-absolute-import`, which checks for a behaviour that's already part of python 2.7 # cf https://www.python.org/dev/peps/pep-0328/ linter.disable("no-absolute-import") with fix_import_path([path_to_module]): syspath = sys.path[:] try: # Remove site-packages from imports. It keeps the standard # library, but it prevents pylint from parsing potentially big # third party modules. sys.path = [p for p in syspath if 'site-packages' not in p] linter.check(path_to_module) finally: sys.path = syspath linter.generate_reports() raw_results = json.loads(out.getvalue() or "{}") results = [] for problem in raw_results: # An issue found by pylint is a dict like # { # "message": "Calling a dict.iter*() method", # "obj": "OpenFilesCheck.check", # "column": 27, # "path": "/path/to/file.py", # "line": 235, # "message-id": "W1620", # "type": "warning", # "symbol": "dict-iter-method",co # "module": "file" # } results.append({ "message": "Line {}, column {}: {}".format(problem["line"], problem["column"], problem["message"]), "path": problem["path"], }) return results
def execute(self, finder): packages = list(finder.packages(filters=self.config['filters'])) modules = [ mod for mod in finder.modules(filters=self.config['filters']) if os.path.dirname(mod) not in packages ] targets = modules + finder.topmost_directories(packages) if not targets: return [] pylint = PyLinter() pylint.load_default_plugins() pylint.load_plugin_modules(self.config['options']['plugins']) astroid.MANAGER.extension_package_whitelist.update( self.config['options']['extension-pkg-whitelist'], ) reporter = TidyPyReporter( pylint.msgs_store, filters=self.config['filters'], finder=finder, targets=targets, ) pylint.set_reporter(reporter) for checker in pylint.get_checkers(): if not hasattr(checker, 'options'): continue for option in checker.options: if option[0] in self.config['options']: checker.set_option( option[0], self.config['options'][option[0]], ) for disabled in self.config['disabled'] + self.ALWAYS_DISABLED: try: pylint.disable(disabled) except UnknownMessageError: pass sys_paths = finder.sys_paths(filters=self.config['filters']) with mod_sys_path(sys_paths): pylint.check(targets) return reporter.get_issues()
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter(reporter=TextReporter()) self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) os.environ.pop('PYLINTRC', None) def test_template_option(self): output = cStringIO.StringIO() self.linter.reporter.set_output(output) self.linter.set_option('msg-template', '{msg_id}:{line:03d}') self.linter.open() 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(), '************* Module 0123\n' 'C0301:001\n' 'C0301:002\n')
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter(reporter=TextReporter()) self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) os.environ.pop('PYLINTRC', None) def test_template_option(self): output = six.StringIO() self.linter.reporter.set_output(output) self.linter.set_option('msg-template', '{msg_id}:{line:03d}') self.linter.open() 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(), '************* Module 0123\n' 'C0301:001\n' 'C0301:002\n') def test_parseable_output_regression(self): output = six.StringIO() linter = PyLinter(reporter=ParseableTextReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.set_option('output-format', 'parseable') linter.open() linter.set_current_module('0123') linter.add_message('line-too-long', line=1, args=(1, 2)) self.assertMultiLineEqual(output.getvalue(), '************* Module 0123\n' '0123:1: [C0301(line-too-long), ] ' 'Line too long (1/2)\n')
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) def _compare_messages(self, desc, msg, checkerref=False): # replace \r\n with \n, because # logilab.common.textutils.normalize_text # uses os.linesep, which will # not properly compare with triple # quoted multilines used in these tests self.assertMultiLineEqual( desc, msg.format_help(checkerref=checkerref).replace('\r\n', '\n')) 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.check_message_id('F0001') self._compare_messages(''':fatal (F0001): 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, checkerref=True) self._compare_messages(''':fatal (F0001): Used when an error occurred preventing the analysis of a module (unable to find it for instance).''', msg, 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._compare_messages( ''':duplicate-keyword-arg (E1122): *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, checkerref=True) self._compare_messages( ''':duplicate-keyword-arg (E1122): *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, checkerref=False) def test_enable_message(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertFalse(linter.is_message_enabled('C0121', line=1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertTrue(linter.is_message_enabled('C0121', line=1)) def test_message_state_scope(self): linter = self.linter linter.open() linter.disable('C0121') self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0121')) linter.disable('W0101', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0121')) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0101', 3)) linter.enable('W0102', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0102', 3)) def test_enable_message_block(self): linter = self.linter linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astroid = linter.get_ast(filepath, 'func_block_disable_msg') linter.process_tokens(tokenize_module(astroid)) orig_state = linter._module_msgs_state.copy() linter._module_msgs_state = {} linter._suppression_mapping = {} linter.collect_block_lines(astroid, orig_state) # global (module level) self.assertTrue(linter.is_message_enabled('W0613')) self.assertTrue(linter.is_message_enabled('E1101')) # meth1 self.assertTrue(linter.is_message_enabled('W0613', 13)) # meth2 self.assertFalse(linter.is_message_enabled('W0613', 18)) # meth3 self.assertFalse(linter.is_message_enabled('E1101', 24)) self.assertTrue(linter.is_message_enabled('E1101', 26)) # meth4 self.assertFalse(linter.is_message_enabled('E1101', 32)) self.assertTrue(linter.is_message_enabled('E1101', 36)) # meth5 self.assertFalse(linter.is_message_enabled('E1101', 42)) self.assertFalse(linter.is_message_enabled('E1101', 43)) self.assertTrue(linter.is_message_enabled('E1101', 46)) self.assertFalse(linter.is_message_enabled('E1101', 49)) self.assertFalse(linter.is_message_enabled('E1101', 51)) # meth6 self.assertFalse(linter.is_message_enabled('E1101', 57)) self.assertTrue(linter.is_message_enabled('E1101', 61)) self.assertFalse(linter.is_message_enabled('E1101', 64)) self.assertFalse(linter.is_message_enabled('E1101', 66)) self.assertTrue(linter.is_message_enabled('E0602', 57)) self.assertTrue(linter.is_message_enabled('E0602', 61)) self.assertFalse(linter.is_message_enabled('E0602', 62)) self.assertTrue(linter.is_message_enabled('E0602', 64)) self.assertTrue(linter.is_message_enabled('E0602', 66)) # meth7 self.assertFalse(linter.is_message_enabled('E1101', 70)) self.assertTrue(linter.is_message_enabled('E1101', 72)) self.assertTrue(linter.is_message_enabled('E1101', 75)) self.assertTrue(linter.is_message_enabled('E1101', 77)) self.assertEqual(17, linter._suppression_mapping['W0613', 18]) self.assertEqual(30, linter._suppression_mapping['E1101', 33]) self.assertTrue(('E1101', 46) not in linter._suppression_mapping) self.assertEqual(1, linter._suppression_mapping['C0302', 18]) self.assertEqual(1, linter._suppression_mapping['C0302', 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, linter._suppression_mapping['E1101', 108]) self.assertEqual(109, linter._suppression_mapping['E1101', 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.disable('unreachable', scope='package') linter.disable('dangerous-default-value', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertFalse(linter.is_message_enabled('W0102', 1)) self.assertFalse( linter.is_message_enabled('dangerous-default-value', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.enable('unreachable', scope='package') linter.enable('dangerous-default-value', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102', 1)) self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) def test_list_messages(self): sys.stdout = StringIO() try: self.linter.list_messages() output = sys.stdout.getvalue() finally: sys.stdout = sys.__stdout__ # cursory examination of the output: we're mostly testing it completes self.assertIn(':empty-docstring (C0112): *Empty %s docstring*', output) def test_lint_ext_module_with_file_output(self): self.linter.set_reporter(text.TextReporter()) if sys.version_info < (3, 0): strio = 'StringIO' else: strio = 'io' self.linter.config.files_output = True pylint_strio = 'pylint_%s.txt' % strio try: self.linter.check(strio) self.assertTrue(os.path.exists(pylint_strio)) self.assertTrue(os.path.exists('pylint_global.txt')) finally: try: os.remove(pylint_strio) os.remove('pylint_global.txt') except: pass def test_lint_should_analyze_file(self): self.linter.set_reporter(text.TextReporter()) self.linter.config.files_output = True self.linter.should_analyze_file = lambda *args: False self.linter.check('os') self.assertFalse(os.path.exists('pylint_os.txt')) def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option('output-format', 'text') self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter') def test_report_output_format_custom(self): this_module = sys.modules[__name__] class TestReporter(object): pass this_module.TestReporter = TestReporter class_name = ".".join((this_module.__name__, 'TestReporter')) self.linter.set_option('output-format', class_name) self.assertEqual(self.linter.reporter.__class__.__name__, 'TestReporter') def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0142') self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0142')) self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_enable_checkers(self): self.linter.disable('design') self.assertFalse( 'design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue( 'design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set(('design', 'format', 'imports', 'metrics', 'miscellaneous', 'similarities')) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option('disable', 'RP0801') self.linter.set_option('disable', 'R0801') self.assertFalse( 'similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ('design', 'metrics', 'similarities', 'imports'): # as a Fatal message that should be ignored self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual( ['C: 1: Line too long (1/2)', 'C: 2: Line too long (3/4)'], self.linter.reporter.messages) def test_add_renamed_message(self): self.linter.add_renamed_message('C9999', 'old-bad-name', 'invalid-name') self.assertEqual('invalid-name', self.linter.check_message_id('C9999').symbol) self.assertEqual('invalid-name', self.linter.check_message_id('old-bad-name').symbol) def test_renamed_message_register(self): class Checker(object): msgs = { 'W1234': ('message', 'msg-symbol', 'msg-description', { 'old_names': [('W0001', 'old-symbol')] }) } self.linter.register_messages(Checker()) self.assertEqual('msg-symbol', self.linter.check_message_id('W0001').symbol) self.assertEqual('msg-symbol', self.linter.check_message_id('old-symbol').symbol)
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter(reporter=TextReporter()) self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) os.environ.pop('PYLINTRC', None) def test_template_option(self): output = six.StringIO() self.linter.reporter.set_output(output) self.linter.set_option('msg-template', '{msg_id}:{line:03d}') self.linter.open() 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(), '************* Module 0123\n' 'C0301:001\n' 'C0301:002\n') def test_parseable_output_deprecated(self): with testutils.catch_warnings() as cm: ParseableTextReporter() self.assertEqual(len(cm), 1) self.assertIsInstance(cm[0].message, DeprecationWarning) def test_html_reporter_deprecated(self): with testutils.catch_warnings() as caught: HTMLReporter() self.assertEqual(len(caught), 1) self.assertIsInstance(caught[0].message, DeprecationWarning) self.assertEqual(str(caught[0].message), 'This reporter will be removed in Pylint 2.0.') def test_parseable_output_regression(self): output = six.StringIO() with testutils.catch_warnings(): linter = PyLinter(reporter=ParseableTextReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.set_option('output-format', 'parseable') linter.open() linter.set_current_module('0123') linter.add_message('line-too-long', line=1, args=(1, 2)) self.assertMultiLineEqual( output.getvalue(), '************* Module 0123\n' '0123:1: [C0301(line-too-long), ] ' 'Line too long (1/2)\n') def test_html_reporter_msg_template(self): expected = ''' <html> <body> <div> <div> <h2>Messages</h2> <table> <tr class="header"> <th>category</th> <th>msg_id</th> </tr> <tr class="even"> <td>warning</td> <td>W0332</td> </tr> </table> </div> </div> </body> </html>'''.strip().splitlines() output = six.StringIO() with testutils.catch_warnings(): linter = PyLinter(reporter=HTMLReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.set_option('msg-template', '{category}{msg_id}') linter.open() linter.set_current_module('0123') linter.add_message('lowercase-l-suffix', line=1) linter.reporter.display_messages(Section()) self.assertEqual(output.getvalue().splitlines(), expected) @unittest.expectedFailure def test_html_reporter_type(self): # Integration test for issue #263 # https://bitbucket.org/logilab/pylint/issue/263/html-report-type-problems expected = '''<html> <body> <div> <div> <h2>Messages</h2> <table> <tr class="header"> <th>type</th> <th>module</th> <th>object</th> <th>line</th> <th>col_offset</th> <th>message</th> </tr> <tr class="even"> <td>convention</td> <td>0123</td> <td> </td> <td>1</td> <td>0</td> <td>Exactly one space required before comparison a< 5: print "zero"</td> </tr> </table> </div> </div> </body> </html> ''' output = six.StringIO() with testutils.catch_warnings(): linter = PyLinter(reporter=HTMLReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.open() linter.set_current_module('0123') linter.add_message('bad-whitespace', line=1, args=('Exactly one', 'required', 'before', 'comparison', 'a< 5: print "zero"')) linter.reporter.display_reports(Section()) self.assertMultiLineEqual(output.getvalue(), expected) def test_display_results_is_renamed(self): class CustomReporter(TextReporter): def _display(self, layout): return None reporter = CustomReporter() if __pkginfo__.numversion >= (2, 0): with self.assertRaises(AttributeError): reporter.display_results else: with testutils.catch_warnings() as cm: reporter.display_results(Section()) self.assertEqual(len(cm), 1) self.assertIsInstance(cm[0].message, DeprecationWarning)
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) 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') def test_enable_message(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertFalse(linter.is_message_enabled('C0121', line=1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertTrue(linter.is_message_enabled('C0121', line=1)) def test_message_state_scope(self): linter = self.linter linter.open() linter.disable('C0121') self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0121')) linter.disable('W0101', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0121')) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0101', 3)) linter.enable('W0102', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0102', 3)) def test_enable_message_block(self): linter = self.linter linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astroid = linter.get_astroid(filepath, 'func_block_disable_msg') linter.process_tokens(tokenize_module(astroid)) orig_state = linter._module_msgs_state.copy() linter._module_msgs_state = {} linter._suppression_mapping = {} linter.collect_block_lines(astroid, orig_state) # global (module level) self.assertTrue(linter.is_message_enabled('W0613')) self.assertTrue(linter.is_message_enabled('E1101')) # meth1 self.assertTrue(linter.is_message_enabled('W0613', 13)) # meth2 self.assertFalse(linter.is_message_enabled('W0613', 18)) # meth3 self.assertFalse(linter.is_message_enabled('E1101', 24)) self.assertTrue(linter.is_message_enabled('E1101', 26)) # meth4 self.assertFalse(linter.is_message_enabled('E1101', 32)) self.assertTrue(linter.is_message_enabled('E1101', 36)) # meth5 self.assertFalse(linter.is_message_enabled('E1101', 42)) self.assertFalse(linter.is_message_enabled('E1101', 43)) self.assertTrue(linter.is_message_enabled('E1101', 46)) self.assertFalse(linter.is_message_enabled('E1101', 49)) self.assertFalse(linter.is_message_enabled('E1101', 51)) # meth6 self.assertFalse(linter.is_message_enabled('E1101', 57)) self.assertTrue(linter.is_message_enabled('E1101', 61)) self.assertFalse(linter.is_message_enabled('E1101', 64)) self.assertFalse(linter.is_message_enabled('E1101', 66)) self.assertTrue(linter.is_message_enabled('E0602', 57)) self.assertTrue(linter.is_message_enabled('E0602', 61)) self.assertFalse(linter.is_message_enabled('E0602', 62)) self.assertTrue(linter.is_message_enabled('E0602', 64)) self.assertTrue(linter.is_message_enabled('E0602', 66)) # meth7 self.assertFalse(linter.is_message_enabled('E1101', 70)) self.assertTrue(linter.is_message_enabled('E1101', 72)) self.assertTrue(linter.is_message_enabled('E1101', 75)) self.assertTrue(linter.is_message_enabled('E1101', 77)) self.assertEqual(17, linter._suppression_mapping['W0613', 18]) self.assertEqual(30, linter._suppression_mapping['E1101', 33]) self.assert_(('E1101', 46) not in linter._suppression_mapping) self.assertEqual(1, linter._suppression_mapping['C0302', 18]) self.assertEqual(1, linter._suppression_mapping['C0302', 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, linter._suppression_mapping['E1101', 108]) self.assertEqual(109, linter._suppression_mapping['E1101', 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.disable('unreachable', scope='package') linter.disable('dangerous-default-value', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertFalse(linter.is_message_enabled('W0102', 1)) self.assertFalse(linter.is_message_enabled('dangerous-default-value', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.enable('unreachable', scope='package') linter.enable('dangerous-default-value', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102', 1)) self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) def test_list_messages(self): sys.stdout = StringIO() try: self.linter.list_messages() output = sys.stdout.getvalue() finally: sys.stdout = sys.__stdout__ # cursory examination of the output: we're mostly testing it completes self.assertTrue(':C0112 (empty-docstring): *Empty %s docstring*' in output) def test_lint_ext_module_with_file_output(self): self.linter.set_reporter(text.TextReporter()) if sys.version_info < (3, 0): strio = 'StringIO' else: strio = 'io' self.linter.config.files_output = True pylint_strio = 'pylint_%s.txt' % strio try: self.linter.check(strio) self.assertTrue(os.path.exists(pylint_strio)) self.assertTrue(os.path.exists('pylint_global.txt')) finally: try: os.remove(pylint_strio) os.remove('pylint_global.txt') except: pass def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option('output-format', 'text') self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter') def test_report_output_format_custom(self): this_module = sys.modules[__name__] class TestReporter(object): pass this_module.TestReporter = TestReporter class_name = ".".join((this_module.__name__, 'TestReporter')) self.linter.set_option('output-format', class_name) self.assertEqual(self.linter.reporter.__class__.__name__, 'TestReporter') def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0142') self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0142') ) self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_enable_checkers(self): self.linter.disable('design') self.assertFalse('design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue('design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set(('design', 'format', 'imports', 'metrics', 'miscellaneous', 'similarities')) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option('disable', 'RP0801') self.linter.set_option('disable', 'R0801') self.assertFalse('similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ('design', 'metrics', 'similarities', 'imports'): # as a Fatal message that should be ignored self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual( ['C: 1: Line too long (1/2)', 'C: 2: Line too long (3/4)'], self.linter.reporter.messages)
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter(reporter=TextReporter()) self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) os.environ.pop('PYLINTRC', None) def test_template_option(self): output = six.StringIO() self.linter.reporter.set_output(output) self.linter.set_option('msg-template', '{msg_id}:{line:03d}') self.linter.open() 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(), '************* Module 0123\n' 'C0301:001\n' 'C0301:002\n') def test_parseable_output_regression(self): output = six.StringIO() linter = PyLinter(reporter=ParseableTextReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.set_option('output-format', 'parseable') linter.open() linter.set_current_module('0123') linter.add_message('line-too-long', line=1, args=(1, 2)) self.assertMultiLineEqual(output.getvalue(), '************* Module 0123\n' '0123:1: [C0301(line-too-long), ] ' 'Line too long (1/2)\n') @unittest.expectedFailure def test_html_reporter_type(self): # Integration test for issue #263 # https://bitbucket.org/logilab/pylint/issue/263/html-report-type-problems expected = '''<html> <body> <div> <div> <h2>Messages</h2> <table> <tr class="header"> <th>type</th> <th>module</th> <th>object</th> <th>line</th> <th>col_offset</th> <th>message</th> </tr> <tr class="even"> <td>convention</td> <td>0123</td> <td> </td> <td>1</td> <td>0</td> <td>Exactly one space required before comparison a< 5: print "zero"</td> </tr> </table> </div> </div> </body> </html> ''' output = six.StringIO() linter = PyLinter(reporter=HTMLReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.open() linter.set_current_module('0123') linter.add_message('bad-whitespace', line=1, args=('Exactly one', 'required', 'before', 'comparison', 'a< 5: print "zero"')) linter.reporter.display_results(Section()) self.assertMultiLineEqual(output.getvalue(), expected)
class LintModuleTest: maxDiff = None def __init__(self, test_file: FunctionalTestFile, config: Optional[Config] = None) -> None: _test_reporter = FunctionalTestReporter() self._linter = PyLinter() self._linter.namespace.persistent = 0 checkers.initialize(self._linter) # See if test has its own .rc file, if so we use that one rc_file: Union[Path, str] = PYLINTRC try: rc_file = test_file.option_file self._linter.disable("suppressed-message") self._linter.disable("locally-disabled") self._linter.disable("useless-suppression") except NoFileError: pass try: args = [test_file.source] except NoFileError: # If we're still raising NoFileError the actual source file doesn't exist args = [""] _config_initialization(self._linter, args_list=args, config_file=rc_file, reporter=_test_reporter) self._test_file = test_file self._config = config self._check_end_position = ( sys.version_info >= self._test_file.options["min_pyver_end_position"]) def setUp(self) -> None: if self._should_be_skipped_due_to_version(): pytest.skip( f"Test cannot run with Python {sys.version.split(' ', maxsplit=1)[0]}." ) missing = [] for requirement in self._test_file.options["requires"]: try: __import__(requirement) except ImportError: missing.append(requirement) if missing: pytest.skip(f"Requires {','.join(missing)} to be present.") except_implementations = self._test_file.options[ "except_implementations"] if except_implementations: if platform.python_implementation() in except_implementations: msg = "Test cannot run with Python implementation %r" pytest.skip(msg % platform.python_implementation()) excluded_platforms = self._test_file.options["exclude_platforms"] if excluded_platforms: if sys.platform.lower() in excluded_platforms: pytest.skip(f"Test cannot run on platform {sys.platform!r}") def runTest(self) -> None: self._runTest() def _should_be_skipped_due_to_version(self) -> bool: return (sys.version_info < self._test_file.options["min_pyver"] or sys.version_info > self._test_file.options["max_pyver"]) def __str__(self) -> str: return f"{self._test_file.base} ({self.__class__.__module__}.{self.__class__.__name__})" @staticmethod def get_expected_messages(stream: TextIO) -> MessageCounter: """Parses a file and get expected messages. :param stream: File-like input stream. :type stream: enumerable :returns: A dict mapping line,msg-symbol tuples to the count on this line. :rtype: dict """ messages: MessageCounter = Counter() for i, line in enumerate(stream): match = _EXPECTED_RE.search(line) if match is None: continue line = match.group("line") if line is None: lineno = i + 1 elif line.startswith("+") or line.startswith("-"): lineno = i + 1 + int(line) else: lineno = int(line) version = match.group("version") op = match.group("op") if version: required = parse_python_version(version) if not _OPERATORS[op](sys.version_info, required): continue for msg_id in match.group("msgs").split(","): messages[lineno, msg_id.strip()] += 1 return messages @staticmethod def multiset_difference( expected_entries: MessageCounter, actual_entries: MessageCounter, ) -> Tuple[MessageCounter, Dict[Tuple[int, str], int]]: """Takes two multisets and compares them. A multiset is a dict with the cardinality of the key as the value. """ missing = expected_entries.copy() missing.subtract(actual_entries) unexpected = {} for key, value in list(missing.items()): if value <= 0: missing.pop(key) if value < 0: unexpected[key] = -value return missing, unexpected def _open_expected_file(self) -> TextIO: try: return open(self._test_file.expected_output, encoding="utf-8") except FileNotFoundError: return StringIO("") def _open_source_file(self) -> TextIO: if self._test_file.base == "invalid_encoded_data": return open(self._test_file.source, encoding="utf-8") if "latin1" in self._test_file.base: return open(self._test_file.source, encoding="latin1") return open(self._test_file.source, encoding="utf8") def _get_expected(self) -> Tuple[MessageCounter, List[OutputLine]]: with self._open_source_file() as f: expected_msgs = self.get_expected_messages(f) if not expected_msgs: expected_msgs = Counter() with self._open_expected_file() as f: expected_output_lines = [ OutputLine.from_csv(row, self._check_end_position) for row in csv.reader(f, "test") ] return expected_msgs, expected_output_lines def _get_actual(self) -> Tuple[MessageCounter, List[OutputLine]]: messages: List[Message] = self._linter.reporter.messages messages.sort(key=lambda m: (m.line, m.symbol, m.msg)) received_msgs: MessageCounter = Counter() received_output_lines = [] for msg in messages: assert (msg.symbol != "fatal"), f"Pylint analysis failed because of '{msg.msg}'" received_msgs[msg.line, msg.symbol] += 1 received_output_lines.append( OutputLine.from_msg(msg, self._check_end_position)) return received_msgs, received_output_lines def _runTest(self) -> None: __tracebackhide__ = True # pylint: disable=unused-variable modules_to_check = [self._test_file.source] self._linter.check(modules_to_check) expected_messages, expected_output = self._get_expected() actual_messages, actual_output = self._get_actual() assert (expected_messages == actual_messages ), self.error_msg_for_unequal_messages(actual_messages, expected_messages, actual_output) self._check_output_text(expected_messages, expected_output, actual_output) def error_msg_for_unequal_messages( self, actual_messages: MessageCounter, expected_messages: MessageCounter, actual_output: List[OutputLine], ) -> str: msg = [f'Wrong results for file "{self._test_file.base}":'] missing, unexpected = self.multiset_difference(expected_messages, actual_messages) if missing: msg.append("\nExpected in testdata:") msg.extend(f" {msg[0]:3}: {msg[1]}" for msg in sorted(missing)) if unexpected: msg.append("\nUnexpected in testdata:") msg.extend(f" {msg[0]:3}: {msg[1]}" for msg in sorted(unexpected)) error_msg = "\n".join(msg) if self._config and self._config.getoption("verbose") > 0: error_msg += "\n\nActual pylint output for this file:\n" error_msg += "\n".join(str(o) for o in actual_output) return error_msg def error_msg_for_unequal_output( self, expected_lines: List[OutputLine], received_lines: List[OutputLine], ) -> str: missing = set(expected_lines) - set(received_lines) unexpected = set(received_lines) - set(expected_lines) error_msg = (f"Wrong output for '{self._test_file.base}.txt':\n" "You can update the expected output automatically with: '" f"python tests/test_functional.py {UPDATE_OPTION} -k " f'"test_functional[{self._test_file.base}]"\'\n\n') sort_by_line_number = operator.attrgetter("lineno") if missing: error_msg += "\n- Missing lines:\n" for line in sorted(missing, key=sort_by_line_number): error_msg += f"{line}\n" if unexpected: error_msg += "\n- Unexpected lines:\n" for line in sorted(unexpected, key=sort_by_line_number): error_msg += f"{line}\n" return error_msg def _check_output_text( self, _: MessageCounter, expected_output: List[OutputLine], actual_output: List[OutputLine], ) -> None: """This is a function because we want to be able to update the text in LintModuleOutputUpdate.""" assert expected_output == actual_output, self.error_msg_for_unequal_output( expected_output, actual_output)
class Runner(): """ Run and control the checking process. """ outputStream = None linter = None allowOptions = None # Customized checkers. checkers = ("header.HeaderChecker", "names.TwistedNamesChecker", "pycodestyleformat.PyCodeStyleChecker", "docstring.DocstringChecker", "formattingoperation.FormattingOperationChecker", "comment.CommentChecker", "testclassname.TestClassNameChecker") allowedMessagesFromPylint = ("F0001", "C0103", "C0301", "W0311", "W0312") diffOption = None errorResultRead = "Error: Failed to read result file '%s'.\n" prefixModuleName = "************* Module " regexLineStart = "^[WCEFR]\d{4}\:" def __init__(self): """ Initialize C{PyLinter} object, and load configuration file. """ self.allowOptions = True self.linter = PyLinter(self._makeOptions()) # register standard checkers. self.linter.load_default_plugins() # read configuration. pathConfig = os.path.join(twistedchecker.abspath, "configuration", "pylintrc") self.linter.read_config_file(pathConfig) # now we can load file config and command line, plugins (which can # provide options) have been registered. self.linter.load_config_file() allowedMessages = self.registerCheckers() # disable messages disabledMessages = set(self.linter .cfgfile_parser.get("TWISTEDCHECKER", "disable") .replace(" ", "").split(",")) if disabledMessages != {""}: for msg in disabledMessages: self.linter.disable(msg) allowedMessages -= disabledMessages # set default output stream to stdout self.setOutput(sys.stdout) # set default reporter to limited reporter self.setReporter(LimitedReporter(allowedMessages)) def _makeOptions(self): """ Return options for twistedchecker. """ return ( ("diff", {"type": "string", "metavar": "<result-file>", "help": "Set comparing result file to automatically " "generate a diff."} ), ('pep8', {'type': 'yn', 'metavar': '<y_or_n>', 'default': False, 'help': 'Show pep8 warnings.'} ), ('strict-epydoc', {'type': 'yn', 'metavar': '<y_or_n>', 'default': False, 'help': "Check '@type' and '@rtype' in epydoc."} ), ) def setOutput(self, stream): """ Set the stream to output result of checking. @param stream: output stream, defaultly it should be stdout """ self.outputStream = stream sys.stdout = stream def setReporter(self, reporter): """ Set the reporter of pylint. @param reporter: reporter used to show messages """ self.linter.set_reporter(reporter) def displayHelp(self): """ Output help message of twistedchecker. """ self.outputStream.write(self.linter.help()) sys.exit(32) def registerCheckers(self): """ Register all checkers of TwistedChecker to C{PyLinter}. @return: a list of allowed messages """ # We patch the default pylint format checker. patch_pylint_format.patch() # register checkers allowedMessages = list(self.allowedMessagesFromPylint) for strChecker in self.checkers: modname, classname = strChecker.split(".") strModule = "twistedchecker.checkers.%s" % modname checker = getattr(__import__(strModule, fromlist=["twistedchecker.checkers"]), classname) instanceChecker = checker(self.linter) allowedMessages += list(instanceChecker.msgs.keys()) self.linter.register_checker(instanceChecker) self.restrictCheckers(allowedMessages) return set(allowedMessages) def unregisterChecker(self, checker): """ Remove a checker from the list of registered checkers. @param checker: the checker to remove """ self.linter._checkers[checker.name].remove(checker) if checker in self.linter._reports: del self.linter._reports[checker] if checker in self.linter.options_providers: self.linter.options_providers.remove(checker) def findUselessCheckers(self, allowedMessages): """ Find checkers which generate no allowed messages. @param allowedMessages: allowed messages @return: useless checkers, remove them from pylint """ uselessCheckers = [] for checkerName in self.linter._checkers: for checker in list(self.linter._checkers[checkerName]): messagesOfChecker = set(checker.msgs) if not messagesOfChecker.intersection(allowedMessages): uselessCheckers.append(checker) return uselessCheckers def restrictCheckers(self, allowedMessages): """ Unregister useless checkers to speed up twistedchecker. @param allowedMessages: output messages allowed in twistedchecker """ uselessCheckers = self.findUselessCheckers(allowedMessages) # Unregister these checkers for checker in uselessCheckers: self.unregisterChecker(checker) def getCheckerByName(self, checkerType): """ Get checker by given name. @checkerType: type of the checker """ for checker in sum(list(self.linter._checkers.values()), []): if isinstance(checker, checkerType): return checker return None def allowPatternsForNameChecking(self, patternsFunc, patternsClass): """ Allow name exceptions by given patterns. @param patternsFunc: patterns of special function names @param patternsClass: patterns of special class names """ cfgParser = self.linter.cfgfile_parser nameChecker = self.getCheckerByName(NameChecker) if not nameChecker: return if patternsFunc: regexFuncAdd = "|((%s).+)$" % "|".join(patternsFunc) else: regexFuncAdd = "" if patternsClass: regexClassAdd = "|((%s).+)$" % "|".join(patternsClass) else: regexClassAdd = "" # Modify regex for function, method and class name. regexMethod = cfgParser.get("BASIC", "method-rgx") + regexFuncAdd regexFunction = cfgParser.get("BASIC", "function-rgx") + regexFuncAdd regexClass = cfgParser.get("BASIC", "class-rgx") + regexClassAdd # Save to config parser. cfgParser.set("BASIC", "method-rgx", regexMethod) cfgParser.set("BASIC", "function-rgx", regexFunction) cfgParser.set("BASIC", "class-rgx", regexClass) # Save to name checker. nameChecker.config.method_rgx = re.compile(regexMethod) nameChecker.config.function_rgx = re.compile(regexFunction) nameChecker.config.class_rgx = re.compile(regexClass) def getPathList(self, filesOrModules): """ Transform a list of modules to path. @param filesOrModules: a list of modules (may be foo/bar.py or foo.bar) """ pathList = [] for fileOrMod in filesOrModules: if not os.path.exists(fileOrMod): # May be given module is not not a path, # then transform it to a path. try: filepath = file_from_modpath(fileOrMod.split('.')) except (ImportError, SyntaxError): # Could not load this module. continue if not os.path.exists(filepath): # Could not find this module in file system. continue if os.path.basename(filepath) == "__init__.py": filepath = os.path.dirname(filepath) else: filepath = fileOrMod pathList.append(filepath) return pathList def setNameExceptions(self, filesOrModules): """ Find name exceptions in codes and allow them to be ignored in checking. @param filesOrModules: a list of modules (may be foo/bar.py or foo.bar) """ pathList = self.getPathList(filesOrModules) for path in pathList: patternsFunc, patternsClass = findAllExceptions(path) self.allowPatternsForNameChecking(patternsFunc, patternsClass) def run(self, args): """ Setup the environment, and run pylint. @param args: arguments will be passed to pylint @type args: list of string """ # set output stream. if self.outputStream: self.linter.reporter.set_output(self.outputStream) try: args = self.linter.load_command_line_configuration(args) except SystemExit as exc: if exc.code == 2: # bad options exc.code = 32 raise if not args: self.displayHelp() # Check for 'strict-epydoc' option. if self.allowOptions and not self.linter.option_value("strict-epydoc"): for msg in ["W9203", "W9205"]: self.linter.disable(msg) # insert current working directory to the python path to have a correct # behaviour. sys.path.insert(0, os.getcwd()) # set exceptions for name checking. self.setNameExceptions(args) # check for diff option. self.diffOption = self.linter.option_value("diff") if self.diffOption: self.prepareDiff() # check codes. self.linter.check(args) # show diff of warnings if diff option on. if self.diffOption: diffCount = self.showDiffResults() exitCode = 1 if diffCount else 0 sys.exit(exitCode) sys.exit(self.linter.msg_status) def prepareDiff(self): """ Prepare to run the checker and get diff results. """ self.streamForDiff = NativeStringIO() self.linter.reporter.set_output(self.streamForDiff) def showDiffResults(self): """ Show results when diff option on. """ try: oldWarnings = self.parseWarnings(self._readDiffFile()) except: sys.stderr.write(self.errorResultRead % self.diffOption) return 1 newWarnings = self.parseWarnings(self.streamForDiff.getvalue()) diffWarnings = self.generateDiff(oldWarnings, newWarnings) if diffWarnings: diffResult = self.formatWarnings(diffWarnings) self.outputStream.write(diffResult + "\n") return len(diffWarnings) else: return 0 def _readDiffFile(self): """ Read content of diff file. This is here to help with testing. @return: File content. @rtype: c{str} """ with open(self.diffOption) as f: content = f.read() return content def generateDiff(self, oldWarnings, newWarnings): """ Generate diff between given two lists of warnings. @param oldWarnings: parsed old warnings @param newWarnings: parsed new warnings @return: a dict object of diff """ diffWarnings = {} for modulename in newWarnings: diffInModule = ( newWarnings[modulename] - oldWarnings.get(modulename, set())) if diffInModule: diffWarnings[modulename] = diffInModule return diffWarnings def parseWarnings(self, result): """ Transform result in string to a dict object. @param result: a list of warnings in string @return: a dict of warnings """ warnings = {} currentModule = None warningsCurrentModule = [] for line in result.splitlines(): if line.startswith(self.prefixModuleName): # Save results for previous module if currentModule: warnings[currentModule] = set(warningsCurrentModule) # Initial results for current module moduleName = line.replace(self.prefixModuleName, "") currentModule = moduleName warningsCurrentModule = [] elif re.search(self.regexLineStart, line): warningsCurrentModule.append(line) else: if warningsCurrentModule: warningsCurrentModule[-1] += "\n" + line # Save warnings for last module if currentModule: warnings[currentModule] = set(warningsCurrentModule) return warnings def formatWarnings(self, warnings): """ Format warnings to a list of results. @param warnings: a dict of warnings produced by parseWarnings @return: a list of warnings in string """ lines = [] for modulename in sorted(warnings): lines.append(self.prefixModuleName + modulename) lines.extend(sorted(warnings[modulename], key=lambda x: x.split(":")[1])) return "\n".join(lines)
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) def _compare_messages(self, desc, msg, checkerref=False): # replace \r\n with \n, because # logilab.common.textutils.normalize_text # uses os.linesep, which will # not properly compare with triple # quoted multilines used in these tests self.assertMultiLineEqual(desc, msg.format_help(checkerref=checkerref) .replace('\r\n', '\n')) 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.check_message_id('F0001') self._compare_messages( ''':fatal (F0001): 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, checkerref=True) self._compare_messages( ''':fatal (F0001): Used when an error occurred preventing the analysis of a module (unable to find it for instance).''', msg, 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._compare_messages( ''':duplicate-keyword-arg (E1122): *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, checkerref=True) self._compare_messages( ''':duplicate-keyword-arg (E1122): *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, checkerref=False) def test_enable_message(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertFalse(linter.is_message_enabled('C0121', line=1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertTrue(linter.is_message_enabled('C0121', line=1)) def test_message_state_scope(self): linter = self.linter linter.open() linter.disable('C0121') self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0121')) linter.disable('W0101', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0121')) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0101', 3)) linter.enable('W0102', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0102', 3)) def test_enable_message_block(self): linter = self.linter linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astroid = linter.get_ast(filepath, 'func_block_disable_msg') linter.process_tokens(tokenize_module(astroid)) orig_state = linter._module_msgs_state.copy() linter._module_msgs_state = {} linter._suppression_mapping = {} linter.collect_block_lines(astroid, orig_state) # global (module level) self.assertTrue(linter.is_message_enabled('W0613')) self.assertTrue(linter.is_message_enabled('E1101')) # meth1 self.assertTrue(linter.is_message_enabled('W0613', 13)) # meth2 self.assertFalse(linter.is_message_enabled('W0613', 18)) # meth3 self.assertFalse(linter.is_message_enabled('E1101', 24)) self.assertTrue(linter.is_message_enabled('E1101', 26)) # meth4 self.assertFalse(linter.is_message_enabled('E1101', 32)) self.assertTrue(linter.is_message_enabled('E1101', 36)) # meth5 self.assertFalse(linter.is_message_enabled('E1101', 42)) self.assertFalse(linter.is_message_enabled('E1101', 43)) self.assertTrue(linter.is_message_enabled('E1101', 46)) self.assertFalse(linter.is_message_enabled('E1101', 49)) self.assertFalse(linter.is_message_enabled('E1101', 51)) # meth6 self.assertFalse(linter.is_message_enabled('E1101', 57)) self.assertTrue(linter.is_message_enabled('E1101', 61)) self.assertFalse(linter.is_message_enabled('E1101', 64)) self.assertFalse(linter.is_message_enabled('E1101', 66)) self.assertTrue(linter.is_message_enabled('E0602', 57)) self.assertTrue(linter.is_message_enabled('E0602', 61)) self.assertFalse(linter.is_message_enabled('E0602', 62)) self.assertTrue(linter.is_message_enabled('E0602', 64)) self.assertTrue(linter.is_message_enabled('E0602', 66)) # meth7 self.assertFalse(linter.is_message_enabled('E1101', 70)) self.assertTrue(linter.is_message_enabled('E1101', 72)) self.assertTrue(linter.is_message_enabled('E1101', 75)) self.assertTrue(linter.is_message_enabled('E1101', 77)) self.assertEqual(17, linter._suppression_mapping['W0613', 18]) self.assertEqual(30, linter._suppression_mapping['E1101', 33]) self.assertTrue(('E1101', 46) not in linter._suppression_mapping) self.assertEqual(1, linter._suppression_mapping['C0302', 18]) self.assertEqual(1, linter._suppression_mapping['C0302', 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, linter._suppression_mapping['E1101', 108]) self.assertEqual(109, linter._suppression_mapping['E1101', 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.disable('unreachable', scope='package') linter.disable('dangerous-default-value', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertFalse(linter.is_message_enabled('W0102', 1)) self.assertFalse(linter.is_message_enabled('dangerous-default-value', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.enable('unreachable', scope='package') linter.enable('dangerous-default-value', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102', 1)) self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) def test_list_messages(self): sys.stdout = StringIO() try: self.linter.list_messages() output = sys.stdout.getvalue() finally: sys.stdout = sys.__stdout__ # cursory examination of the output: we're mostly testing it completes self.assertIn(':empty-docstring (C0112): *Empty %s docstring*', output) def test_lint_ext_module_with_file_output(self): self.linter.set_reporter(text.TextReporter()) if sys.version_info < (3, 0): strio = 'StringIO' else: strio = 'io' self.linter.config.files_output = True pylint_strio = 'pylint_%s.txt' % strio try: self.linter.check(strio) self.assertTrue(os.path.exists(pylint_strio)) self.assertTrue(os.path.exists('pylint_global.txt')) finally: try: os.remove(pylint_strio) os.remove('pylint_global.txt') except: pass def test_lint_should_analyze_file(self): self.linter.set_reporter(text.TextReporter()) self.linter.config.files_output = True self.linter.should_analyze_file = lambda *args: False self.linter.check('os') self.assertFalse(os.path.exists('pylint_os.txt')) def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option('output-format', 'text') self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter') def test_report_output_format_custom(self): this_module = sys.modules[__name__] class TestReporter(object): pass this_module.TestReporter = TestReporter class_name = ".".join((this_module.__name__, 'TestReporter')) self.linter.set_option('output-format', class_name) self.assertEqual(self.linter.reporter.__class__.__name__, 'TestReporter') def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0142') self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0142') ) self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_enable_checkers(self): self.linter.disable('design') self.assertFalse('design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue('design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set(('design', 'format', 'imports', 'metrics', 'miscellaneous', 'similarities')) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option('disable', 'RP0801') self.linter.set_option('disable', 'R0801') self.assertFalse('similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ('design', 'metrics', 'similarities', 'imports'): # as a Fatal message that should be ignored self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual( ['C: 1: Line too long (1/2)', 'C: 2: Line too long (3/4)'], self.linter.reporter.messages) def test_add_renamed_message(self): self.linter.add_renamed_message('C9999', 'old-bad-name', 'invalid-name') self.assertEqual('invalid-name', self.linter.check_message_id('C9999').symbol) self.assertEqual('invalid-name', self.linter.check_message_id('old-bad-name').symbol) def test_renamed_message_register(self): class Checker(object): msgs = {'W1234': ('message', 'msg-symbol', 'msg-description', {'old_names': [('W0001', 'old-symbol')]})} self.linter.register_messages(Checker()) self.assertEqual('msg-symbol', self.linter.check_message_id('W0001').symbol) self.assertEqual('msg-symbol', self.linter.check_message_id('old-symbol').symbol)
class LintModuleTest: maxDiff = None def __init__(self, test_file): _test_reporter = FunctionalTestReporter() self._linter = PyLinter() self._linter.set_reporter(_test_reporter) self._linter.config.persistent = 0 checkers.initialize(self._linter) self._linter.disable("I") try: self._linter.read_config_file(test_file.option_file) self._linter.load_config_file() except NoFileError: pass self._test_file = test_file def setUp(self): if self._should_be_skipped_due_to_version(): pytest.skip("Test cannot run with Python %s." % (sys.version.split(" ")[0], )) missing = [] for req in self._test_file.options["requires"]: try: __import__(req) except ImportError: missing.append(req) if missing: pytest.skip("Requires %s to be present." % (",".join(missing), )) if self._test_file.options["except_implementations"]: implementations = [ item.strip() for item in self._test_file.options["except_implementations"].split(",") ] implementation = platform.python_implementation() if implementation in implementations: pytest.skip("Test cannot run with Python implementation %r" % (implementation, )) if self._test_file.options["exclude_platforms"]: platforms = [ item.strip() for item in self._test_file.options["exclude_platforms"].split(",") ] if sys.platform.lower() in platforms: pytest.skip("Test cannot run on platform %r" % (sys.platform, )) def _should_be_skipped_due_to_version(self): return (sys.version_info < self._test_file.options["min_pyver"] or sys.version_info > self._test_file.options["max_pyver"]) def __str__(self): return "%s (%s.%s)" % ( self._test_file.base, self.__class__.__module__, self.__class__.__name__, ) def _open_expected_file(self): return open(self._test_file.expected_output) def _open_source_file(self): if self._test_file.base == "invalid_encoded_data": return open(self._test_file.source) if "latin1" in self._test_file.base: return open(self._test_file.source, encoding="latin1") return open(self._test_file.source, encoding="utf8") def _get_expected(self): with self._open_source_file() as fobj: expected_msgs = get_expected_messages(fobj) if expected_msgs: with self._open_expected_file() as fobj: expected_output_lines = parse_expected_output(fobj) else: expected_output_lines = [] return expected_msgs, expected_output_lines def _get_received(self): messages = self._linter.reporter.messages messages.sort(key=lambda m: (m.line, m.symbol, m.msg)) received_msgs = collections.Counter() received_output_lines = [] for msg in messages: assert (msg.symbol != "fatal"), "Pylint analysis failed because of '{}'".format( msg.msg) received_msgs[msg.line, msg.symbol] += 1 received_output_lines.append(OutputLine.from_msg(msg)) return received_msgs, received_output_lines def _runTest(self): modules_to_check = [self._test_file.source] self._linter.check(modules_to_check) expected_messages, expected_text = self._get_expected() received_messages, received_text = self._get_received() if expected_messages != received_messages: msg = ['Wrong results for file "%s":' % (self._test_file.base)] missing, unexpected = multiset_difference(expected_messages, received_messages) if missing: msg.append("\nExpected in testdata:") msg.extend(" %3d: %s" % msg for msg in sorted(missing)) if unexpected: msg.append("\nUnexpected in testdata:") msg.extend(" %3d: %s" % msg for msg in sorted(unexpected)) pytest.fail("\n".join(msg)) self._check_output_text(expected_messages, expected_text, received_text) @classmethod def _split_lines(cls, expected_messages, lines): emitted, omitted = [], [] for msg in lines: if (msg[1], msg[0]) in expected_messages: emitted.append(msg) else: omitted.append(msg) return emitted, omitted def _check_output_text(self, expected_messages, expected_lines, received_lines): expected_lines = self._split_lines(expected_messages, expected_lines)[0] assert (expected_lines == received_lines ), "Expected test lines did not match for test: {}".format( self._test_file.base)
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter(reporter=TextReporter()) self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) os.environ.pop('PYLINTRC', None) def test_template_option(self): output = six.StringIO() self.linter.reporter.set_output(output) self.linter.set_option('msg-template', '{msg_id}:{line:03d}') self.linter.open() 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(), '************* Module 0123\n' 'C0301:001\n' 'C0301:002\n') def test_parseable_output_deprecated(self): with warnings.catch_warnings(record=True) as cm: warnings.simplefilter("always") ParseableTextReporter() self.assertEqual(len(cm), 1) self.assertIsInstance(cm[0].message, DeprecationWarning) def test_parseable_output_regression(self): output = six.StringIO() with warnings.catch_warnings(record=True): linter = PyLinter(reporter=ParseableTextReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.set_option('output-format', 'parseable') linter.open() linter.set_current_module('0123') linter.add_message('line-too-long', line=1, args=(1, 2)) self.assertMultiLineEqual( output.getvalue(), '************* Module 0123\n' '0123:1: [C0301(line-too-long), ] ' 'Line too long (1/2)\n') @unittest.expectedFailure def test_html_reporter_type(self): # Integration test for issue #263 # https://bitbucket.org/logilab/pylint/issue/263/html-report-type-problems expected = '''<html> <body> <div> <div> <h2>Messages</h2> <table> <tr class="header"> <th>type</th> <th>module</th> <th>object</th> <th>line</th> <th>col_offset</th> <th>message</th> </tr> <tr class="even"> <td>convention</td> <td>0123</td> <td> </td> <td>1</td> <td>0</td> <td>Exactly one space required before comparison a< 5: print "zero"</td> </tr> </table> </div> </div> </body> </html> ''' output = six.StringIO() linter = PyLinter(reporter=HTMLReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.open() linter.set_current_module('0123') linter.add_message('bad-whitespace', line=1, args=('Exactly one', 'required', 'before', 'comparison', 'a< 5: print "zero"')) linter.reporter.display_results(Section()) self.assertMultiLineEqual(output.getvalue(), expected)
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) def test_message_help(self): msg = self.linter.get_message_help('F0001', checkerref=True) expected = ':F0001:\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.assertTextEqual(msg, expected) self.assertRaises(UnknownMessage, self.linter.get_message_help, 'YB12') def test_enable_message(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assert_(linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assert_(not linter.is_message_enabled('W0101')) self.assert_(not linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assert_(not linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assert_(linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assert_(linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('C0121')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assert_(not linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('C0121')) self.assert_(not linter.is_message_enabled('C0121', line=1)) linter.set_current_module('tutu') self.assert_(not linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('C0121')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assert_(linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('C0121')) self.assert_(linter.is_message_enabled('C0121', line=1)) def test_enable_message_block(self): linter = self.linter linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') linter.process_module(open(filepath)) orig_state = linter._module_msgs_state.copy() linter._module_msgs_state = {} linter.collect_block_lines(linter.get_astng(filepath, 'func_block_disable_msg'), orig_state) # global (module level) self.assert_(linter.is_message_enabled('W0613')) self.assert_(linter.is_message_enabled('E1101')) # meth1 self.assert_(linter.is_message_enabled('W0613', 13)) # meth2 self.assert_(not linter.is_message_enabled('W0613', 18)) # meth3 self.assert_(not linter.is_message_enabled('E1101', 24)) self.assert_(linter.is_message_enabled('E1101', 26)) # meth4 self.assert_(not linter.is_message_enabled('E1101', 32)) self.assert_(linter.is_message_enabled('E1101', 36)) # meth5 self.assert_(not linter.is_message_enabled('E1101', 42)) self.assert_(not linter.is_message_enabled('E1101', 43)) self.assert_(linter.is_message_enabled('E1101', 46)) self.assert_(not linter.is_message_enabled('E1101', 49)) self.assert_(not linter.is_message_enabled('E1101', 51)) # meth6 self.assert_(not linter.is_message_enabled('E1101', 57)) self.assert_(linter.is_message_enabled('E1101', 61)) self.assert_(not linter.is_message_enabled('E1101', 64)) self.assert_(not linter.is_message_enabled('E1101', 66)) self.assert_(linter.is_message_enabled('E0602', 57)) self.assert_(linter.is_message_enabled('E0602', 61)) self.assert_(not linter.is_message_enabled('E0602', 62)) self.assert_(linter.is_message_enabled('E0602', 64)) self.assert_(linter.is_message_enabled('E0602', 66)) # meth7 self.assert_(not linter.is_message_enabled('E1101', 70)) self.assert_(linter.is_message_enabled('E1101', 72)) self.assert_(linter.is_message_enabled('E1101', 75)) self.assert_(linter.is_message_enabled('E1101', 77)) def test_list_messages(self): sys.stdout = StringIO() try: # just invoke it, don't check the output self.linter.list_messages() finally: sys.stdout = sys.__stdout__ def test_lint_ext_module_with_file_output(self): self.linter.config.files_output = True try: self.linter.check('StringIO') self.assert_(os.path.exists('pylint_StringIO.txt')) self.assert_(os.path.exists('pylint_global.txt')) finally: try: os.remove('pylint_StringIO.txt') os.remove('pylint_global.txt') except: pass def test_enable_report(self): self.assertEquals(self.linter.is_report_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEquals(self.linter.is_report_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEquals(self.linter.is_report_enabled('RP0001'), True) def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0142') self.assert_(not linter.is_message_enabled('C0111')) self.assert_(not linter.is_message_enabled('W0142')) self.assert_(linter.is_message_enabled('W0113')) def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0142') ) self.assert_(not linter.is_message_enabled('C0111')) self.assert_(not linter.is_message_enabled('W0142')) self.assert_(linter.is_message_enabled('W0113')) def test_enable_checkers(self): self.linter.disable('design') self.failIf('design' in set([c.name for c in self.linter._get_checkers()])) self.linter.enable('design') self.failUnless('design' in set([c.name for c in self.linter._get_checkers()]))
class LintModuleTest: maxDiff = None def __init__(self, test_file: FunctionalTestFile): _test_reporter = FunctionalTestReporter() self._linter = PyLinter() self._linter.set_reporter(_test_reporter) self._linter.config.persistent = 0 checkers.initialize(self._linter) self._linter.disable("I") try: self._linter.read_config_file(test_file.option_file) self._linter.load_config_file() except NoFileError: pass self._test_file = test_file def setUp(self): if self._should_be_skipped_due_to_version(): pytest.skip("Test cannot run with Python %s." % sys.version.split(" ")[0]) missing = [] for requirement in self._test_file.options["requires"]: try: __import__(requirement) except ImportError: missing.append(requirement) if missing: pytest.skip("Requires %s to be present." % ",".join(missing)) except_implementations = self._test_file.options[ "except_implementations"] if except_implementations: implementations = [ i.strip() for i in except_implementations.split(",") ] if platform.python_implementation() in implementations: msg = "Test cannot run with Python implementation %r" pytest.skip(msg % platform.python_implementation()) excluded_platforms = self._test_file.options["exclude_platforms"] if excluded_platforms: platforms = [p.strip() for p in excluded_platforms.split(",")] if sys.platform.lower() in platforms: pytest.skip("Test cannot run on platform %r" % sys.platform) def _should_be_skipped_due_to_version(self): return (sys.version_info < self._test_file.options["min_pyver"] or sys.version_info > self._test_file.options["max_pyver"]) def __str__(self): return "%s (%s.%s)" % ( self._test_file.base, self.__class__.__module__, self.__class__.__name__, ) @staticmethod def get_expected_messages(stream): """Parses a file and get expected messages. :param stream: File-like input stream. :type stream: enumerable :returns: A dict mapping line,msg-symbol tuples to the count on this line. :rtype: dict """ messages = Counter() for i, line in enumerate(stream): match = _EXPECTED_RE.search(line) if match is None: continue line = match.group("line") if line is None: line = i + 1 elif line.startswith("+") or line.startswith("-"): line = i + 1 + int(line) else: line = int(line) version = match.group("version") op = match.group("op") if version: required = parse_python_version(version) if not _OPERATORS[op](sys.version_info, required): continue for msg_id in match.group("msgs").split(","): messages[line, msg_id.strip()] += 1 return messages @staticmethod def multiset_difference( expected_entries: Counter, actual_entries: Counter) -> Tuple[Counter, Dict[str, int]]: """Takes two multisets and compares them. A multiset is a dict with the cardinality of the key as the value.""" missing = expected_entries.copy() missing.subtract(actual_entries) unexpected = {} for key, value in list(missing.items()): if value <= 0: missing.pop(key) if value < 0: unexpected[key] = -value return missing, unexpected def _open_expected_file(self): try: return open(self._test_file.expected_output) except FileNotFoundError: return StringIO("") def _open_source_file(self): if self._test_file.base == "invalid_encoded_data": return open(self._test_file.source) if "latin1" in self._test_file.base: return open(self._test_file.source, encoding="latin1") return open(self._test_file.source, encoding="utf8") def _get_expected(self): with self._open_source_file() as f: expected_msgs = self.get_expected_messages(f) if not expected_msgs: return Counter(), [] with self._open_expected_file() as f: expected_output_lines = [ OutputLine.from_csv(row) for row in csv.reader(f, "test") ] return expected_msgs, expected_output_lines def _get_actual(self): messages = self._linter.reporter.messages messages.sort(key=lambda m: (m.line, m.symbol, m.msg)) received_msgs = Counter() received_output_lines = [] for msg in messages: assert (msg.symbol != "fatal"), "Pylint analysis failed because of '{}'".format( msg.msg) received_msgs[msg.line, msg.symbol] += 1 received_output_lines.append(OutputLine.from_msg(msg)) return received_msgs, received_output_lines def _runTest(self): modules_to_check = [self._test_file.source] self._linter.check(modules_to_check) expected_messages, expected_output = self._get_expected() actual_messages, actual_output = self._get_actual() assert (expected_messages == actual_messages ), self.error_msg_for_unequal_messages(actual_messages, expected_messages) self._check_output_text(expected_messages, expected_output, actual_output) def error_msg_for_unequal_messages(self, actual_messages, expected_messages): msg = ['Wrong results for file "%s":' % (self._test_file.base)] missing, unexpected = self.multiset_difference(expected_messages, actual_messages) if missing: msg.append("\nExpected in testdata:") msg.extend(" %3d: %s" % msg for msg in sorted(missing)) if unexpected: msg.append("\nUnexpected in testdata:") msg.extend(" %3d: %s" % msg for msg in sorted(unexpected)) error_msg = "\n".join(msg) return error_msg def error_msg_for_unequal_output(self, expected_lines, received_lines) -> str: missing = set(expected_lines) - set(received_lines) unexpected = set(received_lines) - set(expected_lines) error_msg = ( "Wrong output for '{_file}.txt':\n" "You can update the expected output automatically with: '" 'python tests/test_functional.py {update_option} -k "test_functional[{_file}]"\'\n\n' .format( update_option=UPDATE_OPTION, _file=self._test_file.base, )) sort_by_line_number = operator.attrgetter("lineno") if missing: error_msg += "\n- Missing lines:\n" for line in sorted(missing, key=sort_by_line_number): error_msg += "{}\n".format(line) if unexpected: error_msg += "\n- Unexpected lines:\n" for line in sorted(unexpected, key=sort_by_line_number): error_msg += "{}\n".format(line) return error_msg def _check_output_text(self, _, expected_output, actual_output): """This is a function because we want to be able to update the text in LintModuleOutputUpdate""" assert expected_output == actual_output, self.error_msg_for_unequal_output( expected_output, actual_output)
import sys import platform import os from os.path import abspath, dirname, join import unittest from pylint.testutils import TestReporter from pylint.lint import PyLinter from pylint import checkers from pylint import epylint test_reporter = TestReporter() linter = PyLinter() linter.set_reporter(test_reporter) linter.disable("I") linter.config.persistent = 0 checkers.initialize(linter) REGR_DATA = join(dirname(abspath(__file__)), "regrtest_data") sys.path.insert(1, REGR_DATA) class NonRegrTC(unittest.TestCase): def setUp(self): """call reporter.finalize() to cleanup pending messages if a test finished badly """ linter.reporter.finalize() def test_package___path___manipulation(self):
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) 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') def test_enable_message(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertFalse(linter.is_message_enabled('C0121', line=1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertTrue(linter.is_message_enabled('C0121', line=1)) def test_message_state_scope(self): linter = self.linter linter.open() linter.disable('C0121') self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0121')) linter.disable('W0101', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0121')) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0101', 3)) linter.enable('W0102', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0102', 3)) def test_enable_message_block(self): linter = self.linter linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astroid = linter.get_astroid(filepath, 'func_block_disable_msg') linter.process_tokens(tokenize_module(astroid)) orig_state = linter._module_msgs_state.copy() linter._module_msgs_state = {} linter._suppression_mapping = {} linter.collect_block_lines(astroid, orig_state) # global (module level) self.assertTrue(linter.is_message_enabled('W0613')) self.assertTrue(linter.is_message_enabled('E1101')) # meth1 self.assertTrue(linter.is_message_enabled('W0613', 13)) # meth2 self.assertFalse(linter.is_message_enabled('W0613', 18)) # meth3 self.assertFalse(linter.is_message_enabled('E1101', 24)) self.assertTrue(linter.is_message_enabled('E1101', 26)) # meth4 self.assertFalse(linter.is_message_enabled('E1101', 32)) self.assertTrue(linter.is_message_enabled('E1101', 36)) # meth5 self.assertFalse(linter.is_message_enabled('E1101', 42)) self.assertFalse(linter.is_message_enabled('E1101', 43)) self.assertTrue(linter.is_message_enabled('E1101', 46)) self.assertFalse(linter.is_message_enabled('E1101', 49)) self.assertFalse(linter.is_message_enabled('E1101', 51)) # meth6 self.assertFalse(linter.is_message_enabled('E1101', 57)) self.assertTrue(linter.is_message_enabled('E1101', 61)) self.assertFalse(linter.is_message_enabled('E1101', 64)) self.assertFalse(linter.is_message_enabled('E1101', 66)) self.assertTrue(linter.is_message_enabled('E0602', 57)) self.assertTrue(linter.is_message_enabled('E0602', 61)) self.assertFalse(linter.is_message_enabled('E0602', 62)) self.assertTrue(linter.is_message_enabled('E0602', 64)) self.assertTrue(linter.is_message_enabled('E0602', 66)) # meth7 self.assertFalse(linter.is_message_enabled('E1101', 70)) self.assertTrue(linter.is_message_enabled('E1101', 72)) self.assertTrue(linter.is_message_enabled('E1101', 75)) self.assertTrue(linter.is_message_enabled('E1101', 77)) self.assertEqual(17, linter._suppression_mapping['W0613', 18]) self.assertEqual(30, linter._suppression_mapping['E1101', 33]) self.assert_(('E1101', 46) not in linter._suppression_mapping) self.assertEqual(1, linter._suppression_mapping['C0302', 18]) self.assertEqual(1, linter._suppression_mapping['C0302', 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, linter._suppression_mapping['E1101', 108]) self.assertEqual(109, linter._suppression_mapping['E1101', 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.linter linter.open() linter.set_current_module('toto') self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.disable('unreachable', scope='package') linter.disable('dangerous-default-value', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertFalse(linter.is_message_enabled('W0102', 1)) self.assertFalse( linter.is_message_enabled('dangerous-default-value', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.enable('unreachable', scope='package') linter.enable('dangerous-default-value', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102', 1)) self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) def test_list_messages(self): sys.stdout = StringIO() try: self.linter.list_messages() output = sys.stdout.getvalue() finally: sys.stdout = sys.__stdout__ # cursory examination of the output: we're mostly testing it completes self.assertTrue( ':C0112 (empty-docstring): *Empty %s docstring*' in output) def test_lint_ext_module_with_file_output(self): self.linter.set_reporter(text.TextReporter()) if sys.version_info < (3, 0): strio = 'StringIO' else: strio = 'io' self.linter.config.files_output = True pylint_strio = 'pylint_%s.txt' % strio try: self.linter.check(strio) self.assertTrue(os.path.exists(pylint_strio)) self.assertTrue(os.path.exists('pylint_global.txt')) finally: try: os.remove(pylint_strio) os.remove('pylint_global.txt') except: pass def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option('output-format', 'text') self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter') def test_report_output_format_custom(self): this_module = sys.modules[__name__] class TestReporter(object): pass this_module.TestReporter = TestReporter class_name = ".".join((this_module.__name__, 'TestReporter')) self.linter.set_option('output-format', class_name) self.assertEqual(self.linter.reporter.__class__.__name__, 'TestReporter') def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0142') self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0142')) self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_enable_checkers(self): self.linter.disable('design') self.assertFalse( 'design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue( 'design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set(('design', 'format', 'imports', 'metrics', 'miscellaneous', 'similarities')) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option('disable', 'RP0801') self.linter.set_option('disable', 'R0801') self.assertFalse( 'similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ('design', 'metrics', 'similarities', 'imports'): # as a Fatal message that should be ignored self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual( ['C: 1: Line too long (1/2)', 'C: 2: Line too long (3/4)'], self.linter.reporter.messages)
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter(reporter=TextReporter()) self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) os.environ.pop('PYLINTRC', None) def test_add_message_is_deprecated(self): if __pkginfo__.numversion >= (1, 6, 0): with self.assertRaises(AttributeError): BaseReporter().add_message with warnings.catch_warnings(record=True) as cm: warnings.simplefilter("always") BaseReporter().add_message(None, None, None) self.assertEqual(len(cm), 1) self.assertIsInstance(cm[0].message, DeprecationWarning) msg = ('This method is deprecated, use handle_message ' 'instead. It will be removed in Pylint 1.6.') self.assertEqual(str(cm[0].message), msg) def test_template_option(self): output = six.StringIO() self.linter.reporter.set_output(output) self.linter.set_option('msg-template', '{msg_id}:{line:03d}') self.linter.open() 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(), '************* Module 0123\n' 'C0301:001\n' 'C0301:002\n') def test_parseable_output_deprecated(self): with warnings.catch_warnings(record=True) as cm: warnings.simplefilter("always") ParseableTextReporter() self.assertEqual(len(cm), 1) self.assertIsInstance(cm[0].message, DeprecationWarning) def test_parseable_output_regression(self): output = six.StringIO() with warnings.catch_warnings(record=True): linter = PyLinter(reporter=ParseableTextReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.set_option('output-format', 'parseable') linter.open() linter.set_current_module('0123') linter.add_message('line-too-long', line=1, args=(1, 2)) self.assertMultiLineEqual(output.getvalue(), '************* Module 0123\n' '0123:1: [C0301(line-too-long), ] ' 'Line too long (1/2)\n') def test_html_reporter_msg_template(self): expected = ''' <html> <body> <div> <div> <h2>Messages</h2> <table> <tr class="header"> <th>category</th> <th>msg_id</th> </tr> <tr class="even"> <td>warning</td> <td>W0332</td> </tr> </table> </div> </div> </body> </html>'''.strip().splitlines() output = six.StringIO() linter = PyLinter(reporter=HTMLReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.set_option('msg-template', '{category}{msg_id}') linter.open() linter.set_current_module('0123') linter.add_message('lowercase-l-suffix', line=1) linter.reporter.display_results(Section()) self.assertEqual(output.getvalue().splitlines(), expected) @unittest.expectedFailure def test_html_reporter_type(self): # Integration test for issue #263 # https://bitbucket.org/logilab/pylint/issue/263/html-report-type-problems expected = '''<html> <body> <div> <div> <h2>Messages</h2> <table> <tr class="header"> <th>type</th> <th>module</th> <th>object</th> <th>line</th> <th>col_offset</th> <th>message</th> </tr> <tr class="even"> <td>convention</td> <td>0123</td> <td> </td> <td>1</td> <td>0</td> <td>Exactly one space required before comparison a< 5: print "zero"</td> </tr> </table> </div> </div> </body> </html> ''' output = six.StringIO() linter = PyLinter(reporter=HTMLReporter()) checkers.initialize(linter) linter.config.persistent = 0 linter.reporter.set_output(output) linter.open() linter.set_current_module('0123') linter.add_message('bad-whitespace', line=1, args=('Exactly one', 'required', 'before', 'comparison', 'a< 5: print "zero"')) linter.reporter.display_results(Section()) self.assertMultiLineEqual(output.getvalue(), expected)
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) def init_linter(self): linter = self.linter linter.open() linter.set_current_module('toto') linter.file_state = FileState('toto') return linter def test_enable_message(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertFalse(linter.is_message_enabled('C0121', line=1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertTrue(linter.is_message_enabled('C0121', line=1)) def test_message_state_scope(self): linter = self.init_linter() fs = linter.file_state linter.disable('C0121') self.assertEqual(MSG_STATE_SCOPE_CONFIG, fs._message_state_scope('C0121')) linter.disable('W0101', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, fs._message_state_scope('C0121')) self.assertEqual(MSG_STATE_SCOPE_MODULE, fs._message_state_scope('W0101', 3)) linter.enable('W0102', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, fs._message_state_scope('W0102', 3)) def test_enable_message_block(self): linter = self.init_linter() linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astroid = linter.get_ast(filepath, 'func_block_disable_msg') linter.process_tokens(tokenize_module(astroid)) fs = linter.file_state fs.collect_block_lines(linter.msgs_store, astroid) # global (module level) self.assertTrue(linter.is_message_enabled('W0613')) self.assertTrue(linter.is_message_enabled('E1101')) # meth1 self.assertTrue(linter.is_message_enabled('W0613', 13)) # meth2 self.assertFalse(linter.is_message_enabled('W0613', 18)) # meth3 self.assertFalse(linter.is_message_enabled('E1101', 24)) self.assertTrue(linter.is_message_enabled('E1101', 26)) # meth4 self.assertFalse(linter.is_message_enabled('E1101', 32)) self.assertTrue(linter.is_message_enabled('E1101', 36)) # meth5 self.assertFalse(linter.is_message_enabled('E1101', 42)) self.assertFalse(linter.is_message_enabled('E1101', 43)) self.assertTrue(linter.is_message_enabled('E1101', 46)) self.assertFalse(linter.is_message_enabled('E1101', 49)) self.assertFalse(linter.is_message_enabled('E1101', 51)) # meth6 self.assertFalse(linter.is_message_enabled('E1101', 57)) self.assertTrue(linter.is_message_enabled('E1101', 61)) self.assertFalse(linter.is_message_enabled('E1101', 64)) self.assertFalse(linter.is_message_enabled('E1101', 66)) self.assertTrue(linter.is_message_enabled('E0602', 57)) self.assertTrue(linter.is_message_enabled('E0602', 61)) self.assertFalse(linter.is_message_enabled('E0602', 62)) self.assertTrue(linter.is_message_enabled('E0602', 64)) self.assertTrue(linter.is_message_enabled('E0602', 66)) # meth7 self.assertFalse(linter.is_message_enabled('E1101', 70)) self.assertTrue(linter.is_message_enabled('E1101', 72)) self.assertTrue(linter.is_message_enabled('E1101', 75)) self.assertTrue(linter.is_message_enabled('E1101', 77)) fs = linter.file_state self.assertEqual(17, fs._suppression_mapping['W0613', 18]) self.assertEqual(30, fs._suppression_mapping['E1101', 33]) self.assertTrue(('E1101', 46) not in fs._suppression_mapping) self.assertEqual(1, fs._suppression_mapping['C0302', 18]) self.assertEqual(1, fs._suppression_mapping['C0302', 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, fs._suppression_mapping['E1101', 108]) self.assertEqual(109, fs._suppression_mapping['E1101', 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.disable('unreachable', scope='package') linter.disable('dangerous-default-value', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertFalse(linter.is_message_enabled('W0102', 1)) self.assertFalse( linter.is_message_enabled('dangerous-default-value', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.enable('unreachable', scope='package') linter.enable('dangerous-default-value', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102', 1)) self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) def test_lint_ext_module_with_file_output(self): self.linter.set_reporter(text.TextReporter()) if sys.version_info < (3, 0): strio = 'StringIO' else: strio = 'io' self.linter.config.files_output = True pylint_strio = 'pylint_%s.txt' % strio try: self.linter.check(strio) self.assertTrue(os.path.exists(pylint_strio)) self.assertTrue(os.path.exists('pylint_global.txt')) finally: try: os.remove(pylint_strio) os.remove('pylint_global.txt') except: pass def test_lint_should_analyze_file(self): self.linter.set_reporter(text.TextReporter()) self.linter.config.files_output = True self.linter.should_analyze_file = lambda *args: False self.linter.check('logilab') self.assertTrue(os.path.exists('pylint_logilab.txt')) self.assertFalse(os.path.exists('pylint_logilab_common.txt')) def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option('output-format', 'text') self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter') def test_report_output_format_custom(self): this_module = sys.modules[__name__] class TestReporter(object): pass this_module.TestReporter = TestReporter class_name = ".".join((this_module.__name__, 'TestReporter')) self.linter.set_option('output-format', class_name) self.assertEqual(self.linter.reporter.__class__.__name__, 'TestReporter') def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0142') self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0142')) self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_enable_checkers(self): self.linter.disable('design') self.assertFalse( 'design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue( 'design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set(('design', 'format', 'imports', 'metrics', 'miscellaneous', 'similarities')) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option('disable', 'RP0801') self.linter.set_option('disable', 'R0801') self.assertFalse( 'similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ('design', 'metrics', 'similarities', 'imports'): # as a Fatal message that should be ignored self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual( ['C: 1: Line too long (1/2)', 'C: 2: Line too long (3/4)'], self.linter.reporter.messages) def test_init_hooks_called_before_load_plugins(self): self.assertRaises(RuntimeError, Run, [ '--load-plugins', 'unexistant', '--init-hook', 'raise RuntimeError' ]) self.assertRaises(RuntimeError, Run, [ '--init-hook', 'raise RuntimeError', '--load-plugins', 'unexistant' ]) def test_analyze_explicit_script(self): self.linter.set_reporter(TestReporter()) self.linter.check(self.datapath('ascript')) self.assertEqual(['C: 2: Line too long (175/80)'], self.linter.reporter.messages)
def test_enable_report(linter: PyLinter) -> None: assert linter.report_is_enabled("RP0001") linter.disable("RP0001") assert not linter.report_is_enabled("RP0001") linter.enable("RP0001") assert linter.report_is_enabled("RP0001")
def test_enable_checkers(linter: PyLinter) -> None: linter.disable("design") assert not ("design" in [c.name for c in linter.prepare_checkers()]) linter.enable("design") assert "design" in [c.name for c in linter.prepare_checkers()]
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) def init_linter(self): linter = self.linter linter.open() linter.set_current_module('toto') linter.file_state = FileState('toto') return linter def test_pylint_visit_method_taken_in_account(self): class CustomChecker(checkers.BaseChecker): __implements__ = interfaces.IAstroidChecker name = 'custom' msgs = {'W9999': ('', 'custom', '')} @check_messages('custom') def visit_class(self, _): pass self.linter.register_checker(CustomChecker(self.linter)) self.linter.open() out = six.moves.StringIO() self.linter.set_reporter(text.TextReporter(out)) self.linter.check('abc') def test_enable_message(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) self.assertFalse(linter.is_message_enabled('C0202', line=1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) self.assertTrue(linter.is_message_enabled('C0202', line=1)) def test_message_state_scope(self): class FakeConfig(object): confidence = ['HIGH'] linter = self.init_linter() linter.disable('C0202') self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0202')) linter.disable('W0101', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0202')) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0101', 3)) linter.enable('W0102', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0102', 3)) linter.config = FakeConfig() self.assertEqual( MSG_STATE_CONFIDENCE, linter.get_message_state_scope('this-is-bad', confidence=interfaces.INFERENCE)) def test_enable_message_block(self): linter = self.init_linter() linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astroid = linter.get_ast(filepath, 'func_block_disable_msg') linter.process_tokens(tokenize_module(astroid)) fs = linter.file_state fs.collect_block_lines(linter.msgs_store, astroid) # global (module level) self.assertTrue(linter.is_message_enabled('W0613')) self.assertTrue(linter.is_message_enabled('E1101')) # meth1 self.assertTrue(linter.is_message_enabled('W0613', 13)) # meth2 self.assertFalse(linter.is_message_enabled('W0613', 18)) # meth3 self.assertFalse(linter.is_message_enabled('E1101', 24)) self.assertTrue(linter.is_message_enabled('E1101', 26)) # meth4 self.assertFalse(linter.is_message_enabled('E1101', 32)) self.assertTrue(linter.is_message_enabled('E1101', 36)) # meth5 self.assertFalse(linter.is_message_enabled('E1101', 42)) self.assertFalse(linter.is_message_enabled('E1101', 43)) self.assertTrue(linter.is_message_enabled('E1101', 46)) self.assertFalse(linter.is_message_enabled('E1101', 49)) self.assertFalse(linter.is_message_enabled('E1101', 51)) # meth6 self.assertFalse(linter.is_message_enabled('E1101', 57)) self.assertTrue(linter.is_message_enabled('E1101', 61)) self.assertFalse(linter.is_message_enabled('E1101', 64)) self.assertFalse(linter.is_message_enabled('E1101', 66)) self.assertTrue(linter.is_message_enabled('E0602', 57)) self.assertTrue(linter.is_message_enabled('E0602', 61)) self.assertFalse(linter.is_message_enabled('E0602', 62)) self.assertTrue(linter.is_message_enabled('E0602', 64)) self.assertTrue(linter.is_message_enabled('E0602', 66)) # meth7 self.assertFalse(linter.is_message_enabled('E1101', 70)) self.assertTrue(linter.is_message_enabled('E1101', 72)) self.assertTrue(linter.is_message_enabled('E1101', 75)) self.assertTrue(linter.is_message_enabled('E1101', 77)) fs = linter.file_state self.assertEqual(17, fs._suppression_mapping['W0613', 18]) self.assertEqual(30, fs._suppression_mapping['E1101', 33]) self.assertTrue(('E1101', 46) not in fs._suppression_mapping) self.assertEqual(1, fs._suppression_mapping['C0302', 18]) self.assertEqual(1, fs._suppression_mapping['C0302', 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, fs._suppression_mapping['E1101', 108]) self.assertEqual(109, fs._suppression_mapping['E1101', 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.disable('unreachable', scope='package') linter.disable('dangerous-default-value', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertFalse(linter.is_message_enabled('W0102', 1)) self.assertFalse(linter.is_message_enabled('dangerous-default-value', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.enable('unreachable', scope='package') linter.enable('dangerous-default-value', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102', 1)) self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) def test_lint_ext_module_with_file_output(self): self.linter.set_reporter(text.TextReporter()) if sys.version_info < (3, 0): strio = 'StringIO' else: strio = 'io' self.linter.config.files_output = True self.linter.config.reports = True pylint_strio = 'pylint_%s.txt' % strio files = [pylint_strio, 'pylint_global.txt'] for file in files: self.addCleanup(remove, file) self.linter.check(strio) self.linter.generate_reports() for f in files: self.assertTrue(os.path.exists(f)) def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option('output-format', 'text') self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter') def test_report_output_format_custom(self): this_module = sys.modules[__name__] class TestReporter(object): pass this_module.TestReporter = TestReporter class_name = ".".join((this_module.__name__, 'TestReporter')) self.linter.set_option('output-format', class_name) self.assertEqual(self.linter.reporter.__class__.__name__, 'TestReporter') def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0234') self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0234')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('non-iterator-returned')) def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0234') ) self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0234')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('non-iterator-returned')) def test_enable_checkers(self): self.linter.disable('design') self.assertFalse('design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue('design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set(('design', 'format', 'metrics', 'miscellaneous', 'similarities')) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option('disable', 'RP0801') self.linter.set_option('disable', 'R0801') self.assertFalse('similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ('design', 'metrics', 'similarities'): self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual( ['C: 1: Line too long (1/2)', 'C: 2: Line too long (3/4)'], self.linter.reporter.messages) def test_init_hooks_called_before_load_plugins(self): self.assertRaises(RuntimeError, Run, ['--load-plugins', 'unexistant', '--init-hook', 'raise RuntimeError']) self.assertRaises(RuntimeError, Run, ['--init-hook', 'raise RuntimeError', '--load-plugins', 'unexistant']) def test_analyze_explicit_script(self): self.linter.set_reporter(TestReporter()) self.linter.check(os.path.join(os.path.dirname(__file__), 'data', 'ascript')) self.assertEqual( ['C: 2: Line too long (175/100)'], self.linter.reporter.messages) def test_html_reporter_missing_files(self): output = six.StringIO() self.linter.set_reporter(html.HTMLReporter(output)) self.linter.set_option('output-format', 'html') self.linter.check('troppoptop.py') self.linter.generate_reports() value = output.getvalue() self.assertIn('troppoptop.py', value) self.assertIn('fatal', value) def test_python3_checker_disabled(self): checker_names = [c.name for c in self.linter.prepare_checkers()] self.assertNotIn('python3', checker_names) self.linter.set_option('enable', 'python3') checker_names = [c.name for c in self.linter.prepare_checkers()] self.assertIn('python3', checker_names)
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) def init_linter(self): linter = self.linter linter.open() linter.set_current_module('toto') linter.file_state = FileState('toto') return linter def test_pylint_visit_method_taken_in_account(self): class CustomChecker(checkers.BaseChecker): __implements__ = interfaces.IAstroidChecker name = 'custom' msgs = {'W9999': ('', 'custom', '')} @check_messages('custom') def visit_class(self, _): pass self.linter.register_checker(CustomChecker(self.linter)) self.linter.open() out = six.moves.StringIO() self.linter.set_reporter(text.TextReporter(out)) self.linter.check('abc') def test_enable_message(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) self.assertFalse(linter.is_message_enabled('C0202', line=1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) self.assertTrue(linter.is_message_enabled('C0202', line=1)) def test_message_state_scope(self): class FakeConfig(object): confidence = ['HIGH'] linter = self.init_linter() linter.disable('C0202') self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0202')) linter.disable('W0101', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0202')) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0101', 3)) linter.enable('W0102', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0102', 3)) linter.config = FakeConfig() self.assertEqual( MSG_STATE_CONFIDENCE, linter.get_message_state_scope('this-is-bad', confidence=interfaces.INFERENCE)) def test_enable_message_block(self): linter = self.init_linter() linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astroid = linter.get_ast(filepath, 'func_block_disable_msg') linter.process_tokens(tokenize_module(astroid)) fs = linter.file_state fs.collect_block_lines(linter.msgs_store, astroid) # global (module level) self.assertTrue(linter.is_message_enabled('W0613')) self.assertTrue(linter.is_message_enabled('E1101')) # meth1 self.assertTrue(linter.is_message_enabled('W0613', 13)) # meth2 self.assertFalse(linter.is_message_enabled('W0613', 18)) # meth3 self.assertFalse(linter.is_message_enabled('E1101', 24)) self.assertTrue(linter.is_message_enabled('E1101', 26)) # meth4 self.assertFalse(linter.is_message_enabled('E1101', 32)) self.assertTrue(linter.is_message_enabled('E1101', 36)) # meth5 self.assertFalse(linter.is_message_enabled('E1101', 42)) self.assertFalse(linter.is_message_enabled('E1101', 43)) self.assertTrue(linter.is_message_enabled('E1101', 46)) self.assertFalse(linter.is_message_enabled('E1101', 49)) self.assertFalse(linter.is_message_enabled('E1101', 51)) # meth6 self.assertFalse(linter.is_message_enabled('E1101', 57)) self.assertTrue(linter.is_message_enabled('E1101', 61)) self.assertFalse(linter.is_message_enabled('E1101', 64)) self.assertFalse(linter.is_message_enabled('E1101', 66)) self.assertTrue(linter.is_message_enabled('E0602', 57)) self.assertTrue(linter.is_message_enabled('E0602', 61)) self.assertFalse(linter.is_message_enabled('E0602', 62)) self.assertTrue(linter.is_message_enabled('E0602', 64)) self.assertTrue(linter.is_message_enabled('E0602', 66)) # meth7 self.assertFalse(linter.is_message_enabled('E1101', 70)) self.assertTrue(linter.is_message_enabled('E1101', 72)) self.assertTrue(linter.is_message_enabled('E1101', 75)) self.assertTrue(linter.is_message_enabled('E1101', 77)) fs = linter.file_state self.assertEqual(17, fs._suppression_mapping['W0613', 18]) self.assertEqual(30, fs._suppression_mapping['E1101', 33]) self.assertTrue(('E1101', 46) not in fs._suppression_mapping) self.assertEqual(1, fs._suppression_mapping['C0302', 18]) self.assertEqual(1, fs._suppression_mapping['C0302', 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, fs._suppression_mapping['E1101', 108]) self.assertEqual(109, fs._suppression_mapping['E1101', 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.disable('unreachable', scope='package') linter.disable('dangerous-default-value', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertFalse(linter.is_message_enabled('W0102', 1)) self.assertFalse( linter.is_message_enabled('dangerous-default-value', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.enable('unreachable', scope='package') linter.enable('dangerous-default-value', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102', 1)) self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option('output-format', 'text') self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter') def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0234') self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0234')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('non-iterator-returned')) def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0234')) self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0234')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('non-iterator-returned')) def test_enable_checkers(self): self.linter.disable('design') self.assertFalse( 'design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue( 'design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set( ('design', 'format', 'metrics', 'miscellaneous', 'similarities')) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option('disable', 'RP0801') self.linter.set_option('disable', 'R0801') self.assertFalse( 'similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ('design', 'metrics', 'similarities'): self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual( ['C: 1: Line too long (1/2)', 'C: 2: Line too long (3/4)'], self.linter.reporter.messages) def test_addmessage_invalid(self): self.linter.set_reporter(TestReporter()) self.linter.open() self.linter.set_current_module('0123') with self.assertRaises(InvalidMessageError) as cm: self.linter.add_message('line-too-long', args=(1, 2)) self.assertEqual(str(cm.exception), "Message C0301 must provide line, got None") with self.assertRaises(InvalidMessageError) as cm: self.linter.add_message('line-too-long', line=2, node='fake_node', args=(1, 2)) self.assertEqual( str(cm.exception), "Message C0301 must only provide line, got line=2, node=fake_node") with self.assertRaises(InvalidMessageError) as cm: self.linter.add_message('C0321') self.assertEqual(str(cm.exception), "Message C0321 must provide Node, got None") def test_init_hooks_called_before_load_plugins(self): self.assertRaises(RuntimeError, Run, [ '--load-plugins', 'unexistant', '--init-hook', 'raise RuntimeError' ]) self.assertRaises(RuntimeError, Run, [ '--init-hook', 'raise RuntimeError', '--load-plugins', 'unexistant' ]) def test_analyze_explicit_script(self): self.linter.set_reporter(TestReporter()) self.linter.check( os.path.join(os.path.dirname(__file__), 'data', 'ascript')) self.assertEqual(['C: 2: Line too long (175/100)'], self.linter.reporter.messages) def test_python3_checker_disabled(self): checker_names = [c.name for c in self.linter.prepare_checkers()] self.assertNotIn('python3', checker_names) self.linter.set_option('enable', 'python3') checker_names = [c.name for c in self.linter.prepare_checkers()] self.assertIn('python3', checker_names) def test_full_documentation(self): out = six.StringIO() self.linter.print_full_documentation(out) output = out.getvalue() # A few spot checks only for re_str in [ # autogenerated text "^Pylint global options and switches$", "Verbatim name of the checker is ``python3``", # messages "^:old-octal-literal \(E1608\):", # options "^:dummy-variables-rgx:", ]: regexp = re.compile(re_str, re.MULTILINE) self.assertRegexpMatches(output, regexp)
class Runner(): """ Run and control the checking process. """ outputStream = None linter = None allowOptions = None # Customized checkers. checkers = ("header.HeaderChecker", "names.TwistedNamesChecker", "pycodestyleformat.PyCodeStyleChecker", "docstring.DocstringChecker", "formattingoperation.FormattingOperationChecker", "comment.CommentChecker", "testclassname.TestClassNameChecker") allowedMessagesFromPylint = ("F0001", "C0103", "C0301", "W0311", "W0312") diffOption = None errorResultRead = "Error: Failed to read result file '%s'.\n" prefixModuleName = "************* Module " regexLineStart = "^[WCEFR]\d{4}\:" def __init__(self): """ Initialize C{PyLinter} object, and load configuration file. """ self.allowOptions = True self.linter = PyLinter(self._makeOptions()) # register standard checkers. self.linter.load_default_plugins() # read configuration. pathConfig = os.path.join(twistedchecker.abspath, "configuration", "pylintrc") self.linter.read_config_file(pathConfig) # now we can load file config and command line, plugins (which can # provide options) have been registered. self.linter.load_config_file() allowedMessages = self.registerCheckers() # disable messages disabledMessages = set( self.linter.cfgfile_parser.get("TWISTEDCHECKER", "disable").replace(" ", "").split(",")) if disabledMessages != {""}: for msg in disabledMessages: self.linter.disable(msg) allowedMessages -= disabledMessages # set default output stream to stdout self.setOutput(sys.stdout) # set default reporter to limited reporter self.setReporter(LimitedReporter(allowedMessages)) def _makeOptions(self): """ Return options for twistedchecker. """ return ( ("diff", { "type": "string", "metavar": "<result-file>", "help": "Set comparing result file to automatically " "generate a diff." }), ('pep8', { 'type': 'yn', 'metavar': '<y_or_n>', 'default': False, 'help': 'Show pep8 warnings.' }), ('strict-epydoc', { 'type': 'yn', 'metavar': '<y_or_n>', 'default': False, 'help': "Check '@type' and '@rtype' in epydoc." }), ) def setOutput(self, stream): """ Set the stream to output result of checking. @param stream: output stream, defaultly it should be stdout """ self.outputStream = stream sys.stdout = stream def setReporter(self, reporter): """ Set the reporter of pylint. @param reporter: reporter used to show messages """ self.linter.set_reporter(reporter) def displayHelp(self): """ Output help message of twistedchecker. """ self.outputStream.write(self.linter.help()) sys.exit(32) def registerCheckers(self): """ Register all checkers of TwistedChecker to C{PyLinter}. @return: a list of allowed messages """ # We patch the default pylint format checker. patch_pylint_format.patch() # register checkers allowedMessages = list(self.allowedMessagesFromPylint) for strChecker in self.checkers: modname, classname = strChecker.split(".") strModule = "twistedchecker.checkers.%s" % modname checker = getattr( __import__(strModule, fromlist=["twistedchecker.checkers"]), classname) instanceChecker = checker(self.linter) allowedMessages += list(instanceChecker.msgs.keys()) self.linter.register_checker(instanceChecker) self.restrictCheckers(allowedMessages) return set(allowedMessages) def unregisterChecker(self, checker): """ Remove a checker from the list of registered checkers. @param checker: the checker to remove """ self.linter._checkers[checker.name].remove(checker) if checker in self.linter._reports: del self.linter._reports[checker] if checker in self.linter.options_providers: self.linter.options_providers.remove(checker) def findUselessCheckers(self, allowedMessages): """ Find checkers which generate no allowed messages. @param allowedMessages: allowed messages @return: useless checkers, remove them from pylint """ uselessCheckers = [] for checkerName in self.linter._checkers: for checker in list(self.linter._checkers[checkerName]): messagesOfChecker = set(checker.msgs) if not messagesOfChecker.intersection(allowedMessages): uselessCheckers.append(checker) return uselessCheckers def restrictCheckers(self, allowedMessages): """ Unregister useless checkers to speed up twistedchecker. @param allowedMessages: output messages allowed in twistedchecker """ uselessCheckers = self.findUselessCheckers(allowedMessages) # Unregister these checkers for checker in uselessCheckers: self.unregisterChecker(checker) def getCheckerByName(self, checkerType): """ Get checker by given name. @checkerType: type of the checker """ for checker in sum(list(self.linter._checkers.values()), []): if isinstance(checker, checkerType): return checker return None def allowPatternsForNameChecking(self, patternsFunc, patternsClass): """ Allow name exceptions by given patterns. @param patternsFunc: patterns of special function names @param patternsClass: patterns of special class names """ cfgParser = self.linter.cfgfile_parser nameChecker = self.getCheckerByName(NameChecker) if not nameChecker: return if patternsFunc: regexFuncAdd = "|((%s).+)$" % "|".join(patternsFunc) else: regexFuncAdd = "" if patternsClass: regexClassAdd = "|((%s).+)$" % "|".join(patternsClass) else: regexClassAdd = "" # Modify regex for function, method and class name. regexMethod = cfgParser.get("BASIC", "method-rgx") + regexFuncAdd regexFunction = cfgParser.get("BASIC", "function-rgx") + regexFuncAdd regexClass = cfgParser.get("BASIC", "class-rgx") + regexClassAdd # Save to config parser. cfgParser.set("BASIC", "method-rgx", regexMethod) cfgParser.set("BASIC", "function-rgx", regexFunction) cfgParser.set("BASIC", "class-rgx", regexClass) # Save to name checker. nameChecker.config.method_rgx = re.compile(regexMethod) nameChecker.config.function_rgx = re.compile(regexFunction) nameChecker.config.class_rgx = re.compile(regexClass) def getPathList(self, filesOrModules): """ Transform a list of modules to path. @param filesOrModules: a list of modules (may be foo/bar.py or foo.bar) """ pathList = [] for fileOrMod in filesOrModules: if not os.path.exists(fileOrMod): # May be given module is not not a path, # then transform it to a path. try: filepath = file_from_modpath(fileOrMod.split('.')) except (ImportError, SyntaxError): # Could not load this module. continue if not os.path.exists(filepath): # Could not find this module in file system. continue if os.path.basename(filepath) == "__init__.py": filepath = os.path.dirname(filepath) else: filepath = fileOrMod pathList.append(filepath) return pathList def setNameExceptions(self, filesOrModules): """ Find name exceptions in codes and allow them to be ignored in checking. @param filesOrModules: a list of modules (may be foo/bar.py or foo.bar) """ pathList = self.getPathList(filesOrModules) for path in pathList: patternsFunc, patternsClass = findAllExceptions(path) self.allowPatternsForNameChecking(patternsFunc, patternsClass) def run(self, args): """ Setup the environment, and run pylint. @param args: arguments will be passed to pylint @type args: list of string """ # set output stream. if self.outputStream: self.linter.reporter.set_output(self.outputStream) try: args = self.linter.load_command_line_configuration(args) except SystemExit as exc: if exc.code == 2: # bad options exc.code = 32 raise if not args: self.displayHelp() # Check for 'strict-epydoc' option. if self.allowOptions and not self.linter.option_value("strict-epydoc"): for msg in ["W9203", "W9205"]: self.linter.disable(msg) # insert current working directory to the python path to have a correct # behaviour. sys.path.insert(0, os.getcwd()) # set exceptions for name checking. self.setNameExceptions(args) # check for diff option. self.diffOption = self.linter.option_value("diff") if self.diffOption: self.prepareDiff() # check codes. self.linter.check(args) # show diff of warnings if diff option on. if self.diffOption: diffCount = self.showDiffResults() exitCode = 1 if diffCount else 0 sys.exit(exitCode) sys.exit(self.linter.msg_status) def prepareDiff(self): """ Prepare to run the checker and get diff results. """ self.streamForDiff = NativeStringIO() self.linter.reporter.set_output(self.streamForDiff) def showDiffResults(self): """ Show results when diff option on. """ try: oldWarnings = self.parseWarnings(self._readDiffFile()) except: sys.stderr.write(self.errorResultRead % self.diffOption) return 1 newWarnings = self.parseWarnings(self.streamForDiff.getvalue()) diffWarnings = self.generateDiff(oldWarnings, newWarnings) if diffWarnings: diffResult = self.formatWarnings(diffWarnings) self.outputStream.write(diffResult + "\n") return len(diffWarnings) else: return 0 def _readDiffFile(self): """ Read content of diff file. This is here to help with testing. @return: File content. @rtype: c{str} """ with open(self.diffOption) as f: content = f.read() return content def generateDiff(self, oldWarnings, newWarnings): """ Generate diff between given two lists of warnings. @param oldWarnings: parsed old warnings @param newWarnings: parsed new warnings @return: a dict object of diff """ diffWarnings = {} for modulename in newWarnings: diffInModule = (newWarnings[modulename] - oldWarnings.get(modulename, set())) if diffInModule: diffWarnings[modulename] = diffInModule return diffWarnings def parseWarnings(self, result): """ Transform result in string to a dict object. @param result: a list of warnings in string @return: a dict of warnings """ warnings = {} currentModule = None warningsCurrentModule = [] for line in result.splitlines(): if line.startswith(self.prefixModuleName): # Save results for previous module if currentModule: warnings[currentModule] = set(warningsCurrentModule) # Initial results for current module moduleName = line.replace(self.prefixModuleName, "") currentModule = moduleName warningsCurrentModule = [] elif re.search(self.regexLineStart, line): warningsCurrentModule.append(line) else: if warningsCurrentModule: warningsCurrentModule[-1] += "\n" + line # Save warnings for last module if currentModule: warnings[currentModule] = set(warningsCurrentModule) return warnings def formatWarnings(self, warnings): """ Format warnings to a list of results. @param warnings: a dict of warnings produced by parseWarnings @return: a list of warnings in string """ lines = [] for modulename in sorted(warnings): lines.append(self.prefixModuleName + modulename) lines.extend( sorted(warnings[modulename], key=lambda x: x.split(":")[1])) return "\n".join(lines)
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) def test_message_help(self): msg = self.linter.get_message_help('F0001', checkerref=True) expected = ':F0001:\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') def test_enable_message(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assert_(linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assert_(not linter.is_message_enabled('W0101')) self.assert_(not linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assert_(not linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assert_(linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.linter linter.open() linter.set_current_module('toto') self.assert_(linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('C0121')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assert_(not linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('C0121')) self.assert_(not linter.is_message_enabled('C0121', line=1)) linter.set_current_module('tutu') self.assert_(not linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('C0121')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assert_(linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('C0121')) self.assert_(linter.is_message_enabled('C0121', line=1)) def test_enable_message_block(self): linter = self.linter linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astng = linter.get_astng(filepath, 'func_block_disable_msg') linter.process_module(astng) orig_state = linter._module_msgs_state.copy() linter._module_msgs_state = {} linter.collect_block_lines(astng, orig_state) # global (module level) self.assert_(linter.is_message_enabled('W0613')) self.assert_(linter.is_message_enabled('E1101')) # meth1 self.assert_(linter.is_message_enabled('W0613', 13)) # meth2 self.assert_(not linter.is_message_enabled('W0613', 18)) # meth3 self.assert_(not linter.is_message_enabled('E1101', 24)) self.assert_(linter.is_message_enabled('E1101', 26)) # meth4 self.assert_(not linter.is_message_enabled('E1101', 32)) self.assert_(linter.is_message_enabled('E1101', 36)) # meth5 self.assert_(not linter.is_message_enabled('E1101', 42)) self.assert_(not linter.is_message_enabled('E1101', 43)) self.assert_(linter.is_message_enabled('E1101', 46)) self.assert_(not linter.is_message_enabled('E1101', 49)) self.assert_(not linter.is_message_enabled('E1101', 51)) # meth6 self.assert_(not linter.is_message_enabled('E1101', 57)) self.assert_(linter.is_message_enabled('E1101', 61)) self.assert_(not linter.is_message_enabled('E1101', 64)) self.assert_(not linter.is_message_enabled('E1101', 66)) self.assert_(linter.is_message_enabled('E0602', 57)) self.assert_(linter.is_message_enabled('E0602', 61)) self.assert_(not linter.is_message_enabled('E0602', 62)) self.assert_(linter.is_message_enabled('E0602', 64)) self.assert_(linter.is_message_enabled('E0602', 66)) # meth7 self.assert_(not linter.is_message_enabled('E1101', 70)) self.assert_(linter.is_message_enabled('E1101', 72)) self.assert_(linter.is_message_enabled('E1101', 75)) self.assert_(linter.is_message_enabled('E1101', 77)) def test_list_messages(self): sys.stdout = StringIO() try: # just invoke it, don't check the output self.linter.list_messages() finally: sys.stdout = sys.__stdout__ def test_lint_ext_module_with_file_output(self): if sys.version_info < (3, 0): strio = 'StringIO' else: strio = 'io' self.linter.config.files_output = True pylint_strio = 'pylint_%s.txt' % strio try: self.linter.check(strio) self.assert_(os.path.exists(pylint_strio)) self.assert_(os.path.exists('pylint_global.txt')) finally: try: os.remove(pylint_strio) os.remove('pylint_global.txt') except: pass def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0142') self.assert_(not linter.is_message_enabled('C0111')) self.assert_(not linter.is_message_enabled('W0142')) self.assert_(linter.is_message_enabled('W0113')) def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0142') ) self.assert_(not linter.is_message_enabled('C0111')) self.assert_(not linter.is_message_enabled('W0142')) self.assert_(linter.is_message_enabled('W0113')) def test_enable_checkers(self): self.linter.disable('design') self.assertFalse('design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue('design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = tuple(c.name for c in checkers) should_not = ('design', 'format', 'imports', 'metrics', 'miscellaneous', 'similarities') self.assertFalse(any(name in checker_names for name in should_not)) def test_disable_similar(self): # XXX we have to disable them both, that's no good self.linter.set_option('reports', False) self.linter.set_option('disable', 'R0801') self.assertFalse('similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) # FIXME should it be necessary to explicitly desactivate failures ? self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] should_not = ('design', 'metrics', 'similarities') rest = [name for name in checker_names if name in should_not] self.assertListEqual(rest, []) self.linter.set_option('disable', 'R,C,W,F') checker_names = [c.name for c in self.linter.prepare_checkers()] should_not += ('format', 'imports') rest = [name for name in checker_names if name in should_not] self.assertListEqual(rest, [])
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) def init_linter(self): linter = self.linter linter.open() linter.set_current_module('toto') linter.file_state = FileState('toto') return linter def test_enable_message(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertFalse(linter.is_message_enabled('C0121', line=1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0121')) self.assertTrue(linter.is_message_enabled('C0121', line=1)) def test_message_state_scope(self): linter = self.init_linter() fs = linter.file_state linter.disable('C0121') self.assertEqual(MSG_STATE_SCOPE_CONFIG, fs._message_state_scope('C0121')) linter.disable('W0101', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, fs._message_state_scope('C0121')) self.assertEqual(MSG_STATE_SCOPE_MODULE, fs._message_state_scope('W0101', 3)) linter.enable('W0102', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, fs._message_state_scope('W0102', 3)) def test_enable_message_block(self): linter = self.init_linter() linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astroid = linter.get_ast(filepath, 'func_block_disable_msg') linter.process_tokens(tokenize_module(astroid)) fs = linter.file_state fs.collect_block_lines(linter.msgs_store, astroid) # global (module level) self.assertTrue(linter.is_message_enabled('W0613')) self.assertTrue(linter.is_message_enabled('E1101')) # meth1 self.assertTrue(linter.is_message_enabled('W0613', 13)) # meth2 self.assertFalse(linter.is_message_enabled('W0613', 18)) # meth3 self.assertFalse(linter.is_message_enabled('E1101', 24)) self.assertTrue(linter.is_message_enabled('E1101', 26)) # meth4 self.assertFalse(linter.is_message_enabled('E1101', 32)) self.assertTrue(linter.is_message_enabled('E1101', 36)) # meth5 self.assertFalse(linter.is_message_enabled('E1101', 42)) self.assertFalse(linter.is_message_enabled('E1101', 43)) self.assertTrue(linter.is_message_enabled('E1101', 46)) self.assertFalse(linter.is_message_enabled('E1101', 49)) self.assertFalse(linter.is_message_enabled('E1101', 51)) # meth6 self.assertFalse(linter.is_message_enabled('E1101', 57)) self.assertTrue(linter.is_message_enabled('E1101', 61)) self.assertFalse(linter.is_message_enabled('E1101', 64)) self.assertFalse(linter.is_message_enabled('E1101', 66)) self.assertTrue(linter.is_message_enabled('E0602', 57)) self.assertTrue(linter.is_message_enabled('E0602', 61)) self.assertFalse(linter.is_message_enabled('E0602', 62)) self.assertTrue(linter.is_message_enabled('E0602', 64)) self.assertTrue(linter.is_message_enabled('E0602', 66)) # meth7 self.assertFalse(linter.is_message_enabled('E1101', 70)) self.assertTrue(linter.is_message_enabled('E1101', 72)) self.assertTrue(linter.is_message_enabled('E1101', 75)) self.assertTrue(linter.is_message_enabled('E1101', 77)) fs = linter.file_state self.assertEqual(17, fs._suppression_mapping['W0613', 18]) self.assertEqual(30, fs._suppression_mapping['E1101', 33]) self.assertTrue(('E1101', 46) not in fs._suppression_mapping) self.assertEqual(1, fs._suppression_mapping['C0302', 18]) self.assertEqual(1, fs._suppression_mapping['C0302', 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, fs._suppression_mapping['E1101', 108]) self.assertEqual(109, fs._suppression_mapping['E1101', 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.disable('unreachable', scope='package') linter.disable('dangerous-default-value', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertFalse(linter.is_message_enabled('W0102', 1)) self.assertFalse(linter.is_message_enabled('dangerous-default-value', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.enable('unreachable', scope='package') linter.enable('dangerous-default-value', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102', 1)) self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) def test_lint_ext_module_with_file_output(self): self.linter.set_reporter(text.TextReporter()) if sys.version_info < (3, 0): strio = 'StringIO' else: strio = 'io' self.linter.config.files_output = True pylint_strio = 'pylint_%s.txt' % strio try: self.linter.check(strio) self.assertTrue(os.path.exists(pylint_strio)) self.assertTrue(os.path.exists('pylint_global.txt')) finally: try: os.remove(pylint_strio) os.remove('pylint_global.txt') except: pass def test_lint_should_analyze_file(self): self.linter.set_reporter(text.TextReporter()) self.linter.config.files_output = True self.linter.should_analyze_file = lambda *args: False self.linter.check('logilab') self.assertTrue(os.path.exists('pylint_logilab.txt')) self.assertFalse(os.path.exists('pylint_logilab_common.txt')) def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option('output-format', 'text') self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter') def test_report_output_format_custom(self): this_module = sys.modules[__name__] class TestReporter(object): pass this_module.TestReporter = TestReporter class_name = ".".join((this_module.__name__, 'TestReporter')) self.linter.set_option('output-format', class_name) self.assertEqual(self.linter.reporter.__class__.__name__, 'TestReporter') def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0142') self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0142') ) self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0142')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('star-args')) # no name for W0113 def test_enable_checkers(self): self.linter.disable('design') self.assertFalse('design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue('design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set(('design', 'format', 'imports', 'metrics', 'miscellaneous', 'similarities')) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option('disable', 'RP0801') self.linter.set_option('disable', 'R0801') self.assertFalse('similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ('design', 'metrics', 'similarities', 'imports'): # as a Fatal message that should be ignored self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual( ['C: 1: Line too long (1/2)', 'C: 2: Line too long (3/4)'], self.linter.reporter.messages) def test_init_hooks_called_before_load_plugins(self): self.assertRaises(RuntimeError, Run, ['--load-plugins', 'unexistant', '--init-hook', 'raise RuntimeError']) self.assertRaises(RuntimeError, Run, ['--init-hook', 'raise RuntimeError', '--load-plugins', 'unexistant']) def test_analyze_explicit_script(self): self.linter.set_reporter(TestReporter()) self.linter.check(self.datapath('ascript')) self.assertEqual( ['C: 2: Line too long (175/80)'], self.linter.reporter.messages)
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable("I") self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) def init_linter(self): linter = self.linter linter.open() linter.set_current_module("toto") linter.file_state = FileState("toto") return linter def test_enable_message(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled("W0101")) self.assertTrue(linter.is_message_enabled("W0102")) linter.disable("W0101", scope="package") linter.disable("W0102", scope="module", line=1) self.assertFalse(linter.is_message_enabled("W0101")) self.assertFalse(linter.is_message_enabled("W0102", 1)) linter.set_current_module("tutu") self.assertFalse(linter.is_message_enabled("W0101")) self.assertTrue(linter.is_message_enabled("W0102")) linter.enable("W0101", scope="package") linter.enable("W0102", scope="module", line=1) self.assertTrue(linter.is_message_enabled("W0101")) self.assertTrue(linter.is_message_enabled("W0102", 1)) def test_enable_message_category(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled("W0101")) self.assertTrue(linter.is_message_enabled("C0121")) linter.disable("W", scope="package") linter.disable("C", scope="module", line=1) self.assertFalse(linter.is_message_enabled("W0101")) self.assertTrue(linter.is_message_enabled("C0121")) self.assertFalse(linter.is_message_enabled("C0121", line=1)) linter.set_current_module("tutu") self.assertFalse(linter.is_message_enabled("W0101")) self.assertTrue(linter.is_message_enabled("C0121")) linter.enable("W", scope="package") linter.enable("C", scope="module", line=1) self.assertTrue(linter.is_message_enabled("W0101")) self.assertTrue(linter.is_message_enabled("C0121")) self.assertTrue(linter.is_message_enabled("C0121", line=1)) def test_message_state_scope(self): class FakeConfig(object): confidence = ["HIGH"] linter = self.init_linter() linter.disable("C0121") self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope("C0121")) linter.disable("W0101", scope="module", line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope("C0121")) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope("W0101", 3)) linter.enable("W0102", scope="module", line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope("W0102", 3)) linter.config = FakeConfig() self.assertEqual( MSG_STATE_CONFIDENCE, linter.get_message_state_scope("this-is-bad", confidence=interfaces.INFERENCE) ) def test_enable_message_block(self): linter = self.init_linter() linter.open() filepath = join(INPUTDIR, "func_block_disable_msg.py") linter.set_current_module("func_block_disable_msg") astroid = linter.get_ast(filepath, "func_block_disable_msg") linter.process_tokens(tokenize_module(astroid)) fs = linter.file_state fs.collect_block_lines(linter.msgs_store, astroid) # global (module level) self.assertTrue(linter.is_message_enabled("W0613")) self.assertTrue(linter.is_message_enabled("E1101")) # meth1 self.assertTrue(linter.is_message_enabled("W0613", 13)) # meth2 self.assertFalse(linter.is_message_enabled("W0613", 18)) # meth3 self.assertFalse(linter.is_message_enabled("E1101", 24)) self.assertTrue(linter.is_message_enabled("E1101", 26)) # meth4 self.assertFalse(linter.is_message_enabled("E1101", 32)) self.assertTrue(linter.is_message_enabled("E1101", 36)) # meth5 self.assertFalse(linter.is_message_enabled("E1101", 42)) self.assertFalse(linter.is_message_enabled("E1101", 43)) self.assertTrue(linter.is_message_enabled("E1101", 46)) self.assertFalse(linter.is_message_enabled("E1101", 49)) self.assertFalse(linter.is_message_enabled("E1101", 51)) # meth6 self.assertFalse(linter.is_message_enabled("E1101", 57)) self.assertTrue(linter.is_message_enabled("E1101", 61)) self.assertFalse(linter.is_message_enabled("E1101", 64)) self.assertFalse(linter.is_message_enabled("E1101", 66)) self.assertTrue(linter.is_message_enabled("E0602", 57)) self.assertTrue(linter.is_message_enabled("E0602", 61)) self.assertFalse(linter.is_message_enabled("E0602", 62)) self.assertTrue(linter.is_message_enabled("E0602", 64)) self.assertTrue(linter.is_message_enabled("E0602", 66)) # meth7 self.assertFalse(linter.is_message_enabled("E1101", 70)) self.assertTrue(linter.is_message_enabled("E1101", 72)) self.assertTrue(linter.is_message_enabled("E1101", 75)) self.assertTrue(linter.is_message_enabled("E1101", 77)) fs = linter.file_state self.assertEqual(17, fs._suppression_mapping["W0613", 18]) self.assertEqual(30, fs._suppression_mapping["E1101", 33]) self.assertTrue(("E1101", 46) not in fs._suppression_mapping) self.assertEqual(1, fs._suppression_mapping["C0302", 18]) self.assertEqual(1, fs._suppression_mapping["C0302", 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, fs._suppression_mapping["E1101", 108]) self.assertEqual(109, fs._suppression_mapping["E1101", 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.init_linter() self.assertTrue(linter.is_message_enabled("W0101")) self.assertTrue(linter.is_message_enabled("unreachable")) self.assertTrue(linter.is_message_enabled("W0102")) self.assertTrue(linter.is_message_enabled("dangerous-default-value")) linter.disable("unreachable", scope="package") linter.disable("dangerous-default-value", scope="module", line=1) self.assertFalse(linter.is_message_enabled("W0101")) self.assertFalse(linter.is_message_enabled("unreachable")) self.assertFalse(linter.is_message_enabled("W0102", 1)) self.assertFalse(linter.is_message_enabled("dangerous-default-value", 1)) linter.set_current_module("tutu") self.assertFalse(linter.is_message_enabled("W0101")) self.assertFalse(linter.is_message_enabled("unreachable")) self.assertTrue(linter.is_message_enabled("W0102")) self.assertTrue(linter.is_message_enabled("dangerous-default-value")) linter.enable("unreachable", scope="package") linter.enable("dangerous-default-value", scope="module", line=1) self.assertTrue(linter.is_message_enabled("W0101")) self.assertTrue(linter.is_message_enabled("unreachable")) self.assertTrue(linter.is_message_enabled("W0102", 1)) self.assertTrue(linter.is_message_enabled("dangerous-default-value", 1)) def test_lint_ext_module_with_file_output(self): self.linter.set_reporter(text.TextReporter()) if sys.version_info < (3, 0): strio = "StringIO" else: strio = "io" self.linter.config.files_output = True pylint_strio = "pylint_%s.txt" % strio files = [pylint_strio, "pylint_global.txt"] for file in files: self.addCleanup(remove, file) self.linter.check(strio) self.linter.generate_reports() for f in files: self.assertTrue(os.path.exists(f)) def test_lint_should_analyze_file(self): self.linter.set_reporter(text.TextReporter()) self.linter.config.files_output = True self.linter.should_analyze_file = lambda *args: False self.addCleanup(remove, "pylint_logilab.txt") self.linter.check("logilab") self.assertTrue(os.path.exists("pylint_logilab.txt")) self.assertFalse(os.path.exists("pylint_logilab_common.txt")) def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled("RP0001"), True) self.linter.disable("RP0001") self.assertEqual(self.linter.report_is_enabled("RP0001"), False) self.linter.enable("RP0001") self.assertEqual(self.linter.report_is_enabled("RP0001"), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option("output-format", "text") self.assertEqual(self.linter.reporter.__class__.__name__, "TextReporter") def test_report_output_format_custom(self): this_module = sys.modules[__name__] class TestReporter(object): pass this_module.TestReporter = TestReporter class_name = ".".join((this_module.__name__, "TestReporter")) self.linter.set_option("output-format", class_name) self.assertEqual(self.linter.reporter.__class__.__name__, "TestReporter") def test_set_option_1(self): linter = self.linter linter.set_option("disable", "C0111,W0142") self.assertFalse(linter.is_message_enabled("C0111")) self.assertFalse(linter.is_message_enabled("W0142")) self.assertTrue(linter.is_message_enabled("W0113")) self.assertFalse(linter.is_message_enabled("missing-docstring")) self.assertFalse(linter.is_message_enabled("star-args")) # no name for W0113 def test_set_option_2(self): linter = self.linter linter.set_option("disable", ("C0111", "W0142")) self.assertFalse(linter.is_message_enabled("C0111")) self.assertFalse(linter.is_message_enabled("W0142")) self.assertTrue(linter.is_message_enabled("W0113")) self.assertFalse(linter.is_message_enabled("missing-docstring")) self.assertFalse(linter.is_message_enabled("star-args")) # no name for W0113 def test_enable_checkers(self): self.linter.disable("design") self.assertFalse("design" in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable("design") self.assertTrue("design" in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set(("design", "format", "imports", "metrics", "miscellaneous", "similarities")) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option("disable", "RP0801") self.linter.set_option("disable", "R0801") self.assertFalse("similarities" in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option("reports", False) self.linter.set_option("disable", "R,C,W") checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ("design", "metrics", "similarities", "imports"): # as a Fatal message that should be ignored self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual(["C: 1: Line too long (1/2)", "C: 2: Line too long (3/4)"], self.linter.reporter.messages) def test_init_hooks_called_before_load_plugins(self): self.assertRaises(RuntimeError, Run, ["--load-plugins", "unexistant", "--init-hook", "raise RuntimeError"]) self.assertRaises(RuntimeError, Run, ["--init-hook", "raise RuntimeError", "--load-plugins", "unexistant"]) def test_analyze_explicit_script(self): self.linter.set_reporter(TestReporter()) self.linter.check(os.path.join(os.path.dirname(__file__), "data", "ascript")) self.assertEqual(["C: 2: Line too long (175/100)"], self.linter.reporter.messages) def test_html_reporter_missing_files(self): output = six.StringIO() self.linter.set_reporter(html.HTMLReporter(output)) self.linter.set_option("output-format", "html") self.linter.check("troppoptop.py") self.linter.generate_reports() value = output.getvalue() self.assertIn("troppoptop.py", value) self.assertIn("fatal", value) def test_python3_checker_disabled(self): checker_names = [c.name for c in self.linter.prepare_checkers()] self.assertNotIn("python3", checker_names) self.linter.set_option("enable", "python3") checker_names = [c.name for c in self.linter.prepare_checkers()] self.assertIn("python3", checker_names)
import sys import os from os.path import abspath, dirname, join from logilab.common.testlib import TestCase, unittest_main from utils import TestReporter from pylint.lint import PyLinter from pylint import checkers test_reporter = TestReporter() linter = PyLinter() linter.set_reporter(test_reporter) linter.disable('I') linter.config.persistent = 0 checkers.initialize(linter) REGR_DATA = join(dirname(abspath(__file__)), 'regrtest_data') sys.path.insert(1, REGR_DATA) class NonRegrTC(TestCase): def setUp(self): """call reporter.finalize() to cleanup pending messages if a test finished badly """ linter.reporter.finalize() def test_package___path___manipulation(self): linter.check('package.__init__')
class PyLinterTC(unittest.TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable('I') self.linter.config.persistent = 0 # register checkers checkers.initialize(self.linter) self.linter.set_reporter(TestReporter()) def init_linter(self): linter = self.linter linter.open() linter.set_current_module('toto') linter.file_state = FileState('toto') return linter def test_pylint_visit_method_taken_in_account(self): class CustomChecker(checkers.BaseChecker): __implements__ = interfaces.IAstroidChecker name = 'custom' msgs = {'W9999': ('', 'custom', '')} @check_messages('custom') def visit_class(self, _): pass self.linter.register_checker(CustomChecker(self.linter)) self.linter.open() out = six.moves.StringIO() self.linter.set_reporter(text.TextReporter(out)) self.linter.check('abc') def test_enable_message(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.disable('W0101', scope='package') linter.disable('W0102', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('W0102', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102')) linter.enable('W0101', scope='package') linter.enable('W0102', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('W0102', 1)) def test_enable_message_category(self): linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) linter.disable('W', scope='package') linter.disable('C', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) self.assertFalse(linter.is_message_enabled('C0202', line=1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) linter.enable('W', scope='package') linter.enable('C', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('C0202')) self.assertTrue(linter.is_message_enabled('C0202', line=1)) def test_message_state_scope(self): class FakeConfig(object): confidence = ['HIGH'] linter = self.init_linter() linter.disable('C0202') self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0202')) linter.disable('W0101', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_CONFIG, linter.get_message_state_scope('C0202')) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0101', 3)) linter.enable('W0102', scope='module', line=3) self.assertEqual(MSG_STATE_SCOPE_MODULE, linter.get_message_state_scope('W0102', 3)) linter.config = FakeConfig() self.assertEqual( MSG_STATE_CONFIDENCE, linter.get_message_state_scope('this-is-bad', confidence=interfaces.INFERENCE)) def test_enable_message_block(self): linter = self.init_linter() linter.open() filepath = join(INPUTDIR, 'func_block_disable_msg.py') linter.set_current_module('func_block_disable_msg') astroid = linter.get_ast(filepath, 'func_block_disable_msg') linter.process_tokens(tokenize_module(astroid)) fs = linter.file_state fs.collect_block_lines(linter.msgs_store, astroid) # global (module level) self.assertTrue(linter.is_message_enabled('W0613')) self.assertTrue(linter.is_message_enabled('E1101')) # meth1 self.assertTrue(linter.is_message_enabled('W0613', 13)) # meth2 self.assertFalse(linter.is_message_enabled('W0613', 18)) # meth3 self.assertFalse(linter.is_message_enabled('E1101', 24)) self.assertTrue(linter.is_message_enabled('E1101', 26)) # meth4 self.assertFalse(linter.is_message_enabled('E1101', 32)) self.assertTrue(linter.is_message_enabled('E1101', 36)) # meth5 self.assertFalse(linter.is_message_enabled('E1101', 42)) self.assertFalse(linter.is_message_enabled('E1101', 43)) self.assertTrue(linter.is_message_enabled('E1101', 46)) self.assertFalse(linter.is_message_enabled('E1101', 49)) self.assertFalse(linter.is_message_enabled('E1101', 51)) # meth6 self.assertFalse(linter.is_message_enabled('E1101', 57)) self.assertTrue(linter.is_message_enabled('E1101', 61)) self.assertFalse(linter.is_message_enabled('E1101', 64)) self.assertFalse(linter.is_message_enabled('E1101', 66)) self.assertTrue(linter.is_message_enabled('E0602', 57)) self.assertTrue(linter.is_message_enabled('E0602', 61)) self.assertFalse(linter.is_message_enabled('E0602', 62)) self.assertTrue(linter.is_message_enabled('E0602', 64)) self.assertTrue(linter.is_message_enabled('E0602', 66)) # meth7 self.assertFalse(linter.is_message_enabled('E1101', 70)) self.assertTrue(linter.is_message_enabled('E1101', 72)) self.assertTrue(linter.is_message_enabled('E1101', 75)) self.assertTrue(linter.is_message_enabled('E1101', 77)) fs = linter.file_state self.assertEqual(17, fs._suppression_mapping['W0613', 18]) self.assertEqual(30, fs._suppression_mapping['E1101', 33]) self.assertTrue(('E1101', 46) not in fs._suppression_mapping) self.assertEqual(1, fs._suppression_mapping['C0302', 18]) self.assertEqual(1, fs._suppression_mapping['C0302', 50]) # This is tricky. While the disable in line 106 is disabling # both 108 and 110, this is usually not what the user wanted. # Therefore, we report the closest previous disable comment. self.assertEqual(106, fs._suppression_mapping['E1101', 108]) self.assertEqual(109, fs._suppression_mapping['E1101', 110]) def test_enable_by_symbol(self): """messages can be controlled by symbolic names. The state is consistent across symbols and numbers. """ linter = self.init_linter() self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.disable('unreachable', scope='package') linter.disable('dangerous-default-value', scope='module', line=1) self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertFalse(linter.is_message_enabled('W0102', 1)) self.assertFalse(linter.is_message_enabled('dangerous-default-value', 1)) linter.set_current_module('tutu') self.assertFalse(linter.is_message_enabled('W0101')) self.assertFalse(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102')) self.assertTrue(linter.is_message_enabled('dangerous-default-value')) linter.enable('unreachable', scope='package') linter.enable('dangerous-default-value', scope='module', line=1) self.assertTrue(linter.is_message_enabled('W0101')) self.assertTrue(linter.is_message_enabled('unreachable')) self.assertTrue(linter.is_message_enabled('W0102', 1)) self.assertTrue(linter.is_message_enabled('dangerous-default-value', 1)) def test_enable_report(self): self.assertEqual(self.linter.report_is_enabled('RP0001'), True) self.linter.disable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), False) self.linter.enable('RP0001') self.assertEqual(self.linter.report_is_enabled('RP0001'), True) def test_report_output_format_aliased(self): text.register(self.linter) self.linter.set_option('output-format', 'text') self.assertEqual(self.linter.reporter.__class__.__name__, 'TextReporter') def test_set_option_1(self): linter = self.linter linter.set_option('disable', 'C0111,W0234') self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0234')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('non-iterator-returned')) def test_set_option_2(self): linter = self.linter linter.set_option('disable', ('C0111', 'W0234') ) self.assertFalse(linter.is_message_enabled('C0111')) self.assertFalse(linter.is_message_enabled('W0234')) self.assertTrue(linter.is_message_enabled('W0113')) self.assertFalse(linter.is_message_enabled('missing-docstring')) self.assertFalse(linter.is_message_enabled('non-iterator-returned')) def test_enable_checkers(self): self.linter.disable('design') self.assertFalse('design' in [c.name for c in self.linter.prepare_checkers()]) self.linter.enable('design') self.assertTrue('design' in [c.name for c in self.linter.prepare_checkers()]) def test_errors_only(self): linter = self.linter self.linter.error_mode() checkers = self.linter.prepare_checkers() checker_names = set(c.name for c in checkers) should_not = set(('design', 'format', 'metrics', 'miscellaneous', 'similarities')) self.assertSetEqual(set(), should_not & checker_names) def test_disable_similar(self): self.linter.set_option('disable', 'RP0801') self.linter.set_option('disable', 'R0801') self.assertFalse('similarities' in [c.name for c in self.linter.prepare_checkers()]) def test_disable_alot(self): """check that we disabled a lot of checkers""" self.linter.set_option('reports', False) self.linter.set_option('disable', 'R,C,W') checker_names = [c.name for c in self.linter.prepare_checkers()] for cname in ('design', 'metrics', 'similarities'): self.assertFalse(cname in checker_names, cname) def test_addmessage(self): self.linter.set_reporter(TestReporter()) self.linter.open() 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.assertEqual( ['C: 1: Line too long (1/2)', 'C: 2: Line too long (3/4)'], self.linter.reporter.messages) def test_addmessage_invalid(self): self.linter.set_reporter(TestReporter()) self.linter.open() self.linter.set_current_module('0123') with self.assertRaises(InvalidMessageError) as cm: self.linter.add_message('line-too-long', args=(1,2)) self.assertEqual(str(cm.exception), "Message C0301 must provide line, got None") with self.assertRaises(InvalidMessageError) as cm: self.linter.add_message('line-too-long', line=2, node='fake_node', args=(1, 2)) self.assertEqual(str(cm.exception), "Message C0301 must only provide line, got line=2, node=fake_node") with self.assertRaises(InvalidMessageError) as cm: self.linter.add_message('C0321') self.assertEqual(str(cm.exception), "Message C0321 must provide Node, got None") def test_init_hooks_called_before_load_plugins(self): self.assertRaises(RuntimeError, Run, ['--load-plugins', 'unexistant', '--init-hook', 'raise RuntimeError']) self.assertRaises(RuntimeError, Run, ['--init-hook', 'raise RuntimeError', '--load-plugins', 'unexistant']) def test_analyze_explicit_script(self): self.linter.set_reporter(TestReporter()) self.linter.check(os.path.join(os.path.dirname(__file__), 'data', 'ascript')) self.assertEqual( ['C: 2: Line too long (175/100)'], self.linter.reporter.messages) def test_python3_checker_disabled(self): checker_names = [c.name for c in self.linter.prepare_checkers()] self.assertNotIn('python3', checker_names) self.linter.set_option('enable', 'python3') checker_names = [c.name for c in self.linter.prepare_checkers()] self.assertIn('python3', checker_names) def test_full_documentation(self): out = six.StringIO() self.linter.print_full_documentation(out) output = out.getvalue() # A few spot checks only for re_str in [ # autogenerated text "^Pylint global options and switches$", "Verbatim name of the checker is ``python3``", # messages "^:old-octal-literal \(E1608\):", # options "^:dummy-variables-rgx:", ]: regexp = re.compile(re_str, re.MULTILINE) self.assertRegexpMatches(output, regexp)