HPy Types and Modules¶
Types, modules and their attributes (i.e. methods, members, slots, get-set descriptors) are defined in a similar way. Section HPy Type documents the type-specific and HPy Module documents the module-specific part. Section HPy Definition documents how to define attributes for both, types and modules.
HPy Type¶
Definition¶
-
struct
HPyType_Spec
¶
[source] -
-
int
basicsize
¶
[source] The size in bytes of the types associated native structure. Usually, you define some C structure, e.g.,
typedef struct { int a; } MyObject;
, and then this field is set tosizeof(MyObject)
.
-
unsigned long
flags
¶
[source] Type flags (see
HPy_TPFLAGS_DEFAULT
,HPy_TPFLAGS_BASETYPE
,HPy_TPFLAGS_HAVE_GC
, and others if available).
-
HPyType_BuiltinShape
builtin_shape
¶
[source] The internal shape of the type. The shape gives the necessary hint to compute the offset to the data pointer of the object’s underlying struct that should be returned when calling
MyObject_AsStruct
. ATTENTION: It is also necessary to specify the right base class in the type’s specification parameters (seeHPyType_SpecParam
). Assuming that the type’s C structure is calledMyObject
, this field should be initialized with.builtin_shape = SHAPE(MyObject)
. Note: This requires that you useHPyType_HELPERS
orHPyType_LEGACY_HELPERS
. Some more explanation: It would be possible to reduce this information to a Boolean that specifies if the type is a legacy type or not. Everything else could be determined by looking at the base classes. However, with this information it is possible to do the data pointer computation statically and thus is performance critical. Types that do not define a struct of their own, should set the value of.builtin_shape
to the same value as the type they inherit from. If they inherit from a built-in type, they must set the corresponding.builtin_shape
.
-
void *
legacy_slots
¶
[source] Pointer to a
NULL
-terminated array of legacy (i.e.PyType_Slot
) slots. A type with.legacy_slots != NULL
is required to haveHPyType_BuiltinShape_Legacy
and to includePyObject_HEAD
at the start of its struct. It would be easy to relax this requirement on CPython (where thePyObject_HEAD
fields are always present) but a large burden on other implementations (e.g. PyPy, GraalPy) where a struct starting withPyObject_HEAD
might not exist.
-
int
-
enum
HPyType_BuiltinShape
¶
[source] -
enumerator
HPyType_BuiltinShape_Legacy
= -1¶
[source] A type whose struct starts with
PyObject_HEAD
or equivalent is a legacy type. A legacy type must set.builtin_shape = HPyType_BuiltinShape_Legacy
in itsHPyType_Spec
. A type is a non-legacy type, also called HPy pure type, if its struct does not includePyObject_HEAD
. Using pure types should be preferred. Legacy types are available to allow gradual porting of existing CPython extensions. A type with.legacy_slots != NULL
(seeHPyType_Spec.legacy_slots
) is required to haveHPyType_BuiltinShape_Legacy
and to includePyObject_HEAD
at the start of its struct. It would be easy to relax this requirement on CPython (where thePyObject_HEAD
fields are always present) but a large burden on other implementations (e.g. PyPy, GraalPy) where a struct starting withPyObject_HEAD
might not exist. Types created via the old Python C API are automatically legacy types.
-
enumerator
HPyType_BuiltinShape_Object
= 0¶
[source] The type inherits from built-in type
object
(default).
-
enumerator
HPyType_BuiltinShape_Type
= 1¶
[source] The type inherits from built-in type
type
. This can be used to create metaclasses. If using this shape, you need to specify base classctx->h_TypeType
.
-
enumerator
HPyType_BuiltinShape_Long
= 2¶
[source] The type inherits from built-in type
int
(aka. long object). If using this shape, you need to specify base classctx->h_LongType
.
-
enumerator
HPyType_BuiltinShape_Float
= 3¶
[source] The type inherits from built-in type
float
. If using this shape, you need to specify base classctx->h_FloatType
.
-
enumerator
HPyType_BuiltinShape_Unicode
= 4¶
[source] The type inherits from built-in type
str
(aka. unicode object). If using this shape, you need to specify base classctx->h_UnicodeType
.
-
enumerator
-
struct
HPyType_SpecParam
¶
[source] -
HPyType_SpecParam_Kind
kind
¶
[source] The kind of the type spec param.
-
HPyType_SpecParam_Kind
-
enum
HPyType_SpecParam_Kind
¶
[source] -
enumerator
HPyType_SpecParam_Base
= 1¶
[source] Specify a base class. This parameter may be repeated but cannot be used together with
HPyType_SpecParam_Kind.HPyType_SpecParam_BasesTuple
.
-
enumerator
HPyType_SpecParam_BasesTuple
= 2¶
[source] Specify a tuple of base classes. Cannot be used together with
HPyType_SpecParam_Kind.HPyType_SpecParam_Base
-
enumerator
-
HPyType_HELPERS
()¶
[source] A macro for creating (static inline) helper functions for custom types.
Two versions of the helper exist. One for legacy types and one for pure HPy types.
Example for a pure HPy custom type:
HPyType_HELPERS(PointObject)
It is also possible to inherit from some built-in types. The list of available built-in base types is given in enum HPyTupe_BuiltinShape. In case you want to inherit from one of those, it is necessary to specify the base built-in type in the HPyType_HELPERS macro. Here is an example for a pure HPy custom type inheriting from a built-in type ‘tuple’:
HPyType_HELPERS(PointObject, HPyType_BuiltinShape_Tuple)
This would generate the following:
PointObject * PointObject_AsStruct(HPyContext *ctx, HPy h)
: a static inline function that uses HPy_AsStruct to return the PointObject struct associated with a given handle. The behaviour is undefined if h is associated with an object that is not an instance of PointObject. However, debug mode will catch an incorrect usage.SHAPE(PointObject)
: a macro that is meant to be used as static initializer in the corresponding HPyType_Spec. It is recommended to write.builtin_shape = SHAPE(PointObject)
such that you don’t have to remember to update the spec when the helpers used changes.
Example for a legacy custom type:
HPyType_LEGACY_HELPERS(PointObject)
This would generate the same functions and constants as above, except:
_HPy_AsStruct_Legacy
is used instead of_HPy_AsStruct_Object
.SHAPE(PointObject)
would beHPyType_BuiltinShape_Legacy
.
- Parameters
STRUCT – The C structure of the HPy type.
SHAPE – Optional. The built-in shape of the type. This defaults to
HPyType_BuiltinShape_Object
. Possible values are all enumerators ofHPyType_BuiltinShape
.
Construction and More¶
-
HPy
HPyType_FromSpec
(HPyContext *ctx, HPyType_Spec *spec, HPyType_SpecParam *params)¶
[source] Create a type from a
HPyType_Spec
and an additional list of specification parameters.- Parameters
ctx – The execution context.
spec – The type spec to use to create the type.
params – A 0-terminated list of type specification parameters or
NULL
.
- Returns
a handle of the created type on success,
HPy_NULL
on failure.
-
const char *
HPyType_GetName
(HPyContext *ctx, HPy type)¶
[source] Return the type’s name.
Equivalent to getting the type’s
__name__
attribute. If you want to retrieve the type’s name as a handle that refers to astr
, then just useHPy_GetAttr_s(ctx, type, "__name__")
.- Parameters
ctx – The execution context.
type – A Python type object. This argument must not be
HPy_NULL
and must be a type (i.e. it must inherit from Pythontype
). If this is not the case, the behavior is undefined (verification of the argument is only done in debug mode).
- Returns
The name of the type as C string (UTF-8 encoded) or
NULL
in case of an error. The returned pointer is read-only and guaranteed to be valid as long as the handletype
is valid.
-
int
HPyType_IsSubtype
(HPyContext *ctx, HPy sub, HPy type)¶
[source] Checks if
sub
is a subtype oftype
.This function only checks for actual subtypes, which means that
__subclasscheck__()
is not called ontype
.- Parameters
ctx – The execution context.
sub – A Python type object. This argument must not be
HPy_NULL
and must be a type (i.e. it must inherit from Pythontype
). If this is not the case, the behavior is undefined (verification of the argument is only done in debug mode).type – A Python type object. This argument must not be
HPy_NULL
and must be a type (i.e. it must inherit from Pythontype
). If this is not the case, the behavior is undefined (verification of the argument is only done in debug mode).
- Returns
Non-zero if
sub
is a subtype oftype
.
HPy Module¶
-
HPY_EMBEDDED_MODULES
¶ If
HPY_EMBEDDED_MODULES
is defined, this means that there will be several embedded HPy modules (and so, severalHPy_MODINIT
usages) in the same binary. In this case, some restrictions apply:all of the module’s methods/member/slots/… must be defined in the same file
the embedder MUST declare the module to be embeddable by using macro
HPY_MOD_EMBEDDABLE
.
-
HPY_MOD_EMBEDDABLE
(modname)¶
[source] Declares a module to be embeddable which means that it and its members can be compiled/linked into a binary together with other embeddable HPy modules.
You may declare a module to be embeddable if all of its member definitions are in the same file.
-
struct
HPyModuleDef
¶
[source] Definition of a Python module. Pointer to this struct is returned from the HPy initialization function
HPyInit_{extname}
and the Python interpreter creates a Python module from it. HPy supports only the multi-phase module initialization approach (PEP 451).There is no HPy API to create a Python module manually, i.e., equivalent of
PyModule_Create
orPyModule_FromDefAndSpec
, for the time being, but may be added if a use-case arises.Note: unlike Python/C API, HPy module definition does not specify module name. The name if always taken from the ModuleSpec, which is also the case in multi-phase module initialization on Python/C API.
-
int
size
¶
[source] The size (in bytes) of the module state structure. If set to zero, then the module will not get allocated and assigned any HPy module state. Negative size, unlike in Python/C API, does not have any specific meaning and will produce a runtime error.
-
int *
legacy_methods
¶
[source] NULL
-terminated list of legacy module-level methods. In order to enable incremental migration from C API to HPy, it is possible to still add legacy method definitions. Those methods have a C API signature which means that they still receivePyObject *
and similar arguments. If legacy methods are defined, you cannot create a universal binary (i.e. a binary that will run on all Python engines).
-
int
-
HPy_MODINIT
(ext_name, mod_def)¶
[source] Convenience macro for generating the module initialization code. This will generate three functions that are used by to verify an initialize the module when loading:
get_required_hpy_major_version_<modname>
The HPy major version this module was built with.
get_required_hpy_minor_version_<modname>
The HPy minor version this module was built with.
HPyModuleDef* HPyInit_<extname>
The init function that will be called by the interpreter. This function does not have an access to HPyContext and thus cannot call any HPy APIs. The purpose of this function is to return a pointer to a HPyModuleDef structure that will serve as a specification of the module that should be created by the interpreter. HPy supports only multi-phase module initialization (PEP 451). Any module initialization code can be added to the HPy_mod_execute slot of the module if needed.
Example:
HPy_MODINIT(myextension_shared_library_filename, my_hpy_module_def)
HPy Definition¶
Defining slots, methods, members, and get-set descriptors for types and modules
is done with HPy definition (represented by C struct HPyDef
).
-
struct
HPyDef
¶
[source] Generic structure of an HPy definition.
This struct can be used to define a slot, method, member, or get/set descriptor. For details, see embedded structures
HPySlot
,HPyMeth
,HPyMember
, orHPyGetSet
.-
HPyDef_Kind
kind
¶
[source] The kind of this definition. The value of this field determines which one of the embedded members
slot
,meth
,member
, orgetset
is used. Since those are combined in a union, only one can be used at a time.
-
HPyDef_Kind
-
struct
HPySlot
¶
[source] C structure to define an HPy slot.
It is perfectly fine to fill this structure manually. However, the recommended and easier way is to use macro
HPyDef_SLOT
.
-
struct
HPyMeth
¶
[source] C structure to define an HPy method.
It is perfectly fine to fill this structure manually. However, the recommended and easier way is to use macro
HPyDef_METH
.
-
enum
HPyMember_FieldType
¶
[source] Describes the type (and therefore also the size) of an HPy member.
-
struct
HPyMember
¶
[source] C structure to define an HPy member.
It is perfectly fine to fill this structure manually. However, the recommended and easier way is to use macro
HPyDef_MEMBER
.-
HPyMember_FieldType
type
¶
[source] The type of the HPy member (see enum
HPyMember_FieldType
).
-
HPyMember_FieldType
-
struct
HPyGetSet
¶
[source] C structure to define an HPy get/set descriptor.
It is perfectly fine to fill this structure manually. However, the recommended and easier way is to use macros
HPyDef_GET
(to create a get descriptor only),HPyDef_SET
(to create a set descriptor only), orHPyDef_GETSET
(to create both).-
int
getter_cpy_trampoline
¶
[source] Function pointer to the CPython trampoline function for the getter (may be
NULL
if (and only if)getter_impl == NULL
)
-
int
-
HPyDef_SLOT
(SYM, SLOT)¶
[source] A convenience macro and recommended way to create a definition for an HPy slot.
The macro generates a C global variable and an appropriate CPython trampoline function. It will fill an
HPyDef
structure appropriately and store it in the global variable.This macro expects a C function
SYM_impl
that will be used as the implementing slot function.- Parameters
SYM – A C symbol name of the resulting global variable that will contain the generated HPy definition. The variable is defined as
static
.SLOT – The HPy slot identifier.
-
HPyDef_METH
(SYM, NAME, SIG)¶
[source] A convenience macro and recommended way to create a definition for an HPy method.
The macro generates a C global variable and an appropriate CPython trampoline function. It will fill an
HPyDef
structure appropriately and store it in the global variable.This macro expects a C function
SYM_impl
that will be used as the implementing C function.- Parameters
SYM – A C symbol name of the resulting global variable that will contain the generated HPy definition. The variable is defined as
static
.NAME – The Python attribute name (UTF-8 encoded).
SIG – The implementation’s C signature (see
HPyFunc_Signature
).
-
HPyDef_MEMBER
(SYM, NAME, TYPE, OFFSET)¶
[source] A convenience macro and recommended way to create a definition for an HPy member.
The macro generates a C global variable. It will fill an
HPyDef
structure appropriately and store it in the global variable.- Parameters
SYM – A C symbol name of the resulting global variable that will contain the generated HPy definition. The variable is defined as
static
.NAME – The Python attribute name (UTF-8 encoded).
TYPE – The implementation’s C signature (see
HPyFunc_Signature
).OFFSET – The Python attribute name (UTF-8 encoded).
.readonly – Optional flag indicating if the member is read-only.
.doc – Optional docstring (UTF-8 encoded).
-
HPyDef_GET
(SYM, NAME)¶
[source] A convenience macro and recommended way to create a definition for an HPy get descriptor.
The macro generates a C global variable. It will fill an
HPyDef
structure appropriately and store it in the global variable.- Parameters
SYM – A C symbol name of the resulting global variable that will contain the generated HPy definition. The variable is defined as
static
.NAME – The Python attribute name (UTF-8 encoded).
.doc – Optional docstring (UTF-8 encoded).
.closure – Optional pointer, providing additional data for the getter.
-
HPyDef_SET
(SYM, NAME)¶
[source] A convenience macro and recommended way to create a definition for an HPy set descriptor.
The macro generates a C global variable. It will fill an
HPyDef
structure appropriately and store it in the global variable.- Parameters
SYM – A C symbol name of the resulting global variable that will contain the generated HPy definition. The variable is defined as
static
.NAME – The Python attribute name (UTF-8 encoded).
.doc – Optional docstring (UTF-8 encoded).
.closure – Optional pointer, providing additional data for the setter.
-
HPyDef_GETSET
(SYM, NAME)¶
[source] A convenience macro and recommended way to create a definition for an HPy get/set descriptor.
The macro generates a C global variable. It will fill an
HPyDef
structure appropriately and store it in the global variable.- Parameters
SYM – A C symbol name of the resulting global variable that will contain the generated HPy definition. The variable is defined as
static
.NAME – The Python attribute name (UTF-8 encoded).
.doc – Optional docstring (UTF-8 encoded).
.closure – Optional pointer, providing additional data for the getter and setter.