mirror of
https://github.com/vale981/emacs-jupyter
synced 2025-03-06 07:51:39 -05:00
Remove jupyter-connection.el
This commit is contained in:
parent
17a09d5ac8
commit
9d801b72a3
4 changed files with 0 additions and 303 deletions
|
@ -1,299 +0,0 @@
|
||||||
;;; jupyter-connection.el --- Linking kernels and clients -*- lexical-binding: t -*-
|
|
||||||
|
|
||||||
;; Copyright (C) 2020 Nathaniel Nicandro
|
|
||||||
|
|
||||||
;; Author: Nathaniel Nicandro <nathanielnicandro@gmail.com>
|
|
||||||
;; Created: 21 Apr 2020
|
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or
|
|
||||||
;; modify it under the terms of the GNU General Public License as
|
|
||||||
;; published by the Free Software Foundation; either version 3, or (at
|
|
||||||
;; your option) any later version.
|
|
||||||
|
|
||||||
;; This program is distributed in the hope that it will be useful, but
|
|
||||||
;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
;; General Public License for more details.
|
|
||||||
|
|
||||||
;; You should have received a copy of the GNU General Public License
|
|
||||||
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
|
||||||
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
;; Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
;;; Commentary:
|
|
||||||
|
|
||||||
;; This file defines the `jupyter-connect' function used to connect a
|
|
||||||
;; client to a kernel.
|
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; Before a client and kernel can be connected, a connection to a
|
|
||||||
;; kernel must be made to get at the
|
|
||||||
|
|
||||||
;; This file defines the `jupyter-connection' method which takes a
|
|
||||||
;; kernel and a client and returns an instance of the
|
|
||||||
;; `jupyter-connection' struct type, representing the set of IO
|
|
||||||
;; actions and state transformations required to establish
|
|
||||||
;; communication between a kernel and a client.
|
|
||||||
|
|
||||||
;;; Code:
|
|
||||||
|
|
||||||
(require 'jupyter-kernel)
|
|
||||||
(require 'jupyter-client)
|
|
||||||
(require 'thunk)
|
|
||||||
|
|
||||||
(defgroup jupyter-connection nil
|
|
||||||
"Linking kernels and clients"
|
|
||||||
:group 'jupyter)
|
|
||||||
|
|
||||||
(defvar jupyter-connections (make-hash-table :weakness 'key)
|
|
||||||
"A cache for Jupyter kernel connections.
|
|
||||||
The keys are objects like kernels, clients, and other auxiliary
|
|
||||||
objects. The values are lists whose elements are related in some
|
|
||||||
way to connecting clients to kernels in the current Emacs
|
|
||||||
session.
|
|
||||||
|
|
||||||
This table is used by `jupyter-io' to store the connection lists
|
|
||||||
returned by `jupyter-connection'. It is also used by
|
|
||||||
`jupyter-connect' to keep track of the kernel a client is
|
|
||||||
connected to.")
|
|
||||||
|
|
||||||
;; FIXME: Remove the channel argument
|
|
||||||
(cl-defmethod jupyter-alive-p ((io function) &optional _channel)
|
|
||||||
"Return non-nil if CONN is live."
|
|
||||||
(jupyter-send io 'alive-p))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-start ((io function) &optional _channel)
|
|
||||||
(jupyter-send io 'start))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-stop ((io function) &optional _channel)
|
|
||||||
(jupyter-send io 'stop))
|
|
||||||
|
|
||||||
;;;; `jupyter-connection'
|
|
||||||
|
|
||||||
(defmacro jupyter-run-handlers (place event)
|
|
||||||
"Evaluate the list of functions in PLACE using ARGS.
|
|
||||||
Set PLACE to those functions that returned non-nil."
|
|
||||||
`(setf ,place
|
|
||||||
(let ((handlers ,place)
|
|
||||||
(event ,event)
|
|
||||||
(new-handlers '()))
|
|
||||||
(while handlers
|
|
||||||
(let ((h (pop handlers)))
|
|
||||||
(when (funcall h event)
|
|
||||||
(push h new-handlers))))
|
|
||||||
new-handlers)))
|
|
||||||
|
|
||||||
(cl-defgeneric jupyter-connection (thing)
|
|
||||||
"Establish a connection to THING.
|
|
||||||
Return a list (IO ...), where IO is a function used to perform
|
|
||||||
I/O actions on THING, the rest of the list is ignored.
|
|
||||||
|
|
||||||
IO takes arguments like (TYPE ARGS...) where TYPE is a symbol
|
|
||||||
describing the type of I/O action/query that ARGS are parameters
|
|
||||||
to.
|
|
||||||
|
|
||||||
This method should not be called directly, use `jupyter-io'.
|
|
||||||
|
|
||||||
At a minimum, IO should accept to the following sets of I/O
|
|
||||||
actions/queries:
|
|
||||||
|
|
||||||
* Connection lifetime
|
|
||||||
|
|
||||||
- ('start) :: Enable I/O.
|
|
||||||
- ('stop) :: Disable I/O.
|
|
||||||
- ('alive-p &optional CHANNEL) :: Return non-nil if I/O
|
|
||||||
connection is live. If CHANNEL is specified and the I/O
|
|
||||||
connection resolves individual channels, return non-nil if
|
|
||||||
CHANNEL is live.
|
|
||||||
|
|
||||||
* Message sending/receiving
|
|
||||||
|
|
||||||
- ('send ARGS...) :: Send ARGS as a message to THING.
|
|
||||||
|
|
||||||
- ('add-handler FN) :: Add FN, a function, as a handler of
|
|
||||||
messages received from THING.
|
|
||||||
|
|
||||||
- ('remove-handler FN) :: Remove FN as a handler.
|
|
||||||
|
|
||||||
'send and 'add-handler are also responsible for enabling the
|
|
||||||
connection if it has not been already.
|
|
||||||
|
|
||||||
* Heartbeat channel [1]
|
|
||||||
|
|
||||||
- ('hb) :: Return a `jupyter-hb-channel' or nil if the
|
|
||||||
connection does not support one.
|
|
||||||
|
|
||||||
\[1] https://jupyter-client.readthedocs.io/en/stable/messaging.html#heartbeat-for-kernels")
|
|
||||||
|
|
||||||
(declare-function jupyter-kernel-process "ext:jupyter-kernel-process")
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-connection ((kernel jupyter-kernel))
|
|
||||||
"Return a default connection list for KERNEL."
|
|
||||||
(list
|
|
||||||
(lambda (&rest args)
|
|
||||||
(pcase (car args)
|
|
||||||
((or 'start 'stop 'alive-p))
|
|
||||||
((or 'message 'add-handler 'remove-handler) (error "Not implemented"))
|
|
||||||
('hb nil)
|
|
||||||
(_ (error "Unhandled IO: %s" args))))))
|
|
||||||
|
|
||||||
;; Kernel -> IO Kernel-IO
|
|
||||||
(cl-defmethod jupyter-connect ((kernel jupyter-kernel))
|
|
||||||
;; Any -> IO Kernel-IO
|
|
||||||
(jupyter-launch kernel)
|
|
||||||
(jupyter-return (jupyter-io kernel)))
|
|
||||||
|
|
||||||
;; Client -> IO Client
|
|
||||||
(cl-defmethod jupyter-connect ((client jupyter-kernel-client))
|
|
||||||
;; Any -> IO Client-IO
|
|
||||||
(lambda (_)
|
|
||||||
(let ((io (jupyter-io (jupyter-kernel client))))
|
|
||||||
(jupyter-return
|
|
||||||
(lambda (&rest args)
|
|
||||||
(let ((jupyter-current-client client))
|
|
||||||
(apply io args)))))))
|
|
||||||
|
|
||||||
(defun jupyter-io (thing)
|
|
||||||
"Return a function that can be used to perform I/O with THING.
|
|
||||||
THING must implement both `jupyter-alive-p' and
|
|
||||||
`jupyter-connection'. If THING is not alive an error is
|
|
||||||
signaled, otherwise the connection of THING is cached and the I/O
|
|
||||||
function returned.
|
|
||||||
|
|
||||||
The function takes arguments like (TYPE ARGS...) where TYPE is a
|
|
||||||
symbol describing the type of I/O action/query that ARGS are
|
|
||||||
parameters to."
|
|
||||||
(cl-assert (jupyter-alive-p thing))
|
|
||||||
(pcase-let ((`(,io . ,_)
|
|
||||||
(or (gethash thing jupyter-connections)
|
|
||||||
(puthash thing (jupyter-connection thing)
|
|
||||||
jupyter-connections))))
|
|
||||||
io))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-send ((io function) &rest args)
|
|
||||||
"Send ARGS on IO."
|
|
||||||
(apply io args))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-send ((kernel jupyter-kernel) &rest args)
|
|
||||||
"Send a message to KERNEL.
|
|
||||||
Any associated messages will be received by KERNEL's handlers.
|
|
||||||
See `jupyter-connection' for how a handler can be added."
|
|
||||||
(apply (jupyter-io kernel) 'message args))
|
|
||||||
|
|
||||||
;; `jupyter-connection' is an example of a monad that passes monadic
|
|
||||||
;; values like (IO ....), where ... is the context, mainly finalizers,
|
|
||||||
;; of the IO connection functions. `jupyter-connection' is actually
|
|
||||||
;; taking a monadic value and returning another monadic value.
|
|
||||||
;;
|
|
||||||
;; TODO I need to have a bind like function that I can use here. That
|
|
||||||
;; way I can probably get rid of the boiler plate. The bind function
|
|
||||||
;; takes the IO function and wraps it with another one, and returns a
|
|
||||||
;; new list like what is being done here. Mapping from one category to
|
|
||||||
;; another.
|
|
||||||
;;
|
|
||||||
;; Can't be :extra since we don't know when those files will be loaded
|
|
||||||
|
|
||||||
(defun jupyter-with-client-handlers (io)
|
|
||||||
"Return an I/O function that can take clients as handlers.
|
|
||||||
The returned function allows the argument to the 'add-handler and
|
|
||||||
'remove-handler I/O actions to take `jupyter-kernel-client'
|
|
||||||
objects.
|
|
||||||
|
|
||||||
All other I/O actions are passed through to IO."
|
|
||||||
(let ((handlers (make-hash-table :weakness 'key)))
|
|
||||||
(cl-macrolet ((kernel-io (&rest args)
|
|
||||||
(if (eq (car (last args)) 'args)
|
|
||||||
`(apply io ,@args)
|
|
||||||
`(funcall io ,@args))))
|
|
||||||
(cl-labels
|
|
||||||
((handler
|
|
||||||
(client)
|
|
||||||
;; Make a weak ref. to CLIENT so that remhandler, below,
|
|
||||||
;; will be called if CLIENT is not disconnected before being
|
|
||||||
;; garbage collected.
|
|
||||||
(letrec
|
|
||||||
((ref (jupyter-weak-ref client))
|
|
||||||
(h (lambda (event)
|
|
||||||
;; FIXME: Handle the `sent' event, but not here.
|
|
||||||
;; How can I get rid of it?
|
|
||||||
(pcase (car event)
|
|
||||||
((and 'message (let `(,channel ,_idents . ,msg) (cdr event)))
|
|
||||||
(if-let ((client (jupyter-weak-ref-resolve ref)))
|
|
||||||
(jupyter-handle-message client channel msg)
|
|
||||||
(kernel-io 'remove-handler h)))))))
|
|
||||||
h)))
|
|
||||||
(list
|
|
||||||
(lambda (&rest args)
|
|
||||||
(pcase args
|
|
||||||
(`(,(and (or 'add-handler 'remove-handler) action)
|
|
||||||
,(and (guard (object-of-class-p (cadr args) 'jupyter-kernel-client))
|
|
||||||
(let client (cadr args))))
|
|
||||||
(let ((h (gethash client handlers)))
|
|
||||||
(pcase action
|
|
||||||
((and 'add-handler (guard (not h)))
|
|
||||||
(kernel-io action (setf (gethash client handlers) (handler client))))
|
|
||||||
((and 'remove-handler (guard h))
|
|
||||||
(kernel-io action (progn (remhash client handlers) h))))))
|
|
||||||
(_ (kernel-io args)))))))))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-connection :around ((kernel jupyter-kernel))
|
|
||||||
(jupyter-bind (cl-call-next-method) #'jupyter-with-client-handlers))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-connect ((client jupyter-kernel-client) (kernel jupyter-kernel))
|
|
||||||
"Connect CLIENT to KERNEL.
|
|
||||||
When CLIENT has been connected to KERNEL, it handles messages
|
|
||||||
KERNEL sends to its clients. Return an I/O function that can be
|
|
||||||
used to send messages to KERNEL.
|
|
||||||
|
|
||||||
The connection exists as long as CLIENT exists or until CLIENT is
|
|
||||||
connected to a different kernel. The connection of a client can
|
|
||||||
be removed manually with `jupyter-disconnect'.
|
|
||||||
|
|
||||||
See `jupyter-connection' for more info. on the I/O function."
|
|
||||||
(jupyter-disconnect client)
|
|
||||||
(jupyter-launch kernel)
|
|
||||||
(let ((io (jupyter-io kernel)))
|
|
||||||
(jupyter-send io 'add-handler client)
|
|
||||||
(puthash client (list kernel) jupyter-connections)
|
|
||||||
io))
|
|
||||||
(cl-defmethod jupyter-connect ((kernel jupyter-kernel) (client jupyter-kernel-client))
|
|
||||||
(jupyter-connect client kernel))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-disconnect ((client jupyter-kernel-client))
|
|
||||||
"Disconnect CLIENT from its kernel, if any."
|
|
||||||
(when-let* ((kernel (car (gethash client jupyter-connections))))
|
|
||||||
(jupyter-send (jupyter-io kernel) 'remove-handler client)
|
|
||||||
(remhash client jupyter-connections)))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-kernel ((client jupyter-kernel-client))
|
|
||||||
"Return the kernel CLIENT is connected to.
|
|
||||||
Return nil if CLIENT is not connected to any kernel."
|
|
||||||
(let ((kernel (car (gethash client jupyter-connections))))
|
|
||||||
kernel))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-clients ((kernel jupyter-kernel))
|
|
||||||
"Return a list of clients KERNEL is connected to."
|
|
||||||
(let ((clients '()))
|
|
||||||
(maphash (lambda (k v)
|
|
||||||
(when (and (eieio-object-p k)
|
|
||||||
(object-of-class-p k 'jupyter-kernel-client)
|
|
||||||
(memq kernel v))
|
|
||||||
(push k clients)))
|
|
||||||
jupyter-connections)
|
|
||||||
clients))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-disconnect ((kernel jupyter-kernel))
|
|
||||||
"Disconnect all clients of KERNEL."
|
|
||||||
(cl-loop for client in (jupyter-clients kernel)
|
|
||||||
do (jupyter-disconnect client)))
|
|
||||||
|
|
||||||
(cl-defmethod jupyter-shutdown :extra "IO" ((kernel jupyter-kernel))
|
|
||||||
"Stop KERNEL's I/O connections."
|
|
||||||
(jupyter-disconnect kernel)
|
|
||||||
(when (jupyter-alive-p kernel)
|
|
||||||
(jupyter-stop (jupyter-io kernel)))
|
|
||||||
(cl-call-next-method))
|
|
||||||
|
|
||||||
(provide 'jupyter-connection)
|
|
||||||
|
|
||||||
;;; jupyter-connection.el ends here
|
|
|
@ -57,7 +57,6 @@
|
||||||
(eval-when-compile (require 'subr-x))
|
(eval-when-compile (require 'subr-x))
|
||||||
(require 'jupyter-base)
|
(require 'jupyter-base)
|
||||||
(require 'jupyter-mime)
|
(require 'jupyter-mime)
|
||||||
(require 'jupyter-connection)
|
|
||||||
(require 'jupyter-kernelspec)
|
(require 'jupyter-kernelspec)
|
||||||
(require 'jupyter-widget-client)
|
(require 'jupyter-widget-client)
|
||||||
(require 'ring)
|
(require 'ring)
|
||||||
|
|
|
@ -54,8 +54,6 @@ Used in, e.g. a `jupyter-server-kernel-list-mode' buffer.")
|
||||||
;; communication channel with one.
|
;; communication channel with one.
|
||||||
(defclass jupyter-server (jupyter-rest-client eieio-instance-tracker)
|
(defclass jupyter-server (jupyter-rest-client eieio-instance-tracker)
|
||||||
((tracking-symbol :initform 'jupyter--servers)
|
((tracking-symbol :initform 'jupyter--servers)
|
||||||
(conn :type jupyter-connection)
|
|
||||||
(handlers :type list :initform nil)
|
|
||||||
(kernelspecs
|
(kernelspecs
|
||||||
:type json-plist
|
:type json-plist
|
||||||
:initform nil
|
:initform nil
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
|
|
||||||
(require 'zmq)
|
(require 'zmq)
|
||||||
(require 'jupyter-zmq-channel-ioloop)
|
(require 'jupyter-zmq-channel-ioloop)
|
||||||
(require 'jupyter-connection)
|
|
||||||
(require 'jupyter-kernel-process)
|
(require 'jupyter-kernel-process)
|
||||||
(require 'jupyter-repl)
|
(require 'jupyter-repl)
|
||||||
(require 'jupyter-org-client)
|
(require 'jupyter-org-client)
|
||||||
|
|
Loading…
Add table
Reference in a new issue