##// END OF EJS Templates
Checkpoint with more tests working....
Fernando Perez -
Show More
@@ -0,0 +1,146 b''
1 ## The basic trick is to generate the source code for the decorated function
2 ## with the right signature and to evaluate it.
3 ## Uncomment the statement 'print >> sys.stderr, func_src' in _decorate
4 ## to understand what is going on.
5
6 __all__ = ["decorator", "update_wrapper", "getinfo"]
7
8 import inspect, sys
9
10 def getinfo(func):
11 """
12 Returns an info dictionary containing:
13 - name (the name of the function : str)
14 - argnames (the names of the arguments : list)
15 - defaults (the values of the default arguments : tuple)
16 - signature (the signature : str)
17 - doc (the docstring : str)
18 - module (the module name : str)
19 - dict (the function __dict__ : str)
20
21 >>> def f(self, x=1, y=2, *args, **kw): pass
22
23 >>> info = getinfo(f)
24
25 >>> info["name"]
26 'f'
27 >>> info["argnames"]
28 ['self', 'x', 'y', 'args', 'kw']
29
30 >>> info["defaults"]
31 (1, 2)
32
33 >>> info["signature"]
34 'self, x, y, *args, **kw'
35 """
36 assert inspect.ismethod(func) or inspect.isfunction(func)
37 regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
38 argnames = list(regargs)
39 if varargs:
40 argnames.append(varargs)
41 if varkwargs:
42 argnames.append(varkwargs)
43 signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults,
44 formatvalue=lambda value: "")[1:-1]
45 return dict(name=func.__name__, argnames=argnames, signature=signature,
46 defaults = func.func_defaults, doc=func.__doc__,
47 module=func.__module__, dict=func.__dict__,
48 globals=func.func_globals, closure=func.func_closure)
49
50 def update_wrapper(wrapper, wrapped, create=False):
51 """
52 An improvement over functools.update_wrapper. By default it works the
53 same, but if the 'create' flag is set, generates a copy of the wrapper
54 with the right signature and update the copy, not the original.
55 Moreovoer, 'wrapped' can be a dictionary with keys 'name', 'doc', 'module',
56 'dict', 'defaults'.
57 """
58 if isinstance(wrapped, dict):
59 infodict = wrapped
60 else: # assume wrapped is a function
61 infodict = getinfo(wrapped)
62 assert not '_wrapper_' in infodict["argnames"], \
63 '"_wrapper_" is a reserved argument name!'
64 if create: # create a brand new wrapper with the right signature
65 src = "lambda %(signature)s: _wrapper_(%(signature)s)" % infodict
66 # import sys; print >> sys.stderr, src # for debugging purposes
67 wrapper = eval(src, dict(_wrapper_=wrapper))
68 try:
69 wrapper.__name__ = infodict['name']
70 except: # Python version < 2.4
71 pass
72 wrapper.__doc__ = infodict['doc']
73 wrapper.__module__ = infodict['module']
74 wrapper.__dict__.update(infodict['dict'])
75 wrapper.func_defaults = infodict['defaults']
76 return wrapper
77
78 # the real meat is here
79 def _decorator(caller, func):
80 infodict = getinfo(func)
81 argnames = infodict['argnames']
82 assert not ('_call_' in argnames or '_func_' in argnames), \
83 'You cannot use _call_ or _func_ as argument names!'
84 src = "lambda %(signature)s: _call_(_func_, %(signature)s)" % infodict
85 dec_func = eval(src, dict(_func_=func, _call_=caller))
86 return update_wrapper(dec_func, func)
87
88 def decorator(caller, func=None):
89 """
90 General purpose decorator factory: takes a caller function as
91 input and returns a decorator with the same attributes.
92 A caller function is any function like this::
93
94 def caller(func, *args, **kw):
95 # do something
96 return func(*args, **kw)
97
98 Here is an example of usage:
99
100 >>> @decorator
101 ... def chatty(f, *args, **kw):
102 ... print "Calling %r" % f.__name__
103 ... return f(*args, **kw)
104
105 >>> chatty.__name__
106 'chatty'
107
108 >>> @chatty
109 ... def f(): pass
110 ...
111 >>> f()
112 Calling 'f'
113
114 For sake of convenience, the decorator factory can also be called with
115 two arguments. In this casem ``decorator(caller, func)`` is just a
116 shortcut for ``decorator(caller)(func)``.
117 """
118 if func is None: # return a decorator function
119 return update_wrapper(lambda f : _decorator(caller, f), caller)
120 else: # return a decorated function
121 return _decorator(caller, func)
122
123 if __name__ == "__main__":
124 import doctest; doctest.testmod()
125
126 ####################### LEGALESE ##################################
127
128 ## Redistributions of source code must retain the above copyright
129 ## notice, this list of conditions and the following disclaimer.
130 ## Redistributions in bytecode form must reproduce the above copyright
131 ## notice, this list of conditions and the following disclaimer in
132 ## the documentation and/or other materials provided with the
133 ## distribution.
134
135 ## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
136 ## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
137 ## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
138 ## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
139 ## HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
140 ## INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
141 ## BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
142 ## OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
143 ## ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
144 ## TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
145 ## USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
146 ## DAMAGE.
@@ -0,0 +1,144 b''
1 """Decorators for labeling test objects.
2
3 Decorators that merely return a modified version of the original
4 function object are straightforward. Decorators that return a new
5 function object need to use
6 nose.tools.make_decorator(original_function)(decorator) in returning
7 the decorator, in order to preserve metadata such as function name,
8 setup and teardown functions and so on - see nose.tools for more
9 information.
10
11 NOTE: This file contains IPython-specific decorators and imports the
12 numpy.testing.decorators file, which we've copied verbatim. Any of our own
13 code will be added at the bottom if we end up extending this.
14 """
15
16 # Stdlib imports
17 import inspect
18
19 # Third-party imports
20
21 # This is Michele Simionato's decorator module, also kept verbatim.
22 from decorator_msim import decorator
23
24 # Grab the numpy-specific decorators which we keep in a file that we
25 # occasionally update from upstream: decorators_numpy.py is an IDENTICAL copy
26 # of numpy.testing.decorators.
27 from decorators_numpy import *
28
29 ##############################################################################
30 # Local code begins
31
32 # Utility functions
33
34 def apply_wrapper(wrapper,func):
35 """Apply a wrapper to a function for decoration.
36
37 This mixes Michele Simionato's decorator tool with nose's make_decorator,
38 to apply a wrapper in a decorator so that all nose attributes, as well as
39 function signature and other properties, survive the decoration cleanly.
40 This will ensure that wrapped functions can still be well introspected via
41 IPython, for example.
42 """
43 import nose.tools
44
45 return decorator(wrapper,nose.tools.make_decorator(func)(wrapper))
46
47
48 def make_label_dec(label,ds=None):
49 """Factory function to create a decorator that applies one or more labels.
50
51 :Parameters:
52 label : string or sequence
53 One or more labels that will be applied by the decorator to the functions
54 it decorates. Labels are attributes of the decorated function with their
55 value set to True.
56
57 :Keywords:
58 ds : string
59 An optional docstring for the resulting decorator. If not given, a
60 default docstring is auto-generated.
61
62 :Returns:
63 A decorator.
64
65 :Examples:
66
67 A simple labeling decorator:
68 >>> slow = make_label_dec('slow')
69 >>> print slow.__doc__
70 Labels a test as 'slow'.
71
72 And one that uses multiple labels and a custom docstring:
73 >>> rare = make_label_dec(['slow','hard'],
74 ... "Mix labels 'slow' and 'hard' for rare tests.")
75 >>> print rare.__doc__
76 Mix labels 'slow' and 'hard' for rare tests.
77
78 Now, let's test using this one:
79 >>> @rare
80 ... def f(): pass
81 ...
82 >>>
83 >>> f.slow
84 True
85 >>> f.hard
86 True
87 """
88
89 if isinstance(label,basestring):
90 labels = [label]
91 else:
92 labels = label
93
94 # Validate that the given label(s) are OK for use in setattr() by doing a
95 # dry run on a dummy function.
96 tmp = lambda : None
97 for label in labels:
98 setattr(tmp,label,True)
99
100 # This is the actual decorator we'll return
101 def decor(f):
102 for label in labels:
103 setattr(f,label,True)
104 return f
105
106 # Apply the user's docstring, or autogenerate a basic one
107 if ds is None:
108 ds = "Labels a test as %r." % label
109 decor.__doc__ = ds
110
111 return decor
112
113 #-----------------------------------------------------------------------------
114 # Decorators for public use
115
116 def skip_doctest(func):
117 """Decorator - mark a function for skipping its doctest.
118
119 This decorator allows you to mark a function whose docstring you wish to
120 omit from testing, while preserving the docstring for introspection, help,
121 etc."""
122
123 # We just return the function unmodified, but the wrapping has the effect
124 # of making the doctest plugin skip the doctest.
125 def wrapper(*a,**k):
126 return func(*a,**k)
127
128 # Here we use plain 'decorator' and not apply_wrapper, because we don't
129 # need all the nose-protection machinery (functions containing doctests
130 # can't be full-blown nose tests, so we don't need to prserve
131 # setup/teardown).
132 return decorator(wrapper,func)
133
134
135 def skip(func):
136 """Decorator - mark a test function for skipping from test suite."""
137
138 import nose
139
140 def wrapper(*a,**k):
141 raise nose.SkipTest("Skipping test for function: %s" %
142 func.__name__)
143
144 return apply_wrapper(wrapper,func)
@@ -0,0 +1,94 b''
1 """Decorators for labeling test objects
2
3 Decorators that merely return a modified version of the original
4 function object are straightforward. Decorators that return a new
5 function object need to use
6 nose.tools.make_decorator(original_function)(decorator) in returning
7 the decorator, in order to preserve metadata such as function name,
8 setup and teardown functions and so on - see nose.tools for more
9 information.
10
11 """
12
13 def slow(t):
14 """Labels a test as 'slow'.
15
16 The exact definition of a slow test is obviously both subjective and
17 hardware-dependent, but in general any individual test that requires more
18 than a second or two should be labeled as slow (the whole suite consits of
19 thousands of tests, so even a second is significant)."""
20
21 t.slow = True
22 return t
23
24 def setastest(tf=True):
25 ''' Signals to nose that this function is or is not a test
26
27 Parameters
28 ----------
29 tf : bool
30 If True specifies this is a test, not a test otherwise
31
32 e.g
33 >>> from numpy.testing.decorators import setastest
34 >>> @setastest(False)
35 ... def func_with_test_in_name(arg1, arg2): pass
36 ...
37 >>>
38
39 This decorator cannot use the nose namespace, because it can be
40 called from a non-test module. See also istest and nottest in
41 nose.tools
42
43 '''
44 def set_test(t):
45 t.__test__ = tf
46 return t
47 return set_test
48
49 def skipif(skip_condition, msg=None):
50 ''' Make function raise SkipTest exception if skip_condition is true
51
52 Parameters
53 ---------
54 skip_condition : bool
55 Flag to determine whether to skip test (True) or not (False)
56 msg : string
57 Message to give on raising a SkipTest exception
58
59 Returns
60 -------
61 decorator : function
62 Decorator, which, when applied to a function, causes SkipTest
63 to be raised when the skip_condition was True, and the function
64 to be called normally otherwise.
65
66 Notes
67 -----
68 You will see from the code that we had to further decorate the
69 decorator with the nose.tools.make_decorator function in order to
70 transmit function name, and various other metadata.
71 '''
72 if msg is None:
73 msg = 'Test skipped due to test condition'
74 def skip_decorator(f):
75 # Local import to avoid a hard nose dependency and only incur the
76 # import time overhead at actual test-time.
77 import nose
78 def skipper(*args, **kwargs):
79 if skip_condition:
80 raise nose.SkipTest, msg
81 else:
82 return f(*args, **kwargs)
83 return nose.tools.make_decorator(f)(skipper)
84 return skip_decorator
85
86 def skipknownfailure(f):
87 ''' Decorator to raise SkipTest for test known to fail
88 '''
89 # Local import to avoid a hard nose dependency and only incur the
90 # import time overhead at actual test-time.
91 import nose
92 def skipper(*args, **kwargs):
93 raise nose.SkipTest, 'This test is known to fail'
94 return nose.tools.make_decorator(f)(skipper)
@@ -0,0 +1,2 b''
1 x = 1
2 print 'x is:',x
@@ -2,29 +2,45 b''
2 PREFIX=~/usr/local
2 PREFIX=~/usr/local
3 PREFIX=~/tmp/local
3 PREFIX=~/tmp/local
4
4
5 NOSE0=nosetests -vs --with-doctest --doctest-tests
6 NOSE=nosetests -vvs --with-ipdoctest --doctest-tests --doctest-extension=txt
7
8 #--with-color
9
10 SRC=ipdoctest.py setup.py decorators.py
11
5 plugin: IPython_doctest_plugin.egg-info
12 plugin: IPython_doctest_plugin.egg-info
6
13
7 dtest: plugin dtexample.py
14 dtest: plugin dtexample.py
8 nosetests -vs --with-ipdoctest --doctest-tests --doctest-extension=txt \
15 $(NOSE) dtexample.py
9 dtexample.py
10
16
11 # Note: this test is double counting!!!
17 # Note: this test is double counting!!!
12 rtest: plugin dtexample.py
18 rtest: plugin dtexample.py
13 nosetests -vs --with-ipdoctest --doctest-tests test_refs.py
19 $(NOSE) test_refs.py
20
21 std: plugin
22 nosetests -vs --with-doctest --doctest-tests IPython.strdispatch
23 $(NOSE) IPython.strdispatch
14
24
15 test: plugin dtexample.py
25 test: plugin dtexample.py
16 nosetests -vs --with-ipdoctest --doctest-tests --doctest-extension=txt \
26 $(NOSE) dtexample.py test*.py test*.txt
17 dtexample.py test*.py test*.txt
18
27
19 deb: plugin dtexample.py
28 deb: plugin dtexample.py
20 nosetests -vs --with-ipdoctest --doctest-tests --doctest-extension=txt \
29 $(NOSE) test_combo.txt
21 test_combo.txt
22
30
23 iptest: plugin
31 iptest: plugin
24 nosetests -vs --with-ipdoctest --doctest-tests --doctest-extension=txt \
32 $(NOSE) IPython
25 IPython
33
34 deco:
35 $(NOSE0) decorators.py
36
37 sr: rtest std
38
39 base: dtest rtest test std deco
40
41 all: base iptest
26
42
27 IPython_doctest_plugin.egg-info: ipdoctest.py setup.py
43 IPython_doctest_plugin.egg-info: $(SRC)
28 python setup.py install --prefix=$(PREFIX)
44 python setup.py install --prefix=$(PREFIX)
29 touch $@
45 touch $@
30
46
@@ -68,6 +68,29 b' log = logging.getLogger(__name__)'
68 # machinery into a fit. This code should be considered a gross hack, but it
68 # machinery into a fit. This code should be considered a gross hack, but it
69 # gets the job done.
69 # gets the job done.
70
70
71 class ncdict(dict):
72 """Non-copying dict class.
73
74 This is a special-purpose dict subclass that overrides the .copy() method
75 to return the original object itself. We need it to ensure that doctests
76 happen in the IPython namespace, but doctest always makes a shallow copy of
77 the given globals for execution. Since we actually *want* this namespace
78 to be persistent (this is how the user's session maintains state), we
79 simply fool doctest by returning the original object upoon copy.
80 """
81
82 def copy(self):
83 return self
84
85
86 def _my_run(self,arg_s,runner=None):
87 """
88 """
89 #print 'HA!' # dbg
90
91 return _ip.IP.magic_run_ori(arg_s,runner)
92
93
71 def start_ipython():
94 def start_ipython():
72 """Start a global IPython shell, which we need for IPython-specific syntax.
95 """Start a global IPython shell, which we need for IPython-specific syntax.
73 """
96 """
@@ -88,8 +111,11 b' def start_ipython():'
88 _excepthook = sys.excepthook
111 _excepthook = sys.excepthook
89 _main = sys.modules.get('__main__')
112 _main = sys.modules.get('__main__')
90
113
91 # Start IPython instance
114 # Start IPython instance. We customize it to start with minimal frills and
92 IPython.Shell.IPShell(['--classic','--noterm_title'])
115 # with our own namespace.
116 argv = ['--classic','--noterm_title']
117 user_ns = ncdict()
118 IPython.Shell.IPShell(argv,user_ns)
93
119
94 # Deactivate the various python system hooks added by ipython for
120 # Deactivate the various python system hooks added by ipython for
95 # interactive convenience so we don't confuse the doctest system
121 # interactive convenience so we don't confuse the doctest system
@@ -107,6 +133,11 b' def start_ipython():'
107 # doctest machinery would miss them.
133 # doctest machinery would miss them.
108 _ip.system = xsys
134 _ip.system = xsys
109
135
136 import new
137 im = new.instancemethod(_my_run,_ip.IP, _ip.IP.__class__)
138 _ip.IP.magic_run_ori = _ip.IP.magic_run
139 _ip.IP.magic_run = im
140
110 # The start call MUST be made here. I'm not sure yet why it doesn't work if
141 # The start call MUST be made here. I'm not sure yet why it doesn't work if
111 # it is made later, at plugin initialization time, but in all my tests, that's
142 # it is made later, at plugin initialization time, but in all my tests, that's
112 # the case.
143 # the case.
@@ -214,14 +245,14 b' class DocTestFinder(doctest.DocTestFinder):'
214 globs, seen)
245 globs, seen)
215
246
216
247
217 # second-chance checker; if the default comparison doesn't
248 # second-chance checker; if the default comparison doesn't
218 # pass, then see if the expected output string contains flags that
249 # pass, then see if the expected output string contains flags that
219 # tell us to ignore the output
250 # tell us to ignore the output
220 class IPDoctestOutputChecker(doctest.OutputChecker):
251 class IPDoctestOutputChecker(doctest.OutputChecker):
221 def check_output(self, want, got, optionflags):
252 def check_output(self, want, got, optionflags):
222 #print '*** My Checker!' # dbg
253 #print '*** My Checker!' # dbg
223
254
224 ret = doctest.OutputChecker.check_output(self, want, got,
255 ret = doctest.OutputChecker.check_output(self, want, got,
225 optionflags)
256 optionflags)
226 if not ret:
257 if not ret:
227 if "#random" in want:
258 if "#random" in want:
@@ -239,22 +270,22 b' class DocTestCase(doctests.DocTestCase):'
239 """
270 """
240
271
241 # Note: this method was taken from numpy's nosetester module.
272 # Note: this method was taken from numpy's nosetester module.
242
273
243 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
274 # Subclass nose.plugins.doctests.DocTestCase to work around a bug in
244 # its constructor that blocks non-default arguments from being passed
275 # its constructor that blocks non-default arguments from being passed
245 # down into doctest.DocTestCase
276 # down into doctest.DocTestCase
246
277
247 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
278 def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
248 checker=None, obj=None, result_var='_'):
279 checker=None, obj=None, result_var='_'):
249 self._result_var = result_var
280 self._result_var = result_var
250 doctests.DocTestCase.__init__(self, test,
281 doctests.DocTestCase.__init__(self, test,
251 optionflags=optionflags,
282 optionflags=optionflags,
252 setUp=setUp, tearDown=tearDown,
283 setUp=setUp, tearDown=tearDown,
253 checker=checker)
284 checker=checker)
254 # Now we must actually copy the original constructor from the stdlib
285 # Now we must actually copy the original constructor from the stdlib
255 # doctest class, because we can't call it directly and a bug in nose
286 # doctest class, because we can't call it directly and a bug in nose
256 # means it never gets passed the right arguments.
287 # means it never gets passed the right arguments.
257
288
258 self._dt_optionflags = optionflags
289 self._dt_optionflags = optionflags
259 self._dt_checker = checker
290 self._dt_checker = checker
260 self._dt_test = test
291 self._dt_test = test
@@ -325,9 +356,9 b' class IPDocTestParser(doctest.DocTestParser):'
325 out = []
356 out = []
326 newline = out.append
357 newline = out.append
327 for lnum,line in enumerate(source.splitlines()):
358 for lnum,line in enumerate(source.splitlines()):
328 #newline(_ip.IPipython.prefilter(line,True))
329 newline(_ip.IP.prefilter(line,lnum>0))
359 newline(_ip.IP.prefilter(line,lnum>0))
330 newline('') # ensure a closing newline, needed by doctest
360 newline('') # ensure a closing newline, needed by doctest
361 #print "PYSRC:", '\n'.join(out) # dbg
331 return '\n'.join(out)
362 return '\n'.join(out)
332
363
333 def parse(self, string, name='<string>'):
364 def parse(self, string, name='<string>'):
@@ -338,7 +369,7 b' class IPDocTestParser(doctest.DocTestParser):'
338 argument `name` is a name identifying this string, and is only
369 argument `name` is a name identifying this string, and is only
339 used for error messages.
370 used for error messages.
340 """
371 """
341
372
342 #print 'Parse string:\n',string # dbg
373 #print 'Parse string:\n',string # dbg
343
374
344 string = string.expandtabs()
375 string = string.expandtabs()
@@ -492,6 +523,201 b' class IPDocTestParser(doctest.DocTestParser):'
492 SKIP = doctest.register_optionflag('SKIP')
523 SKIP = doctest.register_optionflag('SKIP')
493
524
494
525
526 class IPDocTestRunner(doctest.DocTestRunner):
527
528 # Unfortunately, doctest uses a private method (__run) for the actual run
529 # execution, so we can't cleanly override just that part. Instead, we have
530 # to copy/paste the entire run() implementation so we can call our own
531 # customized runner.
532 #/////////////////////////////////////////////////////////////////
533 # DocTest Running
534 #/////////////////////////////////////////////////////////////////
535
536 def __run(self, test, compileflags, out):
537 """
538 Run the examples in `test`. Write the outcome of each example
539 with one of the `DocTestRunner.report_*` methods, using the
540 writer function `out`. `compileflags` is the set of compiler
541 flags that should be used to execute examples. Return a tuple
542 `(f, t)`, where `t` is the number of examples tried, and `f`
543 is the number of examples that failed. The examples are run
544 in the namespace `test.globs`.
545 """
546 # Keep track of the number of failures and tries.
547 failures = tries = 0
548
549 # Save the option flags (since option directives can be used
550 # to modify them).
551 original_optionflags = self.optionflags
552
553 SUCCESS, FAILURE, BOOM = range(3) # `outcome` state
554
555 check = self._checker.check_output
556
557 # Process each example.
558 for examplenum, example in enumerate(test.examples):
559
560 # If REPORT_ONLY_FIRST_FAILURE is set, then supress
561 # reporting after the first failure.
562 quiet = (self.optionflags & REPORT_ONLY_FIRST_FAILURE and
563 failures > 0)
564
565 # Merge in the example's options.
566 self.optionflags = original_optionflags
567 if example.options:
568 for (optionflag, val) in example.options.items():
569 if val:
570 self.optionflags |= optionflag
571 else:
572 self.optionflags &= ~optionflag
573
574 # If 'SKIP' is set, then skip this example.
575 if self.optionflags & SKIP:
576 continue
577
578 # Record that we started this example.
579 tries += 1
580 if not quiet:
581 self.report_start(out, test, example)
582
583 # Use a special filename for compile(), so we can retrieve
584 # the source code during interactive debugging (see
585 # __patched_linecache_getlines).
586 filename = '<doctest %s[%d]>' % (test.name, examplenum)
587
588 # Run the example in the given context (globs), and record
589 # any exception that gets raised. (But don't intercept
590 # keyboard interrupts.)
591 try:
592 # Don't blink! This is where the user's code gets run.
593 exec compile(example.source, filename, "single",
594 compileflags, 1) in test.globs
595 self.debugger.set_continue() # ==== Example Finished ====
596 exception = None
597 except KeyboardInterrupt:
598 raise
599 except:
600 exception = sys.exc_info()
601 self.debugger.set_continue() # ==== Example Finished ====
602
603 got = self._fakeout.getvalue() # the actual output
604 self._fakeout.truncate(0)
605 outcome = FAILURE # guilty until proved innocent or insane
606
607 # If the example executed without raising any exceptions,
608 # verify its output.
609 if exception is None:
610 if check(example.want, got, self.optionflags):
611 outcome = SUCCESS
612
613 # The example raised an exception: check if it was expected.
614 else:
615 exc_info = sys.exc_info()
616 exc_msg = traceback.format_exception_only(*exc_info[:2])[-1]
617 if not quiet:
618 got += _exception_traceback(exc_info)
619
620 # If `example.exc_msg` is None, then we weren't expecting
621 # an exception.
622 if example.exc_msg is None:
623 outcome = BOOM
624
625 # We expected an exception: see whether it matches.
626 elif check(example.exc_msg, exc_msg, self.optionflags):
627 outcome = SUCCESS
628
629 # Another chance if they didn't care about the detail.
630 elif self.optionflags & IGNORE_EXCEPTION_DETAIL:
631 m1 = re.match(r'[^:]*:', example.exc_msg)
632 m2 = re.match(r'[^:]*:', exc_msg)
633 if m1 and m2 and check(m1.group(0), m2.group(0),
634 self.optionflags):
635 outcome = SUCCESS
636
637 # Report the outcome.
638 if outcome is SUCCESS:
639 if not quiet:
640 self.report_success(out, test, example, got)
641 elif outcome is FAILURE:
642 if not quiet:
643 self.report_failure(out, test, example, got)
644 failures += 1
645 elif outcome is BOOM:
646 if not quiet:
647 self.report_unexpected_exception(out, test, example,
648 exc_info)
649 failures += 1
650 else:
651 assert False, ("unknown outcome", outcome)
652
653 # Restore the option flags (in case they were modified)
654 self.optionflags = original_optionflags
655
656 # Record and return the number of failures and tries.
657
658 #self.__record_outcome(test, failures, tries)
659
660 # Hack to access a parent private method by working around Python's
661 # name mangling (which is fortunately simple).
662 doctest.DocTestRunner._DocTestRunner__record_outcome(self,test,
663 failures, tries)
664 return failures, tries
665
666 def run(self, test, compileflags=None, out=None, clear_globs=True):
667 """
668 Run the examples in `test`, and display the results using the
669 writer function `out`.
670
671 The examples are run in the namespace `test.globs`. If
672 `clear_globs` is true (the default), then this namespace will
673 be cleared after the test runs, to help with garbage
674 collection. If you would like to examine the namespace after
675 the test completes, then use `clear_globs=False`.
676
677 `compileflags` gives the set of flags that should be used by
678 the Python compiler when running the examples. If not
679 specified, then it will default to the set of future-import
680 flags that apply to `globs`.
681
682 The output of each example is checked using
683 `DocTestRunner.check_output`, and the results are formatted by
684 the `DocTestRunner.report_*` methods.
685 """
686 self.test = test
687
688 if compileflags is None:
689 compileflags = _extract_future_flags(test.globs)
690
691 save_stdout = sys.stdout
692 if out is None:
693 out = save_stdout.write
694 sys.stdout = self._fakeout
695
696 # Patch pdb.set_trace to restore sys.stdout during interactive
697 # debugging (so it's not still redirected to self._fakeout).
698 # Note that the interactive output will go to *our*
699 # save_stdout, even if that's not the real sys.stdout; this
700 # allows us to write test cases for the set_trace behavior.
701 save_set_trace = pdb.set_trace
702 self.debugger = _OutputRedirectingPdb(save_stdout)
703 self.debugger.reset()
704 pdb.set_trace = self.debugger.set_trace
705
706 # Patch linecache.getlines, so we can see the example's source
707 # when we're inside the debugger.
708 self.save_linecache_getlines = linecache.getlines
709 linecache.getlines = self.__patched_linecache_getlines
710
711 try:
712 return self.__run(test, compileflags, out)
713 finally:
714 sys.stdout = save_stdout
715 pdb.set_trace = save_set_trace
716 linecache.getlines = self.save_linecache_getlines
717 if clear_globs:
718 test.globs.clear()
719
720
495 class DocFileCase(doctest.DocFileCase):
721 class DocFileCase(doctest.DocFileCase):
496 """Overrides to provide filename
722 """Overrides to provide filename
497 """
723 """
@@ -514,7 +740,8 b' class ExtensionDoctest(doctests.Doctest):'
514 self.extension = tolist(options.doctestExtension)
740 self.extension = tolist(options.doctestExtension)
515 self.finder = DocTestFinder()
741 self.finder = DocTestFinder()
516 self.parser = doctest.DocTestParser()
742 self.parser = doctest.DocTestParser()
517
743 self.globs = None
744 self.extraglobs = None
518
745
519 def loadTestsFromExtensionModule(self,filename):
746 def loadTestsFromExtensionModule(self,filename):
520 bpath,mod = os.path.split(filename)
747 bpath,mod = os.path.split(filename)
@@ -529,14 +756,21 b' class ExtensionDoctest(doctests.Doctest):'
529
756
530 # NOTE: the method below is almost a copy of the original one in nose, with
757 # NOTE: the method below is almost a copy of the original one in nose, with
531 # a few modifications to control output checking.
758 # a few modifications to control output checking.
532
759
533 def loadTestsFromModule(self, module):
760 def loadTestsFromModule(self, module):
534 #print 'lTM',module # dbg
761 #print 'lTM',module # dbg
535
762
536 if not self.matches(module.__name__):
763 if not self.matches(module.__name__):
537 log.debug("Doctest doesn't want module %s", module)
764 log.debug("Doctest doesn't want module %s", module)
538 return
765 return
539 tests = self.finder.find(module)
766
767 ## try:
768 ## print 'Globs:',self.globs.keys() # dbg
769 ## except:
770 ## pass
771
772 tests = self.finder.find(module,globs=self.globs,
773 extraglobs=self.extraglobs)
540 if not tests:
774 if not tests:
541 return
775 return
542 tests.sort()
776 tests.sort()
@@ -549,12 +783,13 b' class ExtensionDoctest(doctests.Doctest):'
549 if not test.filename:
783 if not test.filename:
550 test.filename = module_file
784 test.filename = module_file
551
785
552 #yield DocTestCase(test)
786 # xxx - checker and options may be ok instantiated once outside loop
553
787
554 # always use whitespace and ellipsis options
788 # always use whitespace and ellipsis options
555 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
789 optionflags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
556 checker = IPDoctestOutputChecker()
790 checker = IPDoctestOutputChecker()
557 yield DocTestCase(test,
791
792 yield DocTestCase(test,
558 optionflags=optionflags,
793 optionflags=optionflags,
559 checker=checker)
794 checker=checker)
560
795
@@ -565,25 +800,21 b' class ExtensionDoctest(doctests.Doctest):'
565 for t in self.loadTestsFromExtensionModule(filename):
800 for t in self.loadTestsFromExtensionModule(filename):
566 yield t
801 yield t
567 else:
802 else:
568 ## for t in list(doctests.Doctest.loadTestsFromFile(self,filename)):
803 if self.extension and anyp(filename.endswith, self.extension):
569 ## yield t
804 name = os.path.basename(filename)
570 pass
805 dh = open(filename)
571
806 try:
572 if self.extension and anyp(filename.endswith, self.extension):
807 doc = dh.read()
573 name = os.path.basename(filename)
808 finally:
574 dh = open(filename)
809 dh.close()
575 try:
810 test = self.parser.get_doctest(
576 doc = dh.read()
811 doc, globs={'__file__': filename}, name=name,
577 finally:
812 filename=filename, lineno=0)
578 dh.close()
813 if test.examples:
579 test = self.parser.get_doctest(
814 #print 'FileCase:',test.examples # dbg
580 doc, globs={'__file__': filename}, name=name,
815 yield DocFileCase(test)
581 filename=filename, lineno=0)
816 else:
582 if test.examples:
817 yield False # no tests to load
583 #print 'FileCase:',test.examples # dbg
584 yield DocFileCase(test)
585 else:
586 yield False # no tests to load
587
818
588 def wantFile(self,filename):
819 def wantFile(self,filename):
589 """Return whether the given filename should be scanned for tests.
820 """Return whether the given filename should be scanned for tests.
@@ -591,7 +822,7 b' class ExtensionDoctest(doctests.Doctest):'
591 Modified version that accepts extension modules as valid containers for
822 Modified version that accepts extension modules as valid containers for
592 doctests.
823 doctests.
593 """
824 """
594 print 'Filename:',filename # dbg
825 #print 'Filename:',filename # dbg
595
826
596 # temporarily hardcoded list, will move to driver later
827 # temporarily hardcoded list, will move to driver later
597 exclude = ['IPython/external/',
828 exclude = ['IPython/external/',
@@ -626,3 +857,11 b' class IPythonDoctest(ExtensionDoctest):'
626 self.extension = tolist(options.doctestExtension)
857 self.extension = tolist(options.doctestExtension)
627 self.parser = IPDocTestParser()
858 self.parser = IPDocTestParser()
628 self.finder = DocTestFinder(parser=self.parser)
859 self.finder = DocTestFinder(parser=self.parser)
860
861 # XXX - we need to run in the ipython user's namespace, but doing so is
862 # breaking normal doctests!
863
864 #self.globs = _ip.user_ns
865 self.globs = None
866
867 self.extraglobs = None
@@ -1,4 +1,117 b''
1 def test_refs():
1 # Module imports
2 # Std lib
3 import inspect
4
5 # Third party
6
7 # Our own
8 import decorators as dec
9
10 #-----------------------------------------------------------------------------
11 # Utilities
12
13 # Note: copied from OInspect, kept here so the testing stuff doesn't create
14 # circular dependencies and is easier to reuse.
15 def getargspec(obj):
16 """Get the names and default values of a function's arguments.
17
18 A tuple of four things is returned: (args, varargs, varkw, defaults).
19 'args' is a list of the argument names (it may contain nested lists).
20 'varargs' and 'varkw' are the names of the * and ** arguments or None.
21 'defaults' is an n-tuple of the default values of the last n arguments.
22
23 Modified version of inspect.getargspec from the Python Standard
24 Library."""
25
26 if inspect.isfunction(obj):
27 func_obj = obj
28 elif inspect.ismethod(obj):
29 func_obj = obj.im_func
30 else:
31 raise TypeError, 'arg is not a Python function'
32 args, varargs, varkw = inspect.getargs(func_obj.func_code)
33 return args, varargs, varkw, func_obj.func_defaults
34
35 #-----------------------------------------------------------------------------
36 # Testing functions
37
38 def test_trivial():
39 """A trivial passing test."""
40 pass
41
42
43 @dec.skip
44 def test_deliberately_broken():
45 """A deliberately broken test - we want to skip this one."""
46 1/0
47
48
49 # Verify that we can correctly skip the doctest for a function at will, but
50 # that the docstring itself is NOT destroyed by the decorator.
51 @dec.skip_doctest
52 def doctest_bad(x,y=1,**k):
53 """A function whose doctest we need to skip.
54
55 >>> 1+1
56 3
57 """
58 z=2
59
60
61 def test_skip_dt_decorator():
62 """Doctest-skipping decorator should preserve the docstring.
63 """
64 # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
65 check = """A function whose doctest we need to skip.
66
67 >>> 1+1
68 3
69 """
70 # Fetch the docstring from doctest_bad after decoration.
71 val = doctest_bad.__doc__
72
73 assert check==val,"doctest_bad docstrings don't match"
74
75
76 def test_skip_dt_decorator2():
77 """Doctest-skipping decorator should preserve function signature.
78 """
79 # Hardcoded correct answer
80 dtargs = (['x', 'y'], None, 'k', (1,))
81 # Introspect out the value
82 dtargsr = getargspec(doctest_bad)
83 assert dtargsr==dtargs, \
84 "Incorrectly reconstructed args for doctest_bad: %s" % (dtargsr,)
85
86
87 def doctest_run():
88 """Test running a trivial script.
89
90 In [13]: run simplevars.py
91 x is: 1
92 """
93
94 #@dec.skip_doctest
95 def doctest_runvars():
96 """Test that variables defined in scripts get loaded correcly via %run.
97
98 In [13]: run simplevars.py
99 x is: 1
100
101 In [14]: x
102 Out[14]: 1
103 """
104
105 def doctest_ivars():
106 """Test that variables defined interactively are picked up.
107 In [5]: zz=1
108
109 In [6]: zz
110 Out[6]: 1
111 """
112
113 @dec.skip_doctest
114 def doctest_refs():
2 """DocTest reference holding issues when running scripts.
115 """DocTest reference holding issues when running scripts.
3
116
4 In [32]: run show_refs.py
117 In [32]: run show_refs.py
@@ -6,6 +119,4 b' def test_refs():'
6
119
7 In [33]: map(type,gc.get_referrers(c))
120 In [33]: map(type,gc.get_referrers(c))
8 Out[33]: [<type 'dict'>]
121 Out[33]: [<type 'dict'>]
9
10 """
122 """
11 pass
General Comments 0
You need to be logged in to leave comments. Login now