# # Tables describing slots in the CPython type object # and associated know-how. # from __future__ import absolute_import from . import Naming from . import PyrexTypes from .Errors import error invisible = ['__cinit__', '__dealloc__', '__richcmp__', '__nonzero__', '__bool__'] richcmp_special_methods = ['__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'] class Signature(object): # Method slot signature descriptor. # # has_dummy_arg boolean # has_generic_args boolean # fixed_arg_format string # ret_format string # error_value string # # The formats are strings made up of the following # characters: # # 'O' Python object # 'T' Python object of the type of 'self' # 'v' void # 'p' void * # 'P' void ** # 'i' int # 'b' bint # 'I' int * # 'l' long # 'f' float # 'd' double # 'h' Py_hash_t # 'z' Py_ssize_t # 'Z' Py_ssize_t * # 's' char * # 'S' char ** # 'r' int used only to signal exception # 'B' Py_buffer * # '-' dummy 'self' argument (not used) # '*' rest of args passed as generic Python # arg tuple and kw dict (must be last # char in format string) format_map = { 'O': PyrexTypes.py_object_type, 'v': PyrexTypes.c_void_type, 'p': PyrexTypes.c_void_ptr_type, 'P': PyrexTypes.c_void_ptr_ptr_type, 'i': PyrexTypes.c_int_type, 'b': PyrexTypes.c_bint_type, 'I': PyrexTypes.c_int_ptr_type, 'l': PyrexTypes.c_long_type, 'f': PyrexTypes.c_float_type, 'd': PyrexTypes.c_double_type, 'h': PyrexTypes.c_py_hash_t_type, 'z': PyrexTypes.c_py_ssize_t_type, 'Z': PyrexTypes.c_py_ssize_t_ptr_type, 's': PyrexTypes.c_char_ptr_type, 'S': PyrexTypes.c_char_ptr_ptr_type, 'r': PyrexTypes.c_returncode_type, 'B': PyrexTypes.c_py_buffer_ptr_type, # 'T', '-' and '*' are handled otherwise # and are not looked up in here } type_to_format_map = dict( (type_, format_) for format_, type_ in format_map.items()) error_value_map = { 'O': "NULL", 'T': "NULL", 'i': "-1", 'b': "-1", 'l': "-1", 'r': "-1", 'h': "-1", 'z': "-1", } def __init__(self, arg_format, ret_format): self.has_dummy_arg = 0 self.has_generic_args = 0 if arg_format[:1] == '-': self.has_dummy_arg = 1 arg_format = arg_format[1:] if arg_format[-1:] == '*': self.has_generic_args = 1 arg_format = arg_format[:-1] self.fixed_arg_format = arg_format self.ret_format = ret_format self.error_value = self.error_value_map.get(ret_format, None) self.exception_check = ret_format != 'r' and self.error_value is not None self.is_staticmethod = False def __repr__(self): return '' % ( self.ret_format, ', '.join(self.fixed_arg_format), '*' if self.has_generic_args else '') def num_fixed_args(self): return len(self.fixed_arg_format) def is_self_arg(self, i): # argument is 'self' for methods or 'class' for classmethods return self.fixed_arg_format[i] == 'T' def returns_self_type(self): # return type is same as 'self' argument type return self.ret_format == 'T' def fixed_arg_type(self, i): return self.format_map[self.fixed_arg_format[i]] def return_type(self): return self.format_map[self.ret_format] def format_from_type(self, arg_type): if arg_type.is_pyobject: arg_type = PyrexTypes.py_object_type return self.type_to_format_map[arg_type] def exception_value(self): return self.error_value_map.get(self.ret_format) def function_type(self, self_arg_override=None): # Construct a C function type descriptor for this signature args = [] for i in range(self.num_fixed_args()): if self_arg_override is not None and self.is_self_arg(i): assert isinstance(self_arg_override, PyrexTypes.CFuncTypeArg) args.append(self_arg_override) else: arg_type = self.fixed_arg_type(i) args.append(PyrexTypes.CFuncTypeArg("", arg_type, None)) if self_arg_override is not None and self.returns_self_type(): ret_type = self_arg_override.type else: ret_type = self.return_type() exc_value = self.exception_value() return PyrexTypes.CFuncType( ret_type, args, exception_value=exc_value, exception_check=self.exception_check) def method_flags(self): if self.ret_format == "O": full_args = self.fixed_arg_format if self.has_dummy_arg: full_args = "O" + full_args if full_args in ["O", "T"]: if self.has_generic_args: return [method_varargs, method_keywords] else: return [method_noargs] elif full_args in ["OO", "TO"] and not self.has_generic_args: return [method_onearg] if self.is_staticmethod: return [method_varargs, method_keywords] return None class SlotDescriptor(object): # Abstract base class for type slot descriptors. # # slot_name string Member name of the slot in the type object # is_initialised_dynamically Is initialised by code in the module init function # is_inherited Is inherited by subtypes (see PyType_Ready()) # py3 Indicates presence of slot in Python 3 # py2 Indicates presence of slot in Python 2 # ifdef Full #ifdef string that slot is wrapped in. Using this causes py3, py2 and flags to be ignored.) def __init__(self, slot_name, dynamic=False, inherited=False, py3=True, py2=True, ifdef=None): self.slot_name = slot_name self.is_initialised_dynamically = dynamic self.is_inherited = inherited self.ifdef = ifdef self.py3 = py3 self.py2 = py2 def preprocessor_guard_code(self): ifdef = self.ifdef py2 = self.py2 py3 = self.py3 guard = None if ifdef: guard = ("#if %s" % ifdef) elif not py3 or py3 == '': guard = ("#if PY_MAJOR_VERSION < 3") elif not py2: guard = ("#if PY_MAJOR_VERSION >= 3") return guard def generate(self, scope, code): preprocessor_guard = self.preprocessor_guard_code() if preprocessor_guard: code.putln(preprocessor_guard) end_pypy_guard = False if self.is_initialised_dynamically: value = "0" else: value = self.slot_code(scope) if value == "0" and self.is_inherited: # PyPy currently has a broken PyType_Ready() that fails to # inherit some slots. To work around this, we explicitly # set inherited slots here, but only in PyPy since CPython # handles this better than we do. inherited_value = value current_scope = scope while (inherited_value == "0" and current_scope.parent_type and current_scope.parent_type.base_type and current_scope.parent_type.base_type.scope): current_scope = current_scope.parent_type.base_type.scope inherited_value = self.slot_code(current_scope) if inherited_value != "0": code.putln("#if CYTHON_COMPILING_IN_PYPY") code.putln("%s, /*%s*/" % (inherited_value, self.slot_name)) code.putln("#else") end_pypy_guard = True code.putln("%s, /*%s*/" % (value, self.slot_name)) if end_pypy_guard: code.putln("#endif") if self.py3 == '': code.putln("#else") code.putln("0, /*reserved*/") if preprocessor_guard: code.putln("#endif") # Some C implementations have trouble statically # initialising a global with a pointer to an extern # function, so we initialise some of the type slots # in the module init function instead. def generate_dynamic_init_code(self, scope, code): if self.is_initialised_dynamically: value = self.slot_code(scope) if value != "0": code.putln("%s.%s = %s;" % ( scope.parent_type.typeobj_cname, self.slot_name, value ) ) class FixedSlot(SlotDescriptor): # Descriptor for a type slot with a fixed value. # # value string def __init__(self, slot_name, value, py3=True, py2=True, ifdef=None): SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2, ifdef=ifdef) self.value = value def slot_code(self, scope): return self.value class EmptySlot(FixedSlot): # Descriptor for a type slot whose value is always 0. def __init__(self, slot_name, py3=True, py2=True, ifdef=None): FixedSlot.__init__(self, slot_name, "0", py3=py3, py2=py2, ifdef=ifdef) class MethodSlot(SlotDescriptor): # Type slot descriptor for a user-definable method. # # signature Signature # method_name string The __xxx__ name of the method # alternatives [string] Alternative list of __xxx__ names for the method def __init__(self, signature, slot_name, method_name, fallback=None, py3=True, py2=True, ifdef=None, inherited=True): SlotDescriptor.__init__(self, slot_name, py3=py3, py2=py2, ifdef=ifdef, inherited=inherited) self.signature = signature self.slot_name = slot_name self.method_name = method_name self.alternatives = [] method_name_to_slot[method_name] = self # if fallback: self.alternatives.append(fallback) for alt in (self.py2, self.py3): if isinstance(alt, (tuple, list)): slot_name, method_name = alt self.alternatives.append(method_name) method_name_to_slot[method_name] = self def slot_code(self, scope): entry = scope.lookup_here(self.method_name) if entry and entry.is_special and entry.func_cname: return entry.func_cname for method_name in self.alternatives: entry = scope.lookup_here(method_name) if entry and entry.is_special and entry.func_cname: return entry.func_cname return "0" class InternalMethodSlot(SlotDescriptor): # Type slot descriptor for a method which is always # synthesized by Cython. # # slot_name string Member name of the slot in the type object def __init__(self, slot_name, **kargs): SlotDescriptor.__init__(self, slot_name, **kargs) def slot_code(self, scope): return scope.mangle_internal(self.slot_name) class GCDependentSlot(InternalMethodSlot): # Descriptor for a slot whose value depends on whether # the type participates in GC. def __init__(self, slot_name, **kargs): InternalMethodSlot.__init__(self, slot_name, **kargs) def slot_code(self, scope): if not scope.needs_gc(): return "0" if not scope.has_cyclic_pyobject_attrs: # if the type does not have GC relevant object attributes, it can # delegate GC methods to its parent - iff the parent functions # are defined in the same module parent_type_scope = scope.parent_type.base_type.scope if scope.parent_scope is parent_type_scope.parent_scope: entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) if entry.visibility != 'extern': return self.slot_code(parent_type_scope) return InternalMethodSlot.slot_code(self, scope) class GCClearReferencesSlot(GCDependentSlot): def slot_code(self, scope): if scope.needs_tp_clear(): return GCDependentSlot.slot_code(self, scope) return "0" class ConstructorSlot(InternalMethodSlot): # Descriptor for tp_new and tp_dealloc. def __init__(self, slot_name, method, **kargs): InternalMethodSlot.__init__(self, slot_name, **kargs) self.method = method def slot_code(self, scope): entry = scope.lookup_here(self.method) if (self.slot_name != 'tp_new' and scope.parent_type.base_type and not scope.has_pyobject_attrs and not scope.has_memoryview_attrs and not scope.has_cpp_class_attrs and not (entry and entry.is_special)): # if the type does not have object attributes, it can # delegate GC methods to its parent - iff the parent # functions are defined in the same module parent_type_scope = scope.parent_type.base_type.scope if scope.parent_scope is parent_type_scope.parent_scope: entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) if entry.visibility != 'extern': return self.slot_code(parent_type_scope) if entry and not entry.is_special: return "0" return InternalMethodSlot.slot_code(self, scope) class SyntheticSlot(InternalMethodSlot): # Type slot descriptor for a synthesized method which # dispatches to one or more user-defined methods depending # on its arguments. If none of the relevant methods are # defined, the method will not be synthesized and an # alternative default value will be placed in the type # slot. def __init__(self, slot_name, user_methods, default_value, **kargs): InternalMethodSlot.__init__(self, slot_name, **kargs) self.user_methods = user_methods self.default_value = default_value def slot_code(self, scope): if scope.defines_any_special(self.user_methods): return InternalMethodSlot.slot_code(self, scope) else: return self.default_value class RichcmpSlot(MethodSlot): def slot_code(self, scope): entry = scope.lookup_here(self.method_name) if entry and entry.is_special and entry.func_cname: return entry.func_cname elif scope.defines_any_special(richcmp_special_methods): return scope.mangle_internal(self.slot_name) else: return "0" class TypeFlagsSlot(SlotDescriptor): # Descriptor for the type flags slot. def slot_code(self, scope): value = "Py_TPFLAGS_DEFAULT" if scope.directives['type_version_tag']: # it's not in 'Py_TPFLAGS_DEFAULT' in Py2 value += "|Py_TPFLAGS_HAVE_VERSION_TAG" else: # it's enabled in 'Py_TPFLAGS_DEFAULT' in Py3 value = "(%s&~Py_TPFLAGS_HAVE_VERSION_TAG)" % value value += "|Py_TPFLAGS_CHECKTYPES|Py_TPFLAGS_HAVE_NEWBUFFER" if not scope.parent_type.is_final_type: value += "|Py_TPFLAGS_BASETYPE" if scope.needs_gc(): value += "|Py_TPFLAGS_HAVE_GC" return value class DocStringSlot(SlotDescriptor): # Descriptor for the docstring slot. def slot_code(self, scope): doc = scope.doc if doc is None: return "0" if doc.is_unicode: doc = doc.as_utf8_string() return doc.as_c_string_literal() class SuiteSlot(SlotDescriptor): # Descriptor for a substructure of the type object. # # sub_slots [SlotDescriptor] def __init__(self, sub_slots, slot_type, slot_name, ifdef=None): SlotDescriptor.__init__(self, slot_name, ifdef=ifdef) self.sub_slots = sub_slots self.slot_type = slot_type substructures.append(self) def is_empty(self, scope): for slot in self.sub_slots: if slot.slot_code(scope) != "0": return False return True def substructure_cname(self, scope): return "%s%s_%s" % (Naming.pyrex_prefix, self.slot_name, scope.class_name) def slot_code(self, scope): if not self.is_empty(scope): return "&%s" % self.substructure_cname(scope) return "0" def generate_substructure(self, scope, code): if not self.is_empty(scope): code.putln("") if self.ifdef: code.putln("#if %s" % self.ifdef) code.putln( "static %s %s = {" % ( self.slot_type, self.substructure_cname(scope))) for slot in self.sub_slots: slot.generate(scope, code) code.putln("};") if self.ifdef: code.putln("#endif") substructures = [] # List of all SuiteSlot instances class MethodTableSlot(SlotDescriptor): # Slot descriptor for the method table. def slot_code(self, scope): if scope.pyfunc_entries: return scope.method_table_cname else: return "0" class MemberTableSlot(SlotDescriptor): # Slot descriptor for the table of Python-accessible attributes. def slot_code(self, scope): return "0" class GetSetSlot(SlotDescriptor): # Slot descriptor for the table of attribute get & set methods. def slot_code(self, scope): if scope.property_entries: return scope.getset_table_cname else: return "0" class BaseClassSlot(SlotDescriptor): # Slot descriptor for the base class slot. def __init__(self, name): SlotDescriptor.__init__(self, name, dynamic = 1) def generate_dynamic_init_code(self, scope, code): base_type = scope.parent_type.base_type if base_type: code.putln("%s.%s = %s;" % ( scope.parent_type.typeobj_cname, self.slot_name, base_type.typeptr_cname)) class DictOffsetSlot(SlotDescriptor): # Slot descriptor for a class' dict offset, for dynamic attributes. def slot_code(self, scope): dict_entry = scope.lookup_here("__dict__") if not scope.is_closure_class_scope else None if dict_entry and dict_entry.is_variable: if getattr(dict_entry.type, 'cname', None) != 'PyDict_Type': error(dict_entry.pos, "__dict__ slot must be of type 'dict'") return "0" type = scope.parent_type if type.typedef_flag: objstruct = type.objstruct_cname else: objstruct = "struct %s" % type.objstruct_cname return ("offsetof(%s, %s)" % ( objstruct, dict_entry.cname)) else: return "0" # The following dictionary maps __xxx__ method names to slot descriptors. method_name_to_slot = {} ## The following slots are (or could be) initialised with an ## extern function pointer. # #slots_initialised_from_extern = ( # "tp_free", #) #------------------------------------------------------------------------------------------ # # Utility functions for accessing slot table data structures # #------------------------------------------------------------------------------------------ def get_special_method_signature(name): # Given a method name, if it is a special method, # return its signature, else return None. slot = method_name_to_slot.get(name) if slot: return slot.signature elif name in richcmp_special_methods: return ibinaryfunc else: return None def get_property_accessor_signature(name): # Return signature of accessor for an extension type # property, else None. return property_accessor_signatures.get(name) def get_base_slot_function(scope, slot): # Returns the function implementing this slot in the baseclass. # This is useful for enabling the compiler to optimize calls # that recursively climb the class hierarchy. base_type = scope.parent_type.base_type if scope.parent_scope is base_type.scope.parent_scope: parent_slot = slot.slot_code(base_type.scope) if parent_slot != '0': entry = scope.parent_scope.lookup_here(scope.parent_type.base_type.name) if entry.visibility != 'extern': return parent_slot return None def get_slot_function(scope, slot): # Returns the function implementing this slot in the baseclass. # This is useful for enabling the compiler to optimize calls # that recursively climb the class hierarchy. slot_code = slot.slot_code(scope) if slot_code != '0': entry = scope.parent_scope.lookup_here(scope.parent_type.name) if entry.visibility != 'extern': return slot_code return None def get_slot_by_name(slot_name): # For now, only search the type struct, no referenced sub-structs. for slot in slot_table: if slot.slot_name == slot_name: return slot assert False, "Slot not found: %s" % slot_name def get_slot_code_by_name(scope, slot_name): slot = get_slot_by_name(slot_name) return slot.slot_code(scope) def is_reverse_number_slot(name): """ Tries to identify __radd__ and friends (so the METH_COEXIST flag can be applied). There's no great consequence if it inadvertently identifies a few other methods so just use a simple rule rather than an exact list. """ if name.startswith("__r") and name.endswith("__"): forward_name = name.replace("r", "", 1) for meth in PyNumberMethods: if getattr(meth, "method_name", None) == forward_name: return True return False #------------------------------------------------------------------------------------------ # # Signatures for generic Python functions and methods. # #------------------------------------------------------------------------------------------ pyfunction_signature = Signature("-*", "O") pymethod_signature = Signature("T*", "O") #------------------------------------------------------------------------------------------ # # Signatures for simple Python functions. # #------------------------------------------------------------------------------------------ pyfunction_noargs = Signature("-", "O") pyfunction_onearg = Signature("-O", "O") #------------------------------------------------------------------------------------------ # # Signatures for the various kinds of function that # can appear in the type object and its substructures. # #------------------------------------------------------------------------------------------ unaryfunc = Signature("T", "O") # typedef PyObject * (*unaryfunc)(PyObject *); binaryfunc = Signature("OO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); ibinaryfunc = Signature("TO", "O") # typedef PyObject * (*binaryfunc)(PyObject *, PyObject *); ternaryfunc = Signature("OOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); iternaryfunc = Signature("TOO", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); callfunc = Signature("T*", "O") # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *); inquiry = Signature("T", "i") # typedef int (*inquiry)(PyObject *); lenfunc = Signature("T", "z") # typedef Py_ssize_t (*lenfunc)(PyObject *); # typedef int (*coercion)(PyObject **, PyObject **); intargfunc = Signature("Ti", "O") # typedef PyObject *(*intargfunc)(PyObject *, int); ssizeargfunc = Signature("Tz", "O") # typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t); intintargfunc = Signature("Tii", "O") # typedef PyObject *(*intintargfunc)(PyObject *, int, int); ssizessizeargfunc = Signature("Tzz", "O") # typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t); intobjargproc = Signature("TiO", 'r') # typedef int(*intobjargproc)(PyObject *, int, PyObject *); ssizeobjargproc = Signature("TzO", 'r') # typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *); intintobjargproc = Signature("TiiO", 'r') # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *); ssizessizeobjargproc = Signature("TzzO", 'r') # typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); intintargproc = Signature("Tii", 'r') ssizessizeargproc = Signature("Tzz", 'r') objargfunc = Signature("TO", "O") objobjargproc = Signature("TOO", 'r') # typedef int (*objobjargproc)(PyObject *, PyObject *, PyObject *); readbufferproc = Signature("TzP", "z") # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **); writebufferproc = Signature("TzP", "z") # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **); segcountproc = Signature("TZ", "z") # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *); charbufferproc = Signature("TzS", "z") # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **); objargproc = Signature("TO", 'r') # typedef int (*objobjproc)(PyObject *, PyObject *); # typedef int (*visitproc)(PyObject *, void *); # typedef int (*traverseproc)(PyObject *, visitproc, void *); destructor = Signature("T", "v") # typedef void (*destructor)(PyObject *); # printfunc = Signature("TFi", 'r') # typedef int (*printfunc)(PyObject *, FILE *, int); # typedef PyObject *(*getattrfunc)(PyObject *, char *); getattrofunc = Signature("TO", "O") # typedef PyObject *(*getattrofunc)(PyObject *, PyObject *); # typedef int (*setattrfunc)(PyObject *, char *, PyObject *); setattrofunc = Signature("TOO", 'r') # typedef int (*setattrofunc)(PyObject *, PyObject *, PyObject *); delattrofunc = Signature("TO", 'r') cmpfunc = Signature("TO", "i") # typedef int (*cmpfunc)(PyObject *, PyObject *); reprfunc = Signature("T", "O") # typedef PyObject *(*reprfunc)(PyObject *); hashfunc = Signature("T", "h") # typedef Py_hash_t (*hashfunc)(PyObject *); richcmpfunc = Signature("TOi", "O") # typedef PyObject *(*richcmpfunc) (PyObject *, PyObject *, int); getiterfunc = Signature("T", "O") # typedef PyObject *(*getiterfunc) (PyObject *); iternextfunc = Signature("T", "O") # typedef PyObject *(*iternextfunc) (PyObject *); descrgetfunc = Signature("TOO", "O") # typedef PyObject *(*descrgetfunc) (PyObject *, PyObject *, PyObject *); descrsetfunc = Signature("TOO", 'r') # typedef int (*descrsetfunc) (PyObject *, PyObject *, PyObject *); descrdelfunc = Signature("TO", 'r') initproc = Signature("T*", 'r') # typedef int (*initproc)(PyObject *, PyObject *, PyObject *); # typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *); # typedef PyObject *(*allocfunc)(struct _typeobject *, int); getbufferproc = Signature("TBi", "r") # typedef int (*getbufferproc)(PyObject *, Py_buffer *, int); releasebufferproc = Signature("TB", "v") # typedef void (*releasebufferproc)(PyObject *, Py_buffer *); #------------------------------------------------------------------------------------------ # # Signatures for accessor methods of properties. # #------------------------------------------------------------------------------------------ property_accessor_signatures = { '__get__': Signature("T", "O"), '__set__': Signature("TO", 'r'), '__del__': Signature("T", 'r') } #------------------------------------------------------------------------------------------ # # Descriptor tables for the slots of the various type object # substructures, in the order they appear in the structure. # #------------------------------------------------------------------------------------------ PyNumberMethods_Py3_GUARD = "PY_MAJOR_VERSION < 3 || (CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03050000)" PyNumberMethods = ( MethodSlot(binaryfunc, "nb_add", "__add__"), MethodSlot(binaryfunc, "nb_subtract", "__sub__"), MethodSlot(binaryfunc, "nb_multiply", "__mul__"), MethodSlot(binaryfunc, "nb_divide", "__div__", ifdef = PyNumberMethods_Py3_GUARD), MethodSlot(binaryfunc, "nb_remainder", "__mod__"), MethodSlot(binaryfunc, "nb_divmod", "__divmod__"), MethodSlot(ternaryfunc, "nb_power", "__pow__"), MethodSlot(unaryfunc, "nb_negative", "__neg__"), MethodSlot(unaryfunc, "nb_positive", "__pos__"), MethodSlot(unaryfunc, "nb_absolute", "__abs__"), MethodSlot(inquiry, "nb_nonzero", "__nonzero__", py3 = ("nb_bool", "__bool__")), MethodSlot(unaryfunc, "nb_invert", "__invert__"), MethodSlot(binaryfunc, "nb_lshift", "__lshift__"), MethodSlot(binaryfunc, "nb_rshift", "__rshift__"), MethodSlot(binaryfunc, "nb_and", "__and__"), MethodSlot(binaryfunc, "nb_xor", "__xor__"), MethodSlot(binaryfunc, "nb_or", "__or__"), EmptySlot("nb_coerce", ifdef = PyNumberMethods_Py3_GUARD), MethodSlot(unaryfunc, "nb_int", "__int__", fallback="__long__"), MethodSlot(unaryfunc, "nb_long", "__long__", fallback="__int__", py3 = ""), MethodSlot(unaryfunc, "nb_float", "__float__"), MethodSlot(unaryfunc, "nb_oct", "__oct__", ifdef = PyNumberMethods_Py3_GUARD), MethodSlot(unaryfunc, "nb_hex", "__hex__", ifdef = PyNumberMethods_Py3_GUARD), # Added in release 2.0 MethodSlot(ibinaryfunc, "nb_inplace_add", "__iadd__"), MethodSlot(ibinaryfunc, "nb_inplace_subtract", "__isub__"), MethodSlot(ibinaryfunc, "nb_inplace_multiply", "__imul__"), MethodSlot(ibinaryfunc, "nb_inplace_divide", "__idiv__", ifdef = PyNumberMethods_Py3_GUARD), MethodSlot(ibinaryfunc, "nb_inplace_remainder", "__imod__"), MethodSlot(ibinaryfunc, "nb_inplace_power", "__ipow__"), # actually ternaryfunc!!! MethodSlot(ibinaryfunc, "nb_inplace_lshift", "__ilshift__"), MethodSlot(ibinaryfunc, "nb_inplace_rshift", "__irshift__"), MethodSlot(ibinaryfunc, "nb_inplace_and", "__iand__"), MethodSlot(ibinaryfunc, "nb_inplace_xor", "__ixor__"), MethodSlot(ibinaryfunc, "nb_inplace_or", "__ior__"), # Added in release 2.2 # The following require the Py_TPFLAGS_HAVE_CLASS flag MethodSlot(binaryfunc, "nb_floor_divide", "__floordiv__"), MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"), MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"), MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"), # Added in release 2.5 MethodSlot(unaryfunc, "nb_index", "__index__"), # Added in release 3.5 MethodSlot(binaryfunc, "nb_matrix_multiply", "__matmul__", ifdef="PY_VERSION_HEX >= 0x03050000"), MethodSlot(ibinaryfunc, "nb_inplace_matrix_multiply", "__imatmul__", ifdef="PY_VERSION_HEX >= 0x03050000"), ) PySequenceMethods = ( MethodSlot(lenfunc, "sq_length", "__len__"), EmptySlot("sq_concat"), # nb_add used instead EmptySlot("sq_repeat"), # nb_multiply used instead SyntheticSlot("sq_item", ["__getitem__"], "0"), #EmptySlot("sq_item"), # mp_subscript used instead MethodSlot(ssizessizeargfunc, "sq_slice", "__getslice__"), EmptySlot("sq_ass_item"), # mp_ass_subscript used instead SyntheticSlot("sq_ass_slice", ["__setslice__", "__delslice__"], "0"), MethodSlot(cmpfunc, "sq_contains", "__contains__"), EmptySlot("sq_inplace_concat"), # nb_inplace_add used instead EmptySlot("sq_inplace_repeat"), # nb_inplace_multiply used instead ) PyMappingMethods = ( MethodSlot(lenfunc, "mp_length", "__len__"), MethodSlot(objargfunc, "mp_subscript", "__getitem__"), SyntheticSlot("mp_ass_subscript", ["__setitem__", "__delitem__"], "0"), ) PyBufferProcs = ( MethodSlot(readbufferproc, "bf_getreadbuffer", "__getreadbuffer__", py3 = False), MethodSlot(writebufferproc, "bf_getwritebuffer", "__getwritebuffer__", py3 = False), MethodSlot(segcountproc, "bf_getsegcount", "__getsegcount__", py3 = False), MethodSlot(charbufferproc, "bf_getcharbuffer", "__getcharbuffer__", py3 = False), MethodSlot(getbufferproc, "bf_getbuffer", "__getbuffer__"), MethodSlot(releasebufferproc, "bf_releasebuffer", "__releasebuffer__") ) PyAsyncMethods = ( MethodSlot(unaryfunc, "am_await", "__await__"), MethodSlot(unaryfunc, "am_aiter", "__aiter__"), MethodSlot(unaryfunc, "am_anext", "__anext__"), EmptySlot("am_send", ifdef="PY_VERSION_HEX >= 0x030A00A3"), ) #------------------------------------------------------------------------------------------ # # The main slot table. This table contains descriptors for all the # top-level type slots, beginning with tp_dealloc, in the order they # appear in the type object. # #------------------------------------------------------------------------------------------ slot_table = ( ConstructorSlot("tp_dealloc", '__dealloc__'), EmptySlot("tp_print", ifdef="PY_VERSION_HEX < 0x030800b4"), EmptySlot("tp_vectorcall_offset", ifdef="PY_VERSION_HEX >= 0x030800b4"), EmptySlot("tp_getattr"), EmptySlot("tp_setattr"), # tp_compare (Py2) / tp_reserved (Py3<3.5) / tp_as_async (Py3.5+) is always used as tp_as_async in Py3 MethodSlot(cmpfunc, "tp_compare", "__cmp__", ifdef="PY_MAJOR_VERSION < 3"), SuiteSlot(PyAsyncMethods, "__Pyx_PyAsyncMethodsStruct", "tp_as_async", ifdef="PY_MAJOR_VERSION >= 3"), MethodSlot(reprfunc, "tp_repr", "__repr__"), SuiteSlot(PyNumberMethods, "PyNumberMethods", "tp_as_number"), SuiteSlot(PySequenceMethods, "PySequenceMethods", "tp_as_sequence"), SuiteSlot(PyMappingMethods, "PyMappingMethods", "tp_as_mapping"), MethodSlot(hashfunc, "tp_hash", "__hash__", inherited=False), # Py3 checks for __richcmp__ MethodSlot(callfunc, "tp_call", "__call__"), MethodSlot(reprfunc, "tp_str", "__str__"), SyntheticSlot("tp_getattro", ["__getattr__","__getattribute__"], "0"), #"PyObject_GenericGetAttr"), SyntheticSlot("tp_setattro", ["__setattr__", "__delattr__"], "0"), #"PyObject_GenericSetAttr"), SuiteSlot(PyBufferProcs, "PyBufferProcs", "tp_as_buffer"), TypeFlagsSlot("tp_flags"), DocStringSlot("tp_doc"), GCDependentSlot("tp_traverse"), GCClearReferencesSlot("tp_clear"), RichcmpSlot(richcmpfunc, "tp_richcompare", "__richcmp__", inherited=False), # Py3 checks for __hash__ EmptySlot("tp_weaklistoffset"), MethodSlot(getiterfunc, "tp_iter", "__iter__"), MethodSlot(iternextfunc, "tp_iternext", "__next__"), MethodTableSlot("tp_methods"), MemberTableSlot("tp_members"), GetSetSlot("tp_getset"), BaseClassSlot("tp_base"), #EmptySlot("tp_base"), EmptySlot("tp_dict"), SyntheticSlot("tp_descr_get", ["__get__"], "0"), SyntheticSlot("tp_descr_set", ["__set__", "__delete__"], "0"), DictOffsetSlot("tp_dictoffset"), MethodSlot(initproc, "tp_init", "__init__"), EmptySlot("tp_alloc"), #FixedSlot("tp_alloc", "PyType_GenericAlloc"), InternalMethodSlot("tp_new"), EmptySlot("tp_free"), EmptySlot("tp_is_gc"), EmptySlot("tp_bases"), EmptySlot("tp_mro"), EmptySlot("tp_cache"), EmptySlot("tp_subclasses"), EmptySlot("tp_weaklist"), EmptySlot("tp_del"), EmptySlot("tp_version_tag"), EmptySlot("tp_finalize", ifdef="PY_VERSION_HEX >= 0x030400a1"), EmptySlot("tp_vectorcall", ifdef="PY_VERSION_HEX >= 0x030800b1 && (!CYTHON_COMPILING_IN_PYPY || PYPY_VERSION_NUM >= 0x07030800)"), EmptySlot("tp_print", ifdef="PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000"), # PyPy specific extension - only here to avoid C compiler warnings. EmptySlot("tp_pypy_flags", ifdef="CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX >= 0x03090000 && PY_VERSION_HEX < 0x030a0000"), ) #------------------------------------------------------------------------------------------ # # Descriptors for special methods which don't appear directly # in the type object or its substructures. These methods are # called from slot functions synthesized by Cython. # #------------------------------------------------------------------------------------------ MethodSlot(initproc, "", "__cinit__") MethodSlot(destructor, "", "__dealloc__") MethodSlot(objobjargproc, "", "__setitem__") MethodSlot(objargproc, "", "__delitem__") MethodSlot(ssizessizeobjargproc, "", "__setslice__") MethodSlot(ssizessizeargproc, "", "__delslice__") MethodSlot(getattrofunc, "", "__getattr__") MethodSlot(getattrofunc, "", "__getattribute__") MethodSlot(setattrofunc, "", "__setattr__") MethodSlot(delattrofunc, "", "__delattr__") MethodSlot(descrgetfunc, "", "__get__") MethodSlot(descrsetfunc, "", "__set__") MethodSlot(descrdelfunc, "", "__delete__") # Method flags for python-exposed methods. method_noargs = "METH_NOARGS" method_onearg = "METH_O" method_varargs = "METH_VARARGS" method_keywords = "METH_KEYWORDS" method_coexist = "METH_COEXIST"