Merge branch 'ein-query'

This commit is contained in:
Takafumi Arakaki 2012-05-27 01:39:39 +02:00
commit 66a8a90ddc
8 changed files with 387 additions and 172 deletions

View file

@ -31,7 +31,7 @@
(require 'ein-utils) (require 'ein-utils)
(require 'ein-websocket) (require 'ein-websocket)
(require 'ein-events) (require 'ein-events)
(require 'url) (require 'ein-query)
(defstruct ein:$kernel (defstruct ein:$kernel
@ -90,17 +90,14 @@ FIXME: document other slots."
(defun ein:kernel-start (kernel notebook-id) (defun ein:kernel-start (kernel notebook-id)
"Start kernel of the notebook whose id is NOTEBOOK-ID." "Start kernel of the notebook whose id is NOTEBOOK-ID."
(unless (ein:$kernel-running kernel) (unless (ein:$kernel-running kernel)
(let* ((qs (format "notebook=%s" notebook-id)) (ein:query-ajax
(url (concat (ein:url (ein:$kernel-url-or-port kernel) (concat (ein:url (ein:$kernel-url-or-port kernel)
(ein:$kernel-base-url kernel)) (ein:$kernel-base-url kernel))
"?" qs)) "?" (format "notebook=%s" notebook-id))
(url-request-method "POST")) :type "POST"
(url-retrieve :parser #'ein:json-read
url :success (cons #'ein:kernel--kernel-started kernel)
(lambda (status kernel) :timeout 5000)))
(ein:kernel--kernel-started kernel (ein:json-read))
(kill-buffer (current-buffer)))
(list kernel)))))
(defun ein:kernel-restart (kernel) (defun ein:kernel-restart (kernel)
@ -109,23 +106,21 @@ FIXME: document other slots."
(ein:log 'info "Restarting kernel") (ein:log 'info "Restarting kernel")
(when (ein:$kernel-running kernel) (when (ein:$kernel-running kernel)
(ein:kernel-stop-channels kernel) (ein:kernel-stop-channels kernel)
(let ((url (ein:url (ein:$kernel-url-or-port kernel) (ein:query-ajax
(ein:$kernel-kernel-url kernel) (ein:url (ein:$kernel-url-or-port kernel)
"restart")) (ein:$kernel-kernel-url kernel)
(url-request-method "POST")) "restart")
(url-retrieve :type "POST"
url :parser #'ein:json-read
(lambda (status kernel) :success (cons #'ein:kernel--kernel-started kernel)
(ein:kernel--kernel-started kernel (ein:json-read)) :timeout 5000)))
(kill-buffer (current-buffer)))
(list kernel)))))
(defun ein:kernel--kernel-started (kernel json) (defun* ein:kernel--kernel-started (kernel &key data &allow-other-keys)
(ein:log 'info "Kernel started: %s" (plist-get json :kernel_id)) (ein:log 'info "Kernel started: %s" (plist-get data :kernel_id))
(setf (ein:$kernel-running kernel) t) (setf (ein:$kernel-running kernel) t)
(setf (ein:$kernel-kernel-id kernel) (plist-get json :kernel_id)) (setf (ein:$kernel-kernel-id kernel) (plist-get data :kernel_id))
(setf (ein:$kernel-ws-url kernel) (plist-get json :ws_url)) (setf (ein:$kernel-ws-url kernel) (plist-get data :ws_url))
(setf (ein:$kernel-kernel-url kernel) (setf (ein:$kernel-kernel-url kernel)
(concat (ein:$kernel-base-url kernel) "/" (concat (ein:$kernel-base-url kernel) "/"
(ein:$kernel-kernel-id kernel))) (ein:$kernel-kernel-id kernel)))
@ -362,29 +357,29 @@ http://ipython.org/ipython-doc/dev/development/messaging.html#complete
(defun ein:kernel-interrupt (kernel) (defun ein:kernel-interrupt (kernel)
(when (ein:$kernel-running kernel) (when (ein:$kernel-running kernel)
(ein:log 'info "Interrupting kernel") (ein:log 'info "Interrupting kernel")
(let ((url (ein:url (ein:$kernel-url-or-port kernel) (ein:query-ajax
(ein:$kernel-kernel-url kernel) (ein:url (ein:$kernel-url-or-port kernel)
"interrupt")) (ein:$kernel-kernel-url kernel)
(url-request-method "POST")) "interrupt")
(url-retrieve :type "POST"
url :success (cons (lambda (&rest ignore)
(lambda (s) (ein:log 'info "Sent interruption command."))
(ein:log 'info "Sent interruption command.") nil)
(kill-buffer (current-buffer))))))) :timeout 5000)))
(defun ein:kernel-kill (kernel) (defun ein:kernel-kill (kernel)
(when (ein:$kernel-running kernel) (when (ein:$kernel-running kernel)
(setf (ein:$kernel-running kernel) nil) (setf (ein:$kernel-running kernel) nil)
(let ((url-request-method "DELETE") (ein:query-ajax
(url (ein:url-no-cache (ein:url (ein:$kernel-url-or-port kernel)
(ein:url (ein:$kernel-url-or-port kernel) (ein:$kernel-kernel-url kernel))
(ein:$kernel-kernel-url kernel))))) :cache nil
(url-retrieve :type "DELETE"
url :success (cons (lambda (&rest ignore)
(lambda (s) (ein:log 'info "Notebook kernel is killed"))
(ein:log 'info "Notebook kernel is killed") nil)
(kill-buffer (current-buffer))))))) :timeout 5000)))
;; Reply handlers. ;; Reply handlers.

View file

@ -92,16 +92,23 @@
(get-buffer-create (format ein:log-buffer-name-template name))) (get-buffer-create (format ein:log-buffer-name-template name)))
(ein:log 'verbose "Start logging.")) (ein:log 'verbose "Start logging."))
;; FIXME: this variable must go to somewhere more central
(defvar ein:debug nil
"Set to non-`nil' to raise errors instead of suppressing it.
Change the behavior of `ein:log-ignore-errors'.")
(defmacro ein:log-ignore-errors (&rest body) (defmacro ein:log-ignore-errors (&rest body)
"Execute BODY; if an error occurs, log the error and return nil. "Execute BODY; if an error occurs, log the error and return nil.
Otherwise, return result of last form in BODY." Otherwise, return result of last form in BODY."
(declare (debug t) (indent 0)) (declare (debug t) (indent 0))
`(condition-case err `(if ein:debug
(progn ,@body) (progn ,@body)
(error (condition-case err
(ein:log 'debug "Error: %S" err) (progn ,@body)
(ein:log 'error (error-message-string err)) (error
nil))) (ein:log 'debug "Error: %S" err)
(ein:log 'error (error-message-string err))
nil))))
(defun ein:log-del () (defun ein:log-del ()
"Kill buffer `ein:log-buffer'." "Kill buffer `ein:log-buffer'."

View file

@ -21,7 +21,14 @@
;;; Commentary: ;;; Commentary:
;; ;; * Coding rule about current buffer.
;; A lot of notebook and cell functions touches to current buffer and
;; it is not ideal to wrap all these functions by `with-current-buffer'.
;; Therefore, when the function takes `notebook' to the first argument
;; ("method" function), it is always assumed that the current buffer
;; is the notebook buffer. **However**, functions called as callback
;; (via `url-retrieve', for example) must protect themselves by
;; calling from unknown buffer.
;;; Code: ;;; Code:
@ -39,6 +46,7 @@
(require 'ein-events) (require 'ein-events)
(require 'ein-notification) (require 'ein-notification)
(require 'ein-kill-ring) (require 'ein-kill-ring)
(require 'ein-query)
;;; Configuration ;;; Configuration
@ -62,12 +70,13 @@ yet. So be careful when using EIN functions. They may change."
) )
:group 'ein) :group 'ein)
(defun ein:notebook-discard-output-p () (defun ein:notebook-discard-output-p (notebook)
"Return non-`nil' if the output must be discarded, otherwise save." "Return non-`nil' if the output must be discarded, otherwise save."
(case ein:notebook-discard-output-on-save (case ein:notebook-discard-output-on-save
(no nil) (no nil)
(yes t) (yes t)
(t (funcall ein:notebook-discard-output-on-save)))) (t (with-current-buffer (ein:notebook-buffer notebook)
(funcall ein:notebook-discard-output-on-save)))))
;;; Class and variable ;;; Class and variable
@ -212,18 +221,18 @@ the time of execution."
(let ((url (ein:notebook-url-from-url-and-id url-or-port notebook-id)) (let ((url (ein:notebook-url-from-url-and-id url-or-port notebook-id))
(notebook (ein:notebook-new url-or-port notebook-id))) (notebook (ein:notebook-new url-or-port notebook-id)))
(ein:log 'debug "Opening notebook at %s" url) (ein:log 'debug "Opening notebook at %s" url)
(url-retrieve url (ein:query-ajax
#'ein:notebook-url-retrieve-callback url
(list notebook)) :parser #'ein:json-read
:success (cons #'ein:notebook-request-open-callback notebook))
notebook)) notebook))
(defun ein:notebook-url-retrieve-callback (status notebook) (defun* ein:notebook-request-open-callback (notebook &key status data
&allow-other-keys)
(ein:log 'debug "URL-RETRIEVE nodtebook-id = %S, status = %S" (ein:log 'debug "URL-RETRIEVE nodtebook-id = %S, status = %S"
(ein:$notebook-notebook-id notebook) (ein:$notebook-notebook-id notebook)
status) status)
(let ((data (ein:json-read)) (let ((notebook-id (ein:$notebook-notebook-id notebook)))
(notebook-id (ein:$notebook-notebook-id notebook)))
(kill-buffer (current-buffer))
(ein:notebook-init notebook data) (ein:notebook-init notebook data)
(with-current-buffer (ein:notebook-get-buffer notebook) (with-current-buffer (ein:notebook-get-buffer notebook)
(ein:log-setup (ein:$notebook-notebook-id notebook)) (ein:log-setup (ein:$notebook-notebook-id notebook))
@ -738,7 +747,7 @@ Do not clear input prompts when the prefix argument is given."
(defun ein:notebook-to-json (notebook) (defun ein:notebook-to-json (notebook)
"Return json-ready alist." "Return json-ready alist."
(let* ((discard (ein:notebook-discard-output-p)) (let* ((discard (ein:notebook-discard-output-p notebook))
(cells (mapcar (lambda (c) (ein:cell-to-json c discard)) (cells (mapcar (lambda (c) (ein:cell-to-json c discard))
(ein:notebook-get-cells notebook)))) (ein:notebook-get-cells notebook))))
`((worksheets . [((cells . ,(apply #'vector cells)))]) `((worksheets . [((cells . ,(apply #'vector cells)))])
@ -751,63 +760,54 @@ Do not clear input prompts when the prefix argument is given."
(push `(nbformat . ,(ein:$notebook-nbformat notebook)) data) (push `(nbformat . ,(ein:$notebook-nbformat notebook)) data)
(ein:events-trigger (ein:$notebook-events notebook) (ein:events-trigger (ein:$notebook-events notebook)
'(notebook_saving . Notebook)) '(notebook_saving . Notebook))
(let ((url (ein:url-no-cache (ein:notebook-url notebook))) (ein:query-ajax
(url-request-method "PUT") (ein:notebook-url notebook)
(url-request-extra-headers '(("Content-Type" . "application/json"))) :type "PUT"
(url-request-data (json-encode data))) :headers '(("Content-Type" . "application/json"))
(ein:log 'debug "URL-RETRIEVE url = %s" url) :cache nil
(ein:log 'debug "URL-REQUEST-DATA = %s" url-request-data) :data (json-encode data)
(url-retrieve :error (cons #'ein:notebook-save-notebook-error notebook)
url :success (cons #'ein:notebook-save-notebook-workaround
#'ein:notebook-save-notebook-callback (cons notebook retry))
(list notebook retry))))) :status-code
`((204 . ,(cons #'ein:notebook-save-notebook-success notebook)))
:timeout 5000)))
(defun ein:notebook-save-notebook-command () (defun ein:notebook-save-notebook-command ()
(interactive) (interactive)
(ein:notebook-save-notebook ein:notebook 0)) (ein:notebook-save-notebook ein:notebook 0))
(defun ein:notebook-save-notebook-callback (status notebook retry) (defun* ein:notebook-save-notebook-workaround (nb-retry &rest args
(declare (special url-http-response-status &key
url-http-method)) status
(ein:log 'debug "SAVE-NOTEBOOK-CALLBACK nodtebook-id = %S, status = %S" response-status
(ein:$notebook-notebook-id notebook) &allow-other-keys)
status) ;; IPython server returns 204 only when the notebook URL is
(ein:log 'debug "url-http-response-status = %s" url-http-response-status) ;; accessed via PUT or DELETE. As it seems Emacs failed to
(ein:log 'debug "url-request-method = %s" url-request-method) ;; choose PUT method every two times, let's check the response
(ein:log 'debug "url-http-method = %s" (when (boundp 'url-http-method) ;; here and fail when 204 is not returned.
url-http-method)) (unless (eq response-status 204)
(ein:log 'debug "(buffer-string) = \n%s" (buffer-string)) (let ((notebook (car nb-retry))
(let ((response url-http-response-status)) (retry (cdr nb-retry)))
;; ^-- "save" local variable before killing buffer. (with-current-buffer (ein:notebook-buffer notebook)
(kill-buffer (current-buffer)) (if (< retry ein:notebook-save-retry-max)
(with-current-buffer (ewoc-buffer (ein:$notebook-ewoc notebook)) (progn
(ein:aif (plist-get status :error) (ein:log 'info "Retry saving... Next count: %s" (1+ retry))
(progn (ein:notebook-save-notebook notebook (1+ retry)))
(ein:log 'debug "ERROR CODE = %S" it) (ein:notebook-save-notebook-error notebook :status status)
(ein:notebook-save-notebook-error notebook status)) (ein:log 'info
;; IPython server returns 204 only when the notebook URL is "Status code (=%s) is not 204 and retry exceeds limit (=%s)."
;; accessed via PUT or DELETE. As it seems Emacs failed to response-status ein:notebook-save-retry-max))))))
;; choose PUT method every two times, let's check the response
;; here and fail when 204 is not returned.
(if (eq response 204)
(ein:notebook-save-notebook-success notebook status)
(if (< retry ein:notebook-save-retry-max)
(progn
(ein:log 'info "Retry saving... Next count: %s" (1+ retry))
(ein:notebook-save-notebook notebook (1+ retry)))
(ein:notebook-save-notebook-error notebook status)
(ein:log 'info
"Status code (=%s) is not 204 and retry exceeds limit (=%s)."
response ein:notebook-save-retry-max)))))))
(defun ein:notebook-save-notebook-success (notebook status) (defun ein:notebook-save-notebook-success (notebook &rest ignore)
(ein:log 'info "Notebook is saved.") (ein:log 'info "Notebook is saved.")
(setf (ein:$notebook-dirty notebook) nil) (setf (ein:$notebook-dirty notebook) nil)
(set-buffer-modified-p nil) (with-current-buffer (ein:notebook-buffer notebook)
(set-buffer-modified-p nil))
(ein:events-trigger (ein:$notebook-events notebook) (ein:events-trigger (ein:$notebook-events notebook)
'(notebook_saved . Notebook))) '(notebook_saved . Notebook)))
(defun ein:notebook-save-notebook-error (notebook status) (defun ein:notebook-save-notebook-error (notebook &rest ignore)
(ein:log 'info "Failed to save notebook!") (ein:log 'info "Failed to save notebook!")
(ein:events-trigger (ein:$notebook-events notebook) (ein:events-trigger (ein:$notebook-events notebook)
'(notebook_save_failed . Notebook))) '(notebook_save_failed . Notebook)))

View file

@ -71,29 +71,36 @@
(when (and (stringp url-or-port) (when (and (stringp url-or-port)
(string-match "^[0-9]+$" url-or-port)) (string-match "^[0-9]+$" url-or-port))
(setq url-or-port (string-to-number url-or-port))) (setq url-or-port (string-to-number url-or-port)))
(url-retrieve (let ((success
(ein:notebooklist-url url-or-port) (if no-popup
(if no-popup #'ein:notebooklist-url-retrieve-callback
#'ein:notebooklist-url-retrieve-callback (lambda (&rest args)
(lambda (&rest args) (pop-to-buffer
(pop-to-buffer (apply #'ein:notebooklist-url-retrieve-callback args)))) (apply #'ein:notebooklist-url-retrieve-callback args))))))
(list url-or-port)) (ein:query-ajax
(ein:notebooklist-url url-or-port)
:cache nil
:parser #'ein:json-read
:success (cons success url-or-port)
:timeout 5000))
(ein:notebooklist-get-buffer url-or-port)) (ein:notebooklist-get-buffer url-or-port))
(defun ein:notebooklist-url-retrieve-callback (status url-or-port) (defun* ein:notebooklist-url-retrieve-callback (url-or-port
&key
status
data
&allow-other-keys)
"Called via `ein:notebooklist-open'." "Called via `ein:notebooklist-open'."
(ein:aif (plist-get status :error) (ein:aif (plist-get status :error)
(error "Failed to connect to server '%s'. Got: %S" (error "Failed to connect to server '%s'. Got: %S"
(ein:url url-or-port) it)) (ein:url url-or-port) it))
(let ((data (ein:json-read))) (with-current-buffer (ein:notebooklist-get-buffer url-or-port)
(kill-buffer (current-buffer)) (setq ein:notebooklist
(with-current-buffer (ein:notebooklist-get-buffer url-or-port) (make-ein:$notebooklist :url-or-port url-or-port
(setq ein:notebooklist :data data))
(make-ein:$notebooklist :url-or-port url-or-port (ein:notebooklist-render)
:data data)) (goto-char (point-min))
(ein:notebooklist-render) (current-buffer)))
(goto-char (point-min))
(current-buffer))))
(defun ein:notebooklist-reload () (defun ein:notebooklist-reload ()
"Reload current Notebook list." "Reload current Notebook list."
@ -117,20 +124,24 @@
"Ask server to create a new notebook and update the notebook list buffer." "Ask server to create a new notebook and update the notebook list buffer."
(message "Creating a new notebook...") (message "Creating a new notebook...")
(unless (setq url-or-port (ein:$notebooklist-url-or-port ein:notebooklist))) (unless (setq url-or-port (ein:$notebooklist-url-or-port ein:notebooklist)))
(url-retrieve (ein:query-ajax
(ein:notebooklist-new-url url-or-port) (ein:notebooklist-new-url url-or-port)
(lambda (s buffer) :parser (lambda ()
(let ((notebook-id (ein:notebooklist-get-data-in-body-tag "data-notebook-id"))
(ein:notebooklist-get-data-in-body-tag "data-notebook-id"))) :success (cons #'ein:notebooklist-new-notebook-callback (current-buffer))
(kill-buffer (current-buffer)) :timeout 5000))
(message "Creating a new notebook... Done.")
(with-current-buffer buffer (defun* ein:notebooklist-new-notebook-callback (buffer &key
(if notebook-id data
(ein:notebooklist-open-notebook ein:notebooklist notebook-id) &allow-other-keys)
(message (concat "Oops. EIN failed to open new notebook. " (let ((notebook-id data))
"Please find it in the notebook list.")) (message "Creating a new notebook... Done.")
(ein:notebooklist-reload))))) (with-current-buffer buffer
(list (current-buffer)))) (if notebook-id
(ein:notebooklist-open-notebook ein:notebooklist notebook-id)
(message (concat "Oops. EIN failed to open new notebook. "
"Please find it in the notebook list."))
(ein:notebooklist-reload)))))
(defun ein:notebooklist-delete-notebook-ask (notebook-id name) (defun ein:notebooklist-delete-notebook-ask (notebook-id name)
(when (y-or-n-p (format "Delete notebook %s?" name)) (when (y-or-n-p (format "Delete notebook %s?" name))
@ -138,19 +149,17 @@
(defun ein:notebooklist-delete-notebook (notebook-id name) (defun ein:notebooklist-delete-notebook (notebook-id name)
(message "Deleting notebook %s..." name) (message "Deleting notebook %s..." name)
(let ((url (ein:url-no-cache (ein:query-ajax
(ein:notebook-url-from-url-and-id (ein:notebook-url-from-url-and-id
(ein:$notebooklist-url-or-port ein:notebooklist) (ein:$notebooklist-url-or-port ein:notebooklist)
notebook-id))) notebook-id)
(url-request-method "DELETE")) :cache nil
(url-retrieve :type "DELETE"
url :success (cons (lambda (packed &rest ignore)
(lambda (s buffer name) (message "Deleting notebook %s... Done." (cdr packed))
(kill-buffer (current-buffer)) (with-current-buffer (car packed)
(message "Deleting notebook %s... Done." name) (ein:notebooklist-reload)))
(with-current-buffer buffer (cons (current-buffer) name))))
(ein:notebooklist-reload)))
(list (current-buffer) name))))
(defun ein:notebooklist-render () (defun ein:notebooklist-render ()
"Render notebook list widget. "Render notebook list widget.

179
ein-query.el Normal file
View file

@ -0,0 +1,179 @@
;;; ein-query.el --- jQuery like interface on to of url-retrieve
;; Copyright (C) 2012- Takafumi Arakaki
;; Author: Takafumi Arakaki
;; This file is NOT part of GNU Emacs.
;; ein-query.el 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 of the License, or
;; (at your option) any later version.
;; ein-query.el 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 ein-query.el. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;
;;; Code:
(eval-when-compile (require 'cl))
(require 'url)
(require 'ein-utils)
(require 'ein-log)
(defun ein:safe-funcall-packed (packed &rest args)
(when packed
(ein:log-ignore-errors (apply #'ein:funcall-packed packed args))))
(defmacro ein:with-live-buffer (buffer &rest body)
"Execute BODY if BUFFER is alive."
(declare (indent 1) (debug t))
`(when (buffer-live-p ,buffer) (with-current-buffer ,buffer ,@body)))
(ein:deflocal ein:query-ajax-timer nil)
(defun* ein:query-ajax (url &rest settings
&key
(cache t)
(type "GET")
(data nil)
(parser nil)
(headers nil)
(success nil)
(error nil)
(timeout nil)
(status-code nil))
"Mimic `$.ajax'.
:CACHE (nil/t) : append time-stamp to URL so the URL is always loaded.
:TYPE (string) : sets `url-request-method'
:DATA (string) : sets `url-request-data'
:PARSER (symbol) : a function that reads current buffer and return data
:HEADERS (alist) : sets `url-request-extra-headers'
:SUCCESS (cons) : called on success
:ERROR (cons) : called on error
:TIMEOUT (number) : timeout in millisecond
:STATUS-CODE (alist) : map status code (int) to callback (cons)
* Callback functions
All callbacks must be given as `cons' where car is a FUNCTION and
cdr is its first ARGUMENT. It is analogous of `$.proxy'. Call
signature is like this:
\(FUNCTION ARGUMENT [other callback specific arguments])
Also note that the callback FUNCTION must be defined
using `defun*' with `&key' and `&allow-other-keys' to ignore
missing/extra arguments as some callback (namely :ERROR) changes
arguments to be passed, depending on situation.
* :ERROR callback
:SYMBOL-STATUS (`error'/`timeout') : analogous of `textStatus'
:STATUS (list) : see `url-retrieve'
:RESPONSE-STATUS : = `url-http-response-status'
* :SUCCESS callback
This callback takes :DATA (object), which is a data object parsed
by :PARSER. If :PARSER is not specified, this is nil.
The :SUCCESS callback also takes the :STATUS and :RESPONSE-STATUS
argument.
* :STATUS-CODE callback
Each value of this alist is a callback which is similar to :ERROR
or :SUCCESS callback. However, current buffer of this callback
is not guaranteed to be the process buffer.
* :PARSER function
This is analogous to the `dataType' argument of `$.ajax'.
Only this function can accuses to the process buffer, which
is killed immediately after the execution of this function.
* See also: http://api.jquery.com/jQuery.ajax/"
(ein:log 'debug "EIN:QUERY-AJAX")
(unless cache
(setq url (ein:url-no-cache url)))
(let* ((url-request-extra-headers headers)
(url-request-method type)
(url-request-data data)
(buffer (url-retrieve url #'ein:query-ajax-callback settings)))
(when timeout
(ein:log 'debug "Start timer: timeout=%s ms" timeout)
(with-current-buffer buffer
(setq ein:query-ajax-timer
(apply #'run-at-time
(/ timeout 1000.0) nil
#'ein:query-ajax-timeout-callback
(cons buffer settings)))))
buffer))
(defun* ein:query-ajax-callback (status &key
(headers nil)
(parser nil)
(success nil)
(error nil)
(timeout nil)
(status-code nil)
&allow-other-keys)
(declare (special url-http-response-status))
(ein:log 'debug "EIN:QUERY-AJAX-CALLBACK")
(ein:log 'debug "status = %S" status)
(ein:log 'debug "url-http-response-status = %s" url-http-response-status)
(ein:log 'debug "(buffer-string) =\n%s" (buffer-string))
(ein:query-ajax-cancel-timer)
(let* ((buffer (current-buffer)) ; `parser' could change buffer...
(response-status url-http-response-status)
(status-code-callback (cdr (assq response-status status-code)))
(status-error (plist-get status :error))
(data (if (and parser (not status-error))
(unwind-protect
(funcall parser)
(kill-buffer buffer)))))
(ein:log 'debug "data = %s" data)
(ein:log 'debug "Executing success/error callback.")
(apply #'ein:safe-funcall-packed
(append (if (plist-get status :error)
(list error :symbol-status 'error)
(list success))
(list :status status :data data
:response-status response-status)))
(ein:log 'debug "Executing status-code callback.")
(ein:safe-funcall-packed status-code-callback
:status status :data data)))
(defun* ein:query-ajax-timeout-callback (buffer &key
(error nil)
&allow-other-keys)
(ein:log 'debug "EIN:QUERY-AJAX-TIMEOUT-CALLBACK buffer = %s" buffer)
(ein:with-live-buffer buffer
(ein:safe-funcall-packed error :symbol-status 'timeout)
(let ((proc (process-buffer buffer)))
(kill-process proc)
(kill-buffer buffer))))
(defun ein:query-ajax-cancel-timer ()
(ein:log 'debug "EIN:QUERY-AJAX-CANCEL-TIMER")
(when ein:query-ajax-timer
(cancel-timer ein:query-ajax-timer)
(setq ein:query-ajax-timer nil)))
(provide 'ein-query)
;;; ein-query.el ends here

View file

@ -2,6 +2,7 @@
(require 'ert) (require 'ert)
(require 'ein-notebooklist) (require 'ein-notebooklist)
(require 'wid-edit)
;; Execute `eintest:dz-ipython-start' before starting the following ;; Execute `eintest:dz-ipython-start' before starting the following
;; test to setup server. ;; test to setup server.
@ -39,14 +40,27 @@ Make MAX-COUNT larger \(default 50) to wait longer before timeout."
(let ((notebook (eintest:get-notebook-by-name url-or-port "Untitled0"))) (let ((notebook (eintest:get-notebook-by-name url-or-port "Untitled0")))
(if notebook (if notebook
notebook notebook
(with-current-buffer (ein:notebooklist-get-buffer url-or-port) (with-current-buffer (ein:notebooklist-open url-or-port t)
(setq ein:notebooklist nil) (setq ein:notebooklist nil)
(eintest:wait-until (lambda () ein:notebooklist)) (eintest:wait-until (lambda () ein:notebooklist))
(setq ein:notebooklist nil)
(ein:notebooklist-new-notebook url-or-port) (ein:notebooklist-new-notebook url-or-port)
(eintest:wait-until (lambda () ein:notebooklist))) (eintest:wait-until
(lambda () (eintest:get-notebook-by-name url-or-port "Untitled0"))))
(eintest:get-notebook-by-name url-or-port "Untitled0")))) (eintest:get-notebook-by-name url-or-port "Untitled0"))))
(defun eintest:delete-notebook-by-name (url-or-port notebook-name)
(with-current-buffer (ein:notebooklist-open url-or-port nil)
(eintest:wait-until (lambda () ein:notebooklist))
(save-excursion
(goto-char (point-min))
(search-forward notebook-name)
(move-beginning-of-line 1)
(search-forward "Delete")
(flet ((y-or-n-p (ignore) t))
(widget-button-press (point))))
(setq ein:notebooklist nil)
(eintest:wait-until (lambda () ein:notebooklist))))
(ert-deftest eintest:get-untitled0-or-create () (ert-deftest eintest:get-untitled0-or-create ()
(let ((notebook (eintest:get-untitled0-or-create eintest:port))) (let ((notebook (eintest:get-untitled0-or-create eintest:port)))
(eintest:wait-until (lambda () (ein:aand (ein:$notebook-kernel notebook) (eintest:wait-until (lambda () (ein:aand (ein:$notebook-kernel notebook)
@ -54,6 +68,16 @@ Make MAX-COUNT larger \(default 50) to wait longer before timeout."
(with-current-buffer (ein:notebook-buffer notebook) (with-current-buffer (ein:notebook-buffer notebook)
(should (equal (ein:$notebook-notebook-name ein:notebook) "Untitled0"))))) (should (equal (ein:$notebook-notebook-name ein:notebook) "Untitled0")))))
(ert-deftest eintest:delete-untitled0 ()
(loop
repeat 2
do (let ((notebook (eintest:get-untitled0-or-create eintest:port)))
(eintest:wait-until
(lambda () (ein:aand (ein:$notebook-kernel notebook)
(ein:kernel-ready-p it)))))
do (eintest:delete-notebook-by-name eintest:port "Untitled0")
do (should-not (eintest:get-notebook-by-name eintest:port "Untitled0"))))
(ert-deftest ein:notebook-execute-current-cell-simple () (ert-deftest ein:notebook-execute-current-cell-simple ()
(let ((notebook (eintest:get-untitled0-or-create eintest:port))) (let ((notebook (eintest:get-untitled0-or-create eintest:port)))
(eintest:wait-until (lambda () (ein:aand (ein:$notebook-kernel notebook) (eintest:wait-until (lambda () (ein:aand (ein:$notebook-kernel notebook)

View file

@ -12,8 +12,9 @@
(let* ((kernel (eintest:kernel-new 8888)) (let* ((kernel (eintest:kernel-new 8888))
(notebook-id "NOTEBOOK-ID") (notebook-id "NOTEBOOK-ID")
(desired-url "http://127.0.0.1:8888/kernels?notebook=NOTEBOOK-ID") (desired-url "http://127.0.0.1:8888/kernels?notebook=NOTEBOOK-ID")
(dummy-buffer (get-buffer-create "*eintest:dummy*"))
got-url) got-url)
(flet ((url-retrieve (url &rest ignore) (setq got-url url))) (flet ((url-retrieve (url &rest ignore) (setq got-url url) dummy-buffer))
(ein:kernel-start kernel notebook-id) (ein:kernel-start kernel notebook-id)
(should (equal got-url desired-url))))) (should (equal got-url desired-url)))))
@ -21,12 +22,13 @@
(let* ((kernel (eintest:kernel-new 8888)) (let* ((kernel (eintest:kernel-new 8888))
(kernel-id "KERNEL-ID") (kernel-id "KERNEL-ID")
(desired-url "http://127.0.0.1:8888/kernels/KERNEL-ID/restart") (desired-url "http://127.0.0.1:8888/kernels/KERNEL-ID/restart")
(dummy-buffer (get-buffer-create "*eintest:dummy*"))
got-url) got-url)
(flet ((url-retrieve (url &rest ignore) (setq got-url url)); (flet ((url-retrieve (url &rest ignore) (setq got-url url) dummy-buffer)
(ein:kernel-stop-channels (&rest ignore)) (ein:kernel-stop-channels (&rest ignore))
(ein:websocket (&rest ignore) (make-ein:$websocket)) (ein:websocket (&rest ignore) (make-ein:$websocket))
(ein:events-trigger (&rest ignore))) (ein:events-trigger (&rest ignore)))
(ein:kernel--kernel-started kernel (list :kernel_id kernel-id)) (ein:kernel--kernel-started kernel :data (list :kernel_id kernel-id))
(ein:kernel-restart kernel) (ein:kernel-restart kernel)
(should (equal got-url desired-url))))) (should (equal got-url desired-url)))))
@ -35,11 +37,12 @@
(let* ((kernel (eintest:kernel-new 8888)) (let* ((kernel (eintest:kernel-new 8888))
(kernel-id "KERNEL-ID") (kernel-id "KERNEL-ID")
(desired-url "http://127.0.0.1:8888/kernels/KERNEL-ID/interrupt") (desired-url "http://127.0.0.1:8888/kernels/KERNEL-ID/interrupt")
(dummy-buffer (get-buffer-create "*eintest:dummy*"))
got-url) got-url)
(flet ((url-retrieve (url &rest ignore) (setq got-url url)) (flet ((url-retrieve (url &rest ignore) (setq got-url url) dummy-buffer)
(ein:kernel-stop-channels (&rest ignore)) (ein:kernel-stop-channels (&rest ignore))
(ein:websocket (&rest ignore) (make-ein:$websocket))) (ein:websocket (&rest ignore) (make-ein:$websocket)))
(ein:kernel--kernel-started kernel (list :kernel_id kernel-id)) (ein:kernel--kernel-started kernel :data (list :kernel_id kernel-id))
(ein:kernel-interrupt kernel) (ein:kernel-interrupt kernel)
(should (equal got-url desired-url))))) (should (equal got-url desired-url)))))
@ -47,11 +50,12 @@
(let* ((kernel (eintest:kernel-new 8888)) (let* ((kernel (eintest:kernel-new 8888))
(kernel-id "KERNEL-ID") (kernel-id "KERNEL-ID")
(desired-url "http://127.0.0.1:8888/kernels/KERNEL-ID") (desired-url "http://127.0.0.1:8888/kernels/KERNEL-ID")
(dummy-buffer (get-buffer-create "*eintest:dummy*"))
got-url) got-url)
(flet ((url-retrieve (url &rest ignore) (setq got-url url)) (flet ((url-retrieve (url &rest ignore) (setq got-url url) dummy-buffer)
(ein:kernel-stop-channels (&rest ignore)) (ein:kernel-stop-channels (&rest ignore))
(ein:websocket (&rest ignore) (make-ein:$websocket))) (ein:websocket (&rest ignore) (make-ein:$websocket)))
(ein:kernel--kernel-started kernel (list :kernel_id kernel-id)) (ein:kernel--kernel-started kernel :data (list :kernel_id kernel-id))
(ein:kernel-kill kernel) (ein:kernel-kill kernel)
(let* ((l (split-string got-url "?")) (let* ((l (split-string got-url "?"))
(got-url-0 (nth 0 l)) (got-url-0 (nth 0 l))

View file

@ -44,19 +44,16 @@
(defun eintest:notebook-from-json (json-string &optional notebook-id) (defun eintest:notebook-from-json (json-string &optional notebook-id)
(unless notebook-id (setq notebook-id "NOTEBOOK-ID")) (unless notebook-id (setq notebook-id "NOTEBOOK-ID"))
(with-temp-buffer (flet ((pop-to-buffer (buf) buf)
(erase-buffer) (ein:notebook-start-kernel ()))
(insert json-string) (with-current-buffer (ein:notebook-request-open-callback
(flet ((pop-to-buffer (buf) buf) (ein:notebook-new "DUMMY-URL" notebook-id)
(ein:notebook-start-kernel ())) :data (ein:json-read-from-string json-string))
(with-current-buffer (ein:notebook-url-retrieve-callback (let ((events (ein:events-new (current-buffer))))
nil (setf (ein:$notebook-events ein:notebook) events)
(ein:notebook-new "DUMMY-URL" notebook-id)) (setf (ein:$notebook-kernel ein:notebook)
(let ((events (ein:events-new (current-buffer)))) (ein:kernel-new 8888 "/kernels" events)))
(setf (ein:$notebook-events ein:notebook) events) (current-buffer))))
(setf (ein:$notebook-kernel ein:notebook)
(ein:kernel-new 8888 "/kernels" events)))
(current-buffer)))))
(defun eintest:notebook-make-data (cells &optional name) (defun eintest:notebook-make-data (cells &optional name)
(unless name (setq name "Dummy Name")) (unless name (setq name "Dummy Name"))