Jupyter#

Jupyter is a set of tools for developing and sharing scientific code with description. See the official website.

IPython#

ipython actually exists separately from jupyter. But the most common way to use it as the backend for jupyter notebooks, that’s why this tool udner jupyter section. Find out more at the corresponding page.

Client/kernel#

Jupyter has a client/server architecture. All commands are executed by the server - so called jupyter kernel. Client only sends code to be executed - receives and displays the output.

See more on the corresponding Kernel and Client pages. In some cases you can use the special tool that starts the kernel and connects the client to it jupyter_client.KernelManager.


The following cell shows the creation of the KernelManager instance.

from jupyter_client import KernelManager
km = KernelManager(kernel_name="python3")
km.start_kernel()

kc = km.client()
kc.start_channels()

Kernel is a separate process, to which you can send code you want to execute and wait for the response. The following cell makes exactly that.

kc.execute("print(f'hello from kernel {10 + 99}')", reply=True)
msg = kc.get_iopub_msg()
while True:
   msg = kc.get_iopub_msg(timeout=5)
   if msg['msg_type'] == 'stream':
        break

Once we have received the response, we can check it.

print(msg["content"]["text"])
hello from kernel 109

Expected output for the code we sent to kernel to execute.

Kernel must be shut down:

kc.shutdown(reply=True)
km.shutdown_kernel(now=True)

Jupyter console#

The jupyter console is a minimalistic utility that allows to connect to the jupyter server with command line.

It’s especially handy during kernel debugging. Therefore, the most useful features is connecting to existing jupyter server. Some aspects of jupyter console are:

  • Use --existing <path to the kernel .json> option to connect to the existing jupyter server.

  • Use Ctrl + D to exit the console while leaving the server running.


Due to the limitations of the used jupyter kernel, it is not possible to demonstrate the usage of the jupyter console interactively. Instead, we will just show the command line outputs.

The following code creates an ipykernel server with which a connection will be established using the Jupyter console.

$ python3 -m ipykernel -f /tmp/my_connection.json &
[1] 333000
$ NOTE: When using the `ipython kernel` entry point, Ctrl-C will not work.

To exit, you will have to explicitly quit this process, by either sending
"quit" from a client, or using Ctrl-\ in UNIX-like environments.

To read more about this, see https://github.com/ipython/ipython/issues/2049


To connect another client to this kernel, use:
    --existing /tmp/my_connection.json

$ export server_pid=$!

Here, the connnection to the server with the jupyter console and running some command there.

$ jupyter console --existing /tmp/my_connection.json
Jupyter console 6.6.3

Python 3.13.9 (main, Oct 26 2025, 14:00:38) [GCC 13.3.0]
Type 'copyright', 'credits' or 'license' for more information
IPython 9.6.0 -- An enhanced Interactive Python. Type '?' for help.
Tip: `?` alone on a line will brings up IPython's help

In [1]: print("hello world")
hello world

In [2]:                                                                                                                                                                                                                                                                                                 
Do you really want to exit ([y]/n)? y
keeping kernel alive
(python) fedor@fedor-NUC10i7FNK:~/Documents/code/python$ kill $server_pid

Traitlets#

Traitlets is a tool that allows to make python objects that, automatically check types, autamatically change values of attributes and implement “on change” callbacks. It designed to be used in general, but jet I haven’t seen usage anywhere else except Jupyter project. Check out the traitlest github page. Practically if you want to dive deep into customizing your jupyter workflow you have to learn it.


To get an idea what traitlets are in general consider an example using the traitlets.HasTraits class, which only allows to build classes that automatically validate type, set dynamic default value for the instances and set up methods that will be called in an attemt to change the attribute.

The following cell defines the traitlets.HasTraitlet ancestor with the value attribute, the _default_value method sets up rules which default value value will have, _observe_value is a method that will be callled on an attempt to change the value of value.

import random
import traitlets

class MyFirstTraitlet(traitlets.HasTraits): 
    value = traitlets.Int()

    @traitlets.default("value")
    def _default_value(self):
        return random.randint(1, 100)
    
    @traitlets.observe("value")
    def _observe_value(self, change):
        print(f"Invoked to change: {change["old"]} to {change["new"]}")

The following cell creates the number of MyFirstTraitlet and displays value for them.

for i in range(3):
    obj = MyFirstTraitlet()
    print(obj.value)
56
29
54

Each time there is a different default value for the instance - just as specified in the _default_value method.

The following cell attemts to create MyFirstTrait instance and set value with a str datatype.

try:
    MyFirstTraitlet(value="string")
except Exception as e:
    print(f"Exception: {e}")
Exception: The 'value' trait of a MyFirstTraitlet instance expected an int, not the str 'string'.

But due to the value defined as traitlets.Int it doesn’t allow to set string value to it.

The following cell attempts to change change the value.

traitlet = MyFirstTraitlet()
traitlet.value = 10
Invoked to change: 0 to 10

As a result there will be a message in the output that defined by the _observe_value method.