AnalysedTreeTransforms.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. from __future__ import absolute_import
  2. from .Visitor import ScopeTrackingTransform
  3. from .Nodes import StatListNode, SingleAssignmentNode, CFuncDefNode, DefNode
  4. from .ExprNodes import DictNode, DictItemNode, NameNode, UnicodeNode
  5. from .PyrexTypes import py_object_type
  6. from .StringEncoding import EncodedString
  7. from . import Symtab
  8. class AutoTestDictTransform(ScopeTrackingTransform):
  9. # Handles autotestdict directive
  10. blacklist = ['__cinit__', '__dealloc__', '__richcmp__',
  11. '__nonzero__', '__bool__',
  12. '__len__', '__contains__']
  13. def visit_ModuleNode(self, node):
  14. if node.is_pxd:
  15. return node
  16. self.scope_type = 'module'
  17. self.scope_node = node
  18. if not self.current_directives['autotestdict']:
  19. return node
  20. self.all_docstrings = self.current_directives['autotestdict.all']
  21. self.cdef_docstrings = self.all_docstrings or self.current_directives['autotestdict.cdef']
  22. assert isinstance(node.body, StatListNode)
  23. # First see if __test__ is already created
  24. if u'__test__' in node.scope.entries:
  25. # Do nothing
  26. return node
  27. pos = node.pos
  28. self.tests = []
  29. self.testspos = node.pos
  30. test_dict_entry = node.scope.declare_var(EncodedString(u'__test__'),
  31. py_object_type,
  32. pos,
  33. visibility='public')
  34. create_test_dict_assignment = SingleAssignmentNode(pos,
  35. lhs=NameNode(pos, name=EncodedString(u'__test__'),
  36. entry=test_dict_entry),
  37. rhs=DictNode(pos, key_value_pairs=self.tests))
  38. self.visitchildren(node)
  39. node.body.stats.append(create_test_dict_assignment)
  40. return node
  41. def add_test(self, testpos, path, doctest):
  42. pos = self.testspos
  43. keystr = u'%s (line %d)' % (path, testpos[1])
  44. key = UnicodeNode(pos, value=EncodedString(keystr))
  45. value = UnicodeNode(pos, value=doctest)
  46. self.tests.append(DictItemNode(pos, key=key, value=value))
  47. def visit_ExprNode(self, node):
  48. # expressions cannot contain functions and lambda expressions
  49. # do not have a docstring
  50. return node
  51. def visit_FuncDefNode(self, node):
  52. if not node.doc or (isinstance(node, DefNode) and node.fused_py_func):
  53. return node
  54. if not self.cdef_docstrings:
  55. if isinstance(node, CFuncDefNode) and not node.py_func:
  56. return node
  57. if not self.all_docstrings and '>>>' not in node.doc:
  58. return node
  59. pos = self.testspos
  60. if self.scope_type == 'module':
  61. path = node.entry.name
  62. elif self.scope_type in ('pyclass', 'cclass'):
  63. if isinstance(node, CFuncDefNode):
  64. if node.py_func is not None:
  65. name = node.py_func.name
  66. else:
  67. name = node.entry.name
  68. else:
  69. name = node.name
  70. if self.scope_type == 'cclass' and name in self.blacklist:
  71. return node
  72. if self.scope_type == 'pyclass':
  73. class_name = self.scope_node.name
  74. else:
  75. class_name = self.scope_node.class_name
  76. if isinstance(node.entry.scope, Symtab.PropertyScope):
  77. property_method_name = node.entry.scope.name
  78. path = "%s.%s.%s" % (class_name, node.entry.scope.name,
  79. node.entry.name)
  80. else:
  81. path = "%s.%s" % (class_name, node.entry.name)
  82. else:
  83. assert False
  84. self.add_test(node.pos, path, node.doc)
  85. return node