aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/udfs/common/python/bindings/py_stream_ut.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'yql/essentials/udfs/common/python/bindings/py_stream_ut.cpp')
-rw-r--r--yql/essentials/udfs/common/python/bindings/py_stream_ut.cpp208
1 files changed, 208 insertions, 0 deletions
diff --git a/yql/essentials/udfs/common/python/bindings/py_stream_ut.cpp b/yql/essentials/udfs/common/python/bindings/py_stream_ut.cpp
new file mode 100644
index 0000000000..4a24dd1a13
--- /dev/null
+++ b/yql/essentials/udfs/common/python/bindings/py_stream_ut.cpp
@@ -0,0 +1,208 @@
+#include "ut3/py_test_engine.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+
+using namespace NPython;
+
+Y_UNIT_TEST_SUITE(TPyStreamTest) {
+ void Ui32StreamValidator(const NUdf::TUnboxedValuePod& value) {
+ UNIT_ASSERT(value);
+ UNIT_ASSERT(value.IsBoxed());
+
+ NUdf::TUnboxedValue item;
+ ui32 expected = 0;
+ NUdf::EFetchStatus status;
+
+ while (true) {
+ status = value.Fetch(item);
+ if (status != NUdf::EFetchStatus::Ok) break;
+
+ ui32 actual = item.Get<ui32>();
+ UNIT_ASSERT_EQUAL(actual, expected);
+ expected++;
+ }
+
+ UNIT_ASSERT_EQUAL(status, NUdf::EFetchStatus::Finish);
+ UNIT_ASSERT_EQUAL(expected, 10);
+ }
+
+ struct TTestStream final: NUdf::TBoxedValue {
+ TTestStream(ui32 maxValue, ui32 yieldOn = Max<ui32>())
+ : Current_(0)
+ , YieldOn_(yieldOn)
+ , MaxValue_(maxValue)
+ {
+ }
+
+ private:
+ NUdf::EFetchStatus Fetch(NUdf::TUnboxedValue& result) override {
+ if (Current_ == YieldOn_) {
+ return NUdf::EFetchStatus::Yield;
+ } else if (Current_ >= MaxValue_) {
+ return NUdf::EFetchStatus::Finish;
+ }
+ result = NUdf::TUnboxedValuePod(Current_++);
+ return NUdf::EFetchStatus::Ok;
+ }
+
+ ui32 Current_, YieldOn_, MaxValue_;
+ };
+
+ Y_UNIT_TEST(FromGenerator) {
+ TPythonTestEngine engine;
+ engine.ToMiniKQL<NUdf::TStream<ui32>>(
+ "def Test():\n"
+ " num = 0\n"
+ " while num < 10:\n"
+ " yield num\n"
+ " num += 1\n",
+ Ui32StreamValidator);
+ }
+
+ Y_UNIT_TEST(FromGeneratorFactory) {
+ TPythonTestEngine engine;
+ engine.ToMiniKQL<NUdf::TStream<ui32>>(
+ "def first_10():\n"
+ " num = 0\n"
+ " while num < 10:\n"
+ " yield num\n"
+ " num += 1\n"
+ "def Test():\n"
+ " return first_10\n",
+ Ui32StreamValidator);
+ }
+
+ Y_UNIT_TEST(FromIterator) {
+ TPythonTestEngine engine;
+ engine.ToMiniKQL<NUdf::TStream<ui32>>(
+ "def Test():\n"
+ " return iter(range(10))\n",
+ Ui32StreamValidator);
+ }
+
+ Y_UNIT_TEST(FromIterable) {
+ TPythonTestEngine engine;
+ engine.ToMiniKQL<NUdf::TStream<ui32>>(
+ "def Test():\n"
+#if PY_MAJOR_VERSION >= 3
+ " return range(10)\n",
+#else
+ " return xrange(10)\n",
+#endif
+ Ui32StreamValidator);
+ }
+
+ Y_UNIT_TEST(FromCustomIterable) {
+ TPythonTestEngine engine;
+ engine.ToMiniKQL<NUdf::TStream<ui32>>(
+ "class T:\n"
+ " def __init__(self, l):\n"
+ " self.l = l\n"
+ " def __len__(self):\n"
+ " return len(self.l)\n"
+ " def __nonzero__(self):\n"
+ " return bool(self.l)\n"
+ " def __iter__(self):\n"
+ " return iter(self.l)\n"
+ "\n"
+ "def Test():\n"
+ " return T(list(range(10)))\n",
+ Ui32StreamValidator);
+ }
+
+ Y_UNIT_TEST(FromList) {
+ TPythonTestEngine engine;
+ engine.ToMiniKQL<NUdf::TStream<ui32>>(
+ "def Test():\n"
+ " return [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
+ Ui32StreamValidator);
+ }
+
+ Y_UNIT_TEST(ToPython) {
+ TPythonTestEngine engine;
+ engine.ToPython<NUdf::TStream<ui32>>(
+ [](const TType* /*type*/, const NUdf::IValueBuilder& /*vb*/) {
+ return NUdf::TUnboxedValuePod(new TTestStream(10));
+ },
+ "def Test(value):\n"
+ " import yql\n"
+ " assert repr(value) == '<yql.TStream>'\n"
+ " assert type(value).__name__ == 'TStream'\n"
+ " assert list(value) == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n");
+ }
+
+ Y_UNIT_TEST(ToPythonAndBackAsIs) {
+ TPythonTestEngine engine;
+ engine.ToPythonAndBack<NUdf::TStream<ui32>>(
+ [](const TType* /*type*/, const NUdf::IValueBuilder& /*vb*/) {
+ return NUdf::TUnboxedValuePod(new TTestStream(10));
+ },
+ "def Test(value): return value",
+ Ui32StreamValidator
+ );
+ }
+
+ Y_UNIT_TEST(YieldingStreamFromPython) {
+ TPythonTestEngine engine;
+ engine.ToMiniKQL<NUdf::TStream<ui32>>(
+ "import yql\n"
+ "def Test():\n"
+ " yield 0\n"
+ " yield 1\n"
+ " yield yql.TYieldIteration\n"
+ " yield 2\n",
+ [](const NUdf::TUnboxedValuePod& value) {
+ UNIT_ASSERT(value);
+ UNIT_ASSERT(value.IsBoxed());
+
+ NUdf::TUnboxedValue item;
+ ui32 expected = 0;
+ NUdf::EFetchStatus status;
+
+ while ((status = value.Fetch(item)) == NUdf::EFetchStatus::Ok) {
+ ui32 actual = item.Get<ui32>();
+ UNIT_ASSERT_EQUAL(actual, expected);
+ expected++;
+ }
+
+ UNIT_ASSERT_EQUAL(status, NUdf::EFetchStatus::Yield);
+ UNIT_ASSERT_EQUAL(expected, 2);
+ });
+ }
+
+ Y_UNIT_TEST(YieldingStreamFromCpp) {
+ TPythonTestEngine engine;
+ engine.ToPython<NUdf::TStream<ui32>>(
+ [](const TType* /*type*/, const NUdf::IValueBuilder& /*vb*/) {
+ return NUdf::TUnboxedValuePod(new TTestStream(5, 2));
+ },
+ "import yql\n"
+ "def Test(value):\n"
+ " assert repr(value) == '<yql.TStream>'\n"
+ " assert type(value).__name__ == 'TStream'\n"
+ " assert next(value) == 0\n"
+ " assert next(value) == 1\n"
+ " try:\n"
+ " next(value)\n"
+ " except yql.TYieldIteration:\n"
+ " pass\n"
+ " else:\n"
+ " assert False, 'Expected yql.TYieldIteration'\n");
+ }
+
+ Y_UNIT_TEST(FromCppListIterator) {
+ TPythonTestEngine engine;
+ engine.ToPythonAndBack<NUdf::TListType<ui32>, NUdf::TStream<ui32>>(
+ [](const TType*, const NUdf::IValueBuilder& vb) {
+ NUdf::TUnboxedValue *items = nullptr;
+ const auto a = vb.NewArray(10U, items);
+ ui32 i = 0U;
+ std::generate_n(items, 10U, [&i](){ return NUdf::TUnboxedValuePod(i++); });
+ return a;
+ },
+ "def Test(value): return iter(value)",
+ Ui32StreamValidator
+ );
+ }
+}