cyfunction.pyx 7.75 KB
Newer Older
Vitja Makarov's avatar
Vitja Makarov committed
1 2 3 4
# cython: binding=True
# mode: run
# tag: cyfunction

5 6
import sys
IS_PY3 = sys.version_info[0] >= 3
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
IS_PY34 = sys.version_info > (3, 4, 0, 'beta', 3)


def inspect_isroutine():
    """
    >>> inspect_isroutine()
    True
    """
    import inspect
    return inspect.isroutine(inspect_isroutine)


def inspect_isfunction():
    """
    >>> inspect_isfunction()
    False
    False
    """
    import inspect, types
    print isinstance(inspect_isfunction, types.FunctionType)
    return inspect.isfunction(inspect_isfunction)


def inspect_isbuiltin():
    """
    >>> inspect_isbuiltin()
    False
    False
    """
    import inspect, types
    print isinstance(inspect_isfunction, types.BuiltinFunctionType)
    return inspect.isbuiltin(inspect_isbuiltin)


def inspect_signature(a, b, c=123, *, d=234):
    """
    >>> sig = inspect_signature(1, 2)
    >>> if IS_PY34: list(sig.parameters)
    ... else: ['a', 'b', 'c', 'd']
    ['a', 'b', 'c', 'd']
    >>> if IS_PY34: sig.parameters['c'].default == 123
    ... else: True
    True
    >>> if IS_PY34: sig.parameters['d'].default == 234
    ... else: True
    True
    """
    import inspect
    return inspect.signature(inspect_signature) if IS_PY34 else None

57

58 59 60 61 62 63 64 65 66 67 68 69 70 71
# def test___signature__(a, b, c=123, *, d=234):
#     """
#     >>> sig = test___signature__(1, 2)
#     >>> if IS_PY34: list(sig.parameters)
#     ... else: ['a', 'b', 'c', 'd']
#     ['a', 'b', 'c', 'd']
#     >>> if IS_PY34: sig.parameters['c'].default == 123
#     ... else: True
#     True
#     >>> if IS_PY34: sig.parameters['d'].default == 234
#     ... else: True
#     True
#     """
#     return inspect_signature.__signature__ if IS_PY34 else None
72 73


Vitja Makarov's avatar
Vitja Makarov committed
74 75 76 77 78
def test_dict():
    """
    >>> test_dict.foo = 123
    >>> test_dict.__dict__
    {'foo': 123}
Vitja Makarov's avatar
Vitja Makarov committed
79 80 81 82 83
    >>> test_dict.__dict__ = {'bar': 321}
    >>> test_dict.__dict__
    {'bar': 321}
    >>> test_dict.func_dict
    {'bar': 321}
Vitja Makarov's avatar
Vitja Makarov committed
84 85 86 87 88 89
    """

def test_name():
    """
    >>> test_name.__name__
    'test_name'
Vitja Makarov's avatar
Vitja Makarov committed
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
    >>> test_name.func_name
    'test_name'
    >>> test_name.__name__ = 123 #doctest:+ELLIPSIS
    Traceback (most recent call last):
    TypeError: __name__ must be set to a ... object
    >>> test_name.__name__ = 'foo'
    >>> test_name.__name__
    'foo'
    """

def test_doc():
    """
    >>> del test_doc.__doc__
    >>> test_doc.__doc__
    >>> test_doc.__doc__ = 'docstring'
    >>> test_doc.__doc__
    'docstring'
    >>> test_doc.func_doc
    'docstring'
Vitja Makarov's avatar
Vitja Makarov committed
109 110
    """

111 112 113 114 115 116 117 118 119 120 121 122 123

def test_hash():
    """
    >>> d = {test_hash: 123}
    >>> test_hash in d
    True
    >>> d[test_hash]
    123
    >>> hash(test_hash) == hash(test_hash)
    True
    """


124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
def test_closure():
    """
    >>> test_closure.func_closure is None
    True
    """

def test_globals():
    """
    >>> test_globals.func_globals is not None
    True
    >>> 'test_globals' in test_globals.func_globals or test_globals.func_globals
    True
    >>> 'test_name' in test_globals.func_globals or test_globals.func_globals
    True
    >>> 'not there' not in test_globals.func_globals or test_globals.func_globals
    True
    >>> try: test_globals.func_globals = {}
    ... except (AttributeError, TypeError): pass
    ... else: assert 0, 'FAILED'
    """

Vitja Makarov's avatar
Vitja Makarov committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
def test_reduce():
    """
    >>> import pickle
    >>> pickle.loads(pickle.dumps(test_reduce))()
    'Hello, world!'
    """
    return 'Hello, world!'

def test_method(self):
    return self

class BindingTest:
    """
    >>> BindingTest.test_method = test_method
    >>> BindingTest.test_method() #doctest:+ELLIPSIS
    Traceback (most recent call last):
    TypeError: ...
    >>> BindingTest().test_method()
    <BindingTest instance>
    """
    def __repr__(self):
        return '<BindingTest instance>'
167 168 169 170 171 172 173 174


def codeof(func):
    if IS_PY3:
        return func.__code__
    else:
        return func.func_code

Stefan Behnel's avatar
Stefan Behnel committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
def varnamesof(func):
    code = codeof(func)
    varnames = code.co_varnames
    if sys.version_info < (2,5):
        pos = {'a':0, 'x':1, 'b':2, 'l':3, 'm':4}
        varnames = tuple(sorted(varnames, key=pos.__getitem__))
    return varnames

def namesof(func):
    code = codeof(func)
    names = code.co_names
    if sys.version_info < (2,5):
        names = ()
    return names

190
def cy_no_arg():
191
    l = m = 1
192
def cy_one_arg(a):
193
    l = m = 1
194
def cy_two_args(x, b):
195
    l = m = 1
196
def cy_default_args(x=1, b=2):
197
    l = m = 1
198 199 200

def test_code():
    """
201 202 203 204
    >>> def no_arg(): l = m = 1
    >>> def one_arg(a): l = m = 1
    >>> def two_args(x, b): l = m = 1
    >>> def default_args(x=1, b=2): l = m = 1
205 206 207 208 209 210 211 212 213

    >>> codeof(no_arg).co_argcount
    0
    >>> codeof(cy_no_arg).co_argcount
    0
    >>> print(codeof(no_arg).co_name)
    no_arg
    >>> print(codeof(cy_no_arg).co_name)
    cy_no_arg
Stefan Behnel's avatar
Stefan Behnel committed
214
    >>> namesof(no_arg)
215
    ()
216
    >>> codeof(cy_no_arg).co_names
217
    ()
Stefan Behnel's avatar
Stefan Behnel committed
218
    >>> varnamesof(no_arg)
219 220 221
    ('l', 'm')
    >>> codeof(cy_no_arg).co_varnames
    ('l', 'm')
222 223 224 225 226 227 228 229 230

    >>> codeof(one_arg).co_argcount
    1
    >>> codeof(cy_one_arg).co_argcount
    1
    >>> print(codeof(one_arg).co_name)
    one_arg
    >>> print(codeof(cy_one_arg).co_name)
    cy_one_arg
Stefan Behnel's avatar
Stefan Behnel committed
231
    >>> namesof(one_arg)
232 233 234
    ()
    >>> codeof(cy_one_arg).co_names
    ()
Stefan Behnel's avatar
Stefan Behnel committed
235
    >>> varnamesof(one_arg)
236
    ('a', 'l', 'm')
237
    >>> codeof(cy_one_arg).co_varnames
238
    ('a', 'l', 'm')
239 240 241 242 243

    >>> codeof(two_args).co_argcount
    2
    >>> codeof(cy_two_args).co_argcount
    2
Stefan Behnel's avatar
Stefan Behnel committed
244
    >>> namesof(two_args)
245 246 247
    ()
    >>> codeof(cy_two_args).co_names
    ()
Stefan Behnel's avatar
Stefan Behnel committed
248
    >>> varnamesof(two_args)
249
    ('x', 'b', 'l', 'm')
250
    >>> codeof(cy_two_args).co_varnames
251
    ('x', 'b', 'l', 'm')
252 253 254 255 256

    >>> codeof(default_args).co_argcount
    2
    >>> codeof(cy_default_args).co_argcount
    2
Stefan Behnel's avatar
Stefan Behnel committed
257
    >>> namesof(default_args)
258 259 260
    ()
    >>> codeof(cy_default_args).co_names
    ()
Stefan Behnel's avatar
Stefan Behnel committed
261
    >>> varnamesof(default_args)
262
    ('x', 'b', 'l', 'm')
263
    >>> codeof(cy_default_args).co_varnames
264
    ('x', 'b', 'l', 'm')
265
    """
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306


def test_annotations(a: "test", b: "other" = 2, c: 123 = 4) -> "ret":
    """
    >>> isinstance(test_annotations.__annotations__, dict)
    True
    >>> sorted(test_annotations.__annotations__.items())
    [('a', 'test'), ('b', 'other'), ('c', 123), ('return', 'ret')]

    >>> def func_b(): return 42
    >>> def func_c(): return 99
    >>> inner = test_annotations(1, func_b, func_c)
    >>> sorted(inner.__annotations__.items())
    [('return', 99), ('x', 'banana'), ('y', 42)]

    >>> inner.__annotations__ = {234: 567}
    >>> inner.__annotations__
    {234: 567}
    >>> inner.__annotations__ = None
    >>> inner.__annotations__
    {}
    >>> inner.__annotations__ = 321
    Traceback (most recent call last):
    TypeError: __annotations__ must be set to a dict object
    >>> inner.__annotations__
    {}

    >>> inner = test_annotations(1, func_b, func_c)
    >>> sorted(inner.__annotations__.items())
    [('return', 99), ('x', 'banana'), ('y', 42)]
    >>> inner.__annotations__['abc'] = 66
    >>> sorted(inner.__annotations__.items())
    [('abc', 66), ('return', 99), ('x', 'banana'), ('y', 42)]

    >>> inner = test_annotations(1, func_b, func_c)
    >>> sorted(inner.__annotations__.items())
    [('return', 99), ('x', 'banana'), ('y', 42)]
    """
    def inner(x: "banana", y: b()) -> c():
        return x,y
    return inner
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350


def add_one(func):
    "Decorator to add 1 to the last argument of the function call"
    def inner(*args):
        args = args[:-1] + (args[-1] + 1,)
        return func(*args)
    return inner

@add_one
def test_decorated(x):
    """
    >>> test_decorated(0)
    1
    """
    return x

@add_one
@add_one
def test_decorated2(x):
    """
    >>> test_decorated2(0)
    2
    """
    return x


cdef class TestDecoratedMethods:
    @add_one
    def test(self, x):
        """
        >>> TestDecoratedMethods().test(0)
        1
        """
        return x

    @add_one
    @add_one
    def test2(self, x):
        """
        >>> TestDecoratedMethods().test2(0)
        2
        """
        return x