Add the jupyter-kernelspecs method

Replaces both `jupyter-available-kernelspecs` and
`jupyter-server-kernelspecs`.
This commit is contained in:
Nathaniel Nicandro 2021-04-03 13:34:16 -05:00
parent 35e44798c4
commit 5857352135
6 changed files with 57 additions and 43 deletions

View file

@ -94,18 +94,26 @@ REFRESH."
jupyter--kernelspecs))))) jupyter--kernelspecs)))))
kernelspecs)) kernelspecs))
(cl-defgeneric jupyter-kernelspecs (host &optional refresh)
"Return a list of kernelspecs on HOST.")
(cl-defmethod jupyter-kernelspecs ((host string) &optional refresh)
(let ((default-directory host))
(jupyter-available-kernelspecs refresh)))
(defun jupyter-get-kernelspec (name &optional specs refresh) (defun jupyter-get-kernelspec (name &optional specs refresh)
"Get the kernelspec for a kernel named NAME. "Get the kernelspec for a kernel named NAME.
If no kernelspec is found, return nil. Otherwise return the If no kernelspec is found, return nil. Otherwise return the
kernelspec plist for the kernel names NAME. Optional argument kernelspec for the kernel named NAME.
REFRESH has the same meaning as in
`jupyter-available-kernelspecs'.
If SPECS is provided, it is a list of kernelspecs that will be If SPECS is provided, it is a list of kernelspecs that will be
searched, otherwise the kernelspecs returned by searched. Otherwise the kernelspecs associated with the
`jupyter-available-kernelspecs' are used." `default-directory' are used.
Optional argument REFRESH has the same meaning as in
`jupyter-kernelspecs'."
(cl-loop (cl-loop
for kernelspec in (or specs (jupyter-available-kernelspecs refresh)) for kernelspec in (or specs (jupyter-kernelspecs default-directory refresh))
thereis (when (string= (jupyter-kernelspec-name kernelspec) name) thereis (when (string= (jupyter-kernelspec-name kernelspec) name)
kernelspec))) kernelspec)))
@ -114,15 +122,15 @@ searched, otherwise the kernelspecs returned by
RE is a regular expression use to match the name of a kernel. RE is a regular expression use to match the name of a kernel.
Return a list of `jupyter-kernelspec' objects. Return a list of `jupyter-kernelspec' objects.
If SPECS is non-nil search SPECS, otherwise search the specs If SPECS is non-nil search SPECS, otherwise search the
returned by `jupyter-available-kernelspecs'. kernelspecs associated with the `default-directory'.
Optional argument REFRESH has the same meaning as in Optional argument REFRESH has the same meaning as in
`jupyter-available-kernelspecs'." `jupyter-kernelspecs'."
(cl-remove-if-not (cl-remove-if-not
(lambda (kernelspec) (lambda (kernelspec)
(string-match-p re (jupyter-kernelspec-name kernelspec))) (string-match-p re (jupyter-kernelspec-name kernelspec)))
(or specs (jupyter-available-kernelspecs refresh)))) (or specs (jupyter-kernelspecs default-directory refresh))))
(defun jupyter-guess-kernelspec (name &optional specs refresh) (defun jupyter-guess-kernelspec (name &optional specs refresh)
"Return the first kernelspec starting with NAME. "Return the first kernelspec starting with NAME.
@ -137,11 +145,12 @@ SPECS and REFRESH have the same meaning as in
"Use `completing-read' to select a kernel and return its kernelspec. "Use `completing-read' to select a kernel and return its kernelspec.
SPECS is a list of kernelspecs that will be used for completion, SPECS is a list of kernelspecs that will be used for completion,
if it is nil the `jupyter-available-kernelspecs' will be used. if it is nil the kernelspecs associated with the
`default-directory' will be used.
Optional argument REFRESH has the same meaning as in Optional argument REFRESH has the same meaning as in
`jupyter-available-kernelspecs'." `jupyter-kernelspecs'."
(let* ((specs (or specs (jupyter-available-kernelspecs refresh))) (let* ((specs (or specs (jupyter-kernelspecs default-directory refresh)))
(display-names (if (null specs) (error "No kernelspecs available") (display-names (if (null specs) (error "No kernelspecs available")
(mapcar (lambda (k) (mapcar (lambda (k)
(plist-get (plist-get

View file

@ -26,11 +26,11 @@
;; ;;
;; The main entry points are `jupyter-run-repl' and `jupyter-connect-repl'. ;; The main entry points are `jupyter-run-repl' and `jupyter-connect-repl'.
;; ;;
;; When called interactively, `jupyter-run-repl' asks for a kernel to start ;; When called interactively, `jupyter-run-repl' asks for a kernel to
;; (based on the kernels found using `jupyter-available-kernelspecs'), connects ;; start, connects a `jupyter-repl-client' to the selected kernel, and
;; a `jupyter-repl-client' to the selected kernel, and pops up a REPL buffer. ;; pops up a REPL buffer. The main difference of
;; The main difference of `jupyter-connect-repl' is that it will obtain the ;; `jupyter-connect-repl' is that it will obtain the kernel's
;; kernel's connection info by asking for the JSON file containing it to start ;; connection info by asking for the JSON file containing it to start
;; connection to a kernel. ;; connection to a kernel.
;; ;;
;; Additionally, `jupyter-repl-associate-buffer' associates the ;; Additionally, `jupyter-repl-associate-buffer' associates the

View file

@ -54,8 +54,8 @@ Used in, e.g. a `jupyter-server-kernel-list-mode' buffer.")
(kernelspecs (kernelspecs
:type json-plist :type json-plist
:initform nil :initform nil
:documentation "Kernelspecs for the kernels available behind this gateway. :documentation "Kernelspecs for the kernels available behind
Access should be done through `jupyter-available-kernelspecs'."))) this gateway. Access them through `jupyter-kernelspecs'.")))
(cl-defmethod make-instance ((class (subclass jupyter-server)) &rest slots) (cl-defmethod make-instance ((class (subclass jupyter-server)) &rest slots)
(cl-assert (plist-get slots :url)) (cl-assert (plist-get slots :url))
@ -87,18 +87,18 @@ with default `jupyter-api-authentication-method'"))
(prog1 (cl-call-next-method) (prog1 (cl-call-next-method)
(jupyter-reauthenticate-websockets server))))) (jupyter-reauthenticate-websockets server)))))
(cl-defmethod jupyter-server-kernelspecs ((server jupyter-server) &optional refresh) (cl-defmethod jupyter-kernelspecs ((client jupyter-rest-client) &optional _refresh)
(or (jupyter-api-get-kernelspec client)
(error "Can't retrieve kernelspecs from server @ %s"
(oref client url))))
(cl-defmethod jupyter-kernelspecs ((server jupyter-server) &optional refresh)
"Return the kernelspecs on SERVER. "Return the kernelspecs on SERVER.
By default the available kernelspecs are cached. To force an By default the available kernelspecs are cached. To force an
update of the cached kernelspecs, give a non-nil value to update of the cached kernelspecs, give a non-nil value to
REFRESH. REFRESH."
The kernelspecs are returned in the same form as returned by
`jupyter-available-kernelspecs'."
(when (or refresh (null (oref server kernelspecs))) (when (or refresh (null (oref server kernelspecs)))
(let ((specs (or (jupyter-api-get-kernelspec server) (let ((specs (cl-call-next-method)))
(error "Can't retrieve kernelspecs from server @ %s"
(oref server url)))))
(plist-put specs :kernelspecs (plist-put specs :kernelspecs
(cl-loop (cl-loop
for (_ spec) on (plist-get specs :kernelspecs) by #'cddr for (_ spec) on (plist-get specs :kernelspecs) by #'cddr
@ -109,9 +109,14 @@ The kernelspecs are returned in the same form as returned by
(oset server kernelspecs specs))) (oset server kernelspecs specs)))
(plist-get (oref server kernelspecs) :kernelspecs)) (plist-get (oref server kernelspecs) :kernelspecs))
(cl-defmethod jupyter-kernelspecs :extra "server" ((host string) &optional refresh)
(if (jupyter-tramp-file-name-p host)
(jupyter-kernelspecs (jupyter-tramp-server-from-file-name host) refresh)
(cl-call-next-method)))
(cl-defmethod jupyter-server-has-kernelspec-p ((server jupyter-server) name) (cl-defmethod jupyter-server-has-kernelspec-p ((server jupyter-server) name)
"Return non-nil if SERVER can launch kernels with kernelspec NAME." "Return non-nil if SERVER can launch kernels with kernelspec NAME."
(jupyter-guess-kernelspec name (jupyter-server-kernelspecs server))) (jupyter-guess-kernelspec name (jupyter-kernelspecs server)))
;;; Kernel definition ;;; Kernel definition
@ -165,7 +170,7 @@ Call the next method if ARGS does not contain :server."
;; the server connection already open and ;; the server connection already open and
;; kernelspecs already retrieved. ;; kernelspecs already retrieved.
(or (jupyter-guess-kernelspec (or (jupyter-guess-kernelspec
spec (jupyter-server-kernelspecs server)) spec (jupyter-kernelspecs server))
;; TODO: Return the error to the I/O context. ;; TODO: Return the error to the I/O context.
(error "No kernelspec matching %s @ %s" spec (error "No kernelspec matching %s @ %s" spec
(oref server url)))))) (oref server url))))))
@ -287,7 +292,7 @@ this case FN will be evaluated on KERNEL."
(cl-defmethod jupyter-launch ((server jupyter-server) &optional (kernel string)) (cl-defmethod jupyter-launch ((server jupyter-server) &optional (kernel string))
(cl-check-type kernel string) (cl-check-type kernel string)
(let* ((spec (jupyter-guess-kernelspec (let* ((spec (jupyter-guess-kernelspec
kernel (jupyter-server-kernelspecs server))) kernel (jupyter-kernelspecs server)))
(plist (jupyter-api-start-kernel (plist (jupyter-api-start-kernel
server (jupyter-kernelspec-name spec)))) server (jupyter-kernelspec-name spec))))
(jupyter-kernel :server server :id (plist-get plist :id) :spec spec))) (jupyter-kernel :server server :id (plist-get plist :id) :spec spec)))
@ -313,7 +318,7 @@ using its SPEC."
(setf (jupyter-kernel-spec kernel) (setf (jupyter-kernel-spec kernel)
(jupyter-guess-kernelspec (jupyter-guess-kernelspec
(plist-get model :name) (plist-get model :name)
(jupyter-server-kernelspecs server))))) (jupyter-kernelspecs server)))))
(let ((plist (jupyter-api-start-kernel (let ((plist (jupyter-api-start-kernel
server (jupyter-kernelspec-name spec)))) server (jupyter-kernelspec-name spec))))
(setf (jupyter-server-kernel-id kernel) (plist-get plist :id)) (setf (jupyter-server-kernel-id kernel) (plist-get plist :id))

View file

@ -29,7 +29,7 @@
;; Websocket URL for the server, the `jupyter-server' object can launch kernels ;; Websocket URL for the server, the `jupyter-server' object can launch kernels
;; using the function `jupyter-server-start-new-kernel'. The kernelspecs ;; using the function `jupyter-server-start-new-kernel'. The kernelspecs
;; available on the server can be accessed by calling ;; available on the server can be accessed by calling
;; `jupyter-server-kernelspecs'. ;; `jupyter-kernelspecs'.
;; ;;
;; Starting REPLs ;; Starting REPLs
;; ;;
@ -290,7 +290,7 @@ With a prefix argument, ask to select a server if there are
mutiple to choose from, otherwise the most recently used server mutiple to choose from, otherwise the most recently used server
is used as determined by `jupyter-current-server'." is used as determined by `jupyter-current-server'."
(interactive (list (jupyter-current-server current-prefix-arg))) (interactive (list (jupyter-current-server current-prefix-arg)))
(let* ((specs (jupyter-server-kernelspecs server)) (let* ((specs (jupyter-kernelspecs server))
(spec (jupyter-completing-read-kernelspec specs))) (spec (jupyter-completing-read-kernelspec specs)))
(jupyter-api-start-kernel server (jupyter-kernelspec-name spec)))) (jupyter-api-start-kernel server (jupyter-kernelspec-name spec))))
@ -310,7 +310,7 @@ is used as determined by `jupyter-current-server'."
(let ((server (jupyter-current-server current-prefix-arg))) (let ((server (jupyter-current-server current-prefix-arg)))
(list server (list server
(car (jupyter-completing-read-kernelspec (car (jupyter-completing-read-kernelspec
(jupyter-server-kernelspecs server))) (jupyter-kernelspecs server)))
;; FIXME: Ambiguity with `jupyter-current-server' and ;; FIXME: Ambiguity with `jupyter-current-server' and
;; `current-prefix-arg' ;; `current-prefix-arg'
(when (and current-prefix-arg (when (and current-prefix-arg

View file

@ -48,7 +48,7 @@
(declare-function jupyter-run-server-repl "jupyter-server") (declare-function jupyter-run-server-repl "jupyter-server")
(declare-function jupyter-connect-server-repl "jupyter-server") (declare-function jupyter-connect-server-repl "jupyter-server")
(declare-function jupyter-server-kernelspecs "jupyter-server") (declare-function jupyter-kernelspecs "jupyter-server")
(declare-function jupyter-server-kernel-id-from-name "jupyter-server") (declare-function jupyter-server-kernel-id-from-name "jupyter-server")
(declare-function jupyter-server-name-client-kernel "jupyter-server") (declare-function jupyter-server-name-client-kernel "jupyter-server")
(declare-function jupyter-api-get-kernel "jupyter-rest-api") (declare-function jupyter-api-get-kernel "jupyter-rest-api")
@ -316,7 +316,7 @@ session."
;; Language aliases may not exist for the kernels that are accessible on ;; Language aliases may not exist for the kernels that are accessible on
;; the server so ensure they do. ;; the server so ensure they do.
(org-babel-jupyter-aliases-from-kernelspecs (org-babel-jupyter-aliases-from-kernelspecs
nil (jupyter-server-kernelspecs server)) nil (jupyter-kernelspecs server))
(let ((sname (file-local-name rsession))) (let ((sname (file-local-name rsession)))
(if-let ((id (jupyter-server-kernel-id-from-name server sname))) (if-let ((id (jupyter-server-kernel-id-from-name server sname)))
;; Connecting to an existing kernel ;; Connecting to an existing kernel
@ -682,9 +682,9 @@ For all kernel SPECS, make a language alias for the kernel
language if one does not already exist. The alias is created with language if one does not already exist. The alias is created with
`org-babel-jupyter-make-language-alias'. `org-babel-jupyter-make-language-alias'.
SPECS defaults to `jupyter-available-kernelspecs'. Optional SPECS defaults to those associated with the `default-directory'.
argument REFRESH has the same meaning as in Optional argument REFRESH has the same meaning as in
`jupyter-available-kernelspecs'. `jupyter-kernelspecs'.
Note, spaces in the kernel language name are converted into Note, spaces in the kernel language name are converted into
dashes in the language alias, e.g. dashes in the language alias, e.g.
@ -701,7 +701,7 @@ language to exist on someone's system."
(cl-loop (cl-loop
for spec in (or specs for spec in (or specs
(with-demoted-errors "Error retrieving kernelspecs: %S" (with-demoted-errors "Error retrieving kernelspecs: %S"
(jupyter-available-kernelspecs refresh))) (jupyter-kernelspecs default-directory refresh)))
for kernel = (jupyter-kernelspec-name spec) for kernel = (jupyter-kernelspec-name spec)
for lang = (jupyter-canonicalize-language-string for lang = (jupyter-canonicalize-language-string
(plist-get (jupyter-kernelspec-plist spec) :language)) (plist-get (jupyter-kernelspec-plist spec) :language))
@ -726,7 +726,7 @@ mapped to their appropriate minted language in
(cond (cond
((org-export-derived-backend-p backend 'latex) ((org-export-derived-backend-p backend 'latex)
(cl-loop (cl-loop
for spec in (jupyter-available-kernelspecs) for spec in (jupyter-kernelspecs default-directory)
for lang = (plist-get (jupyter-kernelspec-plist spec) :language) for lang = (plist-get (jupyter-kernelspec-plist spec) :language)
do (cl-pushnew (list (intern (concat "jupyter-" lang)) lang) do (cl-pushnew (list (intern (concat "jupyter-" lang)) lang)
org-latex-minted-langs :test #'equal))))) org-latex-minted-langs :test #'equal)))))

View file

@ -302,7 +302,7 @@ For `url-retrieve', the callback will be called with a nil status."
`(let ((,kernel (jupyter-kernel `(let ((,kernel (jupyter-kernel
:server server :server server
:spec (jupyter-guess-kernelspec :spec (jupyter-guess-kernelspec
,name (jupyter-server-kernelspecs ,server))))) ,name (jupyter-kernelspecs ,server)))))
(jupyter-launch ,kernel) (jupyter-launch ,kernel)
(unwind-protect (unwind-protect
(progn ,@body) (progn ,@body)