mirror of
https://github.com/vale981/emacs-jupyter
synced 2025-03-04 15:41:37 -05:00
Move server slot of jupyter-server-kernel-manager
to the kernel object
This commit is contained in:
parent
9fe99744fd
commit
239715919f
3 changed files with 76 additions and 68 deletions
|
@ -129,17 +129,27 @@ Access should be done through `jupyter-available-kernelspecs'.")))
|
|||
|
||||
;; TODO: Add the server as a slot
|
||||
(defclass jupyter-server-kernel (jupyter-meta-kernel)
|
||||
((id
|
||||
((server
|
||||
:type jupyter-server
|
||||
:initarg :server
|
||||
:documentation "The kernel server.")
|
||||
(id
|
||||
:type string
|
||||
:initarg :id
|
||||
:documentation "The kernel ID.")))
|
||||
|
||||
(cl-defmethod jupyter-kernel-alive-p ((kernel jupyter-server-kernel))
|
||||
(slot-boundp kernel 'id))
|
||||
(and (slot-boundp kernel 'id)
|
||||
(slot-boundp kernel 'server)
|
||||
;; TODO: Cache this call
|
||||
(condition-case err
|
||||
(jupyter-api-get-kernel (oref kernel server) (oref kernel id))
|
||||
(jupyter-api-http-error
|
||||
(unless (= (cadr err) 404) ; Not Found
|
||||
(signal (car err) (cdr err)))))))
|
||||
|
||||
(cl-defmethod jupyter-start-kernel ((kernel jupyter-server-kernel) server &rest _ignore)
|
||||
(cl-check-type server jupyter-server)
|
||||
(with-slots (spec) kernel
|
||||
(cl-defmethod jupyter-start-kernel ((kernel jupyter-server-kernel) &rest _ignore)
|
||||
(with-slots (server spec) kernel
|
||||
(jupyter-server--verify-kernelspec server spec)
|
||||
(cl-destructuring-bind (&key id &allow-other-keys)
|
||||
(jupyter-api-start-kernel server (car spec))
|
||||
|
@ -150,8 +160,7 @@ Access should be done through `jupyter-available-kernelspecs'.")))
|
|||
(ignore))
|
||||
|
||||
(defclass jupyter-server-kernel-comm (jupyter-comm-layer)
|
||||
((server :type jupyter-server :initarg :server)
|
||||
(kernel :type jupyter-server-kernel :initarg :kernel)))
|
||||
((kernel :type jupyter-server-kernel :initarg :kernel)))
|
||||
|
||||
(cl-defmethod jupyter-comm-id ((comm jupyter-server-kernel-comm))
|
||||
(format "kid=%s" (truncate-string-to-width
|
||||
|
@ -280,30 +289,33 @@ The kernelspecs are returned in the same form as returned by
|
|||
If SERVER receives events that have the same kernel ID as the
|
||||
kernel associated with COMM, then COMM's `jupyter-event-handler'
|
||||
will receive those events."
|
||||
(with-slots (server) comm
|
||||
(with-slots (server) (oref comm kernel)
|
||||
(jupyter-comm-start server)
|
||||
(jupyter-connect-client server comm)))
|
||||
|
||||
(cl-defmethod jupyter-comm-stop ((comm jupyter-server-kernel-comm) &rest _ignore)
|
||||
"Disconnect COMM from receiving server events."
|
||||
(jupyter-disconnect-client (oref comm server) comm))
|
||||
(jupyter-disconnect-client (oref (oref comm kernel) server) comm))
|
||||
|
||||
(cl-defmethod jupyter-send ((comm jupyter-server-kernel-comm) event-type &rest event)
|
||||
"Use COMM to send an EVENT to the server with type, EVENT-TYPE.
|
||||
SERVER will direct EVENT to the right kernel based on the kernel
|
||||
ID of the kernel associated with COMM."
|
||||
(with-slots (server kernel) comm
|
||||
(apply #'jupyter-send server event-type (oref kernel id) event)))
|
||||
(with-slots (kernel) comm
|
||||
(unless (jupyter-comm-alive-p comm)
|
||||
(jupyter-comm-start comm))
|
||||
(apply #'jupyter-send (oref kernel server) event-type (oref kernel id) event)))
|
||||
|
||||
(cl-defmethod jupyter-comm-alive-p ((comm jupyter-server-kernel-comm))
|
||||
"Return non-nil if COMM can receive server events for its associated kernel."
|
||||
(and (jupyter-server-kernel-connected-p
|
||||
(oref comm server)
|
||||
(oref (oref comm kernel) id))
|
||||
(catch 'member
|
||||
(jupyter-comm-client-loop (oref comm server) client
|
||||
(when (eq client comm)
|
||||
(throw 'member t))))))
|
||||
(with-slots (kernel) comm
|
||||
(and (jupyter-server-kernel-connected-p
|
||||
(oref kernel server)
|
||||
(oref kernel id))
|
||||
(catch 'member
|
||||
(jupyter-comm-client-loop (oref kernel server) client
|
||||
(when (eq client comm)
|
||||
(throw 'member t)))))))
|
||||
|
||||
;; TODO: Remove the need for these methods, they are remnants from an older
|
||||
;; implementation. They will need to be removed from `jupyter-kernel-client'.
|
||||
|
@ -316,22 +328,18 @@ ID of the kernel associated with COMM."
|
|||
;;;; `jupyter-server-kernel-manager'
|
||||
|
||||
(defclass jupyter-server-kernel-manager (jupyter-kernel-manager-base)
|
||||
((server :type jupyter-server :initarg :server)
|
||||
(kernel :type jupyter-server-kernel :initarg :kernel)
|
||||
((kernel :type jupyter-server-kernel :initarg :kernel)
|
||||
(comm :type jupyter-server-kernel-comm)))
|
||||
|
||||
(cl-defmethod jupyter-comm-start ((manager jupyter-server-kernel-manager))
|
||||
"Start a websocket connection to MANAGER's kernel.
|
||||
MANAGER's COMM slot will be set to the `jupyter-comm-layer'
|
||||
receiving events on the websocket when this method returns."
|
||||
(with-slots (kernel server) manager
|
||||
(with-slots (kernel comm) manager
|
||||
(unless (slot-boundp manager 'comm)
|
||||
(oset manager comm (jupyter-server-kernel-comm
|
||||
:kernel kernel
|
||||
:server server)))
|
||||
(with-slots (comm) manager
|
||||
(unless (jupyter-comm-alive-p comm)
|
||||
(jupyter-comm-start comm)))))
|
||||
(oset manager comm (jupyter-server-kernel-comm :kernel kernel)))
|
||||
(unless (jupyter-comm-alive-p comm)
|
||||
(jupyter-comm-start comm))))
|
||||
|
||||
(cl-defmethod jupyter-comm-stop ((manager jupyter-server-kernel-manager))
|
||||
"Stop a websocket connection to MANAGER's kernel."
|
||||
|
@ -341,30 +349,29 @@ receiving events on the websocket when this method returns."
|
|||
(jupyter-comm-stop comm)))))
|
||||
|
||||
(cl-defmethod jupyter-kernel-alive-p ((manager jupyter-server-kernel-manager))
|
||||
(with-slots (server kernel) manager
|
||||
(and (jupyter-kernel-alive-p kernel)
|
||||
(ignore-errors (jupyter-api-get-kernel server (oref kernel id))))))
|
||||
(jupyter-kernel-alive-p (oref manager kernel)))
|
||||
|
||||
(cl-defmethod jupyter-start-kernel ((manager jupyter-server-kernel-manager) &rest _ignore)
|
||||
"Ensure that the gateway can receive events from its kernel."
|
||||
(with-slots (server kernel) manager
|
||||
(with-slots (kernel) manager
|
||||
(unless (jupyter-kernel-alive-p kernel)
|
||||
(jupyter-start-kernel kernel server))
|
||||
(jupyter-start-kernel kernel))
|
||||
(jupyter-comm-start manager)))
|
||||
|
||||
(cl-defmethod jupyter-interrupt-kernel ((manager jupyter-server-kernel-manager))
|
||||
(with-slots (server kernel) manager
|
||||
(jupyter-api-interrupt-kernel server (oref kernel id))))
|
||||
(with-slots (kernel) manager
|
||||
(jupyter-api-interrupt-kernel (oref kernel server) (oref kernel id))))
|
||||
|
||||
(cl-defmethod jupyter-kill-kernel ((manager jupyter-server-kernel-manager))
|
||||
(jupyter-shutdown-kernel manager))
|
||||
|
||||
(cl-defmethod jupyter-shutdown-kernel ((manager jupyter-server-kernel-manager) &optional restart _timeout)
|
||||
(with-slots (server kernel comm) manager
|
||||
(if restart (jupyter-api-restart-kernel server (oref kernel id))
|
||||
(jupyter-comm-stop manager)
|
||||
(when (jupyter-kernel-alive-p manager)
|
||||
(jupyter-api-shutdown-kernel server (oref kernel id))))))
|
||||
(with-slots (kernel) manager
|
||||
(let ((server (oref kernel server)))
|
||||
(if restart (jupyter-api-restart-kernel server (oref kernel id))
|
||||
(jupyter-comm-stop manager)
|
||||
(when (jupyter-kernel-alive-p manager)
|
||||
(jupyter-api-shutdown-kernel server (oref kernel id)))))))
|
||||
|
||||
(cl-defmethod jupyter-make-client ((manager jupyter-server-kernel-manager) _class &rest _slots)
|
||||
(let ((client (cl-call-next-method)))
|
||||
|
@ -380,9 +387,10 @@ Return nil if none could be found."
|
|||
(cl-loop
|
||||
for manager in (jupyter-kernel-managers)
|
||||
thereis (and (cl-typep manager 'jupyter-server-kernel-manager)
|
||||
(eq (oref manager server) server)
|
||||
(jupyter-kernel-alive-p manager)
|
||||
(equal (oref (oref manager kernel) id) id)
|
||||
(with-slots (kernel) manager
|
||||
(and (eq (oref kernel server) server)
|
||||
(equal (oref kernel id) id)))
|
||||
manager)))
|
||||
|
||||
(defun jupyter-find-server (url &optional ws-url)
|
||||
|
@ -475,6 +483,7 @@ a URL."
|
|||
'jupyter-server-kernel-comm)
|
||||
(thread-first jupyter-current-client
|
||||
(oref kcomm)
|
||||
(oref kernel)
|
||||
(oref server))))
|
||||
;; Server of the current TRAMP remote context
|
||||
((and (file-remote-p default-directory)
|
||||
|
@ -531,10 +540,9 @@ see ‘jupyter-make-client’."
|
|||
(or client-class (setq client-class 'jupyter-kernel-client))
|
||||
(let* ((specs (jupyter-server-kernelspecs server))
|
||||
(kernel (jupyter-server-kernel
|
||||
:server server
|
||||
:spec (jupyter-guess-kernelspec kernel-name specs)))
|
||||
(manager (jupyter-server-kernel-manager
|
||||
:server server
|
||||
:kernel kernel)))
|
||||
(manager (jupyter-server-kernel-manager :kernel kernel)))
|
||||
;; Needs to be started before calling `jupyter-make-client' since that
|
||||
;; method will send a request to start a websocket channel to the kernel.
|
||||
;; FIXME: This should be done in a `jupyter-initialize-connection' method,
|
||||
|
@ -599,13 +607,12 @@ the same meaning as in `jupyter-connect-repl'."
|
|||
(let* ((specs (jupyter-server-kernelspecs server))
|
||||
(manager
|
||||
(or (jupyter-server-find-manager server kernel-id)
|
||||
(let* ((model (jupyter-api-get-kernel server kernel-id))
|
||||
(kernel (jupyter-server-kernel
|
||||
:id kernel-id
|
||||
:spec (assoc (plist-get model :name) specs))))
|
||||
(let ((model (jupyter-api-get-kernel server kernel-id)))
|
||||
(jupyter-server-kernel-manager
|
||||
:server server
|
||||
:kernel kernel))))
|
||||
:kernel (jupyter-server-kernel
|
||||
:id kernel-id
|
||||
:server server
|
||||
:spec (assoc (plist-get model :name) specs))))))
|
||||
(client (jupyter-make-client manager client-class)))
|
||||
(jupyter-start-channels client)
|
||||
(jupyter-bootstrap-repl client repl-name associate-buffer display)))
|
||||
|
|
|
@ -250,7 +250,6 @@
|
|||
(should (jupyter-api-get-kernel server id))
|
||||
(ert-info ("Connecting kernel comm to server")
|
||||
(let ((kcomm (jupyter-server-kernel-comm
|
||||
:server server
|
||||
:kernel kernel)))
|
||||
(should-not (jupyter-server-kernel-connected-p server id))
|
||||
(jupyter-connect-client server kcomm)
|
||||
|
@ -261,7 +260,6 @@
|
|||
(should (jupyter-comm-alive-p server))))
|
||||
(ert-info ("Connecting kernel comm starts server comm if necessary")
|
||||
(let ((kcomm (jupyter-server-kernel-comm
|
||||
:server server
|
||||
:kernel kernel)))
|
||||
(jupyter-comm-stop server)
|
||||
(should-not (jupyter-comm-alive-p server))
|
||||
|
@ -274,30 +272,32 @@
|
|||
|
||||
(ert-deftest jupyter-server-kernel ()
|
||||
:tags '(kernel server)
|
||||
(let ((kernel (jupyter-server-kernel)))
|
||||
(should-not (slot-boundp kernel 'id))
|
||||
(should-not (jupyter-kernel-alive-p kernel))
|
||||
;; TODO: How should this work? Pass the server as an argument?
|
||||
(should-error (jupyter-start-kernel kernel))
|
||||
(ert-info ("ID slot as a proxy for kernel liveness")
|
||||
(jupyter-test-with-notebook server
|
||||
(let ((kernel (jupyter-server-kernel
|
||||
:server server
|
||||
:spec (jupyter-guess-kernelspec
|
||||
"python" (jupyter-server-kernelspecs server)))))
|
||||
(should (slot-boundp kernel 'server))
|
||||
(should (eq (oref kernel server) server))
|
||||
(should-not (slot-boundp kernel 'id))
|
||||
(should-not (jupyter-kernel-alive-p kernel))
|
||||
(oset kernel id "foobar")
|
||||
;; FIXME: There is actually nowhere in the code where the ID slot is made
|
||||
;; unbound since the event handler of the server relies on the ID slot,
|
||||
;; but if the kernel is shutdown the necessary communication layer
|
||||
;; connections are removed.
|
||||
(should (jupyter-kernel-alive-p kernel)))
|
||||
(ert-info ("Force killing a server kernel isn't possible")
|
||||
(should-error (jupyter-kill-kernel kernel)))))
|
||||
(jupyter-start-kernel kernel)
|
||||
(should (slot-boundp kernel 'id))
|
||||
(let ((id (oref kernel id)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(should (jupyter-api-get-kernel server id))
|
||||
(should (jupyter-kernel-alive-p kernel)))
|
||||
(jupyter-api-shutdown-kernel server id))))))
|
||||
|
||||
(ert-deftest jupyter-server-kernel-manager ()
|
||||
:tags '(server)
|
||||
(jupyter-test-with-notebook server
|
||||
(let* ((kernel (jupyter-server-kernel
|
||||
:server server
|
||||
:spec (jupyter-guess-kernelspec
|
||||
"python" (jupyter-server-kernelspecs server))))
|
||||
(manager (jupyter-server-kernel-manager
|
||||
:server server
|
||||
:kernel kernel)))
|
||||
(should-not (jupyter-kernel-alive-p manager))
|
||||
(jupyter-start-kernel manager)
|
||||
|
|
|
@ -350,9 +350,10 @@ For `url-retrieve', the callback will be called with a nil status."
|
|||
(declare (indent 3))
|
||||
(let ((id (make-symbol "id")))
|
||||
`(let ((,kernel (jupyter-server-kernel
|
||||
:server server
|
||||
:spec (jupyter-guess-kernelspec
|
||||
,name (jupyter-server-kernelspecs ,server)))))
|
||||
(let ((,id (jupyter-start-kernel kernel server)))
|
||||
(let ((,id (jupyter-start-kernel kernel)))
|
||||
(unwind-protect
|
||||
(progn ,@body)
|
||||
(jupyter-api-shutdown-kernel ,server ,id))))))
|
||||
|
|
Loading…
Add table
Reference in a new issue