1# cython: binding=True 2# mode: run 3# tag: cyfunction 4 5import sys 6IS_PY2 = sys.version_info[0] < 3 7IS_PY3 = sys.version_info[0] >= 3 8IS_PY34 = sys.version_info > (3, 4, 0, 'beta', 3) 9 10 11def inspect_isroutine(): 12 """ 13 >>> inspect_isroutine() 14 True 15 """ 16 import inspect 17 return inspect.isroutine(inspect_isroutine) 18 19 20def inspect_isfunction(): 21 """ 22 >>> inspect_isfunction() 23 False 24 False 25 """ 26 import inspect, types 27 print isinstance(inspect_isfunction, types.FunctionType) 28 return inspect.isfunction(inspect_isfunction) 29 30 31def inspect_isbuiltin(): 32 """ 33 >>> inspect_isbuiltin() 34 False 35 False 36 """ 37 import inspect, types 38 print isinstance(inspect_isfunction, types.BuiltinFunctionType) 39 return inspect.isbuiltin(inspect_isbuiltin) 40 41 42def inspect_signature(a, b, c=123, *, d=234): 43 """ 44 >>> sig = inspect_signature(1, 2) 45 >>> if IS_PY34: list(sig.parameters) 46 ... else: ['a', 'b', 'c', 'd'] 47 ['a', 'b', 'c', 'd'] 48 >>> if IS_PY34: sig.parameters['c'].default == 123 49 ... else: True 50 True 51 >>> if IS_PY34: sig.parameters['d'].default == 234 52 ... else: True 53 True 54 """ 55 import inspect 56 return inspect.signature(inspect_signature) if IS_PY34 else None 57 58 59# def test___signature__(a, b, c=123, *, d=234): 60# """ 61# >>> sig = test___signature__(1, 2) 62# >>> if IS_PY34: list(sig.parameters) 63# ... else: ['a', 'b', 'c', 'd'] 64# ['a', 'b', 'c', 'd'] 65# >>> if IS_PY34: sig.parameters['c'].default == 123 66# ... else: True 67# True 68# >>> if IS_PY34: sig.parameters['d'].default == 234 69# ... else: True 70# True 71# """ 72# return inspect_signature.__signature__ if IS_PY34 else None 73 74 75def test_dict(): 76 """ 77 >>> test_dict.foo = 123 78 >>> test_dict.__dict__ 79 {'foo': 123} 80 >>> test_dict.__dict__ = {'bar': 321} 81 >>> test_dict.__dict__ 82 {'bar': 321} 83 >>> test_dict.func_dict 84 {'bar': 321} 85 """ 86 87def test_name(): 88 """ 89 >>> test_name.__name__ 90 'test_name' 91 >>> test_name.func_name 92 'test_name' 93 >>> test_name.__name__ = 123 #doctest:+ELLIPSIS 94 Traceback (most recent call last): 95 TypeError: __name__ must be set to a ... object 96 >>> test_name.__name__ = 'foo' 97 >>> test_name.__name__ 98 'foo' 99 """ 100 101def test_doc(): 102 """ 103 >>> del test_doc.__doc__ 104 >>> test_doc.__doc__ 105 >>> test_doc.__doc__ = 'docstring' 106 >>> test_doc.__doc__ 107 'docstring' 108 >>> test_doc.func_doc 109 'docstring' 110 """ 111 112 113def test_hash(): 114 """ 115 >>> d = {test_hash: 123} 116 >>> test_hash in d 117 True 118 >>> d[test_hash] 119 123 120 >>> hash(test_hash) == hash(test_hash) 121 True 122 """ 123 124 125def test_closure(): 126 """ 127 >>> test_closure.func_closure is None 128 True 129 """ 130 131def test_globals(): 132 """ 133 >>> test_globals.func_globals is not None 134 True 135 >>> 'test_globals' in test_globals.func_globals or test_globals.func_globals 136 True 137 >>> 'test_name' in test_globals.func_globals or test_globals.func_globals 138 True 139 >>> 'not there' not in test_globals.func_globals or test_globals.func_globals 140 True 141 >>> try: test_globals.func_globals = {} 142 ... except (AttributeError, TypeError): pass 143 ... else: assert 0, 'FAILED' 144 """ 145 146def test_reduce(): 147 """ 148 >>> import pickle 149 >>> pickle.loads(pickle.dumps(test_reduce))() 150 'Hello, world!' 151 """ 152 return 'Hello, world!' 153 154def test_method(self): 155 return self 156 157class BindingTest: 158 """ 159 >>> BindingTest.test_method = test_method 160 >>> BindingTest.test_method() #doctest:+ELLIPSIS 161 Traceback (most recent call last): 162 TypeError: ... 163 >>> BindingTest().test_method() 164 <BindingTest instance> 165 """ 166 def __repr__(self): 167 return '<BindingTest instance>' 168 169 170def codeof(func): 171 if IS_PY3: 172 return func.__code__ 173 else: 174 return func.func_code 175 176def varnamesof(func): 177 code = codeof(func) 178 varnames = code.co_varnames 179 if sys.version_info < (2,5): 180 pos = {'a':0, 'x':1, 'b':2, 'l':3, 'm':4} 181 varnames = tuple(sorted(varnames, key=pos.__getitem__)) 182 return varnames 183 184def namesof(func): 185 code = codeof(func) 186 names = code.co_names 187 if sys.version_info < (2,5): 188 names = () 189 return names 190 191def cy_no_arg(): 192 l = m = 1 193def cy_one_arg(a): 194 l = m = 1 195def cy_two_args(x, b): 196 l = m = 1 197def cy_default_args(x=1, b=2): 198 l = m = 1 199 200def test_code(): 201 """ 202 >>> def no_arg(): l = m = 1 203 >>> def one_arg(a): l = m = 1 204 >>> def two_args(x, b): l = m = 1 205 >>> def default_args(x=1, b=2): l = m = 1 206 207 >>> codeof(no_arg).co_argcount 208 0 209 >>> codeof(cy_no_arg).co_argcount 210 0 211 >>> print(codeof(no_arg).co_name) 212 no_arg 213 >>> print(codeof(cy_no_arg).co_name) 214 cy_no_arg 215 >>> namesof(no_arg) 216 () 217 >>> codeof(cy_no_arg).co_names 218 () 219 >>> varnamesof(no_arg) 220 ('l', 'm') 221 >>> codeof(cy_no_arg).co_varnames 222 ('l', 'm') 223 224 >>> codeof(one_arg).co_argcount 225 1 226 >>> codeof(cy_one_arg).co_argcount 227 1 228 >>> print(codeof(one_arg).co_name) 229 one_arg 230 >>> print(codeof(cy_one_arg).co_name) 231 cy_one_arg 232 >>> namesof(one_arg) 233 () 234 >>> codeof(cy_one_arg).co_names 235 () 236 >>> varnamesof(one_arg) 237 ('a', 'l', 'm') 238 >>> codeof(cy_one_arg).co_varnames 239 ('a', 'l', 'm') 240 241 >>> codeof(two_args).co_argcount 242 2 243 >>> codeof(cy_two_args).co_argcount 244 2 245 >>> namesof(two_args) 246 () 247 >>> codeof(cy_two_args).co_names 248 () 249 >>> varnamesof(two_args) 250 ('x', 'b', 'l', 'm') 251 >>> codeof(cy_two_args).co_varnames 252 ('x', 'b', 'l', 'm') 253 254 >>> codeof(default_args).co_argcount 255 2 256 >>> codeof(cy_default_args).co_argcount 257 2 258 >>> namesof(default_args) 259 () 260 >>> codeof(cy_default_args).co_names 261 () 262 >>> varnamesof(default_args) 263 ('x', 'b', 'l', 'm') 264 >>> codeof(cy_default_args).co_varnames 265 ('x', 'b', 'l', 'm') 266 """ 267 268 269def test_annotations(a: "test", b: "other" = 2, c: 123 = 4) -> "ret": 270 """ 271 >>> isinstance(test_annotations.__annotations__, dict) 272 True 273 >>> sorted(test_annotations.__annotations__.items()) 274 [('a', 'test'), ('b', 'other'), ('c', 123), ('return', 'ret')] 275 276 >>> def func_b(): return 42 277 >>> def func_c(): return 99 278 >>> inner = test_annotations(1, func_b, func_c) 279 >>> sorted(inner.__annotations__.items()) 280 [('return', 99), ('x', 'banana'), ('y', 42)] 281 282 >>> inner.__annotations__ = {234: 567} 283 >>> inner.__annotations__ 284 {234: 567} 285 >>> inner.__annotations__ = None 286 >>> inner.__annotations__ 287 {} 288 >>> inner.__annotations__ = 321 289 Traceback (most recent call last): 290 TypeError: __annotations__ must be set to a dict object 291 >>> inner.__annotations__ 292 {} 293 294 >>> inner = test_annotations(1, func_b, func_c) 295 >>> sorted(inner.__annotations__.items()) 296 [('return', 99), ('x', 'banana'), ('y', 42)] 297 >>> inner.__annotations__['abc'] = 66 298 >>> sorted(inner.__annotations__.items()) 299 [('abc', 66), ('return', 99), ('x', 'banana'), ('y', 42)] 300 301 >>> inner = test_annotations(1, func_b, func_c) 302 >>> sorted(inner.__annotations__.items()) 303 [('return', 99), ('x', 'banana'), ('y', 42)] 304 """ 305 def inner(x: "banana", y: b()) -> c(): 306 return x,y 307 return inner 308 309 310def add_one(func): 311 "Decorator to add 1 to the last argument of the function call" 312 def inner(*args): 313 args = args[:-1] + (args[-1] + 1,) 314 return func(*args) 315 return inner 316 317@add_one 318def test_decorated(x): 319 """ 320 >>> test_decorated(0) 321 1 322 """ 323 return x 324 325@add_one 326@add_one 327def test_decorated2(x): 328 """ 329 >>> test_decorated2(0) 330 2 331 """ 332 return x 333 334 335cdef class TestDecoratedMethods: 336 @add_one 337 def test(self, x): 338 """ 339 >>> TestDecoratedMethods().test(0) 340 1 341 """ 342 return x 343 344 @add_one 345 @add_one 346 def test2(self, x): 347 """ 348 >>> TestDecoratedMethods().test2(0) 349 2 350 """ 351 return x 352 353 def test_calls(self, x): 354 """ 355 >>> TestDecoratedMethods().test_calls(2) 356 25 357 """ 358 return self.test(x) + self.test2(x*10) 359 360 361cdef class TestUnboundMethodCdef: 362 """ 363 >>> C = TestUnboundMethodCdef 364 >>> IS_PY2 or (C.meth is C.__dict__["meth"]) 365 True 366 """ 367 def meth(self): pass 368 369 370class TestUnboundMethod: 371 """ 372 >>> C = TestUnboundMethod 373 >>> IS_PY2 or (C.meth is C.__dict__["meth"]) 374 True 375 """ 376 def meth(self): pass 377 378 379cdef class TestOptimisedBuiltinMethod: 380 """ 381 >>> obj = TestOptimisedBuiltinMethod() 382 >>> obj.append(2) 383 3 384 >>> obj.call(2) 385 4 386 >>> obj.call(3, obj) 387 5 388 """ 389 def append(self, arg): 390 print(arg+1) 391 392 def call(self, arg, obj=None): 393 (obj or self).append(arg+1) # optimistically optimised => uses fast fallback method call 394