diff options
author | vvvv <[email protected]> | 2025-10-10 09:49:53 +0300 |
---|---|---|
committer | vvvv <[email protected]> | 2025-10-10 10:04:09 +0300 |
commit | c62bab8ab3141ff460f885bf2dafb922e0c19d38 (patch) | |
tree | b37257fe1cd06a87b589992db93124d456f39152 /yql/essentials/udfs/common/python | |
parent | 172bf557598ad5d2a67c1d18ff9d4857a6b40722 (diff) |
YQL-20339 Python UDF support
init
commit_hash:2a30a1b920f341e1f9250df382dd951604a0894f
Diffstat (limited to 'yql/essentials/udfs/common/python')
22 files changed, 484 insertions, 2 deletions
diff --git a/yql/essentials/udfs/common/python/bindings/py_cast.cpp b/yql/essentials/udfs/common/python/bindings/py_cast.cpp index 42237428bb3..67524eb7890 100644 --- a/yql/essentials/udfs/common/python/bindings/py_cast.cpp +++ b/yql/essentials/udfs/common/python/bindings/py_cast.cpp @@ -7,6 +7,7 @@ #include "py_gil.h" #include "py_utils.h" #include "py_void.h" +#include "py_linear.h" #include "py_resource.h" #include "py_stream.h" #include "py_struct.h" @@ -899,6 +900,32 @@ NUdf::TUnboxedValue FromPyNull( throw yexception() << "Can't cast " << PyObjectRepr(value) << " to null."; } +TPyObjectPtr ToPyLinear( + const TPyCastContext::TPtr& ctx, + const NUdf::TType* type, + const NUdf::TUnboxedValuePod& value) +{ + const NUdf::TLinearTypeInspector inspector(*ctx->PyCtx->TypeInfoHelper, type); + if (inspector.IsDynamic()) { + return ToPyDynamicLinear(ctx, inspector.GetItemType(), value); + } + + return ToPyObject(ctx, inspector.GetItemType(), value); +} + +NUdf::TUnboxedValue FromPyLinear( + const TPyCastContext::TPtr& ctx, + const NUdf::TType* type, PyObject* value) +{ + const NUdf::TLinearTypeInspector inspector(*ctx->PyCtx->TypeInfoHelper, type); + if (inspector.IsDynamic()) { + TPyObjectPtr valuePtr(value, TPyObjectPtr::ADD_REF); + return FromPyDynamicLinear(ctx, inspector.GetItemType(), valuePtr); + } + + return FromPyObject(ctx, inspector.GetItemType(), value); +} + } // namespace TPyObjectPtr ToPyObject( @@ -932,6 +959,8 @@ TPyObjectPtr ToPyObject( return ToPyVariant(ctx, type, value); case NUdf::ETypeKind::Null: return ToPyNull(ctx, type, value); + case NUdf::ETypeKind::Linear: + return ToPyLinear(ctx, type, value); default: { ::TStringBuilder sb; sb << "Failed to export: "; @@ -972,6 +1001,8 @@ NUdf::TUnboxedValue FromPyObject( return FromPyVariant(ctx, type, value); case NUdf::ETypeKind::Null: return FromPyNull(ctx, type, value); + case NUdf::ETypeKind::Linear: + return FromPyLinear(ctx, type, value); default: { ::TStringBuilder sb; sb << "Failed to import: "; diff --git a/yql/essentials/udfs/common/python/bindings/py_linear.cpp b/yql/essentials/udfs/common/python/bindings/py_linear.cpp new file mode 100644 index 00000000000..cfad0695f6a --- /dev/null +++ b/yql/essentials/udfs/common/python/bindings/py_linear.cpp @@ -0,0 +1,226 @@ +#include "py_linear.h" +#include "py_cast.h" +#include "py_errors.h" +#include "py_utils.h" +#include "py_gil.h" + +#include <yql/essentials/public/udf/udf_value.h> +#include <yql/essentials/public/udf/udf_value_builder.h> +#include <yql/essentials/public/udf/udf_type_inspection.h> + +#include <util/string/builder.h> + +using namespace NKikimr; + +namespace NPython { + +////////////////////////////////////////////////////////////////////////////// +// TPyDynamicLinear interface +////////////////////////////////////////////////////////////////////////////// +struct TPyDynamicLinear { + using TPtr = NUdf::TRefCountedPtr<TPyDynamicLinear, TPyPtrOps<TPyDynamicLinear>>; + + PyObject_HEAD; + TPyCastContext::TPtr CastCtx; + const NUdf::TType* ItemType; + TPyCleanupListItem<NUdf::IBoxedValuePtr> Value; + + inline static TPyDynamicLinear* Cast(PyObject* o) { + return reinterpret_cast<TPyDynamicLinear*>(o); + } + + inline static void Dealloc(PyObject* self) { + delete Cast(self); + } + + static PyObject* New( + const TPyCastContext::TPtr& castCtx, + const NUdf::TType* itemType, + NUdf::IBoxedValuePtr value); + + static PyObject* Repr(PyObject* self); + static PyObject* Extract(PyObject* self, PyObject* /* arg */); +}; + +static PyMethodDef TPyDynamicLinearMethods[] = { + {"extract", TPyDynamicLinear::Extract, METH_NOARGS, nullptr}, + {nullptr, nullptr, 0, nullptr} /* sentinel */ +}; + +#if PY_MAJOR_VERSION >= 3 + #define Py_TPFLAGS_HAVE_ITER 0 // NOLINT(readability-identifier-naming) +#endif + +PyTypeObject PyDynamicLinearType = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + // clang-format off + INIT_MEMBER(tp_name, "yql.TDynamicLinear"), + // clang-format on + INIT_MEMBER(tp_basicsize, sizeof(TPyDynamicLinear)), + INIT_MEMBER(tp_itemsize, 0), + INIT_MEMBER(tp_dealloc, TPyDynamicLinear::Dealloc), +#if PY_VERSION_HEX < 0x030800b4 + INIT_MEMBER(tp_print, nullptr), +#else + INIT_MEMBER(tp_vectorcall_offset, 0), +#endif + INIT_MEMBER(tp_getattr, nullptr), + INIT_MEMBER(tp_setattr, nullptr), +#if PY_MAJOR_VERSION >= 3 + INIT_MEMBER(tp_as_async, nullptr), +#else + INIT_MEMBER(tp_compare, nullptr), +#endif + INIT_MEMBER(tp_repr, TPyDynamicLinear::Repr), + INIT_MEMBER(tp_as_number, nullptr), + INIT_MEMBER(tp_as_sequence, nullptr), + INIT_MEMBER(tp_as_mapping, nullptr), + INIT_MEMBER(tp_hash, nullptr), + INIT_MEMBER(tp_call, nullptr), + INIT_MEMBER(tp_str, nullptr), + INIT_MEMBER(tp_getattro, nullptr), + INIT_MEMBER(tp_setattro, nullptr), + INIT_MEMBER(tp_as_buffer, nullptr), + INIT_MEMBER(tp_flags, 0), + INIT_MEMBER(tp_doc, "yql.TDynamicLinear object"), + INIT_MEMBER(tp_traverse, nullptr), + INIT_MEMBER(tp_clear, nullptr), + INIT_MEMBER(tp_richcompare, nullptr), + INIT_MEMBER(tp_weaklistoffset, 0), + INIT_MEMBER(tp_iter, nullptr), + INIT_MEMBER(tp_iternext, nullptr), + INIT_MEMBER(tp_methods, TPyDynamicLinearMethods), + INIT_MEMBER(tp_members, nullptr), + INIT_MEMBER(tp_getset, nullptr), + INIT_MEMBER(tp_base, nullptr), + INIT_MEMBER(tp_dict, nullptr), + INIT_MEMBER(tp_descr_get, nullptr), + INIT_MEMBER(tp_descr_set, nullptr), + INIT_MEMBER(tp_dictoffset, 0), + INIT_MEMBER(tp_init, nullptr), + INIT_MEMBER(tp_alloc, nullptr), + INIT_MEMBER(tp_new, nullptr), + INIT_MEMBER(tp_free, nullptr), + INIT_MEMBER(tp_is_gc, nullptr), + INIT_MEMBER(tp_bases, nullptr), + INIT_MEMBER(tp_mro, nullptr), + INIT_MEMBER(tp_cache, nullptr), + INIT_MEMBER(tp_subclasses, nullptr), + INIT_MEMBER(tp_weaklist, nullptr), + INIT_MEMBER(tp_del, nullptr), + INIT_MEMBER(tp_version_tag, 0), +#if PY_MAJOR_VERSION >= 3 + INIT_MEMBER(tp_finalize, nullptr), +#endif +#if PY_VERSION_HEX >= 0x030800b1 + INIT_MEMBER(tp_vectorcall, nullptr), +#endif +#if PY_VERSION_HEX >= 0x030800b4 && PY_VERSION_HEX < 0x03090000 + INIT_MEMBER(tp_print, nullptr), +#endif +}; + +PyObject* TPyDynamicLinear::New( + const TPyCastContext::TPtr& castCtx, + const NUdf::TType* itemType, + NUdf::IBoxedValuePtr value) +{ + TPyDynamicLinear* linear = new TPyDynamicLinear; + PyObject_INIT(linear, &PyDynamicLinearType); + + linear->CastCtx = castCtx; + linear->ItemType = itemType; + linear->Value.Set(castCtx->PyCtx, value); + + return reinterpret_cast<PyObject*>(linear); +} + +PyObject* TPyDynamicLinear::Repr(PyObject*) +{ + return PyRepr("<yql.TDynamicLinear>").Release(); +} + +PyObject* TPyDynamicLinear::Extract(PyObject* self, PyObject* /* arg */) +{ + PY_TRY { + TPyDynamicLinear* linear = Cast(self); + NUdf::TUnboxedValue res; + if (NUdf::TBoxedValueAccessor::Next(*linear->Value.Get(), res)) { + return ToPyObject(linear->CastCtx, linear->ItemType, res).Release(); + } + + PyErr_SetString(PyExc_ValueError, "The linear value has already been used"); + return nullptr; + } + PY_CATCH(nullptr) +} + +class TDynamicLinearProxy: public NUdf::TBoxedValue { +public: + TDynamicLinearProxy(const TPyCastContext::TPtr& castCtx, const NUdf::TType* itemType, TPyObjectPtr&& pyObject) + : CastCtx_(castCtx) + , ItemType_(itemType) + , PyObject_(std::move(pyObject)) + { + } + + ~TDynamicLinearProxy() { + const TPyGilLocker lock; + PyObject_.Reset(); + } + + bool Next(NUdf::TUnboxedValue& value) override try { + const TPyGilLocker lock; + if (Consumed_) { + return false; + } + + TPyObjectPtr function(PyObject_GetAttrString(PyObject_.Get(), "extract")); + if (!function) { + throw yexception() << "Missing 'extract' attribute"; + } + + if (!PyCallable_Check(function.Get())) { + throw yexception() << "'extract' attribute should be a callable"; + } + + TPyObjectPtr resultObj = PyObject_CallObject(function.Get(), nullptr); + if (!resultObj) { + throw yexception() << "Failed to execute:\n" + << GetLastErrorAsString(); + } + + Consumed_ = true; + value = FromPyObject(CastCtx_, ItemType_, resultObj.Get()); + return true; + } catch (const yexception& e) { + UdfTerminate((TStringBuilder() << CastCtx_->PyCtx->Pos << e.what()).c_str()); + } + +private: + const TPyCastContext::TPtr CastCtx_; + const NUdf::TType* ItemType_; + TPyObjectPtr PyObject_; + bool Consumed_ = false; +}; + +////////////////////////////////////////////////////////////////////////////// +// public functions +////////////////////////////////////////////////////////////////////////////// +TPyObjectPtr ToPyDynamicLinear( + const TPyCastContext::TPtr& castCtx, + const NUdf::TType* itemType, + const NUdf::TUnboxedValuePod& value) +{ + return TPyDynamicLinear::New(castCtx, itemType, value.AsBoxed()); +} + +NUdf::TUnboxedValue FromPyDynamicLinear( + const TPyCastContext::TPtr& castCtx, + const NUdf::TType* itemType, + TPyObjectPtr value) +{ + return NUdf::TUnboxedValuePod(new TDynamicLinearProxy(castCtx, itemType, std::move(value))); +} + +} // namespace NPython diff --git a/yql/essentials/udfs/common/python/bindings/py_linear.h b/yql/essentials/udfs/common/python/bindings/py_linear.h new file mode 100644 index 00000000000..3ce528b7586 --- /dev/null +++ b/yql/essentials/udfs/common/python/bindings/py_linear.h @@ -0,0 +1,17 @@ +#pragma once + +#include "py_ctx.h" + +namespace NPython { + +TPyObjectPtr ToPyDynamicLinear( + const TPyCastContext::TPtr& castCtx, + const NKikimr::NUdf::TType* itemType, + const NKikimr::NUdf::TUnboxedValuePod& value); + +NKikimr::NUdf::TUnboxedValue FromPyDynamicLinear( + const TPyCastContext::TPtr& castCtx, + const NKikimr::NUdf::TType* itemType, + TPyObjectPtr value); + +} // namespace NPython diff --git a/yql/essentials/udfs/common/python/bindings/ya.make b/yql/essentials/udfs/common/python/bindings/ya.make index 29dca847ee9..1e5eb4cd0b0 100644 --- a/yql/essentials/udfs/common/python/bindings/ya.make +++ b/yql/essentials/udfs/common/python/bindings/ya.make @@ -1,6 +1,6 @@ PY23_NATIVE_LIBRARY() -YQL_ABI_VERSION(2 27 0) +YQL_ABI_VERSION(2 44 0) ENABLE(YQL_STYLE_CPP) @@ -13,6 +13,7 @@ SRCS( py_list.cpp py_lazy_mkql_dict.cpp py_lazy_mkql_list.cpp + py_linear.cpp py_iterator.cpp py_resource.cpp py_stream.cpp diff --git a/yql/essentials/udfs/common/python/python3_small/test/canondata/result.json b/yql/essentials/udfs/common/python/python3_small/test/canondata/result.json index 5db4c2b5055..cd5bbbcf26f 100644 --- a/yql/essentials/udfs/common/python/python3_small/test/canondata/result.json +++ b/yql/essentials/udfs/common/python/python3_small/test/canondata/result.json @@ -46,6 +46,26 @@ "uri": "https://{canondata_backend}/995452/085d43bbd16f44afc51d6cafed42465a3d20215c/resource.tar.gz#test.test_GreedyInputContainers_/results.txt" } ], + "test.test[LinearDynamicFail1]": [ + { + "uri": "file://test.test_LinearDynamicFail1_/extracted" + } + ], + "test.test[LinearDynamicFail2]": [ + { + "uri": "file://test.test_LinearDynamicFail2_/extracted" + } + ], + "test.test[LinearDynamic]": [ + { + "uri": "file://test.test_LinearDynamic_/results.txt" + } + ], + "test.test[Linear]": [ + { + "uri": "file://test.test_Linear_/results.txt" + } + ], "test.test[OptionalNested]": [ { "uri": "file://test.test_OptionalNested_/extracted" diff --git a/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_LinearDynamicFail1_/extracted b/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_LinearDynamicFail1_/extracted new file mode 100644 index 00000000000..05e09cd7eda --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_LinearDynamicFail1_/extracted @@ -0,0 +1,12 @@ +<tmp_path>/program.sql:<main>: Error: Execution + + <tmp_path>/program.sql:<main>:50:1: Error: Execution of node: Result + select $c($p(1)); + ^ + <tmp_path>/program.sql:<main>:46:14: Error: Failed to execute: +Traceback (most recent call last): + File "embedded:g", line 35, in g +ValueError: The linear value has already been used + + $c = Python::g(Callable<($l)->Int32>, $s); + ^
\ No newline at end of file diff --git a/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_LinearDynamicFail2_/extracted b/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_LinearDynamicFail2_/extracted new file mode 100644 index 00000000000..462b4b5332d --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_LinearDynamicFail2_/extracted @@ -0,0 +1,12 @@ +<tmp_path>/program.sql:<main>: Error: Execution + + <tmp_path>/program.sql:<main>:52:1: Error: Execution of node: Result + select $c($a,0),$c($a,1); + ^ + <tmp_path>/program.sql:<main>:46:14: Error: Failed to execute: +Traceback (most recent call last): + File "embedded:g", line 35, in g +ValueError: The linear value has already been used + + $c = Python::g(Callable<($l,Int32)->Int32>, $s); + ^
\ No newline at end of file diff --git a/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_LinearDynamic_/results.txt b/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_LinearDynamic_/results.txt new file mode 100644 index 00000000000..40dd4232253 --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_LinearDynamic_/results.txt @@ -0,0 +1,28 @@ +[ + { + "Write" = [ + { + "Type" = [ + "ListType"; + [ + "StructType"; + [ + [ + "column0"; + [ + "DataType"; + "Int32" + ] + ] + ] + ] + ]; + "Data" = [ + [ + "4" + ] + ] + } + ] + } +]
\ No newline at end of file diff --git a/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_Linear_/results.txt b/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_Linear_/results.txt new file mode 100644 index 00000000000..40dd4232253 --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/canondata/test.test_Linear_/results.txt @@ -0,0 +1,28 @@ +[ + { + "Write" = [ + { + "Type" = [ + "ListType"; + [ + "StructType"; + [ + [ + "column0"; + [ + "DataType"; + "Int32" + ] + ] + ] + ] + ]; + "Data" = [ + [ + "4" + ] + ] + } + ] + } +]
\ No newline at end of file diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/Linear.cfg b/yql/essentials/udfs/common/python/python3_small/test/cases/Linear.cfg new file mode 100644 index 00000000000..7e882f1da85 --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/Linear.cfg @@ -0,0 +1,2 @@ +langver 2025.04 + diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/Linear.in b/yql/essentials/udfs/common/python/python3_small/test/cases/Linear.in new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/Linear.in diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/Linear.sql b/yql/essentials/udfs/common/python/python3_small/test/cases/Linear.sql new file mode 100644 index 00000000000..ef4aa9f0132 --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/Linear.sql @@ -0,0 +1,15 @@ +$s = @@ +def f(x): + return x + 1 + +def g(x): + return x * 2 +@@; + +$l = LinearType(Int32); +$p = Python::f(Callable<(Int32)->$l>, $s); +$c = Python::g(Callable<($l)->Int32>, $s); + +select $c($p(1)); + + diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamic.cfg b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamic.cfg new file mode 100644 index 00000000000..7e882f1da85 --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamic.cfg @@ -0,0 +1,2 @@ +langver 2025.04 + diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamic.in b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamic.in new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamic.in diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamic.sql b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamic.sql new file mode 100644 index 00000000000..58b4a649a05 --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamic.sql @@ -0,0 +1,27 @@ +$s = @@ +def f(x): + class Once: + def __init__(self, v): + self.v = v + self.extracted = False + + def extract(self): + assert not self.extracted + self.extracted = True + ret = self.v + self.v = None + return ret + + return Once(x + 1) + +def g(x): + return x.extract() * 2 +@@; + +$l = DynamicLinearType(Int32); +$p = Python::f(Callable<(Int32)->$l>, $s); +$c = Python::g(Callable<($l)->Int32>, $s); + +select $c($p(1)); + + diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail1.cfg b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail1.cfg new file mode 100644 index 00000000000..57e3ac59f66 --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail1.cfg @@ -0,0 +1,3 @@ +langver 2025.04 +xfail + diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail1.in b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail1.in new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail1.in diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail1.sql b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail1.sql new file mode 100644 index 00000000000..5a91c16589f --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail1.sql @@ -0,0 +1,27 @@ +$s = @@ +def f(x): + class Once: + def __init__(self, v): + self.v = v + self.extracted = False + + def extract(self): + assert not self.extracted + self.extracted = True + ret = self.v + self.v = None + return ret + + return Once(x + 1) + +def g(x): + return x.extract() * x.extract() +@@; + +$l = DynamicLinearType(Int32); +$p = Python::f(Callable<(Int32)->$l>, $s); +$c = Python::g(Callable<($l)->Int32>, $s); + +select $c($p(1)); + + diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail2.cfg b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail2.cfg new file mode 100644 index 00000000000..57e3ac59f66 --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail2.cfg @@ -0,0 +1,3 @@ +langver 2025.04 +xfail + diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail2.in b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail2.in new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail2.in diff --git a/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail2.sql b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail2.sql new file mode 100644 index 00000000000..09610de9aa3 --- /dev/null +++ b/yql/essentials/udfs/common/python/python3_small/test/cases/LinearDynamicFail2.sql @@ -0,0 +1,28 @@ +$s = @@ +def f(x): + class Once: + def __init__(self, v): + self.v = v + self.extracted = False + + def extract(self): + assert not self.extracted + self.extracted = True + ret = self.v + self.v = None + return ret + + return Once(x + 1) + +def g(x,n): + return x.extract() + n +@@; + +$l = DynamicLinearType(Int32); +$p = Python::f(Callable<(Int32)->$l>, $s); +$c = Python::g(Callable<($l,Int32)->Int32>, $s); + +$a = $p(1); +select $c($a,0),$c($a,1); + + diff --git a/yql/essentials/udfs/common/python/python_udf/ya.make b/yql/essentials/udfs/common/python/python_udf/ya.make index 124f075c904..41f4514dfd0 100644 --- a/yql/essentials/udfs/common/python/python_udf/ya.make +++ b/yql/essentials/udfs/common/python/python_udf/ya.make @@ -1,6 +1,6 @@ PY23_NATIVE_LIBRARY() -YQL_ABI_VERSION(2 27 0) +YQL_ABI_VERSION(2 44 0) ENABLE(YQL_STYLE_CPP) |