mirror of
https://github.com/vale981/emacs-ipython-notebook
synced 2025-03-05 09:01:40 -05:00
Follow-up to cleaning up websockets
Renaming of functions with better understanding of reconnects. Under the original logic, reconnecting blithely created a new session if the original no longer existed. Now it will alert the user when this happens. Also hopefully fixes #381 as there was a bug of missing argument not being caught by lisp's undisciplined typing.
This commit is contained in:
parent
c92b8bdfc1
commit
ee3b0f095c
10 changed files with 217 additions and 148 deletions
|
@ -16,7 +16,7 @@ Scenario: not running server locally
|
|||
Then I should not see "ein:completions--prepare-oinfo"
|
||||
|
||||
@reconnect
|
||||
Scenario: kernel restart succeeds
|
||||
Scenario: kernel reconnect succeeds
|
||||
Given new default notebook
|
||||
When I type "import math"
|
||||
And I wait for cell to execute
|
||||
|
@ -25,14 +25,26 @@ Scenario: kernel restart succeeds
|
|||
Then I should see "WS closed unexpectedly"
|
||||
And I switch to buffer like "Untitled"
|
||||
And header says "Kernel requires reconnect C-c C-r"
|
||||
And I clear log expr "ein:log-all-buffer-name"
|
||||
And I press "C-c C-r"
|
||||
And I wait for the smoke to clear
|
||||
And header does not say "Kernel requires reconnect C-c C-r"
|
||||
And I clear log expr "ein:log-all-buffer-name"
|
||||
And I reconnect kernel
|
||||
And I switch to log expr "ein:log-all-buffer-name"
|
||||
Then I should not see "[warn]"
|
||||
And I should not see "[error]"
|
||||
And I should see "ein:kernel-start--complete"
|
||||
And I should see "ein:kernel-retrieve-session--complete"
|
||||
And I switch to buffer like "Untitled"
|
||||
And I clear log expr "ein:log-all-buffer-name"
|
||||
And I restart kernel
|
||||
And I switch to log expr "ein:log-all-buffer-name"
|
||||
Then I should not see "[warn]"
|
||||
And I should not see "[error]"
|
||||
And I should see "ein:kernel-retrieve-session--complete"
|
||||
And I switch to buffer like "Untitled"
|
||||
And I kill kernel
|
||||
And header says "Kernel requires reconnect C-c C-r"
|
||||
And I clear log expr "ein:log-all-buffer-name"
|
||||
And my reconnect is questioned
|
||||
|
||||
|
||||
|
|
@ -1,16 +1,27 @@
|
|||
(When "with no opened notebooks call \"\\(.+\\)\"$"
|
||||
(When "^with no opened notebooks call \"\\(.+\\)\"$"
|
||||
(lambda (func)
|
||||
(cl-letf (((symbol-function 'ein:notebook-opened-buffer-names) #'ignore))
|
||||
(When (format "I call \"%s\"" func)))))
|
||||
|
||||
(When "header \\(does not \\)?says? \"\\(.+\\)\"$"
|
||||
(When "^header \\(does not \\)?says? \"\\(.+\\)\"$"
|
||||
(lambda (negate says)
|
||||
(let ((equal-p (string= says (slot-value (slot-value ein:%notification% 'kernel) 'message))))
|
||||
(cl-assert (if negate (not equal-p) equal-p)))))
|
||||
|
||||
(When "I reconnect kernel$"
|
||||
(When "^I kill kernel$"
|
||||
(lambda ()
|
||||
(ein:notebook-reconnect-kernel)
|
||||
(ein:kernel-delete-session (ein:$notebook-kernel ein:%notebook%))
|
||||
(And "I wait for the smoke to clear")))
|
||||
|
||||
(When "^my reconnect is questioned"
|
||||
(lambda ()
|
||||
(ein:notebook-reconnect-session-command (lambda (notebook session-p)
|
||||
(assert (not session-p))))))
|
||||
|
||||
(When "I restart kernel$"
|
||||
(lambda ()
|
||||
(cl-letf (((symbol-function 'y-or-n-p) (lambda (&rest ignore) t)))
|
||||
(ein:notebook-restart-session-command))
|
||||
(And "I wait for the smoke to clear")))
|
||||
|
||||
(When "I call eldoc-documentation-function$"
|
||||
|
|
|
@ -228,10 +228,8 @@
|
|||
;; FIXME: Rewrite `ein:$kernel' using `defclass'. It should ease
|
||||
;; testing since I can mock I/O using method overriding.
|
||||
(defstruct ein:$kernel
|
||||
"Hold kernel variables.
|
||||
"Should perhaps be named ein:$session. We glom session and kernel as defined by the server as just ein:$kernel in the client.
|
||||
|
||||
`ein:$kernel-url-or-port'
|
||||
URL or port of IPython server.
|
||||
"
|
||||
url-or-port
|
||||
events
|
||||
|
|
|
@ -161,11 +161,11 @@ the source is in git repository."
|
|||
:timeout ein:content-query-timeout
|
||||
:parser 'ein:json-read
|
||||
:sync ein:force-sync
|
||||
:complete (apply-partially #'ein:query-kernelspecs--complete url-or-port callback)
|
||||
:success (apply-partially #'ein:query-kernelspecs--success url-or-port)
|
||||
:complete (apply-partially #'ein:query-kernelspecs--complete url-or-port)
|
||||
:success (apply-partially #'ein:query-kernelspecs--success url-or-port callback)
|
||||
:error (apply-partially #'ein:query-kernelspecs--error url-or-port callback iteration)))
|
||||
|
||||
(defun* ein:query-kernelspecs--success (url-or-port
|
||||
(defun* ein:query-kernelspecs--success (url-or-port callback
|
||||
&key data symbol-status response
|
||||
&allow-other-keys)
|
||||
(let ((ks (list :default (plist-get data :default)))
|
||||
|
@ -181,7 +181,8 @@ the source is in git repository."
|
|||
:language (plist-get (plist-get info :spec)
|
||||
:language)
|
||||
:spec (plist-get info :spec)))
|
||||
ks)))))))
|
||||
ks))))))
|
||||
(when callback (funcall callback)))
|
||||
|
||||
(defun* ein:query-kernelspecs--error (url-or-port callback iteration
|
||||
&key response error-thrown
|
||||
|
@ -191,13 +192,13 @@ the source is in git repository."
|
|||
(ein:log 'verbose "Retry kernelspecs #%s in response to %s" iteration (request-response-status-code response))
|
||||
(ein:query-kernelspecs url-or-port callback (1+ iteration)))
|
||||
(ein:log 'error
|
||||
"ein:query-kernelspecs--error %s: ERROR %s DATA %s" url-or-port (car error-thrown) (cdr error-thrown))))
|
||||
"ein:query-kernelspecs--error %s: ERROR %s DATA %s" url-or-port (car error-thrown) (cdr error-thrown))
|
||||
(when callback (funcall callback))))
|
||||
|
||||
(defun* ein:query-kernelspecs--complete (url-or-port callback &key data response
|
||||
(defun* ein:query-kernelspecs--complete (url-or-port &key data response
|
||||
&allow-other-keys
|
||||
&aux (resp-string (format "STATUS: %s DATA: %s" (request-response-status-code response) data)))
|
||||
(ein:log 'debug "ein:query-kernelspecs--complete %s" resp-string)
|
||||
(when callback (funcall callback)))
|
||||
(ein:log 'debug "ein:query-kernelspecs--complete %s" resp-string))
|
||||
|
||||
(defsubst ein:get-ipython-major-version (vstr)
|
||||
(if vstr
|
||||
|
|
|
@ -20,8 +20,11 @@
|
|||
;; along with ein-kernel.el. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;
|
||||
;; `ein:kernel' is the proxy class of notebook server state.
|
||||
;; It agglomerates both the "kernel" and "session" objects of server described here
|
||||
;; https://github.com/jupyter/jupyter/wiki/Jupyter-Notebook-Server-API
|
||||
;; It may have been better to keep them separate to allow parallel reasoning with
|
||||
;; the notebook server, but that time is past.
|
||||
|
||||
;;; Code:
|
||||
|
||||
|
@ -95,18 +98,80 @@
|
|||
:content content
|
||||
:parent_header (make-hash-table)))
|
||||
|
||||
(defun ein:kernel-start (kernel notebook &optional iteration callback)
|
||||
"Start kernel of the notebook whose id is NOTEBOOK-ID.
|
||||
(defun* ein:kernel-session-p (notebook callback &optional iteration &aux (kernel (ein:$notebook-kernel notebook)))
|
||||
"Don't make any changes on the server side. CALLBACK with arity 1, a boolean whether session exists on server."
|
||||
(unless iteration
|
||||
(setq iteration 0))
|
||||
(let ((session-id (ein:$kernel-session-id kernel)))
|
||||
(ein:query-singleton-ajax
|
||||
(list 'kernel-session-p session-id)
|
||||
(ein:url (ein:$kernel-url-or-port kernel) "api/sessions" session-id)
|
||||
:type "GET"
|
||||
:sync ein:force-sync
|
||||
:parser #'ein:json-read
|
||||
:complete (apply-partially #'ein:kernel-session-p--complete session-id)
|
||||
:success (apply-partially #'ein:kernel-session-p--success session-id callback)
|
||||
:error (apply-partially #'ein:kernel-session-p--error notebook callback iteration))))
|
||||
|
||||
CALLBACK of arity 0 (e.g., print a message kernel started)"
|
||||
(assert (and (ein:$notebook-p notebook) (ein:$kernel-p kernel)))
|
||||
(defun* ein:kernel-session-p--complete (session-id &key data response
|
||||
&allow-other-keys
|
||||
&aux (resp-string (format "STATUS: %s DATA: %s" (request-response-status-code response) data)))
|
||||
(ein:log 'debug "ein:kernel-session-p--complete %s" resp-string))
|
||||
|
||||
(defun* ein:kernel-session-p--error (notebook callback iteration &key error-thrown symbol-status data &allow-other-keys)
|
||||
(if (ein:aand (plist-get data :message) (search "not found" it))
|
||||
(when callback (funcall callback nil))
|
||||
(let* ((max-tries 3)
|
||||
(tries-left (1- (- max-tries iteration))))
|
||||
(ein:log 'verbose "ein:kernel-session-p--error [%s], %s tries left"
|
||||
(car error-thrown) tries-left)
|
||||
(if (> tries-left 0)
|
||||
(ein:kernel-session-p notebook callback (1+ iteration))))))
|
||||
|
||||
(defun* ein:kernel-session-p--success (session-id callback &key data &allow-other-keys)
|
||||
(let ((session-p (equal (plist-get data :id) session-id)))
|
||||
(ein:log 'verbose "ein:kernel-session-p--success: session-id=%s session-p=%s"
|
||||
session-id session-p)
|
||||
(when callback (funcall callback session-p))))
|
||||
|
||||
(defun* ein:kernel-restart-session (notebook
|
||||
&aux (kernel (ein:$notebook-kernel notebook)))
|
||||
"Server side delete of NOTEBOOK session and subsequent restart with all new state"
|
||||
(ein:kernel-delete-session kernel
|
||||
(apply-partially
|
||||
(lambda (notebook*)
|
||||
(ein:events-trigger (ein:$kernel-events kernel)
|
||||
'status_restarting.Kernel)
|
||||
(ein:kernel-retrieve-session notebook* 0
|
||||
(apply-partially
|
||||
(lambda (nb)
|
||||
(with-current-buffer (ein:notebook-buffer nb)
|
||||
(ein:notification-status-set
|
||||
(slot-value ein:%notification% 'kernel)
|
||||
'status_restarted.Kernel)))
|
||||
notebook*)))
|
||||
notebook)))
|
||||
|
||||
(defun* ein:kernel-retrieve-session (notebook &optional iteration callback
|
||||
&aux (kernel (ein:$notebook-kernel notebook)))
|
||||
"Formerly ein:kernel-start, but that was misnomer because 1. the server really starts a session (and an accompanying kernel), and 2. it may not even start a session if one exists for the same path.
|
||||
|
||||
The server logic is here (could not find other documentation)
|
||||
https://github.com/jupyter/notebook/blob/04a686dbaf9dfe553324a03cb9e6f778cf1e3da1/notebook/services/sessions/handlers.py#L56-L81
|
||||
|
||||
CALLBACK of arity 0 (e.g., print a message kernel started)
|
||||
|
||||
This no longer works in iPython-2.0. Protocol is to create a session for a
|
||||
notebook, which will automatically create and associate a kernel with the notebook.
|
||||
"
|
||||
(unless iteration
|
||||
(setq iteration 0))
|
||||
(if (<= (ein:$kernel-api-version kernel) 2)
|
||||
(error "Api version %s unsupported" (ein:$kernel-api-version kernel))
|
||||
(let ((kernelspec (ein:$notebook-kernelspec notebook)))
|
||||
(error "Api %s unsupported" (ein:$kernel-api-version kernel))
|
||||
(let ((kernelspec (ein:$notebook-kernelspec notebook))
|
||||
(kernel-id (ein:$kernel-kernel-id kernel)))
|
||||
(ein:query-singleton-ajax
|
||||
(list 'kernel-start (ein:$kernel-kernel-id kernel))
|
||||
(list 'kernel-retrieve-session kernel-id)
|
||||
(ein:url (ein:$kernel-url-or-port kernel) "api/sessions")
|
||||
:type "POST"
|
||||
:data (json-encode
|
||||
|
@ -118,55 +183,37 @@ CALLBACK of arity 0 (e.g., print a message kernel started)"
|
|||
(("name" . ,(ein:$kernelspec-name kernelspec))))))))
|
||||
(t `(("path" . ,(ein:$notebook-notebook-path notebook))
|
||||
("type" . "notebook")
|
||||
,@(if kernelspec
|
||||
`(("kernel" .
|
||||
(("name" . ,(ein:$kernelspec-name kernelspec))))))))))
|
||||
("kernel" .
|
||||
(,@(if kernelspec
|
||||
`(("name" . ,(ein:$kernelspec-name kernelspec))))
|
||||
,@(if kernel-id
|
||||
`(("id" . ,kernel-id)))))
|
||||
))))
|
||||
:sync ein:force-sync
|
||||
:parser #'ein:json-read
|
||||
:complete (apply-partially #'ein:kernel-start--complete kernel callback)
|
||||
:success (apply-partially #'ein:kernel-start--success kernel callback)
|
||||
:error (apply-partially #'ein:kernel-start--error kernel notebook iteration callback)))))
|
||||
:complete (apply-partially #'ein:kernel-retrieve-session--complete kernel callback)
|
||||
:success (apply-partially #'ein:kernel-retrieve-session--success kernel callback)
|
||||
:error (apply-partially #'ein:kernel-retrieve-session--error notebook iteration callback)))))
|
||||
|
||||
(defun ein:kernel-restart (kernel)
|
||||
"Will not restart kernel if kernel doesn't have a session-id.
|
||||
|
||||
Kernel can be dead (as in the websocket died unexpectedly) but must be fully-formed for the restart."
|
||||
(ein:kernel-delete kernel
|
||||
(apply-partially
|
||||
(lambda (kernel* notebook)
|
||||
(if (ein:kernel-live-p kernel*)
|
||||
(ein:log 'error "Kernel %s still live!" (ein:$kernel-kernel-id kernel*))
|
||||
(ein:events-trigger (ein:$kernel-events kernel*)
|
||||
'status_restarting.Kernel)
|
||||
(ein:kernel-start kernel* notebook 0
|
||||
(apply-partially
|
||||
(lambda (nb)
|
||||
(with-current-buffer (ein:notebook-buffer nb)
|
||||
(ein:notification-status-set
|
||||
(slot-value ein:%notification% 'kernel)
|
||||
'status_restarted.Kernel)))
|
||||
notebook))))
|
||||
kernel (ein:get-notebook-or-error))))
|
||||
|
||||
(defun* ein:kernel-start--complete (kernel callback &key data response
|
||||
&allow-other-keys
|
||||
(defun* ein:kernel-retrieve-session--complete (kernel callback &key data response
|
||||
&allow-other-keys
|
||||
&aux (resp-string (format "STATUS: %s DATA: %s" (request-response-status-code response) data)))
|
||||
(ein:log 'debug "ein:kernel-start--complete %s" resp-string))
|
||||
(ein:log 'debug "ein:kernel-retrieve-session--complete %s" resp-string))
|
||||
|
||||
(defun* ein:kernel-start--error (kernel notebook iteration callback &key error-thrown sybmol-status &allow-other-keys)
|
||||
(defun* ein:kernel-retrieve-session--error (notebook iteration callback &key error-thrown symbol-status &allow-other-keys)
|
||||
(let* ((max-tries 3)
|
||||
(tries-left (1- (- max-tries iteration))))
|
||||
(ein:log 'verbose "ein:kernel-start--error [%s], %s tries left"
|
||||
(ein:log 'verbose "ein:kernel-retrieve-session--error [%s], %s tries left"
|
||||
(car error-thrown) tries-left)
|
||||
(if (> tries-left 0)
|
||||
(ein:kernel-start kernel notebook (1+ iteration) callback))))
|
||||
(ein:kernel-retrieve-session notebook (1+ iteration) callback))))
|
||||
|
||||
(defun* ein:kernel-start--success (kernel callback &key data &allow-other-keys)
|
||||
(defun* ein:kernel-retrieve-session--success (kernel callback &key data &allow-other-keys)
|
||||
(let ((session-id (plist-get data :id)))
|
||||
(if (plist-get data :kernel)
|
||||
(setq data (plist-get data :kernel)))
|
||||
(destructuring-bind (&key id &allow-other-keys) data
|
||||
(ein:log 'verbose "ein:kernel-start--success: kernel-id=%s session-id=%s"
|
||||
(ein:log 'verbose "ein:kernel-retrieve-session--success: kernel-id=%s session-id=%s"
|
||||
id session-id)
|
||||
(setf (ein:$kernel-kernel-id kernel) id)
|
||||
(setf (ein:$kernel-session-id kernel) session-id)
|
||||
|
@ -255,8 +302,8 @@ See: https://github.com/ipython/ipython/pull/3307"
|
|||
(ein:$kernel-after-start-hook kernel)))
|
||||
|
||||
(defun ein:kernel-disconnect (kernel)
|
||||
"Disconnect websocket connection to running kernel, but do not
|
||||
kill the kernel."
|
||||
"Close websocket connection to running kernel, but do not
|
||||
delete the kernel on the server side"
|
||||
(ein:events-trigger (ein:$kernel-events kernel) 'status_disconnected.Kernel)
|
||||
(ein:aif (ein:$kernel-websocket kernel)
|
||||
(progn (ein:websocket-close it)
|
||||
|
@ -558,32 +605,31 @@ Example::
|
|||
:success (lambda (&rest ignore)
|
||||
(ein:log 'info "Sent interruption command.")))))
|
||||
|
||||
(defun ein:kernel-delete (kernel &optional callback)
|
||||
(defun ein:kernel-delete-session (kernel &optional callback)
|
||||
"Regardless of success or error, we clear all state variables of kernel and funcall CALLBACK of arity 0 (e.g., kernel restart)"
|
||||
(ein:and-let* ((kernel kernel)
|
||||
(session-id (ein:$kernel-session-id kernel)))
|
||||
(ein:and-let* ((session-id (ein:$kernel-session-id kernel)))
|
||||
(ein:query-singleton-ajax
|
||||
(list 'kernel-delete session-id)
|
||||
(list 'kernel-delete-session session-id)
|
||||
(ein:url (ein:$kernel-url-or-port kernel) "api/sessions" session-id)
|
||||
:type "DELETE"
|
||||
:complete (apply-partially #'ein:kernel-delete--complete kernel session-id callback)
|
||||
:error (apply-partially #'ein:kernel-delete--error session-id callback)
|
||||
:success (apply-partially #'ein:kernel-delete--success session-id callback))))
|
||||
:complete (apply-partially #'ein:kernel-delete-session--complete kernel session-id callback)
|
||||
:error (apply-partially #'ein:kernel-delete-session--error session-id callback)
|
||||
:success (apply-partially #'ein:kernel-delete-session--success session-id callback))))
|
||||
|
||||
(defun* ein:kernel-delete--error (session-id callback
|
||||
(defun* ein:kernel-delete-session--error (session-id callback
|
||||
&key response error-thrown
|
||||
&allow-other-keys)
|
||||
(ein:log 'error "ein:kernel-delete--error %s: ERROR %s DATA %s"
|
||||
(ein:log 'error "ein:kernel-delete-session--error %s: ERROR %s DATA %s"
|
||||
session-id (car error-thrown) (cdr error-thrown)))
|
||||
|
||||
(defun* ein:kernel-delete--success (session-id callback &key data symbol-status response
|
||||
(defun* ein:kernel-delete-session--success (session-id callback &key data symbol-status response
|
||||
&allow-other-keys)
|
||||
(ein:log 'verbose "ein:kernel-delete--success: %s deleted" session-id))
|
||||
(ein:log 'verbose "ein:kernel-delete-session--success: %s deleted" session-id))
|
||||
|
||||
(defun* ein:kernel-delete--complete (kernel session-id callback &key data response
|
||||
&allow-other-keys
|
||||
(defun* ein:kernel-delete-session--complete (kernel session-id callback &key data response
|
||||
&allow-other-keys
|
||||
&aux (resp-string (format "STATUS: %s DATA: %s" (request-response-status-code response) data)))
|
||||
(ein:log 'debug "ein:kernel-delete--complete %s" resp-string)
|
||||
(ein:log 'debug "ein:kernel-delete-session--complete %s" resp-string)
|
||||
(ein:kernel-disconnect kernel)
|
||||
(when callback (funcall callback)))
|
||||
|
||||
|
|
|
@ -253,7 +253,7 @@ jupyter are concerned, 'localhost:8888' and '127.0.0.1:8888' are
|
|||
(ein:$notebook-notebook-name notebook))
|
||||
(setf (ein:$notebook-url-or-port notebook) new-url-or-port)
|
||||
(with-current-buffer (ein:notebook-buffer notebook)
|
||||
(ein:notebook-start-kernel notebook)
|
||||
(ein:notebook-retrieve-session notebook)
|
||||
(rename-buffer (format ein:notebook-buffer-name-template
|
||||
(ein:$notebook-url-or-port notebook)
|
||||
(ein:$notebook-notebook-name notebook)))))
|
||||
|
@ -369,7 +369,7 @@ notebook buffer. Let's warn for now to see who is doing this.
|
|||
(ein:$notebook-notebook-name notebook) (ein:$content-name content))
|
||||
(ein:notebook-bind-events notebook (ein:events-new))
|
||||
(ein:notebook-maybe-set-kernelspec notebook (plist-get (ein:$content-raw-content content) :metadata))
|
||||
(ein:notebook-start-kernel notebook)
|
||||
(ein:notebook-retrieve-session notebook)
|
||||
(ein:notebook-from-json notebook (ein:$content-raw-content content)) ; notebook buffer is created here
|
||||
(setf (ein:$notebook-kernelinfo notebook)
|
||||
(ein:kernelinfo-new (ein:$notebook-kernel notebook)
|
||||
|
@ -485,27 +485,14 @@ notebook buffer."
|
|||
(ein:$notebook-notebook-name notebook))
|
||||
(ein:$notebook-events notebook))))
|
||||
|
||||
(defun ein:notebook-reconnect-kernel ()
|
||||
"Assuming server will give us back the old kernel id if we send the same noteobook path. TODO - Need to re-verify."
|
||||
(interactive)
|
||||
(ein:aif ein:%notebook%
|
||||
(progn
|
||||
(ein:kernel-disconnect (ein:$notebook-kernel it))
|
||||
(ein:events-trigger (ein:$kernel-events (ein:$notebook-kernel it))
|
||||
'status_reconnecting.Kernel)
|
||||
(ein:kernel-start (ein:$notebook-kernel it) it
|
||||
(apply-partially
|
||||
(lambda (nb)
|
||||
(with-current-buffer (ein:notebook-buffer nb)
|
||||
(ein:notification-status-set
|
||||
(slot-value ein:%notification% 'kernel)
|
||||
'status_reconnected.Kernel)))
|
||||
it)))))
|
||||
|
||||
(define-obsolete-function-alias
|
||||
'ein:notebook-show-in-shared-output
|
||||
'ein:shared-output-show-code-cell-at-point "0.1.2")
|
||||
|
||||
(autoload 'org-toggle-latex-fragment "org")
|
||||
(defalias 'ein:notebook-toggle-latex-fragment 'org-toggle-latex-fragment
|
||||
"Borrow from org-mode the rendering of latex overlays")
|
||||
|
||||
|
||||
;;; Kernel related things
|
||||
|
||||
|
@ -537,21 +524,22 @@ notebook buffer."
|
|||
notebook buffer then the user will be prompted to select an opened notebook."
|
||||
(interactive
|
||||
(let* ((notebook (or (ein:get-notebook)
|
||||
(completing-read
|
||||
"Select notebook [URL-OR-PORT/NAME]: "
|
||||
(ido-completing-read
|
||||
"Select notebook: "
|
||||
(ein:notebook-opened-buffer-names))))
|
||||
(kernel-name (completing-read
|
||||
(kernel-name (ido-completing-read
|
||||
"Select kernel: "
|
||||
(ein:list-available-kernels (ein:$notebook-url-or-port notebook)))))
|
||||
(list notebook kernel-name)))
|
||||
(setf (ein:$notebook-kernelspec notebook) (ein:get-kernelspec (ein:$notebook-url-or-port notebook)
|
||||
kernel-name))
|
||||
(ein:log 'info "Restarting notebook %s with new kernel %s." (ein:$notebook-notebook-name notebook) kernel-name)
|
||||
(ein:notebook-restart-kernel notebook))
|
||||
(ein:kernel-restart-session notebook))
|
||||
|
||||
;;; This no longer works in iPython-2.0. Protocol is to create a session for a
|
||||
;;; notebook, which will automatically create and associate a kernel with the notebook.
|
||||
(defun ein:notebook-start-kernel (notebook)
|
||||
(defun ein:notebook-retrieve-session (notebook)
|
||||
"Formerly ein:notebook-start-kernel.
|
||||
|
||||
If 'picking up from where we last off', that is, we restart emacs and reconnect to same server, jupyter will hand us back the original, still running session."
|
||||
(let* ((base-url (concat ein:base-kernel-url "kernels"))
|
||||
(kernelspec (ein:$notebook-kernelspec notebook))
|
||||
(kernel (ein:kernel-new (ein:$notebook-url-or-port notebook)
|
||||
|
@ -561,23 +549,37 @@ notebook buffer then the user will be prompted to select an opened notebook."
|
|||
(setf (ein:$notebook-kernel notebook) kernel)
|
||||
(when (eq (ein:get-mode-for-kernel (ein:$notebook-kernelspec notebook)) 'python)
|
||||
(ein:pytools-setup-hooks kernel notebook))
|
||||
(ein:kernel-start kernel notebook)))
|
||||
(ein:kernel-retrieve-session notebook)))
|
||||
|
||||
(defun ein:notebook-restart-kernel (notebook)
|
||||
(ein:kernel-restart (ein:$notebook-kernel notebook)))
|
||||
(defun ein:notebook-reconnect-session-command (&optional callback)
|
||||
"It seems convenient but undisciplined to blithely create a new session if the original one no longer exists. CALLBACK takes notebook and session-p."
|
||||
(interactive)
|
||||
(unless callback
|
||||
(setq callback
|
||||
(lambda (notebook session-p)
|
||||
(if (or session-p (y-or-n-p "Session not found. Restart?"))
|
||||
(ein:kernel-retrieve-session notebook 0
|
||||
(apply-partially (lambda (nb)
|
||||
(with-current-buffer (ein:notebook-buffer nb)
|
||||
(ein:notification-status-set
|
||||
(slot-value ein:%notification% 'kernel)
|
||||
'status_reconnected.Kernel)))
|
||||
notebook))))))
|
||||
(ein:aif ein:%notebook%
|
||||
(progn
|
||||
(ein:kernel-disconnect (ein:$notebook-kernel it))
|
||||
(ein:events-trigger (ein:$kernel-events (ein:$notebook-kernel it))
|
||||
'status_reconnecting.Kernel)
|
||||
(ein:kernel-session-p
|
||||
it (apply-partially callback it)))))
|
||||
|
||||
(autoload 'org-toggle-latex-fragment "org")
|
||||
(defalias 'ein:notebook-toggle-latex-fragment 'org-toggle-latex-fragment
|
||||
"Borrow from org-mode the rendering of latex overlays")
|
||||
|
||||
(defun ein:notebook-restart-kernel-command ()
|
||||
"Send request to the server to restart kernel."
|
||||
(defun ein:notebook-restart-session-command ()
|
||||
"Delete session on server side. Start new session."
|
||||
(interactive)
|
||||
(ein:aif ein:%notebook%
|
||||
(when (or (not (ein:kernel-live-p (ein:$notebook-kernel it)))
|
||||
(y-or-n-p "Restart kernel? "))
|
||||
(ein:notebook-restart-kernel it))
|
||||
(ein:log 'error "Not in notebook buffer!")))
|
||||
(if (y-or-n-p "Are you sure? ")
|
||||
(ein:kernel-restart-session it))
|
||||
(message "Not in notebook buffer!")))
|
||||
|
||||
(define-obsolete-function-alias
|
||||
'ein:notebook-request-tool-tip-or-help-command
|
||||
|
@ -598,11 +600,6 @@ This is equivalent to do ``C-c`` in the console program."
|
|||
(interactive)
|
||||
(ein:kernel-interrupt (ein:$notebook-kernel ein:%notebook%)))
|
||||
|
||||
(defun ein:notebook-kernel-delete-command ()
|
||||
(interactive)
|
||||
(when (y-or-n-p "Delete kernel?")
|
||||
(ein:kernel-delete (ein:$notebook-kernel ein:%notebook%))))
|
||||
|
||||
;; autoexec
|
||||
|
||||
(defun ein:notebook-execute-autoexec-cells (notebook)
|
||||
|
@ -903,7 +900,7 @@ as usual."
|
|||
(let ((kernel (ein:$notebook-kernel notebook)))
|
||||
;; If kernel is live, kill it before closing.
|
||||
(if (ein:kernel-live-p kernel)
|
||||
(ein:kernel-delete kernel (apply-partially #'ein:notebook-close notebook))
|
||||
(ein:kernel-delete-session kernel (apply-partially #'ein:notebook-close notebook))
|
||||
(ein:notebook-close notebook)))))
|
||||
|
||||
(defun ein:fast-content-from-notebook (notebook)
|
||||
|
@ -1388,8 +1385,8 @@ This hook is run regardless the actual major mode used."
|
|||
(define-key map (kbd "C-c C-$") 'ein:tb-show)
|
||||
(define-key map "\C-c\C-x" nil)
|
||||
(define-key map "\C-c\C-x\C-l" 'ein:notebook-toggle-latex-fragment)
|
||||
(define-key map "\C-c\C-x\C-r" 'ein:notebook-restart-kernel-command)
|
||||
(define-key map "\C-c\C-r" 'ein:notebook-reconnect-kernel)
|
||||
(define-key map "\C-c\C-x\C-r" 'ein:notebook-restart-session-command)
|
||||
(define-key map "\C-c\C-r" 'ein:notebook-reconnect-session-command)
|
||||
(define-key map "\C-c\C-z" 'ein:notebook-kernel-interrupt-command)
|
||||
(define-key map "\C-c\C-q" 'ein:notebook-kill-kernel-then-close-command)
|
||||
(define-key map (kbd "C-c C-#") 'ein:notebook-close)
|
||||
|
@ -1494,8 +1491,8 @@ This hook is run regardless the actual major mode used."
|
|||
ein:worksheet-next-input-history))))
|
||||
("Kernel"
|
||||
,@(ein:generate-menu
|
||||
'(("Restart kernel" ein:notebook-restart-kernel-command)
|
||||
("Reconnect kernel" ein:notebook-reconnect-kernel)
|
||||
'(("Restart session" ein:notebook-restart-session-command)
|
||||
("Reconnect session" ein:notebook-reconnect-session-command)
|
||||
("Switch kernel" ein:notebook-switch-kernel)
|
||||
("Interrupt kernel" ein:notebook-kernel-interrupt-command))))
|
||||
("Worksheets [Experimental]"
|
||||
|
|
|
@ -372,9 +372,10 @@ This function is called via `ein:notebook-after-rename-hook'."
|
|||
|
||||
TODO - New and open should be separate, and we should flag an exception if we try to new an existing.
|
||||
"
|
||||
|
||||
(interactive (list (ein:notebooklist-ask-url-or-port)
|
||||
(completing-read
|
||||
"Select kernel [default]: "
|
||||
(ido-completing-read
|
||||
"Select kernel: "
|
||||
(ein:list-available-kernels (ein:$notebooklist-url-or-port ein:%notebooklist%)) nil t nil nil "default" nil)))
|
||||
(let ((path (or path (ein:$notebooklist-path (or ein:%notebooklist%
|
||||
(ein:notebooklist-list-get url-or-port)))))
|
||||
|
@ -436,8 +437,8 @@ You may find the new one in the notebook list." error)
|
|||
"Open new notebook and rename the notebook."
|
||||
(interactive (let* ((url-or-port (or (ein:get-url-or-port)
|
||||
(ein:default-url-or-port)))
|
||||
(kernelspec (completing-read
|
||||
"Select kernel [default]: "
|
||||
(kernelspec (ido-completing-read
|
||||
"Select kernel: "
|
||||
(ein:list-available-kernels url-or-port) nil t nil nil "default" nil))
|
||||
(name (read-from-minibuffer
|
||||
(format "Notebook name (at %s): " url-or-port))))
|
||||
|
@ -651,6 +652,7 @@ You may find the new one in the notebook list." error)
|
|||
(ein:format-time-string ein:notebooklist-date-format dt))))
|
||||
|
||||
(defun render-directory (url-or-port sessions)
|
||||
;; SESSIONS is a hashtable of path to (session-id . kernel-id) pairs
|
||||
(with-current-buffer (ein:notebooklist-get-buffer url-or-port)
|
||||
(widget-insert "\n------------------------------------------\n\n")
|
||||
(ein:make-sorting-widget "Sort by" ein:notebooklist-sort-field)
|
||||
|
@ -712,12 +714,14 @@ You may find the new one in the notebook list." error)
|
|||
(if (gethash path sessions)
|
||||
(widget-create
|
||||
'link
|
||||
:notify (lexical-let ((session (car (gethash path sessions)))
|
||||
(nblist ein:%notebooklist%))
|
||||
:notify (lexical-let ((url-or-port url-or-port)
|
||||
(path path)
|
||||
(session (car (gethash path sessions))))
|
||||
(lambda (&rest ignore)
|
||||
(run-at-time 1 nil #'ein:notebooklist-reload)
|
||||
(ein:kernel-delete (make-ein:$kernel :url-or-port (ein:$notebooklist-url-or-port nblist)
|
||||
:session-id session))))
|
||||
;; can only stop opened notebooks
|
||||
(ein:and-let* ((nb (ein:notebook-get-opened-notebook url-or-port path)))
|
||||
(ein:kernel-delete-session (ein:$notebook-kernel nb)))))
|
||||
"Stop")
|
||||
(widget-insert "------"))
|
||||
(widget-insert " ")
|
||||
|
|
|
@ -41,12 +41,9 @@
|
|||
(content (make-ein:$content :url-or-port ein:testing-notebook-dummy-url
|
||||
:notebook-version 3
|
||||
:path path)))
|
||||
;; using dynamically scoped flet instead of cl-flet, where
|
||||
;; "bindings are lexical... all references to the named functions
|
||||
;; must appear physically within the body of the cl-flet"
|
||||
(flet ((pop-to-buffer (buf) buf)
|
||||
(ein:need-notebook-version (url-or-port) 3)
|
||||
(ein:notebook-start-kernel (notebook))
|
||||
(ein:notebook-new-session (notebook))
|
||||
(ein:notebook-enable-autosaves (notebook)))
|
||||
(let ((notebook (ein:notebook-new ein:testing-notebook-dummy-url path kernelspec)))
|
||||
(setf (ein:$notebook-kernel notebook)
|
||||
|
|
|
@ -3,17 +3,20 @@
|
|||
|
||||
(require 'ein-kernel)
|
||||
(require 'ein-testing-kernel)
|
||||
(require 'ein-testing-notebook)
|
||||
|
||||
(defun eintest:kernel-new (port)
|
||||
(ein:kernel-new port "/api/kernels"
|
||||
(get-buffer-create "*eintest: dummy for kernel test*")))
|
||||
|
||||
(ert-deftest ein:kernel-restart-check-url ()
|
||||
(lexical-let* ((kernel (eintest:kernel-new 8888))
|
||||
(lexical-let* ((notebook (ein:notebook-new ein:testing-notebook-dummy-url "" nil))
|
||||
(kernel (eintest:kernel-new 8888))
|
||||
(kernel-id "KERNEL-ID")
|
||||
(desired-url "http://127.0.0.1:8888/api/sessions/KERNEL-ID")
|
||||
(dummy-response (make-request-response))
|
||||
got-url)
|
||||
(setq (ein:$notebook-kernel notebook) kernel)
|
||||
(cl-letf (((symbol-function 'request)
|
||||
(lambda (url &rest ignore) (setq got-url url) dummy-response))
|
||||
((symbol-function 'set-process-query-on-exit-flag) #'ignore)
|
||||
|
@ -21,9 +24,9 @@
|
|||
((symbol-function 'ein:websocket) (lambda (&rest ignore) (make-ein:$websocket :ws nil :kernel kernel :closed-by-client nil)))
|
||||
((symbol-function 'ein:events-trigger) #'ignore)
|
||||
((symbol-function 'ein:get-notebook-or-error) (lambda () (ein:get-notebook))))
|
||||
(ein:kernel-start--success
|
||||
(ein:kernel-retrieve-session--success
|
||||
kernel nil :data (list :ws_url "ws://127.0.0.1:8888" :id kernel-id))
|
||||
(ein:kernel-restart kernel)
|
||||
(ein:kernel-restart-session notebook)
|
||||
(should (equal got-url desired-url)))))
|
||||
|
||||
(ert-deftest ein:kernel-interrupt-check-url ()
|
||||
|
@ -37,7 +40,7 @@
|
|||
(ein:kernel-stop-channels (&rest ignore))
|
||||
(ein:websocket (url kernel on-message on-close on-open) (make-ein:$websocket :ws nil :kernel kernel :closed-by-client nil))
|
||||
(ein:websocket-open-p (websocket) t))
|
||||
(ein:kernel-start--success
|
||||
(ein:kernel-retrieve-session--success
|
||||
kernel nil :data (list :ws_url "ws://127.0.0.1:8888" :id kernel-id))
|
||||
(ein:kernel-interrupt kernel)
|
||||
(should (equal got-url desired-url)))))
|
||||
|
@ -52,10 +55,10 @@
|
|||
(set-process-query-on-exit-flag (process flag))
|
||||
(ein:kernel-stop-channels (&rest ignore))
|
||||
(ein:websocket (url kernel on-message on-close on-open) (make-ein:$websocket :ws nil :kernel kernel :closed-by-client nil)))
|
||||
(ein:kernel-start--success
|
||||
(ein:kernel-retrieve-session--success
|
||||
kernel nil :data (list :ws_url "ws://127.0.0.1:8888" :id kernel-id))
|
||||
(ein:kernel-delete kernel)
|
||||
(should (equal got-url desired-url)))))
|
||||
(ein:kernel-delete-session kernel))
|
||||
(should (equal got-url desired-url))))
|
||||
|
||||
|
||||
;;; Test `ein:kernel-construct-help-string'
|
||||
|
|
|
@ -968,7 +968,7 @@ defined."
|
|||
((ein:kernel-live-p
|
||||
(kernel)
|
||||
((:input (list kernel) :output t)))
|
||||
(ein:kernel-delete
|
||||
(ein:kernel-delete-session
|
||||
(kernel &optional callback)
|
||||
((:input (list kernel (apply-partially #'ein:notebook-close notebook))))))
|
||||
(call-interactively #'ein:notebook-kill-kernel-then-close-command))
|
||||
|
|
Loading…
Add table
Reference in a new issue