From f55b93eef04e7c364a046930226a3090115383eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaim=20=28Jo=C3=ABl=20Lamotte=29?= <142265+Klaim@users.noreply.github.com> Date: Wed, 21 Jan 2026 19:26:35 +0100 Subject: [PATCH 01/19] dont use std::system to launch processes, it's cli api is system-dependant - fixup attempt by using boost.process instead --- test/CMakeLists.txt | 7 ++- test/test_debugger.cpp | 124 +++++++++++++++++++++++------------------ 2 files changed, 74 insertions(+), 57 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d5fafe2c..b80f574e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -43,7 +43,10 @@ if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) endif() find_package(Threads) -find_package(doctest) +find_package(doctest REQUIRED) + +cmake_policy(SET CMP0167 OLD) # use find boost from old cmake +find_package(Boost REQUIRED COMPONENTS process filesystem) include_directories(${GTEST_INCLUDE_DIRS} SYSTEM) @@ -70,7 +73,7 @@ set_target_properties(test_xeus_python PROPERTIES ) include_directories(${PYTHON_INCLUDE_DIRS}) -target_link_libraries(test_xeus_python ${PYTHON_LIBRARIES} xeus-zmq doctest::doctest ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(test_xeus_python ${PYTHON_LIBRARIES} xeus-zmq doctest::doctest Boost::headers Boost::filesystem Boost::process ${CMAKE_THREAD_LIBS_INIT}) target_include_directories(test_xeus_python PRIVATE ${XEUS_PYTHON_INCLUDE_DIR}) add_custom_target(xtest COMMAND test_xeus_python DEPENDS test_xeus_python) diff --git a/test/test_debugger.cpp b/test/test_debugger.cpp index 208c07af..ef81e44b 100644 --- a/test/test_debugger.cpp +++ b/test/test_debugger.cpp @@ -8,8 +8,10 @@ * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ + #include "doctest/doctest.h" + #include #include #include @@ -19,6 +21,7 @@ #include #include + #include "xeus/xsystem.hpp" #include "xeus_client.hpp" @@ -35,6 +38,11 @@ #include #endif +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + /*********************************** * Should be moved in a utils file * ***********************************/ @@ -361,7 +369,7 @@ nl::json make_exception_breakpoint_request(int seq) })}, {"breakMode", "always"} }; - nl::json options = nl::json::array({except_option, except_option}); + nl::json options = nl::json::array({ except_option, except_option }); nl::json req = { {"type", "request"}, {"seq", seq}, @@ -383,8 +391,8 @@ class debugger_client public: debugger_client(xeus::xcontext& context, - const std::string& connection_file, - const std::string& log_file); + const std::string& connection_file, + const std::string& log_file); bool test_init(); bool test_disconnect(); @@ -430,10 +438,10 @@ class debugger_client }; debugger_client::debugger_client(xeus::xcontext& context, - const std::string& connection_file, - const std::string& log_file) + const std::string& connection_file, + const std::string& log_file) : m_client(context, "debugger_client", - xeus::load_configuration(connection_file), log_file) + xeus::load_configuration(connection_file), log_file) { } @@ -471,7 +479,7 @@ bool debugger_client::print_code_variable(const std::string& expected, int& seq) ++seq; nl::json json1 = m_client.receive_on_control(); - if(json1["content"]["body"]["stackFrames"].empty()) + if (json1["content"]["body"]["stackFrames"].empty()) { m_client.send_on_control("debug_request", make_stacktrace_request(seq, 1)); ++seq; @@ -491,11 +499,11 @@ bool debugger_client::print_code_variable(const std::string& expected, int& seq) const auto& ar = json3["content"]["body"]["variables"]; bool var_found = false; std::string name, value; - for(auto it = ar.begin(); it != ar.end() && !var_found; ++it) + for (auto it = ar.begin(); it != ar.end() && !var_found; ++it) { auto d = *it; name = d["name"]; - if(name == "i") + if (name == "i") { var_found = true; value = d["value"]; @@ -745,7 +753,7 @@ bool debugger_client::test_inspect_variables() auto check_var = [&vars](const std::string& name, const std::string& value) { auto x = std::find_if(vars.begin(), vars.end(), [&name](const nl::json& var) { return var.is_object() && var.value("name", "") == name; - }); + }); if (x == vars.end()) { std::cout << "missing " << name << std::endl; @@ -753,7 +761,7 @@ bool debugger_client::test_inspect_variables() } nl::json var = *x; return var["value"] == value && var["variablesReference"] == 0; - }; + }; bool res = check_var("i", "4") && check_var("j", "8") && check_var("k", "5"); return res; @@ -858,7 +866,7 @@ bool debugger_client::test_variables() ++seq; nl::json json1 = m_client.receive_on_control(); - if(json1["content"]["body"]["stackFrames"].empty()) + if (json1["content"]["body"]["stackFrames"].empty()) { m_client.send_on_control("debug_request", make_stacktrace_request(seq, 1)); ++seq; @@ -909,7 +917,7 @@ bool debugger_client::test_copy_to_globals() m_client.send_on_control("debug_request", make_stacktrace_request(seq, 1)); ++seq; nl::json json1 = m_client.receive_on_control(); - if(json1["content"]["body"]["stackFrames"].empty()) + if (json1["content"]["body"]["stackFrames"].empty()) { m_client.send_on_control("debug_request", make_stacktrace_request(seq, 1)); ++seq; @@ -935,7 +943,7 @@ bool debugger_client::test_copy_to_globals() ++seq; nl::json json3 = m_client.receive_on_control(); nl::json local_var = {}; - for (auto &var: json3["content"]["body"]["variables"]){ + for (auto& var : json3["content"]["body"]["variables"]) { if (var["evaluateName"] == local_var_name) { local_var = var; } @@ -952,7 +960,7 @@ bool debugger_client::test_copy_to_globals() ++seq; nl::json json4 = m_client.receive_on_control(); nl::json global_var = {}; - for (auto &var: json4["content"]["body"]["variables"]){ + for (auto& var : json4["content"]["body"]["variables"]) { if (var["evaluateName"] == global_var_name) { global_var = var; } @@ -1034,7 +1042,7 @@ std::string debugger_client::get_external_path() void debugger_client::dump_external_file() { static bool already_dumped = false; - if(!already_dumped) + if (!already_dumped) { std::ofstream out(get_external_path()); out << make_external_code() << std::endl; @@ -1139,7 +1147,7 @@ void dump_connection_file() "kernel_name": "xcpp" } )"; - if(!dumped) + if (!dumped) { std::ofstream out(KERNEL_JSON); out << connection_file; @@ -1147,19 +1155,25 @@ void dump_connection_file() } } -void start_kernel() +struct KernelProcess { - dump_connection_file(); - std::string cmd = "xpython -f " + KERNEL_JSON + "&"; - int ret2 = std::system(cmd.c_str()); - std::this_thread::sleep_for(2s); -} + KernelProcess() + { + std::this_thread::sleep_for(2s); + } + +private: + + bool _ = [] { dump_connection_file(); return true; }(); + boost::asio::io_context ctx; + boost::process::process process{ ctx, boost::process::environment::find_executable("xpython"), { "-f" , KERNEL_JSON } }; +}; TEST_SUITE("debugger") { TEST_CASE("init") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1176,7 +1190,7 @@ TEST_SUITE("debugger") TEST_CASE("disconnect") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1192,7 +1206,7 @@ TEST_SUITE("debugger") TEST_CASE("attach") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1209,7 +1223,7 @@ TEST_SUITE("debugger") TEST_CASE("multisession") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1228,7 +1242,7 @@ TEST_SUITE("debugger") TEST_CASE("set_external_breakpoints") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1247,7 +1261,7 @@ TEST_SUITE("debugger") /* TEST_CASE("external_next_continue") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1264,7 +1278,7 @@ TEST_SUITE("debugger") */ TEST_CASE("set_breakpoints") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1281,7 +1295,7 @@ TEST_SUITE("debugger") TEST_CASE("set_exception_breakpoints") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1298,7 +1312,7 @@ TEST_SUITE("debugger") TEST_CASE("source") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1317,7 +1331,7 @@ TEST_SUITE("debugger") /* TEST_CASE("next_continue") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1337,7 +1351,7 @@ TEST_SUITE("debugger") /* TEST_CASE("stepin") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1355,7 +1369,7 @@ TEST_SUITE("debugger") TEST_CASE("stack_trace") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1372,7 +1386,7 @@ TEST_SUITE("debugger") TEST_CASE("debug_info") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1389,7 +1403,7 @@ TEST_SUITE("debugger") TEST_CASE("inspect_variables") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1404,28 +1418,28 @@ TEST_SUITE("debugger") } } -// TODO: Get test_rich_inspect_variables to work -/* - TEST_CASE("rich_inspect_variables") - { - start_kernel(); - timer t; - auto context_ptr = xeus::make_zmq_context(); + // TODO: Get test_rich_inspect_variables to work + /* + TEST_CASE("rich_inspect_variables") { - debugger_client deb(*context_ptr, KERNEL_JSON, "debugger_rich_inspect_variables.log"); - deb.start(); - bool res = deb.test_rich_inspect_variables(); - deb.shutdown(); - std::this_thread::sleep_for(2s); - CHECK(res); - t.notify_done(); + KernelProcess xpython_process; + timer t; + auto context_ptr = xeus::make_zmq_context(); + { + debugger_client deb(*context_ptr, KERNEL_JSON, "debugger_rich_inspect_variables.log"); + deb.start(); + bool res = deb.test_rich_inspect_variables(); + deb.shutdown(); + std::this_thread::sleep_for(2s); + CHECK(res); + t.notify_done(); + } } - } -*/ + */ TEST_CASE("variables") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { @@ -1442,7 +1456,7 @@ TEST_SUITE("debugger") TEST_CASE("copy_to_globals") { - start_kernel(); + KernelProcess xpython_process; timer t; auto context_ptr = xeus::make_zmq_context(); { From 25b0d7abb7837f4636e5f6e1440e7f52fb555c70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaim=20=28Jo=C3=ABl=20Lamotte=29?= <142265+Klaim@users.noreply.github.com> Date: Thu, 22 Jan 2026 05:19:02 +0100 Subject: [PATCH 02/19] ignore root build dirs --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 041239f7..97eb65ac 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ docs/build/ # Build directory build/ +/build-*/ # generated kernel specs /share/jupyter/kernels/xpython/kernel.json From f89a2e491290c1f528bef53bed0280984ddbc165 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaim=20=28Jo=C3=ABl=20Lamotte=29?= <142265+Klaim@users.noreply.github.com> Date: Thu, 22 Jan 2026 09:45:10 +0100 Subject: [PATCH 03/19] added missing boost dependency --- environment-dev.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/environment-dev.yml b/environment-dev.yml index be0e6932..905297f2 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -25,3 +25,4 @@ dependencies: - jupyter_kernel_test<0.8 - doctest - pluggy=1.3 + - libboost From d84a025330ee9ed6636135479a48b5474484af66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaim=20=28Jo=C3=ABl=20Lamotte=29?= <142265+Klaim@users.noreply.github.com> Date: Thu, 22 Jan 2026 10:04:11 +0100 Subject: [PATCH 04/19] added missing boost packages dependencies --- environment-dev.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/environment-dev.yml b/environment-dev.yml index 905297f2..2166667d 100644 --- a/environment-dev.yml +++ b/environment-dev.yml @@ -26,3 +26,6 @@ dependencies: - doctest - pluggy=1.3 - libboost + - libboost-devel + - libboost-headers + From 77ed32084745a635c8d550359414f1f987528c80 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Fri, 13 Feb 2026 11:57:29 +0100 Subject: [PATCH 05/19] trigger ci From 9d1dac85fea179c2cec273a3fca1a287bb4f2000 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Fri, 13 Feb 2026 12:02:01 +0100 Subject: [PATCH 06/19] trigger ci --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9870f650..c79417e8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, ubuntu-24.04, macos-13, macos-14] + os: [ubuntu-22.04, ubuntu-24.04, macos-14] build_type: [static_build, shared_build] steps: From 3cbef422238a183136a8c9e265d5538be8df8abe Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Fri, 13 Feb 2026 13:00:58 +0100 Subject: [PATCH 07/19] sanity checkv2 --- .github/workflows/main.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c79417e8..971f2a69 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -139,7 +139,6 @@ jobs: - name: Test xeus-python C++ shell: cmd /C call {0} run: | - micromamba activate xeus-python test_xeus_python timeout-minutes: 4 working-directory: build\test From 3ee6b105222385078207a14b491f450a7f69ebf0 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Sat, 14 Feb 2026 14:33:09 +0100 Subject: [PATCH 08/19] sanity checkv2 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 971f2a69..4b919b30 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -139,7 +139,7 @@ jobs: - name: Test xeus-python C++ shell: cmd /C call {0} run: | - test_xeus_python + for /L %i in (1,1,20) do test_xeus_python timeout-minutes: 4 working-directory: build\test From 7fd1c88f7b3ea964e69ddf468926f39b4f4e4f4e Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Sat, 14 Feb 2026 14:41:46 +0100 Subject: [PATCH 09/19] sanity checkv2 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4b919b30..6078639e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -139,7 +139,7 @@ jobs: - name: Test xeus-python C++ shell: cmd /C call {0} run: | - for /L %i in (1,1,20) do test_xeus_python + for /L %%i in (1,1,20) do test_xeus_python timeout-minutes: 4 working-directory: build\test From cd37b1b14b24f247a955d1e448aac4dfa5f98e2f Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Sat, 14 Feb 2026 14:42:43 +0100 Subject: [PATCH 10/19] sanity checkv2 --- .github/workflows/main.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6078639e..4ec0df40 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -136,10 +136,12 @@ jobs: shell: cmd /C call {0} run: pytest . -vvv - - name: Test xeus-python C++ + - name: Test xeus-python C++ (20 iterations) shell: cmd /C call {0} run: | - for /L %%i in (1,1,20) do test_xeus_python - timeout-minutes: 4 - working-directory: build\test - + for /L %%i in (1,1,20) do ( + echo Running iteration %%i + test_xeus_python || exit /b 1 + ) + timeout-minutes: 20 + working-directory: build\test \ No newline at end of file From a4c43bdf2c6151dcf5396905a2b014e0aed880c1 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Wed, 25 Feb 2026 11:34:02 +0100 Subject: [PATCH 11/19] add couts --- src/xinterpreter.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index ff210b2d..2bf60e1f 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -37,6 +37,9 @@ #include "xinternal_utils.hpp" #include "xstream.hpp" +// TODO REMOVE AFTER DEBUGGING +#include + namespace py = pybind11; namespace nl = nlohmann; using namespace pybind11::literals; @@ -323,30 +326,41 @@ namespace xpyt nl::json interpreter::internal_request_impl(const nl::json& content) { + std::cout << "Received internal request with content: " << content.dump(4) << std::endl; py::gil_scoped_acquire acquire; std::string code = content.value("code", ""); + std::cout<<"reset traceback"< Date: Wed, 25 Feb 2026 11:35:16 +0100 Subject: [PATCH 12/19] more couts / more try catch --- src/xinterpreter.cpp | 55 +++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index 2bf60e1f..4cd67951 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -343,25 +343,52 @@ namespace xpyt } catch (py::error_already_set& e) { - std::cout<<"an error occurred during code execution: "<()); + } + catch(std::exception& e) + { + std::cout<<"a standard exception occurred during error handling: "<()); + } + catch (...) + { + std::cout<<"an unknown error occurred during error handling"<()); + } + } + catch(std::exception& e) + { + std::cout<<"a standard exception occurred during code execution: "<()); + } + catch (...) + { + std::cout<<"an unknown error occurred during code execution"<()); } } From 951f6c864218a0129adbde12535f38d4ea5d00bd Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Wed, 25 Feb 2026 12:05:35 +0100 Subject: [PATCH 13/19] more couts / more try catch --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index cf05af80..68790812 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -138,12 +138,12 @@ jobs: shell: cmd /C call {0} run: pytest . -vvv - - name: Test xeus-python C++ (20 iterations) + - name: Test xeus-python C++ (40 iterations) shell: cmd /C call {0} run: | - for /L %%i in (1,1,20) do ( + for /L %%i in (1,1,40) do ( echo Running iteration %%i test_xeus_python || exit /b 1 ) - timeout-minutes: 20 + timeout-minutes: 60 working-directory: build\test \ No newline at end of file From 38be29675ceb66395103e73ab5a91755fa26589c Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Wed, 25 Feb 2026 12:59:57 +0100 Subject: [PATCH 14/19] more couts / more try catch From b011aeee7aed56ba7f898e6c02ebc60233dd3c5f Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Wed, 25 Feb 2026 13:34:29 +0100 Subject: [PATCH 15/19] more couts / more try catch --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 68790812..99f781c2 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -138,10 +138,10 @@ jobs: shell: cmd /C call {0} run: pytest . -vvv - - name: Test xeus-python C++ (40 iterations) + - name: Test xeus-python C++ (100 iterations) shell: cmd /C call {0} run: | - for /L %%i in (1,1,40) do ( + for /L %%i in (1,1,100) do ( echo Running iteration %%i test_xeus_python || exit /b 1 ) From 1ac2a15f0b4abab43cd85df6eb2fd54e9fca4fb6 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Wed, 25 Feb 2026 15:41:15 +0100 Subject: [PATCH 16/19] more couts / more try catch --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 99f781c2..ce1084fd 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -141,7 +141,7 @@ jobs: - name: Test xeus-python C++ (100 iterations) shell: cmd /C call {0} run: | - for /L %%i in (1,1,100) do ( + for /L %%i in (1,1,50) do ( echo Running iteration %%i test_xeus_python || exit /b 1 ) From f0fecec3021875d6c87a61e23980691c79adbf52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaim=20=28Jo=C3=ABl=20Lamotte=29?= <142265+Klaim@users.noreply.github.com> Date: Mon, 2 Mar 2026 14:18:02 +0100 Subject: [PATCH 17/19] debug duct tape and more info --- include/xeus-python/xdebugger.hpp | 13 ++++++ src/main.cpp | 4 ++ src/xdebugger.cpp | 3 ++ src/xinterpreter.cpp | 30 ++++++++++++++ src/xpaths.cpp | 13 ++++++ test/test_debugger.cpp | 69 +++++++++++++++++++++++++++---- 6 files changed, 125 insertions(+), 7 deletions(-) diff --git a/include/xeus-python/xdebugger.hpp b/include/xeus-python/xdebugger.hpp index a7268818..a349cb88 100644 --- a/include/xeus-python/xdebugger.hpp +++ b/include/xeus-python/xdebugger.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "nlohmann/json.hpp" #include "pybind11/pybind11.h" @@ -69,7 +70,19 @@ namespace xpyt std::string m_debugpy_host; std::string m_debugpy_port; nl::json m_debugger_config; + + struct after { ~after(){ std::cout << "\n### " << std::this_thread::get_id() << " DESTROYING PYDEBUGGER - DONE" << std::endl; } } after_pydebugger; py::object m_pydebugger; + struct before { + py::object& ref_pydebugger; + __declspec(noinline) ~before(){ + std::cout << "\n### " << std::this_thread::get_id() << " DESTROYING PYDEBUGGER ..." << std::endl; + py::gil_scoped_acquire acquire; + auto pydebugger = std::move(ref_pydebugger); + std::cout << "\n### " << std::this_thread::get_id() << " DESTROYING PYDEBUGGER - local destroy ..." << std::endl; + } + } before_pydebugger{ m_pydebugger }; + xeus::xthread m_client_runner; bool m_copy_to_globals_available; }; diff --git a/src/main.cpp b/src/main.cpp index 8862a319..6cc41ff4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -80,6 +80,10 @@ int main(int argc, char* argv[]) // Setting Program Name static const std::string executable(xpyt::get_python_path()); static const std::wstring wexecutable(executable.cbegin(), executable.cend()); + if (!std::filesystem::exists(wexecutable)) + { + throw std::runtime_error(std::string("cannot find python executable, tried ") + executable); + } config.program_name = const_cast(wexecutable.c_str()); // Setting Python Home diff --git a/src/xdebugger.cpp b/src/xdebugger.cpp index 700e4702..934d7d77 100644 --- a/src/xdebugger.cpp +++ b/src/xdebugger.cpp @@ -255,6 +255,7 @@ namespace xpyt if (std::getenv("XEUS_LOG") != nullptr) { std::ofstream out("xeus.log", std::ios_base::app); + //auto& out = std::cout; out << "===== DEBUGGER CONFIG =====" << std::endl; out << m_debugger_config.dump() << std::endl; } @@ -283,9 +284,11 @@ namespace xpyt } else { + std::cout << "\n### " << std::this_thread::get_id() << " CREATING PYDEBUGGER ..." << std::endl; py::gil_scoped_acquire acquire; py::module xeus_python_shell = py::module::import("xeus_python_shell.debugger"); m_pydebugger = xeus_python_shell.attr("XDebugger")(); + std::cout << "\n### " << std::this_thread::get_id() << " CREATING PYDEBUGGER - DONE" << std::endl; // Get debugpy version std::string expression = "debugpy.__version__"; diff --git a/src/xinterpreter.cpp b/src/xinterpreter.cpp index ef3abc4e..d803bbef 100644 --- a/src/xinterpreter.cpp +++ b/src/xinterpreter.cpp @@ -401,6 +401,36 @@ namespace xpyt std::cout<<"an unknown error occurred during code execution"<()); } + + std::cout << "\n--> processing error ... " << std::endl; + py::list pyerror = [&]() -> py::list { + try { + auto last_error = m_ipython_shell.attr("last_error"); + std::cout << "\n--> converting last_error to list ... " << std::endl; + return py::list(last_error); + } + catch (py::error_already_set& e) + { + std::cout << "\n--> processing error: failed acquiring `last_error` " << std::endl; + return py::list{}; + } + }(); + + if (pyerror.empty()) + { + return xeus::create_error_reply("SNAFU", "python SNAFU"); + } + + std::cout << "\n--> A " << std::endl; + xerror error = extract_error(pyerror); + std::cout << "\n--> B " << std::endl; + publish_execution_error(error.m_ename, error.m_evalue, error.m_traceback); + std::cout << "\n--> C " << std::endl; + error.m_traceback.resize(1); + error.m_traceback[0] = code; + std::cout << "\n--> D " << std::endl; + return xeus::create_error_reply(error.m_ename, error.m_evalue, error.m_traceback); + } void interpreter::set_request_context(xeus::xrequest_context context) diff --git a/src/xpaths.cpp b/src/xpaths.cpp index 9ccc468d..3ca84226 100644 --- a/src/xpaths.cpp +++ b/src/xpaths.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "pybind11/pybind11.h" @@ -44,7 +45,12 @@ namespace xpyt #elif defined(XEUS_PYTHONHOME_ABSPATH) static const std::string pythonhome = XPYT_STRINGIFY(XEUS_PYTHONHOME_ABSPATH); #else +# ifdef _WIN32 + using namespace std::filesystem; + static const std::string pythonhome = canonical(xeus::prefix_path()).parent_path().string(); // wont work with unicode paths +# else static const std::string pythonhome = xeus::prefix_path(); +# endif #endif return pythonhome; } @@ -52,6 +58,13 @@ namespace xpyt std::string get_python_path() { + const char* python_exe_environment = std::getenv("PYTHON_EXECUTABLE"); + if (python_exe_environment != nullptr && std::strlen(python_exe_environment) != 0) + { + static const std::string python_exe_path = python_exe_environment; + return python_exe_path; + } + std::string python_prefix = get_python_prefix(); #ifdef _WIN32 if (python_prefix.back() != '\\') diff --git a/test/test_debugger.cpp b/test/test_debugger.cpp index ef81e44b..d612458b 100644 --- a/test/test_debugger.cpp +++ b/test/test_debugger.cpp @@ -1073,6 +1073,8 @@ class timer { public: + struct timeout : std::runtime_error { using std::runtime_error::runtime_error; }; + timer(); ~timer(); @@ -1116,8 +1118,10 @@ void timer::run_timer() std::unique_lock lk(m_mcv); if (!m_cv.wait_for(lk, std::chrono::seconds(20), [this]() { return m_done; })) { - std::clog << "Unit test time out !!" << std::endl; - std::terminate(); + constexpr auto message = "Unit test time out !!"; + std::clog << message << std::endl; + //std::terminate(); + throw timeout{ message }; // same as calling terminate if unhandled, but some impl will also display the error in the console } } @@ -1157,18 +1161,69 @@ void dump_connection_file() struct KernelProcess { + KernelProcess() { - std::this_thread::sleep_for(2s); + running.emplace_back(m_impl); + std::cout << "=> xpython launched" << std::endl; + std::this_thread::sleep_for(4s); } -private: + ~KernelProcess() + { + std::cout << "=> xpython - destructor end" << std::endl; + } - bool _ = [] { dump_connection_file(); return true; }(); - boost::asio::io_context ctx; - boost::process::process process{ ctx, boost::process::environment::find_executable("xpython"), { "-f" , KERNEL_JSON } }; + private: + struct Impl + { + bool _ = [] { dump_connection_file(); return true; }(); + boost::asio::io_context ctx; + boost::filesystem::path xpython_path = boost::process::environment::find_executable("xpython"); + boost::process::process process{ ctx, xpython_path, { "-f" , KERNEL_JSON } }; + + struct on_destruction { + ~on_destruction() + { + std::cout << "=> xpython - destructor begin" << std::endl; + } + }; + }; + + std::shared_ptr m_impl = std::make_shared(); + + struct on_program_exit + { + ~on_program_exit() + { + std::cout << "=> test program exiting (after `main()`): explicitly terminate remaining sub-processes ..." << std::endl; + for (auto& maybe_process : running) + { + if (auto process_impl = maybe_process.lock()) + { + std::cout << "=> request exit politely : " << process_impl->xpython_path << "(" << process_impl->process.id() << ") ..." << std::endl; + process_impl->process.request_exit(); + //process_impl->process.wait(); + std::this_thread::sleep_for(std::chrono::seconds(2)); + if (process_impl->process.running()) + { + std::cout << "=> still running, force terminate : " << process_impl->xpython_path << "(" << process_impl->process.id() << ") ..." << std::endl; + process_impl->process.terminate(); + process_impl->process.wait(); + } + std::cout << "=> terminate " << process_impl->xpython_path << "(" << process_impl->process.id() << ") - DONE" << std::endl; + } + } + std::cout << "=> test program exiting : explicitly terminate remaining sub-processes - DONE" << std::endl; + } + }; + static std::vector> running; + static on_program_exit run_on_program_exit; }; +std::vector> KernelProcess::running; +KernelProcess::on_program_exit KernelProcess::run_on_program_exit; + TEST_SUITE("debugger") { TEST_CASE("init") From ff6ab0205041e6dd0ea772c83cebb7414d47b253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaim=20=28Jo=C3=ABl=20Lamotte=29?= <142265+Klaim@users.noreply.github.com> Date: Mon, 2 Mar 2026 15:14:49 +0100 Subject: [PATCH 18/19] removed msvc-specific instruction --- include/xeus-python/xdebugger.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/xeus-python/xdebugger.hpp b/include/xeus-python/xdebugger.hpp index a349cb88..58a1e948 100644 --- a/include/xeus-python/xdebugger.hpp +++ b/include/xeus-python/xdebugger.hpp @@ -75,7 +75,7 @@ namespace xpyt py::object m_pydebugger; struct before { py::object& ref_pydebugger; - __declspec(noinline) ~before(){ + ~before(){ std::cout << "\n### " << std::this_thread::get_id() << " DESTROYING PYDEBUGGER ..." << std::endl; py::gil_scoped_acquire acquire; auto pydebugger = std::move(ref_pydebugger); From 93273462f15f98fb1a4502e96b7ef23271799376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Klaim=20=28Jo=C3=ABl=20Lamotte=29?= <142265+Klaim@users.noreply.github.com> Date: Mon, 2 Mar 2026 16:37:33 +0100 Subject: [PATCH 19/19] tests wait for xpython's ready message instead of sleep --- test/test_debugger.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/test_debugger.cpp b/test/test_debugger.cpp index d612458b..a051a9bc 100644 --- a/test/test_debugger.cpp +++ b/test/test_debugger.cpp @@ -41,6 +41,7 @@ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif +#include #include /*********************************** @@ -1166,7 +1167,14 @@ struct KernelProcess { running.emplace_back(m_impl); std::cout << "=> xpython launched" << std::endl; - std::this_thread::sleep_for(4s); + + // wait for xpython to be ready before continuing + constexpr std::string_view ready_message = "Run with XEUS"; + std::string err_output; + boost::asio::read_until(m_impl->err_pipe, boost::asio::dynamic_buffer(err_output), ready_message); + + std::cout << "=> xpython is ready" << std::endl; + } ~KernelProcess() @@ -1179,8 +1187,9 @@ struct KernelProcess { bool _ = [] { dump_connection_file(); return true; }(); boost::asio::io_context ctx; + boost::asio::readable_pipe err_pipe{ ctx }; boost::filesystem::path xpython_path = boost::process::environment::find_executable("xpython"); - boost::process::process process{ ctx, xpython_path, { "-f" , KERNEL_JSON } }; + boost::process::process process{ ctx, xpython_path, { "-f" , KERNEL_JSON }, boost::process::process_stdio{{}, {}, err_pipe} }; struct on_destruction { ~on_destruction()