Skip to content

Commit 475c997

Browse files
committed
Intermediate changes
commit_hash:4b0cad6620396d4b5422b264f4aa162104d45e8d
1 parent aac2e8a commit 475c997

File tree

3 files changed

+72
-4
lines changed

3 files changed

+72
-4
lines changed

yql/essentials/udfs/common/python/bindings/py_cast.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,19 @@ TPyObjectPtr ToPyArgs(
916916
TPyObjectPtr tuple(PyTuple_New(argsCount));
917917

918918
for (ui32 i = 0; i < argsCount; i++) {
919-
auto arg = ToPyObject(ctx, inspector.GetArgType(i), args[i]);
919+
const auto argType = inspector.GetArgType(i);
920+
auto arg = ToPyObject(ctx, argType, args[i]);
921+
// PyTuple_SET_ITEM doesn't handle the case if nullptr is
922+
// given as a payload to be set (unlike PyList_Append or
923+
// PyDict_SetItem do), so we have to explicitly handle
924+
// the failed export from UnboxedValue to PyObject here.
925+
if (!arg) {
926+
::TStringBuilder sb;
927+
sb << "Failed to export ";
928+
NUdf::TTypePrinter(*ctx->PyCtx->TypeInfoHelper, argType).Out(sb.Out);
929+
sb << " given as args[" << i << "]: ";
930+
UdfTerminate((sb << ctx->PyCtx->Pos << GetLastErrorAsString()).data());
931+
}
920932
PyTuple_SET_ITEM(tuple.Get(), i, arg.Release());
921933
}
922934

yql/essentials/udfs/common/python/bindings/py_cast_ut.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,29 @@ Y_UNIT_TEST_SUITE(TPyCastTest) {
124124
Y_UNIT_TEST(BadFromPythonJson) {
125125
TestBadUtf8Encode<NUdf::TJson>();
126126
}
127+
128+
Y_UNIT_TEST(BadToPythonJson) {
129+
TPythonTestEngine engine;
130+
UNIT_ASSERT_EXCEPTION_CONTAINS(
131+
engine.UnsafeCall<void(NUdf::TJson)>(
132+
[](const TType*, const NUdf::IValueBuilder& builder) {
133+
// XXX: The value below is built with the
134+
// following expression:
135+
// $query = "a=1&t%EDb=2";
136+
// $qdict = Url::QueryStringToDict($query);
137+
// $qyson = Yson::From($qdict);
138+
// $badJson = Yson::SerializeJson($qyson);
139+
//
140+
// For more info, see YQL-20231 and YQL-20220.
141+
constexpr TStringBuf badJson = "\x7b\x22\x61\x22\x3a\x5b\x22\x31\x22\x5d\x2c\x22\x74\xed\x62\x22\x3a\x5b\x22\x32\x22\x5d\x7d";
142+
return builder.NewString(badJson);
143+
},
144+
"def Test(arg):\n"
145+
" pass",
146+
[](const NUdf::TUnboxedValuePod&) {
147+
Y_UNREACHABLE();
148+
}
149+
),
150+
yexception, "Failed to export Json given as args[0]");
151+
}
127152
} // Y_UNIT_TEST_SUITE(TPyCastTest)

yql/essentials/udfs/common/python/bindings/py_test_engine.h

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,32 @@ class TPythonTestEngine {
115115
ToMiniKQLWithArg<TChecker>(type, argValue, script, std::move(checker));
116116
}
117117

118+
template <typename FunctionType,
119+
typename TMiniKQLValueBuilder,
120+
typename TChecker>
121+
void UnsafeCall(TMiniKQLValueBuilder&& builder,
122+
const TStringBuf& script,
123+
TChecker&& checker)
124+
{
125+
TPyObjectPtr function = CompilePythonFunction(script);
126+
const auto functionType = GetTypeBuilder().SimpleSignatureType<FunctionType>();
127+
NUdf::TCallableTypeInspector inspector(*CastCtx_->PyCtx->TypeInfoHelper, functionType);
128+
Y_ENSURE(inspector.GetArgsCount() == 1);
129+
const TType* argType = static_cast<const TType*>(inspector.GetArgType(0));
130+
NUdf::TUnboxedValue value = builder(argType, GetValueBuilder());
131+
TPyObjectPtr pyArgs = ToPyArgs(CastCtx_, functionType, &value, inspector);
132+
TPyObjectPtr resultObj = PyObject_CallObject(function.Get(), pyArgs.Get());
133+
134+
if (!resultObj) {
135+
return checker(NUdf::TUnboxedValuePod::Invalid());
136+
}
137+
138+
const auto returnType = inspector.GetReturnType();
139+
Y_ENSURE(CastCtx_->PyCtx->TypeInfoHelper->GetTypeKind(returnType) != NUdf::ETypeKind::Stream);
140+
141+
checker(FromPyObject(CastCtx_, returnType, resultObj.Get()));
142+
}
143+
118144
template <typename TMiniKQLValueBuilder>
119145
TPyObjectPtr ToPython(
120146
NUdf::TType* udfType,
@@ -189,9 +215,7 @@ class TPythonTestEngine {
189215
}
190216

191217
private:
192-
TPyObjectPtr RunPythonFunction(
193-
const TStringBuf& script, PyObject* args = nullptr)
194-
{
218+
TPyObjectPtr CompilePythonFunction(const TStringBuf& script) {
195219
TString filename(TStringBuf("embedded:test.py"));
196220
TPyObjectPtr code(Py_CompileString(script.data(), filename.data(), Py_file_input));
197221
if (!code) {
@@ -211,6 +235,13 @@ class TPythonTestEngine {
211235
PyErr_Print();
212236
UNIT_FAIL("function 'Test' is not found in module");
213237
}
238+
return function;
239+
}
240+
241+
TPyObjectPtr RunPythonFunction(
242+
const TStringBuf& script, PyObject* args = nullptr)
243+
{
244+
TPyObjectPtr function(CompilePythonFunction(script));
214245
return PyObject_CallObject(function.Get(), args);
215246
}
216247

0 commit comments

Comments
 (0)