diff options
author | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-07-08 01:21:24 +0300 |
---|---|---|
committer | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-07-08 01:21:24 +0300 |
commit | 19709366ac41c5ce7a1bf9c7f48b1aaca6c8e9bf (patch) | |
tree | 3103c28d5701346567b0e71fb5c0a6f9deec5b46 /pylint | |
parent | 2ecfa1fc655976cf57efe50beeb9ebf7347b0160 (diff) | |
download | pylint-git-19709366ac41c5ce7a1bf9c7f48b1aaca6c8e9bf.tar.gz |
Fix the previous commit, only ignored-modules should use patterns, not ignored-classes.
Thanks to The-Compiler for noticing the discrepancy.
Diffstat (limited to 'pylint')
-rw-r--r-- | pylint/checkers/typecheck.py | 51 | ||||
-rw-r--r-- | pylint/test/unittest_checker_typecheck.py | 42 |
2 files changed, 58 insertions, 35 deletions
diff --git a/pylint/checkers/typecheck.py b/pylint/checkers/typecheck.py index cbbd0545a..f4551f8a1 100644 --- a/pylint/checkers/typecheck.py +++ b/pylint/checkers/typecheck.py @@ -48,15 +48,32 @@ def _unflatten(iterable): yield elem -def _is_ignored_class(owner, name, ignores): +def _is_owner_ignored(owner, name, ignored_classes, ignored_modules): + """Check if the given owner should be ignored + + This will verify if the owner's module is in *ignored_modules* + or the owner's module fully qualified name is in *ignored_modules* + or if the *ignored_modules* contains a pattern which catches + the fully qualified name of the module. + + Also, similar checks are done for the owner itself, if its name + matches any name from the *ignored_classes* or if its qualified + name can be found in *ignored_classes*. + """ + ignored_modules = set(ignored_modules) + module_name = owner.root().name + module_qname = owner.root().qname() + if any(module_name in ignored_modules or + module_qname in ignored_modules or + fnmatch.fnmatch(module_qname, ignore) for ignore in ignored_modules): + return True + + ignored_classes = set(ignored_classes) if hasattr(owner, 'qname'): qname = owner.qname() else: qname = '' - ignores = set(ignores) - return any(name == ignore or - qname == ignore or - fnmatch.fnmatch(qname, ignore) for ignore in ignores) + return any(name == ignore or qname == ignore for ignore in ignored_classes) MSGS = { @@ -126,8 +143,7 @@ SEQUENCE_TYPES = set(['str', 'unicode', 'list', 'tuple', 'bytearray', 'xrange', 'range', 'bytes', 'memoryview']) -def _emit_no_member(node, owner, owner_name, attrname, - ignored_modules, ignored_mixins): +def _emit_no_member(node, owner, owner_name, attrname, ignored_mixins): """Try to see if no-member should be emitted for the given owner. The following cases are ignored: @@ -164,9 +180,6 @@ def _emit_no_member(node, owner, owner_name, attrname, return False if not all(map(helpers.has_known_bases, owner.type.mro())): return False - # explicit skipping of module member access - if owner.root().name in ignored_modules: - return False if isinstance(owner, astroid.Class): # Look up in the metaclass only if the owner is itself # a class. @@ -250,10 +263,12 @@ class should be ignored. A mixin class is detected if its name ends with \ {'default': (), 'type': 'csv', 'metavar': '<module names>', - 'help': 'List of module names for which member attributes \ -should not be checked (useful for modules/projects where namespaces are \ -manipulated during runtime and thus existing member attributes cannot be \ -deduced by static analysis'}, + 'help': 'List of module names for which member attributes ' + 'should not be checked (useful for modules/projects ' + 'where namespaces are manipulated during runtime and ' + 'thus existing member attributes cannot be ' + 'deduced by static analysis. It supports qualified ' + 'module names, as well as Unix pattern matching.'} ), ('ignored-classes', {'default' : (), @@ -262,9 +277,7 @@ deduced by static analysis'}, 'help' : 'List of classes names for which member attributes ' 'should not be checked (useful for classes with ' 'attributes dynamically set). This supports ' - 'three types of names: class names, qualified names, ' - 'and names with Unix pattern matching ' - '(https://docs.python.org/3.5/library/fnmatch.html)'} + 'can work with qualified names.'} ), ('zope', @@ -331,7 +344,8 @@ accessed. Python regular expressions are accepted.'} continue name = getattr(owner, 'name', None) - if _is_ignored_class(owner, name, self.config.ignored_classes): + if _is_owner_ignored(owner, name, self.config.ignored_classes, + self.config.ignored_modules): continue try: @@ -351,7 +365,6 @@ accessed. Python regular expressions are accepted.'} # attribute, then we'll have a false positive. # So call this only after the call has been made. if not _emit_no_member(node, owner, name, node.attrname, - self.config.ignored_modules, self.config.ignore_mixin_members): continue missingattr.add((owner, name)) diff --git a/pylint/test/unittest_checker_typecheck.py b/pylint/test/unittest_checker_typecheck.py index 452e9c830..aa60a7bee 100644 --- a/pylint/test/unittest_checker_typecheck.py +++ b/pylint/test/unittest_checker_typecheck.py @@ -37,16 +37,37 @@ class TypeCheckerTest(CheckerTestCase): with self.assertNoMessages(): self.checker.visit_getattr(node) - @set_config(ignored_classes=('xml.*', )) - def test_ignored_classes_recursive_pattern(self): - """Test that ignored-classes supports patterns for ignoring.""" + @set_config(ignored_classes=('xml.etree.', )) + def test_ignored_modules_invalid_pattern(self): node = test_utils.extract_node(''' - import xml.etree - xml.etree.Ala.Bala.Portocala + import xml + xml.etree.Lala + ''') + message = Message('no-member', node=node, + args=('Module', 'xml.etree', 'Lala')) + with self.assertAddsMessages(message): + self.checker.visit_getattr(node) + + @set_config(ignored_modules=('xml.etree*', )) + def test_ignored_modules_patterns(self): + node = test_utils.extract_node(''' + import xml + xml.etree.portocola #@ ''') with self.assertNoMessages(): self.checker.visit_getattr(node) + @set_config(ignored_classes=('xml.*', )) + def test_ignored_classes_no_recursive_pattern(self): + node = test_utils.extract_node(''' + import xml + xml.etree.ElementTree.Test + ''') + message = Message('no-member', node=node, + args=('Module', 'xml.etree.ElementTree', 'Test')) + with self.assertAddsMessages(message): + self.checker.visit_getattr(node) + @set_config(ignored_classes=('optparse.Values', )) def test_ignored_classes_qualified_name(self): """Test that ignored-classes supports qualified name for ignoring.""" @@ -67,17 +88,6 @@ class TypeCheckerTest(CheckerTestCase): with self.assertNoMessages(): self.checker.visit_getattr(node) - @set_config(ignored_classes=('xml.etree.', )) - def test_ignored_classes_invalid_pattern(self): - node = test_utils.extract_node(''' - import xml - xml.etree.Lala - ''') - message = Message('no-member', node=node, - args=('Module', 'xml.etree', 'Lala')) - with self.assertAddsMessages(message): - self.checker.visit_getattr(node) - if __name__ == '__main__': unittest.main() |