From a83e4c66aa9c2067786da988e0e50cc0d704a3ea Mon Sep 17 00:00:00 2001 From: Thanos Date: Mon, 19 Feb 2024 22:03:02 -0500 Subject: [PATCH 1/5] Begin process of adding iter-related functions. --- docs/api-reference/function-index.rst | 3 ++ docs/porting-guide.rst | 3 ++ hpy/debug/src/autogen_debug_ctx_init.h | 6 +++ hpy/debug/src/autogen_debug_wrappers.c | 36 +++++++++++++++++ .../include/hpy/cpython/autogen_api_impl.h | 15 +++++++ hpy/devel/include/hpy/universal/autogen_ctx.h | 3 ++ .../hpy/universal/autogen_trampolines.h | 12 ++++++ hpy/tools/autogen/conf.py | 3 ++ hpy/tools/autogen/public_api.h | 9 +++++ hpy/trace/src/autogen_trace_ctx_init.h | 10 ++++- hpy/trace/src/autogen_trace_func_table.c | 7 +++- hpy/trace/src/autogen_trace_wrappers.c | 39 +++++++++++++++++++ hpy/universal/src/autogen_ctx_def.h | 3 ++ hpy/universal/src/autogen_ctx_impl.h | 15 +++++++ test/test_hpyiter.py | 26 +++++++++++++ 15 files changed, 186 insertions(+), 4 deletions(-) create mode 100644 test/test_hpyiter.py diff --git a/docs/api-reference/function-index.rst b/docs/api-reference/function-index.rst index 9c4014bb..d267f1e3 100644 --- a/docs/api-reference/function-index.rst +++ b/docs/api-reference/function-index.rst @@ -48,6 +48,8 @@ HPy Core API Function Index * :c:func:`HPyGlobal_Load` * :c:func:`HPyGlobal_Store` * :c:func:`HPyImport_ImportModule` +* :c:func:`HPyIter_Check` +* :c:func:`HPyIter_Next` * :c:func:`HPyListBuilder_Build` * :c:func:`HPyListBuilder_Cancel` * :c:func:`HPyListBuilder_New` @@ -131,6 +133,7 @@ HPy Core API Function Index * :c:func:`HPy_GetItem` * :c:func:`HPy_GetItem_i` * :c:func:`HPy_GetItem_s` +* :c:func:`HPy_GetIter` * :c:func:`HPy_GetSlice` * :c:func:`HPy_HasAttr` * :c:func:`HPy_HasAttr_s` diff --git a/docs/porting-guide.rst b/docs/porting-guide.rst index 70d3e8f6..6f076bba 100644 --- a/docs/porting-guide.rst +++ b/docs/porting-guide.rst @@ -190,6 +190,8 @@ with the code for the :term:`CPython ABI` mode, so it is guaranteed to be correc `PyFloat_AsDouble `_ :c:func:`HPyFloat_AsDouble` `PyFloat_FromDouble `_ :c:func:`HPyFloat_FromDouble` `PyImport_ImportModule `_ :c:func:`HPyImport_ImportModule` + `PyIter_Check `_ :c:func:`HPyIter_Check` + `PyIter_Next `_ :c:func:`HPyIter_Next` `PyList_Append `_ :c:func:`HPyList_Append` `PyList_Check `_ :c:func:`HPyList_Check` `PyList_Insert `_ :c:func:`HPyList_Insert` @@ -252,6 +254,7 @@ with the code for the :term:`CPython ABI` mode, so it is guaranteed to be correc `PyObject_GetAttr `_ :c:func:`HPy_GetAttr` `PyObject_GetAttrString `_ :c:func:`HPy_GetAttr_s` `PyObject_GetItem `_ :c:func:`HPy_GetItem` + `PyObject_GetIter `_ :c:func:`HPy_GetIter` `PyObject_HasAttr `_ :c:func:`HPy_HasAttr` `PyObject_HasAttrString `_ :c:func:`HPy_HasAttr_s` `PyObject_Hash `_ :c:func:`HPy_Hash` diff --git a/hpy/debug/src/autogen_debug_ctx_init.h b/hpy/debug/src/autogen_debug_ctx_init.h index 598e7a3f..8de702f9 100644 --- a/hpy/debug/src/autogen_debug_ctx_init.h +++ b/hpy/debug/src/autogen_debug_ctx_init.h @@ -106,6 +106,9 @@ int debug_ctx_DelItem(HPyContext *dctx, DHPy obj, DHPy key); int debug_ctx_DelItem_i(HPyContext *dctx, DHPy obj, HPy_ssize_t idx); int debug_ctx_DelItem_s(HPyContext *dctx, DHPy obj, const char *utf8_key); int debug_ctx_DelSlice(HPyContext *dctx, DHPy obj, HPy_ssize_t start, HPy_ssize_t end); +DHPy debug_ctx_GetIter(HPyContext *dctx, DHPy obj); +DHPy debug_ctx_Iter_Next(HPyContext *dctx, DHPy obj); +int debug_ctx_Iter_Check(HPyContext *dctx, DHPy obj); DHPy debug_ctx_Type(HPyContext *dctx, DHPy obj); int debug_ctx_TypeCheck(HPyContext *dctx, DHPy obj, DHPy type); const char *debug_ctx_Type_GetName(HPyContext *dctx, DHPy type); @@ -378,6 +381,9 @@ static inline void debug_ctx_init_fields(HPyContext *dctx, HPyContext *uctx) dctx->ctx_DelItem_i = &debug_ctx_DelItem_i; dctx->ctx_DelItem_s = &debug_ctx_DelItem_s; dctx->ctx_DelSlice = &debug_ctx_DelSlice; + dctx->ctx_GetIter = &debug_ctx_GetIter; + dctx->ctx_Iter_Next = &debug_ctx_Iter_Next; + dctx->ctx_Iter_Check = &debug_ctx_Iter_Check; dctx->ctx_Type = &debug_ctx_Type; dctx->ctx_TypeCheck = &debug_ctx_TypeCheck; dctx->ctx_Type_GetName = &debug_ctx_Type_GetName; diff --git a/hpy/debug/src/autogen_debug_wrappers.c b/hpy/debug/src/autogen_debug_wrappers.c index 87b73384..e20ce3f2 100644 --- a/hpy/debug/src/autogen_debug_wrappers.c +++ b/hpy/debug/src/autogen_debug_wrappers.c @@ -1134,6 +1134,42 @@ int debug_ctx_DelSlice(HPyContext *dctx, DHPy obj, HPy_ssize_t start, HPy_ssize_ return universal_result; } +DHPy debug_ctx_GetIter(HPyContext *dctx, DHPy obj) +{ + if (!get_ctx_info(dctx)->is_valid) { + report_invalid_debug_context(); + } + HPy dh_obj = DHPy_unwrap(dctx, obj); + get_ctx_info(dctx)->is_valid = false; + HPy universal_result = HPy_GetIter(get_info(dctx)->uctx, dh_obj); + get_ctx_info(dctx)->is_valid = true; + return DHPy_open(dctx, universal_result); +} + +DHPy debug_ctx_Iter_Next(HPyContext *dctx, DHPy obj) +{ + if (!get_ctx_info(dctx)->is_valid) { + report_invalid_debug_context(); + } + HPy dh_obj = DHPy_unwrap(dctx, obj); + get_ctx_info(dctx)->is_valid = false; + HPy universal_result = HPyIter_Next(get_info(dctx)->uctx, dh_obj); + get_ctx_info(dctx)->is_valid = true; + return DHPy_open(dctx, universal_result); +} + +int debug_ctx_Iter_Check(HPyContext *dctx, DHPy obj) +{ + if (!get_ctx_info(dctx)->is_valid) { + report_invalid_debug_context(); + } + HPy dh_obj = DHPy_unwrap(dctx, obj); + get_ctx_info(dctx)->is_valid = false; + int universal_result = HPyIter_Check(get_info(dctx)->uctx, dh_obj); + get_ctx_info(dctx)->is_valid = true; + return universal_result; +} + DHPy debug_ctx_Type(HPyContext *dctx, DHPy obj) { if (!get_ctx_info(dctx)->is_valid) { diff --git a/hpy/devel/include/hpy/cpython/autogen_api_impl.h b/hpy/devel/include/hpy/cpython/autogen_api_impl.h index 77c837c9..96c1d180 100644 --- a/hpy/devel/include/hpy/cpython/autogen_api_impl.h +++ b/hpy/devel/include/hpy/cpython/autogen_api_impl.h @@ -369,6 +369,21 @@ HPyAPI_FUNC int HPy_DelSlice(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ss return PySequence_DelSlice(_h2py(obj), start, end); } +HPyAPI_FUNC HPy HPy_GetIter(HPyContext *ctx, HPy obj) +{ + return _py2h(PyObject_GetIter(_h2py(obj))); +} + +HPyAPI_FUNC HPy HPyIter_Next(HPyContext *ctx, HPy obj) +{ + return _py2h(PyIter_Next(_h2py(obj))); +} + +HPyAPI_FUNC int HPyIter_Check(HPyContext *ctx, HPy obj) +{ + return PyIter_Check(_h2py(obj)); +} + HPyAPI_FUNC HPy HPy_Repr(HPyContext *ctx, HPy obj) { return _py2h(PyObject_Repr(_h2py(obj))); diff --git a/hpy/devel/include/hpy/universal/autogen_ctx.h b/hpy/devel/include/hpy/universal/autogen_ctx.h index 60ae238d..ecf357d8 100644 --- a/hpy/devel/include/hpy/universal/autogen_ctx.h +++ b/hpy/devel/include/hpy/universal/autogen_ctx.h @@ -283,4 +283,7 @@ struct _HPyContext_s { HPy (*ctx_GetSlice)(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ssize_t end); int (*ctx_SetSlice)(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ssize_t end, HPy value); int (*ctx_DelSlice)(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ssize_t end); + HPy (*ctx_GetIter)(HPyContext *ctx, HPy obj); + HPy (*ctx_Iter_Next)(HPyContext *ctx, HPy obj); + int (*ctx_Iter_Check)(HPyContext *ctx, HPy obj); }; diff --git a/hpy/devel/include/hpy/universal/autogen_trampolines.h b/hpy/devel/include/hpy/universal/autogen_trampolines.h index 4d10e132..d48a1cd5 100644 --- a/hpy/devel/include/hpy/universal/autogen_trampolines.h +++ b/hpy/devel/include/hpy/universal/autogen_trampolines.h @@ -390,6 +390,18 @@ HPyAPI_FUNC int HPy_DelSlice(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ss return ctx->ctx_DelSlice ( ctx, obj, start, end ); } +HPyAPI_FUNC HPy HPy_GetIter(HPyContext *ctx, HPy obj) { + return ctx->ctx_GetIter ( ctx, obj ); +} + +HPyAPI_FUNC HPy HPyIter_Next(HPyContext *ctx, HPy obj) { + return ctx->ctx_Iter_Next ( ctx, obj ); +} + +HPyAPI_FUNC int HPyIter_Check(HPyContext *ctx, HPy obj) { + return ctx->ctx_Iter_Check ( ctx, obj ); +} + HPyAPI_FUNC HPy HPy_Type(HPyContext *ctx, HPy obj) { return ctx->ctx_Type ( ctx, obj ); } diff --git a/hpy/tools/autogen/conf.py b/hpy/tools/autogen/conf.py index 80ee2bc8..4e7bf36f 100644 --- a/hpy/tools/autogen/conf.py +++ b/hpy/tools/autogen/conf.py @@ -29,6 +29,9 @@ 'HPy_HasAttr_s': 'PyObject_HasAttrString', 'HPy_SetAttr': 'PyObject_SetAttr', 'HPy_SetAttr_s': 'PyObject_SetAttrString', + 'HPy_GetIter': 'PyObject_GetIter', + 'HPyIter_Next': 'PyIter_Next', + 'HPyIter_Check': 'PyIter_Check', 'HPy_GetItem': 'PyObject_GetItem', 'HPy_GetItem_i': None, 'HPy_GetItem_s': None, diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 78286fcf..742a713f 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -502,6 +502,15 @@ int HPy_DelItem_s(HPyContext *ctx, HPy obj, const char *utf8_key); HPy_ID(268) int HPy_DelSlice(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ssize_t end); +HPy_ID(269) +HPy HPy_GetIter(HPyContext *ctx, HPy obj); + +HPy_ID(270) +HPy HPyIter_Next(HPyContext *ctx, HPy obj); + +HPy_ID(271) +int HPyIter_Check(HPyContext *ctx, HPy obj); + /** * Returns the type of the given object ``obj``. * diff --git a/hpy/trace/src/autogen_trace_ctx_init.h b/hpy/trace/src/autogen_trace_ctx_init.h index c6453373..c63f984c 100644 --- a/hpy/trace/src/autogen_trace_ctx_init.h +++ b/hpy/trace/src/autogen_trace_ctx_init.h @@ -105,6 +105,9 @@ int trace_ctx_DelItem(HPyContext *tctx, HPy obj, HPy key); int trace_ctx_DelItem_i(HPyContext *tctx, HPy obj, HPy_ssize_t idx); int trace_ctx_DelItem_s(HPyContext *tctx, HPy obj, const char *utf8_key); int trace_ctx_DelSlice(HPyContext *tctx, HPy obj, HPy_ssize_t start, HPy_ssize_t end); +HPy trace_ctx_GetIter(HPyContext *tctx, HPy obj); +HPy trace_ctx_Iter_Next(HPyContext *tctx, HPy obj); +int trace_ctx_Iter_Check(HPyContext *tctx, HPy obj); HPy trace_ctx_Type(HPyContext *tctx, HPy obj); int trace_ctx_TypeCheck(HPyContext *tctx, HPy obj, HPy type); const char *trace_ctx_Type_GetName(HPyContext *tctx, HPy type); @@ -198,8 +201,8 @@ static inline void trace_ctx_init_info(HPyTraceInfo *info, HPyContext *uctx) { info->magic_number = HPY_TRACE_MAGIC; info->uctx = uctx; - info->call_counts = (uint64_t *)calloc(269, sizeof(uint64_t)); - info->durations = (_HPyTime_t *)calloc(269, sizeof(_HPyTime_t)); + info->call_counts = (uint64_t *)calloc(272, sizeof(uint64_t)); + info->durations = (_HPyTime_t *)calloc(272, sizeof(_HPyTime_t)); info->on_enter_func = HPy_NULL; info->on_exit_func = HPy_NULL; } @@ -395,6 +398,9 @@ static inline void trace_ctx_init_fields(HPyContext *tctx, HPyContext *uctx) tctx->ctx_DelItem_i = &trace_ctx_DelItem_i; tctx->ctx_DelItem_s = &trace_ctx_DelItem_s; tctx->ctx_DelSlice = &trace_ctx_DelSlice; + tctx->ctx_GetIter = &trace_ctx_GetIter; + tctx->ctx_Iter_Next = &trace_ctx_Iter_Next; + tctx->ctx_Iter_Check = &trace_ctx_Iter_Check; tctx->ctx_Type = &trace_ctx_Type; tctx->ctx_TypeCheck = &trace_ctx_TypeCheck; tctx->ctx_Type_GetName = &trace_ctx_Type_GetName; diff --git a/hpy/trace/src/autogen_trace_func_table.c b/hpy/trace/src/autogen_trace_func_table.c index 4a239e03..1f45abcd 100644 --- a/hpy/trace/src/autogen_trace_func_table.c +++ b/hpy/trace/src/autogen_trace_func_table.c @@ -12,7 +12,7 @@ #include "trace_internal.h" -#define TRACE_NFUNC 185 +#define TRACE_NFUNC 188 #define NO_FUNC "" static const char *trace_func_table[] = { @@ -285,6 +285,9 @@ static const char *trace_func_table[] = { "ctx_GetSlice", "ctx_SetSlice", "ctx_DelSlice", + "ctx_GetIter", + "ctx_Iter_Next", + "ctx_Iter_Check", NULL /* sentinel */ }; @@ -295,7 +298,7 @@ int hpy_trace_get_nfunc(void) const char * hpy_trace_get_func_name(int idx) { - if (idx >= 0 && idx < 269) + if (idx >= 0 && idx < 272) return trace_func_table[idx]; return NULL; } diff --git a/hpy/trace/src/autogen_trace_wrappers.c b/hpy/trace/src/autogen_trace_wrappers.c index 6f53bcdb..e099f24d 100644 --- a/hpy/trace/src/autogen_trace_wrappers.c +++ b/hpy/trace/src/autogen_trace_wrappers.c @@ -1240,6 +1240,45 @@ int trace_ctx_DelSlice(HPyContext *tctx, HPy obj, HPy_ssize_t start, HPy_ssize_t return res; } +HPy trace_ctx_GetIter(HPyContext *tctx, HPy obj) +{ + HPyTraceInfo *info = hpy_trace_on_enter(tctx, 269); + HPyContext *uctx = info->uctx; + _HPyTime_t _ts_start, _ts_end; + _HPyClockStatus_t r0, r1; + r0 = get_monotonic_clock(&_ts_start); + HPy res = HPy_GetIter(uctx, obj); + r1 = get_monotonic_clock(&_ts_end); + hpy_trace_on_exit(info, 269, r0, r1, &_ts_start, &_ts_end); + return res; +} + +HPy trace_ctx_Iter_Next(HPyContext *tctx, HPy obj) +{ + HPyTraceInfo *info = hpy_trace_on_enter(tctx, 270); + HPyContext *uctx = info->uctx; + _HPyTime_t _ts_start, _ts_end; + _HPyClockStatus_t r0, r1; + r0 = get_monotonic_clock(&_ts_start); + HPy res = HPyIter_Next(uctx, obj); + r1 = get_monotonic_clock(&_ts_end); + hpy_trace_on_exit(info, 270, r0, r1, &_ts_start, &_ts_end); + return res; +} + +int trace_ctx_Iter_Check(HPyContext *tctx, HPy obj) +{ + HPyTraceInfo *info = hpy_trace_on_enter(tctx, 271); + HPyContext *uctx = info->uctx; + _HPyTime_t _ts_start, _ts_end; + _HPyClockStatus_t r0, r1; + r0 = get_monotonic_clock(&_ts_start); + int res = HPyIter_Check(uctx, obj); + r1 = get_monotonic_clock(&_ts_end); + hpy_trace_on_exit(info, 271, r0, r1, &_ts_start, &_ts_end); + return res; +} + HPy trace_ctx_Type(HPyContext *tctx, HPy obj) { HPyTraceInfo *info = hpy_trace_on_enter(tctx, 165); diff --git a/hpy/universal/src/autogen_ctx_def.h b/hpy/universal/src/autogen_ctx_def.h index e49c62e7..64521b2c 100644 --- a/hpy/universal/src/autogen_ctx_def.h +++ b/hpy/universal/src/autogen_ctx_def.h @@ -111,6 +111,9 @@ struct _HPyContext_s g_universal_ctx = { .ctx_DelItem_i = &ctx_DelItem_i, .ctx_DelItem_s = &ctx_DelItem_s, .ctx_DelSlice = &ctx_DelSlice, + .ctx_GetIter = &ctx_GetIter, + .ctx_Iter_Next = &ctx_Iter_Next, + .ctx_Iter_Check = &ctx_Iter_Check, .ctx_Type = &ctx_Type, .ctx_TypeCheck = &ctx_TypeCheck, .ctx_Type_GetName = &ctx_Type_GetName, diff --git a/hpy/universal/src/autogen_ctx_impl.h b/hpy/universal/src/autogen_ctx_impl.h index 68ffafbe..9578bfb8 100644 --- a/hpy/universal/src/autogen_ctx_impl.h +++ b/hpy/universal/src/autogen_ctx_impl.h @@ -365,6 +365,21 @@ HPyAPI_IMPL int ctx_DelSlice(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ss return PySequence_DelSlice(_h2py(obj), start, end); } +HPyAPI_IMPL HPy ctx_GetIter(HPyContext *ctx, HPy obj) +{ + return _py2h(PyObject_GetIter(_h2py(obj))); +} + +HPyAPI_IMPL HPy ctx_Iter_Next(HPyContext *ctx, HPy obj) +{ + return _py2h(PyIter_Next(_h2py(obj))); +} + +HPyAPI_IMPL int ctx_Iter_Check(HPyContext *ctx, HPy obj) +{ + return PyIter_Check(_h2py(obj)); +} + HPyAPI_IMPL HPy ctx_Repr(HPyContext *ctx, HPy obj) { return _py2h(PyObject_Repr(_h2py(obj))); diff --git a/test/test_hpyiter.py b/test/test_hpyiter.py new file mode 100644 index 00000000..a1559019 --- /dev/null +++ b/test/test_hpyiter.py @@ -0,0 +1,26 @@ +from .support import HPyTest + +class TestIter(HPyTest): + + def test_check(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", HPyFunc_O) + static HPy f_impl(HPyContext *ctx, HPy self, HPy arg) + { + if (HPyIter_Check(ctx, arg)) + return HPy_Dup(ctx, ctx->h_True); + return HPy_Dup(ctx, ctx->h_False); + } + @EXPORT(f) + @INIT + """) + + class MyList(list): + pass + + assert mod.f(iter((1,))) is True + assert mod.f(iter([])) is True + assert mod.f(iter('hello')) is True + assert mod.f(iter(MyList())) is True + assert mod.f(object()) is False + assert mod.f(10) is False From 4fd7e7e2dce08d3b766df14fe1de71819ed81745 Mon Sep 17 00:00:00 2001 From: Thanos Date: Tue, 20 Feb 2024 14:27:11 -0500 Subject: [PATCH 2/5] Flesh out tests a bit more. --- hpy/tools/autogen/conf.py | 4 +-- test/test_hpyiter.py | 65 ++++++++++++++++++++++++++++++++++----- test/test_object.py | 58 ++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 9 deletions(-) diff --git a/hpy/tools/autogen/conf.py b/hpy/tools/autogen/conf.py index 4e7bf36f..5ebf3457 100644 --- a/hpy/tools/autogen/conf.py +++ b/hpy/tools/autogen/conf.py @@ -30,8 +30,6 @@ 'HPy_SetAttr': 'PyObject_SetAttr', 'HPy_SetAttr_s': 'PyObject_SetAttrString', 'HPy_GetIter': 'PyObject_GetIter', - 'HPyIter_Next': 'PyIter_Next', - 'HPyIter_Check': 'PyIter_Check', 'HPy_GetItem': 'PyObject_GetItem', 'HPy_GetItem_i': None, 'HPy_GetItem_s': None, @@ -110,6 +108,8 @@ 'HPy_RichCompare': 'PyObject_RichCompare', 'HPy_RichCompareBool': 'PyObject_RichCompareBool', 'HPy_Hash': 'PyObject_Hash', + 'HPyIter_Next': 'PyIter_Next', + 'HPyIter_Check': 'PyIter_Check', 'HPyListBuilder_New': None, 'HPyListBuilder_Set': None, 'HPyListBuilder_Build': None, diff --git a/test/test_hpyiter.py b/test/test_hpyiter.py index a1559019..de5990c3 100644 --- a/test/test_hpyiter.py +++ b/test/test_hpyiter.py @@ -2,7 +2,7 @@ class TestIter(HPyTest): - def test_check(self): + def test_Check(self): mod = self.make_module(""" HPyDef_METH(f, "f", HPyFunc_O) static HPy f_impl(HPyContext *ctx, HPy self, HPy arg) @@ -15,12 +15,63 @@ def test_check(self): @INIT """) - class MyList(list): - pass + class CustomIterable: + def __init__(self): + self._iter = iter([1, 2, 3]) + + def __iter__(self): + return self._iter + + class CustomIterator: + def __init__(self): + self._iter = iter([1, 2, 3]) + + def __iter__(self): + return self._iter + + def __next__(self): + return next(self._iter) - assert mod.f(iter((1,))) is True - assert mod.f(iter([])) is True - assert mod.f(iter('hello')) is True - assert mod.f(iter(MyList())) is True assert mod.f(object()) is False assert mod.f(10) is False + + assert mod.f((1, 2)) is False + assert mod.f(iter((1, 2))) is True + + assert mod.f([]) is False + assert mod.f(iter([])) is True + + assert mod.f('hello') is False + assert mod.f(iter('hello')) is True + + assert mod.f(map(int, ("1", "2"))) is True + assert mod.f(range(1, 10)) is False + + assert mod.f(CustomIterable()) is False + assert mod.f(iter(CustomIterable())) is True + assert mod.f(CustomIterator()) is True + + def test_Next(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", HPyFunc_O) + static HPy f_impl(HPyContext *ctx, HPy self, HPy arg) + { + HPy result = HPyIter_Next(ctx, arg); + int is_null = HPy_IsNull(result); + + if (is_null && HPyErr_Occurred(ctx)) + return HPy_NULL; + if (is_null) + return HPyErr_SetObject(ctx, ctx->h_StopIteration, ctx->h_None); + return result; + } + @EXPORT(f) + @INIT + """) + + import pytest + + with pytest.raises(StopIteration): + assert mod.f(iter([])) + + assert mod.f((i for i in range(1, 10))) == 1 diff --git a/test/test_object.py b/test/test_object.py index 10ef4f84..8e504504 100644 --- a/test/test_object.py +++ b/test/test_object.py @@ -905,6 +905,64 @@ class Dummy: import pytest with pytest.raises(TypeError): mod.f(Dummy(), 42) + + def test_getiter(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", HPyFunc_O) + static HPy f_impl(HPyContext *ctx, HPy self, HPy arg) + { + HPy iterator; + iterator = HPy_GetIter(ctx, arg); + if HPy_IsNull(iterator) + return HPy_NULL; + return iterator; + } + @EXPORT(f) + @INIT + """) + + def test_for_loop(iterator): + results = [] + for obj in iterator: + results.append(obj) + return results + + class WithIter: + def __iter__(self): + return (1, 2, 3).__iter__() + + class WithoutIter: + pass + + case = [1, 2, 3] + result = mod.f(case) + assert result + assert test_for_loop(result) == [1, 2, 3] + + case = iter([1, 2, 3]) + result = mod.f(case) + assert result + assert test_for_loop(result) == [1, 2, 3] + + case = zip((1, 2, 3), [4, 5, 6]) + result = mod.f(case) + assert result + assert test_for_loop(result) == [(1, 4), (2, 5), (3, 6)] + + case = range(10) + result = mod.f(case) + assert result + assert test_for_loop(result) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + case = WithIter() + result = mod.f(case) + assert result + assert test_for_loop(result) == [1, 2, 3] + + import pytest + with pytest.raises(TypeError): + assert mod.f(WithoutIter()) + def test_dump(self): # _HPy_Dump is supposed to be used e.g. inside a gdb session: it From 73d03e89b817150de4b47c0cddbedc3d0658a1fd Mon Sep 17 00:00:00 2001 From: Thanos Date: Tue, 20 Feb 2024 16:47:57 -0500 Subject: [PATCH 3/5] Add docstrings to new functions in public_api.h. - Move functions to be consistent with reference file comments (i.e. `abstract.h`). - Additionally, add a bit more body to the HPyIter_Next test method. --- hpy/debug/src/autogen_debug_ctx_init.h | 12 +-- hpy/debug/src/autogen_debug_wrappers.c | 72 ++++++++--------- .../include/hpy/cpython/autogen_api_impl.h | 30 +++---- .../hpy/universal/autogen_trampolines.h | 24 +++--- hpy/tools/autogen/public_api.h | 59 +++++++++++--- hpy/trace/src/autogen_trace_ctx_init.h | 12 +-- hpy/trace/src/autogen_trace_wrappers.c | 78 +++++++++---------- hpy/universal/src/autogen_ctx_def.h | 6 +- hpy/universal/src/autogen_ctx_impl.h | 30 +++---- test/test_hpyiter.py | 17 +++- 10 files changed, 197 insertions(+), 143 deletions(-) diff --git a/hpy/debug/src/autogen_debug_ctx_init.h b/hpy/debug/src/autogen_debug_ctx_init.h index 8de702f9..609a5d19 100644 --- a/hpy/debug/src/autogen_debug_ctx_init.h +++ b/hpy/debug/src/autogen_debug_ctx_init.h @@ -71,6 +71,9 @@ int debug_ctx_Callable_Check(HPyContext *dctx, DHPy h); DHPy debug_ctx_CallTupleDict(HPyContext *dctx, DHPy callable, DHPy args, DHPy kw); DHPy debug_ctx_Call(HPyContext *dctx, DHPy callable, const DHPy *args, size_t nargs, DHPy kwnames); DHPy debug_ctx_CallMethod(HPyContext *dctx, DHPy name, const DHPy *args, size_t nargs, DHPy kwnames); +DHPy debug_ctx_GetIter(HPyContext *dctx, DHPy obj); +DHPy debug_ctx_Iter_Next(HPyContext *dctx, DHPy obj); +int debug_ctx_Iter_Check(HPyContext *dctx, DHPy obj); void debug_ctx_FatalError(HPyContext *dctx, const char *message); void debug_ctx_Err_SetString(HPyContext *dctx, DHPy h_type, const char *utf8_message); void debug_ctx_Err_SetObject(HPyContext *dctx, DHPy h_type, DHPy h_value); @@ -106,9 +109,6 @@ int debug_ctx_DelItem(HPyContext *dctx, DHPy obj, DHPy key); int debug_ctx_DelItem_i(HPyContext *dctx, DHPy obj, HPy_ssize_t idx); int debug_ctx_DelItem_s(HPyContext *dctx, DHPy obj, const char *utf8_key); int debug_ctx_DelSlice(HPyContext *dctx, DHPy obj, HPy_ssize_t start, HPy_ssize_t end); -DHPy debug_ctx_GetIter(HPyContext *dctx, DHPy obj); -DHPy debug_ctx_Iter_Next(HPyContext *dctx, DHPy obj); -int debug_ctx_Iter_Check(HPyContext *dctx, DHPy obj); DHPy debug_ctx_Type(HPyContext *dctx, DHPy obj); int debug_ctx_TypeCheck(HPyContext *dctx, DHPy obj, DHPy type); const char *debug_ctx_Type_GetName(HPyContext *dctx, DHPy type); @@ -346,6 +346,9 @@ static inline void debug_ctx_init_fields(HPyContext *dctx, HPyContext *uctx) dctx->ctx_CallTupleDict = &debug_ctx_CallTupleDict; dctx->ctx_Call = &debug_ctx_Call; dctx->ctx_CallMethod = &debug_ctx_CallMethod; + dctx->ctx_GetIter = &debug_ctx_GetIter; + dctx->ctx_Iter_Next = &debug_ctx_Iter_Next; + dctx->ctx_Iter_Check = &debug_ctx_Iter_Check; dctx->ctx_FatalError = &debug_ctx_FatalError; dctx->ctx_Err_SetString = &debug_ctx_Err_SetString; dctx->ctx_Err_SetObject = &debug_ctx_Err_SetObject; @@ -381,9 +384,6 @@ static inline void debug_ctx_init_fields(HPyContext *dctx, HPyContext *uctx) dctx->ctx_DelItem_i = &debug_ctx_DelItem_i; dctx->ctx_DelItem_s = &debug_ctx_DelItem_s; dctx->ctx_DelSlice = &debug_ctx_DelSlice; - dctx->ctx_GetIter = &debug_ctx_GetIter; - dctx->ctx_Iter_Next = &debug_ctx_Iter_Next; - dctx->ctx_Iter_Check = &debug_ctx_Iter_Check; dctx->ctx_Type = &debug_ctx_Type; dctx->ctx_TypeCheck = &debug_ctx_TypeCheck; dctx->ctx_Type_GetName = &debug_ctx_Type_GetName; diff --git a/hpy/debug/src/autogen_debug_wrappers.c b/hpy/debug/src/autogen_debug_wrappers.c index e20ce3f2..c0fda457 100644 --- a/hpy/debug/src/autogen_debug_wrappers.c +++ b/hpy/debug/src/autogen_debug_wrappers.c @@ -731,6 +731,42 @@ DHPy debug_ctx_CallTupleDict(HPyContext *dctx, DHPy callable, DHPy args, DHPy kw return DHPy_open(dctx, universal_result); } +DHPy debug_ctx_GetIter(HPyContext *dctx, DHPy obj) +{ + if (!get_ctx_info(dctx)->is_valid) { + report_invalid_debug_context(); + } + HPy dh_obj = DHPy_unwrap(dctx, obj); + get_ctx_info(dctx)->is_valid = false; + HPy universal_result = HPy_GetIter(get_info(dctx)->uctx, dh_obj); + get_ctx_info(dctx)->is_valid = true; + return DHPy_open(dctx, universal_result); +} + +DHPy debug_ctx_Iter_Next(HPyContext *dctx, DHPy obj) +{ + if (!get_ctx_info(dctx)->is_valid) { + report_invalid_debug_context(); + } + HPy dh_obj = DHPy_unwrap(dctx, obj); + get_ctx_info(dctx)->is_valid = false; + HPy universal_result = HPyIter_Next(get_info(dctx)->uctx, dh_obj); + get_ctx_info(dctx)->is_valid = true; + return DHPy_open(dctx, universal_result); +} + +int debug_ctx_Iter_Check(HPyContext *dctx, DHPy obj) +{ + if (!get_ctx_info(dctx)->is_valid) { + report_invalid_debug_context(); + } + HPy dh_obj = DHPy_unwrap(dctx, obj); + get_ctx_info(dctx)->is_valid = false; + int universal_result = HPyIter_Check(get_info(dctx)->uctx, dh_obj); + get_ctx_info(dctx)->is_valid = true; + return universal_result; +} + void debug_ctx_FatalError(HPyContext *dctx, const char *message) { if (!get_ctx_info(dctx)->is_valid) { @@ -1134,42 +1170,6 @@ int debug_ctx_DelSlice(HPyContext *dctx, DHPy obj, HPy_ssize_t start, HPy_ssize_ return universal_result; } -DHPy debug_ctx_GetIter(HPyContext *dctx, DHPy obj) -{ - if (!get_ctx_info(dctx)->is_valid) { - report_invalid_debug_context(); - } - HPy dh_obj = DHPy_unwrap(dctx, obj); - get_ctx_info(dctx)->is_valid = false; - HPy universal_result = HPy_GetIter(get_info(dctx)->uctx, dh_obj); - get_ctx_info(dctx)->is_valid = true; - return DHPy_open(dctx, universal_result); -} - -DHPy debug_ctx_Iter_Next(HPyContext *dctx, DHPy obj) -{ - if (!get_ctx_info(dctx)->is_valid) { - report_invalid_debug_context(); - } - HPy dh_obj = DHPy_unwrap(dctx, obj); - get_ctx_info(dctx)->is_valid = false; - HPy universal_result = HPyIter_Next(get_info(dctx)->uctx, dh_obj); - get_ctx_info(dctx)->is_valid = true; - return DHPy_open(dctx, universal_result); -} - -int debug_ctx_Iter_Check(HPyContext *dctx, DHPy obj) -{ - if (!get_ctx_info(dctx)->is_valid) { - report_invalid_debug_context(); - } - HPy dh_obj = DHPy_unwrap(dctx, obj); - get_ctx_info(dctx)->is_valid = false; - int universal_result = HPyIter_Check(get_info(dctx)->uctx, dh_obj); - get_ctx_info(dctx)->is_valid = true; - return universal_result; -} - DHPy debug_ctx_Type(HPyContext *dctx, DHPy obj) { if (!get_ctx_info(dctx)->is_valid) { diff --git a/hpy/devel/include/hpy/cpython/autogen_api_impl.h b/hpy/devel/include/hpy/cpython/autogen_api_impl.h index 96c1d180..53cc8e43 100644 --- a/hpy/devel/include/hpy/cpython/autogen_api_impl.h +++ b/hpy/devel/include/hpy/cpython/autogen_api_impl.h @@ -240,6 +240,21 @@ HPyAPI_FUNC int HPyCallable_Check(HPyContext *ctx, HPy h) return PyCallable_Check(_h2py(h)); } +HPyAPI_FUNC HPy HPy_GetIter(HPyContext *ctx, HPy obj) +{ + return _py2h(PyObject_GetIter(_h2py(obj))); +} + +HPyAPI_FUNC HPy HPyIter_Next(HPyContext *ctx, HPy obj) +{ + return _py2h(PyIter_Next(_h2py(obj))); +} + +HPyAPI_FUNC int HPyIter_Check(HPyContext *ctx, HPy obj) +{ + return PyIter_Check(_h2py(obj)); +} + HPyAPI_FUNC HPy HPyErr_SetString(HPyContext *ctx, HPy h_type, const char *utf8_message) { PyErr_SetString(_h2py(h_type), utf8_message); @@ -369,21 +384,6 @@ HPyAPI_FUNC int HPy_DelSlice(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ss return PySequence_DelSlice(_h2py(obj), start, end); } -HPyAPI_FUNC HPy HPy_GetIter(HPyContext *ctx, HPy obj) -{ - return _py2h(PyObject_GetIter(_h2py(obj))); -} - -HPyAPI_FUNC HPy HPyIter_Next(HPyContext *ctx, HPy obj) -{ - return _py2h(PyIter_Next(_h2py(obj))); -} - -HPyAPI_FUNC int HPyIter_Check(HPyContext *ctx, HPy obj) -{ - return PyIter_Check(_h2py(obj)); -} - HPyAPI_FUNC HPy HPy_Repr(HPyContext *ctx, HPy obj) { return _py2h(PyObject_Repr(_h2py(obj))); diff --git a/hpy/devel/include/hpy/universal/autogen_trampolines.h b/hpy/devel/include/hpy/universal/autogen_trampolines.h index d48a1cd5..c4dc36ca 100644 --- a/hpy/devel/include/hpy/universal/autogen_trampolines.h +++ b/hpy/devel/include/hpy/universal/autogen_trampolines.h @@ -254,6 +254,18 @@ HPyAPI_FUNC HPy HPy_CallMethod(HPyContext *ctx, HPy name, const HPy *args, size_ return ctx->ctx_CallMethod ( ctx, name, args, nargs, kwnames ); } +HPyAPI_FUNC HPy HPy_GetIter(HPyContext *ctx, HPy obj) { + return ctx->ctx_GetIter ( ctx, obj ); +} + +HPyAPI_FUNC HPy HPyIter_Next(HPyContext *ctx, HPy obj) { + return ctx->ctx_Iter_Next ( ctx, obj ); +} + +HPyAPI_FUNC int HPyIter_Check(HPyContext *ctx, HPy obj) { + return ctx->ctx_Iter_Check ( ctx, obj ); +} + HPyAPI_FUNC HPy HPyErr_SetString(HPyContext *ctx, HPy h_type, const char *utf8_message) { ctx->ctx_Err_SetString ( ctx, h_type, utf8_message ); return HPy_NULL; } @@ -390,18 +402,6 @@ HPyAPI_FUNC int HPy_DelSlice(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ss return ctx->ctx_DelSlice ( ctx, obj, start, end ); } -HPyAPI_FUNC HPy HPy_GetIter(HPyContext *ctx, HPy obj) { - return ctx->ctx_GetIter ( ctx, obj ); -} - -HPyAPI_FUNC HPy HPyIter_Next(HPyContext *ctx, HPy obj) { - return ctx->ctx_Iter_Next ( ctx, obj ); -} - -HPyAPI_FUNC int HPyIter_Check(HPyContext *ctx, HPy obj) { - return ctx->ctx_Iter_Check ( ctx, obj ); -} - HPyAPI_FUNC HPy HPy_Type(HPyContext *ctx, HPy obj) { return ctx->ctx_Type ( ctx, obj ); } diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 742a713f..a0fa0c3c 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -307,6 +307,56 @@ HPy HPy_Call(HPyContext *ctx, HPy callable, const HPy *args, size_t nargs, HPy k HPy_ID(262) HPy HPy_CallMethod(HPyContext *ctx, HPy name, const HPy *args, size_t nargs, HPy kwnames); +/** + * Return a new iterator for iterable object ``obj``. This is the equivalent + * of the Python expression ``iter(obj)``. + * + * :param ctx: + * The execution context. + * :param obj: + * An iterable Python object (must not be ``HPy_NULL``). If the object is + * not iterable, a ``TypeError`` will be raised. + * + * :returns: + * The new iterator, ``obj`` itself if it is already an iterator, or + * ``HPy_NULL`` on failure. + */ +HPy_ID(269) +HPy HPy_GetIter(HPyContext *ctx, HPy obj); + +/** + * Return the next value from iterator ``obj``. + * + * :param ctx: + * The execution context. + * :param obj: + * An iterator Python object (must not be ``HPy_NULL``). This can be + * verified with ``HPy_IterCheck``. Otherwise, the behavior is undefined + * (verification of the argument is only done in debug mode). + * + * :returns: + * The new value in iterator ``obj``, or ``HPy_NULL`` on failure. If the + * iterator was exhausted normally, an exception will not be set. In + * case of some other error, one will be set. + */ +HPy_ID(270) +HPy HPyIter_Next(HPyContext *ctx, HPy obj); + +/** + * Tests if an object is an instance of a Python iterator. + * + * :param ctx: + * The execution context. + * :param obj: + * A handle to an arbitrary object (must not be ``HPy_NULL``). + * + * :returns: + * Non-zero if object ``h`` provides the ``Iterator`` protocol, and ``0`` + * otherwise. + */ +HPy_ID(271) +int HPyIter_Check(HPyContext *ctx, HPy obj); + /* pyerrors.h */ HPy_ID(136) void HPy_FatalError(HPyContext *ctx, const char *message); @@ -502,15 +552,6 @@ int HPy_DelItem_s(HPyContext *ctx, HPy obj, const char *utf8_key); HPy_ID(268) int HPy_DelSlice(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ssize_t end); -HPy_ID(269) -HPy HPy_GetIter(HPyContext *ctx, HPy obj); - -HPy_ID(270) -HPy HPyIter_Next(HPyContext *ctx, HPy obj); - -HPy_ID(271) -int HPyIter_Check(HPyContext *ctx, HPy obj); - /** * Returns the type of the given object ``obj``. * diff --git a/hpy/trace/src/autogen_trace_ctx_init.h b/hpy/trace/src/autogen_trace_ctx_init.h index c63f984c..9d5eae4b 100644 --- a/hpy/trace/src/autogen_trace_ctx_init.h +++ b/hpy/trace/src/autogen_trace_ctx_init.h @@ -71,6 +71,9 @@ int trace_ctx_Callable_Check(HPyContext *tctx, HPy h); HPy trace_ctx_CallTupleDict(HPyContext *tctx, HPy callable, HPy args, HPy kw); HPy trace_ctx_Call(HPyContext *tctx, HPy callable, const HPy *args, size_t nargs, HPy kwnames); HPy trace_ctx_CallMethod(HPyContext *tctx, HPy name, const HPy *args, size_t nargs, HPy kwnames); +HPy trace_ctx_GetIter(HPyContext *tctx, HPy obj); +HPy trace_ctx_Iter_Next(HPyContext *tctx, HPy obj); +int trace_ctx_Iter_Check(HPyContext *tctx, HPy obj); void trace_ctx_Err_SetString(HPyContext *tctx, HPy h_type, const char *utf8_message); void trace_ctx_Err_SetObject(HPyContext *tctx, HPy h_type, HPy h_value); HPy trace_ctx_Err_SetFromErrnoWithFilename(HPyContext *tctx, HPy h_type, const char *filename_fsencoded); @@ -105,9 +108,6 @@ int trace_ctx_DelItem(HPyContext *tctx, HPy obj, HPy key); int trace_ctx_DelItem_i(HPyContext *tctx, HPy obj, HPy_ssize_t idx); int trace_ctx_DelItem_s(HPyContext *tctx, HPy obj, const char *utf8_key); int trace_ctx_DelSlice(HPyContext *tctx, HPy obj, HPy_ssize_t start, HPy_ssize_t end); -HPy trace_ctx_GetIter(HPyContext *tctx, HPy obj); -HPy trace_ctx_Iter_Next(HPyContext *tctx, HPy obj); -int trace_ctx_Iter_Check(HPyContext *tctx, HPy obj); HPy trace_ctx_Type(HPyContext *tctx, HPy obj); int trace_ctx_TypeCheck(HPyContext *tctx, HPy obj, HPy type); const char *trace_ctx_Type_GetName(HPyContext *tctx, HPy type); @@ -363,6 +363,9 @@ static inline void trace_ctx_init_fields(HPyContext *tctx, HPyContext *uctx) tctx->ctx_CallTupleDict = &trace_ctx_CallTupleDict; tctx->ctx_Call = &trace_ctx_Call; tctx->ctx_CallMethod = &trace_ctx_CallMethod; + tctx->ctx_GetIter = &trace_ctx_GetIter; + tctx->ctx_Iter_Next = &trace_ctx_Iter_Next; + tctx->ctx_Iter_Check = &trace_ctx_Iter_Check; tctx->ctx_FatalError = uctx->ctx_FatalError; tctx->ctx_Err_SetString = &trace_ctx_Err_SetString; tctx->ctx_Err_SetObject = &trace_ctx_Err_SetObject; @@ -398,9 +401,6 @@ static inline void trace_ctx_init_fields(HPyContext *tctx, HPyContext *uctx) tctx->ctx_DelItem_i = &trace_ctx_DelItem_i; tctx->ctx_DelItem_s = &trace_ctx_DelItem_s; tctx->ctx_DelSlice = &trace_ctx_DelSlice; - tctx->ctx_GetIter = &trace_ctx_GetIter; - tctx->ctx_Iter_Next = &trace_ctx_Iter_Next; - tctx->ctx_Iter_Check = &trace_ctx_Iter_Check; tctx->ctx_Type = &trace_ctx_Type; tctx->ctx_TypeCheck = &trace_ctx_TypeCheck; tctx->ctx_Type_GetName = &trace_ctx_Type_GetName; diff --git a/hpy/trace/src/autogen_trace_wrappers.c b/hpy/trace/src/autogen_trace_wrappers.c index e099f24d..da2bfe95 100644 --- a/hpy/trace/src/autogen_trace_wrappers.c +++ b/hpy/trace/src/autogen_trace_wrappers.c @@ -804,6 +804,45 @@ HPy trace_ctx_CallMethod(HPyContext *tctx, HPy name, const HPy *args, size_t nar return res; } +HPy trace_ctx_GetIter(HPyContext *tctx, HPy obj) +{ + HPyTraceInfo *info = hpy_trace_on_enter(tctx, 269); + HPyContext *uctx = info->uctx; + _HPyTime_t _ts_start, _ts_end; + _HPyClockStatus_t r0, r1; + r0 = get_monotonic_clock(&_ts_start); + HPy res = HPy_GetIter(uctx, obj); + r1 = get_monotonic_clock(&_ts_end); + hpy_trace_on_exit(info, 269, r0, r1, &_ts_start, &_ts_end); + return res; +} + +HPy trace_ctx_Iter_Next(HPyContext *tctx, HPy obj) +{ + HPyTraceInfo *info = hpy_trace_on_enter(tctx, 270); + HPyContext *uctx = info->uctx; + _HPyTime_t _ts_start, _ts_end; + _HPyClockStatus_t r0, r1; + r0 = get_monotonic_clock(&_ts_start); + HPy res = HPyIter_Next(uctx, obj); + r1 = get_monotonic_clock(&_ts_end); + hpy_trace_on_exit(info, 270, r0, r1, &_ts_start, &_ts_end); + return res; +} + +int trace_ctx_Iter_Check(HPyContext *tctx, HPy obj) +{ + HPyTraceInfo *info = hpy_trace_on_enter(tctx, 271); + HPyContext *uctx = info->uctx; + _HPyTime_t _ts_start, _ts_end; + _HPyClockStatus_t r0, r1; + r0 = get_monotonic_clock(&_ts_start); + int res = HPyIter_Check(uctx, obj); + r1 = get_monotonic_clock(&_ts_end); + hpy_trace_on_exit(info, 271, r0, r1, &_ts_start, &_ts_end); + return res; +} + void trace_ctx_Err_SetString(HPyContext *tctx, HPy h_type, const char *utf8_message) { HPyTraceInfo *info = hpy_trace_on_enter(tctx, 137); @@ -1240,45 +1279,6 @@ int trace_ctx_DelSlice(HPyContext *tctx, HPy obj, HPy_ssize_t start, HPy_ssize_t return res; } -HPy trace_ctx_GetIter(HPyContext *tctx, HPy obj) -{ - HPyTraceInfo *info = hpy_trace_on_enter(tctx, 269); - HPyContext *uctx = info->uctx; - _HPyTime_t _ts_start, _ts_end; - _HPyClockStatus_t r0, r1; - r0 = get_monotonic_clock(&_ts_start); - HPy res = HPy_GetIter(uctx, obj); - r1 = get_monotonic_clock(&_ts_end); - hpy_trace_on_exit(info, 269, r0, r1, &_ts_start, &_ts_end); - return res; -} - -HPy trace_ctx_Iter_Next(HPyContext *tctx, HPy obj) -{ - HPyTraceInfo *info = hpy_trace_on_enter(tctx, 270); - HPyContext *uctx = info->uctx; - _HPyTime_t _ts_start, _ts_end; - _HPyClockStatus_t r0, r1; - r0 = get_monotonic_clock(&_ts_start); - HPy res = HPyIter_Next(uctx, obj); - r1 = get_monotonic_clock(&_ts_end); - hpy_trace_on_exit(info, 270, r0, r1, &_ts_start, &_ts_end); - return res; -} - -int trace_ctx_Iter_Check(HPyContext *tctx, HPy obj) -{ - HPyTraceInfo *info = hpy_trace_on_enter(tctx, 271); - HPyContext *uctx = info->uctx; - _HPyTime_t _ts_start, _ts_end; - _HPyClockStatus_t r0, r1; - r0 = get_monotonic_clock(&_ts_start); - int res = HPyIter_Check(uctx, obj); - r1 = get_monotonic_clock(&_ts_end); - hpy_trace_on_exit(info, 271, r0, r1, &_ts_start, &_ts_end); - return res; -} - HPy trace_ctx_Type(HPyContext *tctx, HPy obj) { HPyTraceInfo *info = hpy_trace_on_enter(tctx, 165); diff --git a/hpy/universal/src/autogen_ctx_def.h b/hpy/universal/src/autogen_ctx_def.h index 64521b2c..ec33d46f 100644 --- a/hpy/universal/src/autogen_ctx_def.h +++ b/hpy/universal/src/autogen_ctx_def.h @@ -76,6 +76,9 @@ struct _HPyContext_s g_universal_ctx = { .ctx_CallTupleDict = &ctx_CallTupleDict, .ctx_Call = &ctx_Call, .ctx_CallMethod = &ctx_CallMethod, + .ctx_GetIter = &ctx_GetIter, + .ctx_Iter_Next = &ctx_Iter_Next, + .ctx_Iter_Check = &ctx_Iter_Check, .ctx_FatalError = &ctx_FatalError, .ctx_Err_SetString = &ctx_Err_SetString, .ctx_Err_SetObject = &ctx_Err_SetObject, @@ -111,9 +114,6 @@ struct _HPyContext_s g_universal_ctx = { .ctx_DelItem_i = &ctx_DelItem_i, .ctx_DelItem_s = &ctx_DelItem_s, .ctx_DelSlice = &ctx_DelSlice, - .ctx_GetIter = &ctx_GetIter, - .ctx_Iter_Next = &ctx_Iter_Next, - .ctx_Iter_Check = &ctx_Iter_Check, .ctx_Type = &ctx_Type, .ctx_TypeCheck = &ctx_TypeCheck, .ctx_Type_GetName = &ctx_Type_GetName, diff --git a/hpy/universal/src/autogen_ctx_impl.h b/hpy/universal/src/autogen_ctx_impl.h index 9578bfb8..540888e4 100644 --- a/hpy/universal/src/autogen_ctx_impl.h +++ b/hpy/universal/src/autogen_ctx_impl.h @@ -240,6 +240,21 @@ HPyAPI_IMPL int ctx_Callable_Check(HPyContext *ctx, HPy h) return PyCallable_Check(_h2py(h)); } +HPyAPI_IMPL HPy ctx_GetIter(HPyContext *ctx, HPy obj) +{ + return _py2h(PyObject_GetIter(_h2py(obj))); +} + +HPyAPI_IMPL HPy ctx_Iter_Next(HPyContext *ctx, HPy obj) +{ + return _py2h(PyIter_Next(_h2py(obj))); +} + +HPyAPI_IMPL int ctx_Iter_Check(HPyContext *ctx, HPy obj) +{ + return PyIter_Check(_h2py(obj)); +} + HPyAPI_IMPL void ctx_Err_SetString(HPyContext *ctx, HPy h_type, const char *utf8_message) { PyErr_SetString(_h2py(h_type), utf8_message); @@ -365,21 +380,6 @@ HPyAPI_IMPL int ctx_DelSlice(HPyContext *ctx, HPy obj, HPy_ssize_t start, HPy_ss return PySequence_DelSlice(_h2py(obj), start, end); } -HPyAPI_IMPL HPy ctx_GetIter(HPyContext *ctx, HPy obj) -{ - return _py2h(PyObject_GetIter(_h2py(obj))); -} - -HPyAPI_IMPL HPy ctx_Iter_Next(HPyContext *ctx, HPy obj) -{ - return _py2h(PyIter_Next(_h2py(obj))); -} - -HPyAPI_IMPL int ctx_Iter_Check(HPyContext *ctx, HPy obj) -{ - return PyIter_Check(_h2py(obj)); -} - HPyAPI_IMPL HPy ctx_Repr(HPyContext *ctx, HPy obj) { return _py2h(PyObject_Repr(_h2py(obj))); diff --git a/test/test_hpyiter.py b/test/test_hpyiter.py index de5990c3..58387253 100644 --- a/test/test_hpyiter.py +++ b/test/test_hpyiter.py @@ -69,9 +69,22 @@ def test_Next(self): @INIT """) - import pytest + class CustomIterator: + def __init__(self): + self._iter = iter(["a", "b", "c"]) + + def __iter__(self): + return self._iter + def __next__(self): + return next(self._iter) + + assert mod.f(iter([3, 2, 1])) == 3 + assert mod.f((i for i in range(1, 10))) == 1 + assert mod.f(CustomIterator()) == "a" + + import pytest with pytest.raises(StopIteration): assert mod.f(iter([])) - assert mod.f((i for i in range(1, 10))) == 1 + From e8d5c79561b9cadf66f3c98b6c5e2af6f6242906 Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Thu, 22 Feb 2024 20:13:23 -0500 Subject: [PATCH 4/5] Fix docstring mistake in hpy/tools/autogen/public_api.h Co-authored-by: Simon Cross --- hpy/tools/autogen/public_api.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index a0fa0c3c..596bbbf5 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -351,7 +351,7 @@ HPy HPyIter_Next(HPyContext *ctx, HPy obj); * A handle to an arbitrary object (must not be ``HPy_NULL``). * * :returns: - * Non-zero if object ``h`` provides the ``Iterator`` protocol, and ``0`` + * Non-zero if object ``obj`` provides the ``Iterator`` protocol, and ``0`` * otherwise. */ HPy_ID(271) From 0506ca2d277daaefdd5b6bb29ac391e7d90d8936 Mon Sep 17 00:00:00 2001 From: Thanos <111999343+Sachaa-Thanasius@users.noreply.github.com> Date: Thu, 29 Feb 2024 09:10:08 -0500 Subject: [PATCH 5/5] Remove "verification done in debug mode" clause in docstring. - This can be added later. --- hpy/tools/autogen/public_api.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 596bbbf5..ae2c18a6 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -331,8 +331,7 @@ HPy HPy_GetIter(HPyContext *ctx, HPy obj); * The execution context. * :param obj: * An iterator Python object (must not be ``HPy_NULL``). This can be - * verified with ``HPy_IterCheck``. Otherwise, the behavior is undefined - * (verification of the argument is only done in debug mode). + * verified with ``HPy_IterCheck``. Otherwise, the behavior is undefined. * * :returns: * The new value in iterator ``obj``, or ``HPy_NULL`` on failure. If the