test_checker.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. import ast
  2. from pyflakes import checker
  3. from pyflakes.test.harness import TestCase
  4. class TypeableVisitorTests(TestCase):
  5. """
  6. Tests of L{_TypeableVisitor}
  7. """
  8. @staticmethod
  9. def _run_visitor(s):
  10. """
  11. Run L{_TypeableVisitor} on the parsed source and return the visitor.
  12. """
  13. tree = ast.parse(s)
  14. visitor = checker._TypeableVisitor()
  15. visitor.visit(tree)
  16. return visitor
  17. def test_node_types(self):
  18. """
  19. Test that the typeable node types are collected
  20. """
  21. visitor = self._run_visitor(
  22. """\
  23. x = 1 # assignment
  24. for x in range(1): pass # for loop
  25. def f(): pass # function definition
  26. with a as b: pass # with statement
  27. """
  28. )
  29. self.assertEqual(visitor.typeable_lines, [1, 2, 3, 4])
  30. self.assertIsInstance(visitor.typeable_nodes[1], ast.Assign)
  31. self.assertIsInstance(visitor.typeable_nodes[2], ast.For)
  32. self.assertIsInstance(visitor.typeable_nodes[3], ast.FunctionDef)
  33. self.assertIsInstance(visitor.typeable_nodes[4], ast.With)
  34. def test_visitor_recurses(self):
  35. """
  36. Test the common pitfall of missing `generic_visit` in visitors by
  37. ensuring that nested nodes are reported
  38. """
  39. visitor = self._run_visitor(
  40. """\
  41. def f():
  42. x = 1
  43. """
  44. )
  45. self.assertEqual(visitor.typeable_lines, [1, 2])
  46. self.assertIsInstance(visitor.typeable_nodes[1], ast.FunctionDef)
  47. self.assertIsInstance(visitor.typeable_nodes[2], ast.Assign)
  48. def test_py35_node_types(self):
  49. """
  50. Test that the PEP 492 node types are collected
  51. """
  52. visitor = self._run_visitor(
  53. """\
  54. async def f(): # async def
  55. async for x in y: pass # async for
  56. async with a as b: pass # async with
  57. """
  58. )
  59. self.assertEqual(visitor.typeable_lines, [1, 2, 3])
  60. self.assertIsInstance(visitor.typeable_nodes[1], ast.AsyncFunctionDef)
  61. self.assertIsInstance(visitor.typeable_nodes[2], ast.AsyncFor)
  62. self.assertIsInstance(visitor.typeable_nodes[3], ast.AsyncWith)
  63. def test_last_node_wins(self):
  64. """
  65. Test that when two typeable nodes are present on a line, the last
  66. typeable one wins.
  67. """
  68. visitor = self._run_visitor('x = 1; y = 1')
  69. # detected both assignable nodes
  70. self.assertEqual(visitor.typeable_lines, [1, 1])
  71. # but the assignment to `y` wins
  72. self.assertEqual(visitor.typeable_nodes[1].targets[0].id, 'y')
  73. class CollectTypeCommentsTests(TestCase):
  74. """
  75. Tests of L{_collect_type_comments}
  76. """
  77. @staticmethod
  78. def _collect(s):
  79. """
  80. Run L{_collect_type_comments} on the parsed source and return the
  81. mapping from nodes to comments. The return value is converted to
  82. a set: {(node_type, tuple of comments), ...}
  83. """
  84. tree = ast.parse(s)
  85. tokens = checker.make_tokens(s)
  86. ret = checker._collect_type_comments(tree, tokens)
  87. return {(type(k), tuple(s for _, s in v)) for k, v in ret.items()}
  88. def test_bytes(self):
  89. """
  90. Test that the function works for binary source
  91. """
  92. ret = self._collect(b'x = 1 # type: int')
  93. self.assertSetEqual(ret, {(ast.Assign, ('# type: int',))})
  94. def test_text(self):
  95. """
  96. Test that the function works for text source
  97. """
  98. ret = self._collect('x = 1 # type: int')
  99. self.assertEqual(ret, {(ast.Assign, ('# type: int',))})
  100. def test_non_type_comment_ignored(self):
  101. """
  102. Test that a non-type comment is ignored
  103. """
  104. ret = self._collect('x = 1 # noqa')
  105. self.assertSetEqual(ret, set())
  106. def test_type_comment_before_typeable(self):
  107. """
  108. Test that a type comment before something typeable is ignored.
  109. """
  110. ret = self._collect('# type: int\nx = 1')
  111. self.assertSetEqual(ret, set())
  112. def test_type_ignore_comment_ignored(self):
  113. """
  114. Test that `# type: ignore` comments are not collected.
  115. """
  116. ret = self._collect('x = 1 # type: ignore')
  117. self.assertSetEqual(ret, set())
  118. def test_type_ignore_with_other_things_ignored(self):
  119. """
  120. Test that `# type: ignore` comments with more content are also not
  121. collected.
  122. """
  123. ret = self._collect('x = 1 # type: ignore # noqa')
  124. self.assertSetEqual(ret, set())
  125. ret = self._collect('x = 1 #type:ignore#noqa')
  126. self.assertSetEqual(ret, set())
  127. def test_type_comment_with_extra_still_collected(self):
  128. ret = self._collect('x = 1 # type: int # noqa')
  129. self.assertSetEqual(ret, {(ast.Assign, ('# type: int # noqa',))})
  130. def test_type_comment_without_whitespace(self):
  131. ret = self._collect('x = 1 #type:int')
  132. self.assertSetEqual(ret, {(ast.Assign, ('#type:int',))})
  133. def test_type_comment_starts_with_word_ignore(self):
  134. ret = self._collect('x = 1 # type: ignore[T]')
  135. self.assertSetEqual(ret, set())
  136. def test_last_node_wins(self):
  137. """
  138. Test that when two typeable nodes are present on a line, the last
  139. typeable one wins.
  140. """
  141. ret = self._collect('def f(): x = 1 # type: int')
  142. self.assertSetEqual(ret, {(ast.Assign, ('# type: int',))})
  143. def test_function_def_assigned_comments(self):
  144. """
  145. Test that type comments for function arguments are all attributed to
  146. the function definition.
  147. """
  148. ret = self._collect(
  149. """\
  150. def f(
  151. a, # type: int
  152. b, # type: str
  153. ):
  154. # type: (...) -> None
  155. pass
  156. """
  157. )
  158. expected = {(
  159. ast.FunctionDef,
  160. ('# type: int', '# type: str', '# type: (...) -> None'),
  161. )}
  162. self.assertSetEqual(ret, expected)