From cd4c539934404fdf03e03c47126a8d7ae1171e9f Mon Sep 17 00:00:00 2001 From: Christian Klein <167265+cklein@users.noreply.github.com> Date: Sun, 11 Apr 2021 13:30:35 +0200 Subject: [PATCH] Implementation with a preallocated list The idea turned out to be very closely related to HPyTracker, so I blatantly stole some code there. --- hpy/debug/src/autogen_debug_ctx_init.h | 6 +- hpy/debug/src/autogen_debug_wrappers.c | 8 +- .../common/runtime/ctx_unicodebuilder.h | 6 +- hpy/devel/include/cpython/hpy.h | 51 +++++---- hpy/devel/include/universal/autogen_ctx.h | 4 +- .../include/universal/autogen_trampolines.h | 8 +- hpy/devel/include/universal/hpy.h | 2 +- hpy/devel/src/runtime/ctx_unicodebuilder.c | 102 +++++++++++++----- hpy/tools/autogen/parse.py | 8 +- hpy/tools/autogen/public_api.h | 5 +- hpy/universal/src/autogen_ctx_def.h | 2 +- test/test_hpystringbuilder.py | 23 ---- test/test_hpyunicodebuilder.py | 51 +++++++++ 13 files changed, 173 insertions(+), 103 deletions(-) delete mode 100644 test/test_hpystringbuilder.py create mode 100644 test/test_hpyunicodebuilder.py diff --git a/hpy/debug/src/autogen_debug_ctx_init.h b/hpy/debug/src/autogen_debug_ctx_init.h index cbb856012..cc1acd862 100644 --- a/hpy/debug/src/autogen_debug_ctx_init.h +++ b/hpy/debug/src/autogen_debug_ctx_init.h @@ -131,8 +131,8 @@ HPyListBuilder debug_ctx_ListBuilder_New(HPyContext *dctx, HPy_ssize_t initial_s void debug_ctx_ListBuilder_Set(HPyContext *dctx, HPyListBuilder builder, HPy_ssize_t index, DHPy h_item); DHPy debug_ctx_ListBuilder_Build(HPyContext *dctx, HPyListBuilder builder); void debug_ctx_ListBuilder_Cancel(HPyContext *dctx, HPyListBuilder builder); -HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx); -void debug_ctx_UnicodeBuilder_Append(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item); +HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx, HPy_ssize_t size); +int debug_ctx_UnicodeBuilder_Add(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item); DHPy debug_ctx_UnicodeBuilder_Build(HPyContext *dctx, HPyUnicodeBuilder builder); void debug_ctx_UnicodeBuilder_Cancel(HPyContext *dctx, HPyUnicodeBuilder builder); HPyTupleBuilder debug_ctx_TupleBuilder_New(HPyContext *dctx, HPy_ssize_t initial_size); @@ -344,7 +344,7 @@ static inline void debug_ctx_init_fields(HPyContext *dctx, HPyContext *uctx) dctx->ctx_ListBuilder_Build = &debug_ctx_ListBuilder_Build; dctx->ctx_ListBuilder_Cancel = &debug_ctx_ListBuilder_Cancel; dctx->ctx_UnicodeBuilder_New = &debug_ctx_UnicodeBuilder_New; - dctx->ctx_UnicodeBuilder_Append = &debug_ctx_UnicodeBuilder_Append; + dctx->ctx_UnicodeBuilder_Add = &debug_ctx_UnicodeBuilder_Add; dctx->ctx_UnicodeBuilder_Build = &debug_ctx_UnicodeBuilder_Build; dctx->ctx_UnicodeBuilder_Cancel = &debug_ctx_UnicodeBuilder_Cancel; dctx->ctx_TupleBuilder_New = &debug_ctx_TupleBuilder_New; diff --git a/hpy/debug/src/autogen_debug_wrappers.c b/hpy/debug/src/autogen_debug_wrappers.c index 98721a93b..f0affd025 100644 --- a/hpy/debug/src/autogen_debug_wrappers.c +++ b/hpy/debug/src/autogen_debug_wrappers.c @@ -592,14 +592,14 @@ void debug_ctx_ListBuilder_Cancel(HPyContext *dctx, HPyListBuilder builder) HPyListBuilder_Cancel(get_info(dctx)->uctx, builder); } -HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx) +HPyUnicodeBuilder debug_ctx_UnicodeBuilder_New(HPyContext *dctx, HPy_ssize_t size) { - return HPyUnicodeBuilder_New(get_info(dctx)->uctx); + return HPyUnicodeBuilder_New(get_info(dctx)->uctx, size); } -void debug_ctx_UnicodeBuilder_Append(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item) +int debug_ctx_UnicodeBuilder_Add(HPyContext *dctx, HPyUnicodeBuilder builder, DHPy h_item) { - HPyUnicodeBuilder_Append(get_info(dctx)->uctx, builder, DHPy_unwrap(dctx, h_item)); + return HPyUnicodeBuilder_Add(get_info(dctx)->uctx, builder, DHPy_unwrap(dctx, h_item)); } DHPy debug_ctx_UnicodeBuilder_Build(HPyContext *dctx, HPyUnicodeBuilder builder) diff --git a/hpy/devel/include/common/runtime/ctx_unicodebuilder.h b/hpy/devel/include/common/runtime/ctx_unicodebuilder.h index 5d00783b2..ce7ad975a 100644 --- a/hpy/devel/include/common/runtime/ctx_unicodebuilder.h +++ b/hpy/devel/include/common/runtime/ctx_unicodebuilder.h @@ -6,9 +6,9 @@ #include "common/hpytype.h" -_HPy_HIDDEN HPyUnicodeBuilder ctx_UnicodeBuilder_New(HPyContext *ctx); -_HPy_HIDDEN void ctx_UnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, - HPy h_item); +_HPy_HIDDEN HPyUnicodeBuilder ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity); +_HPy_HIDDEN int ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, + HPy h_item); _HPy_HIDDEN HPy ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder); _HPy_HIDDEN void ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder); diff --git a/hpy/devel/include/cpython/hpy.h b/hpy/devel/include/cpython/hpy.h index a6b76e862..b60305026 100644 --- a/hpy/devel/include/cpython/hpy.h +++ b/hpy/devel/include/cpython/hpy.h @@ -31,9 +31,9 @@ typedef struct { PyObject *_o; } HPy; typedef struct { Py_ssize_t _lst; } HPyListBuilder; -typedef struct { Py_ssize_t _lst; } HPyUnicodeBuilder; typedef struct { Py_ssize_t _tup; } HPyTupleBuilder; typedef struct { void *_o; } HPyTracker; +typedef struct { void *_o; } HPyUnicodeBuilder; typedef Py_ssize_t HPy_ssize_t; typedef Py_hash_t HPy_hash_t; @@ -380,31 +380,6 @@ HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder) ctx_ListBuilder_Cancel(ctx, builder); } -HPyAPI_FUNC(HPyUnicodeBuilder) -HPyUnicodeBuilder_New(HPyContext *ctx) -{ - return ctx_UnicodeBuilder_New(ctx); -} - -HPyAPI_FUNC(void) -HPyUnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, - HPy h_item) -{ - ctx_UnicodeBuilder_Append(ctx, builder, h_item); -} - -HPyAPI_FUNC(HPy) -HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) -{ - return ctx_UnicodeBuilder_Build(ctx, builder); -} - -HPyAPI_FUNC(void) -HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) -{ - ctx_UnicodeBuilder_Cancel(ctx, builder); -} - HPyAPI_FUNC(HPyTupleBuilder) HPyTupleBuilder_New(HPyContext *ctx, HPy_ssize_t initial_size) { @@ -460,4 +435,28 @@ HPyTracker_Close(HPyContext *ctx, HPyTracker ht) ctx_Tracker_Close(ctx, ht); } +HPyAPI_FUNC(HPyUnicodeBuilder) +HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size) +{ + return ctx_UnicodeBuilder_New(ctx, size); +} + +HPyAPI_FUNC(int) +HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) +{ + return ctx_UnicodeBuilder_Add(ctx, builder, h_item); +} + +HPyAPI_FUNC(HPy) +HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) +{ + return ctx_UnicodeBuilder_Build(ctx, builder); +} + +HPyAPI_FUNC(void) +HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) +{ + ctx_UnicodeBuilder_Cancel(ctx, builder); +} + #endif /* !HPy_CPYTHON_H */ diff --git a/hpy/devel/include/universal/autogen_ctx.h b/hpy/devel/include/universal/autogen_ctx.h index b3f8c5d5e..22aa45996 100644 --- a/hpy/devel/include/universal/autogen_ctx.h +++ b/hpy/devel/include/universal/autogen_ctx.h @@ -210,8 +210,8 @@ struct _HPyContext_s { void (*ctx_ListBuilder_Set)(HPyContext *ctx, HPyListBuilder builder, HPy_ssize_t index, HPy h_item); HPy (*ctx_ListBuilder_Build)(HPyContext *ctx, HPyListBuilder builder); void (*ctx_ListBuilder_Cancel)(HPyContext *ctx, HPyListBuilder builder); - HPyUnicodeBuilder (*ctx_UnicodeBuilder_New)(HPyContext *ctx); - void (*ctx_UnicodeBuilder_Append)(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); + HPyUnicodeBuilder (*ctx_UnicodeBuilder_New)(HPyContext *ctx, HPy_ssize_t size); + int (*ctx_UnicodeBuilder_Add)(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); HPy (*ctx_UnicodeBuilder_Build)(HPyContext *ctx, HPyUnicodeBuilder builder); void (*ctx_UnicodeBuilder_Cancel)(HPyContext *ctx, HPyUnicodeBuilder builder); HPyTupleBuilder (*ctx_TupleBuilder_New)(HPyContext *ctx, HPy_ssize_t initial_size); diff --git a/hpy/devel/include/universal/autogen_trampolines.h b/hpy/devel/include/universal/autogen_trampolines.h index ec29dc766..b5999941c 100644 --- a/hpy/devel/include/universal/autogen_trampolines.h +++ b/hpy/devel/include/universal/autogen_trampolines.h @@ -486,12 +486,12 @@ static inline void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder ctx->ctx_ListBuilder_Cancel ( ctx, builder ); } -static inline HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx) { - return ctx->ctx_UnicodeBuilder_New ( ctx ); +static inline HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size) { + return ctx->ctx_UnicodeBuilder_New ( ctx, size ); } -static inline void HPyUnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { - ctx->ctx_UnicodeBuilder_Append ( ctx, builder, h_item ); +static inline int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { + return ctx->ctx_UnicodeBuilder_Add ( ctx, builder, h_item ); } static inline HPy HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) { diff --git a/hpy/devel/include/universal/hpy.h b/hpy/devel/include/universal/hpy.h index 8fec06c85..1ec11ff1e 100644 --- a/hpy/devel/include/universal/hpy.h +++ b/hpy/devel/include/universal/hpy.h @@ -34,9 +34,9 @@ typedef intptr_t HPy_hash_t; the HPy structure contains an index in a global array. */ typedef struct _HPy_s { HPy_ssize_t _i; } HPy; typedef struct { HPy_ssize_t _lst; } HPyListBuilder; -typedef struct { HPy_ssize_t _lst; } HPyUnicodeBuilder; typedef struct { HPy_ssize_t _tup; } HPyTupleBuilder; typedef struct { HPy_ssize_t _i; } HPyTracker; +typedef struct { HPy_ssize_t _i; } HPyUnicodeBuilder; typedef struct _HPyContext_s HPyContext; diff --git a/hpy/devel/src/runtime/ctx_unicodebuilder.c b/hpy/devel/src/runtime/ctx_unicodebuilder.c index 2cf9d9925..5716b3652 100644 --- a/hpy/devel/src/runtime/ctx_unicodebuilder.c +++ b/hpy/devel/src/runtime/ctx_unicodebuilder.c @@ -7,57 +7,101 @@ # include "handles.h" #endif -#include +static const Py_ssize_t HPYUNICODEBUILDER_INITIAL_CAPACITY = 5; + +typedef struct { + Py_ssize_t capacity; // allocated handles + Py_ssize_t length; // used handles + PyObject *list; +} _PyUnicodeBuilder_s; + +#ifdef HPY_UNIVERSAL_ABI +static inline _PyUnicodeBuilder_s *_hb2pb(HPyUnicodeBuilder ht) { + return (_PyUnicodeBuilder_s *) (ht)._i; +} +static inline HPyUnicodeBuilder _pb2hb(_PyUnicodeBuilder_s *bp) { + return (HPyUnicodeBuilder) {(HPy_ssize_t) (bp)}; +} +#else +static inline _PyUnicodeBuilder_s *_hb2pb(HPyUnicodeBuilder ht) { + return (_PyUnicodeBuilder_s *) (ht)._o; +} +static inline HPyUnicodeBuilder _pb2hb(_PyUnicodeBuilder_s *bp) { + return (HPyUnicodeBuilder) {(void *) (bp)}; +} +#endif _HPy_HIDDEN HPyUnicodeBuilder -ctx_UnicodeBuilder_New(HPyContext *ctx) +ctx_UnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t capacity) { - PyObject *lst = PyList_New(0); - if (lst == NULL) - PyErr_Clear(); /* delay the MemoryError */ - return (HPyUnicodeBuilder){(HPy_ssize_t)lst }; + _PyUnicodeBuilder_s *bp; + if (capacity == 0) { + capacity = HPYUNICODEBUILDER_INITIAL_CAPACITY; + } + capacity++; // always reserve space for an extra handle, see the docs, analogue to HPyTracker + + bp = malloc(sizeof(_PyUnicodeBuilder_s)); + if (bp == NULL) { + HPyErr_NoMemory(ctx); + return _pb2hb(0); + } + + bp->list = PyList_New(capacity); + if (bp->list == NULL) { + free(bp); + HPyErr_NoMemory(ctx); + return _pb2hb(0); + } + bp->capacity = capacity; + bp->length = 0; + return _pb2hb(bp); } -_HPy_HIDDEN void -ctx_UnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) +_HPy_HIDDEN int +ctx_UnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item) { - PyObject *lst = (PyObject *)builder._lst; - if (lst != NULL) { - PyObject *item = _h2py(h_item); - PyList_Append(lst, item); + if(!HPyUnicode_Check(ctx, h_item)) { + HPyErr_SetString(ctx, ctx->h_TypeError, "Argument must be of type HPyUnicode"); + return -1; + } + + _PyUnicodeBuilder_s *bp = _hb2pb(builder); + PyObject *item = _h2py(h_item); + + // XXX: For the initial PoC we don't care about reallocation + if (bp->capacity <= bp->length) { + return -1; } + Py_INCREF(item); + PyList_SET_ITEM(bp->list, bp->length++, item); + return 0; } _HPy_HIDDEN HPy ctx_UnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder) { - PyObject *lst = (PyObject *)builder._lst; - if (lst == NULL) { - PyErr_NoMemory(); - return HPy_NULL; - } - builder._lst = 0; + _PyUnicodeBuilder_s *bp = _hb2pb(builder); + PyObject *list = PyList_GetSlice(bp->list, 0, bp->length); + PyObject *sep = PyUnicode_FromString(""); - PyObject *str = PyUnicode_Join(sep, lst); + PyObject *str = PyUnicode_Join(sep, list); Py_XDECREF(sep); + if(str == NULL) { PyErr_NoMemory(); return HPy_NULL; } - Py_XDECREF(lst); + + Py_XDECREF(bp->list); + Py_XDECREF(list); + free(bp); return _py2h(str); } _HPy_HIDDEN void ctx_UnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder) { - PyObject *lst = (PyObject *)builder._lst; - if (lst == NULL) { - // we don't report the memory error here: the builder - // is being cancelled (so the result of the builder is not being used) - // and likely it's being cancelled during the handling of another error - return; - } - builder._lst = 0; - Py_XDECREF(lst); + _PyUnicodeBuilder_s *bp = _hb2pb(builder); + Py_XDECREF(bp->list); + free(bp); } diff --git a/hpy/tools/autogen/parse.py b/hpy/tools/autogen/parse.py index 072d1ee87..365147007 100644 --- a/hpy/tools/autogen/parse.py +++ b/hpy/tools/autogen/parse.py @@ -210,10 +210,6 @@ def _visit_hpyslot_slot(self, node): 'HPyListBuilder_Set': None, 'HPyListBuilder_Build': None, 'HPyListBuilder_Cancel': None, - 'HPyUnicodeBuilder_New': None, - 'HPyUnicodeBuilder_Append': None, - 'HPyUnicodeBuilder_Build': None, - 'HPyUnicodeBuilder_Cancel': None, 'HPyTuple_FromArray': None, 'HPyTupleBuilder_New': None, 'HPyTupleBuilder_Set': None, @@ -223,6 +219,10 @@ def _visit_hpyslot_slot(self, node): 'HPyTracker_Add': None, 'HPyTracker_ForgetAll': None, 'HPyTracker_Close': None, + 'HPyUnicodeBuilder_New': None, + 'HPyUnicodeBuilder_Add': None, + 'HPyUnicodeBuilder_Build': None, + 'HPyUnicodeBuilder_Cancel': None, '_HPy_Dump': None, 'HPy_Type': 'PyObject_Type', 'HPy_TypeCheck': None, diff --git a/hpy/tools/autogen/public_api.h b/hpy/tools/autogen/public_api.h index 74703b048..f77c951b5 100644 --- a/hpy/tools/autogen/public_api.h +++ b/hpy/tools/autogen/public_api.h @@ -283,9 +283,8 @@ void HPyListBuilder_Set(HPyContext *ctx, HPyListBuilder builder, HPy HPyListBuilder_Build(HPyContext *ctx, HPyListBuilder builder); void HPyListBuilder_Cancel(HPyContext *ctx, HPyListBuilder builder); -HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx); -void HPyUnicodeBuilder_Append(HPyContext *ctx, HPyUnicodeBuilder builder, - HPy h_item); +HPyUnicodeBuilder HPyUnicodeBuilder_New(HPyContext *ctx, HPy_ssize_t size); +int HPyUnicodeBuilder_Add(HPyContext *ctx, HPyUnicodeBuilder builder, HPy h_item); HPy HPyUnicodeBuilder_Build(HPyContext *ctx, HPyUnicodeBuilder builder); void HPyUnicodeBuilder_Cancel(HPyContext *ctx, HPyUnicodeBuilder builder); diff --git a/hpy/universal/src/autogen_ctx_def.h b/hpy/universal/src/autogen_ctx_def.h index 1bf11c027..c537790ca 100644 --- a/hpy/universal/src/autogen_ctx_def.h +++ b/hpy/universal/src/autogen_ctx_def.h @@ -137,7 +137,7 @@ struct _HPyContext_s g_universal_ctx = { .ctx_ListBuilder_Build = &ctx_ListBuilder_Build, .ctx_ListBuilder_Cancel = &ctx_ListBuilder_Cancel, .ctx_UnicodeBuilder_New = &ctx_UnicodeBuilder_New, - .ctx_UnicodeBuilder_Append = &ctx_UnicodeBuilder_Append, + .ctx_UnicodeBuilder_Add = &ctx_UnicodeBuilder_Add, .ctx_UnicodeBuilder_Build = &ctx_UnicodeBuilder_Build, .ctx_UnicodeBuilder_Cancel = &ctx_UnicodeBuilder_Cancel, .ctx_TupleBuilder_New = &ctx_TupleBuilder_New, diff --git a/test/test_hpystringbuilder.py b/test/test_hpystringbuilder.py deleted file mode 100644 index 9b79bd341..000000000 --- a/test/test_hpystringbuilder.py +++ /dev/null @@ -1,23 +0,0 @@ -from .support import HPyTest - -class TestString(HPyTest): - def test_UnicodeBuilder(self, hpy_abi): - mod = self.make_module(""" - HPyDef_METH(f, "f", f_impl, HPyFunc_O) - static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) - { - HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx); - HPy h_s1 = HPyUnicode_FromString(ctx, "hello "); - HPy h_s2 = HPyUnicode_FromString(ctx, "!"); - HPyUnicodeBuilder_Append(ctx, builder, h_s1); - HPyUnicodeBuilder_Append(ctx, builder, h_arg); - HPyUnicodeBuilder_Append(ctx, builder, h_s2); - HPy h_string = HPyUnicodeBuilder_Build(ctx, builder); - HPy_Close(ctx, h_s1); - HPy_Close(ctx, h_s2); - return h_string; - } - @EXPORT(f) - @INIT - """) - assert mod.f("world") == "hello world!" diff --git a/test/test_hpyunicodebuilder.py b/test/test_hpyunicodebuilder.py new file mode 100644 index 000000000..6b30285d1 --- /dev/null +++ b/test/test_hpyunicodebuilder.py @@ -0,0 +1,51 @@ +from .support import HPyTest + +class TestString(HPyTest): + def test_unicode_builder(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_O) + static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) + { + HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx, 0); + if(HPy_IsNull(builder)) { + HPyErr_SetString(ctx, ctx->h_RuntimeError, "Could not create HPyUnicodeBuilder"); + return HPy_NULL; + } + HPy h_s1 = HPyUnicode_FromString(ctx, "hello "); + HPy h_s2 = HPyUnicode_FromString(ctx, "!"); + HPyUnicodeBuilder_Add(ctx, builder, h_s1); + HPyUnicodeBuilder_Add(ctx, builder, h_arg); + HPyUnicodeBuilder_Add(ctx, builder, h_s2); + HPy h_string = HPyUnicodeBuilder_Build(ctx, builder); + HPy_Close(ctx, h_s1); + HPy_Close(ctx, h_s2); + return h_string; + } + @EXPORT(f) + @INIT + """) + assert mod.f("world") == "hello world!" + + def test_type_error(self): + mod = self.make_module(""" + HPyDef_METH(f, "f", f_impl, HPyFunc_O) + static HPy f_impl(HPyContext *ctx, HPy h_self, HPy h_arg) + { + HPyUnicodeBuilder builder = HPyUnicodeBuilder_New(ctx, 0); + if(HPy_IsNull(builder)) { + HPyErr_SetString(ctx, ctx->h_RuntimeError, "Could not create HPyUnicodeBuilder"); + return HPy_NULL; + } + HPy h_long = HPyLong_FromLong(ctx, 42); + HPyUnicodeBuilder_Add(ctx, builder, h_long); + HPy_Close(ctx, h_long); + HPyUnicodeBuilder_Cancel(ctx, builder); + return HPy_NULL; + } + @EXPORT(f) + @INIT + """) + import pytest + with pytest.raises(TypeError) as exc_info: + mod.f("world") + assert exc_info.match("Argument must be of type HPyUnicode")