Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

unittest_checker_typecheck.py 8.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2014 Google, Inc.
  3. # Copyright (c) 2014 LOGILAB S.A. (Paris, FRANCE) <contact@logilab.fr>
  4. # Copyright (c) 2014 Holger Peters <email@holger-peters.de>
  5. # Copyright (c) 2015-2017 Claudiu Popa <pcmanticore@gmail.com>
  6. # Copyright (c) 2015 Dmitry Pribysh <dmand@yandex.ru>
  7. # Copyright (c) 2015 Ionel Cristian Maries <contact@ionelmc.ro>
  8. # Copyright (c) 2016 Derek Gustafson <degustaf@gmail.com>
  9. # Copyright (c) 2016 Filipe Brandenburger <filbranden@google.com>
  10. # Copyright (c) 2017 Łukasz Rogalski <rogalski.91@gmail.com>
  11. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  12. # For details: https://github.com/PyCQA/pylint/blob/master/COPYING
  13. """Unittest for the type checker."""
  14. import sys
  15. import pytest
  16. import astroid
  17. from pylint.checkers import typecheck
  18. from pylint.testutils import CheckerTestCase, Message, set_config
  19. def c_extension_missing():
  20. """Coverage module has C-extension, which we can reuse for test"""
  21. try:
  22. import coverage.tracer as _
  23. return False
  24. except ImportError:
  25. _ = None
  26. return True
  27. needs_c_extension = pytest.mark.skipif(c_extension_missing(),
  28. reason='Requires coverage (source of C-extension)')
  29. class TestTypeChecker(CheckerTestCase):
  30. "Tests for pylint.checkers.typecheck"
  31. CHECKER_CLASS = typecheck.TypeChecker
  32. def test_no_member_in_getattr(self):
  33. """Make sure that a module attribute access is checked by pylint.
  34. """
  35. node = astroid.extract_node("""
  36. import optparse
  37. optparse.THIS_does_not_EXIST
  38. """)
  39. with self.assertAddsMessages(
  40. Message(
  41. 'no-member',
  42. node=node,
  43. args=('Module', 'optparse', 'THIS_does_not_EXIST', ''))):
  44. self.checker.visit_attribute(node)
  45. @set_config(ignored_modules=('argparse',))
  46. def test_no_member_in_getattr_ignored(self):
  47. """Make sure that a module attribute access check is omitted with a
  48. module that is configured to be ignored.
  49. """
  50. node = astroid.extract_node("""
  51. import argparse
  52. argparse.THIS_does_not_EXIST
  53. """)
  54. with self.assertNoMessages():
  55. self.checker.visit_attribute(node)
  56. @set_config(ignored_classes=('xml.etree.', ))
  57. def test_ignored_modules_invalid_pattern(self):
  58. node = astroid.extract_node('''
  59. import xml
  60. xml.etree.Lala
  61. ''')
  62. message = Message('no-member', node=node,
  63. args=('Module', 'xml.etree', 'Lala', ''))
  64. with self.assertAddsMessages(message):
  65. self.checker.visit_attribute(node)
  66. @set_config(ignored_modules=('xml.etree*', ))
  67. def test_ignored_modules_patterns(self):
  68. node = astroid.extract_node('''
  69. import xml
  70. xml.etree.portocola #@
  71. ''')
  72. with self.assertNoMessages():
  73. self.checker.visit_attribute(node)
  74. @set_config(ignored_classes=('xml.*', ))
  75. def test_ignored_classes_no_recursive_pattern(self):
  76. node = astroid.extract_node('''
  77. import xml
  78. xml.etree.ElementTree.Test
  79. ''')
  80. message = Message('no-member', node=node,
  81. args=('Module', 'xml.etree.ElementTree', 'Test', ''))
  82. with self.assertAddsMessages(message):
  83. self.checker.visit_attribute(node)
  84. @set_config(ignored_classes=('optparse.Values', ))
  85. def test_ignored_classes_qualified_name(self):
  86. """Test that ignored-classes supports qualified name for ignoring."""
  87. node = astroid.extract_node('''
  88. import optparse
  89. optparse.Values.lala
  90. ''')
  91. with self.assertNoMessages():
  92. self.checker.visit_attribute(node)
  93. @set_config(ignored_classes=('Values', ))
  94. def test_ignored_classes_only_name(self):
  95. """Test that ignored_classes works with the name only."""
  96. node = astroid.extract_node('''
  97. import optparse
  98. optparse.Values.lala
  99. ''')
  100. with self.assertNoMessages():
  101. self.checker.visit_attribute(node)
  102. @set_config(suggestion_mode=False)
  103. @needs_c_extension
  104. def test_nomember_on_c_extension_error_msg(self):
  105. node = astroid.extract_node('''
  106. from coverage import tracer
  107. tracer.CTracer #@
  108. ''')
  109. message = Message('no-member', node=node,
  110. args=('Module', 'coverage.tracer', 'CTracer', ''))
  111. with self.assertAddsMessages(message):
  112. self.checker.visit_attribute(node)
  113. @set_config(suggestion_mode=True)
  114. @needs_c_extension
  115. def test_nomember_on_c_extension_info_msg(self):
  116. node = astroid.extract_node('''
  117. from coverage import tracer
  118. tracer.CTracer #@
  119. ''')
  120. message = Message('c-extension-no-member', node=node,
  121. args=('Module', 'coverage.tracer', 'CTracer', ''))
  122. with self.assertAddsMessages(message):
  123. self.checker.visit_attribute(node)
  124. @set_config(contextmanager_decorators=('contextlib.contextmanager',
  125. '.custom_contextmanager'))
  126. def test_custom_context_manager(self):
  127. """Test that @custom_contextmanager is recognized as configured."""
  128. node = astroid.extract_node('''
  129. from contextlib import contextmanager
  130. def custom_contextmanager(f):
  131. return contextmanager(f)
  132. @custom_contextmanager
  133. def dec():
  134. yield
  135. with dec():
  136. pass
  137. ''')
  138. with self.assertNoMessages():
  139. self.checker.visit_with(node)
  140. def test_invalid_metaclass(self):
  141. module = astroid.parse('''
  142. import six
  143. class InvalidAsMetaclass(object):
  144. pass
  145. @six.add_metaclass(int)
  146. class FirstInvalid(object):
  147. pass
  148. @six.add_metaclass(InvalidAsMetaclass)
  149. class SecondInvalid(object):
  150. pass
  151. @six.add_metaclass(2)
  152. class ThirdInvalid(object):
  153. pass
  154. ''')
  155. for class_obj, metaclass_name in (('ThirdInvalid', '2'),
  156. ('SecondInvalid', 'InvalidAsMetaclass'),
  157. ('FirstInvalid', 'int')):
  158. classdef = module[class_obj]
  159. message = Message('invalid-metaclass', node=classdef, args=(metaclass_name, ))
  160. with self.assertAddsMessages(message):
  161. self.checker.visit_classdef(classdef)
  162. @pytest.mark.skipif(sys.version_info[0] < 3, reason='Needs Python 3.')
  163. def test_invalid_metaclass_function_metaclasses(self):
  164. module = astroid.parse('''
  165. def invalid_metaclass_1(name, bases, attrs):
  166. return int
  167. def invalid_metaclass_2(name, bases, attrs):
  168. return 1
  169. class Invalid(metaclass=invalid_metaclass_1):
  170. pass
  171. class InvalidSecond(metaclass=invalid_metaclass_2):
  172. pass
  173. ''')
  174. for class_obj, metaclass_name in (('Invalid', 'int'), ('InvalidSecond', '1')):
  175. classdef = module[class_obj]
  176. message = Message('invalid-metaclass', node=classdef, args=(metaclass_name, ))
  177. with self.assertAddsMessages(message):
  178. self.checker.visit_classdef(classdef)
  179. @pytest.mark.skipif(sys.version_info < (3, 5), reason='Needs Python 3.5.')
  180. def test_typing_namedtuple_not_callable_issue1295(self):
  181. module = astroid.parse("""
  182. import typing
  183. Named = typing.NamedTuple('Named', [('foo', int), ('bar', int)])
  184. named = Named(1, 2)
  185. """)
  186. call = module.body[-1].value
  187. callables = call.func.infered()
  188. assert len(callables) == 1
  189. assert callables[0].callable()
  190. with self.assertNoMessages():
  191. self.checker.visit_call(call)
  192. @pytest.mark.skipif(sys.version_info < (3, 5), reason='Needs Python 3.5.')
  193. def test_typing_namedtuple_unsubscriptable_object_issue1295(self):
  194. module = astroid.parse("""
  195. import typing
  196. MyType = typing.Tuple[str, str]
  197. """)
  198. subscript = module.body[-1].value
  199. with self.assertNoMessages():
  200. self.checker.visit_subscript(subscript)