Skip to content

Commit

Permalink
Merge pull request #446 from JohanMabille/rich_inspect
Browse files Browse the repository at this point in the history
Implemented rich inspect variables request
  • Loading branch information
JohanMabille authored May 31, 2021
2 parents 07c797f + 9269b22 commit 829e374
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 0 deletions.
3 changes: 3 additions & 0 deletions include/xeus-python/xdebugger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ namespace xpyt
{
public:

using base_type = xeus::xdebugger_base;

debugger(zmq::context_t& context,
const xeus::xconfiguration& config,
const std::string& user_name,
Expand All @@ -40,6 +42,7 @@ namespace xpyt
private:

nl::json inspect_variables_request(const nl::json& message);
nl::json rich_inspect_variables_request(const nl::json& message);
nl::json attach_request(const nl::json& message);
nl::json configuration_done_request(const nl::json& message);

Expand Down
49 changes: 49 additions & 0 deletions src/xdebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "xeus/xsystem.hpp"

#include "xeus-python/xdebugger.hpp"
#include "xeus-python/xutils.hpp"
#include "xdebugpy_client.hpp"
#include "xinternal_utils.hpp"

Expand Down Expand Up @@ -60,6 +61,7 @@ namespace xpyt
{
m_debugpy_port = xeus::find_free_port(100, 5678, 5900);
register_request_handler("inspectVariables", std::bind(&debugger::inspect_variables_request, this, _1), false);
register_request_handler("richInspectVariables", std::bind(&debugger::rich_inspect_variables_request, this, _1), false);
register_request_handler("attach", std::bind(&debugger::attach_request, this, _1), true);
register_request_handler("configurationDone", std::bind(&debugger::configuration_done_request, this, _1), true);
}
Expand Down Expand Up @@ -155,6 +157,53 @@ namespace xpyt
return reply;
}

nl::json debugger::rich_inspect_variables_request(const nl::json& message)
{
nl::json reply = {
{"type", "response"},
{"request_seq", message["seq"]},
{"success", false},
{"command", message["command"]}
};

if (base_type::get_stopped_threads().empty())
{
// The code did not hit a breakpoint, we use the interpreter
// to get the rich reprensentation of the variable
std::string var_name = message["arguments"]["variableName"].get<std::string>();
std::string var_repr_data = var_name + "_repr_data";
std::string var_repr_metadata = var_name + "_repr_metada";
py::gil_scoped_acquire acquire;
std::string code = "from IPython import get_ipython;";
code += var_repr_data + ',' + var_repr_metadata + "= get_ipython().display_formatter.format(" + var_name + ")";
exec(py::str(code));
py::object variables = py::globals();
py::object repr_data = variables[py::str(var_repr_data)];
py::object repr_metadata = variables[py::str(var_repr_metadata)];
nl::json body = {
{"data", {}},
{"metadata", {}}
};
for (const py::handle& key : repr_data)
{
std::string data_key = py::str(key);
body["data"][data_key] = repr_data[key];
if (repr_metadata.contains(key))
{
body["metadata"][data_key] = repr_metadata[key];
}
}
reply["body"] = body;
reply["success"] = true;
}
else
{
// The code has stopped on a breakpoint, we use the evalute request
// to get the rich representation of the variable
}
return reply;
}

nl::json debugger::attach_request(const nl::json& message)
{
nl::json new_message = message;
Expand Down
67 changes: 67 additions & 0 deletions test/test_debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,20 @@ nl::json make_inspect_variables_request(int seq)
return req;
}

nl::json make_rich_inspect_variables_request(int seq, const std::string& var_name)
{
nl::json req = {
{"type", "request"},
{"seq", seq},
{"command", "richInspectVariables"},
{"arguments", {
{"variableName", var_name},
{"variableReference", 0}
}}
};
return req;
}

/*******************
* debugger_client *
*******************/
Expand All @@ -338,6 +352,7 @@ class debugger_client
bool test_stack_trace();
bool test_debug_info();
bool test_inspect_variables();
bool test_rich_inspect_variables();
bool test_variables();
void shutdown();

Expand Down Expand Up @@ -677,6 +692,43 @@ bool debugger_client::test_inspect_variables()
return res;
}

std::string rich_inspect_class_def = R"RICH(
class Person:
def __init__(self, name="John Doe", address="Paris", picture=""):
self.name = name
self.address = address
self.picture = picture
def _repr_mimebundle_(self, include=None, exclude=None):
return {
"text/html": """<img src="{}">
<div><i class='fa-user fa'></i>: {}</div>
<div><i class='fa-map fa'></i>: {}</div>""".format(self.picture, self.name, self.address)
}
)RICH";

std::string rich_html = R"RICH(<img src="">
<div><i class='fa-user fa'></i>: James Smith</div>
<div><i class='fa-map fa'></i>: Boston</div>)RICH";

bool debugger_client::test_rich_inspect_variables()
{
m_client.send_on_shell("execute_request", make_execute_request(rich_inspect_class_def));
m_client.receive_on_shell();

std::string code = "james = Person(\"James Smith\", \"Boston\")";
m_client.send_on_shell("execute_request", make_execute_request(code));
m_client.receive_on_shell();

m_client.send_on_control("debug_request", make_rich_inspect_variables_request(0, "james"));
nl::json rep = m_client.receive_on_control();
nl::json data = rep["content"]["body"]["data"];
std::string html = data["text/html"].get<std::string>();
std::string plain = data["text/plain"].get<std::string>();
bool res = html == rich_html && !plain.empty();
return res;
}

bool debugger_client::test_variables()
{
std::string code = "i=4\nj=i+4\nk=j-3\ni=k+2\n";
Expand Down Expand Up @@ -1069,6 +1121,21 @@ TEST(debugger, inspect_variables)
}
}

TEST(debugger, rich_inspect_variables)
{
start_kernel();
start_timer();
zmq::context_t context;
{
debugger_client deb(context, KERNEL_JSON, "debugger_debug_info.log");
bool res = deb.test_rich_inspect_variables();
deb.shutdown();
std::this_thread::sleep_for(2s);
EXPECT_TRUE(res);
notify_done();
}
}

TEST(debugger, variables)
{
start_kernel();
Expand Down

0 comments on commit 829e374

Please sign in to comment.