3
3
# pylint: disable-msg=W0402
4
4
5
5
from datetime import datetime
6
+ from functools import wraps
6
7
import random
7
8
import string
8
9
import sys
12
13
from contextlib import contextmanager # contextlib is available since 2.5
13
14
14
15
from distutils .version import LooseVersion
16
+ import urllib2
17
+ import nose
15
18
16
19
from numpy .random import randn
17
20
import numpy as np
36
39
37
40
N = 30
38
41
K = 4
39
-
42
+ _RAISE_NETWORK_ERROR_DEFAULT = False
40
43
41
44
def rands (n ):
42
45
choices = string .ascii_letters + string .digits
@@ -663,18 +666,51 @@ def skip_if_no_package(*args, **kwargs):
663
666
# Additional tags decorators for nose
664
667
#
665
668
669
+ def optional_args (decorator ):
670
+ """allows a decorator to take optional positional and keyword arguments.
671
+ Assumes that taking a single, callable, positional argument means that
672
+ it is decorating a function, i.e. something like this::
673
+
674
+ @my_decorator
675
+ def function(): pass
676
+
677
+ Calls decorator with decorator(f, *args, **kwargs)"""
678
+ @wraps (decorator )
679
+ def wrapper (* args , ** kwargs ):
680
+ def dec (f ):
681
+ return decorator (f , * args , ** kwargs )
682
+ is_decorating = not kwargs and len (args ) == 1 and callable (args [0 ])
683
+ if is_decorating :
684
+ f = args [0 ]
685
+ args = []
686
+ return dec (f )
687
+ else :
688
+ return dec
689
+ return wrapper
666
690
667
- def network (t ):
691
+ @optional_args
692
+ def network (t , raise_on_error = _RAISE_NETWORK_ERROR_DEFAULT ,
693
+ error_classes = (IOError ,)):
668
694
"""
669
- Label a test as requiring network connection.
695
+ Label a test as requiring network connection and skip test if it encounters a ``URLError`` .
670
696
671
697
In some cases it is not possible to assume network presence (e.g. Debian
672
698
build hosts).
673
699
700
+ You can pass an optional ``raise_on_error`` argument to the decorator, in
701
+ which case it will always raise an error even if it's not a subclass of
702
+ ``error_classes``.
703
+
674
704
Parameters
675
705
----------
676
706
t : callable
677
707
The test requiring network connectivity.
708
+ raise_on_error : bool
709
+ If True, never catches errors.
710
+ error_classes : iterable
711
+ error classes to ignore. If not in ``error_classes``, raises the error.
712
+ defaults to URLError. Be careful about changing the error classes here,
713
+ it may result in undefined behavior.
678
714
679
715
Returns
680
716
-------
@@ -685,19 +721,46 @@ def network(t):
685
721
--------
686
722
A test can be decorated as requiring network like this::
687
723
688
- from pandas.util.testing import *
689
-
690
- @network
691
- def test_network(self):
692
- print 'Fetch the stars from http://'
724
+ >>> from pandas.util.testing import network
725
+ >>> import urllib2
726
+ >>> @network
727
+ ... def test_network():
728
+ ... urllib2.urlopen("rabbit://bonanza.com")
729
+ ...
730
+ >>> try:
731
+ ... test_network()
732
+ ... except nose.SkipTest:
733
+ ... print "SKIPPING!"
734
+ ...
735
+ SKIPPING!
736
+
737
+ Alternatively, you can use set ``raise_on_error`` in order to get
738
+ the error to bubble up, e.g.::
739
+
740
+ >>> @network(raise_on_error=True)
741
+ ... def test_network():
742
+ ... urllib2.urlopen("complaint://deadparrot.com")
743
+ ...
744
+ >>> test_network()
745
+ Traceback (most recent call last):
746
+ ...
747
+ URLError: <urlopen error unknown url type: complaint>
693
748
694
749
And use ``nosetests -a '!network'`` to exclude running tests requiring
695
- network connectivity.
750
+ network connectivity. ``_RAISE_NETWORK_ERROR_DEFAULT`` in
751
+ ``pandas/util/testing.py`` sets the default behavior (currently False).
696
752
"""
697
-
698
753
t .network = True
699
- return t
700
-
754
+ @wraps (t )
755
+ def network_wrapper (* args , ** kwargs ):
756
+ if raise_on_error :
757
+ return t (* args , ** kwargs )
758
+ else :
759
+ try :
760
+ return t (* args , ** kwargs )
761
+ except error_classes as e :
762
+ raise nose .SkipTest ("Skipping test %s" % e )
763
+ return network_wrapper
701
764
702
765
class SimpleMock (object ):
703
766
"""
0 commit comments