-
Notifications
You must be signed in to change notification settings - Fork 79
Custom displayhook #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| /*************************************************************************** | ||
| * Copyright (c) 2018, Martin Renou, Johan Mabille, Sylvain Corlay and * | ||
| * Wolf Vollprecht * | ||
| * * | ||
| * Distributed under the terms of the BSD 3-Clause License. * | ||
| * * | ||
| * The full license is in the file LICENSE, distributed with this software. * | ||
| ****************************************************************************/ | ||
|
|
||
| #include "pybind11/pybind11.h" | ||
| #include "pybind11/embed.h" | ||
|
|
||
| #include "xpython_display.hpp" | ||
|
|
||
| namespace py = pybind11; | ||
|
|
||
| namespace xpyt | ||
| { | ||
| xdisplayhook::xdisplayhook() : m_execution_count(0) | ||
| { | ||
| } | ||
|
|
||
| xdisplayhook::~xdisplayhook() | ||
| { | ||
| } | ||
|
|
||
| void xdisplayhook::set_execution_count(int execution_count) | ||
| { | ||
| m_execution_count = execution_count; | ||
| } | ||
|
|
||
| void xdisplayhook::add_hook(hook_function_type hook) | ||
| { | ||
| m_hooks.push_back(hook); | ||
| } | ||
|
|
||
| void xdisplayhook::operator()(py::object obj) | ||
| { | ||
| for (auto it = m_hooks.begin(); it != m_hooks.end(); ++it) | ||
| { | ||
| it->operator()(m_execution_count, obj); | ||
| } | ||
| } | ||
|
|
||
| PYBIND11_EMBEDDED_MODULE(xeus_python_display, m) { | ||
| py::class_<xdisplayhook>(m, "XPythonDisplay") | ||
| .def(py::init<>()) | ||
| .def("set_execution_count", &xdisplayhook::set_execution_count) | ||
| .def("add_hook", &xdisplayhook::add_hook) | ||
| .def("__call__", &xdisplayhook::operator()); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /*************************************************************************** | ||
| * Copyright (c) 2018, Martin Renou, Johan Mabille, Sylvain Corlay and * | ||
| * Wolf Vollprecht * | ||
| * * | ||
| * Distributed under the terms of the BSD 3-Clause License. * | ||
| * * | ||
| * The full license is in the file LICENSE, distributed with this software. * | ||
| ****************************************************************************/ | ||
|
|
||
| #ifndef XPYT_PYTHON_DISPLAY_HPP | ||
| #define XPYT_PYTHON_DISPLAY_HPP | ||
|
|
||
| #include <functional> | ||
|
|
||
| #include "pybind11/pybind11.h" | ||
| #include "pybind11/functional.h" | ||
|
|
||
| namespace py = pybind11; | ||
|
|
||
| namespace xpyt | ||
| { | ||
| class xdisplayhook | ||
| { | ||
|
|
||
| public: | ||
|
|
||
| using hook_function_type = std::function<void(int, py::object)>; | ||
| using hooks_type = std::vector<hook_function_type>; | ||
|
|
||
| xdisplayhook(); | ||
| virtual ~xdisplayhook(); | ||
|
|
||
| void set_execution_count(int execution_count); | ||
| void add_hook(hook_function_type hook); | ||
| void operator()(py::object obj); | ||
|
|
||
| private: | ||
|
|
||
| int m_execution_count; | ||
| hooks_type m_hooks; | ||
| }; | ||
| } | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,7 @@ namespace xpyt | |
| py::initialize_interpreter(); | ||
|
|
||
| redirect_output(); | ||
| redirect_display(); | ||
| } | ||
|
|
||
| xpython_interpreter::~xpython_interpreter() {} | ||
|
|
@@ -49,11 +50,44 @@ namespace xpyt | |
|
|
||
| try | ||
| { | ||
| py::exec(code); | ||
| // Import AST ans builtins modules | ||
| py::module ast = py::module::import("ast"); | ||
| py::module builtins = py::module::import("builtins"); | ||
|
|
||
| // Parse code to AST | ||
| py::object code_ast = ast.attr("parse")(code, "<string>", "exec"); | ||
| py::list expressions = code_ast.attr("body"); | ||
|
|
||
| // If the last statement is an expression, we compile it seperately | ||
| // in an interactive mode (This will trigger the display hook) | ||
| py::object last_stmt = expressions[py::len(expressions) - 1]; | ||
| if (py::isinstance(last_stmt, ast.attr("Expr"))) | ||
| { | ||
| code_ast.attr("body").attr("pop")(); | ||
|
|
||
| py::list interactive_nodes; | ||
| interactive_nodes.append(last_stmt); | ||
|
|
||
| py::object interactive_ast = ast.attr("Interactive")(interactive_nodes); | ||
|
|
||
| py::object compiled_code = builtins.attr("compile")(code_ast, "<ast>", "exec"); | ||
| py::object compiled_interactive_code = builtins.attr("compile")(interactive_ast, "<ast>", "single"); | ||
|
|
||
| m_displayhook.attr("set_execution_count")(execution_counter); | ||
|
|
||
| builtins.attr("exec")(compiled_code, py::globals()); | ||
| builtins.attr("exec")(compiled_interactive_code, py::globals()); | ||
| } | ||
| else | ||
| { | ||
| py::object compiled_code = builtins.attr("compile")(code_ast, "<ast>", "exec"); | ||
| builtins.attr("exec")(compiled_code, py::globals()); | ||
| } | ||
|
|
||
| kernel_res["status"] = "ok"; | ||
| kernel_res["payload"] = xeus::xjson::array(); | ||
| kernel_res["user_expressions"] = xeus::xjson::object(); | ||
|
|
||
| } catch(const std::exception& e) { | ||
|
|
||
| std::string ename = "Execution error"; | ||
|
|
@@ -167,4 +201,25 @@ namespace xpyt | |
| sys.attr("stdout") = out_logger; | ||
| sys.attr("stderr") = err_logger; | ||
| } | ||
|
|
||
| void xpython_interpreter::redirect_display() | ||
| { | ||
| py::module sys = py::module::import("sys"); | ||
|
|
||
| py::module xeus_python_display = py::module::import("xeus_python_display"); | ||
| m_displayhook = xeus_python_display.attr("XPythonDisplay")(); | ||
|
|
||
| py::cpp_function publish_display = [this](int execution_counter, py::object obj){ | ||
| if (!obj.is_none()) | ||
| { | ||
| xeus::xjson pub_data; | ||
| pub_data["text/plain"] = py::str(obj); | ||
| publish_execution_result(execution_counter, std::move(pub_data), xeus::xjson::object()); | ||
| } | ||
| }; | ||
|
|
||
| m_displayhook.attr("add_hook")(publish_display); | ||
|
|
||
| sys.attr("displayhook") = m_displayhook; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @Carreau And here I overwrite There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LGTM |
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ | |
|
|
||
| #include <string> | ||
| #include <vector> | ||
| #include <functional> | ||
|
|
||
| namespace xpyt | ||
| { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Carreau would you mind telling me what you think about that code? What I want to do is display the last expression of the cell (e.g. "Out [3]: ...")
What I do is:
Do you think it's how it should be done?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is the same as what we do in IPython. The smaller difference is that we loop of the n-1 non-final statement manually. Not sure it makes a difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note we also have other mode where
But those can be done later or not at all I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your reply! When are those modes used? Is it a command line option? (I can't find it)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are both CLI and dynamic options. Rarely used. So I wouldn't worry about theses yet.