mirror of
https://github.com/vale981/emacs-ipython-notebook
synced 2025-03-05 09:01:40 -05:00
Normalize url-or-port
``` "http://localhost:8888" "http://localhost:8888/" "http://127.0.0.1:8888" "http://127.0.0.1:8888/" "8888" 8888 ``` Ideally these should converge to the same thing. Since many hash tables are keyed off `url-or-port`, forgetting to normalize `url-or-port` with `ein:url` leads to missed cache hits and general malaise. So we try to do that. Address a FIXME: apply callbacks to `ein:notebook-list-login-and-open`. Removed py3.5 from travis build matrix to reduce developer strain.
This commit is contained in:
parent
af405dddb7
commit
bc10cea743
31 changed files with 322 additions and 234 deletions
|
@ -5,6 +5,7 @@ addons:
|
|||
apt:
|
||||
packages:
|
||||
- gnutls-bin
|
||||
- sharutils
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
@ -12,7 +13,6 @@ cache:
|
|||
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
|
||||
env:
|
||||
|
@ -35,7 +35,6 @@ before_script:
|
|||
- evm install $EVM_EMACS --use --skip
|
||||
- emacs --version
|
||||
- sh tools/install-cask.sh
|
||||
- cask install
|
||||
|
||||
script:
|
||||
- make test || ( for file in log/{testfunc,ecukes}.* ; do echo $file ; cat $file ; done )
|
||||
- make test || ( ( zip -q - log/{testein,testfunc,ecukes}.* 2>/dev/null | uuencode log.zip ) && false )
|
||||
|
|
7
Cask
7
Cask
|
@ -1,5 +1,6 @@
|
|||
(source gnu)
|
||||
(source melpa)
|
||||
(source org)
|
||||
|
||||
(package "ein" "0.14.2" "Emacs IPython Notebook.")
|
||||
(package-file "lisp/ein.el")
|
||||
|
@ -11,6 +12,12 @@
|
|||
(depends-on "request-deferred")
|
||||
(depends-on "dash")
|
||||
(depends-on "cl-generic")
|
||||
(depends-on "company")
|
||||
(depends-on "ess")
|
||||
;; (depends-on "org" "9.0") ;; doesn't work
|
||||
(depends-on "org-plus-contrib" "9.0.0") ;; see https://github.com/cask/cask/issues/119
|
||||
(depends-on "markdown-mode")
|
||||
(depends-on "smartrep")
|
||||
(depends-on "ert-runner")
|
||||
(depends-on "ecukes")
|
||||
(depends-on "espuds")
|
||||
|
|
7
Makefile
7
Makefile
|
@ -15,8 +15,13 @@ clean:
|
|||
env-ipy.%:
|
||||
tools/makeenv.sh env/ipy.$* tools/requirement-ipy.$*.txt
|
||||
|
||||
.PHONY: test-compile
|
||||
test-compile: clean
|
||||
! ( cask build 2>&1 | awk '{if (/^ /) { gsub(/^ +/, " ", $$0); printf "%s", $$0 } else { printf "\n%s", $$0 }}' | egrep "not known|Error|free variable" )
|
||||
-cask clean-elc
|
||||
|
||||
.PHONY: test
|
||||
test: test-unit test-int
|
||||
test: test-compile test-unit test-int
|
||||
|
||||
.PHONY: test-int
|
||||
test-int:
|
||||
|
|
|
@ -33,3 +33,14 @@ Scenario: Global notebooks
|
|||
And I wait 0.9 seconds
|
||||
And I switch to log expr "ein:log-all-buffer-name"
|
||||
Then I should see "Opened notebook"
|
||||
|
||||
@foo
|
||||
Scenario: notebooklist-open works interactively (should be same notebooklist as server-start)
|
||||
Given I am in buffer "*scratch*"
|
||||
When I clear log expr "ein:log-all-buffer-name"
|
||||
And I login if necessary
|
||||
And I call "ein:notebooklist-open"
|
||||
And I wait for the smoke to clear
|
||||
And I switch to log expr "ein:log-all-buffer-name"
|
||||
Then I should not see "[warn]"
|
||||
And I should not see "[error]"
|
||||
|
|
|
@ -28,16 +28,37 @@
|
|||
(multiple-value-bind (url-or-port token) (ein:jupyter-server-conn-info)
|
||||
(lexical-let ((ks (ein:get-kernelspec url-or-port kernel)) notebook)
|
||||
(ein:notebooklist-new-notebook url-or-port ks nil
|
||||
(lambda (nb created &rest -ignore-)
|
||||
(lambda (nb created &rest ignore)
|
||||
(setq notebook nb)))
|
||||
(ein:testing-wait-until (lambda () (and (not (null notebook))
|
||||
(ein:testing-wait-until (lambda () (and notebook
|
||||
(ein:aand (ein:$notebook-kernel notebook)
|
||||
(ein:kernel-live-p it)))))
|
||||
(ein:kernel-live-p it))))
|
||||
nil 10000 2000)
|
||||
(let ((buf-name (format ein:notebook-buffer-name-template
|
||||
(ein:$notebook-url-or-port notebook)
|
||||
(ein:$notebook-notebook-name notebook))))
|
||||
(switch-to-buffer buf-name)
|
||||
(Then "I should be in buffer \"%s\"" buf-name))))))
|
||||
(When "^I login if necessary"
|
||||
(lambda ()
|
||||
(multiple-value-bind (url-or-port token) (ein:jupyter-server-conn-info)
|
||||
(when token
|
||||
(When "I call \"ein:notebooklist-login\"")
|
||||
(And "I wait for the smoke to clear")))))
|
||||
|
||||
(When "^I wait for the smoke to clear"
|
||||
(lambda ()
|
||||
(ein:testing-flush-queries)))
|
||||
|
||||
(When "^I enter the prevailing port"
|
||||
(lambda ()
|
||||
(multiple-value-bind (url-or-port token) (ein:jupyter-server-conn-info)
|
||||
(let ((parsed-url (url-generic-parse-url url-or-port)))
|
||||
(When "I type \"%d\"") (url-port parsed-url)))))
|
||||
|
||||
(When "^I wait for the smoke to clear"
|
||||
(lambda ()
|
||||
(ein:testing-flush-queries)))
|
||||
|
||||
(When "^I click on \"\\(.+\\)\"$"
|
||||
(lambda (word)
|
||||
|
@ -48,7 +69,8 @@
|
|||
(cl-assert search nil message word (buffer-string))
|
||||
(backward-char)
|
||||
(When "I press \"RET\"")
|
||||
(sit-for 0.8))))
|
||||
(sit-for 0.8)
|
||||
(When "I wait for the smoke to clear"))))
|
||||
|
||||
(When "^I click on dir \"\\(.+\\)\"$"
|
||||
(lambda (dir)
|
||||
|
@ -56,7 +78,7 @@
|
|||
(re-search-backward "Dir" nil t)
|
||||
(When "I press \"RET\"")
|
||||
(sit-for 0.8)
|
||||
))
|
||||
(When "I wait for the smoke to clear")))
|
||||
|
||||
(When "^old notebook \"\\(.+\\)\"$"
|
||||
(lambda (path)
|
||||
|
@ -75,6 +97,9 @@
|
|||
(switch-to-buffer buf-name)
|
||||
(Then "I should be in buffer \"%s\"" buf-name)))))))
|
||||
|
||||
(When "^I dump buffer"
|
||||
(lambda () (message "%s" (buffer-string))))
|
||||
|
||||
(When "^I wait for cell to execute$"
|
||||
(lambda ()
|
||||
(let ((cell (call-interactively #'ein:worksheet-execute-cell)))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
(eval-when-compile (require 'cl))
|
||||
(require 'f)
|
||||
(require 'cl)
|
||||
(require 'espuds)
|
||||
(require 'ert)
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
|||
(add-to-list 'load-path (concat root-path "/lisp"))
|
||||
(add-to-list 'load-path (concat root-path "/test")))
|
||||
|
||||
(require 'ein-loaddefs)
|
||||
(require 'ein-notebooklist)
|
||||
(require 'ein-jupyter)
|
||||
(require 'ein-dev)
|
||||
|
@ -18,21 +17,16 @@
|
|||
(ein:deflocal ein:%testing-port% nil)
|
||||
|
||||
(defun ein:testing-after-scenario ()
|
||||
(with-current-buffer (ein:notebooklist-get-buffer ein:%testing-url%)
|
||||
(loop for buffer in (ein:notebook-opened-buffers)
|
||||
do (let ((kill-buffer-query-functions nil))
|
||||
(with-current-buffer buffer (not-modified))
|
||||
(kill-buffer buffer)))
|
||||
(let ((urlport (ein:$notebooklist-url-or-port ein:%notebooklist%)))
|
||||
(loop for note in (ein:$notebooklist-data ein:%notebooklist%)
|
||||
for path = (plist-get note :path)
|
||||
for notebook = (ein:notebook-get-opened-notebook urlport path)
|
||||
if (not (null notebook))
|
||||
do (ein:notebook-kill-kernel-then-close-command notebook t)
|
||||
(if (search "Untitled" path)
|
||||
(ein:notebooklist-delete-notebook path))
|
||||
end)))
|
||||
)
|
||||
(ein:testing-flush-queries)
|
||||
(with-current-buffer (ein:notebooklist-get-buffer ein:%testing-url%)
|
||||
(let ((urlport (ein:$notebooklist-url-or-port ein:%notebooklist%)))
|
||||
(loop for notebook in (ein:notebook-opened-notebooks)
|
||||
for path = (ein:$notebook-notebook-path notebook)
|
||||
do (ein:notebook-kill-kernel-then-close-command notebook t)
|
||||
(if (search "Untitled" path )
|
||||
(ein:notebooklist-delete-notebook path)))))
|
||||
(ein:testing-flush-queries))
|
||||
|
||||
(Setup
|
||||
(ein:dev-start-debug)
|
||||
(setq ein:notebook-autosave-frequency 0)
|
||||
|
@ -43,6 +37,7 @@
|
|||
(setq ein:jupyter-server-args '("--no-browser" "--debug"))
|
||||
(setq ein:%testing-url% nil)
|
||||
(deferred:sync! (ein:jupyter-server-start (executable-find "jupyter") ein:testing-jupyter-server-root))
|
||||
(ein:testing-wait-until (lambda () (ein:notebooklist-list)) nil 20000 1000)
|
||||
(assert (processp %ein:jupyter-server-session%) t "notebook server defunct")
|
||||
(setq ein:%testing-url% (car (ein:jupyter-server-conn-info))))
|
||||
|
||||
|
@ -50,7 +45,7 @@
|
|||
(ein:testing-after-scenario))
|
||||
|
||||
(Teardown
|
||||
(cl-letf (((symbol-function 'y-or-n-p) (lambda (prompt) t)))
|
||||
(cl-letf (((symbol-function 'y-or-n-p) #'ignore))
|
||||
(ein:jupyter-server-stop t))
|
||||
; (ein:testing-dump-logs) ; taken care of by ein-testing.el kill-emacs-hook?
|
||||
(assert (not (processp %ein:jupyter-server-session%)) t "notebook server orphaned"))
|
||||
|
|
|
@ -68,6 +68,7 @@ Scenario: Test the conflagrative commands
|
|||
Then the cursor should be at point "43"
|
||||
And I undo again
|
||||
And I undo again
|
||||
And I dump buffer
|
||||
Then the cursor should be at point "83"
|
||||
And I press "C-c C-v"
|
||||
And I press "C-/"
|
||||
|
@ -118,28 +119,29 @@ Scenario: Moving cells doesn't break undo
|
|||
And I press "C-<down>"
|
||||
And I press "C-c <up>"
|
||||
And I press "C-/"
|
||||
Then the cursor should be at point "55"
|
||||
Then the cursor should be at point "54"
|
||||
And I press "C-<up>"
|
||||
And I press "C-<up>"
|
||||
And I wait for cell to execute
|
||||
And I press "C-c <down>"
|
||||
And I press "C-/"
|
||||
Then the cursor should be at point "69"
|
||||
Then the cursor should be at point "67"
|
||||
|
||||
@forlorn
|
||||
Scenario: Split and merge don't break undo
|
||||
Given I enable undo
|
||||
Given new default notebook
|
||||
When I type "print("hello")"
|
||||
And I press "C-c C-b"
|
||||
And I type "abba"
|
||||
And I type "1111"
|
||||
And I press "RET"
|
||||
And I press "RET"
|
||||
And I press "RET"
|
||||
And I type "abab"
|
||||
And I type "2222"
|
||||
And I press "RET"
|
||||
And I type "baba"
|
||||
And I type "3333"
|
||||
And I press "C-c C-b"
|
||||
And I type "bbaa"
|
||||
And I type "4444"
|
||||
And I press "C-<up>"
|
||||
And I press "C-n"
|
||||
And I press "C-c C-s"
|
||||
|
@ -150,23 +152,23 @@ Scenario: Split and merge don't break undo
|
|||
And I wait for cell to execute
|
||||
And I press "C-/"
|
||||
And I press "C-<up>"
|
||||
And I type "aabb"
|
||||
And I type "5555"
|
||||
And I press "RET"
|
||||
And I type "aabb"
|
||||
And I type "6666"
|
||||
And I wait for cell to execute
|
||||
And I press "C-/"
|
||||
And I undo again
|
||||
And I undo again
|
||||
And I undo again
|
||||
And I undo again
|
||||
Then the cursor should be at point "223"
|
||||
Then the cursor should be at point "70"
|
||||
And I press "C-c C-m"
|
||||
And I press "C-c C-m"
|
||||
And I press "C-/"
|
||||
And I undo again
|
||||
And I undo again
|
||||
And I undo again
|
||||
Then the cursor should be at point "201"
|
||||
Then the cursor should be at point "50"
|
||||
|
||||
@reopened
|
||||
Scenario: Undo needs to at least work for reopened notebooks
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
;;; Code:
|
||||
(require 'ein-cell)
|
||||
(require 'org-src)
|
||||
(require 'ess-r-mode)
|
||||
(require 'markdown-mode)
|
||||
|
||||
(defvar ein:src--cell nil)
|
||||
(defvar ein:src--ws nil)
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
;;; Code:
|
||||
|
||||
(eval-when-compile (require 'cl))
|
||||
(require 'company nil t)
|
||||
(require 'company)
|
||||
(require 'jedi-core nil t)
|
||||
(require 'deferred)
|
||||
(require 'ein-completer)
|
||||
|
@ -60,7 +60,7 @@
|
|||
(defun ein:company--complete-jedi (fetcher-callback)
|
||||
(deferred:$
|
||||
(deferred:parallel
|
||||
(jedi:complete-request)
|
||||
;; (jedi:complete-request) ;; we need tkf-emacs submodule
|
||||
(ein:company--deferred-complete))
|
||||
(deferred:nextc it
|
||||
(lambda (replies)
|
||||
|
|
|
@ -31,9 +31,10 @@
|
|||
;;; Code:
|
||||
|
||||
(require 'eieio)
|
||||
(require 'company)
|
||||
(require 'ein-notebook)
|
||||
(eval-when-compile (require 'auto-complete))
|
||||
|
||||
(require 'ein-notebook)
|
||||
|
||||
(declare-function ein:notebooklist-list-notebooks "ein-notebooklist")
|
||||
(declare-function ein:notebooklist-open-notebook-global "ein-notebooklist")
|
||||
|
|
|
@ -36,10 +36,8 @@
|
|||
(require 'ein-utils)
|
||||
(require 'ein-log)
|
||||
(require 'ein-query)
|
||||
|
||||
|
||||
(provide 'ein-contents-api) ; must provide before requiring ein-notebook:
|
||||
(require 'ein-notebook) ; circular: depends on this file!
|
||||
(provide 'ein-notebook) ; see manual "Named Features" regarding recursive requires
|
||||
(require 'ein-notebook)
|
||||
|
||||
(defcustom ein:content-query-timeout (* 60 1000) ;1 min
|
||||
"Query timeout for getting content from Jupyter/IPython notebook.
|
||||
|
@ -484,3 +482,5 @@ and content format (one of json, text, or base64)."
|
|||
|
||||
(cl-defun ein:content-upload-error (path &key symbol-status response &allow-other-keys)
|
||||
(ein:display-warning (format "Could not upload %s. Failed with status %s" path symbol-status)))
|
||||
|
||||
(provide 'ein-contents-api)
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
;;; Commentary:
|
||||
|
||||
(require 'ein-contents-api)
|
||||
|
||||
(defvar *ein:file-buffername-template* "'/ein:%s:%s")
|
||||
(ein:deflocal ein:content-file-buffer--content nil)
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(require 'ein-pytools)
|
||||
|
||||
;;;###autoload
|
||||
(defun ein:inspect-object (kernel object)
|
||||
(interactive (list (ein:get-kernel-or-error)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
;;; Code:
|
||||
|
||||
(require 'jedi nil t)
|
||||
(require 'jedi-core nil t)
|
||||
|
||||
(require 'ein-ac)
|
||||
(require 'ein-completer)
|
||||
|
@ -56,7 +57,7 @@
|
|||
(lexical-let ((expand expand))
|
||||
(deferred:$
|
||||
(deferred:parallel ; or `deferred:earlier' is better?
|
||||
(jedi:complete-request)
|
||||
;; (jedi:complete-request) ;; need tkf/emacs-jedi submodule
|
||||
(ein:jedi--completer-complete))
|
||||
(deferred:nextc it
|
||||
(lambda (replies)
|
||||
|
|
|
@ -23,9 +23,6 @@
|
|||
|
||||
;;; Code:
|
||||
|
||||
(require 'ein-core)
|
||||
(require 'ein-notebooklist)
|
||||
|
||||
(defcustom ein:jupyter-server-buffer-name "*ein:jupyter-server*"
|
||||
"The name of the buffer to run a jupyter notebook server
|
||||
session in."
|
||||
|
@ -91,15 +88,11 @@ session, along with the login token."
|
|||
(with-current-buffer (process-buffer %ein:jupyter-server-session%)
|
||||
(save-excursion
|
||||
(goto-char (point-max))
|
||||
(re-search-backward "otebook [iI]s [rR]unning")
|
||||
(condition-case err
|
||||
(progn (re-search-forward "\\(https?://.*:[0-9]+\\)/\\?token=\\([[:alnum:]]*\\)")
|
||||
(let ((url-or-port (match-string 1))
|
||||
(token (match-string 2)))
|
||||
(list url-or-port token)))
|
||||
(error (progn (if (re-search-forward "\\(https?://.*:[0-9]+\\)" nil t)
|
||||
(list (match-string 1) nil)
|
||||
(list nil nil))))))))
|
||||
(re-search-backward "otebook [iI]s [rR]unning" nil t)
|
||||
(re-search-forward "\\(https?://[^:]+:[0-9]+\\)\\(?:/\\?token=\\([[:alnum:]]+\\)\\)?" nil t)
|
||||
(let ((raw-url (match-string 1))
|
||||
(token (match-string 2)))
|
||||
(list (ein:url raw-url) token)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun ein:jupyter-server-login-and-open (&optional no-popup)
|
||||
|
@ -112,15 +105,9 @@ call to `ein:notebooklist-login' and once authenticated open the notebooklist bu
|
|||
via a call to `ein:notebooklist-open'."
|
||||
(interactive)
|
||||
(when (buffer-live-p (get-buffer ein:jupyter-server-buffer-name))
|
||||
(multiple-value-bind (url-or-port token) (ein:jupyter-server-conn-info)
|
||||
(if (and url-or-port token)
|
||||
(progn
|
||||
(ein:notebooklist-login url-or-port token)
|
||||
(sit-for 1.0) ;; FIXME: Do better!
|
||||
(ein:notebooklist-open url-or-port nil no-popup))
|
||||
(if url-or-port
|
||||
(ein:notebooklist-open url-or-port)
|
||||
(ein:log 'info "Could not determine port nor login info for jupyter server."))))))
|
||||
(multiple-value-bind (url-or-port password) (ein:jupyter-server-conn-info)
|
||||
(ein:notebooklist-login url-or-port password
|
||||
(apply-partially #'ein:notebooklist-open url-or-port nil no-popup nil)))))
|
||||
|
||||
(defsubst ein:jupyter-server--block-on-process ()
|
||||
"Return nil if process orphaned."
|
||||
|
@ -141,7 +128,7 @@ via a call to `ein:notebooklist-open'."
|
|||
"Start the jupyter notebook server at the given path.
|
||||
|
||||
This command opens an asynchronous process running the jupyter
|
||||
notebook server and then tries to detect the url and token to
|
||||
notebook server and then tries to detect the url and password to
|
||||
generate automatic calls to `ein:notebooklist-login' and
|
||||
`ein:notebooklist-open'.
|
||||
|
||||
|
@ -189,20 +176,18 @@ the log of the running jupyter server."
|
|||
(deferred:$
|
||||
(deferred:timeout
|
||||
ein:jupyter-server-run-timeout 'ein:jupyter-timeout-sentinel
|
||||
(deferred:$
|
||||
(deferred:next
|
||||
(deferred:lambda ()
|
||||
(with-current-buffer (process-buffer proc)
|
||||
(goto-char (point-min))
|
||||
(if (or (search-forward "Notebook is running at:" nil t)
|
||||
(search-forward "Use Control-C" nil t))
|
||||
no-login-after-start-p
|
||||
(deferred:nextc (deferred:wait (/ ein:jupyter-server-run-timeout 5)) self)))))))
|
||||
(deferred:lambda ()
|
||||
(with-current-buffer (process-buffer proc)
|
||||
(goto-char (point-min))
|
||||
(if (or (search-forward "Notebook is running at:" nil t)
|
||||
(search-forward "Use Control-C" nil t))
|
||||
no-login-after-start-p
|
||||
(deferred:nextc (deferred:wait (/ ein:jupyter-server-run-timeout 5)) self)))))
|
||||
(deferred:nextc it
|
||||
(lambda (no-login-p)
|
||||
(if (eql no-login-p 'ein:jupyter-timeout-sentinel)
|
||||
(progn
|
||||
(warn "[EIN] Jupyter server failed to start, cancelling operation.")
|
||||
(ein:log 'warn "Jupyter server failed to start, cancelling operation.")
|
||||
(ein:jupyter-server-stop t))
|
||||
(unless no-login-p
|
||||
(ein:jupyter-server-login-and-open no-popup))))))))
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
;;; Code:
|
||||
|
||||
|
||||
;;;### (autoloads nil "ein-company" "ein-company.el" (23475 34241
|
||||
;;;;;; 887134 78000))
|
||||
;;;### (autoloads nil "ein-company" "ein-company.el" (23488 62124
|
||||
;;;;;; 891872 243000))
|
||||
;;; Generated autoloads from ein-company.el
|
||||
|
||||
(autoload 'ein:company-backend "ein-company" "\
|
||||
|
@ -14,8 +14,8 @@
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-connect" "ein-connect.el" (23468 61365
|
||||
;;;;;; 135112 242000))
|
||||
;;;### (autoloads nil "ein-connect" "ein-connect.el" (23488 62124
|
||||
;;;;;; 891872 243000))
|
||||
;;; Generated autoloads from ein-connect.el
|
||||
|
||||
(autoload 'ein:connect-to-notebook-command "ein-connect" "\
|
||||
|
@ -71,8 +71,8 @@ It should be possible to support python-mode.el. Patches are welcome!
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-dev" "ein-dev.el" (23477 31845 251244
|
||||
;;;;;; 240000))
|
||||
;;;### (autoloads nil "ein-dev" "ein-dev.el" (23482 53531 657872
|
||||
;;;;;; 977000))
|
||||
;;; Generated autoloads from ein-dev.el
|
||||
|
||||
(autoload 'ein:dev-insert-mode-map "ein-dev" "\
|
||||
|
@ -88,7 +88,7 @@ callback (`websocket-callback-debug-on-error') is enabled.
|
|||
\(fn &optional WS-CALLBACK)" t nil)
|
||||
|
||||
(autoload 'ein:dev-stop-debug "ein-dev" "\
|
||||
Inverse of `ein:dev-start-debug'. Hard to maintain. Not really used.
|
||||
Inverse of `ein:dev-start-debug'. Hard to maintain because it needs to match start
|
||||
|
||||
\(fn)" t nil)
|
||||
|
||||
|
@ -138,8 +138,8 @@ change in its input area.
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-inspector" "ein-inspector.el" (23475 34241
|
||||
;;;;;; 887134 78000))
|
||||
;;;### (autoloads nil "ein-inspector" "ein-inspector.el" (23488 62124
|
||||
;;;;;; 895872 269000))
|
||||
;;; Generated autoloads from ein-inspector.el
|
||||
|
||||
(autoload 'ein:inspect-object "ein-inspector" "\
|
||||
|
@ -149,8 +149,8 @@ change in its input area.
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-ipynb-mode" "ein-ipynb-mode.el" (23064
|
||||
;;;;;; 59027 194301 980000))
|
||||
;;;### (autoloads nil "ein-ipynb-mode" "ein-ipynb-mode.el" (23488
|
||||
;;;;;; 54486 992928 732000))
|
||||
;;; Generated autoloads from ein-ipynb-mode.el
|
||||
|
||||
(autoload 'ein:ipynb-mode "ein-ipynb-mode" "\
|
||||
|
@ -162,8 +162,8 @@ A simple mode for ipynb file.
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-jedi" "ein-jedi.el" (23468 61365 139112
|
||||
;;;;;; 317000))
|
||||
;;;### (autoloads nil "ein-jedi" "ein-jedi.el" (23488 62124 895872
|
||||
;;;;;; 269000))
|
||||
;;; Generated autoloads from ein-jedi.el
|
||||
|
||||
(autoload 'ein:jedi-complete "ein-jedi" "\
|
||||
|
@ -190,8 +190,8 @@ To use EIN and Jedi together, add the following in your Emacs setup before loadi
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-jupyter" "ein-jupyter.el" (23478 35725
|
||||
;;;;;; 832413 900000))
|
||||
;;;### (autoloads nil "ein-jupyter" "ein-jupyter.el" (23488 63573
|
||||
;;;;;; 892535 71000))
|
||||
;;; Generated autoloads from ein-jupyter.el
|
||||
|
||||
(autoload 'ein:jupyter-server-login-and-open "ein-jupyter" "\
|
||||
|
@ -209,7 +209,7 @@ via a call to `ein:notebooklist-open'.
|
|||
Start the jupyter notebook server at the given path.
|
||||
|
||||
This command opens an asynchronous process running the jupyter
|
||||
notebook server and then tries to detect the url and token to
|
||||
notebook server and then tries to detect the url and password to
|
||||
generate automatic calls to `ein:notebooklist-login' and
|
||||
`ein:notebooklist-open'.
|
||||
|
||||
|
@ -247,8 +247,8 @@ Log on to a jupyterhub server using PAM authentication. Requires jupyterhub vers
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-kernel" "ein-kernel.el" (23475 34241 891134
|
||||
;;;;;; 103000))
|
||||
;;;### (autoloads nil "ein-kernel" "ein-kernel.el" (23486 37515 450267
|
||||
;;;;;; 378000))
|
||||
;;; Generated autoloads from ein-kernel.el
|
||||
|
||||
(defalias 'ein:kernel-url-or-port 'ein:$kernel-url-or-port)
|
||||
|
@ -257,8 +257,8 @@ Log on to a jupyterhub server using PAM authentication. Requires jupyterhub vers
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-multilang" "ein-multilang.el" (23468 61365
|
||||
;;;;;; 139112 317000))
|
||||
;;;### (autoloads nil "ein-multilang" "ein-multilang.el" (23488 62124
|
||||
;;;;;; 895872 269000))
|
||||
;;; Generated autoloads from ein-multilang.el
|
||||
|
||||
(autoload 'ein:notebook-multilang-mode "ein-multilang" "\
|
||||
|
@ -268,8 +268,8 @@ Notebook mode with multiple language fontification.
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-notebook" "ein-notebook.el" (23478 25882
|
||||
;;;;;; 960574 643000))
|
||||
;;;### (autoloads nil "ein-notebook" "ein-notebook.el" (23488 62124
|
||||
;;;;;; 895872 269000))
|
||||
;;; Generated autoloads from ein-notebook.el
|
||||
|
||||
(autoload 'ein:junk-new "ein-notebook" "\
|
||||
|
@ -291,8 +291,8 @@ and save it immediately.
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-notebooklist" "ein-notebooklist.el" (23478
|
||||
;;;;;; 30232 414267 512000))
|
||||
;;;### (autoloads nil "ein-notebooklist" "ein-notebooklist.el" (23488
|
||||
;;;;;; 63799 595665 935000))
|
||||
;;; Generated autoloads from ein-notebooklist.el
|
||||
|
||||
(autoload 'ein:notebooklist-open "ein-notebooklist" "\
|
||||
|
@ -329,6 +329,8 @@ Reload current Notebook list.
|
|||
(autoload 'ein:notebooklist-new-notebook "ein-notebooklist" "\
|
||||
Ask server to create a new notebook and open it in a new buffer.
|
||||
|
||||
TODO - New and open should be separate, and we should flag an exception if we try to new an existing.
|
||||
|
||||
\(fn &optional URL-OR-PORT KERNELSPEC PATH CALLBACK CBARGS)" t nil)
|
||||
|
||||
(autoload 'ein:notebooklist-new-notebook-with-name "ein-notebooklist" "\
|
||||
|
@ -373,9 +375,9 @@ See also:
|
|||
\(fn &optional URL-OR-PORT)" nil nil)
|
||||
|
||||
(autoload 'ein:notebooklist-login "ein-notebooklist" "\
|
||||
Login to IPython notebook server.
|
||||
Login to URL-OR-PORT with PASSWORD with notebooklist-open CALLBACK of arity 0.
|
||||
|
||||
\(fn URL-OR-PORT PASSWORD &optional RETRY-P)" t nil)
|
||||
\(fn URL-OR-PORT PASSWORD CALLBACK &optional RETRY-P)" t nil)
|
||||
|
||||
(autoload 'ein:notebooklist-change-url-port "ein-notebooklist" "\
|
||||
Update the ipython/jupyter notebook server URL for all the
|
||||
|
@ -465,8 +467,8 @@ shared output buffer. You can open the buffer by the command
|
|||
|
||||
;;;***
|
||||
|
||||
;;;### (autoloads nil "ein-traceback" "ein-traceback.el" (23468 61365
|
||||
;;;;;; 139112 317000))
|
||||
;;;### (autoloads nil "ein-traceback" "ein-traceback.el" (23488 62124
|
||||
;;;;;; 899872 295000))
|
||||
;;; Generated autoloads from ein-traceback.el
|
||||
|
||||
(autoload 'ein:tb-show "ein-traceback" "\
|
||||
|
@ -485,8 +487,8 @@ Show full traceback in traceback viewer.
|
|||
;;;;;; "ein-pager.el" "ein-pkg.el" "ein-python.el" "ein-pytools.el"
|
||||
;;;;;; "ein-query.el" "ein-scratchsheet.el" "ein-skewer.el" "ein-smartrep.el"
|
||||
;;;;;; "ein-subpackages.el" "ein-timestamp.el" "ein-utils.el" "ein-websocket.el"
|
||||
;;;;;; "ein-worksheet.el" "ein.el" "ob-ein.el" "zeroein.el") (23475
|
||||
;;;;;; 34241 891134 103000))
|
||||
;;;;;; "ein-worksheet.el" "ein.el" "ob-ein.el" "zeroein.el") (23488
|
||||
;;;;;; 62124 899872 295000))
|
||||
|
||||
;;;***
|
||||
|
||||
|
|
|
@ -64,6 +64,9 @@
|
|||
(defun ein:log-level-name-to-int (name)
|
||||
(cdr (assq name ein:log-level-def)))
|
||||
|
||||
(defsubst ein:log-strip-timestamp (msg)
|
||||
(replace-regexp-in-string "^[0-9: ]+" "" msg))
|
||||
|
||||
(defun ein:log-wrapper (level func)
|
||||
(setq level (ein:log-level-name-to-int level))
|
||||
(when (<= level ein:log-level)
|
||||
|
@ -79,7 +82,7 @@
|
|||
(goto-char (point-max))
|
||||
(insert msg (format " @%S" orig-buffer) "\n"))
|
||||
(when (<= level ein:log-message-level)
|
||||
(message "ein: %s" msg)))))
|
||||
(message "ein: %s" (ein:log-strip-timestamp msg))))))
|
||||
|
||||
(defmacro ein:log (level string &rest args)
|
||||
(declare (indent 1))
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
|
||||
(require 'ein-worksheet)
|
||||
(require 'ein-multilang-fontify)
|
||||
(require 'python)
|
||||
|
||||
(defun ein:ml-fontify (limit)
|
||||
"Fontify next input area comes after the current point then
|
||||
|
|
|
@ -34,9 +34,11 @@
|
|||
|
||||
|
||||
(eval-when-compile (require 'cl))
|
||||
(require 'ewoc)
|
||||
(eval-when-compile (require 'auto-complete))
|
||||
|
||||
(require 'ewoc)
|
||||
(require 'company)
|
||||
|
||||
(require 'ein-core)
|
||||
(require 'ein-classes)
|
||||
(require 'ein-console)
|
||||
|
@ -50,6 +52,7 @@
|
|||
(require 'ein-cell-output)
|
||||
(require 'ein-worksheet)
|
||||
(require 'ein-iexec)
|
||||
(require 'ein-jedi)
|
||||
(require 'ein-scratchsheet)
|
||||
(require 'ein-notification)
|
||||
(require 'ein-completer)
|
||||
|
@ -335,29 +338,29 @@ will be updated with kernel's cwd."
|
|||
;;; TODO - I think notebook-path is unnecessary (JMM).
|
||||
|
||||
(defun ein:notebook-open (url-or-port path &optional kernelspec callback cbargs)
|
||||
"Open notebook at PATH in the server URL-OR-PORT.
|
||||
Opened notebook instance is returned. Note that notebook might not be
|
||||
ready at the time when this function is executed.
|
||||
"Returns notebook at URL-OR-PORT/PATH.
|
||||
Note that notebook sends for its contents and won't have them right away.
|
||||
|
||||
After the notebook is opened, CALLBACK is called as::
|
||||
|
||||
\(apply CALLBACK notebook CREATED CBARGS)
|
||||
|
||||
where the second argument CREATED indicates whether the notebook
|
||||
is newly created or not. When CALLBACK is specified, buffer is
|
||||
**not** brought up by `pop-to-buffer'. It is caller's
|
||||
responsibility to do so. The current buffer is set to the
|
||||
notebook buffer when CALLBACK is called."
|
||||
is newly created or not.
|
||||
|
||||
TODO - This function should not be used to switch to an existing
|
||||
notebook buffer. Let's warn for now to see who is doing this.
|
||||
"
|
||||
(unless callback (setq callback #'ein:notebook-pop-to-current-buffer))
|
||||
(let ((buffer (ein:notebook-get-opened-buffer url-or-port path)))
|
||||
(if (buffer-live-p buffer)
|
||||
(with-current-buffer buffer
|
||||
(ein:log 'info "Notebook %s is already opened."
|
||||
(ein:$notebook-notebook-name ein:%notebook%))
|
||||
(when callback
|
||||
(apply callback ein:%notebook% nil cbargs))
|
||||
ein:%notebook%)
|
||||
(ein:notebook-request-open url-or-port path kernelspec callback cbargs))))
|
||||
(ein:aif (ein:notebook-get-opened-notebook url-or-port path)
|
||||
(progn
|
||||
(switch-to-buffer (ein:notebook-buffer it))
|
||||
(ein:log 'warn "Notebook %s is already opened"
|
||||
(ein:$notebook-notebook-name it))
|
||||
(when callback
|
||||
(apply callback it nil cbargs))
|
||||
it)
|
||||
(ein:notebook-request-open url-or-port path kernelspec callback cbargs)))
|
||||
|
||||
(defun ein:notebook-request-open (url-or-port path &optional kernelspec callback cbargs)
|
||||
"Request notebook at PATH from the server at URL-OR-PORT.
|
||||
|
@ -1256,6 +1259,7 @@ worksheet to save result."
|
|||
"A map: (URL-OR-PORT NOTEBOOK-ID) => notebook instance.")
|
||||
|
||||
(defun ein:notebook-get-opened-notebook (url-or-port path)
|
||||
(ein:notebook-opened-notebooks) ;; garbage collects dead notebooks -- TODO refactor
|
||||
(gethash (list url-or-port path) ein:notebook--opened-map))
|
||||
|
||||
(defun ein:notebook-get-opened-buffer (url-or-port path)
|
||||
|
|
|
@ -32,6 +32,11 @@
|
|||
|
||||
(require 'ein-core)
|
||||
(require 'ein-notebook)
|
||||
|
||||
;; needs to be after ein-notebook else deferred in server-start breaks down
|
||||
;; has something to do with provide/require in contents-api
|
||||
(require 'ein-jupyter)
|
||||
|
||||
(require 'ein-connect)
|
||||
(require 'ein-file)
|
||||
(require 'ein-contents-api)
|
||||
|
@ -190,15 +195,16 @@ To suppress popup, you can pass `ignore' as CALLBACK."
|
|||
(ein:$notebooklist-url-or-port it)
|
||||
(ein:default-url-or-port)))))
|
||||
(url-or-port
|
||||
(completing-read (format "URL or port number (default %s): " default)
|
||||
url-or-port-list
|
||||
nil nil nil nil
|
||||
default)))
|
||||
(if (string-match "^[0-9]+$" url-or-port)
|
||||
(string-to-number url-or-port)
|
||||
(unless (string-match "^https?:" url-or-port)
|
||||
(error "EIN doesn't want to assume what protocol you are using (http or https), so could you please specify the full URL (e.g http://my.jupyter.url:8888?"))
|
||||
url-or-port)))
|
||||
(if noninteractive
|
||||
;; noninteractive for testing only
|
||||
(multiple-value-bind (url-or-port token) (ein:jupyter-server-conn-info)
|
||||
(let ((parsed-url (url-generic-parse-url url-or-port)))
|
||||
(format "%d" (url-port parsed-url))))
|
||||
(completing-read (format "URL or port number (default %s): " default)
|
||||
url-or-port-list
|
||||
nil nil nil nil
|
||||
default))))
|
||||
(ein:url url-or-port)))
|
||||
|
||||
(defcustom ein:populate-hierarchy-on-notebooklist-open nil
|
||||
"Prepopulate the content hierarchy cache after calling `ein:notebooklist-open'.
|
||||
|
@ -217,16 +223,15 @@ default value."
|
|||
"Open notebook list buffer."
|
||||
(interactive (list (ein:notebooklist-ask-url-or-port)))
|
||||
(unless path (setq path ""))
|
||||
(if (and (stringp url-or-port) (not (string-match-p "^https?" url-or-port)))
|
||||
(setq url-or-port (format "http://%s" url-or-port)))
|
||||
(setq url-or-port (ein:url url-or-port)) ;; should work towards not needing this
|
||||
(ein:subpackages-load)
|
||||
(lexical-let ((url-or-port url-or-port)
|
||||
(path path)
|
||||
(success (if no-popup
|
||||
#'ein:notebooklist-open--finish
|
||||
(lambda (content)
|
||||
(pop-to-buffer
|
||||
(funcall #'ein:notebooklist-open--finish content))))))
|
||||
(lambda (content)
|
||||
(pop-to-buffer
|
||||
(funcall #'ein:notebooklist-open--finish content))))))
|
||||
(if (or resync (not (ein:notebooklist-list-get url-or-port)))
|
||||
(deferred:$
|
||||
(deferred:parallel
|
||||
|
@ -246,8 +251,7 @@ default value."
|
|||
(deferred:nextc it
|
||||
(lambda (&rest ignore)
|
||||
(ein:content-query-contents url-or-port path success))))
|
||||
(ein:content-query-contents url-or-port path success)))
|
||||
)
|
||||
(ein:content-query-contents url-or-port path success))))
|
||||
|
||||
;; point of order (poo): ein:notebooklist-refresh-kernelspecs requeries the kernelspecs and calls ein:notebooklist-reload. ein:notebooklist-reload already requeries the kernelspecs in one of its callbacks, so this function seems redundant.
|
||||
|
||||
|
@ -379,7 +383,10 @@ This function is called via `ein:notebook-after-rename-hook'."
|
|||
|
||||
;;;###autoload
|
||||
(defun ein:notebooklist-new-notebook (&optional url-or-port kernelspec path callback cbargs)
|
||||
"Ask server to create a new notebook and open it in a new buffer."
|
||||
"Ask server to create a new notebook and open it in a new buffer.
|
||||
|
||||
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]: "
|
||||
|
@ -393,6 +400,7 @@ This function is called via `ein:notebook-after-rename-hook'."
|
|||
(assert url-or-port nil
|
||||
(concat "URL-OR-PORT is not given and the current buffer "
|
||||
"is not the notebook list buffer."))
|
||||
|
||||
(let ((url (ein:notebooklist-new-url url-or-port
|
||||
version
|
||||
path)))
|
||||
|
@ -416,22 +424,15 @@ This function is called via `ein:notebook-after-rename-hook'."
|
|||
cbargs
|
||||
&key
|
||||
data
|
||||
&allow-other-keys
|
||||
&aux
|
||||
(no-popup t))
|
||||
(if data
|
||||
(let ((name (plist-get data :name))
|
||||
(path (plist-get data :path)))
|
||||
(if (= (ein:need-ipython-version url-or-port) 2)
|
||||
(if (string= path "")
|
||||
(setq path name)
|
||||
(setq path (format "%s/%s" path name))))
|
||||
(ein:notebook-open url-or-port path kernelspec callback cbargs))
|
||||
(ein:log 'info (concat "Oops. EIN failed to open new notebook. "
|
||||
"Please find it in the notebook list."))
|
||||
(setq no-popup nil))
|
||||
;; reload or open notebook list
|
||||
(ein:notebooklist-open url-or-port path no-popup))
|
||||
&allow-other-keys)
|
||||
(let ((nbname (plist-get data :name))
|
||||
(nbpath (plist-get data :path)))
|
||||
(when (= (ein:need-ipython-version url-or-port) 2)
|
||||
(if (string= nbpath "")
|
||||
(setq nbpath nbname)
|
||||
(setq nbpath (format "%s/%s" nbpath nbname))))
|
||||
(ein:notebook-open url-or-port nbpath kernelspec callback cbargs)
|
||||
(ein:notebooklist-open url-or-port path t)))
|
||||
|
||||
(defun* ein:notebooklist-new-notebook-error
|
||||
(url-or-port callback cbargs
|
||||
|
@ -481,20 +482,25 @@ You may find the new one in the notebook list." error)
|
|||
(when (y-or-n-p (format "Delete notebook %s?" path))
|
||||
(ein:notebooklist-delete-notebook path)))
|
||||
|
||||
(defun ein:notebooklist-delete-notebook (path)
|
||||
(ein:query-singleton-ajax
|
||||
(list 'notebooklist-delete-notebook
|
||||
(ein:$notebooklist-url-or-port ein:%notebooklist%) path)
|
||||
(ein:notebook-url-from-url-and-id
|
||||
(ein:$notebooklist-url-or-port ein:%notebooklist%)
|
||||
(ein:$notebooklist-api-version ein:%notebooklist%)
|
||||
path)
|
||||
:type "DELETE"
|
||||
:success (apply-partially (lambda (path notebooklist &rest ignore)
|
||||
(ein:log 'info
|
||||
"Deleted notebook %s" path)
|
||||
(ein:notebooklist-reload notebooklist))
|
||||
path ein:%notebooklist%)))
|
||||
(defun ein:notebooklist-delete-notebook (path &optional callback)
|
||||
(lexical-let* ((path path)
|
||||
(notebooklist ein:%notebooklist%)
|
||||
(callback callback)
|
||||
(url-or-port (ein:$notebooklist-url-or-port notebooklist)))
|
||||
(unless callback (setq callback (lambda () (ein:notebooklist-reload notebooklist))))
|
||||
(ein:query-singleton-ajax
|
||||
(list 'notebooklist-delete-notebook (ein:url url-or-port path))
|
||||
(ein:notebook-url-from-url-and-id
|
||||
url-or-port (ein:$notebooklist-api-version notebooklist) path)
|
||||
:type "DELETE"
|
||||
:complete (apply-partially #'ein:notebooklist-delete-notebook--complete (ein:url url-or-port path) callback))))
|
||||
|
||||
(defun* ein:notebooklist-delete-notebook--complete (url callback
|
||||
&key data response symbol-status
|
||||
&allow-other-keys
|
||||
&aux (resp-string (format "STATUS: %s DATA: %s" (request-response-status-code response) data)))
|
||||
(ein:log 'debug "ein:notebooklist-delete-notebook--complete %s" resp-string)
|
||||
(when (and callback (eq symbol-status 'success)) (funcall callback)))
|
||||
|
||||
;; Because MinRK wants me to suffer (not really, I love MinRK)...
|
||||
(defun ein:get-actual-path (path)
|
||||
|
@ -688,7 +694,7 @@ You may find the new one in the notebook list." error)
|
|||
(lambda (&rest ignore)
|
||||
;; each directory creates a whole new notebooklist
|
||||
(ein:notebooklist-open url-or-port
|
||||
(ein:url (ein:$notebooklist-path ein:%notebooklist%) name))))
|
||||
(concat (directory-file-name (ein:$notebooklist-path ein:%notebooklist%)) name))))
|
||||
"Dir")
|
||||
(widget-insert " : " name)
|
||||
(widget-insert "\n"))
|
||||
|
@ -899,59 +905,73 @@ FIMXE: document how to use `ein:notebooklist-find-file-callback'
|
|||
|
||||
;;;###autoload
|
||||
|
||||
(defun ein:notebooklist-login (url-or-port password &optional retry-p)
|
||||
"Login to IPython notebook server."
|
||||
(defun ein:notebooklist-login (url-or-port password callback &optional retry-p)
|
||||
"Login to URL-OR-PORT with PASSWORD with notebooklist-open CALLBACK of arity 0."
|
||||
(interactive (list (ein:notebooklist-ask-url-or-port)
|
||||
(read-passwd "Password: ")))
|
||||
(ein:query-singleton-ajax
|
||||
(list 'notebooklist-login url-or-port)
|
||||
(ein:url url-or-port "login")
|
||||
:type "POST"
|
||||
:data (concat "password=" (url-hexify-string password))
|
||||
:parser #'ein:notebooklist-login--parser
|
||||
:error (apply-partially #'ein:notebooklist-login--error url-or-port password retry-p)
|
||||
:success (apply-partially #'ein:notebooklist-login--success url-or-port)))
|
||||
(if noninteractive
|
||||
;; noninteractive for testing only
|
||||
(multiple-value-bind (url-or-port token)
|
||||
(ein:jupyter-server-conn-info) token)
|
||||
(read-passwd "Password: "))
|
||||
nil))
|
||||
(if password
|
||||
(ein:query-singleton-ajax
|
||||
(list 'notebooklist-login url-or-port)
|
||||
(ein:url url-or-port "login")
|
||||
:type "POST"
|
||||
:data (concat "password=" (url-hexify-string password))
|
||||
:parser #'ein:notebooklist-login--parser
|
||||
:complete (apply-partially #'ein:notebooklist-login--complete url-or-port)
|
||||
:error (apply-partially #'ein:notebooklist-login--error url-or-port password callback retry-p)
|
||||
:success (apply-partially #'ein:notebooklist-login--success url-or-port callback))
|
||||
(ein:log 'verbose "Skipping formal login for lack of token")
|
||||
(funcall callback)))
|
||||
|
||||
(defun ein:notebooklist-login--parser ()
|
||||
(goto-char (point-min))
|
||||
(list :bad-page (re-search-forward "<input type=.?password" nil t)))
|
||||
|
||||
(defun ein:notebooklist-login--success-1 (url-or-port)
|
||||
(ein:log 'info "Login to %s complete. \
|
||||
Now you can open notebook list by `ein:notebooklist-open'." url-or-port))
|
||||
(defun ein:notebooklist-login--success-1 (url-or-port callback)
|
||||
(ein:log 'info "Login to %s complete." url-or-port)
|
||||
(funcall callback))
|
||||
|
||||
(defun ein:notebooklist-login--error-1 (url-or-port)
|
||||
(ein:log 'info "Failed to login to %s" url-or-port))
|
||||
|
||||
(defun* ein:notebooklist-login--success (url-or-port &key
|
||||
data
|
||||
(defun* ein:notebooklist-login--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:notebooklist-login--complete %s" resp-string))
|
||||
|
||||
(defun* ein:notebooklist-login--success (url-or-port callback
|
||||
&key data
|
||||
&allow-other-keys)
|
||||
(if (plist-get data :bad-page)
|
||||
(ein:notebooklist-login--error-1 url-or-port)
|
||||
(ein:notebooklist-login--success-1 url-or-port)))
|
||||
(ein:notebooklist-login--success-1 url-or-port callback)))
|
||||
|
||||
(defun* ein:notebooklist-login--error
|
||||
(url-or-port password retry-p &key
|
||||
(url-or-port password callback retry-p &key
|
||||
data
|
||||
symbol-status
|
||||
response
|
||||
&allow-other-keys
|
||||
&aux
|
||||
(response-status (request-response-status-code response)))
|
||||
(if (and (eq response-status 403)
|
||||
(not retry-p))
|
||||
(ein:notebooklist-login url-or-port password t))
|
||||
(if (or
|
||||
;; workaround for url-retrieve backend
|
||||
(and (eq symbol-status 'timeout)
|
||||
(equal response-status 302)
|
||||
(request-response-header response "set-cookie"))
|
||||
;; workaround for curl backend
|
||||
(and (equal response-status 405)
|
||||
(ein:aand (car (request-response-history response))
|
||||
(request-response-header it "set-cookie"))))
|
||||
(ein:notebooklist-login--success-1 url-or-port)
|
||||
(ein:notebooklist-login--error-1 url-or-port)))
|
||||
(cond ((and (eq response-status 403)
|
||||
(not retry-p))
|
||||
(ein:notebooklist-login url-or-port password callback t))
|
||||
((or
|
||||
;; workaround for url-retrieve backend
|
||||
(and (eq symbol-status 'timeout)
|
||||
(eq response-status 302)
|
||||
(request-response-header response "set-cookie"))
|
||||
;; workaround for curl backend
|
||||
(and (eq response-status 405)
|
||||
(ein:aand (car (request-response-history response))
|
||||
(request-response-header it "set-cookie"))))
|
||||
(ein:notebooklist-login--success-1 url-or-port callback))
|
||||
(t (ein:notebooklist-login--error-1 url-or-port))))
|
||||
|
||||
;;;###autoload
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
(eval-when-compile (require 'cl))
|
||||
(require 'eieio)
|
||||
|
||||
(require 'ein-notebook)
|
||||
(require 'ein-core)
|
||||
(require 'ein-classes)
|
||||
(require 'ein-events)
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
(require 'ein-core)
|
||||
(require 'ein-events)
|
||||
(require 'view)
|
||||
|
||||
;; FIXME: Make a class with `:get-notebook-name' slot like `ein:worksheet'
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
(declare-function ses-command-hook "ses")
|
||||
|
||||
(require 'ein-kernel)
|
||||
(require 'ein-notebook)
|
||||
|
||||
(defun ein:goto-file (filename lineno &optional other-window)
|
||||
"Jump to file FILEAME at line LINENO.
|
||||
|
|
|
@ -96,7 +96,7 @@ When this option is enabled, cached omni completion is available."
|
|||
(ein:use-ac-backend (require 'ein-ac)
|
||||
(ein:ac-config-once ein:use-auto-complete-superpack))
|
||||
(ein:use-ac-jedi-backend (require 'ein-jedi)
|
||||
(jedi:setup)
|
||||
;; (jedi:setup) ;; need tkf/emacs-jedi submodule
|
||||
(ein:jedi-setup)
|
||||
(ein:ac-config-once ein:use-auto-complete-superpack))
|
||||
(ein:use-company-backend (require 'ein-company)
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
(require 'ansi-color)
|
||||
|
||||
(require 'ein-core)
|
||||
(require 'ein-shared-output)
|
||||
|
||||
(defclass ein:traceback ()
|
||||
((tb-data :initarg :tb-data :type list)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
(require 'json)
|
||||
(require 's)
|
||||
(require 'dash)
|
||||
(require 'url)
|
||||
|
||||
|
||||
;;; Macros and core functions/variables
|
||||
|
@ -182,23 +183,23 @@ at point, i.e. any word before then \"(\", if it is present."
|
|||
(push subtree list)))))
|
||||
(traverse tree))
|
||||
(nreverse list)))
|
||||
|
||||
|
||||
|
||||
;;; URL utils
|
||||
|
||||
(defvar ein:url-localhost "127.0.0.1")
|
||||
(defvar ein:url-localhost-template "http://127.0.0.1:%s")
|
||||
|
||||
(defun ein:url (url-or-port &rest paths)
|
||||
(loop with url = (if (integerp url-or-port)
|
||||
(format ein:url-localhost-template url-or-port)
|
||||
url-or-port)
|
||||
for p in paths
|
||||
do (setq url (concat (ein:trim-right url "/")
|
||||
"/"
|
||||
(ein:trim-left p "/")))
|
||||
finally return url))
|
||||
(if (null url-or-port)
|
||||
nil
|
||||
(if (or (integerp url-or-port)
|
||||
(and (stringp url-or-port) (string-match "^[0-9]+$" url-or-port)))
|
||||
(setq url-or-port (format "http://localhost:%s" url-or-port)))
|
||||
(let ((parsed-url (url-generic-parse-url url-or-port)))
|
||||
(if (or (null (url-host parsed-url)) (string= (url-host parsed-url) "localhost"))
|
||||
(setf (url-host parsed-url) ein:url-localhost))
|
||||
(loop with url = (url-recreate-url parsed-url)
|
||||
for p in paths
|
||||
do (setq url (concat (file-name-as-directory url) (ein:trim-left (directory-file-name p) "/")))
|
||||
finally return (directory-file-name url)))))
|
||||
|
||||
(defun ein:url-no-cache (url)
|
||||
"Imitate `cache=false' of `jQuery.ajax'.
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
(require 'cl)
|
||||
(require 'ein-notebook)
|
||||
(require 'ein-shared-output)
|
||||
(require 'org-src)
|
||||
(require 'org-element)
|
||||
(require 'ein-utils)
|
||||
(require 'python)
|
||||
|
||||
|
@ -86,7 +88,7 @@
|
|||
(case key
|
||||
((svg image/svg)
|
||||
(let ((file (or file (ein:temp-inline-image-info value))))
|
||||
(ein:write-base64-decoded-image value file)
|
||||
(ein:write-base64-image value file)
|
||||
(format "[[file:%s]]" file)))
|
||||
((png image/png jpeg image/jpeg)
|
||||
(let ((file (or file (ein:temp-inline-image-info value))))
|
||||
|
|
|
@ -54,16 +54,25 @@
|
|||
(ein:testing-save-buffer ein:log-all-buffer-name ein:testing-dump-file-log)
|
||||
(ein:testing-save-buffer request-log-buffer-name ein:testing-dump-file-request))
|
||||
|
||||
(defun ein:testing-wait-until (predicate &optional predargs ms interval)
|
||||
(defun ein:testing-flush-queries (&optional ms interval continue)
|
||||
"Forget all the deferred:flush-queue! and deferred:sync! and all the semaphore
|
||||
callbacks. This is what I need."
|
||||
(ein:testing-wait-until (lambda ()
|
||||
(ein:query-gc-running-process-table)
|
||||
(zerop (hash-table-count ein:query-running-process-table)))
|
||||
nil ms interval continue))
|
||||
|
||||
(defun ein:testing-wait-until (predicate &optional predargs ms interval continue)
|
||||
"Wait until PREDICATE function returns non-`nil'.
|
||||
PREDARGS is argument list for the PREDICATE function.
|
||||
MS is milliseconds to wait. INTERVAL is polling interval in milliseconds."
|
||||
(let* ((interval (or interval 300))
|
||||
(count (max 1 (if ms (truncate (/ ms interval)) 25))))
|
||||
(unless (loop repeat count
|
||||
when (apply predicate predargs)
|
||||
return t
|
||||
do (sleep-for 0 interval))
|
||||
(let* ((int (ein:aif interval it (ein:aif ms (max 300 (/ ms 10)) 300)))
|
||||
(count (max 1 (if ms (truncate (/ ms int)) 25))))
|
||||
(unless (or (loop repeat count
|
||||
when (apply predicate predargs)
|
||||
return t
|
||||
do (sleep-for 0 int))
|
||||
continue)
|
||||
(error "Timeout: %s" predicate))))
|
||||
|
||||
(defadvice ert-run-tests-batch (after ein:testing-dump-logs-hook activate)
|
||||
|
|
|
@ -5,8 +5,12 @@
|
|||
(require 'ein-utils)
|
||||
|
||||
(ert-deftest ein-url-simple ()
|
||||
(should (null (ein:url nil)))
|
||||
(should (equal (ein:url 8888) "http://127.0.0.1:8888"))
|
||||
(should (equal (ein:url "http://localhost") "http://localhost")))
|
||||
(should (equal (ein:url "http://localhost") "http://127.0.0.1"))
|
||||
(should (equal (ein:url "https://localhost:8888") "https://127.0.0.1:8888"))
|
||||
(loop for url in '("http://127.0.0.1:8888" "http://localhost:8888" "http://127.0.0.1:8888/" "http://localhost:8888/" "8888" 8888)
|
||||
do (should (equal (ein:url "http://localhost:8888") (ein:url url)))))
|
||||
|
||||
(ert-deftest ein-url-slashes ()
|
||||
(loop for a in '("a" "a/" "/a")
|
||||
|
@ -14,7 +18,7 @@
|
|||
do (should (equal (ein:url 8888 a b)
|
||||
"http://127.0.0.1:8888/a/b")))
|
||||
do (should (equal (ein:url 8888 a "b/")
|
||||
"http://127.0.0.1:8888/a/b/"))))
|
||||
"http://127.0.0.1:8888/a/b"))))
|
||||
|
||||
(ert-deftest ein-trim-simple ()
|
||||
(should (equal (ein:trim "a") "a"))
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
(ein:log 'debug "TESTING-GET-NOTEBOOK-BY-NAME start")
|
||||
(when path
|
||||
(setq notebook-name (format "%s/%s" path notebook-name)))
|
||||
(ein:notebooklist-open url-or-port path t)
|
||||
(ein:notebooklist-open url-or-port path)
|
||||
(ein:testing-wait-until (lambda () (and (bufferp (get-buffer (format ein:notebooklist-buffer-name-template url-or-port)))
|
||||
(ein:notebooklist-get-buffer url-or-port))))
|
||||
(with-current-buffer (ein:notebooklist-get-buffer url-or-port)
|
||||
|
@ -57,7 +57,7 @@
|
|||
|
||||
(defun ein:testing-delete-notebook (url-or-port notebook &optional path)
|
||||
(ein:log 'debug "TESTING-DELETE-NOTEBOOK start")
|
||||
(ein:notebooklist-open url-or-port (ein:$notebook-notebook-path notebook) t)
|
||||
(ein:notebooklist-open url-or-port (ein:$notebook-notebook-path notebook))
|
||||
(ein:testing-wait-until (lambda ()
|
||||
(bufferp (get-buffer (format ein:notebooklist-buffer-name-template url-or-port)))))
|
||||
(with-current-buffer (ein:notebooklist-get-buffer url-or-port)
|
||||
|
@ -66,6 +66,7 @@
|
|||
(ein:notebooklist-delete-notebook (ein:$notebook-notebook-path notebook)))
|
||||
(ein:log 'debug "TESTING-DELETE-NOTEBOOK end"))
|
||||
|
||||
|
||||
;; (ert-deftest 00-jupyter-start-server ()
|
||||
;; (ein:log 'verbose "ERT TESTING-JUPYTER-START-SERVER start")
|
||||
;; (condition-case err
|
||||
|
@ -234,8 +235,7 @@ See the definition of `create-image' for how it works."
|
|||
(ein:testing-wait-until
|
||||
(lambda () (ein:aand (ein:$notebook-kernel notebook)
|
||||
(ein:kernel-live-p it))))
|
||||
(cl-letf (((symbol-function 'y-or-n-p) (lambda (prompt) t)))
|
||||
(ein:jupyter-server-stop t ein:testing-dump-file-server))
|
||||
(ein:jupyter-server-stop t ein:testing-dump-file-server)
|
||||
(should-not (processp %ein:jupyter-server-session%))
|
||||
(cl-flet ((orphans-find (pid) (search (ein:$kernel-kernel-id (ein:$notebook-kernel notebook)) (alist-get 'args (process-attributes pid)))))
|
||||
(should-not (loop repeat 10
|
||||
|
|
|
@ -31,10 +31,11 @@
|
|||
|
||||
(ein:dev-start-debug)
|
||||
(deferred:sync! (ein:jupyter-server-start *ein:testing-jupyter-server-command* *ein:testing-jupyter-server-directory*))
|
||||
;; (ein:testing-wait-until (lambda () (not (null (ein:notebooklist-list))))
|
||||
;; nil 120000 5000)
|
||||
(ein:testing-wait-until (lambda () (ein:notebooklist-list)) nil 15000 1000)
|
||||
(multiple-value-bind (url token) (ein:jupyter-server-conn-info)
|
||||
(ein:log 'info (format "testing-start-server url: %s, token: %s" url token))
|
||||
(setq *ein:testing-port* url)
|
||||
(setq *ein:testing-token* token)
|
||||
(ein:log 'info "testing-start-server succesfully logged in."))
|
||||
(fset 'y-or-n-p (lambda (prompt) nil))
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue