An interface to communicate with Jupyter kernels in Emacs.
Table of Contents
- What does this package do?
- How do I install this package?
- Related packages
- How do I use the built-in frontends?
What does this package do?
- Provides REPL and
org-modesource block frontends to Jupyter kernels.
- Kernel interactions integrated with Emacs’s built-in features. For
- Inspecting a piece of code under
pointwill display the information for that symbol in the
*Help*buffer. You can re-visit inspection requests made to the kernel by calling
help-go-forwardwhile in the
- Uses the
completion-at-pointinterface for code completion.
- Kernel requests for user input entered through the minibuffer.
- You can search through REPL history using
- Inspecting a piece of code under
How do I install this package?
NOTE: This package relies on the
emacs-zmq package which means your
Emacs needs to have been built with module support. See the README of
that package for more information.
You can install this package with any package manager that allows you to install MELPA packages. For Emacs’s built-in package manager:
- Ensure MELPA is in
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
- Ensure the latest versions of MELPA packages are available
M-x package-refresh-contents RET
- Install Jupyter
M-x package-install RET jupyter RET
For a manual installation you can add the repository directory to your
load-path and ensure the following dependencies are installed:
- markdown-mode (optional)
- company-mode (optional)
(add-to-list 'load-path "~/path/to/jupyter") (require 'jupyter)
Building the widget support (EXPERIMENTAL)
There is limited support for interacting with Jupyter widgets through an external browser. In this case, Emacs acts as a relay for passing messages between the kernel and the browser.
To try it out, install
node (https://nodejs.org/en/) then run the
following shell command from the top-level directory of this project.
After, launch Emacs, connect to a kernel (e.g. through a REPL), and run some code that creates a widget.
How do I run the tests?
You must have Cask installed to be able to run the tests. Once Cask is installed, in the top level directory of this project run the following from the command line
# Install all development dependencies via Cask make dev
Then, to run the tests
# Run the whole set of tests make test # Run tests tagged with org make test TAGS=org # Run tests tagged with org and babel make test TAGS=org,babel # Run tests whose name match a pattern make test PATTERN=font-lock
ein is a complete Jupyter notebook interface in Emacs with many powerful
features for Python kernels. There is some overlap in the features provided by
ein, but I have never used
ein so I cannot speak very
much about any similarities/differences.
How do I use the built-in frontends?
M-x jupyter-run-repl launches a new local kernel and displays a REPL
M-x jupyter-connect-repl connects to an existing kernel using the
kernel’s connection file, which is supplied by the user, and displays
a REPL buffer.
The REPL supports some of the rich output that a kernel may send to a client, e.g. images, LaTeX, and HTML.
Rich kernel output
Below is a table of the supported output mimetypes and their dependencies. If a dependency is not available for a particular mimetype, a mimetype of lower priority gets displayed instead.
For widgets, before attempting to open one, you also need to run the
make widgets in the top-level directory of this project
|Emacs built with libxml2|
|Emacs built with librsvg2|
To inspect the code around
Completion is implemented through the
and should just work.
In addition to completing symbols in the REPL buffer, completion also
works in buffers associated with a REPL. For
org-mode users, there is
even completion in the
org-mode buffer when editing the contents of a
Jupyter source code block.
To navigate the REPL history:
To search the REPL history:
Associating buffers with a REPL (
M-x jupyter-repl-associate-buffer sets the
the current buffer to an existing REPL client and
jupyter-repl-interaction-mode, allowing you to, for example,
send the current line for evaluation by the client’s kernel.
jupyter-repl-interaction-mode is enabled, the following
keybindings are available
emacsclient is set as the
EDITOR and evaluated code opens a file in
major-mode compatible with the client that sent the code, the opened
file will automatically be associated with the client and have
This feature probably wont work correctly when there are multiple
competing clients sending requests to their underlying kernels that
want to open files or if the underlying kernel takes longer
jupyter-long-timeout seconds to open a file.
jupyter-server-mode-set-client for more details.
A variable that determines the maximum number of lines a REPL buffer can have before being truncated.
A variable that determines whether to allow insertion of newlines in a REPL cell when a kernel is busy or not. See the variable documentation for more details.
A variable that determines whether code evaluated with
jupyter-eval-* commands gets copied over to a REPL input cell or
not. You can set this variable to
t if you prefer having the history
of all evaluated code visible in the REPL.
org-mode source blocks
To enable support for Jupyter based source code blocks, add
org-babel-load-languages. Ensure the
jupyter entry is added last
ob-jupyter depends on the value of variables such
(org-babel-do-load-languages 'org-babel-load-languages '((emacs-lisp . t) (julia . t) (python . t) (jupyter . t)))
After loading, source code blocks with names like
jupyter-LANG will be
available for use.
LANG can be any one of the kernel languages found
on your system. See
:sessionparameter is required for all Jupyter based source code blocks.
#+BEGIN_SRC jupyter-python :session py x = 'foo' y = 'bar' x + ' ' + y #+END_SRC
- By default, source blocks are executed synchronously. To execute a
source block asynchronously set the
#+BEGIN_SRC jupyter-python :session py :async yes x = 'foo' y = 'bar' x + ' ' + y #+END_SRC
- To change the kernel, set the
#+BEGIN_SRC jupyter-python :session py :async yes :kernel python2 x = 'foo' y = 'bar' x + ' ' + y #+END_SRC
Note, the same session name can be used for different values of
:kernelsince the underlying REPL buffer’s name is based on both
- Any of the default parameters for a language can be changed by
org-babel-default-header-args:jupyter-LANGto an appropriate value. For example to change the defaults for the
juliakernel, you can set
org-babel-default-header-args:jupyter-juliato something like
(setq org-babel-default-header-args:jupyter-julia '((:async . "yes") (:session . "jl") (:kernel . "julia-1.0")))
Note on the language name provided by a kernelspec
Some kernelspecs use spaces in the name of the kernel language. Those
get replaced by dashes in the language name you need to use for the
corresponding source blocks, e.g.
Wolfram Language has the source
If you have
ob-async installed and are getting errors when your source
block specifies the
:async header argument, try putting something like
the following in your configuration:
(setq ob-async-no-async-languages-alist '("jupyter-python" "jupyter-julia"))
See ob-async-no-async-languages-alist for more details.
ob-ipython and this package are installed, you may experience
issues such as this one, causing
Search failed errors. To avoid such
org-babel-do-load-languages and restart
Overriding built-in src-block languages
Instead of having to specify
jupyter-LANG as a source block name, you
LANG source blocks use the Jupyter machinery. To do so,
place a call to
org-babel-jupyter-override-src-block somewhere in your
config (after the call to
After calling the above function, all
python source blocks are effectively
jupyter-python source blocks and the variable
org-babel-default-header-args:python will be set to the value of
org-babel-default-header-args:python will not be an alias
org-babel-default-header-args:jupyter-python, the value of the
former is merely set to the value of the latter after
You can restore the original behavior by
Rich kernel output
The supported display mimetypes ordered by priority are:
- image/svg+xml, image/jpeg, image/png
A note on using the
:results header argument
There are some cases where the normal result insertion mechanism may
not be wanted. To control result insertion somewhat, use the
- Insert unwrapped LaTeX
- Normally LaTeX results are wrapped in a
BEGIN_EXPORTblock, in order to insert LaTeX unwrapped, specify
- Suppress table creation
- Whenever a result can be converted into an
org-modetable, e.g. when it look like
[1, 2 , 3], it is automatically converted into a table. To suppress this behavior you can specify
Fixing the file name of images with the
Whenever an image result is returned, a random image file name is
generated and the image is written
org-babel-jupyter-resource-directory. To specify your own file name
for the image, set the
:file header argument.
Changing the mime-type priority with the
The priority of mimetypes used to display results can be overwritten using the
:display option. If instead of displaying HTML results we’d wish to display
plain text, the argument
:display text/plain text/html would prioritize plain
text results over html ones. The following example displays plain text instead
#+BEGIN_SRC jupyter-python :session py :display plain import pandas as pd data = [[1, 2], [3, 4]] pd.DataFrame(data, columns=["Foo", "Bar"]) #+END_SRC
Image output without the
:file header argument
For images sent by the kernel, if no
:file parameter is provided to the code
block, a file name is automatically generated based on the image data and the
image is written to file in
org-babel-jupyter-resource-directory. This is
great for quickly generating throw-away plots while you are working on your
code. Once you are happy with your results you can specify the
parameter to fix the file name.
This variable is similar to
org-preview-latex-image-directory but solely for
any files created when Jupyter code blocks are run, e.g. automatically
generated image file names.
Deletion of generated image files
Whenever you run a code block multiple times and replace its results, before
the results are replaced, any generated files will be deleted to reduce the
Convert rich kernel output with the
:pandoc header argument
By default html, markdown, and latex results are wrapped in a
block. If the header argument
:pandoc t is set, they are instead
converted to org-mode format with pandoc. You can control which outputs get
converted with the custom variable
Editing the contents of a code block
When editing a Jupyter code block’s contents, i.e. by pressing
C-c '= when at
a code block, =jupyter-repl-interaction-mode is automatically enabled in the
edit buffer and the buffer will be associated with the REPL session of the code
You may also bind the command
org-babel-jupyter-scratch-buffer to an
appropriate key in
org-mode to display a scratch buffer in the code block’s
major-mode and connected to the code block’s session.
Connecting to an existing kernel
To connect to an existing kernel, pass the kernel’s connection file as the
value of the
:session parameter. The name of the file must have a
suffix for this to work.
If the connection file is a remote file name, i.e. has a prefix like
/method:host:, the kernel’s ports are assumed to live on
attempting to connect to the kernel,
ssh tunnels for the connection are
created. So if you had a remote kernel on a host named
ec2 whose connection
/run/user/1000/jupyter/kernel-julia-0.6.json on that host, you could
#+BEGIN_SRC jupyter-julia :session /ssh:ec2:/run/user/1000/jupyter/kernel-julia-0.6.json ... #+END_SRC
Note, the kernel on the remote host needs to have the ZMQ socket ports exposed. This means that starting a kernel using
jupyter notebook --no-browser
currently doesn’t work since the notebook server does not allow communication with a kernel using ZMQ sockets. You will have to use the connection file created from using something like
jupyter kernel --kernel=python
Password handling for remote connections
Currently there is no password handling, so if your
ssh connection requires a
password I suggest you instead use key-based authentication. Or if you are
connecting to a server using a
pem file add something like
Host ec2 User <user> HostName <host> IdentityFile <identity>.pem
Starting a remote kernel
:session is a remote file name that doesn’t end in
/ssh:ec2:jl, then a kernel on the remote host
/ssh:ec2: is started using
jupyter kernel command on the host. The local part of the session name
serves to distinguish different remote sessions on the same host.
Communicating with kernel (notebook) servers
:session is a TRAMP file name like
/jpy:localhost#8888:NAME it is
interpreted as corresponding to a connection to a kernel through a Jupyter
notebook server located at
NAME is a kernel ID corresponding to an existing kernel on a server,
/jpy::161b2318-180c-497a-b4bf-de76176061d9, then a connection to an
existing kernel with the corresponding ID will be made. Otherwise, a new kernel
will be launched on the server and
NAME will be used as an identifier for the
When a new kernel is launched,
NAME will also be associated with the kernel’s
jupyter-server-kernel-names. This is useful to distinguish Org
:session kernels from other ones in the buffer shown
When connecting to an existing kernel, i.e. when
NAME is the ID of a kernel,
:kernel header argument must match the name of the kernel’s kernelspec.
To connect to a kernel behind an
HTTPS connection, use a TRAMP file name that
Standard output, displayed data, and code block results
One significant difference between Jupyter code blocks and regular
code blocks is that the underlying Jupyter kernel can request that the client
display extra data in addition to output or the result of a code block. See
To account for this, Jupyter code blocks do not go through the normal
org-mode result insertion mechanism (see
downside of this is that, compared to normal code blocks, only a small subset
of the header arguments common to all code blocks are supported. The upside is
that all forms of results produced by a kernel can be inserted into the buffer
similar to a Jupyter notebook.
The implementation of
org-mode code blocks is really meant to handle either
capturing the standard output or the result of a code block. When using
Jupyter code blocks, if the kernel produces output or asks to display extra
information, the results are appended to a
A minor mode that enables completion and custom keybindings when
inside a Jupyter code block. This mode is enabled by default in
buffers, but only has an effect when
point is inside a Jupyter code block.
Custom keybindings inside Jupyter code blocks
You can define new keybindings that are enabled when
point is inside a
Jupyter code block by using the function
bindings are added to
jupyter-org-interaction-mode-map and are only active
jupyter-org-interaction-mode is enabled.
By default the following keybindings from
jupyter-org-interaction-mode is enabled
Managing live kernels
The main entry point for working with a kernel server is the
jupyter-server-list-kernels command which shows a list of all live kernels
from the server URL that you provide when first calling the command. Any
subsequent calls to the command will use the same URL as the first call. To
change server URLs give a prefix argument,
C-u M-x jupyter-server-list-kernels. This
will then set the current server URL for future calls to the one you provide.
jupyter-current-server command for more details.
From the buffer shown by
jupyter-server-list-kernels you can launch new kernels
C-RET), connect a REPL to an existing kernel (
RET), interrupt a kernel
C-c TAB), kill a kernel (
C-c C-d or
d), refresh the list of kernels (
jupyter-server-kernel-list-mode for all the available key bindings.
default-directory of the
will be the root directory of the kernel server (so that
dired-jump will show
dired listing of the directory). See the section on TRAMP integration
jupyter-server-list-kernels buffer one can also name (or rename) a
R) so that it has an identifier other than its ID. Naming a kernel adds
the name to the
jupyter-server-kernel-names global variable in a form suitable
for persisting across Emacs sessions. See its documentation for more details
about persisting its value.
There is also integration with the Jupyter notebook contents API in the form of
a TRAMP backend. This means that reading/writing the contents of directories
the notebook server has access to can be done using normal Emacs file
operations using file names with TRAMP syntax. Two new TRAMP file name methods
jpy for HTTP connections and
jpys for HTTPS connections. So
suppose you have a local notebook server at http://localhost:8888, then to
access its directory contents you can type
M-x dired RET /jpy:localhost#8888:/
localhost is the default host and
8888 is the default port so
is equivalent to
/jpy:localhost#8888:. You can change the defaults by
jpys methods in the variable
Authentication method used for new notebook server connections. By default, when connecting to a new notebook server you will be asked if either a password or a token should be used for authentication. If you only use tokens for authentication you can change this variable to avoid being asked on every new connection.
Customizable variables available for all frontends
When non-nil, display the
text/plain representation of evaluation
results inline using overlays. All other representations are
displayed in the usual way. This only works with the
You can control the appearance of the overlay,
jupyter-eval-overlay-prefix and the
To clear all overlays from the buffer,
jupyter-eval-remove-overlays to some key. Its bound to
jupyter-repl-interaction-mode is enabled. Individual overlays
are removed whenever the text in the region that was evaluated is
For multi-line overlays you can fold/unfold the overlay by
point is inside the region of code that caused the
overlay to be created. See
If the number of lines of an evaluation result is smaller than this
variable, the function stored
jupyter-eval-short-result-display-function is used to display a