def run_linter(self): from pylint.lint import PyLinter from pylint import checkers from os.path import join linter = PyLinter(pylintrc=self.lint_config) # same, but not all pylint versions have load_default_plugins if hasattr(linter, 'load_default_plugins'): linter.load_default_plugins() else: checkers.initialize(linter) linter.read_config_file() linter.load_config_file() if self.packages: self.announce("checking packages", 2) report_fn = "packages_report." + linter.reporter.extension report_fn = join(self.build_base, report_fn) with open(report_fn, "wt") as out: linter.reporter.set_output(out) linter.check(self.packages) self.announce_overview(linter, report_fn) if self.build_scripts: self.announce("checking scripts", 2) report_fn = "scripts_report." + linter.reporter.extension report_fn = join(self.build_base, report_fn) with open(report_fn, "wt") as out: linter.reporter.set_output(out) linter.check(self.build_scripts) self.announce_overview(linter, report_fn)
def process_file(filename): """ Analyze the file with pylint and write the result to a database """ linter = PyLinter() checkers.initialize(linter) linter.read_config_file() linter.quiet = 1 filemods = linter.expand_files((filename, )) if filemods: old_stats = config.load_results(filemods[0].get('basename')) old_score = old_stats.get('global_note', 0.0) linter.check(filename) score = eval(linter.config.evaluation, {}, linter.stats) # Calculate the credit for both scores if score < 0: credit = 2.0 * score elif score < old_score: credit = -1.5 * (old_score - score) elif score < MINIMUM_SCORE: credit = -1.5 * (MINIMUM_SCORE - score) else: credit = score - old_score return score, old_score, credit
def test_analyze_explicit_script(linter: PyLinter) -> None: linter.set_reporter(testutils.GenericTestReporter()) linter.check([os.path.join(DATA_DIR, "ascript")]) assert len(linter.reporter.messages) == 1 assert linter.reporter.messages[0] == Message( msg_id="C0301", symbol="line-too-long", msg="Line too long (175/100)", confidence=interfaces.Confidence( name="UNDEFINED", description="Warning without any associated confidence level.", ), location=MessageLocationTuple( abspath=os.path.join(abspath(dirname(__file__)), "ascript").replace( f"lint{os.path.sep}ascript", f"data{os.path.sep}ascript"), path=f"tests{os.path.sep}data{os.path.sep}ascript", module="data.ascript", obj="", line=2, column=0, end_line=None, end_column=None, ), )
def run(files, reporter=None): if not reporter: reporter = TextReporter() reporter.set_output() old_writeln = reporter.writeln # Shared state. Python closures are -final-, that is not mutable by reference. # However, mutating inner state of the final reference is allowed, so we use a # 1 length array to capture this. success = [True] # If you can believe it, pylint doesn't actually give you any data back on wether a linting # run is successful, it expects you to parse output to determine that :'( # To compensate, we monkey patch writeln, and flag a failure as any linter resulting in # output. def new_writeln(*args, **kwds): success[0] = False return old_writeln(*args, **kwds) reporter.__setattr__("writeln", new_writeln) linter = PyLinter(reporter=reporter) linter.register_checker(ArchimedesDslChecker(linter)) linter.check(files) return success[0]
def test_multiprocessing(jobs: int) -> None: """Check that multiprocessing does not create duplicates.""" # For the bug (#3584) to show up we need more than one file with issues # per process filenames = [ "special_attr_scope_lookup_crash.py", "syntax_error.py", "unused_variable.py", "wildcard.py", "wrong_import_position.py", ] reporter = testutils.GenericTestReporter() linter = PyLinter() linter.config.jobs = jobs linter.config.persistent = 0 linter.open() linter.set_reporter(reporter) try: sys.path.append(os.path.dirname(REGRTEST_DATA_DIR)) linter.check( [os.path.join(REGRTEST_DATA_DIR, fname) for fname in filenames]) finally: sys.path.pop() messages = reporter.messages assert len(messages) == len(set(messages))
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 test_checker_dep_graphs(linter: PyLinter) -> None: linter.set_option("persistent", False) linter.set_option("reports", True) linter.set_option("enable", "imports") linter.set_option("import_graph", "import.dot") linter.set_option("ext_import_graph", "ext_import.dot") linter.set_option("int_import_graph", "int_import.dot") linter.check(["input"]) linter.generate_reports() assert exists("import.dot") assert exists("ext_import.dot") assert exists("int_import.dot")
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 test_pylint_visit_method_taken_in_account(linter: PyLinter) -> None: class CustomChecker(checkers.BaseChecker): name = "custom" msgs = {"W9999": ("", "custom", "")} @only_required_for_messages("custom") def visit_class(self, _): pass linter.register_checker(CustomChecker(linter)) linter.open() out = StringIO() linter.set_reporter(text.TextReporter(out)) linter.check(["abc"])
def check_pylint(self): """ Check using pylint. """ options = self.options.get('pylint', self.file_path).copy() if not options['enabled']: return del options['enabled'] if not self._compiled_tree: # We failed to compile the tree. return from pylint.lint import PyLinter, fix_import_path from pylint.reporters import CollectingReporter linter = PyLinter() linter.load_default_plugins() linter.set_reporter(CollectingReporter()) if options['py3k']: linter.python3_porting_mode() del options['py3k'] rcfile = options.get('rcfile', None) del options['rcfile'] if rcfile: linter.read_config_file(config_file=rcfile) linter.load_config_file() else: linter.load_configuration_from_config(options) # PyLint does its own import and parsing, so we only pass the file # name and the precompiled tree. with fix_import_path(self.file_path): linter.check(self.file_path) for message in linter.reporter.messages: self.message( message.line, '%s:%s %s' % ( message.msg_id, message.symbol, message.msg, ), code=message.msg_id, icon='info', category='pylint', )
def test_pylint_visit_method_taken_in_account(linter: PyLinter) -> None: class CustomChecker(checkers.BaseChecker): __implements__ = interfaces.IAstroidChecker name = "custom" msgs = {"W9999": ("", "custom", "")} @check_messages("custom") def visit_class(self, _): pass linter.register_checker(CustomChecker(linter)) linter.open() out = StringIO() linter.set_reporter(text.TextReporter(out)) linter.check(["abc"])
def test_checker_dep_graphs(linter: PyLinter) -> None: linter.global_set_option("persistent", False) linter.global_set_option("reports", True) linter.global_set_option("enable", "imports") linter.global_set_option("import-graph", "import.dot") linter.global_set_option("ext-import-graph", "ext_import.dot") linter.global_set_option("int-import-graph", "int_import.dot") linter.global_set_option("int-import-graph", "int_import.dot") # ignore this file causing spurious MemoryError w/ some python version (>=2.3?) linter.global_set_option("ignore", ("func_unknown_encoding.py", )) linter.check(["input"]) linter.generate_reports() assert exists("import.dot") assert exists("ext_import.dot") assert exists("int_import.dot")
def main(): linter = PyLinter() # linter.msgs = get_msg_ids(error_level) ns = parse_arguments() for mod in ns.module: print("module = %s" % mod) print(linter.check(mod))
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()
def main(): """Run the Wall code quality checks.""" print("Running unit tests...") # TODO: tests = defaultTestLoader.discover('.') tests = defaultTestLoader.loadTestsFromNames(["wall", "wall.util", "wall.bricks.url"]) test_result = TextTestRunner(stream=sys.stdout).run(tests) print("\nLinting (Python)...") linter = PyLinter() linter.load_default_plugins() linter.load_file_configuration() linter.load_configuration(ignore="lib") # TODO: linter.check(['wall', 'walld.py', 'sjmpc.py', 'check.py']) linter.check(["wall.util", "walld.py", "check.py"]) print("\nLinting (text)...") checkre_result = checkre( { ( r"(?!.*/lib/).*\.(html|css)", r"wall/res/default.cfg", r"wall/res/static/(display|remote)/config.default.json", r"pylintrc", ): ( line_length_check(), simple_indentation_check(), trailing_space_check(), whitespace_check(), newline_at_eof_check(), ), r"(?!.*/lib/).*\.md": ( line_length_check(), trailing_space_check(), whitespace_check(), newline_at_eof_check(), ), r"(?!.*/lib/|walld.py|sjmpc.py|check.py).*\.py": header_check("wall/__init__.py", 2), r"(?!.*/lib/).*\.js": header_check("wall/res/static/wall.js", 4), } ) if not test_result.wasSuccessful() or linter.msg_status != 0 or checkre_result != 0: return 1 print("\nEverything looks fine, good work!") return 0
def main(args): if len(args) != 2: print('Usage: %s /path/to/python/code' % args[0]) sys.exit(1) # Need to add tis script's directory to the Python path so that this module # can be made available to Pylint sys.path.append(FILE_DIR) linter = PyLinter() linter.load_default_plugins() linter.load_plugin_modules([THIS_MODULE]) linter.read_config_file(PYLINT_RC_PATH) linter.load_config_file() linter.check(args[1]) linter.generate_reports()
def run_linter(self): linter = PyLinter(pylintrc=self.lint_config) # load_default_plugins will call checkers.initialize if # implemented, but some older versions of pylint don't have # this method so we fall back to calling is manually. if hasattr(linter, 'load_default_plugins'): linter.load_default_plugins() else: checkers.initialize(linter) linter.read_config_file() linter.load_config_file() # don't emit messages about suppressed or useless suppressed # configs, it's just annoying and doesn't help. #linter.disable('suppressed-message') #linter.disable('useless-suppression') if self.packages: self.announce("pylint is checking packages", 2) report_fn = "packages_report." + linter.reporter.extension report_fn = join(self.build_base, report_fn) with open(report_fn, "wt") as out: linter.reporter.set_output(out) linter.check(self.packages) self.announce_overview(linter, report_fn) if self.build_scripts: self.announce("pylint is checking scripts", 2) report_fn = "scripts_report." + linter.reporter.extension report_fn = join(self.build_base, report_fn) with open(report_fn, "wt") as out: linter.reporter.set_output(out) linter.check(self.build_scripts) self.announce_overview(linter, report_fn)
class PyLinterTC(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable_message_category("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_message("W0101", scope="package") linter.disable_message("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_message("W0101", scope="package") linter.enable_message("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("R0102")) linter.disable_message_category("W", scope="package") linter.disable_message_category("R", scope="module") self.assert_(not linter.is_message_enabled("W0101")) self.assert_(not linter.is_message_enabled("R0102")) linter.set_current_module("tutu") self.assert_(not linter.is_message_enabled("W0101")) self.assert_(linter.is_message_enabled("R0102")) linter.enable_message_category("W", scope="package") linter.enable_message_category("R", scope="module") self.assert_(linter.is_message_enabled("W0101")) self.assert_(linter.is_message_enabled("R0102")) 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("R0001"), True) self.linter.disable_report("R0001") self.assertEquals(self.linter.is_report_enabled("R0001"), False) self.linter.enable_report("R0001") self.assertEquals(self.linter.is_report_enabled("R0001"), True) def test_set_option_1(self): linter = self.linter linter.set_option("disable-msg", "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-msg", ("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_checkers1(self): self.linter.enable_checkers(["design"], False) self.assertEquals( sorted([c.name for c in self.linter._checkers.values() if c.is_enabled()]), [ "basic", "classes", "exceptions", "format", "imports", "logging", "master", "metrics", "miscellaneous", "newstyle", "similarities", "string_format", "typecheck", "variables", ], ) def test_enable_checkers2(self): self.linter.enable_checkers(["design"], True) self.assertEquals( sorted([c.name for c in self.linter._checkers.values() if c.is_enabled()]), ["design", "master"] )
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)
#!/usr/bin/env python from pylint.lint import PyLinter from pylint import checkers linter = PyLinter() checkers.initialize(linter) linter.quiet = 999 linter.check("errors.py") s=linter.stats
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 LintModuleTest: def __init__(self, test_file: Tuple[str, Path]) -> None: self._test_file = test_file _test_reporter = FunctionalTestReporter() self._linter = PyLinter() self._linter.config.persistent = 0 checkers.initialize(self._linter) # Check if this message has a custom configuration file (e.g. for enabling optional checkers). # If not, use the default configuration. config_file: Optional[Path] msgid, full_path = test_file pylintrc = full_path.parent / "pylintrc" if pylintrc.exists(): config_file = pylintrc else: config_file = next(config.find_default_config_files(), None) args = [ str(full_path), "--disable=all", f"--enable={msgid},astroid-error,fatal,syntax-error", ] print(f"Command used:\npylint {' '.join(args)}") _config_initialization( self._linter, args_list=args, reporter=_test_reporter, config_file=config_file, ) def runTest(self) -> None: self._runTest() def is_good_test_file(self) -> bool: return self._test_file[1].name == "good.py" def is_bad_test_file(self) -> bool: return self._test_file[1].name == "bad.py" @staticmethod def get_expected_messages(stream: TextIO) -> MessageCounter: """Parse a file and get expected messages.""" 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) for msg_id in match.group("msgs").split(","): messages[lineno, msg_id.strip()] += 1 return messages def _get_expected(self) -> MessageCounter: """Get the expected messages for a file.""" with open(self._test_file[1], encoding="utf8") as f: expected_msgs = self.get_expected_messages(f) return expected_msgs def _get_actual(self) -> MessageCounter: """Get the actual messages after a run.""" messages: List[Message] = self._linter.reporter.messages messages.sort(key=lambda m: (m.line, m.symbol, m.msg)) received_msgs: MessageCounter = Counter() for msg in messages: received_msgs[msg.line, msg.symbol] += 1 return received_msgs def _runTest(self) -> None: """Run the test and assert message differences.""" self._linter.check([str(self._test_file[1])]) expected_messages = self._get_expected() actual_messages = self._get_actual() if self.is_good_test_file(): msg = "There should be no warning raised for 'good.py'" assert actual_messages.total() == 0, msg # type: ignore[attr-defined] if self.is_bad_test_file(): msg = "There should be at least one warning raised for 'bad.py'" assert actual_messages.total() > 0, msg # type: ignore[attr-defined] assert expected_messages == actual_messages
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 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)
#!/usr/bin/env python from cStringIO import StringIO from pylint.lint import PyLinter from pylint.reporters.text import ParseableTextReporter l = PyLinter() reporter = ParseableTextReporter() result = StringIO() reporter.set_output(result) l.check(__file__)
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(TestCase): def setUp(self): self.linter = PyLinter() self.linter.disable_message_category('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_message('W0101', scope='package') linter.disable_message('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_message('W0101', scope='package') linter.enable_message('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('R0102')) linter.disable_message_category('W', scope='package') linter.disable_message_category('R', scope='module') self.assert_(not linter.is_message_enabled('W0101')) self.assert_(not linter.is_message_enabled('R0102')) linter.set_current_module('tutu') self.assert_(not linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('R0102')) linter.enable_message_category('W', scope='package') linter.enable_message_category('R', scope='module') self.assert_(linter.is_message_enabled('W0101')) self.assert_(linter.is_message_enabled('R0102')) 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('R0001'), True) self.linter.disable_report('R0001') self.assertEquals(self.linter.is_report_enabled('R0001'), False) self.linter.enable_report('R0001') self.assertEquals(self.linter.is_report_enabled('R0001'), True) def test_set_option_1(self): linter = self.linter linter.set_option('disable-msg', '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-msg', ('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_checkers1(self): self.linter.enable_checkers(['design'], False) self.assertEquals( sorted([ c.name for c in self.linter._checkers.values() if c.is_enabled() ]), [ 'basic', 'classes', 'exceptions', 'format', 'imports', 'logging', 'master', 'metrics', 'miscellaneous', 'newstyle', 'similarities', 'string_format', 'typecheck', 'variables' ]) def test_enable_checkers2(self): self.linter.enable_checkers(['design'], True) self.assertEquals( sorted([ c.name for c in self.linter._checkers.values() if c.is_enabled() ]), ['design', 'master'])
class LintModuleTest: def __init__(self, test_file: Tuple[str, Path]) -> None: self._test_file = test_file _test_reporter = FunctionalTestReporter() self._linter = PyLinter() self._linter.namespace.persistent = 0 checkers.initialize(self._linter) # Check if this message has a custom configuration file (e.g. for enabling optional checkers). # If not, use the default configuration. config_file: Optional[Path] if (test_file[1].parent / "pylintrc").exists(): config_file = test_file[1].parent / "pylintrc" else: config_file = next(config.find_default_config_files(), None) _config_initialization( self._linter, args_list=[ str(test_file[1]), "--disable=all", f"--enable={test_file[0]}", ], reporter=_test_reporter, config_file=config_file, ) def runTest(self) -> None: self._runTest() def is_good_test_file(self) -> bool: return self._test_file[1].name == "good.py" def is_bad_test_file(self) -> bool: return self._test_file[1].name == "bad.py" @staticmethod def get_expected_messages(stream: TextIO) -> MessageCounter: """Parse a file and get expected messages.""" 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 else: lineno = int(line) for msg_id in match.group("msgs").split(","): messages[lineno, msg_id.strip()] += 1 return messages def _get_expected(self) -> MessageCounter: """Get the expected messages for a file.""" with open(self._test_file[1], encoding="utf8") as f: expected_msgs = self.get_expected_messages(f) return expected_msgs def _get_actual(self) -> MessageCounter: """Get the actual messages after a run.""" messages: List[Message] = self._linter.reporter.messages messages.sort(key=lambda m: (m.line, m.symbol, m.msg)) received_msgs: MessageCounter = Counter() for msg in messages: received_msgs[msg.line, msg.symbol] += 1 return received_msgs def _runTest(self) -> None: """Run the test and assert message differences.""" self._linter.check([str(self._test_file[1])]) expected_messages = self._get_expected() actual_messages = self._get_actual() if self.is_good_test_file(): assert actual_messages.total() == 0 # type: ignore[attr-defined] if self.is_bad_test_file(): assert actual_messages.total() > 0 # type: ignore[attr-defined] assert expected_messages == actual_messages
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 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 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(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)
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)
def test_analyze_explicit_script(linter: PyLinter) -> None: linter.set_reporter(testutils.GenericTestReporter()) linter.check([os.path.join(DATA_DIR, "ascript")]) assert ["C: 2: Line too long (175/100)"] == linter.reporter.messages
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(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 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)
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 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(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)
def test_sequential_checkers_work(self) -> None: """Tests original basic types of checker works as expected in -jN. This means that a sequential checker should return the same data for a given file-stream irrespective of whether it's run in -j1 or -jN """ linter = PyLinter(reporter=Reporter()) # Add a sequential checker to ensure it records data against some streams linter.register_checker(SequentialTestChecker(linter)) # Create a dummy file, the actual contents of which will be ignored by the # register test checkers, but it will trigger at least a single-job to be run. single_file_container = _gen_file_datas(count=1) # Invoke the lint process in a multiprocess way, although we only specify one # job. check_parallel( linter, jobs=1, files=iter(single_file_container), arguments=["--enable", "R9999"], ) assert len(linter.get_checkers()) == 2, ( "We should only have the 'master' and 'sequential-checker' " "checkers registered") assert { "--test-file_data-name-0--": { "convention": 0, "error": 0, "fatal": 0, "info": 0, "refactor": 0, "statement": 18, "warning": 0, } } == linter.stats.by_module assert not linter.stats.by_msg assert linter.stats.convention == 0 assert linter.stats.error == 0 assert linter.stats.fatal == 0 assert linter.stats.info == 0 assert linter.stats.refactor == 0 assert linter.stats.statement == 18 assert linter.stats.warning == 0 # now run the regular mode of checking files and check that, in this proc, we # collect the right data filepath = [single_file_container[0][1]] # get the filepath element linter.check(filepath) assert { "input.similar1": { # module is the only change from previous "convention": 0, "error": 0, "fatal": 0, "info": 0, "refactor": 0, "statement": 18, "warning": 0, } } == linter.stats.by_module assert not linter.stats.by_msg assert linter.stats.convention == 0 assert linter.stats.error == 0 assert linter.stats.fatal == 0 assert linter.stats.info == 0 assert linter.stats.refactor == 0 assert linter.stats.statement == 18 assert linter.stats.warning == 0
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)