File: test_decorators.py

package info (click to toggle)
ipython 9.8.0-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 8,624 kB
  • sloc: python: 45,268; sh: 317; makefile: 168
file content (154 lines) | stat: -rw-r--r-- 3,663 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
"""Tests for the decorators we've created for IPython."""

# Module imports
# Std lib
import inspect
import sys

# Our own
from IPython.testing import decorators as dec
from IPython.testing.skipdoctest import skip_doctest
from IPython.utils.text import dedent

# -----------------------------------------------------------------------------
# Utilities


# Note: copied from OInspect, kept here so the testing stuff doesn't create
# circular dependencies and is easier to reuse.
def getargspec(obj):
    """Get the names and default values of a function's arguments.

    A tuple of four things is returned: (args, varargs, varkw, defaults).
    'args' is a list of the argument names (it may contain nested lists).
    'varargs' and 'varkw' are the names of the * and ** arguments or None.
    'defaults' is an n-tuple of the default values of the last n arguments.

    Modified version of inspect.getargspec from the Python Standard
    Library."""

    if inspect.isfunction(obj):
        func_obj = obj
    elif inspect.ismethod(obj):
        func_obj = obj.__func__
    else:
        raise TypeError("arg is not a Python function")
    args, varargs, varkw = inspect.getargs(func_obj.__code__)
    return args, varargs, varkw, func_obj.__defaults__


# -----------------------------------------------------------------------------
# Testing functions


def test_trivial():
    """A trivial test"""
    pass


@dec.skip()
def test_deliberately_broken():
    """A deliberately broken test - we want to skip this one."""
    1 / 0


@dec.skip("Testing the skip decorator")
def test_deliberately_broken2():
    """Another deliberately broken test - we want to skip this one."""
    1 / 0


# Verify that we can correctly skip the doctest for a function at will, but
# that the docstring itself is NOT destroyed by the decorator.
@skip_doctest
def doctest_bad(x, y=1, **k):
    """A function whose doctest we need to skip.

    >>> 1+1
    3
    """
    print("x:", x)
    print("y:", y)
    print("k:", k)


def call_doctest_bad():
    """Check that we can still call the decorated functions.

    >>> doctest_bad(3,y=4)
    x: 3
    y: 4
    k: {}
    """
    pass


def test_skip_dt_decorator():
    """Doctest-skipping decorator should preserve the docstring."""
    # Careful: 'check' must be a *verbatim* copy of the doctest_bad docstring!
    check = """A function whose doctest we need to skip.

    >>> 1+1
    3
    """

    # Fetch the docstring from doctest_bad after decoration.
    val = doctest_bad.__doc__

    assert dedent(check) == dedent(val), "doctest_bad docstrings don't match"


# Doctest skipping should work for class methods too
class FooClass(object):
    """FooClass

    Example:

    >>> 1+1
    2
    """

    @skip_doctest
    def __init__(self, x):
        """Make a FooClass.

        Example:

        >>> f = FooClass(3)
        junk
        """
        print("Making a FooClass.")
        self.x = x

    @skip_doctest
    def bar(self, y):
        """Example:

        >>> ff = FooClass(3)
        >>> ff.bar(0)
        boom!
        >>> 1/0
        bam!
        """
        return 1 / y

    def baz(self, y):
        """Example:

        >>> ff2 = FooClass(3)
        Making a FooClass.
        >>> ff2.baz(3)
        True
        """
        return self.x == y


def test_skip_dt_decorator2():
    """Doctest-skipping decorator should preserve function signature."""
    # Hardcoded correct answer
    dtargs = (["x", "y"], None, "k", (1,))
    # Introspect out the value
    dtargsr = getargspec(doctest_bad)
    assert dtargsr == dtargs, "Incorrectly reconstructed args for doctest_bad: %s" % (
        dtargsr,
    )