diff --git a/morpheus/_lib/CMakeLists.txt b/morpheus/_lib/CMakeLists.txt index d163a9eec6..ac76601620 100644 --- a/morpheus/_lib/CMakeLists.txt +++ b/morpheus/_lib/CMakeLists.txt @@ -70,9 +70,6 @@ include(cmake/libmorpheus.cmake) # Set the default link targets to avoid repeating this morpheus_utils_python_package_set_default_link_targets(morpheus) -#----------morpheus._lib.pycoro--------- -add_subdirectory(pycoro) - # #----------morpheus._lib.common--------- morpheus_add_pybind11_module(common SOURCE_FILES common/module.cpp) diff --git a/morpheus/_lib/__init__.py b/morpheus/_lib/__init__.py index 7f1885b063..197c99d11d 100644 --- a/morpheus/_lib/__init__.py +++ b/morpheus/_lib/__init__.py @@ -15,7 +15,6 @@ from . import llm from . import messages from . import modules -from . import pycoro from . import stages __all__ = [ @@ -23,6 +22,5 @@ "llm", "messages", "modules", - "pycoro", "stages", ] diff --git a/morpheus/_lib/llm/CMakeLists.txt b/morpheus/_lib/llm/CMakeLists.txt index 82e3383e50..3a2f1f4fe2 100644 --- a/morpheus/_lib/llm/CMakeLists.txt +++ b/morpheus/_lib/llm/CMakeLists.txt @@ -29,7 +29,7 @@ list(APPEND MODULE_SOURCE_FILES module.cpp) morpheus_add_pybind11_module(llm INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include SOURCE_FILES ${MODULE_SOURCE_FILES} - LINK_TARGETS morpheus morpheus._lib.pycoro + LINK_TARGETS morpheus CURRENT_DIR_IS_MODULE ) diff --git a/morpheus/_lib/llm/__init__.pyi b/morpheus/_lib/llm/__init__.pyi index 96b347ee34..0a48535608 100644 --- a/morpheus/_lib/llm/__init__.pyi +++ b/morpheus/_lib/llm/__init__.pyi @@ -9,7 +9,7 @@ from __future__ import annotations import morpheus._lib.llm import typing import morpheus._lib.messages -import morpheus._lib.pycoro +import mrc.core.coro import mrc.core.segment __all__ = [ diff --git a/morpheus/_lib/llm/include/py_llm_engine_stage.hpp b/morpheus/_lib/llm/include/py_llm_engine_stage.hpp index 8e3ae0c833..81b27080f7 100644 --- a/morpheus/_lib/llm/include/py_llm_engine_stage.hpp +++ b/morpheus/_lib/llm/include/py_llm_engine_stage.hpp @@ -17,7 +17,6 @@ #pragma once #include "py_llm_node.hpp" -#include "pycoro/pycoro.hpp" #include "morpheus/export.h" #include "morpheus/llm/input_map.hpp" @@ -54,6 +53,7 @@ #include #include #include +#include #include #include @@ -156,13 +156,13 @@ class PythonAsyncioScheduler : public mrc::coroutines::Scheduler LOG(INFO) << "CoroutineRunnable::run() > Calling run_until_complete() on main_task()"; // Use the BoostFibersMainPyAwaitable to allow fibers to be progressed - loop.attr("run_until_complete")(mrc::pycoro::BoostFibersMainPyAwaitable(std::move(task))); + loop.attr("run_until_complete")(mrc::pymrc::coro::BoostFibersMainPyAwaitable(std::move(task))); LOG(INFO) << "CoroutineRunnable::run() > run_until_complete() returned. Waiting for all enqueued tasks to complete "; // Now wait until all tasks have been processed - loop.attr("run_until_complete")(mrc::pycoro::BoostFibersMainPyAwaitable( + loop.attr("run_until_complete")(mrc::pymrc::coro::BoostFibersMainPyAwaitable( this->get_task_container().garbage_collect_and_yield_until_empty())); } diff --git a/morpheus/_lib/llm/module.cpp b/morpheus/_lib/llm/module.cpp index 3b85a0684c..acc4a9971b 100644 --- a/morpheus/_lib/llm/module.cpp +++ b/morpheus/_lib/llm/module.cpp @@ -21,7 +21,6 @@ #include "./include/py_llm_task_handler.hpp" #include "py_llm_engine_stage.hpp" #include "py_llm_lambda_node.hpp" -#include "pycoro/pycoro.hpp" // IWYU pragma: keep #include "morpheus/llm/input_map.hpp" #include "morpheus/llm/llm_context.hpp" @@ -47,6 +46,7 @@ #include // for arg, init, class_, module_, str_attr_accessor, PYBIND11_MODULE, pybind11 #include // for dict, sequence #include // IWYU pragma: keep +#include // IWYU pragma: keep #include // for pymrc::import #include @@ -73,8 +73,8 @@ PYBIND11_MODULE(llm, _module) // Load the cudf helpers CudfHelper::load(); - // Import the pycoro module - mrc::pymrc::import(_module, "morpheus._lib.pycoro"); + // Import the mrc coro module + mrc::pymrc::import(_module, "mrc.core.coro"); // Import the messages module mrc::pymrc::import(_module, "morpheus._lib.messages"); diff --git a/morpheus/_lib/llm/src/py_llm_lambda_node.cpp b/morpheus/_lib/llm/src/py_llm_lambda_node.cpp index a4e9bdd8c6..fb127c72a2 100644 --- a/morpheus/_lib/llm/src/py_llm_lambda_node.cpp +++ b/morpheus/_lib/llm/src/py_llm_lambda_node.cpp @@ -17,7 +17,7 @@ #include "py_llm_lambda_node.hpp" -#include "pycoro/pycoro.hpp" +#include "pymrc/coro.hpp" #include "morpheus/llm/llm_context.hpp" #include "morpheus/llm/llm_node_base.hpp" @@ -29,6 +29,7 @@ #include #include #include +#include // IWYU pragma: keep #include #include @@ -116,7 +117,7 @@ Task> PyLLMLambdaNode::execute(std::shared_ptr // IWYU pragma: keep #include #include // IWYU pragma: keep +#include // IWYU pragma: keep #include diff --git a/morpheus/_lib/llm/src/py_llm_task_handler.cpp b/morpheus/_lib/llm/src/py_llm_task_handler.cpp index 736946f372..b70f95cf49 100644 --- a/morpheus/_lib/llm/src/py_llm_task_handler.cpp +++ b/morpheus/_lib/llm/src/py_llm_task_handler.cpp @@ -17,13 +17,12 @@ #include "py_llm_task_handler.hpp" -#include "pycoro/pycoro.hpp" - #include "morpheus/llm/llm_context.hpp" #include // IWYU pragma: keep #include #include // IWYU pragma: keep +#include // IWYU pragma: keep #include diff --git a/morpheus/_lib/pycoro/CMakeLists.txt b/morpheus/_lib/pycoro/CMakeLists.txt deleted file mode 100644 index 9c5feb5183..0000000000 --- a/morpheus/_lib/pycoro/CMakeLists.txt +++ /dev/null @@ -1,39 +0,0 @@ -# ============================================================================= -# Copyright (c) 2023, NVIDIA CORPORATION. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except -# in compliance with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software distributed under the License -# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express -# or implied. See the License for the specific language governing permissions and limitations under -# the License. -# ============================================================================= - -list(APPEND CMAKE_MESSAGE_CONTEXT "pycoro") - -set(MODULE_SOURCE_FILES - src/pycoro.cpp -) - -# Add the module file -list(APPEND MODULE_SOURCE_FILES module.cpp) - -# Create the python module -morpheus_add_pybind11_library(pycoro - INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include - SOURCE_FILES ${MODULE_SOURCE_FILES} - LINK_TARGETS mrc::pymrc - OUTPUT_TARGET PYCORO_TARGET_NAME - CURRENT_DIR_IS_MODULE -) - -# Export the include so we can use it in other modules -target_include_directories(${PYCORO_TARGET_NAME} - PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include -) - -list(POP_BACK CMAKE_MESSAGE_CONTEXT) diff --git a/morpheus/_lib/pycoro/__init__.pyi b/morpheus/_lib/pycoro/__init__.pyi deleted file mode 100644 index 2a906b2ef0..0000000000 --- a/morpheus/_lib/pycoro/__init__.pyi +++ /dev/null @@ -1,29 +0,0 @@ -""" - ----------------------- - .. currentmodule:: morpheus.llm - .. autosummary:: - :toctree: _generate - - """ -from __future__ import annotations -import morpheus._lib.pycoro -import typing - -__all__ = [ - "BoostFibersMainPyAwaitable", - "CppToPyAwaitable", - "wrap_coroutine" -] - - -class CppToPyAwaitable(): - def __await__(self) -> CppToPyAwaitable: ... - def __init__(self) -> None: ... - def __iter__(self) -> CppToPyAwaitable: ... - def __next__(self) -> None: ... - pass -class BoostFibersMainPyAwaitable(CppToPyAwaitable): - def __init__(self) -> None: ... - pass -def wrap_coroutine(arg0: typing.Awaitable[typing.List[str]]) -> typing.Awaitable[str]: - pass diff --git a/morpheus/_lib/pycoro/include/pycoro/pycoro.hpp b/morpheus/_lib/pycoro/include/pycoro/pycoro.hpp deleted file mode 100644 index e69af87ec6..0000000000 --- a/morpheus/_lib/pycoro/include/pycoro/pycoro.hpp +++ /dev/null @@ -1,418 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -// Dont directly include python headers -// IWYU pragma: no_include - -namespace mrc::pycoro { - -class PYBIND11_EXPORT StopIteration : public pybind11::stop_iteration -{ - public: - StopIteration(pybind11::object&& result) : stop_iteration("--"), m_result(std::move(result)){}; - ~StopIteration() override; - - void set_error() const override - { - PyErr_SetObject(PyExc_StopIteration, this->m_result.ptr()); - } - - private: - pybind11::object m_result; -}; - -class PYBIND11_EXPORT CppToPyAwaitable : public std::enable_shared_from_this -{ - public: - CppToPyAwaitable() = default; - - template - CppToPyAwaitable(mrc::coroutines::Task&& task) - { - auto converter = [](mrc::coroutines::Task incoming_task) -> mrc::coroutines::Task { - DCHECK_EQ(PyGILState_Check(), 0) << "Should not have the GIL when resuming a C++ coroutine"; - - mrc::pymrc::PyHolder holder; - - if constexpr (std::is_same_v) - { - co_await incoming_task; - - // Need the GIL to make the return object - pybind11::gil_scoped_acquire gil; - - holder = pybind11::none(); - } - else - { - auto result = co_await incoming_task; - - // Need the GIL to cast the return object - pybind11::gil_scoped_acquire gil; - - holder = pybind11::cast(std::move(result)); - } - - co_return holder; - }; - - m_task = converter(std::move(task)); - } - - CppToPyAwaitable(mrc::coroutines::Task&& task) : m_task(std::move(task)) {} - - std::shared_ptr iter() - { - return this->shared_from_this(); - } - - std::shared_ptr await() - { - return this->shared_from_this(); - } - - void next() - { - // Need to release the GIL before waiting - pybind11::gil_scoped_release nogil; - - // Run the tick function which will resume the coroutine - this->tick(); - - if (m_task.is_ready()) - { - pybind11::gil_scoped_acquire gil; - - // job done -> throw - auto exception = StopIteration(std::move(m_task.promise().result())); - - // Destroy the task now that we have the value - m_task.destroy(); - - throw exception; - } - } - - protected: - virtual void tick() - { - if (!m_has_resumed) - { - m_has_resumed = true; - - m_task.resume(); - } - } - - bool m_has_resumed{false}; - mrc::coroutines::Task m_task; -}; - -/** - * @brief Similar to CppToPyAwaitable but will yield to other fibers when waiting for the coroutine to finish. Use this - * once per loop at the main entry point for the asyncio loop - * - */ -class PYBIND11_EXPORT BoostFibersMainPyAwaitable : public CppToPyAwaitable -{ - public: - using CppToPyAwaitable::CppToPyAwaitable; - - protected: - void tick() override - { - // Call the base class and then see if any fibers need processing by calling yield - CppToPyAwaitable::tick(); - - bool has_fibers = boost::fibers::has_ready_fibers(); - - if (has_fibers) - { - // Yield to other fibers - boost::this_fiber::yield(); - } - } -}; - -class PYBIND11_EXPORT PyTaskToCppAwaitable -{ - public: - PyTaskToCppAwaitable() = default; - PyTaskToCppAwaitable(mrc::pymrc::PyObjectHolder&& task) : m_task(std::move(task)) {} - - bool await_ready() const noexcept - { - // Always suspend - return false; - } - - void await_suspend(std::coroutine_handle<> caller) noexcept - { - pybind11::gil_scoped_acquire gil; - - auto done_callback = pybind11::cpp_function([this, caller](pybind11::object future) { - try - { - // Save the result value - m_result = future.attr("result")(); - } catch (pybind11::error_already_set) - { - m_exception_ptr = std::current_exception(); - } - - pybind11::gil_scoped_release nogil; - - // Resume the coroutine - caller.resume(); - }); - - m_task.attr("add_done_callback")(done_callback); - } - - mrc::pymrc::PyHolder await_resume() - { - if (m_exception_ptr) - { - std::rethrow_exception(m_exception_ptr); - } - - return std::move(m_result); - } - - private: - mrc::pymrc::PyObjectHolder m_task; - mrc::pymrc::PyHolder m_result; - std::exception_ptr m_exception_ptr; -}; - -// ====== HELPER MACROS ====== - -#define MRC_PYBIND11_FAIL_ABSTRACT(cname, fnname) \ - pybind11::pybind11_fail(MRC_CONCAT_STR("Tried to call pure virtual function \"" << PYBIND11_STRINGIFY(cname) \ - << "::" << fnname << "\"")); - -// ====== OVERRIDE PURE TEMPLATE ====== -#define MRC_PYBIND11_OVERRIDE_PURE_TEMPLATE_NAME(ret_type, abstract_cname, cname, name, fn, ...) \ - do \ - { \ - PYBIND11_OVERRIDE_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \ - if constexpr (std::is_same_v) \ - { \ - MRC_PYBIND11_FAIL_ABSTRACT(PYBIND11_TYPE(abstract_cname), name); \ - } \ - else \ - { \ - return cname::fn(__VA_ARGS__); \ - } \ - } while (false) - -#define MRC_PYBIND11_OVERRIDE_PURE_TEMPLATE(ret_type, abstract_cname, cname, fn, ...) \ - MRC_PYBIND11_OVERRIDE_PURE_TEMPLATE_NAME( \ - PYBIND11_TYPE(ret_type), PYBIND11_TYPE(abstract_cname), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) -// ====== OVERRIDE PURE TEMPLATE ====== - -// ====== OVERRIDE COROUTINE IMPL ====== -#define MRC_PYBIND11_OVERRIDE_CORO_IMPL(ret_type, cname, name, ...) \ - do \ - { \ - DCHECK_EQ(PyGILState_Check(), 0) << "Should not have the GIL when resuming a C++ coroutine"; \ - pybind11::gil_scoped_acquire gil; \ - pybind11::function override = pybind11::get_override(static_cast(this), name); \ - if (override) \ - { \ - auto o_coro = override(__VA_ARGS__); \ - auto asyncio_module = pybind11::module::import("asyncio"); \ - /* Return type must be a coroutine to allow calling asyncio.create_task() */ \ - if (!asyncio_module.attr("iscoroutine")(o_coro).cast()) \ - { \ - pybind11::pybind11_fail(MRC_CONCAT_STR("Return value from overriden async function " \ - << PYBIND11_STRINGIFY(cname) << "::" << name \ - << " did not return a coroutine. Returned: " \ - << pybind11::str(o_coro).cast())); \ - } \ - auto o_task = asyncio_module.attr("create_task")(o_coro); \ - mrc::pymrc::PyHolder o_result; \ - { \ - pybind11::gil_scoped_release nogil; \ - o_result = co_await mrc::pycoro::PyTaskToCppAwaitable(std::move(o_task)); \ - DCHECK_EQ(PyGILState_Check(), 0) << "Should not have the GIL after returning from co_await"; \ - } \ - if (pybind11::detail::cast_is_temporary_value_reference::value) \ - { \ - static pybind11::detail::override_caster_t caster; \ - co_return pybind11::detail::cast_ref(std::move(o_result), caster); \ - } \ - co_return pybind11::detail::cast_safe(std::move(o_result)); \ - } \ - } while (false) -// ====== OVERRIDE COROUTINE IMPL====== - -// ====== OVERRIDE COROUTINE ====== -#define MRC_PYBIND11_OVERRIDE_CORO_NAME(ret_type, cname, name, fn, ...) \ - do \ - { \ - MRC_PYBIND11_OVERRIDE_CORO_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \ - return cname::fn(__VA_ARGS__); \ - } while (false) - -#define MRC_PYBIND11_OVERRIDE_CORO(ret_type, cname, fn, ...) \ - MRC_PYBIND11_OVERRIDE_CORO_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) -// ====== OVERRIDE COROUTINE ====== - -// ====== OVERRIDE COROUTINE PURE====== -#define MRC_PYBIND11_OVERRIDE_CORO_PURE_NAME(ret_type, cname, name, fn, ...) \ - do \ - { \ - MRC_PYBIND11_OVERRIDE_CORO_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \ - MRC_PYBIND11_FAIL_ABSTRACT(PYBIND11_TYPE(cname), name); \ - } while (false) - -#define MRC_PYBIND11_OVERRIDE_CORO_PURE(ret_type, cname, fn, ...) \ - MRC_PYBIND11_OVERRIDE_CORO_PURE_NAME(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) -// ====== OVERRIDE COROUTINE PURE====== - -// ====== OVERRIDE COROUTINE PURE TEMPLATE====== -#define MRC_PYBIND11_OVERRIDE_CORO_PURE_TEMPLATE_NAME(ret_type, abstract_cname, cname, name, fn, ...) \ - do \ - { \ - MRC_PYBIND11_OVERRIDE_CORO_IMPL(PYBIND11_TYPE(ret_type), PYBIND11_TYPE(cname), name, __VA_ARGS__); \ - if constexpr (std::is_same_v) \ - { \ - MRC_PYBIND11_FAIL_ABSTRACT(PYBIND11_TYPE(abstract_cname), name); \ - } \ - else \ - { \ - co_return co_await cname::fn(__VA_ARGS__); \ - } \ - } while (false) - -#define MRC_PYBIND11_OVERRIDE_CORO_PURE_TEMPLATE(ret_type, abstract_cname, cname, fn, ...) \ - MRC_PYBIND11_OVERRIDE_CORO_PURE_TEMPLATE_NAME( \ - PYBIND11_TYPE(ret_type), PYBIND11_TYPE(abstract_cname), PYBIND11_TYPE(cname), #fn, fn, __VA_ARGS__) -// ====== OVERRIDE COROUTINE PURE TEMPLATE====== - -} // namespace mrc::pycoro - -// NOLINTNEXTLINE(modernize-concat-nested-namespaces) -namespace PYBIND11_NAMESPACE { -namespace detail { - -/** - * @brief Provides a type caster for converting a C++ coroutine to a python awaitable. Include this file in any pybind11 - * module to automatically convert the types. Allows for converting arguments and return values. - * - * @tparam ReturnT The return type of the coroutine - */ -template -struct type_caster> -{ - public: - /** - * This macro establishes the name 'inty' in - * function signatures and declares a local variable - * 'value' of type inty - */ - PYBIND11_TYPE_CASTER(mrc::coroutines::Task, _("typing.Awaitable[") + make_caster::name + _("]")); - - /** - * Conversion part 1 (Python->C++): convert a PyObject into a inty - * instance or return false upon failure. The second argument - * indicates whether implicit conversions should be applied. - */ - bool load(handle src, bool convert) - { - if (!src || src.is_none()) - { - return false; - } - - if (!PyCoro_CheckExact(src.ptr())) - { - return false; - } - - auto cpp_coro = [](mrc::pymrc::PyHolder py_task) -> mrc::coroutines::Task { - DCHECK_EQ(PyGILState_Check(), 0) << "Should not have the GIL when resuming a C++ coroutine"; - - // Always assume we are resuming without the GIL - pybind11::gil_scoped_acquire gil; - - auto asyncio_task = pybind11::module_::import("asyncio").attr("create_task")(py_task); - - mrc::pymrc::PyHolder py_result; - { - // Release the GIL before awaiting - pybind11::gil_scoped_release nogil; - - py_result = co_await mrc::pycoro::PyTaskToCppAwaitable(std::move(asyncio_task)); - } - - // Now cast back to the C++ type - if (pybind11::detail::cast_is_temporary_value_reference::value) - { - static pybind11::detail::override_caster_t caster; - co_return pybind11::detail::cast_ref(std::move(py_result), caster); - } - co_return pybind11::detail::cast_safe(std::move(py_result)); - }; - - value = cpp_coro(pybind11::reinterpret_borrow(std::move(src))); - - return true; - } - - /** - * Conversion part 2 (C++ -> Python): convert an inty instance into - * a Python object. The second and third arguments are used to - * indicate the return value policy and parent object (for - * ``return_value_policy::reference_internal``) and are generally - * ignored by implicit casters. - */ - static handle cast(mrc::coroutines::Task src, return_value_policy policy, handle parent) - { - // Wrap the object in a CppToPyAwaitable - std::shared_ptr awaitable = - std::make_shared(std::move(src)); - - // Convert the object to a python object - auto py_awaitable = pybind11::cast(std::move(awaitable)); - - return py_awaitable.release(); - } -}; - -} // namespace detail -} // namespace PYBIND11_NAMESPACE diff --git a/morpheus/_lib/pycoro/module.cpp b/morpheus/_lib/pycoro/module.cpp deleted file mode 100644 index 8757056316..0000000000 --- a/morpheus/_lib/pycoro/module.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "pycoro/pycoro.hpp" - -#include -#include -#include -#include -#include -#include // IWYU pragma: keep - -#include -#include -#include -#include -#include - -namespace mrc::pycoro { - -namespace py = pybind11; - -PYBIND11_MODULE(pycoro, _module) -{ - _module.doc() = R"pbdoc( - ----------------------- - .. currentmodule:: morpheus.llm - .. autosummary:: - :toctree: _generate - - )pbdoc"; - - py::class_>(_module, "CppToPyAwaitable") - .def(py::init<>()) - .def("__iter__", &CppToPyAwaitable::iter) - .def("__await__", &CppToPyAwaitable::await) - .def("__next__", &CppToPyAwaitable::next); - - py::class_>( - _module, "BoostFibersMainPyAwaitable") - .def(py::init<>()); - - _module.def("wrap_coroutine", [](coroutines::Task> fn) -> coroutines::Task { - DCHECK_EQ(PyGILState_Check(), 0) << "Should not have the GIL when resuming a C++ coroutine"; - - auto strings = co_await fn; - - co_return strings[0]; - }); - - // _module.attr("__version__") = - // MRC_CONCAT_STR(morpheus_VERSION_MAJOR << "." << morpheus_VERSION_MINOR << "." << morpheus_VERSION_PATCH); -} -} // namespace mrc::pycoro diff --git a/morpheus/_lib/pycoro/src/pycoro.cpp b/morpheus/_lib/pycoro/src/pycoro.cpp deleted file mode 100644 index 812fc0acce..0000000000 --- a/morpheus/_lib/pycoro/src/pycoro.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-FileCopyrightText: Copyright (c) 2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "pycoro/pycoro.hpp" - -namespace mrc::pycoro { - -namespace py = pybind11; - -StopIteration::~StopIteration() = default; - -} // namespace mrc::pycoro diff --git a/tests/llm/test_pycoro.py b/tests/llm/test_pycoro.py deleted file mode 100644 index f2c5ee796b..0000000000 --- a/tests/llm/test_pycoro.py +++ /dev/null @@ -1,66 +0,0 @@ -# SPDX-FileCopyrightText: Copyright (c) 2022-2023, NVIDIA CORPORATION & AFFILIATES. All rights reserved. -# SPDX-License-Identifier: Apache-2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import asyncio - -from morpheus._lib import pycoro # pylint: disable=morpheus-incorrect-lib-from-import - - -async def test_pycoro(): - - hit_inside = False - - async def inner(): - - nonlocal hit_inside - - result = await pycoro.wrap_coroutine(asyncio.sleep(1, result=['a', 'b', 'c'])) - - hit_inside = True - - return [result] - - returned_val = await pycoro.wrap_coroutine(inner()) - - assert returned_val == 'a' - assert hit_inside - - -async def test_pycoro_many(): - - expected_count = 1000 - hit_count = 0 - - start_time = asyncio.get_running_loop().time() - - async def inner(): - - nonlocal hit_count - - await asyncio.sleep(1) - - hit_count += 1 - - return ['a', 'b', 'c'] - - coros = [pycoro.wrap_coroutine(inner()) for _ in range(expected_count)] - - returned_vals = await asyncio.gather(*coros) - - end_time = asyncio.get_running_loop().time() - - assert returned_vals == ['a'] * expected_count - assert hit_count == expected_count - assert (end_time - start_time) < 1.5