There is a mode of developing - useful for some things - where you write individuals functions send them to an environment and test them out. This is one of the nice things about Jupyter, and related tools such as org-babel. However sometimes you want to write a script rather than produce a notebook, and force this is can be nice to send code from your editor while you build a script.
Emacs supports this natively with python-shell-send-string but this works with a python shell running natively within emacs - which can be a mess with virtualenvs. Instead I decided to try hacking something up with jupyter/ ipython kernels and it seems to work reasonably well.
With this approach I start an ipython kernel in a virtual env using jupyter kernel then I find the details of this kernel by looking in ~/.local/share/jupyter/runtime/ for the most recent JSON file. I wrote a tiny wrapper in python called jupyter-last-kernel to get this file.
Then I can connect to this from within emacs using emacs-jupyter . This has quite a lot of functionality, but I side-stepped most of this (and the setup that might come with it) by just writing this code:
(defun my-jupyter-connect-last ()
(interactive)
(setq jupyter-current-client (jupyter-connect-repl (s-trim (shell-command-to-string "~/bins/jupytertools/jupyter-last-kernel")))))
(evil-define-operator my-jupyter-send (beg end type)
"Evil operator to replace a region with the current kill"
:move-point nil
(interactive "<r>")
(message (jupyter-eval-string-command (substring-no-properties (buffer-substring beg end)))))
; (jupyter-eval-string-command (buffer-substring beg end)))
(define-key evil-normal-state-map "gYY" 'my-jupyter-send)
(define-key evil-normal-state-map "gYc" 'my-jupyter-connect-last)
so that I can select a region and send it to this ipython kernel, and see the result. (I use the evil vim emulator here - but this code is evil adapted to a โvanillaโ emacs)
You can also connect up and ipython terminal to the backend as well with jupyter console --existing $(jupyter-last-kernel) if you like. This can be useful for debugging when you want a faster evaluation loop.
Hereโs an example of this in use:
Some caveats:
You donโt actually need jupyter to run the kernel, you can use ipython3 kernel instead, which oddly stores its kernel file in the same place as jupyter
There used to be an ipython3 console command - but this seems to have been replaced with jupyter console which again, oddly, connects to ipython kernels.
If you pull up a full jupyter notebook then emacs-jupyter has a command jupyter-server-list-kernels which might be useful.
This blog is mostly about reading ai and obsidian. But if you are interested in emacs org mode you might like to read a bit about Obsidian. And if you are an emacs user who has moved to Obsidian you might like to read about plugin-repl a plugin I wrote that brings some emacs goodness to Obsidian. Orโฆ if you interested in reading, agency and AI you might like to read the whole blog, but I would suggest this page to get a feel.