py_variant.cpp 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. #include "py_variant.h"
  2. #include "py_cast.h"
  3. #include "py_errors.h"
  4. #include "py_utils.h"
  5. #include <yql/essentials/public/udf/udf_value.h>
  6. #include <yql/essentials/public/udf/udf_value_builder.h>
  7. #include <yql/essentials/public/udf/udf_type_inspection.h>
  8. using namespace NKikimr;
  9. namespace NPython {
  10. //////////////////////////////////////////////////////////////////////////////
  11. // public functions
  12. //////////////////////////////////////////////////////////////////////////////
  13. TPyObjectPtr ToPyVariant(
  14. const TPyCastContext::TPtr& castCtx,
  15. const NUdf::TType* type,
  16. const NUdf::TUnboxedValuePod& value)
  17. {
  18. auto& th = *castCtx->PyCtx->TypeInfoHelper;
  19. NUdf::TVariantTypeInspector varInsp(th, type);
  20. const NUdf::TType* subType = varInsp.GetUnderlyingType();
  21. ui32 index = value.GetVariantIndex();
  22. auto item = value.GetVariantItem();
  23. const NUdf::TType* itemType = nullptr;
  24. if (auto tupleInsp = NUdf::TTupleTypeInspector(th, subType)) {
  25. itemType = tupleInsp.GetElementType(index);
  26. TPyObjectPtr pyIndex = PyCast<ui32>(index);
  27. TPyObjectPtr pyItem = ToPyObject(castCtx, itemType, item);
  28. return PyTuple_Pack(2, pyIndex.Get(), pyItem.Get());
  29. } else if (auto structInsp = NUdf::TStructTypeInspector(th, subType)) {
  30. itemType = structInsp.GetMemberType(index);
  31. TPyObjectPtr pyName = ToPyUnicode<NUdf::TStringRef>(
  32. structInsp.GetMemberName(index));
  33. TPyObjectPtr pyItem = ToPyObject(castCtx, itemType, item);
  34. return PyTuple_Pack(2, pyName.Get(), pyItem.Get());
  35. }
  36. throw yexception() << "Cannot get Variant item type";
  37. }
  38. NUdf::TUnboxedValue FromPyVariant(
  39. const TPyCastContext::TPtr& castCtx,
  40. const NUdf::TType* type,
  41. PyObject* value)
  42. {
  43. PY_ENSURE(PyTuple_Check(value),
  44. "Expected to get Tuple, but got " << Py_TYPE(value)->tp_name);
  45. Py_ssize_t tupleSize = PyTuple_GET_SIZE(value);
  46. PY_ENSURE(tupleSize == 2,
  47. "Expected to get Tuple with 2 elements, but got "
  48. << tupleSize << " elements");
  49. auto& th = *castCtx->PyCtx->TypeInfoHelper;
  50. NUdf::TVariantTypeInspector varInsp(th, type);
  51. const NUdf::TType* subType = varInsp.GetUnderlyingType();
  52. PyObject* el0 = PyTuple_GET_ITEM(value, 0);
  53. PyObject* el1 = PyTuple_GET_ITEM(value, 1);
  54. ui32 index;
  55. NUdf::TStringRef name;
  56. if (TryPyCast(el0, index)) {
  57. if (auto tupleInsp = NUdf::TTupleTypeInspector(th, subType)) {
  58. PY_ENSURE(index < tupleInsp.GetElementsCount(),
  59. "Index must be < " << tupleInsp.GetElementsCount()
  60. << ", but got " << index);
  61. auto* itemType = tupleInsp.GetElementType(index);
  62. return castCtx->ValueBuilder->NewVariant(index, FromPyObject(castCtx, itemType, el1));
  63. } else {
  64. throw yexception() << "Cannot convert " << PyObjectRepr(value)
  65. << " underlying Variant type is not a Tuple";
  66. }
  67. } else if (TryPyCast(el0, name)) {
  68. if (auto structInsp = NUdf::TStructTypeInspector(th, subType)) {
  69. ui32 index = structInsp.GetMemberIndex(name);
  70. PY_ENSURE(index < structInsp.GetMembersCount(),
  71. "Unknown member name: " << TStringBuf(name));
  72. auto* itemType = structInsp.GetMemberType(index);
  73. return castCtx->ValueBuilder->NewVariant(index, FromPyObject(castCtx, itemType, el1));
  74. } else {
  75. throw yexception() << "Cannot convert " << PyObjectRepr(value)
  76. << " underlying Variant type is not a Struct";
  77. }
  78. } else {
  79. throw yexception()
  80. << "Expected first Tuple element to either be an int "
  81. "or a str, but got " << Py_TYPE(el0)->tp_name;
  82. }
  83. }
  84. } // namspace NPython