diff --git a/docs/api-reference/builder.rst b/docs/api-reference/builder.rst deleted file mode 100644 index fa17af90d..000000000 --- a/docs/api-reference/builder.rst +++ /dev/null @@ -1,8 +0,0 @@ -Building tuples and lists -========================= - -.. autocmodule:: autogen/public_api.h - :members: HPyTupleBuilder_New,HPyTupleBuilder_Set,HPyTupleBuilder_Build,HPyTupleBuilder_Cancel - -.. autocmodule:: autogen/public_api.h - :members: HPyListBuilder_New,HPyListBuilder_Set,HPyListBuilder_Build,HPyListBuilder_Cancel diff --git a/docs/api-reference/hpy-sequence.rst b/docs/api-reference/hpy-sequence.rst new file mode 100644 index 000000000..21b7756e0 --- /dev/null +++ b/docs/api-reference/hpy-sequence.rst @@ -0,0 +1,23 @@ +HPy Lists and Tuples +==================== + +Building Tuples and Lists +------------------------- + +.. autocmodule:: autogen/public_api.h + :members: HPyTupleBuilder_New,HPyTupleBuilder_Set,HPyTupleBuilder_Build,HPyTupleBuilder_Cancel + +.. autocmodule:: autogen/public_api.h + :members: HPyListBuilder_New,HPyListBuilder_Set,HPyListBuilder_Build,HPyListBuilder_Cancel + +Tuples +------ + +.. autocmodule:: autogen/public_api.h + :members: HPyTuple_Check,HPyTuple_FromArray + +Lists +----- + +.. autocmodule:: autogen/public_api.h + :members: HPyList_Check,HPyList_New,HPyList_Append,HPyList_Insert diff --git a/docs/api-reference/index.rst b/docs/api-reference/index.rst index 10aa9babf..89380d637 100644 --- a/docs/api-reference/index.rst +++ b/docs/api-reference/index.rst @@ -28,9 +28,9 @@ between the modes. hpy-field hpy-global hpy-dict + hpy-sequence hpy-gil hpy-err - builder hpy-eval public-api diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index 5fa422e95..2cad0be30 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -509,7 +509,8 @@ If an error occurs during building the list or tuple, it is necessary to call :c:func:`HPyListBuilder_Cancel` or :c:func:`HPyTupleBuilder_Cancel`, respectively, to avoid memory leaks. -For details, see the API reference documentation :doc:`api-reference/builder`. +For details, see the API reference documentation +:doc:`api-reference/hpy-sequence`. Buffers ------- diff --git a/hpy/devel/include/hpy/autogen_hpyslot.h b/hpy/devel/include/hpy/autogen_hpyslot.h index 0fcf6608a..117e6ccae 100644 --- a/hpy/devel/include/hpy/autogen_hpyslot.h +++ b/hpy/devel/include/hpy/autogen_hpyslot.h @@ -58,6 +58,7 @@ typedef enum { HPy_sq_length = 45, HPy_sq_repeat = 46, HPy_tp_call = 50, + HPy_tp_descr_get = 54, HPy_tp_hash = 59, HPy_tp_init = 60, HPy_tp_new = 65, @@ -120,6 +121,7 @@ typedef enum { #define _HPySlot_SIG__HPy_sq_length HPyFunc_LENFUNC #define _HPySlot_SIG__HPy_sq_repeat HPyFunc_SSIZEARGFUNC #define _HPySlot_SIG__HPy_tp_call HPyFunc_KEYWORDS +#define _HPySlot_SIG__HPy_tp_descr_get HPyFunc_TERNARYFUNC #define _HPySlot_SIG__HPy_tp_hash HPyFunc_HASHFUNC #define _HPySlot_SIG__HPy_tp_init HPyFunc_INITPROC #define _HPySlot_SIG__HPy_tp_new HPyFunc_NEWFUNC diff --git a/hpy/tools/autogen/__init__.py b/hpy/tools/autogen/__init__.py new file mode 100644 index 000000000..81eb61e74 --- /dev/null +++ b/hpy/tools/autogen/__init__.py @@ -0,0 +1,21 @@ +import pycparser +from packaging import version + +if version.parse(pycparser.__version__) < version.parse('2.21'): + raise ImportError('You need pycparser>=2.21 to run autogen') + +from .parse import HPyAPI, AUTOGEN_H + + +def generate(generators, *gen_args): + """ + Takes a sequence of autogen generators that will have access to the parse + tree of 'public_api.c' and can then generate files or whatever. + :param generators: A sequence (e.g. tuple) of classes or callables that + will produce objects with a 'write' method. The 'gen_args' will be passed + to the 'write' method on invocation. + :param gen_args: Arguments for the autogen generator instances. + """ + api = HPyAPI.parse(AUTOGEN_H) + for cls in generators: + cls(api).write(*gen_args) diff --git a/hpy/tools/autogen/__main__.py b/hpy/tools/autogen/__main__.py index 4da28ee23..59cdf0487 100644 --- a/hpy/tools/autogen/__main__.py +++ b/hpy/tools/autogen/__main__.py @@ -5,10 +5,11 @@ import py import pycparser from packaging import version + if version.parse(pycparser.__version__) < version.parse('2.21'): raise ImportError('You need pycparser>=2.21 to run autogen') -from .parse import HPyAPI, AUTOGEN_H +from . import generate from .ctx import (autogen_ctx_h, autogen_ctx_def_h, cpython_autogen_ctx_h) @@ -30,6 +31,27 @@ from .doc import (autogen_function_index, autogen_doc_api_mapping) +DEFAULT_GENERATORS = (autogen_ctx_h, + autogen_ctx_def_h, + cpython_autogen_ctx_h, + autogen_trampolines_h, + cpython_autogen_api_impl_h, + universal_autogen_ctx_impl_h, + autogen_hpyfunc_declare_h, + autogen_hpyfunc_trampoline_h, + autogen_ctx_call_i, + autogen_cpython_hpyfunc_trampoline_h, + autogen_hpyslot_h, + autogen_debug_ctx_init_h, + autogen_debug_wrappers, + autogen_debug_ctx_call_i, + autogen_tracer_ctx_init_h, + autogen_tracer_wrappers, + autogen_trace_func_table_c, + autogen_pypy_txt, + autogen_function_index, + autogen_doc_api_mapping) + def main(): if len(sys.argv) != 2: @@ -37,31 +59,7 @@ def main(): sys.exit(1) outdir = py.path.local(sys.argv[1]) - api = HPyAPI.parse(AUTOGEN_H) - ## for func in api.functions: - ## print(func) - - for cls in (autogen_ctx_h, - autogen_ctx_def_h, - cpython_autogen_ctx_h, - autogen_trampolines_h, - cpython_autogen_api_impl_h, - universal_autogen_ctx_impl_h, - autogen_hpyfunc_declare_h, - autogen_hpyfunc_trampoline_h, - autogen_ctx_call_i, - autogen_cpython_hpyfunc_trampoline_h, - autogen_hpyslot_h, - autogen_debug_ctx_init_h, - autogen_debug_wrappers, - autogen_debug_ctx_call_i, - autogen_tracer_ctx_init_h, - autogen_tracer_wrappers, - autogen_trace_func_table_c, - autogen_pypy_txt, - autogen_function_index, - autogen_doc_api_mapping): - cls(api).write(outdir) + generate(DEFAULT_GENERATORS, outdir) if __name__ == '__main__': diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index f831921a7..972f0ffc0 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -666,10 +666,52 @@ HPy_ID(256) HPy HPyUnicode_Substring(HPyContext *ctx, HPy str, HPy_ssize_t start, HPy_ssize_t end); /* listobject.h */ + +/** + * Tests if an object is an instance of a Python list. + * + * :param ctx: + * The execution context. + * :param h: + * A handle to an arbitrary object (must not be ``HPy_NULL``). + * + * :returns: + * Non-zero if object ``h`` is an instance of type ``list`` or an instance + * of a subtype of ``list``, and ``0`` otherwise. + */ HPy_ID(198) int HPyList_Check(HPyContext *ctx, HPy h); + +/** + * Creates a new list instance with length ``len``. + * + * :param ctx: + * The execution context. + * :param len: + * A Python list object (must not be ``HPy_NULL``). Otherwise, a + * ``SystemError`` will be raised. + * + * :returns: + * The new list instance on success, or ``HPy_NULL`` on failure. + */ HPy_ID(199) HPy HPyList_New(HPyContext *ctx, HPy_ssize_t len); + +/** + * Append item ``h_item`` to list ``h_list``. + * + * :param ctx: + * The execution context. + * :param h_list: + * A Python list object (must not be ``HPy_NULL``). Otherwise, a + * ``SystemError`` will be raised. + * :param h_item: + * The item to append (must not be ``HPy_NULL``). + * + * :returns: + * Return ``0`` if successful; return ``-1`` and set an exception if + * unsuccessful. + */ HPy_ID(200) int HPyList_Append(HPyContext *ctx, HPy h_list, HPy h_item); @@ -763,11 +805,41 @@ HPy_ID(258) HPy HPyDict_Copy(HPyContext *ctx, HPy h); /* tupleobject.h */ + +/** + * Tests if an object is an instance of a Python tuple. + * + * :param ctx: + * The execution context. + * :param h: + * A handle to an arbitrary object (must not be ``HPy_NULL``). + * + * :returns: + * Non-zero if object ``h`` is an instance of type ``tuple`` or an instance + * of a subtype of ``tuple``, and ``0`` otherwise. + */ HPy_ID(203) int HPyTuple_Check(HPyContext *ctx, HPy h); + +/** + * Create a tuple from an array. + * + * Note: Consider to use the convenience function :c:func:`HPyTuple_Pack` to + * create a tuple. + * + * :param ctx: + * The execution context. + * :param items: + * An array of items to use for initialization of the tuple. + * :param n: + * The number of elements in array ``items``. + * + * :return: + * A new tuple with ``n`` elements or ``HPy_NULL`` in case of an error + * occurred. + */ HPy_ID(204) HPy HPyTuple_FromArray(HPyContext *ctx, const HPy items[], HPy_ssize_t n); -// note: HPyTuple_Pack is implemented as a macro in common/macros.h /* sliceobject.h */ @@ -1299,7 +1371,7 @@ typedef enum { //HPy_tp_clear = SLOT(51, HPyFunc_X), NOT SUPPORTED, use tp_traverse //HPy_tp_dealloc = SLOT(52, HPyFunc_X), NOT SUPPORTED //HPy_tp_del = SLOT(53, HPyFunc_X), - //HPy_tp_descr_get = SLOT(54, HPyFunc_X), + HPy_tp_descr_get = SLOT(54, HPyFunc_TERNARYFUNC), //HPy_tp_descr_set = SLOT(55, HPyFunc_X), //HPy_tp_doc = SLOT(56, HPyFunc_X), //HPy_tp_getattr = SLOT(57, HPyFunc_X), diff --git a/test/test_slots.py b/test/test_slots.py index 7b2110e6e..ac9cbe2fc 100644 --- a/test/test_slots.py +++ b/test/test_slots.py @@ -807,3 +807,27 @@ def test_tp_richcompare(self): # assert not p1 >= p2 assert p1 >= p1 + + def test_tp_descr_get(self): + mod = self.make_module(""" + @DEFINE_PointObject + @DEFINE_Point_new + + HPyDef_SLOT(Point_get, HPy_tp_descr_get); + static HPy + Point_get_impl(HPyContext *ctx, HPy self, HPy obj, HPy type) + { + if (HPy_IsNull(obj) || HPy_Is(ctx, self, ctx->h_None)) { + return HPy_Dup(ctx, self); + } + return HPyLong_FromLong(ctx, 123); + } + + @EXPORT_POINT_TYPE(&Point_new, &Point_get) + @INIT + """) + p = mod.Point(10, 10) + class Dummy: + point_func = p + assert Dummy.point_func is p + assert Dummy().point_func == 123