aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/udfs/common/python/bindings/py_dict.cpp
diff options
context:
space:
mode:
authorimunkin <imunkin@yandex-team.com>2024-11-08 10:00:23 +0300
committerimunkin <imunkin@yandex-team.com>2024-11-08 10:12:13 +0300
commita784a2f943d6e15caa6241e2e96d80aac6dbf375 (patch)
tree05f1e5366c916b988a8afb75bdab8ddeee0f6e6d /yql/essentials/udfs/common/python/bindings/py_dict.cpp
parentd70137a7b530ccaa52834274913bbb5a3d1ca06e (diff)
downloadydb-a784a2f943d6e15caa6241e2e96d80aac6dbf375.tar.gz
Move yql/udfs/common/ to /yql/essentials YQL-19206
Except the following directories: * clickhouse/client * datetime * knn * roaring commit_hash:c7da95636144d28db109d6b17ddc762e9bacb59f
Diffstat (limited to 'yql/essentials/udfs/common/python/bindings/py_dict.cpp')
-rw-r--r--yql/essentials/udfs/common/python/bindings/py_dict.cpp683
1 files changed, 683 insertions, 0 deletions
diff --git a/yql/essentials/udfs/common/python/bindings/py_dict.cpp b/yql/essentials/udfs/common/python/bindings/py_dict.cpp
new file mode 100644
index 0000000000..f2bd0669ed
--- /dev/null
+++ b/yql/essentials/udfs/common/python/bindings/py_dict.cpp
@@ -0,0 +1,683 @@
+#include "py_dict.h"
+#include "py_iterator.h"
+#include "py_cast.h"
+#include "py_errors.h"
+#include "py_utils.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>
+
+
+using namespace NKikimr;
+
+namespace NPython {
+
+//////////////////////////////////////////////////////////////////////////////
+// TPyLazyDict interface
+//////////////////////////////////////////////////////////////////////////////
+struct TPyLazyDict
+{
+ using TPtr = NUdf::TRefCountedPtr<TPyLazyDict, TPyPtrOps<TPyLazyDict>>;
+
+ PyObject_HEAD;
+ TPyCastContext::TPtr CastCtx;
+ const NUdf::TType* KeyType;
+ const NUdf::TType* PayloadType;
+ TPyCleanupListItem<NUdf::IBoxedValuePtr> Value;
+
+ inline static TPyLazyDict* Cast(PyObject* o) {
+ return reinterpret_cast<TPyLazyDict*>(o);
+ }
+
+ inline static void Dealloc(PyObject* self) {
+ delete Cast(self);
+ }
+
+ static PyObject* New(
+ const TPyCastContext::TPtr& castCtx,
+ const NUdf::TType* keyType,
+ const NUdf::TType* payloadType,
+ NUdf::IBoxedValuePtr&& value);
+
+ static int Bool(PyObject* self);
+ static PyObject* Repr(PyObject* self);
+ static Py_ssize_t Len(PyObject* self);
+ static PyObject* Subscript(PyObject* self, PyObject* key);
+ static int Contains(PyObject* self, PyObject* key);
+ static PyObject* Get(PyObject* self, PyObject* args);
+
+ static PyObject* Iter(PyObject* self) { return Keys(self, nullptr); }
+ static PyObject* Keys(PyObject* self, PyObject* /* args */);
+ static PyObject* Items(PyObject* self, PyObject* /* args */);
+ static PyObject* Values(PyObject* self, PyObject* /* args */);
+};
+
+PyMappingMethods LazyDictMapping = {
+ INIT_MEMBER(mp_length, TPyLazyDict::Len),
+ INIT_MEMBER(mp_subscript, TPyLazyDict::Subscript),
+ INIT_MEMBER(mp_ass_subscript, nullptr),
+};
+
+PySequenceMethods LazyDictSequence = {
+ INIT_MEMBER(sq_length , TPyLazyDict::Len),
+ INIT_MEMBER(sq_concat , nullptr),
+ INIT_MEMBER(sq_repeat , nullptr),
+ INIT_MEMBER(sq_item , nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(was_sq_slice , nullptr),
+#else
+ INIT_MEMBER(sq_slice , nullptr),
+#endif
+ INIT_MEMBER(sq_ass_item , nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(was_sq_ass_slice , nullptr),
+#else
+ INIT_MEMBER(sq_ass_slice , nullptr),
+#endif
+ INIT_MEMBER(sq_contains , TPyLazyDict::Contains),
+ INIT_MEMBER(sq_inplace_concat , nullptr),
+ INIT_MEMBER(sq_inplace_repeat , nullptr),
+};
+
+PyNumberMethods LazyDictNumbering = {
+ INIT_MEMBER(nb_add, nullptr),
+ INIT_MEMBER(nb_subtract, nullptr),
+ INIT_MEMBER(nb_multiply, nullptr),
+#if PY_MAJOR_VERSION < 3
+ INIT_MEMBER(nb_divide, nullptr),
+#endif
+ INIT_MEMBER(nb_remainder, nullptr),
+ INIT_MEMBER(nb_divmod, nullptr),
+ INIT_MEMBER(nb_power, nullptr),
+ INIT_MEMBER(nb_negative, nullptr),
+ INIT_MEMBER(nb_positive, nullptr),
+ INIT_MEMBER(nb_absolute, nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(nb_bool, TPyLazyDict::Bool),
+#else
+ INIT_MEMBER(nb_nonzero, TPyLazyDict::Bool),
+#endif
+ INIT_MEMBER(nb_invert, nullptr),
+ INIT_MEMBER(nb_lshift, nullptr),
+ INIT_MEMBER(nb_rshift, nullptr),
+ INIT_MEMBER(nb_and, nullptr),
+ INIT_MEMBER(nb_xor, nullptr),
+ INIT_MEMBER(nb_or, nullptr),
+#if PY_MAJOR_VERSION < 3
+ INIT_MEMBER(nb_coerce, nullptr),
+#endif
+ INIT_MEMBER(nb_int, nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(nb_reserved, nullptr),
+#else
+ INIT_MEMBER(nb_long, nullptr),
+#endif
+ INIT_MEMBER(nb_float, nullptr),
+#if PY_MAJOR_VERSION < 3
+ INIT_MEMBER(nb_oct, nullptr),
+ INIT_MEMBER(nb_hex, nullptr),
+#endif
+
+ INIT_MEMBER(nb_inplace_add, nullptr),
+ INIT_MEMBER(nb_inplace_subtract, nullptr),
+ INIT_MEMBER(nb_inplace_multiply, nullptr),
+ INIT_MEMBER(nb_inplace_remainder, nullptr),
+ INIT_MEMBER(nb_inplace_power, nullptr),
+ INIT_MEMBER(nb_inplace_lshift, nullptr),
+ INIT_MEMBER(nb_inplace_rshift, nullptr),
+ INIT_MEMBER(nb_inplace_and, nullptr),
+ INIT_MEMBER(nb_inplace_xor, nullptr),
+ INIT_MEMBER(nb_inplace_or, nullptr),
+
+ INIT_MEMBER(nb_floor_divide, nullptr),
+ INIT_MEMBER(nb_true_divide, nullptr),
+ INIT_MEMBER(nb_inplace_floor_divide, nullptr),
+ INIT_MEMBER(nb_inplace_true_divide, nullptr),
+
+ INIT_MEMBER(nb_index, nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(nb_matrix_multiply, nullptr),
+ INIT_MEMBER(nb_inplace_matrix_multiply, nullptr),
+#endif
+};
+
+
+#if PY_MAJOR_VERSION >= 3
+#define Py_TPFLAGS_HAVE_ITER 0
+#define Py_TPFLAGS_HAVE_SEQUENCE_IN 0
+#endif
+
+PyDoc_STRVAR(get__doc__,
+ "D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.");
+PyDoc_STRVAR(keys__doc__,
+ "D.keys() -> an iterator over the keys of D");
+PyDoc_STRVAR(values__doc__,
+ "D.values() -> an iterator over the values of D");
+PyDoc_STRVAR(items__doc__,
+ "D.items() -> an iterator over the (key, value) items of D");
+#if PY_MAJOR_VERSION < 3
+PyDoc_STRVAR(iterkeys__doc__,
+ "D.iterkeys() -> an iterator over the keys of D");
+PyDoc_STRVAR(itervalues__doc__,
+ "D.itervalues() -> an iterator over the values of D");
+PyDoc_STRVAR(iteritems__doc__,
+ "D.iteritems() -> an iterator over the (key, value) items of D");
+#endif
+
+static PyMethodDef LazyDictMethods[] = {
+ { "get", TPyLazyDict::Get, METH_VARARGS, get__doc__ },
+ { "keys", TPyLazyDict::Keys, METH_NOARGS, keys__doc__ },
+ { "items", TPyLazyDict::Items, METH_NOARGS, items__doc__ },
+ { "values", TPyLazyDict::Values, METH_NOARGS, values__doc__ },
+#if PY_MAJOR_VERSION < 3
+ { "iterkeys", TPyLazyDict::Keys, METH_NOARGS, iterkeys__doc__ },
+ { "iteritems", TPyLazyDict::Items, METH_NOARGS, iteritems__doc__ },
+ { "itervalues", TPyLazyDict::Values, METH_NOARGS, itervalues__doc__ },
+#endif
+ { nullptr, nullptr, 0, nullptr } /* sentinel */
+};
+
+PyTypeObject PyLazyDictType = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ INIT_MEMBER(tp_name , "yql.TDict"),
+ INIT_MEMBER(tp_basicsize , sizeof(TPyLazyDict)),
+ INIT_MEMBER(tp_itemsize , 0),
+ INIT_MEMBER(tp_dealloc , TPyLazyDict::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 , TPyLazyDict::Repr),
+ INIT_MEMBER(tp_as_number , &LazyDictNumbering),
+ INIT_MEMBER(tp_as_sequence , &LazyDictSequence),
+ INIT_MEMBER(tp_as_mapping , &LazyDictMapping),
+ 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 , Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER | Py_TPFLAGS_HAVE_SEQUENCE_IN),
+ INIT_MEMBER(tp_doc , "yql.TDict 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 , &TPyLazyDict::Iter),
+ INIT_MEMBER(tp_iternext , nullptr),
+ INIT_MEMBER(tp_methods , LazyDictMethods),
+ 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
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// TPyLazySet interface
+//////////////////////////////////////////////////////////////////////////////
+struct TPyLazySet
+{
+ using TPtr = NUdf::TRefCountedPtr<TPyLazySet, TPyPtrOps<TPyLazySet>>;
+
+ PyObject_HEAD;
+ TPyCastContext::TPtr CastCtx;
+ const NUdf::TType* ItemType;
+ TPyCleanupListItem<NUdf::IBoxedValuePtr> Value;
+
+ inline static TPyLazySet* Cast(PyObject* o) {
+ return reinterpret_cast<TPyLazySet*>(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 int Bool(PyObject* self);
+ static PyObject* Repr(PyObject* self);
+ static Py_ssize_t Len(PyObject* self);
+ static int Contains(PyObject* self, PyObject* key);
+ static PyObject* Get(PyObject* self, PyObject* args);
+
+ static PyObject* Iter(PyObject* self);
+};
+
+PySequenceMethods LazySetSequence = {
+ INIT_MEMBER(sq_length , TPyLazySet::Len),
+ INIT_MEMBER(sq_concat , nullptr),
+ INIT_MEMBER(sq_repeat , nullptr),
+ INIT_MEMBER(sq_item , nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(was_sq_slice , nullptr),
+#else
+ INIT_MEMBER(sq_slice , nullptr),
+#endif
+ INIT_MEMBER(sq_ass_item , nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(was_sq_ass_slice , nullptr),
+#else
+ INIT_MEMBER(sq_ass_slice , nullptr),
+#endif
+ INIT_MEMBER(sq_contains , TPyLazySet::Contains),
+ INIT_MEMBER(sq_inplace_concat , nullptr),
+ INIT_MEMBER(sq_inplace_repeat , nullptr),
+};
+
+PyNumberMethods LazySetNumbering = {
+ INIT_MEMBER(nb_add, nullptr),
+ INIT_MEMBER(nb_subtract, nullptr),
+ INIT_MEMBER(nb_multiply, nullptr),
+#if PY_MAJOR_VERSION < 3
+ INIT_MEMBER(nb_divide, nullptr),
+#endif
+ INIT_MEMBER(nb_remainder, nullptr),
+ INIT_MEMBER(nb_divmod, nullptr),
+ INIT_MEMBER(nb_power, nullptr),
+ INIT_MEMBER(nb_negative, nullptr),
+ INIT_MEMBER(nb_positive, nullptr),
+ INIT_MEMBER(nb_absolute, nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(nb_bool, TPyLazySet::Bool),
+#else
+ INIT_MEMBER(nb_nonzero, TPyLazySet::Bool),
+#endif
+ INIT_MEMBER(nb_invert, nullptr),
+ INIT_MEMBER(nb_lshift, nullptr),
+ INIT_MEMBER(nb_rshift, nullptr),
+ INIT_MEMBER(nb_and, nullptr),
+ INIT_MEMBER(nb_xor, nullptr),
+ INIT_MEMBER(nb_or, nullptr),
+#if PY_MAJOR_VERSION < 3
+ INIT_MEMBER(nb_coerce, nullptr),
+#endif
+ INIT_MEMBER(nb_int, nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(nb_reserved, nullptr),
+#else
+ INIT_MEMBER(nb_long, nullptr),
+#endif
+ INIT_MEMBER(nb_float, nullptr),
+#if PY_MAJOR_VERSION < 3
+ INIT_MEMBER(nb_oct, nullptr),
+ INIT_MEMBER(nb_hex, nullptr),
+#endif
+
+ INIT_MEMBER(nb_inplace_add, nullptr),
+ INIT_MEMBER(nb_inplace_subtract, nullptr),
+ INIT_MEMBER(nb_inplace_multiply, nullptr),
+ INIT_MEMBER(nb_inplace_remainder, nullptr),
+ INIT_MEMBER(nb_inplace_power, nullptr),
+ INIT_MEMBER(nb_inplace_lshift, nullptr),
+ INIT_MEMBER(nb_inplace_rshift, nullptr),
+ INIT_MEMBER(nb_inplace_and, nullptr),
+ INIT_MEMBER(nb_inplace_xor, nullptr),
+ INIT_MEMBER(nb_inplace_or, nullptr),
+
+ INIT_MEMBER(nb_floor_divide, nullptr),
+ INIT_MEMBER(nb_true_divide, nullptr),
+ INIT_MEMBER(nb_inplace_floor_divide, nullptr),
+ INIT_MEMBER(nb_inplace_true_divide, nullptr),
+
+ INIT_MEMBER(nb_index, nullptr),
+#if PY_MAJOR_VERSION >= 3
+ INIT_MEMBER(nb_matrix_multiply, nullptr),
+ INIT_MEMBER(nb_inplace_matrix_multiply, nullptr),
+#endif
+};
+
+PyTypeObject PyLazySetType = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ INIT_MEMBER(tp_name , "yql.TSet"),
+ INIT_MEMBER(tp_basicsize , sizeof(TPyLazySet)),
+ INIT_MEMBER(tp_itemsize , 0),
+ INIT_MEMBER(tp_dealloc , TPyLazySet::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 , TPyLazySet::Repr),
+ INIT_MEMBER(tp_as_number , &LazySetNumbering),
+ INIT_MEMBER(tp_as_sequence , &LazySetSequence),
+ 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 , Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER | Py_TPFLAGS_HAVE_SEQUENCE_IN),
+ INIT_MEMBER(tp_doc , "yql.TSet 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 , &TPyLazySet::Iter),
+ INIT_MEMBER(tp_iternext , nullptr),
+ INIT_MEMBER(tp_methods , nullptr),
+ 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
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// TPyLazyDict implementation
+//////////////////////////////////////////////////////////////////////////////
+int TPyLazyDict::Bool(PyObject* self)
+{
+ PY_TRY {
+ return NUdf::TBoxedValueAccessor::HasDictItems(*Cast(self)->Value.Get()) ? 1 : 0;
+ } PY_CATCH(-1)
+}
+
+PyObject* TPyLazyDict::Repr(PyObject*)
+{
+ return PyRepr("<yql.TDict>").Release();
+}
+
+Py_ssize_t TPyLazyDict::Len(PyObject* self)
+{
+ PY_TRY {
+ return static_cast<Py_ssize_t>(NUdf::TBoxedValueAccessor::GetDictLength(*Cast(self)->Value.Get()));
+ } PY_CATCH(-1)
+}
+
+PyObject* TPyLazyDict::Subscript(PyObject* self, PyObject* key)
+{
+ PY_TRY {
+ TPyLazyDict* dict = Cast(self);
+
+ if (dict->KeyType) {
+ const auto mkqlKey = FromPyObject(dict->CastCtx, dict->KeyType, key);
+ if (auto value = NUdf::TBoxedValueAccessor::Lookup(*dict->Value.Get(), mkqlKey)) {
+ return ToPyObject(dict->CastCtx, dict->PayloadType, value.Release().GetOptionalValue()).Release();
+ }
+
+ const TPyObjectPtr repr = PyObject_Repr(key);
+ PyErr_SetObject(PyExc_KeyError, repr.Get());
+ return nullptr;
+ } else {
+ if (!PyIndex_Check(key)) {
+ const TPyObjectPtr type = PyObject_Type(key);
+ const TPyObjectPtr repr = PyObject_Repr(type.Get());
+ const TPyObjectPtr error = PyUnicode_FromFormat("Unsupported index object type: %R", repr.Get());
+ PyErr_SetObject(PyExc_TypeError, error.Get());
+ return nullptr;
+ }
+
+ const Py_ssize_t index = PyNumber_AsSsize_t(key, PyExc_IndexError);
+ if (index < 0) {
+ return nullptr;
+ }
+
+ if (auto value = NUdf::TBoxedValueAccessor::Lookup(*dict->Value.Get(), NUdf::TUnboxedValuePod(ui64(index)))) {
+ return ToPyObject(dict->CastCtx, dict->PayloadType, value.Release().GetOptionalValue()).Release();
+ }
+
+ const TPyObjectPtr repr = PyObject_Repr(key);
+ PyErr_SetObject(PyExc_IndexError, repr.Get());
+ return nullptr;
+ }
+
+ } PY_CATCH(nullptr)
+}
+
+// -1 error
+// 0 not found
+// 1 found
+int TPyLazyDict::Contains(PyObject* self, PyObject* key)
+{
+ PY_TRY {
+ TPyLazyDict* dict = Cast(self);
+ NUdf::TUnboxedValue mkqlKey;
+
+ if (dict->KeyType) {
+ mkqlKey = FromPyObject(dict->CastCtx, dict->KeyType, key);
+ } else {
+ if (!PyIndex_Check(key)) {
+ const TPyObjectPtr type = PyObject_Type(key);
+ const TPyObjectPtr repr = PyObject_Repr(type.Get());
+ const TPyObjectPtr error = PyUnicode_FromFormat("Unsupported index object type: %R", repr.Get());
+ PyErr_SetObject(PyExc_TypeError, error.Get());
+ return -1;
+ }
+
+ const Py_ssize_t index = PyNumber_AsSsize_t(key, PyExc_IndexError);
+ if (index < 0) {
+ return 0;
+ }
+ mkqlKey = NUdf::TUnboxedValuePod(ui64(index));
+ }
+
+ return NUdf::TBoxedValueAccessor::Contains(*dict->Value.Get(), mkqlKey) ? 1 : 0;
+ } PY_CATCH(-1)
+}
+
+PyObject* TPyLazyDict::Get(PyObject* self, PyObject* args)
+{
+ PY_TRY {
+ PyObject* key = nullptr;
+ PyObject* failobj = Py_None;
+
+ if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj))
+ return nullptr;
+
+ TPyLazyDict* dict = Cast(self);
+ if (dict->KeyType) {
+ const auto mkqlKey = FromPyObject(dict->CastCtx, dict->KeyType, key);
+ if (auto value = NUdf::TBoxedValueAccessor::Lookup(*dict->Value.Get(), mkqlKey)) {
+ return ToPyObject(dict->CastCtx, dict->PayloadType, value.Release().GetOptionalValue()).Release();
+ }
+ } else {
+ if (!PyIndex_Check(key)) {
+ const TPyObjectPtr type = PyObject_Type(key);
+ const TPyObjectPtr repr = PyObject_Repr(type.Get());
+ const TPyObjectPtr error = PyUnicode_FromFormat("Unsupported index object type: %R", repr.Get());
+ PyErr_SetObject(PyExc_TypeError, error.Get());
+ return nullptr;
+ }
+
+ const Py_ssize_t index = PyNumber_AsSsize_t(key, PyExc_IndexError);
+ if (index < 0) {
+ return nullptr;
+ }
+
+ if (auto value = NUdf::TBoxedValueAccessor::Lookup(*dict->Value.Get(), NUdf::TUnboxedValuePod(ui64(index)))) {
+ return ToPyObject(dict->CastCtx, dict->PayloadType, value.Release().GetOptionalValue()).Release();
+ }
+ }
+
+ Py_INCREF(failobj);
+ return failobj;
+ } PY_CATCH(nullptr)
+}
+
+PyObject* TPyLazyDict::Keys(PyObject* self, PyObject* /* args */)
+{
+ PY_TRY {
+ const auto dict = Cast(self);
+ return ToPyIterator(dict->CastCtx, dict->KeyType,
+ NUdf::TBoxedValueAccessor::GetKeysIterator(*dict->Value.Get())).Release();
+ } PY_CATCH(nullptr)
+}
+
+PyObject* TPyLazyDict::Items(PyObject* self, PyObject* /* args */)
+{
+ PY_TRY {
+ const auto dict = Cast(self);
+ return ToPyIterator(dict->CastCtx, dict->KeyType, dict->PayloadType,
+ NUdf::TBoxedValueAccessor::GetDictIterator(*dict->Value.Get())).Release();
+ } PY_CATCH(nullptr)
+}
+
+PyObject* TPyLazyDict::Values(PyObject* self, PyObject* /* args */)
+{
+ PY_TRY {
+ const auto dict = Cast(self);
+ return ToPyIterator(dict->CastCtx, dict->PayloadType,
+ NUdf::TBoxedValueAccessor::GetPayloadsIterator(*dict->Value.Get())).Release();
+ } PY_CATCH(nullptr)
+}
+
+PyObject* TPyLazyDict::New(
+ const TPyCastContext::TPtr& castCtx,
+ const NUdf::TType* keyType,
+ const NUdf::TType* payloadType,
+ NUdf::IBoxedValuePtr&& value)
+{
+ TPyLazyDict* dict = new TPyLazyDict;
+ PyObject_INIT(dict, &PyLazyDictType);
+
+ dict->CastCtx = castCtx;
+ dict->KeyType = keyType;
+ dict->PayloadType = payloadType;
+ dict->Value.Set(castCtx->PyCtx, value);
+ return reinterpret_cast<PyObject*>(dict);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// TPyLazySet implementation
+//////////////////////////////////////////////////////////////////////////////
+int TPyLazySet::Bool(PyObject* self)
+{
+ PY_TRY {
+ return NUdf::TBoxedValueAccessor::HasDictItems(*Cast(self)->Value.Get()) ? 1 : 0;
+ } PY_CATCH(-1)
+}
+
+PyObject* TPyLazySet::Repr(PyObject*)
+{
+ return PyRepr("<yql.TSet>").Release();
+}
+
+Py_ssize_t TPyLazySet::Len(PyObject* self)
+{
+ PY_TRY {
+ return static_cast<Py_ssize_t>(NUdf::TBoxedValueAccessor::GetDictLength(*Cast(self)->Value.Get()));
+ } PY_CATCH(-1)
+}
+
+// -1 error
+// 0 not found
+// 1 found
+int TPyLazySet::Contains(PyObject* self, PyObject* key)
+{
+ PY_TRY {
+ const auto set = Cast(self);
+ const auto mkqlKey = FromPyObject(set->CastCtx, set->ItemType, key);
+ return NUdf::TBoxedValueAccessor::Contains(*set->Value.Get(), mkqlKey) ? 1 : 0;
+ } PY_CATCH(-1)
+}
+
+PyObject* TPyLazySet::Iter(PyObject* self)
+{
+ PY_TRY {
+ const auto set = Cast(self);
+ return ToPyIterator(set->CastCtx, set->ItemType,
+ NUdf::TBoxedValueAccessor::GetKeysIterator(*set->Value.Get())).Release();
+ } PY_CATCH(nullptr)
+}
+
+PyObject* TPyLazySet::New(
+ const TPyCastContext::TPtr& castCtx,
+ const NUdf::TType* itemType,
+ NUdf::IBoxedValuePtr&& value)
+{
+ TPyLazySet* dict = new TPyLazySet;
+ PyObject_INIT(dict, &PyLazySetType);
+
+ dict->CastCtx = castCtx;
+ dict->ItemType = itemType;
+ dict->Value.Set(castCtx->PyCtx, value);
+ return reinterpret_cast<PyObject*>(dict);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TPyObjectPtr ToPyLazyDict(
+ const TPyCastContext::TPtr& castCtx,
+ const NUdf::TType* keyType,
+ const NUdf::TType* payloadType,
+ const NUdf::TUnboxedValuePod& value)
+{
+ return TPyLazyDict::New(castCtx, keyType, payloadType, value.AsBoxed());
+}
+
+TPyObjectPtr ToPyLazySet(
+ const TPyCastContext::TPtr& castCtx,
+ const NUdf::TType* itemType,
+ const NUdf::TUnboxedValuePod& value)
+{
+ return TPyLazySet::New(castCtx, itemType, value.AsBoxed());
+}
+
+} // namspace NPython