Skip to content
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

Matplotlib magics #401

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 39 additions & 3 deletions notebooks/xeus-python.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,47 @@
"</center>"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"ename": "AttributeError",
"evalue": "'kernel.XInteractiveShell' object has no attribute 'config'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)",
"File \u001b[0;34m/home/martin/miniconda3/envs/xeus-python/lib/python3.9/site-packages/ipykernel/pylab/backend_inline.py\u001b[0m, in \u001b[0;32mconfigure_once\u001b[0m:\nLine \u001b[0;34m168\u001b[0m: configure_inline_support(ip, backend)\n",
"File \u001b[0;34m/home/martin/miniconda3/envs/xeus-python/lib/python3.9/site-packages/IPython/core/pylabtools.py\u001b[0m, in \u001b[0;32mconfigure_inline_support\u001b[0m:\nLine \u001b[0;34m385\u001b[0m: cfg = InlineBackend.instance(parent=shell)\n",
"File \u001b[0;34m/home/martin/miniconda3/envs/xeus-python/lib/python3.9/site-packages/traitlets/config/configurable.py\u001b[0m, in \u001b[0;32minstance\u001b[0m:\nLine \u001b[0;34m537\u001b[0m: inst = \u001b[36mcls\u001b[39;49;00m(*args, **kwargs)\n",
"File \u001b[0;34m/home/martin/miniconda3/envs/xeus-python/lib/python3.9/site-packages/traitlets/config/configurable.py\u001b[0m, in \u001b[0;32m__init__\u001b[0m:\nLine \u001b[0;34m76\u001b[0m: kwargs[\u001b[33m'\u001b[39;49;00m\u001b[33mconfig\u001b[39;49;00m\u001b[33m'\u001b[39;49;00m] = parent.config\n",
"\u001b[0;31mAttributeError\u001b[0m: 'kernel.XInteractiveShell' object has no attribute 'config'\n\u001b[0;31m---------------------------------------------------------------------------\u001b[0m"
]
}
],
"source": [
"%matplotlib inline"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"\n",
"fig = plt.figure()\n",
"plt.plot(np.sin(np.linspace(0, 20, 100)));"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simple code execution"
"## Simple code execution"
]
},
{
Expand Down Expand Up @@ -618,15 +654,15 @@
],
"metadata": {
"kernelspec": {
"display_name": "xpython",
"display_name": "Python 3.9 (XPython)",
"language": "python",
"name": "xpython"
},
"language_info": {
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"version": "3.8.2"
"version": "3.9.1"
}
},
"nbformat": 4,
Expand Down
73 changes: 60 additions & 13 deletions src/xinteractiveshell.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
#include "xinteractiveshell.hpp"

#include <iostream>
#include <string>
#include <utility>

#include "xeus/xinterpreter.hpp"
#include "xeus/xhistory_manager.hpp"

Expand Down Expand Up @@ -29,26 +33,32 @@ namespace xpyt
m_builtin_trap = get_nullcontext_module().attr("nullcontext")();

m_ipython_dir = "";
m_pylab_gui_select = py::none();

py::object osm_magics = m_magics_module.attr("OSMagics");
py::object basic_magics = m_magics_module.attr("BasicMagics");
py::object user_magics = m_magics_module.attr("UserMagics");
py::object extension_magics = m_magics_module.attr("ExtensionMagics");
py::object history_magics = m_magics_module.attr("HistoryMagics");
py::object ns_magics = m_magics_module.attr("NamespaceMagics");
py::object execution_magics = m_magics_module.attr("ExecutionMagics");
py::object pylab_magics = m_magics_module.attr("PylabMagics");

py::object osm_magics = m_magics_module.attr("OSMagics");
py::object basic_magics = m_magics_module.attr("BasicMagics");
py::object user_magics = m_magics_module.attr("UserMagics");
py::object extension_magics = m_magics_module.attr("ExtensionMagics");
py::object history_magics = m_magics_module.attr("HistoryMagics");
py::object ns_magics = m_magics_module.attr("NamespaceMagics");
py::object execution_magics = m_magics_module.attr("ExecutionMagics");
m_magics_manager.attr("register")(osm_magics);
m_magics_manager.attr("register")(basic_magics);
m_magics_manager.attr("register")(user_magics);
m_magics_manager.attr("register")(extension_magics);
m_magics_manager.attr("register")(history_magics);
m_magics_manager.attr("register")(ns_magics);
m_magics_manager.attr("register")(execution_magics);
m_magics_manager.attr("register")(pylab_magics);

m_magics_manager.attr("user_magics") = user_magics("shell"_a=this);

//select magics supported by xeus-python
auto line_magics = m_magics_manager.attr("magics")["line"];
auto cell_magics = m_magics_manager.attr("magics")["cell"];

line_magics = py::dict(
"cd"_a=line_magics["cd"],
"env"_a=line_magics["env"],
Expand All @@ -70,8 +80,11 @@ namespace xpyt
//namespace magics
"pinfo"_a=line_magics["pinfo"],
//execution magics
"timeit"_a=line_magics["timeit"]
"timeit"_a=line_magics["timeit"],
// matplotlib
"matplotlib"_a=line_magics["matplotlib"]
);

cell_magics = py::dict(
"writefile"_a=cell_magics["writefile"],
"sx"_a=cell_magics["sx"],
Expand All @@ -85,9 +98,9 @@ namespace xpyt
"cell"_a=cell_magics);
}


xinteractive_shell::xinteractive_shell()
{
m_config = py::dict();
p_history_manager = &xeus::get_interpreter().get_history_manager();
m_hooks = hooks_object();
m_ipy_process = py::module::import("IPython.utils.process");
Expand All @@ -112,7 +125,6 @@ namespace xpyt

py::object xinteractive_shell::run_line_magic(std::string name, std::string arg)
{

py::object magic_method = m_magics_manager
.attr("magics")["line"]
.attr("get")(name);
Expand All @@ -127,7 +139,6 @@ namespace xpyt
m_user_ns.attr("update")(py::globals());

return magic_method(arg);

}

py::object xinteractive_shell::run_cell_magic(std::string name, std::string arg, std::string body)
Expand Down Expand Up @@ -184,6 +195,34 @@ namespace xpyt
m_payloads.push_back(std::move(data));
}

py::tuple xinteractive_shell::enable_matplotlib(py::object gui)
{
py::module pt = py::module::import("IPython.core.pylabtools");
py::tuple gui_backend_tuple = pt.attr("find_gui_and_backend")(gui, m_pylab_gui_select);
// If we have our first gui selection, store it
if (m_pylab_gui_select.is_none())
{
m_pylab_gui_select = gui;
}
// Otherwise if they are different
else if (!gui.is(m_pylab_gui_select))
{
std::cerr << "Warning: Cannot change to a different GUI toolkit " << std::string(py::str(gui)) << "."
<< " Using " << std::string(py::str(m_pylab_gui_select)) << " instead" << std::endl;
gui_backend_tuple = pt.attr("find_gui_and_backend")(m_pylab_gui_select);
}
auto backend = gui_backend_tuple[1];
pt.attr("activate_matplotlib")(backend);

// Now we must activate the gui pylab wants to use, and fix %run to take
// plot updates into account
enable_gui(gui);

// m_magics_manager.attr("registry")["ExecutionMagics"].attr("default_runner") = pt.mpl_runner(self.safe_execfile);

return gui_backend_tuple;
}

void xinteractive_shell::clear_payloads()
{
m_payloads.clear();
Expand Down Expand Up @@ -225,7 +264,6 @@ namespace xpyt
return m_magics_manager;
}


py::object xinteractive_shell::get_extension_manager() const
{
return m_extension_manager;
Expand Down Expand Up @@ -261,9 +299,18 @@ namespace xpyt
return m_hooks;
}

py::dict xinteractive_shell::get_config() const
{
return m_config;
}

void xinteractive_shell::set_config(py::dict config)
{
m_config = config;
}

const xeus::xhistory_manager& xinteractive_shell::get_history_manager()
{
return *p_history_manager;
}

}
14 changes: 13 additions & 1 deletion src/xinteractiveshell.hpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include <vector>

#include "nlohmann/json.hpp"

#include "pybind11/pybind11.h"

#include "xdisplay.hpp"

#include "xeus/xhistory_manager.hpp"
Expand Down Expand Up @@ -34,7 +36,7 @@ namespace xpyt

// mock required methods
void register_post_execute(py::args, py::kwargs) {};
void enable_gui(py::args, py::kwargs) {};
void enable_gui(py::object gui = py::none()) {};
void observe(py::args, py::kwargs) {};
void showtraceback(py::args, py::kwargs) {};

Expand All @@ -56,6 +58,9 @@ namespace xpyt
void ex(py::str cmd);
py::object ev(py::str expr);

// required by matplotlib
py::tuple enable_matplotlib(py::object gui = py::none());

// required by pinfo
void inspect(std::string, std::string oname, py::kwargs);

Expand All @@ -68,6 +73,8 @@ namespace xpyt
py::object get_builtin_trap() const;
py::str get_ipython_dir() const;
hooks_object get_hooks() const;
py::dict get_config() const;
void set_config(py::dict config);

inline py::list get_dir_stack() const { return m_dir_stack; };
inline py::str get_home_dir() const { return m_home_dir; };
Expand Down Expand Up @@ -104,6 +111,11 @@ namespace xpyt
py::list m_dir_stack;
py::str m_home_dir;

// required by matplotlib
py::object m_pylab_gui_select;

py::dict m_config;

void init_magics();

// history manager
Expand Down
25 changes: 22 additions & 3 deletions src/xinterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ namespace xpyt
py::gil_scoped_acquire acquire;
nl::json kernel_res;

std::cout << "1" << std::endl;
std::cout << m_has_ipython << std::endl;

py::str code_copy;
if(m_has_ipython)
{
Expand Down Expand Up @@ -159,19 +162,26 @@ namespace xpyt
code_copy = code;
}

std::cout << "2" << std::endl;

// Scope guard performing the temporary monkey patching of input and
// getpass with a function sending input_request messages.
auto input_guard = input_redirection(allow_stdin);
std::cout << "21" << std::endl;
std::cout << "210" << std::endl;

try
{
// Import modules
py::module ast = py::module::import("ast");
py::module builtins = py::module::import("builtins");
std::cout << "211" << code_copy.cast<std::string>() << std::endl;

// Parse code to AST
py::object code_ast = ast.attr("parse")(code_copy, "<string>", "exec");
std::cout << "212" << std::endl;
py::list expressions = code_ast.attr("body");
std::cout << "213" << std::endl;

std::string filename = get_cell_tmp_file(code);
register_filename_mapping(filename, execution_count);
Expand All @@ -185,6 +195,7 @@ namespace xpyt
py::object last_stmt = expressions[py::len(expressions) - 1];
if (py::isinstance(last_stmt, ast.attr("Expr")))
{
std::cout << "22" << std::endl;
code_ast.attr("body").attr("pop")();

py::list interactive_nodes;
Expand All @@ -206,17 +217,25 @@ namespace xpyt
}
else
{
std::cout << "23" << std::endl;
py::object compiled_code = builtins.attr("compile")(code_ast, filename, "exec");
exec(compiled_code);
}

std::cout << "3" << std::endl;

kernel_res["status"] = "ok";
kernel_res["user_expressions"] = nl::json::object();
if (m_has_ipython)
{
xinteractive_shell* xshell = get_kernel_module()
.attr("get_ipython")()
.cast<xinteractive_shell*>();
py::object pyshell = get_kernel_module().attr("get_ipython")();

std::cout << "execute post_execute" << std::endl;

pyshell.attr("events").attr("trigger")("post_execute");
pyshell.attr("events").attr("trigger")("post_run_cell");

xinteractive_shell* xshell = pyshell.cast<xinteractive_shell*>();
auto payload = xshell->get_payloads();
kernel_res["payload"] = payload;
xshell->clear_payloads();
Expand Down
Loading