Make ZMQ an optional user dependency

* jupyter-server.el (jupyter-ioloop, jupyter-server-ioloop): Remove requires.
(jupyter-server): Don't subclass `jupyter-ioloop-comm`.
(jupyter-server--connect-channels, jupyter-server--refresh-comm): Only do
something when the SERVER argument is a `jupyter-comm-layer`, i.e. a
`jupyter-server-ioloop-comm`.  We don't check for that class directly since we
would end up requiring ZMQ.
(jupyter-comm-start) [jupyter-server-kernel-manager]: Use the right subclass of
`jupyter-server-abstract-kcomm` depending on if the `jupyter-server` object is
using ZMQ for communication.
(jupyter-server-make-instance): New function. Returns a `jupyter-server`
instance (a `jupyter-server-ioloop-comm`) that uses ZMQ if
`jupyter-server-use-zmq` is non-nil, and a plain old `jupyter-server` instance
otherwise.
(jupyter-current-server): `jupyter-server` -> `jupyter-server-make-instance`.

* ob-jupyter.el (org-babel-jupyter--server-repl): `jupyter-server` ->
  `jupyter-server-make-instance`.

* test/test-helper.el (jupyter-test-with-notebook): `jupyter-server` ->
  `jupyter-server-make-instance`.
This commit is contained in:
Nathaniel Nicandro 2020-03-13 05:56:00 -05:00
parent 318e245ebb
commit a11521dabf
3 changed files with 29 additions and 13 deletions

View file

@ -77,8 +77,6 @@
(require 'jupyter-repl)
(require 'jupyter-rest-api)
(require 'jupyter-kernel-manager)
(require 'jupyter-ioloop-comm)
(require 'jupyter-server-ioloop)
(declare-function jupyter-tramp-file-name-p "jupyter-tramp" (filename))
(declare-function jupyter-tramp-server-from-file-name "jupyter-tramp" (filename))
@ -109,7 +107,6 @@ Used in, e.g. a `jupyter-server-kernel-list-mode' buffer.")
;; `jupyter-server-client' since it isn't a representation of a server, but a
;; communication channel with one.
(defclass jupyter-server (jupyter-rest-client
jupyter-ioloop-comm
eieio-instance-tracker)
((tracking-symbol :initform 'jupyter--servers)
(kernelspecs
@ -265,17 +262,21 @@ ID of the kernel will be associated with NAME, see
(cl-defgeneric jupyter-server-kernel-connected-p ((client jupyter-server) id)
"Return non-nil if CLIENT can communicate with a kernel that has ID.")
;; TODO: Move the following two functions to jupyter-server-ioloop-comm.el
(defun jupyter-server--connect-channels (server id)
(jupyter-send server 'connect-channels id)
(jupyter-with-timeout
(nil jupyter-default-timeout
(error "Timeout when connecting websocket to kernel id %s" id))
(jupyter-server-kernel-connected-p server id)))
(when (object-of-class-p server 'jupyter-comm-layer)
(jupyter-send server 'connect-channels id)
(jupyter-with-timeout
(nil jupyter-default-timeout
(error "Timeout when connecting websocket to kernel id %s" id))
(jupyter-server-kernel-connected-p server id))))
(defun jupyter-server--refresh-comm (server)
"Stop and then start SERVER communication.
Reconnect the previously connected kernels when starting."
(when (jupyter-comm-alive-p server)
(when (and (object-of-class-p server 'jupyter-comm-layer)
(jupyter-comm-alive-p server))
(let ((connected (cl-remove-if-not
(apply-partially #'jupyter-server-kernel-connected-p server)
(mapcar (lambda (kernel) (plist-get kernel :id))
@ -408,7 +409,10 @@ MANAGER's COMM slot will be set to the `jupyter-comm-layer'
receiving events on the websocket when this method returns."
(with-slots (kernel comm) manager
(unless (slot-boundp manager 'comm)
(oset manager comm (jupyter-server-kernel-comm :kernel kernel)))
(oset manager comm
(if (object-of-class-p (oref kernel server) 'jupyter-comm-layer)
(jupyter-server-ioloop-kernel-comm :kernel kernel)
(jupyter-server-kernel-comm :kernel kernel))))
(unless (jupyter-comm-alive-p comm)
(jupyter-comm-start comm))))
@ -508,6 +512,18 @@ least the following keys:
(define-error 'jupyter-server-non-existent
"The server doesn't exist")
(defun jupyter-server-make-instance (&rest args)
"Return a different subclass of `jupyter-server' depending on `jupyter-server-use-zmq'.
A `jupyter-server-ioloop-comm' object is returned if
`jupyter-server-use-zmq' is non-nil, a `jupyter-server' is
returned otherwise. ARGS is passed to the `make-instance'
invocation for the subclass."
(if jupyter-server-use-zmq
(progn
(require 'jupyter-server-ioloop-comm)
(apply #'jupyter-server-ioloop-comm args))
(apply #'jupyter-server args)))
(defun jupyter-current-server (&optional ask)
"Return an existing `jupyter-server' or ASK for a new one.
If ASK is non-nil, always ask for a URL and return the
@ -546,7 +562,7 @@ a URL."
(setf (url-type u) "ws")
(url-recreate-url u)))))
(or (jupyter-find-server url ws-url)
(let ((server (jupyter-server :url url :ws-url ws-url)))
(let ((server (jupyter-server-make-instance :url url :ws-url ws-url)))
(if (jupyter-api-server-exists-p server) server
(delete-instance server)
(signal 'jupyter-server-non-existent (list url)))))))))

View file

@ -239,7 +239,7 @@ variables in PARAMS."
(require 'jupyter-server)
(let* ((url (jupyter-tramp-url-from-file-name session))
(server (or (jupyter-tramp-server-from-file-name session)
(jupyter-server :url url)))
(jupyter-server-make-instance :url url)))
(localname (file-local-name session))
(name-or-id (if (null localname) (error "No remote server session name")
;; If a kernel has an associated name, get its kernel ID

View file

@ -323,7 +323,7 @@ For `url-retrieve', the callback will be called with a nil status."
`(let* ((host (format "localhost:%s" (jupyter-test-ensure-notebook-server)))
(url (format "http://%s" host))
(,server (or (jupyter-find-server url)
(jupyter-server :url url))))
(jupyter-server-make-instance :url url))))
,@body))
(defmacro jupyter-test-with-server-kernel (server name kernel &rest body)