mirror of
https://github.com/vale981/emacs-ipython-notebook
synced 2025-03-07 01:51:39 -05:00
Merge branch 'ein-query'
This commit is contained in:
commit
66a8a90ddc
8 changed files with 387 additions and 172 deletions
|
@ -31,7 +31,7 @@
|
|||
(require 'ein-utils)
|
||||
(require 'ein-websocket)
|
||||
(require 'ein-events)
|
||||
(require 'url)
|
||||
(require 'ein-query)
|
||||
|
||||
|
||||
(defstruct ein:$kernel
|
||||
|
@ -90,17 +90,14 @@ FIXME: document other slots."
|
|||
(defun ein:kernel-start (kernel notebook-id)
|
||||
"Start kernel of the notebook whose id is NOTEBOOK-ID."
|
||||
(unless (ein:$kernel-running kernel)
|
||||
(let* ((qs (format "notebook=%s" notebook-id))
|
||||
(url (concat (ein:url (ein:$kernel-url-or-port kernel)
|
||||
(ein:$kernel-base-url kernel))
|
||||
"?" qs))
|
||||
(url-request-method "POST"))
|
||||
(url-retrieve
|
||||
url
|
||||
(lambda (status kernel)
|
||||
(ein:kernel--kernel-started kernel (ein:json-read))
|
||||
(kill-buffer (current-buffer)))
|
||||
(list kernel)))))
|
||||
(ein:query-ajax
|
||||
(concat (ein:url (ein:$kernel-url-or-port kernel)
|
||||
(ein:$kernel-base-url kernel))
|
||||
"?" (format "notebook=%s" notebook-id))
|
||||
:type "POST"
|
||||
:parser #'ein:json-read
|
||||
:success (cons #'ein:kernel--kernel-started kernel)
|
||||
:timeout 5000)))
|
||||
|
||||
|
||||
(defun ein:kernel-restart (kernel)
|
||||
|
@ -109,23 +106,21 @@ FIXME: document other slots."
|
|||
(ein:log 'info "Restarting kernel")
|
||||
(when (ein:$kernel-running kernel)
|
||||
(ein:kernel-stop-channels kernel)
|
||||
(let ((url (ein:url (ein:$kernel-url-or-port kernel)
|
||||
(ein:$kernel-kernel-url kernel)
|
||||
"restart"))
|
||||
(url-request-method "POST"))
|
||||
(url-retrieve
|
||||
url
|
||||
(lambda (status kernel)
|
||||
(ein:kernel--kernel-started kernel (ein:json-read))
|
||||
(kill-buffer (current-buffer)))
|
||||
(list kernel)))))
|
||||
(ein:query-ajax
|
||||
(ein:url (ein:$kernel-url-or-port kernel)
|
||||
(ein:$kernel-kernel-url kernel)
|
||||
"restart")
|
||||
:type "POST"
|
||||
:parser #'ein:json-read
|
||||
:success (cons #'ein:kernel--kernel-started kernel)
|
||||
:timeout 5000)))
|
||||
|
||||
|
||||
(defun ein:kernel--kernel-started (kernel json)
|
||||
(ein:log 'info "Kernel started: %s" (plist-get json :kernel_id))
|
||||
(defun* ein:kernel--kernel-started (kernel &key data &allow-other-keys)
|
||||
(ein:log 'info "Kernel started: %s" (plist-get data :kernel_id))
|
||||
(setf (ein:$kernel-running kernel) t)
|
||||
(setf (ein:$kernel-kernel-id kernel) (plist-get json :kernel_id))
|
||||
(setf (ein:$kernel-ws-url kernel) (plist-get json :ws_url))
|
||||
(setf (ein:$kernel-kernel-id kernel) (plist-get data :kernel_id))
|
||||
(setf (ein:$kernel-ws-url kernel) (plist-get data :ws_url))
|
||||
(setf (ein:$kernel-kernel-url kernel)
|
||||
(concat (ein:$kernel-base-url 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)
|
||||
(when (ein:$kernel-running kernel)
|
||||
(ein:log 'info "Interrupting kernel")
|
||||
(let ((url (ein:url (ein:$kernel-url-or-port kernel)
|
||||
(ein:$kernel-kernel-url kernel)
|
||||
"interrupt"))
|
||||
(url-request-method "POST"))
|
||||
(url-retrieve
|
||||
url
|
||||
(lambda (s)
|
||||
(ein:log 'info "Sent interruption command.")
|
||||
(kill-buffer (current-buffer)))))))
|
||||
(ein:query-ajax
|
||||
(ein:url (ein:$kernel-url-or-port kernel)
|
||||
(ein:$kernel-kernel-url kernel)
|
||||
"interrupt")
|
||||
:type "POST"
|
||||
:success (cons (lambda (&rest ignore)
|
||||
(ein:log 'info "Sent interruption command."))
|
||||
nil)
|
||||
:timeout 5000)))
|
||||
|
||||
|
||||
(defun ein:kernel-kill (kernel)
|
||||
(when (ein:$kernel-running kernel)
|
||||
(setf (ein:$kernel-running kernel) nil)
|
||||
(let ((url-request-method "DELETE")
|
||||
(url (ein:url-no-cache
|
||||
(ein:url (ein:$kernel-url-or-port kernel)
|
||||
(ein:$kernel-kernel-url kernel)))))
|
||||
(url-retrieve
|
||||
url
|
||||
(lambda (s)
|
||||
(ein:log 'info "Notebook kernel is killed")
|
||||
(kill-buffer (current-buffer)))))))
|
||||
(ein:query-ajax
|
||||
(ein:url (ein:$kernel-url-or-port kernel)
|
||||
(ein:$kernel-kernel-url kernel))
|
||||
:cache nil
|
||||
:type "DELETE"
|
||||
:success (cons (lambda (&rest ignore)
|
||||
(ein:log 'info "Notebook kernel is killed"))
|
||||
nil)
|
||||
:timeout 5000)))
|
||||
|
||||
|
||||
;; Reply handlers.
|
||||
|
|
17
ein-log.el
17
ein-log.el
|
@ -92,16 +92,23 @@
|
|||
(get-buffer-create (format ein:log-buffer-name-template name)))
|
||||
(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)
|
||||
"Execute BODY; if an error occurs, log the error and return nil.
|
||||
Otherwise, return result of last form in BODY."
|
||||
(declare (debug t) (indent 0))
|
||||
`(condition-case err
|
||||
`(if ein:debug
|
||||
(progn ,@body)
|
||||
(error
|
||||
(ein:log 'debug "Error: %S" err)
|
||||
(ein:log 'error (error-message-string err))
|
||||
nil)))
|
||||
(condition-case err
|
||||
(progn ,@body)
|
||||
(error
|
||||
(ein:log 'debug "Error: %S" err)
|
||||
(ein:log 'error (error-message-string err))
|
||||
nil))))
|
||||
|
||||
(defun ein:log-del ()
|
||||
"Kill buffer `ein:log-buffer'."
|
||||
|
|
114
ein-notebook.el
114
ein-notebook.el
|
@ -21,7 +21,14 @@
|
|||
|
||||
;;; 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:
|
||||
|
||||
|
@ -39,6 +46,7 @@
|
|||
(require 'ein-events)
|
||||
(require 'ein-notification)
|
||||
(require 'ein-kill-ring)
|
||||
(require 'ein-query)
|
||||
|
||||
|
||||
;;; Configuration
|
||||
|
@ -62,12 +70,13 @@ yet. So be careful when using EIN functions. They may change."
|
|||
)
|
||||
: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."
|
||||
(case ein:notebook-discard-output-on-save
|
||||
(no nil)
|
||||
(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
|
||||
|
@ -212,18 +221,18 @@ the time of execution."
|
|||
(let ((url (ein:notebook-url-from-url-and-id url-or-port notebook-id))
|
||||
(notebook (ein:notebook-new url-or-port notebook-id)))
|
||||
(ein:log 'debug "Opening notebook at %s" url)
|
||||
(url-retrieve url
|
||||
#'ein:notebook-url-retrieve-callback
|
||||
(list notebook))
|
||||
(ein:query-ajax
|
||||
url
|
||||
:parser #'ein:json-read
|
||||
:success (cons #'ein:notebook-request-open-callback 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:$notebook-notebook-id notebook)
|
||||
status)
|
||||
(let ((data (ein:json-read))
|
||||
(notebook-id (ein:$notebook-notebook-id notebook)))
|
||||
(kill-buffer (current-buffer))
|
||||
(let ((notebook-id (ein:$notebook-notebook-id notebook)))
|
||||
(ein:notebook-init notebook data)
|
||||
(with-current-buffer (ein:notebook-get-buffer 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)
|
||||
"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))
|
||||
(ein:notebook-get-cells notebook))))
|
||||
`((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)
|
||||
(ein:events-trigger (ein:$notebook-events notebook)
|
||||
'(notebook_saving . Notebook))
|
||||
(let ((url (ein:url-no-cache (ein:notebook-url notebook)))
|
||||
(url-request-method "PUT")
|
||||
(url-request-extra-headers '(("Content-Type" . "application/json")))
|
||||
(url-request-data (json-encode data)))
|
||||
(ein:log 'debug "URL-RETRIEVE url = %s" url)
|
||||
(ein:log 'debug "URL-REQUEST-DATA = %s" url-request-data)
|
||||
(url-retrieve
|
||||
url
|
||||
#'ein:notebook-save-notebook-callback
|
||||
(list notebook retry)))))
|
||||
(ein:query-ajax
|
||||
(ein:notebook-url notebook)
|
||||
:type "PUT"
|
||||
:headers '(("Content-Type" . "application/json"))
|
||||
:cache nil
|
||||
:data (json-encode data)
|
||||
:error (cons #'ein:notebook-save-notebook-error notebook)
|
||||
:success (cons #'ein:notebook-save-notebook-workaround
|
||||
(cons notebook retry))
|
||||
:status-code
|
||||
`((204 . ,(cons #'ein:notebook-save-notebook-success notebook)))
|
||||
:timeout 5000)))
|
||||
|
||||
(defun ein:notebook-save-notebook-command ()
|
||||
(interactive)
|
||||
(ein:notebook-save-notebook ein:notebook 0))
|
||||
|
||||
(defun ein:notebook-save-notebook-callback (status notebook retry)
|
||||
(declare (special url-http-response-status
|
||||
url-http-method))
|
||||
(ein:log 'debug "SAVE-NOTEBOOK-CALLBACK nodtebook-id = %S, status = %S"
|
||||
(ein:$notebook-notebook-id notebook)
|
||||
status)
|
||||
(ein:log 'debug "url-http-response-status = %s" url-http-response-status)
|
||||
(ein:log 'debug "url-request-method = %s" url-request-method)
|
||||
(ein:log 'debug "url-http-method = %s" (when (boundp 'url-http-method)
|
||||
url-http-method))
|
||||
(ein:log 'debug "(buffer-string) = \n%s" (buffer-string))
|
||||
(let ((response url-http-response-status))
|
||||
;; ^-- "save" local variable before killing buffer.
|
||||
(kill-buffer (current-buffer))
|
||||
(with-current-buffer (ewoc-buffer (ein:$notebook-ewoc notebook))
|
||||
(ein:aif (plist-get status :error)
|
||||
(progn
|
||||
(ein:log 'debug "ERROR CODE = %S" it)
|
||||
(ein:notebook-save-notebook-error notebook status))
|
||||
;; IPython server returns 204 only when the notebook URL is
|
||||
;; accessed via PUT or DELETE. As it seems Emacs failed to
|
||||
;; 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-workaround (nb-retry &rest args
|
||||
&key
|
||||
status
|
||||
response-status
|
||||
&allow-other-keys)
|
||||
;; IPython server returns 204 only when the notebook URL is
|
||||
;; accessed via PUT or DELETE. As it seems Emacs failed to
|
||||
;; choose PUT method every two times, let's check the response
|
||||
;; here and fail when 204 is not returned.
|
||||
(unless (eq response-status 204)
|
||||
(let ((notebook (car nb-retry))
|
||||
(retry (cdr nb-retry)))
|
||||
(with-current-buffer (ein:notebook-buffer notebook)
|
||||
(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 status)
|
||||
(ein:log 'info
|
||||
"Status code (=%s) is not 204 and retry exceeds limit (=%s)."
|
||||
response-status 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.")
|
||||
(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)
|
||||
'(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:events-trigger (ein:$notebook-events notebook)
|
||||
'(notebook_save_failed . Notebook)))
|
||||
|
|
|
@ -71,29 +71,36 @@
|
|||
(when (and (stringp url-or-port)
|
||||
(string-match "^[0-9]+$" url-or-port))
|
||||
(setq url-or-port (string-to-number url-or-port)))
|
||||
(url-retrieve
|
||||
(ein:notebooklist-url url-or-port)
|
||||
(if no-popup
|
||||
#'ein:notebooklist-url-retrieve-callback
|
||||
(lambda (&rest args)
|
||||
(pop-to-buffer (apply #'ein:notebooklist-url-retrieve-callback args))))
|
||||
(list url-or-port))
|
||||
(let ((success
|
||||
(if no-popup
|
||||
#'ein:notebooklist-url-retrieve-callback
|
||||
(lambda (&rest args)
|
||||
(pop-to-buffer
|
||||
(apply #'ein:notebooklist-url-retrieve-callback args))))))
|
||||
(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))
|
||||
|
||||
(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'."
|
||||
(ein:aif (plist-get status :error)
|
||||
(error "Failed to connect to server '%s'. Got: %S"
|
||||
(ein:url url-or-port) it))
|
||||
(let ((data (ein:json-read)))
|
||||
(kill-buffer (current-buffer))
|
||||
(with-current-buffer (ein:notebooklist-get-buffer url-or-port)
|
||||
(setq ein:notebooklist
|
||||
(make-ein:$notebooklist :url-or-port url-or-port
|
||||
:data data))
|
||||
(ein:notebooklist-render)
|
||||
(goto-char (point-min))
|
||||
(current-buffer))))
|
||||
(with-current-buffer (ein:notebooklist-get-buffer url-or-port)
|
||||
(setq ein:notebooklist
|
||||
(make-ein:$notebooklist :url-or-port url-or-port
|
||||
:data data))
|
||||
(ein:notebooklist-render)
|
||||
(goto-char (point-min))
|
||||
(current-buffer)))
|
||||
|
||||
(defun ein:notebooklist-reload ()
|
||||
"Reload current Notebook list."
|
||||
|
@ -117,20 +124,24 @@
|
|||
"Ask server to create a new notebook and update the notebook list buffer."
|
||||
(message "Creating a new notebook...")
|
||||
(unless (setq url-or-port (ein:$notebooklist-url-or-port ein:notebooklist)))
|
||||
(url-retrieve
|
||||
(ein:query-ajax
|
||||
(ein:notebooklist-new-url url-or-port)
|
||||
(lambda (s buffer)
|
||||
(let ((notebook-id
|
||||
(ein:notebooklist-get-data-in-body-tag "data-notebook-id")))
|
||||
(kill-buffer (current-buffer))
|
||||
(message "Creating a new notebook... Done.")
|
||||
(with-current-buffer 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)))))
|
||||
(list (current-buffer))))
|
||||
:parser (lambda ()
|
||||
(ein:notebooklist-get-data-in-body-tag "data-notebook-id"))
|
||||
:success (cons #'ein:notebooklist-new-notebook-callback (current-buffer))
|
||||
:timeout 5000))
|
||||
|
||||
(defun* ein:notebooklist-new-notebook-callback (buffer &key
|
||||
data
|
||||
&allow-other-keys)
|
||||
(let ((notebook-id data))
|
||||
(message "Creating a new notebook... Done.")
|
||||
(with-current-buffer 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)
|
||||
(when (y-or-n-p (format "Delete notebook %s?" name))
|
||||
|
@ -138,19 +149,17 @@
|
|||
|
||||
(defun ein:notebooklist-delete-notebook (notebook-id name)
|
||||
(message "Deleting notebook %s..." name)
|
||||
(let ((url (ein:url-no-cache
|
||||
(ein:notebook-url-from-url-and-id
|
||||
(ein:$notebooklist-url-or-port ein:notebooklist)
|
||||
notebook-id)))
|
||||
(url-request-method "DELETE"))
|
||||
(url-retrieve
|
||||
url
|
||||
(lambda (s buffer name)
|
||||
(kill-buffer (current-buffer))
|
||||
(message "Deleting notebook %s... Done." name)
|
||||
(with-current-buffer buffer
|
||||
(ein:notebooklist-reload)))
|
||||
(list (current-buffer) name))))
|
||||
(ein:query-ajax
|
||||
(ein:notebook-url-from-url-and-id
|
||||
(ein:$notebooklist-url-or-port ein:notebooklist)
|
||||
notebook-id)
|
||||
:cache nil
|
||||
:type "DELETE"
|
||||
:success (cons (lambda (packed &rest ignore)
|
||||
(message "Deleting notebook %s... Done." (cdr packed))
|
||||
(with-current-buffer (car packed)
|
||||
(ein:notebooklist-reload)))
|
||||
(cons (current-buffer) name))))
|
||||
|
||||
(defun ein:notebooklist-render ()
|
||||
"Render notebook list widget.
|
||||
|
|
179
ein-query.el
Normal file
179
ein-query.el
Normal 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
|
|
@ -2,6 +2,7 @@
|
|||
(require 'ert)
|
||||
|
||||
(require 'ein-notebooklist)
|
||||
(require 'wid-edit)
|
||||
|
||||
;; Execute `eintest:dz-ipython-start' before starting the following
|
||||
;; 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")))
|
||||
(if 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)
|
||||
(eintest:wait-until (lambda () ein:notebooklist))
|
||||
(setq ein:notebooklist nil)
|
||||
(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"))))
|
||||
|
||||
(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 ()
|
||||
(let ((notebook (eintest:get-untitled0-or-create eintest:port)))
|
||||
(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)
|
||||
(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 ()
|
||||
(let ((notebook (eintest:get-untitled0-or-create eintest:port)))
|
||||
(eintest:wait-until (lambda () (ein:aand (ein:$notebook-kernel notebook)
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
(let* ((kernel (eintest:kernel-new 8888))
|
||||
(notebook-id "NOTEBOOK-ID")
|
||||
(desired-url "http://127.0.0.1:8888/kernels?notebook=NOTEBOOK-ID")
|
||||
(dummy-buffer (get-buffer-create "*eintest:dummy*"))
|
||||
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)
|
||||
(should (equal got-url desired-url)))))
|
||||
|
||||
|
@ -21,12 +22,13 @@
|
|||
(let* ((kernel (eintest:kernel-new 8888))
|
||||
(kernel-id "KERNEL-ID")
|
||||
(desired-url "http://127.0.0.1:8888/kernels/KERNEL-ID/restart")
|
||||
(dummy-buffer (get-buffer-create "*eintest:dummy*"))
|
||||
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:websocket (&rest ignore) (make-ein:$websocket))
|
||||
(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)
|
||||
(should (equal got-url desired-url)))))
|
||||
|
||||
|
@ -35,11 +37,12 @@
|
|||
(let* ((kernel (eintest:kernel-new 8888))
|
||||
(kernel-id "KERNEL-ID")
|
||||
(desired-url "http://127.0.0.1:8888/kernels/KERNEL-ID/interrupt")
|
||||
(dummy-buffer (get-buffer-create "*eintest:dummy*"))
|
||||
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: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)
|
||||
(should (equal got-url desired-url)))))
|
||||
|
||||
|
@ -47,11 +50,12 @@
|
|||
(let* ((kernel (eintest:kernel-new 8888))
|
||||
(kernel-id "KERNEL-ID")
|
||||
(desired-url "http://127.0.0.1:8888/kernels/KERNEL-ID")
|
||||
(dummy-buffer (get-buffer-create "*eintest:dummy*"))
|
||||
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: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)
|
||||
(let* ((l (split-string got-url "?"))
|
||||
(got-url-0 (nth 0 l))
|
||||
|
|
|
@ -44,19 +44,16 @@
|
|||
|
||||
(defun eintest:notebook-from-json (json-string &optional notebook-id)
|
||||
(unless notebook-id (setq notebook-id "NOTEBOOK-ID"))
|
||||
(with-temp-buffer
|
||||
(erase-buffer)
|
||||
(insert json-string)
|
||||
(flet ((pop-to-buffer (buf) buf)
|
||||
(ein:notebook-start-kernel ()))
|
||||
(with-current-buffer (ein:notebook-url-retrieve-callback
|
||||
nil
|
||||
(ein:notebook-new "DUMMY-URL" notebook-id))
|
||||
(let ((events (ein:events-new (current-buffer))))
|
||||
(setf (ein:$notebook-events ein:notebook) events)
|
||||
(setf (ein:$notebook-kernel ein:notebook)
|
||||
(ein:kernel-new 8888 "/kernels" events)))
|
||||
(current-buffer)))))
|
||||
(flet ((pop-to-buffer (buf) buf)
|
||||
(ein:notebook-start-kernel ()))
|
||||
(with-current-buffer (ein:notebook-request-open-callback
|
||||
(ein:notebook-new "DUMMY-URL" notebook-id)
|
||||
:data (ein:json-read-from-string json-string))
|
||||
(let ((events (ein:events-new (current-buffer))))
|
||||
(setf (ein:$notebook-events ein:notebook) events)
|
||||
(setf (ein:$notebook-kernel ein:notebook)
|
||||
(ein:kernel-new 8888 "/kernels" events)))
|
||||
(current-buffer))))
|
||||
|
||||
(defun eintest:notebook-make-data (cells &optional name)
|
||||
(unless name (setq name "Dummy Name"))
|
||||
|
|
Loading…
Add table
Reference in a new issue