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
|
# mode: run
# tag: METH_FASTCALL
cimport cython
import sys
import struct
from collections import deque
pack = struct.pack
def deque_methods(v):
"""
>>> deque_methods(2)
[1, 2, 3, 4]
"""
d = deque([1, 3, 4])
assert list(d) == [1,3,4]
if sys.version_info >= (3, 5):
d.insert(1, v)
else:
# deque has no 2-args methods in older Python versions
d.rotate(-1)
d.appendleft(2)
d.rotate(1)
assert list(d) == [1,2,3,4]
d.rotate(len(d) // 2)
assert list(d) == [3,4,1,2]
d.rotate(len(d) // 2)
assert list(d) == [1,2,3,4]
return list(d)
def struct_methods(v):
"""
>>> i, lf, i2, f = struct_methods(2)
>>> struct.unpack('i', i)
(2,)
>>> struct.unpack('i', i2)
(2,)
>>> struct.unpack('lf', lf)
(2, 4.0)
>>> struct.unpack('f', f)
(2.0,)
"""
local_pack = pack
return [
struct.pack('i', v),
struct.pack('lf', v, v*2),
pack('i', v),
local_pack('f', v),
]
cdef class SelfCast:
"""
>>> f = SelfCast()
>>> f.index_of_self([f])
0
>>> f.index_of_self([]) # doctest: +ELLIPSIS
Traceback (most recent call last):
ValueError...
"""
def index_of_self(self, list orbit not None):
return orbit.index(self)
cdef extern from *:
"""
#ifdef NDEBUG
int DEBUG_MODE = 0;
#else
int DEBUG_MODE = 1;
#endif
"""
int PyCFunction_GET_FLAGS(op)
int DEBUG_MODE
def has_fastcall(meth):
"""
Given a builtin_function_or_method or cyfunction ``meth``,
return whether it uses ``METH_FASTCALL``.
"""
# Hardcode METH_FASTCALL constant equal to 0x80 for simplicity
if sys.version_info >= (3, 11) and DEBUG_MODE:
# PyCFunction_GET_FLAGS isn't safe to use on cyfunctions in
# debug mode in Python 3.11 because it does an exact type check
return True
return bool(PyCFunction_GET_FLAGS(meth) & 0x80)
def assert_fastcall(meth):
"""
Assert that ``meth`` uses ``METH_FASTCALL`` if the Python
implementation supports it.
"""
# getattr uses METH_FASTCALL on CPython >= 3.7
if has_fastcall(getattr) and not has_fastcall(meth):
raise AssertionError(f"{meth} does not use METH_FASTCALL")
@cython.binding(False)
def fastcall_function(**kw):
"""
>>> assert_fastcall(fastcall_function)
"""
return kw
@cython.binding(True)
def fastcall_cyfunction(**kw):
"""
>>> assert_fastcall(fastcall_cyfunction)
"""
return kw
cdef class Dummy:
@cython.binding(False)
def fastcall_method(self, x, *args, **kw):
"""
>>> assert_fastcall(Dummy().fastcall_method)
"""
return tuple(args) + tuple(kw)
cdef class CyDummy:
@cython.binding(True)
def fastcall_method(self, x, *args, **kw):
"""
>>> assert_fastcall(CyDummy.fastcall_method)
"""
return tuple(args) + tuple(kw)
class PyDummy:
def fastcall_method(self, x, *args, **kw):
"""
>>> assert_fastcall(PyDummy.fastcall_method)
"""
return tuple(args) + tuple(kw)
|