Commit ee3e8d26 authored by Stefan Behnel's avatar Stefan Behnel

new autotestdict.{cdef,all} directives that put cdef and non-doctest...

new autotestdict.{cdef,all} directives that put cdef and non-doctest docstrings into __test__, skip non-doctest docstrings by default

--HG--
rename : tests/run/autotestdict.pyx => tests/run/autotestdict_all.pyx
rename : tests/run/autotestdict.pyx => tests/run/autotestdict_cdef.pyx
parent 86a3c4d7
...@@ -18,12 +18,13 @@ class AutoTestDictTransform(ScopeTrackingTransform): ...@@ -18,12 +18,13 @@ class AutoTestDictTransform(ScopeTrackingTransform):
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
if node.is_pxd: if node.is_pxd:
return node return node
self.scope_type = 'module' self.scope_type = 'module'
self.scope_node = node self.scope_node = node
if not self.current_directives['autotestdict']: if not self.current_directives['autotestdict']:
return node return node
self.all_docstrings = self.current_directives['autotestdict.all']
self.cdef_docstrings = self.all_docstrings or self.current_directives['autotestdict.cdef']
assert isinstance(node.body, StatListNode) assert isinstance(node.body, StatListNode)
...@@ -59,8 +60,10 @@ class AutoTestDictTransform(ScopeTrackingTransform): ...@@ -59,8 +60,10 @@ class AutoTestDictTransform(ScopeTrackingTransform):
def visit_FuncDefNode(self, node): def visit_FuncDefNode(self, node):
if not node.doc: if not node.doc:
return node return node
if not self.cdef_docstrings:
if isinstance(node, CFuncDefNode) and not node.py_func: if isinstance(node, CFuncDefNode) and not node.py_func:
# skip non-cpdef cdef functions return node
if not self.all_docstrings and '>>>' not in node.doc:
return node return node
pos = self.testspos pos = self.testspos
...@@ -68,7 +71,10 @@ class AutoTestDictTransform(ScopeTrackingTransform): ...@@ -68,7 +71,10 @@ class AutoTestDictTransform(ScopeTrackingTransform):
path = node.entry.name path = node.entry.name
elif self.scope_type in ('pyclass', 'cclass'): elif self.scope_type in ('pyclass', 'cclass'):
if isinstance(node, CFuncDefNode): if isinstance(node, CFuncDefNode):
if node.py_func is not None:
name = node.py_func.name name = node.py_func.name
else:
name = node.entry.name
else: else:
name = node.name name = node.name
if self.scope_type == 'cclass' and name in self.blacklist: if self.scope_type == 'cclass' and name in self.blacklist:
......
...@@ -68,6 +68,8 @@ directive_defaults = { ...@@ -68,6 +68,8 @@ directive_defaults = {
'infer_types': None, 'infer_types': None,
'infer_types.verbose': False, 'infer_types.verbose': False,
'autotestdict': True, 'autotestdict': True,
'autotestdict.cdef': False,
'autotestdict.all': False,
'language_level': 2, 'language_level': 2,
'warn': None, 'warn': None,
...@@ -97,6 +99,8 @@ directive_scopes = { # defaults to available everywhere ...@@ -97,6 +99,8 @@ directive_scopes = { # defaults to available everywhere
'final' : ('cclass',), # add 'method' in the future 'final' : ('cclass',), # add 'method' in the future
'internal' : ('cclass',), 'internal' : ('cclass',),
'autotestdict' : ('module',), 'autotestdict' : ('module',),
'autotestdict.all' : ('module',),
'autotestdict.cdef' : ('module',),
'test_assert_path_exists' : ('function',), 'test_assert_path_exists' : ('function',),
'test_fail_if_path_exists' : ('function',), 'test_fail_if_path_exists' : ('function',),
} }
......
# Directive defaults to True # Directive defaults to True
""" """
Tests doctesthack compiler directive. Tests autotestdict compiler directive.
The doctests are actually run as part of this test; Both module test and individual tests are run; finally,
which makes the test flow a bit untraditional. Both
module test and individual tests are run; finally,
all_tests_run() is executed which does final validation. all_tests_run() is executed which does final validation.
>>> items = list(__test__.items()) >>> items = list(__test__.items())
>>> items.sort() >>> items.sort()
>>> for key, value in items: >>> for key, value in items:
... print('%s ; %s' % (key, value)) ... print('%s ; %s' % (key, value))
MyCdefClass.cpdef_method (line 79) ; >>> add_log("cpdef class method") MyCdefClass.cpdef_method (line 76) ; >>> add_log("cpdef class method")
MyCdefClass.method (line 76) ; >>> add_log("cdef class method") MyCdefClass.method (line 73) ; >>> add_log("cdef class method")
MyClass.method (line 65) ; >>> add_log("class method") MyClass.method (line 62) ; >>> add_log("class method")
doc_without_test (line 47) ; Some docs mycpdeffunc (line 49) ; >>> add_log("cpdef")
mycpdeffunc (line 53) ; >>> add_log("cpdef") myfunc (line 40) ; >>> add_log("def")
myfunc (line 44) ; >>> add_log("def")
""" """
...@@ -25,19 +22,18 @@ log = [] ...@@ -25,19 +22,18 @@ log = []
cdef cdeffunc(): cdef cdeffunc():
""" """
Please don't include me!
>>> True >>> True
False False
""" """
cdeffunc() # make sure it's being used
def all_tests_run(): def all_tests_run():
log.sort() log.sort()
assert log == [u'cdef class', u'cdef class method', u'class method', u'cpdef', u'cpdef class method', u'def'], log assert log == [u'cdef class', u'cdef class method', u'class', u'class method', u'cpdef', u'cpdef class method', u'def'], log
def add_log(s): def add_log(s):
log.append(unicode(s)) log.append(unicode(s))
if len(log) == len(__test__): if len(log) == len(__test__) + 2:
# Final per-function doctest executed # Final per-function doctest executed
all_tests_run() all_tests_run()
...@@ -58,6 +54,7 @@ class MyClass: ...@@ -58,6 +54,7 @@ class MyClass:
""" """
Needs no hack Needs no hack
>>> add_log("class")
>>> True >>> True
True True
""" """
...@@ -79,6 +76,9 @@ cdef class MyCdefClass: ...@@ -79,6 +76,9 @@ cdef class MyCdefClass:
cpdef cpdef_method(self): cpdef cpdef_method(self):
""">>> add_log("cpdef class method")""" """>>> add_log("cpdef class method")"""
cdef cdef_method(self):
""">>> add_log("cdef class method")"""
def __cinit__(self): def __cinit__(self):
""" """
Should not be included, as it can't be looked up with getattr Should not be included, as it can't be looked up with getattr
...@@ -142,5 +142,3 @@ cdef class MyOtherCdefClass: ...@@ -142,5 +142,3 @@ cdef class MyOtherCdefClass:
>>> True >>> True
False False
""" """
cdeffunc()
# cython: autotestdict.all=True
"""
Tests autotestdict compiler directive.
Both module test and individual tests are run; finally,
all_tests_run() is executed which does final validation.
>>> items = list(__test__.items())
>>> items.sort()
>>> for key, value in items:
... print('%s ; %s' % (key, value))
MyCdefClass.cdef_method (line 79) ; >>> add_log("cdef class method")
MyCdefClass.cpdef_method (line 76) ; >>> add_log("cpdef class method")
MyCdefClass.method (line 73) ; >>> add_log("cdef class method")
MyClass.method (line 62) ; >>> add_log("class method")
cdeffunc (line 26) ; >>> add_log("cdef")
doc_without_test (line 43) ; Some docs
mycpdeffunc (line 49) ; >>> add_log("cpdef")
myfunc (line 40) ; >>> add_log("def")
"""
log = []
cdef cdeffunc():
""">>> add_log("cdef")"""
cdeffunc() # make sure it's being used
def all_tests_run():
log.sort()
assert log == [u'cdef', u'cdef class', u'cdef class method', u'class', u'class method', u'cpdef', u'cpdef class method', u'def'], log
def add_log(s):
log.append(unicode(s))
if len(log) == len(__test__):
# Final per-function doctest executed
all_tests_run()
def myfunc():
""">>> add_log("def")"""
def doc_without_test():
"""Some docs"""
def nodocstring():
pass
cpdef mycpdeffunc():
""">>> add_log("cpdef")"""
class MyClass:
"""
Needs no hack
>>> add_log("class")
>>> True
True
"""
def method(self):
""">>> add_log("class method")"""
cdef class MyCdefClass:
"""
Needs no hack
>>> add_log("cdef class")
>>> True
True
"""
def method(self):
""">>> add_log("cdef class method")"""
cpdef cpdef_method(self):
""">>> add_log("cpdef class method")"""
cdef cdef_method(self):
""">>> add_log("cdef class method")"""
def __cinit__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __dealloc__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __richcmp__(self, other, int op):
"""
Should not be included, as it can't be looked up with getattr in Py 2
>>> True
False
"""
def __nonzero__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
def __len__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
def __contains__(self, value):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
cdef class MyOtherCdefClass:
"""
Needs no hack
>>> True
True
"""
def __bool__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 2
>>> True
False
"""
# cython: autotestdict.cdef=True
"""
Tests autotestdict compiler directive.
Both module test and individual tests are run; finally,
all_tests_run() is executed which does final validation.
>>> items = list(__test__.items())
>>> items.sort()
>>> for key, value in items:
... print('%s ; %s' % (key, value))
MyCdefClass.cdef_method (line 78) ; >>> add_log("cdef class method")
MyCdefClass.cpdef_method (line 75) ; >>> add_log("cpdef class method")
MyCdefClass.method (line 72) ; >>> add_log("cdef class method")
MyClass.method (line 61) ; >>> add_log("class method")
cdeffunc (line 25) ; >>> add_log("cdef")
mycpdeffunc (line 48) ; >>> add_log("cpdef")
myfunc (line 39) ; >>> add_log("def")
"""
log = []
cdef cdeffunc():
""">>> add_log("cdef")"""
cdeffunc() # make sure it's being used
def all_tests_run():
log.sort()
assert log == [u'cdef', u'cdef class', u'cdef class method', u'class', u'class method', u'cpdef', u'cpdef class method', u'def'], log
def add_log(s):
log.append(unicode(s))
if len(log) == len(__test__) + 1:
# Final per-function doctest executed
all_tests_run()
def myfunc():
""">>> add_log("def")"""
def doc_without_test():
"""Some docs"""
def nodocstring():
pass
cpdef mycpdeffunc():
""">>> add_log("cpdef")"""
class MyClass:
"""
Needs no hack
>>> add_log("class")
>>> True
True
"""
def method(self):
""">>> add_log("class method")"""
cdef class MyCdefClass:
"""
Needs no hack
>>> add_log("cdef class")
>>> True
True
"""
def method(self):
""">>> add_log("cdef class method")"""
cpdef cpdef_method(self):
""">>> add_log("cpdef class method")"""
cdef cdef_method(self):
""">>> add_log("cdef class method")"""
def __cinit__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __dealloc__(self):
"""
Should not be included, as it can't be looked up with getattr
>>> True
False
"""
def __richcmp__(self, other, int op):
"""
Should not be included, as it can't be looked up with getattr in Py 2
>>> True
False
"""
def __nonzero__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
def __len__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
def __contains__(self, value):
"""
Should not be included, as it can't be looked up with getattr in Py 3.1
>>> True
False
"""
cdef class MyOtherCdefClass:
"""
Needs no hack
>>> True
True
"""
def __bool__(self):
"""
Should not be included, as it can't be looked up with getattr in Py 2
>>> True
False
"""
#cython: doctesthack=True #cython: autotestdict=True
""" """
Tests that doctesthack doesn't come into effect when Tests that autotestdict doesn't come into effect when
a __test__ is defined manually. a __test__ is defined manually.
If this doesn't work, then the function doctest should fail. If this doesn't work, then the function doctest should fail.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment