<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Jupyter Blog - debugging</title><link href="https://blog.jupyter.org/" rel="alternate"/><link href="https://blog.jupyter.org/feeds/tag-debugging.atom.xml" rel="self"/><id>https://blog.jupyter.org/</id><updated>2026-09-22T00:37:00+00:00</updated><subtitle>Debugging code in Jupyter.</subtitle><entry><title>Notebooks-on-Demand</title><link href="https://blog.jupyter.org/posts/2026/notebooks-on-demand-nod-a-jupyterlab-extension-for-a/" rel="alternate"/><published>2026-09-22T00:37:00+00:00</published><updated>2026-09-22T00:37:00+00:00</updated><author><name>Eric Rawn</name></author><id>tag:blog.jupyter.org,2026-09-22:/posts/2026/notebooks-on-demand-nod-a-jupyterlab-extension-for-a/</id><summary type="html">&lt;p&gt;Jump into a Jupyter notebook from anywhere in a Python codebase with this open-source JupyterLab extension.&lt;/p&gt;
</summary><content type="html">&lt;figure&gt;
&lt;iframe src="https://www.youtube-nocookie.com/embed/xgsp8h8bvfI" title="notebooks on demand demo" width="560" height="315" style="aspect-ratio: 560 / 315" loading="lazy" allow="accelerometer; clipboard-write; encrypted-media; gyroscope; picture-in-picture" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen&gt;&lt;/iframe&gt;
&lt;figcaption&gt;
&lt;p&gt;A tour of Notebooks-On-Demand&lt;/p&gt;
&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;a href="https://github.com/erawn/nod"&gt;&lt;em&gt;Nod: Notebooks-on-Demand&lt;/em&gt;&lt;/a&gt; is an open-source JupyterLab extension that lets you jump into a Jupyter notebook from anywhere in a Python codebase. Just call &lt;code&gt;notebook()&lt;/code&gt; from anywhere in your &lt;code&gt;.py&lt;/code&gt; file, run it with &lt;code&gt;nod&lt;/code&gt;, and a notebook opens at that point in the program with all your variables already loaded into the notebook state. When you’re done making edits, send them back to your original Python file with a click.&lt;/p&gt;
&lt;p&gt;Here’s what it looks like in practice. Say you have this Python program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;nodpy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;notebook&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;notebook&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;#our program will pause here&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
  &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;All you need to do is execute your program with &lt;code&gt;nod&lt;/code&gt; at the start:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;nod&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;myfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and a new JupyterLab session will open which looks like this:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Left: The Nod Control Panel shows the call stack for our notebook() call, Center: The notebook created from the current Nod Session, Right: The JupyterLab Debugger shows the current variables in our kernel" src="https://blog.jupyter.org/posts/2026/notebooks-on-demand-nod-a-jupyterlab-extension-for-a/images/001-1_aepH_Tg-Y9filKEEllMe4g.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Left: The Nod Control Panel shows the call stack for our &lt;code&gt;notebook()&lt;/code&gt; call, Center: The notebook created from the current Nod Session, Right: The JupyterLab Debugger shows the current variables in our kernel&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;You’ll notice a couple of things. First, on the right-hand pane, you’ll see that the current notebook state matches the variables available in the Python program at the place &lt;code&gt;notebook()&lt;/code&gt; was called. Second, the body of the current function &lt;code&gt;f&lt;/code&gt; is editable, and the surrounding code is displayed for context.&lt;/p&gt;
&lt;p&gt;From here, you can use your on-demand notebook to write and debug the function &lt;code&gt;f&lt;/code&gt;. When you’re done, you can send your new code back to the original source file with a button at the top of the Nod Panel on the left (see the &lt;a href="https://github.com/erawn/nod"&gt;repository&lt;/a&gt; for detailed instructions). Whatever you wrote in your on-demand notebook will replace the current body of &lt;code&gt;f&lt;/code&gt; in the source file. The notebook cells will be converted to newlines, and markdown cells are converted to comments (thanks to &lt;a href="https://github.com/jupytext/jupytext"&gt;Jupytext&lt;/a&gt;!). We can also re-run our program from the beginning with these new changes in our source file through the Nod panel.&lt;/p&gt;
&lt;p&gt;Here’s a few scenarios that Nod might be helpful:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Scenario 1: You’re working in a large Python project and code is spread over countless files, classes, and function calls. You begin writing a new function, but the arguments are complex and questions abound: &lt;em&gt;What exactly does that class method return&lt;/em&gt;? &lt;em&gt;When I join these two tables, what does the output look like? How do I even construct the inputs to this function?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You think: &lt;em&gt;This would be so much easier if I could just write this function in a notebook!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Instead of manually copying out code snippets, writing data structures to files and reading them into a notebook, and perhaps getting something to work eventually,&lt;/em&gt; you can just call &lt;code&gt;notebook()&lt;/code&gt;, &lt;em&gt;and a Jupyter notebook appears with just the body of your function and the function’s arguments already in your notebook state.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Scenario 2: &lt;em&gt;You realize there’s a bug in a specific function when called with specific arguments. You could use a&lt;/em&gt; &lt;code&gt;breakpoint()&lt;/code&gt; &lt;em&gt;to inspect the program, but you don’t just want to look at the arguments, you want to see if different ways of changing the arguments remove the bug when you run the function code. Instead, you call&lt;/em&gt; &lt;code&gt;notebook()&lt;/code&gt; &lt;em&gt;when the function is invoked with the buggy arguments, opening a Jupyter notebook on the function definition with those arguments loaded in the notebook state. You can modify the arguments and rerun your code in the notebook to test different outcomes and implement your fix. When you’re done, you can send the changes back to your source file and restart (opening a notebook-on-demand for your new program), verifying that your program is now running as expected.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Scenario 3: You use an AI system to generate some code, but there’s a crucial part you want to really understand. Just call &lt;code&gt;notebook()&lt;/code&gt; at that part, and now you have the full functionality of a notebook to walk line-by-line through the code, printing and visualizing the output at each step or experimenting with alternative decisions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Nod’s on-demand notebooks are &lt;em&gt;&lt;strong&gt;designed to be disposable&lt;/strong&gt;&lt;/em&gt;. After you’ve sent your changes back to your source file, all the information to recreate the notebook is already in your Python file, so you can safely quit the JupyterLab session and continue programming in your text editor of choice. Your code can live in your text editor and Python source files, but Nod makes a quick trip to a notebook easy.&lt;/p&gt;
&lt;p&gt;While I’ve found this workflow by itself to be really helpful in my own programming, Nod can do two other things that are pretty neat:&lt;/p&gt;
&lt;p&gt;First, you don’t just have to stay in the function body where you called &lt;code&gt;notebook()&lt;/code&gt;; you can also navigate up and down the call stack with the Nod panel on the left. For example, you can select the function &lt;code&gt;d&lt;/code&gt; to see how &lt;code&gt;f&lt;/code&gt; was called:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The Nod Panel on the Left navigates down the callstack, replacing the current notebook and the state to match." src="https://blog.jupyter.org/posts/2026/notebooks-on-demand-nod-a-jupyterlab-extension-for-a/images/002-1_MB1vHj5UbqOnMG8FxjXLeQ.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The Nod Panel on the Left navigates down the callstack, replacing the current notebook and the state to match.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Both our notebook and the current variables update to our new position in our program (&lt;code&gt;x&lt;/code&gt; isn’t in our debugger pane on the right anymore, since it’s not available within function &lt;code&gt;d&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Second, you can use &lt;code&gt;nodLog()&lt;/code&gt; to collect a bunch of values from your program to poke and prod in an on-demand notebook. Take a look at the following file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;nodpy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;notebook&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nodLog&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;notebook&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;nodLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running it will pop open a JupyterLab interface where, on the right, you’ll have access to a “Nod Log” pane, which lets you select assignments to &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;b&lt;/code&gt; for the on-demand notebook session among the values you saved with &lt;code&gt;nodLog()&lt;/code&gt;:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="nodLog() captures variables while your program runs and makes them available in the on-demand notebook session to experiment with." src="https://blog.jupyter.org/posts/2026/notebooks-on-demand-nod-a-jupyterlab-extension-for-a/images/003-1_6GAT730KwNVY8NJDM2dOLw.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;&lt;code&gt;nodLog()&lt;/code&gt; captures variables while your program runs and makes them available in the on-demand notebook session to experiment with.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;When working with Python objects which can vary in unpredictable ways (like the results of a JSON API call or some other heavily-nested Python dictionary), I find &lt;code&gt;nodLog()&lt;/code&gt; to be helpful in gauging the possible values I need to handle when writing a new function. It lets me inspect and switch between different inputs to my function easily.&lt;/p&gt;
&lt;p&gt;Nod is free and open-source, so &lt;a href="https://github.com/erawn/nod"&gt;check it out here&lt;/a&gt; if you’re interested. Nod also works with JupyterHub with a slightly different workflow (see the repository for a guide!). My goal with Nod is to add to the situations where Jupyter Notebooks are a useful tool. If you have ideas about more ways Nod can be helpful or feedback to make it better, please leave an issue on the Github page and we can discuss!&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
</content><category term="debugging"/><category term="extensions"/><category term="JupyterLab"/></entry><entry><title>Enabling the JupyterLab debugger with ipykernel</title><link href="https://blog.jupyter.org/posts/2021/enabling-the-jupyterlab-debugger-with-ipykernel/" rel="alternate"/><published>2021-05-13T11:45:00+00:00</published><updated>2021-06-02T14:59:00+00:00</updated><author><name>Sylvain Corlay</name></author><id>tag:blog.jupyter.org,2021-05-13:/posts/2021/enabling-the-jupyterlab-debugger-with-ipykernel/</id><summary type="html">&lt;p&gt;Support for the Jupyter Debugger Protocol just landed in ipykernel&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;Support for the Jupyter Debugger Protocol just landed in ipykernel&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;JupyterLab 3.0 includes a visual debugger that allows to interactively set breakpoints, step into functions, and inspect variables with any Jupyter kernel that implements the Jupyter debugger protocol.&lt;/p&gt;
&lt;p&gt;The first two language kernels to implement the new protocol were &lt;a href="https://github.com/jupyter-xeus/xeus-python/"&gt;xeus-python&lt;/a&gt; (a Python kernel) and &lt;a href="https://github.com/jupyter-xeus/xeus-robot/"&gt;xeus-robot&lt;/a&gt; (a kernel for Robot Framework). Unfortunately, the reference Python kernel, &lt;a href="https://github.com/ipython/ipykernel"&gt;&lt;strong&gt;ipykernel&lt;/strong&gt;&lt;/a&gt;, did not support debugging yet, &lt;em&gt;until now&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;Today, we are pleased to announce that debugging support landed in ipykernel, and will be available in the next major release, ipykernel 6.0. Pre-releases including the ipykernel debugger are available.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Debugging with ipykernel" src="https://blog.jupyter.org/posts/2021/enabling-the-jupyterlab-debugger-with-ipykernel/images/001-1_jSQWLvCYoV-L-kp_lTkRKg.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Debugging with ipykernel&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="what-will-change-with-ipykernel-60"&gt;What will change with ipykernel 6.0?&lt;/h2&gt;
&lt;p&gt;Enabling support for debugging in ipykernel required important changes in the code base regarding the concurrency model of the kernel. The main change is that the processing of messages on the “control channel” now happens in a different thread, allowing for the processing to happen while user code is running.&lt;/p&gt;
&lt;p&gt;Ipykernel 6.0 includes several other updates. Tornado coroutines were dropped in favor of native coroutines. The Matplotlib inline backend was split into a separate package, and ipykernel depends on &lt;a href="https://github.com/microsoft/debugpy"&gt;debugpy&lt;/a&gt;, an implementation of the Debug Adapter Protocol for Python.&lt;/p&gt;
&lt;p&gt;If you are interested in testing out the new features, check out the beta release!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install ipykernel --pre
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="try-it-now"&gt;Try it now!&lt;/h2&gt;
&lt;p&gt;Thanks to &lt;a href="https://mybinder.org/"&gt;MyBinder&lt;/a&gt;, you can also try it out without the need of installing anything on your computer. Just follow this link:&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;a href="https://mybinder.org/v2/gist/SylvainCorlay/a6405bbdfa9d58a670a67f3a47741bd2/HEAD?urlpath=doc%2Ftree%2Fdebugger.ipynb"&gt;&lt;img src="https://blog.jupyter.org/posts/2021/enabling-the-jupyterlab-debugger-with-ipykernel/images/002-0_rELNpt0w5qbk_GQn.jpg" alt="" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="what-about-the-future"&gt;What about the future?&lt;/h2&gt;
&lt;p&gt;A lot of new features are in the works with the JupyterLab debugger.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;JupyterLab 3.1 will include several usability improvements to the debugger.&lt;/li&gt;
&lt;li&gt;It will also add the ability to submit code for execution when stopped at a breakpoint.&lt;/li&gt;
&lt;li&gt;We are working on a richer variable explorer, using Jupyter’s rich display system to enable the rich-rendering of variables in the explorer, to &lt;em&gt;e.g.&lt;/em&gt; render dataframes as tables.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, we also plan on adding debugging support to other language kernels.&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;The work of Johan and Sylvain at &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt; on the debugger support in ipykernel was funded by &lt;a href="https://www.twosigma.com/"&gt;Two Sigma&lt;/a&gt;. We are grateful to Min Ragan Kelley and Matthias Bussonnier, who reviewed the pull requests on debugger support.&lt;/p&gt;
&lt;h2 id="about-the-authors"&gt;About the authors&lt;/h2&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2021/enabling-the-jupyterlab-debugger-with-ipykernel/images/003-1_8_HgQuq5_HXhLXSdfGnhrA.jpeg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/JohanMabille"&gt;Johan Mabille&lt;/a&gt; is a scientific software developer at QuantStack.&lt;/p&gt;
&lt;p&gt;Johan is very active in the Jupyter ecosystem, as the creator of &lt;a href="https://github.com/jupyter-xeus/xeus"&gt;xeus&lt;/a&gt;, a C++ implementation of the Jupyter protocol, and several language kernels, such as &lt;a href="https://github.com/jupyter-xeus/xeus-python"&gt;xeus-python&lt;/a&gt;, &lt;a href="https://github.com/jupyter-xeus/xeus-cling"&gt;xeus-cling&lt;/a&gt;, and &lt;a href="https://github.com/jupyter-xeus/xeus-robot"&gt;xeus-robot&lt;/a&gt;. Johan also made contributions to the Jupyter widgets ecosystem and to JupyterLab.&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2021/enabling-the-jupyterlab-debugger-with-ipykernel/images/004-1_LpuIpGQIDYMhv5IBthmwcA.jpeg" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://twitter.com/SylvainCorlay"&gt;Sylvain Corlay&lt;/a&gt; is the founder and CEO of QuantStack.&lt;/p&gt;
&lt;p&gt;As an open-source developer, Sylvain is very active in the Jupyter project with contributions in several components of the stack, including widgets, kernels, nbconvert, and others. He is also a steering committee member of the project.&lt;/p&gt;
&lt;p&gt;Sylvain also does volunteer work for the community, as member of board of directors of NumFOCUS, co-organizer of the &lt;a href="https://www.meetup.com/pyData-paris"&gt;PyData Paris Meetup&lt;/a&gt;, and vice-chair of JupyterCon 2020.&lt;/p&gt;
</content><category term="debugging"/><category term="IPython"/><category term="JupyterLab"/><category term="kernels"/></entry><entry><title>Robotic Process Automation with JupyterLab</title><link href="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/" rel="alternate"/><published>2021-01-18T10:36:00+00:00</published><updated>2021-01-18T10:36:00+00:00</updated><author><name>Martin Renou</name></author><id>tag:blog.jupyter.org,2021-01-18:/posts/2021/robotic-process-automation-with-jupyterlab/</id><summary type="html">&lt;p&gt;Introducing a new Jupyter kernel for Robot Framework&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Robotic Process Automation (RPA) differs from classical automation tools in that the actions to automate can be developed by observing a user perform a task in a graphical user interface, across multiple applications.&lt;/p&gt;
&lt;p&gt;It is a means to lower the entry barrier of process automation and enable the use of tools that don’t provide a programmatic interface.&lt;/p&gt;
&lt;p&gt;Most typically, RPA developers will use a mixed approach between textual programming and performing actions manually. The resulting programs are typically called software &lt;em&gt;robots&lt;/em&gt;. Therefore, interactive computing tools like Jupyter are a natural environment for RPA, as the interactive nature of Jupyter allows for quick iterations and trial-and-errors when developing such robots.&lt;/p&gt;
&lt;p&gt;While many RPA tools are commercial software, &lt;a href="https://robotframework.org/"&gt;Robot Framework&lt;/a&gt; and the tooling developed by &lt;a href="https://robocorp.com/"&gt;Robocorp&lt;/a&gt; provide an open-source RPA programming language, with a high-level syntax, extensible with Python plugins. It has a rich ecosystem of libraries and tools that are developed as separate projects.&lt;/p&gt;
&lt;h2 id="robot-framework-and-project-jupyter"&gt;Robot Framework and Project Jupyter&lt;/h2&gt;
&lt;p&gt;Today, we are happy to announce the first release of &lt;a href="https://github.com/jupyter-xeus/xeus-robot"&gt;&lt;strong&gt;xeus-robot&lt;/strong&gt;&lt;/a&gt;, a Jupyter kernel for &lt;a href="https://robotframework.org/"&gt;Robot Framework&lt;/a&gt; based on &lt;a href="https://github.com/jupyter-xeus/xeus"&gt;xeus&lt;/a&gt;, supporting the new JupyterLab 3.0 visual debugger, auto-completion, and much more!&lt;/p&gt;
&lt;p&gt;But before we dive into xeus-robot, we should recognize the earlier work by &lt;a href="https://github.com/bollwyvl"&gt;Nick Bollweg&lt;/a&gt; and &lt;a href="https://github.com/datakurre"&gt;Asko Soukka&lt;/a&gt;, who developed two Jupyter kernels for Robot Framework, &lt;a href="https://github.com/gtri/irobotframework"&gt;irobotframework&lt;/a&gt;, and &lt;a href="https://github.com/robots-from-jupyter/robotkernel"&gt;robotkernel&lt;/a&gt;, and gave an &lt;a href="https://www.youtube.com/watch?v=rbYF_RmiAR8"&gt;amazing talk&lt;/a&gt; together at &lt;a href="https://robocon.io/"&gt;RoboCon&lt;/a&gt; in 2019!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The motivation for us to reboot this effort with a kernel based on xeus was to enable the &lt;strong&gt;JupyterLab Visual Debugger&lt;/strong&gt; for this kernel. This requires a different concurrency model than that of ipykernel, which underlies both irobotframework and robotkernel. In the end, we were able to provide the same features and more, including e.g. code completion in Python cells, debugging etc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="diving-into-xeus-robot"&gt;Diving into Xeus-robot&lt;/h2&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/001-1_3HNfLnwDpXNZ6n6HPD2lXQ.webp" alt="Xeus robot logo" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/jupyter-xeus/xeus-robot"&gt;xeus-robot&lt;/a&gt; is a reboot of the already existing robotkernel, based on xeus.&lt;/p&gt;
&lt;p&gt;Like most language kernels, &lt;a href="https://github.com/jupyter-xeus/xeus-robot"&gt;xeus-robot&lt;/a&gt; supports code completion, inspection, error handling, etc. It also allows using Python cells to define custom robot keywords in Python, those Python cells support code completion as well.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Code completion in Robot framework" src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/002-1_OPqkYEI78eT1dj5P6WEeXg.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Code Completion in Robot Framework&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;By using the libraries robotframework-seleniumlibrary and robotframework-seleniumscreenshots, you can even complete the selection of elements on the page you are currently testing!&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="RPA code completion" src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/003-1_Z-aWN6goZH_1YcabAYj2fQ.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Code completion with an action of the user in the UI.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;%%python&lt;/code&gt; cell magic makes it possible to extend Robotframework with Python modules in the notebook.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Robot Framework extenions in Python" src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/004-1_TSiSmKHJOGE0PQ_c7alv1w.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Extending RobotFramework with Python, and code completion in Python cells&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Widget-based UIs are provided to test Robotframework “keywords”.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Robot Framework and Jupyter widgets" src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/005-1_nyXQAQivNvV23xvS_1KCYQ.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Testing Robot Framework “keywords” with Jupyter widgets&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Last but not least, xeus-robot comes with full support for the JupyterLab Visual Debugger! After the xeus-python kernel, it is the second Jupyter kernel to support the Jupyter Debugger Protocol! We hope that many more will come.&lt;/p&gt;
&lt;p&gt;You can set breakpoints, step in defined keywords (the equivalent of functions), inspect variables, and see the callstack, as shown below.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="JupyterLab Visual Debugger" src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/006-1_EFxI8mzCwYwnK9DB_xGxTQ.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The JupyterLab Visual Debugger in action with Robot Framework&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="installing-xeus-robot"&gt;Installing xeus-robot&lt;/h2&gt;
&lt;p&gt;Xeus-robot is available for all platforms on conda-forge, and can be installed with conda or mamba.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mamba install xeus-robot -c conda-forge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;jupyterlab-robotmode&lt;/code&gt; package, which provides JupyterLab syntax highlighting for Robot Framework will also be installed as a dependency.&lt;/p&gt;
&lt;p&gt;For your conda installation, we recommend starting from &lt;strong&gt;mambaforge&lt;/strong&gt; or &lt;strong&gt;miniforge&lt;/strong&gt; which are available for download &lt;a href="https://github.com/conda-forge/miniforge"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;, and default to the conda-forge channel (making the &lt;code&gt;-c conda-forge&lt;/code&gt; argument unnecessary).&lt;/p&gt;
&lt;h2 id="try-it-online"&gt;Try it online&lt;/h2&gt;
&lt;p&gt;Thanks to &lt;a href="https://mybinder.org/"&gt;MyBinder&lt;/a&gt;, you can try it out without the need of installing anything on your computer. Just follow this link:&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;a href="https://mybinder.org/v2/gh/jupyter-xeus/xeus-robot/stable?urlpath=/lab/tree/notebooks/xrobot.ipynb"&gt;&lt;img src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/007-0_TQpdhVZSAnE-XOrm.jpg" alt="&amp;quot;Launch binder&amp;quot; badge" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
&lt;h2 id="acknowledgments"&gt;Acknowledgments&lt;/h2&gt;
&lt;p class="standalone-image"&gt;&lt;a href="https://robocorp.com/"&gt;&lt;img src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/008-1_E9XGge6uWrbmvndUoZ1Qug.webp" alt="Robocorp logo" loading="lazy" data-body-image=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The work on xeus-robot by &lt;a href="https://twitter.com/QuantStack"&gt;QuantStack&lt;/a&gt; was funded by &lt;a href="https://robocorp.com/"&gt;Robocorp&lt;/a&gt;, and is part of their initiative to create an open-source RPA ecosystem. Beyond the xeus-robot kernel, Robocorp also funds the integration of Robot Framework with &lt;a href="https://marketplace.visualstudio.com/items?itemName=robocorp.robocorp-code"&gt;Visual Studio Code&lt;/a&gt;, &lt;a href="https://rpaframework.org/"&gt;RPA Framework&lt;/a&gt;, and other development to push the Robot Framework project forward.&lt;/p&gt;
&lt;p&gt;The implementation of the debugger in xeus-robot relies on &lt;a href="https://github.com/robocorp/robotframework-lsp"&gt;robotframework-lsp&lt;/a&gt; by &lt;a href="https://twitter.com/fabiofz"&gt;Fabio Zadrozny&lt;/a&gt; and we want to thank him for his help in integrating it in xeus-robot.&lt;/p&gt;
&lt;h2 id="about-the-authors"&gt;About the authors&lt;/h2&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/009-1_zwPmx9pH4pkXOxowHQOsuQ.jpeg" alt="Martin Renou" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Martin Renou&lt;/strong&gt; is a scientific software developer at QuantStack. He is the creator of the xeus-python and xeus-robot kernels.&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2021/robotic-process-automation-with-jupyterlab/images/010-1_YQZupQRMB6JJfhM_byi2KA.jpeg" alt="Johan Mabille" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Johan Mabille&lt;/strong&gt; is a scientific software developer at QuantStack. He is a co-author of the xeus project, and developed the debugger extensions to xeus-python and xeus-robot. He also co-authored the front-end for the JupyterLab visual debugger.&lt;/p&gt;
</content><category term="debugging"/><category term="JupyterLab"/><category term="kernels"/><category term="xeus"/></entry><entry><title>A visual debugger for Jupyter</title><link href="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/" rel="alternate"/><published>2020-03-25T15:53:00+00:00</published><updated>2020-03-26T09:12:00+00:00</updated><author><name>Project Jupyter</name></author><id>tag:blog.jupyter.org,2020-03-25:/posts/2020/a-visual-debugger-for-jupyter/</id><summary type="html">&lt;p&gt;Most of the progress made in software projects comes from incrementalism. The ability to quickly see the outcome of an execution and iterate has been one of the main reasons for the success of Jupyter, especially in scientific exploratory workflows.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Most of the progress made in software projects comes from &lt;em&gt;incrementalism&lt;/em&gt;. The ability to quickly see the outcome of an execution and iterate has been one of the main reasons for the success of Jupyter, especially in scientific exploratory workflows.&lt;/p&gt;
&lt;p&gt;Jupyter users like to &lt;em&gt;experiment&lt;/em&gt; in the notebook, and to use the notebook as an interactive communication tool. However, for more classical software development tasks such as the refactoring of a large codebase, they often switch to general-purpose IDEs.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The JupyterLab environment." src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/001-1_u8y-ggU2O513KjXdGbdEuQ.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The JupyterLab environment.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The Jupyter project has made strides in the past few years towards filling that gap, notably with the &lt;strong&gt;JupyterLab&lt;/strong&gt; project, which enables a richer UI including a file browser, text editors, consoles, notebooks, and a rich layout system.&lt;/p&gt;
&lt;p&gt;However, a missing piece (which has remained one of the main reasons for users to switch to a different tool) is a &lt;strong&gt;visual debugger&lt;/strong&gt;. This feature has long been requested by users, especially those accustomed to general-purpose development environments.&lt;/p&gt;
&lt;h2 id="a-debugger-for-jupyter"&gt;A debugger for Jupyter&lt;/h2&gt;
&lt;p&gt;Today, after several months of development, we are glad to announce the first public release of the Jupyter visual debugger!&lt;/p&gt;
&lt;p&gt;This is just the first release, but we can already set breakpoints in notebook cells and source files, inspect variables, navigate the call stack and more.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Screencast of the JupyterLab visual debugger in action" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/002-1_NP0bYBdrhwgpJpKDhPLWrQ.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Screencast of the JupyterLab visual debugger in action&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="try-the-debugger-on-binder"&gt;Try the debugger on binder&lt;/h2&gt;
&lt;p&gt;You can also try the debugger online with binder. Just click on the binder link:&lt;/p&gt;
&lt;figure&gt;
&lt;a href="https://mybinder.org/v2/gh/jupyterlab/debugger/stable?urlpath=/lab/tree/examples/index.ipynb"&gt;&lt;img alt="Click on the binder link to launch the demo" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/003-1_NbZ_56IL0J-q0V32qgiq3A.webp" loading="lazy" data-body-image=""&gt;&lt;/a&gt;
&lt;figcaption&gt;Click on the binder link to launch the demo&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="installation"&gt;Installation&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;The debugger &lt;em&gt;&lt;strong&gt;front-end&lt;/strong&gt;&lt;/em&gt; can be installed as a JupyterLab extension.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;jupyter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;labextension&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;@jupyterlab&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;debugger&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;The debugger front-end will be included in JupyterLab by default in a future release.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In the &lt;em&gt;&lt;strong&gt;back-end&lt;/strong&gt;&lt;/em&gt;, a kernel implementing the &lt;strong&gt;Jupyter Debug Protocol&lt;/strong&gt; (which will be detailed in the next section) is required. The only kernel implementing this protocol, for now, is &lt;code&gt;xeus-python&lt;/code&gt; a new Jupyter kernel for the Python programming language. (Support for the debugger protocol in ipykernel is also on the roadmap).&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;conda install xeus-python -c conda-forge
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once xeus-python and the debugger extension are installed, you should be all set to use the Jupyter visual debugger!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Depending on the platform, PyPI wheels are available for xeus-python, but they are still &lt;em&gt;&lt;strong&gt;experimental&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="the-jupyter-debug-protocol"&gt;The Jupyter Debug Protocol&lt;/h2&gt;
&lt;h3 id="new-message-types-for-the-control-and-iopub-channels"&gt;New message types for the Control and IOPub channels&lt;/h3&gt;
&lt;p&gt;Jupyter kernels (the part of the infrastructure that executes the user’s code) communicate with the rest of the infrastructure with a &lt;a href="https://jupyter-client.readthedocs.io/en/stable/messaging.html"&gt;well-specified inter-process communication protocol&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Several communication channels exist, such as&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;strong&gt;Shell&lt;/strong&gt; channel, which is a request/reply channel for e.g. execution requests&lt;/li&gt;
&lt;li&gt;the &lt;strong&gt;IOPub&lt;/strong&gt; channel, which is a one-directional communication channel from the kernel to the client, and is used e.g. to forward the content of the standard output streams (stdout and stderr).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;strong&gt;Control&lt;/strong&gt; channel is similar to Shell but operates on a separate socket so that &lt;em&gt;&lt;strong&gt;messages are not queued behind execution requests&lt;/strong&gt;&lt;/em&gt;, and have a higher priority. Control was already used for Interrupt and Shutdown requests, and we decided to use the same channel for the commands sent to the debugger.&lt;/p&gt;
&lt;p&gt;Two message types were added to the protocol:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;debug_[request/reply]&lt;/code&gt; to request specific actions to be performed by the debugger such as adding a breakpoint or stepping into a code, which is sent to the &lt;strong&gt;Control&lt;/strong&gt; channel.&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;debug_event&lt;/code&gt; uni-directional message used by debugging kernels to send debugging events to the front-end. Debug events are sent over the IOPub channel.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="extending-the-debug-adapter-protocol"&gt;Extending the Debug Adapter Protocol&lt;/h3&gt;
&lt;p&gt;A key principle to the Jupyter design is the &lt;strong&gt;agnosticism to the programming language&lt;/strong&gt;. It is important for the Jupyter debug protocol to be adaptable to other kernel implementations.&lt;/p&gt;
&lt;p&gt;A popular standard for debugging is Microsoft’s “&lt;strong&gt;Debug Adapter Protocol&lt;/strong&gt;” (DAP) which is a JSON-based protocol underlying the debugger of Visual Studio Code and for which there already exist multiple language back-ends.&lt;/p&gt;
&lt;p&gt;It was therefore natural for us to use the DAP messages over the &lt;code&gt;debug_[request/reply]&lt;/code&gt; and &lt;code&gt;debug_event&lt;/code&gt; messages that we just added.&lt;/p&gt;
&lt;p&gt;However, it was not quite &lt;em&gt;sufficient&lt;/em&gt; in the case of Jupyter. Indeed&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In order to support page reloading, or a client connecting at a later stage, Jupyter kernels must store the state of the debugger (breakpoints, whether the debugger is currently stopped). The front-end can request that state over with a &lt;code&gt;debug_request&lt;/code&gt; message.&lt;/li&gt;
&lt;li&gt;In order to support the debugging of notebook cells and of Jupyter consoles, which are not based on source files, we also needed messages to submit code to the debugger to which breakpoints can be added.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Besides these two differences, the content of the debug requests and replies corresponds to the debug adapter protocol.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All these extensions to the Jupyter kernel protocol have been proposed for inclusion in the official specification. The JEP (Jupyter Enhancement Proposal) can be found &lt;a href="https://github.com/jupyter/enhancement-proposals/pull/47"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="xeus-python-the-first-jupyter-kernel-to-support-debugging"&gt;Xeus-python, the first Jupyter Kernel to support debugging&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/QuantStack/xeus"&gt;Xeus&lt;/a&gt; is a C++ implementation of the Jupyter kernel protocol. It is not a kernel by itself but a library that helps kernel authoring. &lt;a href="https://github.com/QuantStack/xeus"&gt;Xeus&lt;/a&gt; is useful when developing a kernel for a language that has a C or a C++API (like Python, Lua, or SQL). It takes the cumbersome task of implementing the &lt;a href="https://jupyter-client.readthedocs.io/en/stable/messaging.html"&gt;Jupyter messaging protocol&lt;/a&gt; for the kernel author to focus on the core interpreter tasks: executing code, inspecting, etc.&lt;/p&gt;
&lt;p&gt;Several kernels have been developed with xeus, including the popular &lt;a href="https://github.com/jupyter-xeus/xeus-cling"&gt;xeus-cling&lt;/a&gt; kernel for the C++ programming language, based on the cling C++ interpreter from CERN. The &lt;a href="https://github.com/jupyter-xeus/xeus-python.git"&gt;xeus-python&lt;/a&gt; kernel is an alternative Python kernel to ipykernel, based on xeus. The first release of the xeus-python kernel was announced on this blog earlier this year: &lt;a href="https://blog.jupyter.org/posts/2019/a-new-python-kernel-for-jupyter/"&gt;A new Python kernel for Jupyter&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Xeus-python was an appropriate choice for this first implementation of the debugging protocol because&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it has a &lt;strong&gt;pluggable concurrency model&lt;/strong&gt;, which allowed running the processing of the Control channel in a different thread.&lt;/li&gt;
&lt;li&gt;it has a &lt;strong&gt;lighter-weight codebase&lt;/strong&gt; which made it a convenient sandbox to iterate upon. Implementing the first version of the protocol in ipykernel would have required more significant refactoring and consensus building at an early stage.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="the-roadmap-of-xeus-python"&gt;The roadmap of Xeus-python&lt;/h3&gt;
&lt;p&gt;The short-term roadmap for xeus-python includes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;adding support for IPython magics in xeus-python, which is the main missing feature with respect to ipykernel.&lt;/li&gt;
&lt;li&gt;improving the PyPI wheels of xeus-python.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="what-about-other-kernels"&gt;What about other kernels?&lt;/h3&gt;
&lt;p&gt;The work in the front-end is valid for any kernel implementing the extended kernel protocol.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We will be working in 2020 to enable debugging with as many kernels as possible.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This will soon be the case for other xeus-based kernels which share a large part of the implementation with xeus-python, such as xeus-cling.&lt;/p&gt;
&lt;h2 id="diving-into-the-debugger-front-end-architecture"&gt;Diving into the debugger front-end architecture&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/jupyterlab/debugger"&gt;debugger extension for JupyterLab&lt;/a&gt; provides what users would typically expect from an IDE:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a sidebar with a variable explorer, a list of breakpoints, a source preview and the possibility to navigate the call stack&lt;/li&gt;
&lt;li&gt;the ability to set breakpoints directly next to the code, namely in code cells and code consoles&lt;/li&gt;
&lt;li&gt;visual markers to indicate where the current execution has stopped&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When working with Jupyter notebooks, the state of the execution is kept in the kernel. But a cell can be executed and then deleted from the notebook. What should happen when a user wants to step in deleted code?&lt;/p&gt;
&lt;p&gt;The extension supports that particular use case and enables retrieving a read-only view of the previously executed cell.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Stepping into a deleted cell" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/004-0_gsIleEb7Q-sq05f0.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Stepping into a deleted cell&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Consoles and files also have support for debugging.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Debugging code consoles in JupyterLab" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/005-0_G5-dLqkhH5CEvQQv.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Debugging code consoles in JupyterLab&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img alt="Debugging files in JupyterLab" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/006-0_ZejsDIpKOEPDgoTs.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Debugging files in JupyterLab&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Debugging can be enabled on a notebook level, which lets users debug a notebook and work on a different one at the same time.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Debugging multiple notebooks simultaneously" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/007-0_EtApkSznZEY-GJhA.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Debugging multiple notebooks simultaneously&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Variables can be inspected using a tree viewer and a table viewer:&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="The variable explorer" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/008-0_9pVDg58cTz5Yezw8.mp4" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;The variable explorer&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The debugger extension for JupyterLab has been designed to work with any kernel that supports debugging.&lt;/p&gt;
&lt;p&gt;By relying on the Debug Adapter Protocol, the debugger extension abstracts away language-specific features and provides a consistent debugging interface to the user.&lt;/p&gt;
&lt;p&gt;The following diagram shows how the debug messages flow between the user, the JupyterLab extension and the kernel during a debugging session.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Using the Debug Adapter Protocol in the debugger extension (source)" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/009-0_fwLQQWxKtGUiMpq1.webp" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Using the Debug Adapter Protocol in the debugger extension (&lt;a href="https://github.com/jupyterlab/debugger/issues/64"&gt;source&lt;/a&gt;)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="future-developments"&gt;Future developments&lt;/h2&gt;
&lt;p&gt;In 2020, we plan on making major improvements to the debugger experience:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for rich mime type rendering in the variable explorer.&lt;/li&gt;
&lt;li&gt;Support for conditional breakpoints in the UI.&lt;/li&gt;
&lt;li&gt;General improvements of the debugger user experience.&lt;/li&gt;
&lt;li&gt;Enable the debugging of &lt;a href="https://github.com/voila-dashboards/voila/"&gt;Voilà dashboards&lt;/a&gt;, from the JupyterLab Voilà preview extension.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="main-content-end" aria-hidden="true"&gt;&lt;/div&gt;
&lt;h2 id="acknowledgements"&gt;Acknowledgements&lt;/h2&gt;
&lt;p&gt;The JupyterLab debugger is the result of the collaboration and coordination of developers from several institutions, including QuantStack, Two Sigma, and Bloomberg.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The work on both the front-end and the back-end at &lt;a href="https://twitter.com/QuantStack"&gt;&lt;strong&gt;QuantStack&lt;/strong&gt;&lt;/a&gt; by &lt;a href="https://twitter.com/jtpio"&gt;&lt;strong&gt;Jeremy Tuloup&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://twitter.com/johanmabille"&gt;&lt;strong&gt;Johan Mabille&lt;/strong&gt;&lt;/a&gt;, &lt;a href="https://twitter.com/martinRenou"&gt;&lt;strong&gt;Martin Renou&lt;/strong&gt;&lt;/a&gt;, and &lt;a href="https://twitter.com/SylvainCorlay"&gt;&lt;strong&gt;Sylvain Corlay&lt;/strong&gt;&lt;/a&gt;, was funded by &lt;a href="https://twitter.com/techatbloomberg"&gt;&lt;strong&gt;Bloomberg&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The work on the Jupyter debugger by &lt;strong&gt;Borys Palka&lt;/strong&gt; and &lt;a href="https://twitter.com/micronova"&gt;&lt;strong&gt;Afshin Darian&lt;/strong&gt;&lt;/a&gt; was made possible by &lt;a href="https://twitter.com/twosigma"&gt;&lt;strong&gt;Two Sigma&lt;/strong&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="about-the-developers"&gt;About the developers&lt;/h2&gt;
&lt;figure&gt;
&lt;img alt="Jeremy Tuloup" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/010-1_4RE97odgcRtRruh0najsVg.jpg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Jeremy Tuloup&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Jeremy Tuloup&lt;/strong&gt; is a Scientific Software developer at QuantStack. He authored a large part of the front-end of the JupyterLab debugger.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Borys Palka" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/011-1_IJw8VB7Sq8v4FwUgP7DY_Q.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Borys Palka&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Borys Palka&lt;/strong&gt; is a software developer at Codete. He authored a large part of the front-end of the JupyterLab debugger.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Johan Mabille" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/012-1_y5KkUTTgNArZGajQWW38EA.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Johan Mabille&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Johan Mabille&lt;/strong&gt; is a scientific software developer at QuantStack. Johan is a co-author of xeus, and developed the debugger extension to xeus-python. He also authored a large part of the debugger front-end.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Martin Renou" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/013-1_GafIA37eUPz6XQDTKS6D8A.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Martin Renou&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Martin Renou&lt;/strong&gt; is a scientific software developer at QuantStack. He is the original author of xeus-python, the xeus-based Python kernel, and contributed to the new concurrency model used for the debugger.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Afshin Darian" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/014-1_FEspm1Hcty29Jxwpb-cHXw.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Afshin Darian&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Afshin Darian&lt;/strong&gt; is a software developer at Two Sigma, and one of the authors of JupyterLab.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt="Sylvain Corlay" src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/015-1_aSY0NNigA16fvOHVZCOaeQ.jpeg" loading="lazy" data-body-image=""&gt;
&lt;figcaption&gt;Sylvain Corlay&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;strong&gt;Sylvain Corlay&lt;/strong&gt; is the founder and CEO of QuantStack, and a core Jupyter developer. He co-authored xeus and xeus-python.&lt;/p&gt;
&lt;p class="standalone-image"&gt;&lt;img src="https://blog.jupyter.org/posts/2020/a-visual-debugger-for-jupyter/images/016-1_Trh8fKqP0c_4Vvnzmu5SvA.webp" alt="" loading="lazy" data-body-image=""&gt;&lt;/p&gt;
</content><category term="debugging"/><category term="JupyterLab"/><category term="kernels"/><category term="xeus"/></entry></feed>