emacs-ipython-notebook/lisp/ein-jupyter.el

315 lines
13 KiB
EmacsLisp
Raw Normal View History

;;; ein-jupyter.el --- Manage the jupyter notebook server
;; Copyright (C) 2017 John M. Miller
;; Authors: John M. Miller <millejoh at mac.com>
;; This file is NOT part of GNU Emacs.
;; ein-jupyter.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-jupyter.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-jupyter.el. If not, see <http://www.gnu.org/licenses/>.
;;; Commentary:
;;; Code:
(require 'ein-core)
(require 'ein-notebooklist)
(require 'ein-dev)
2020-01-02 20:09:42 -05:00
(require 'ein-k8s)
2020-01-02 09:15:27 -05:00
(defcustom ein:jupyter-use-containers nil
2019-11-24 00:17:52 -05:00
"Take EIN in a different direcsh."
:group 'ein
2019-11-24 00:17:52 -05:00
:type 'boolean)
2019-11-24 00:17:52 -05:00
(defcustom ein:jupyter-docker-image "jupyter/datascience-notebook"
"Docker pull whichever jupyter image you prefer. This defaults to
the 'jupyter docker stacks' on hub.docker.com.
2019-11-24 00:17:52 -05:00
Optionally append ':tag', e.g., ':latest' in the customary way."
:group 'ein
2019-11-24 00:17:52 -05:00
:type 'string)
2019-11-26 14:28:22 -05:00
(defcustom ein:jupyter-docker-mount-point "/home/jovyan/ipynb"
"Directory in docker image where to mount `ein:jupyter-default-notebook-directory'."
:group 'ein
2019-11-24 00:17:52 -05:00
:type 'string)
2019-11-24 00:17:52 -05:00
(defcustom ein:jupyter-docker-additional-switches "-e JUPYTER_ENABLE_LAB=no --rm"
"Additional options to the 'docker run' call.
2019-11-24 00:17:52 -05:00
Note some options like '-v' and '-network' are imposed by EIN."
:group 'ein
:type 'string)
2019-11-24 00:17:52 -05:00
(defcustom ein:jupyter-server-command "jupyter"
"The default command to start a jupyter notebook server.
2019-11-24 00:17:52 -05:00
Changing this to `jupyter-notebook' requires customizing `ein:jupyter-server-use-subcommand' to nil."
:group 'ein
:type 'string)
(defcustom ein:jupyter-default-server-command ein:jupyter-server-command
"Obsolete alias for `ein:jupyter-server-command'"
:group 'ein
2019-11-24 00:17:52 -05:00
:type 'string
:set (lambda (_symbol value)
(setq ein:jupyter-server-command value)))
(defcustom ein:jupyter-server-use-subcommand "notebook"
2019-11-24 00:17:52 -05:00
"Users of \"jupyter-notebook\" (as opposed to \"jupyter notebook\") need to Omit."
:group 'ein
:type '(choice (string :tag "Subcommand" "notebook")
(const :tag "Omit" nil)))
2019-11-24 00:17:52 -05:00
(defcustom ein:jupyter-server-args '("--no-browser")
"Add any additional command line options you wish to include
with the call to the jupyter notebook."
:group 'ein
:type '(repeat string))
(defcustom ein:jupyter-default-notebook-directory nil
"Default location of ipynb files."
:group 'ein
:type 'directory)
(defcustom ein:jupyter-default-kernel 'first-alphabetically
"With which of ${XDG_DATA_HOME}/jupyter/kernels to create new notebooks."
:group 'ein
:type (append
'(choice (other :tag "First alphabetically" first-alphabetically))
(condition-case err
(mapcar
(lambda (x) `(const :tag ,(cdr x) ,(car x)))
2020-01-02 20:09:42 -05:00
(cl-loop
for (k . spec) in
(alist-get
'kernelspecs
(let ((json-object-type 'alist))
(json-read-from-string
(shell-command-to-string
(format "%s kernelspec list --json"
2019-11-24 00:17:52 -05:00
ein:jupyter-server-command)))))
collect `(,k . ,(alist-get 'display_name (alist-get 'spec spec)))))
(error (ein:log 'warn "ein:jupyter-default-kernel: %s" err)
'((string :tag "Ask"))))))
2019-11-24 00:17:52 -05:00
(defvar *ein:jupyter-server-process-name* "ein server")
(defvar *ein:jupyter-server-buffer-name*
(format "*%s*" *ein:jupyter-server-process-name*))
2020-01-02 20:09:42 -05:00
(defun ein:jupyter-process-lines (url-or-port command &rest args)
"If URL-OR-PORT registered as a k8s url, preface COMMAND ARGS with `kubectl exec'."
(condition-case err
(cond ((and url-or-port (string= url-or-port (ein:k8s-service-url-or-port)))
(let ((pod-name (kubernetes-state-resource-name (ein:k8s-get-pod))))
(apply #'process-lines kubernetes-kubectl-executable
(nconc
(split-string (format "exec %s -- %s" pod-name command))
args))))
(t (apply #'process-lines command args)))
(error (ein:log 'info "ein:jupyter-process-lines: %s" (error-message-string err))
nil)))
(defsubst ein:jupyter-server-process ()
2019-11-24 00:17:52 -05:00
"Return the emacs process object of our session."
(get-buffer-process (get-buffer *ein:jupyter-server-buffer-name*)))
(defun ein:jupyter-server--run (buf user-cmd dir &optional args)
(let* ((cmd (if ein:jupyter-use-containers "docker" user-cmd))
(vargs (cond (ein:jupyter-use-containers
(split-string
(format "run --network host -v %s:%s %s %s"
dir
2019-11-26 14:28:22 -05:00
ein:jupyter-docker-mount-point
2019-11-24 00:17:52 -05:00
ein:jupyter-docker-additional-switches
ein:jupyter-docker-image)))
(t
(append (aif ein:jupyter-server-use-subcommand (list it))
(list (format "--notebook-dir=%s"
(convert-standard-filename dir)))
args
(let ((copy ein:jupyter-server-args))
(when ein:debug
2019-11-26 14:28:22 -05:00
(add-to-list 'copy "--debug"))
2019-11-24 00:17:52 -05:00
copy)))))
(proc (apply #'start-process
*ein:jupyter-server-process-name* buf cmd vargs)))
(ein:log 'info "ein:jupyter-server--run: %s %s" cmd (ein:join-str " " vargs))
(set-process-query-on-exit-flag proc nil)
proc))
(defun ein:jupyter-server-conn-info (&optional buffer-name)
"Return the url-or-port and password for BUFFER or the global session."
(unless buffer-name
2019-11-24 00:17:52 -05:00
(setq buffer-name *ein:jupyter-server-buffer-name*))
(let ((buffer (get-buffer buffer-name))
(result '(nil nil)))
(if buffer
(with-current-buffer buffer
(save-excursion
(goto-char (point-max))
2018-10-20 11:40:36 -04:00
(re-search-backward (format "Process %s" *ein:jupyter-server-process-name*)
nil "") ;; important if we start-stop-start
(when (re-search-forward "\\([[:alnum:]]+\\) is\\( now\\)? running" nil t)
(let ((hub-p (cl-search "jupyterhub" (downcase (match-string 1)))))
(when (re-search-forward "\\(https?://[^:]*:[0-9]+\\)\\(?:/\\?token=\\([[:alnum:]]+\\)\\)?" nil t)
(let ((raw-url (match-string 1))
(token (or (match-string 2) (and (not hub-p) ""))))
(setq result (list (ein:url raw-url) token)))))))))
result))
(defun ein:jupyter-server-login-and-open (&optional callback)
"Log in and open a notebooklist buffer for a running jupyter notebook server.
Determine if there is a running jupyter server (started via a
call to `ein:jupyter-server-start') and then try to guess if
token authentication is enabled. If a token is found use it to generate a
call to `ein:notebooklist-login' and once authenticated open the notebooklist buffer
via a call to `ein:notebooklist-open'."
(interactive)
(when (ein:jupyter-server-process)
(multiple-value-bind (url-or-port password) (ein:jupyter-server-conn-info)
(ein:notebooklist-login url-or-port callback))))
(defsubst ein:set-process-sentinel (proc url-or-port)
"URL-OR-PORT might get redirected from (ein:jupyter-server-conn-info).
This is currently only the case for jupyterhub.
Once login handshake provides the new URL-OR-PORT, we set various state as pertains
our singleton jupyter server process here."
;; Would have used `add-function' if it didn't produce gv-ref warnings.
Appveyor iterating (WIP) (#573) * ob-ein: Bring back old functionality. Bring back some old features to babel edit buffers while trying to respect recent addition of polymode support. * Override polymode if the user really wants. Polymode is really for notebook buffers in any case, but this will override whatever completion backmode a user has configured for python-mode. * Install cask using python2. For now python2 is the easiest option for testing on Windows since cask does not properly support python3 when in Windows. * Let's throw in the ert-runner, see what happens. * Can I use my fork of cask? Work around smartrep weirdness, try to live without command line wildcard expansion. * Get the url for the fork right. * Experiment with python37, use test_script. * Unstick appveyor, I hope. * Fix parsing error. * test_script is not executing. Why? * Add ert testing. But why are the test_script commands not executing? * tasks: Automate building and testing using invoke. Invoke leverages Python, which I hope will allow us to abstract out differences in platforms when it comes to building and testing ein. * Use invoke on appveyor. * appveyor: Use the environment python. So we can test versions other than python 2.7. * Parsing error. Is https://packaging.python.org/guides/supporting-windows-using-appveyor/#setting-up lying to me? * Quote commands, just in case. * Get python onto the path. * Appveyor is catching up to travis. * Parsing error. * Update pip, try to get quoted syntax right. * Still not liking my pip call. Last try, next step we go to a requirements.txt file. * Go to using a requirements file for pip. * ecukes needs bash to work. * Cleaning up and fiddling. Seems like the emacs-jupyter guy has his act together - maybe we can take some inspiration for our appveyor config. * Syntax error in environment. * More syntax errros. * Maybe we need quoting. * I give up. * Formatting and cleanup. * Add customization, yet another syntax error. New customizable variable `ob-ein-babel-edit-polymode-ignore' to override keybinding for \C-c\C-c in an org source code edit buffer. * John learned some Powershell today. * Fix the executable path. Sometimes there is more than one curl installed on the system, make sure we can account for that in testing. * Handle updating the path inside invoke. * Report which curl we are using before starting functional tests. * Enable RDP so we can see error logs. * Keep the build alive even when it finishes. * Fix #568. Apparently we need to specify the user agent when on windows, otherwise tornado will start throwing 403 responses. Currently using Mozilla/4.0 as the agent, but might be a good idea to make this value customizable. * Clean up emacs config. * Why is appveyor dropping the xsrf token? * xsrf cookie found, what does the header look like? * Try different user-agent header, reenable rdp. * JSON encoding issues on Python side, it appears. Let's try an older Python. Login works, contents query to get notebooklist works (i.e. GET on /contents/api), but creating a notebook (i.e. POST on /contents/api) fails with invalid JSON. ein and emacs-request appear to be generating the proper json, but jupyter notebook does not see the same thing that is being written. Could be bytes vs. text issue with modern v3.x python, so let us see how this all works with Python 2.7. * Python27 does not have pathlib out of the box. * Make amends with Python27 * Back to python37. Tornado/notebook still isn't reading the POST'ed json correctly. * Do we need to specify content type? * Must be selective in specifying application/json content. * Re-enable rdp. * Let's try a different curl. * Ensure most recent curl is on path * Try a different path. * Try to warn user if suspicious curl detected. * Remove debugging statements. * EVM depends on trusty for 26.x See issue #125 (https://github.com/rejeep/evm/issues/125). Let's hope I got the travis.yml syntax right. * Minimal support for ecukes from invoke. * Cleaner server shutdowns, better ecukes support from invoke. Use the /api/shutdown REST API call now to shutdown running server. Also support more command line options for ecukes from invoke. * Almost full support of ecukes using invoke. But! Also disabling integration testing for the time being until I understand why ecukes fails even though everything else is working. * Just do integration and functional testing on appveyor. Better than nothing while I work out what is breaking the integration tests.
2019-07-28 18:20:13 -06:00
(set-process-sentinel
proc
(apply-partially (lambda (url-or-port* sentinel proc* event)
2019-11-24 00:17:52 -05:00
(aif sentinel (funcall it proc* event))
(funcall #'ein:notebooklist-sentinel url-or-port* proc* event))
url-or-port (process-sentinel proc))))
;;;###autoload
2019-11-24 00:17:52 -05:00
(defun ein:jupyter-server-start (server-command
notebook-directory
&optional no-login-p login-callback port)
"Start SERVER-COMMAND with `--notebook-dir' NOTEBOOK-DIRECTORY.
Login after connection established unless NO-LOGIN-P is set.
LOGIN-CALLBACK takes two arguments, the buffer created by
`ein:notebooklist-open--finish', and the url-or-port argument
of `ein:notebooklist-open*'.
With \\[universal-argument] prefix arg, prompt the user for the
server command."
(interactive
2019-11-24 00:17:52 -05:00
(list (let ((default-command (executable-find ein:jupyter-server-command)))
(if (and (not ein:jupyter-use-containers)
(or current-prefix-arg (not default-command)))
(let (command result)
(while (not (setq
result
(executable-find
(setq
command
(read-string
(format
"%sServer command: "
(if command
(format "[%s not executable] " command)
""))
nil nil ein:jupyter-server-command))))))
result)
default-command))
(let (result
(default-dir ein:jupyter-default-notebook-directory))
(while (or (not result) (not (file-directory-p result)))
(setq result (read-directory-name
(format "%sNotebook directory: "
(if result
(format "[%s not a directory]" result)
""))
nil
ein:jupyter-default-notebook-directory
t)))
result)
nil
(lambda (buffer url-or-port)
(pop-to-buffer buffer))
nil))
(if (ein:jupyter-server-process)
2019-11-24 00:17:52 -05:00
(error "ein:jupyter-server-start: please first M-x ein:stop"))
(add-hook 'kill-emacs-hook #'(lambda ()
(ignore-errors (ein:jupyter-server-stop t))))
2019-11-24 00:17:52 -05:00
(let ((proc (ein:jupyter-server--run *ein:jupyter-server-buffer-name*
server-command
notebook-directory
(if (numberp port)
`("--port" ,(format "%s" port)
"--port-retries" "0")))))
2020-01-02 20:09:42 -05:00
(cl-loop repeat 30
2019-11-24 00:17:52 -05:00
until (car (ein:jupyter-server-conn-info *ein:jupyter-server-buffer-name*))
do (sleep-for 0 500)
finally do
2019-11-24 00:17:52 -05:00
(unless (car (ein:jupyter-server-conn-info *ein:jupyter-server-buffer-name*))
(ein:log 'warn "Jupyter server failed to start, cancelling operation")
(ein:jupyter-server-stop t)))
(when (and (not no-login-p) (ein:jupyter-server-process))
(unless login-callback
(setq login-callback #'ignore))
(add-function :after login-callback
(apply-partially (lambda (proc* buffer url-or-port)
(ein:set-process-sentinel proc* url-or-port))
proc))
(ein:jupyter-server-login-and-open login-callback))))
;;;###autoload
(defalias 'ein:run 'ein:jupyter-server-start)
;;;###autoload
(defalias 'ein:stop 'ein:jupyter-server-stop)
(defun ein:undocumented-shutdown (url-or-port)
Appveyor iterating (WIP) (#573) * ob-ein: Bring back old functionality. Bring back some old features to babel edit buffers while trying to respect recent addition of polymode support. * Override polymode if the user really wants. Polymode is really for notebook buffers in any case, but this will override whatever completion backmode a user has configured for python-mode. * Install cask using python2. For now python2 is the easiest option for testing on Windows since cask does not properly support python3 when in Windows. * Let's throw in the ert-runner, see what happens. * Can I use my fork of cask? Work around smartrep weirdness, try to live without command line wildcard expansion. * Get the url for the fork right. * Experiment with python37, use test_script. * Unstick appveyor, I hope. * Fix parsing error. * test_script is not executing. Why? * Add ert testing. But why are the test_script commands not executing? * tasks: Automate building and testing using invoke. Invoke leverages Python, which I hope will allow us to abstract out differences in platforms when it comes to building and testing ein. * Use invoke on appveyor. * appveyor: Use the environment python. So we can test versions other than python 2.7. * Parsing error. Is https://packaging.python.org/guides/supporting-windows-using-appveyor/#setting-up lying to me? * Quote commands, just in case. * Get python onto the path. * Appveyor is catching up to travis. * Parsing error. * Update pip, try to get quoted syntax right. * Still not liking my pip call. Last try, next step we go to a requirements.txt file. * Go to using a requirements file for pip. * ecukes needs bash to work. * Cleaning up and fiddling. Seems like the emacs-jupyter guy has his act together - maybe we can take some inspiration for our appveyor config. * Syntax error in environment. * More syntax errros. * Maybe we need quoting. * I give up. * Formatting and cleanup. * Add customization, yet another syntax error. New customizable variable `ob-ein-babel-edit-polymode-ignore' to override keybinding for \C-c\C-c in an org source code edit buffer. * John learned some Powershell today. * Fix the executable path. Sometimes there is more than one curl installed on the system, make sure we can account for that in testing. * Handle updating the path inside invoke. * Report which curl we are using before starting functional tests. * Enable RDP so we can see error logs. * Keep the build alive even when it finishes. * Fix #568. Apparently we need to specify the user agent when on windows, otherwise tornado will start throwing 403 responses. Currently using Mozilla/4.0 as the agent, but might be a good idea to make this value customizable. * Clean up emacs config. * Why is appveyor dropping the xsrf token? * xsrf cookie found, what does the header look like? * Try different user-agent header, reenable rdp. * JSON encoding issues on Python side, it appears. Let's try an older Python. Login works, contents query to get notebooklist works (i.e. GET on /contents/api), but creating a notebook (i.e. POST on /contents/api) fails with invalid JSON. ein and emacs-request appear to be generating the proper json, but jupyter notebook does not see the same thing that is being written. Could be bytes vs. text issue with modern v3.x python, so let us see how this all works with Python 2.7. * Python27 does not have pathlib out of the box. * Make amends with Python27 * Back to python37. Tornado/notebook still isn't reading the POST'ed json correctly. * Do we need to specify content type? * Must be selective in specifying application/json content. * Re-enable rdp. * Let's try a different curl. * Ensure most recent curl is on path * Try a different path. * Try to warn user if suspicious curl detected. * Remove debugging statements. * EVM depends on trusty for 26.x See issue #125 (https://github.com/rejeep/evm/issues/125). Let's hope I got the travis.yml syntax right. * Minimal support for ecukes from invoke. * Cleaner server shutdowns, better ecukes support from invoke. Use the /api/shutdown REST API call now to shutdown running server. Also support more command line options for ecukes from invoke. * Almost full support of ecukes using invoke. But! Also disabling integration testing for the time being until I understand why ecukes fails even though everything else is working. * Just do integration and functional testing on appveyor. Better than nothing while I work out what is breaking the integration tests.
2019-07-28 18:20:13 -06:00
(ein:query-singleton-ajax
(list 'shutdown-server url-or-port)
Appveyor iterating (WIP) (#573) * ob-ein: Bring back old functionality. Bring back some old features to babel edit buffers while trying to respect recent addition of polymode support. * Override polymode if the user really wants. Polymode is really for notebook buffers in any case, but this will override whatever completion backmode a user has configured for python-mode. * Install cask using python2. For now python2 is the easiest option for testing on Windows since cask does not properly support python3 when in Windows. * Let's throw in the ert-runner, see what happens. * Can I use my fork of cask? Work around smartrep weirdness, try to live without command line wildcard expansion. * Get the url for the fork right. * Experiment with python37, use test_script. * Unstick appveyor, I hope. * Fix parsing error. * test_script is not executing. Why? * Add ert testing. But why are the test_script commands not executing? * tasks: Automate building and testing using invoke. Invoke leverages Python, which I hope will allow us to abstract out differences in platforms when it comes to building and testing ein. * Use invoke on appveyor. * appveyor: Use the environment python. So we can test versions other than python 2.7. * Parsing error. Is https://packaging.python.org/guides/supporting-windows-using-appveyor/#setting-up lying to me? * Quote commands, just in case. * Get python onto the path. * Appveyor is catching up to travis. * Parsing error. * Update pip, try to get quoted syntax right. * Still not liking my pip call. Last try, next step we go to a requirements.txt file. * Go to using a requirements file for pip. * ecukes needs bash to work. * Cleaning up and fiddling. Seems like the emacs-jupyter guy has his act together - maybe we can take some inspiration for our appveyor config. * Syntax error in environment. * More syntax errros. * Maybe we need quoting. * I give up. * Formatting and cleanup. * Add customization, yet another syntax error. New customizable variable `ob-ein-babel-edit-polymode-ignore' to override keybinding for \C-c\C-c in an org source code edit buffer. * John learned some Powershell today. * Fix the executable path. Sometimes there is more than one curl installed on the system, make sure we can account for that in testing. * Handle updating the path inside invoke. * Report which curl we are using before starting functional tests. * Enable RDP so we can see error logs. * Keep the build alive even when it finishes. * Fix #568. Apparently we need to specify the user agent when on windows, otherwise tornado will start throwing 403 responses. Currently using Mozilla/4.0 as the agent, but might be a good idea to make this value customizable. * Clean up emacs config. * Why is appveyor dropping the xsrf token? * xsrf cookie found, what does the header look like? * Try different user-agent header, reenable rdp. * JSON encoding issues on Python side, it appears. Let's try an older Python. Login works, contents query to get notebooklist works (i.e. GET on /contents/api), but creating a notebook (i.e. POST on /contents/api) fails with invalid JSON. ein and emacs-request appear to be generating the proper json, but jupyter notebook does not see the same thing that is being written. Could be bytes vs. text issue with modern v3.x python, so let us see how this all works with Python 2.7. * Python27 does not have pathlib out of the box. * Make amends with Python27 * Back to python37. Tornado/notebook still isn't reading the POST'ed json correctly. * Do we need to specify content type? * Must be selective in specifying application/json content. * Re-enable rdp. * Let's try a different curl. * Ensure most recent curl is on path * Try a different path. * Try to warn user if suspicious curl detected. * Remove debugging statements. * EVM depends on trusty for 26.x See issue #125 (https://github.com/rejeep/evm/issues/125). Let's hope I got the travis.yml syntax right. * Minimal support for ecukes from invoke. * Cleaner server shutdowns, better ecukes support from invoke. Use the /api/shutdown REST API call now to shutdown running server. Also support more command line options for ecukes from invoke. * Almost full support of ecukes using invoke. But! Also disabling integration testing for the time being until I understand why ecukes fails even though everything else is working. * Just do integration and functional testing on appveyor. Better than nothing while I work out what is breaking the integration tests.
2019-07-28 18:20:13 -06:00
(ein:url url-or-port "api/shutdown")
:type "POST"
2019-08-10 18:00:03 -04:00
:timeout 3 ;; content-query-timeout and query-timeout default nil
Appveyor iterating (WIP) (#573) * ob-ein: Bring back old functionality. Bring back some old features to babel edit buffers while trying to respect recent addition of polymode support. * Override polymode if the user really wants. Polymode is really for notebook buffers in any case, but this will override whatever completion backmode a user has configured for python-mode. * Install cask using python2. For now python2 is the easiest option for testing on Windows since cask does not properly support python3 when in Windows. * Let's throw in the ert-runner, see what happens. * Can I use my fork of cask? Work around smartrep weirdness, try to live without command line wildcard expansion. * Get the url for the fork right. * Experiment with python37, use test_script. * Unstick appveyor, I hope. * Fix parsing error. * test_script is not executing. Why? * Add ert testing. But why are the test_script commands not executing? * tasks: Automate building and testing using invoke. Invoke leverages Python, which I hope will allow us to abstract out differences in platforms when it comes to building and testing ein. * Use invoke on appveyor. * appveyor: Use the environment python. So we can test versions other than python 2.7. * Parsing error. Is https://packaging.python.org/guides/supporting-windows-using-appveyor/#setting-up lying to me? * Quote commands, just in case. * Get python onto the path. * Appveyor is catching up to travis. * Parsing error. * Update pip, try to get quoted syntax right. * Still not liking my pip call. Last try, next step we go to a requirements.txt file. * Go to using a requirements file for pip. * ecukes needs bash to work. * Cleaning up and fiddling. Seems like the emacs-jupyter guy has his act together - maybe we can take some inspiration for our appveyor config. * Syntax error in environment. * More syntax errros. * Maybe we need quoting. * I give up. * Formatting and cleanup. * Add customization, yet another syntax error. New customizable variable `ob-ein-babel-edit-polymode-ignore' to override keybinding for \C-c\C-c in an org source code edit buffer. * John learned some Powershell today. * Fix the executable path. Sometimes there is more than one curl installed on the system, make sure we can account for that in testing. * Handle updating the path inside invoke. * Report which curl we are using before starting functional tests. * Enable RDP so we can see error logs. * Keep the build alive even when it finishes. * Fix #568. Apparently we need to specify the user agent when on windows, otherwise tornado will start throwing 403 responses. Currently using Mozilla/4.0 as the agent, but might be a good idea to make this value customizable. * Clean up emacs config. * Why is appveyor dropping the xsrf token? * xsrf cookie found, what does the header look like? * Try different user-agent header, reenable rdp. * JSON encoding issues on Python side, it appears. Let's try an older Python. Login works, contents query to get notebooklist works (i.e. GET on /contents/api), but creating a notebook (i.e. POST on /contents/api) fails with invalid JSON. ein and emacs-request appear to be generating the proper json, but jupyter notebook does not see the same thing that is being written. Could be bytes vs. text issue with modern v3.x python, so let us see how this all works with Python 2.7. * Python27 does not have pathlib out of the box. * Make amends with Python27 * Back to python37. Tornado/notebook still isn't reading the POST'ed json correctly. * Do we need to specify content type? * Must be selective in specifying application/json content. * Re-enable rdp. * Let's try a different curl. * Ensure most recent curl is on path * Try a different path. * Try to warn user if suspicious curl detected. * Remove debugging statements. * EVM depends on trusty for 26.x See issue #125 (https://github.com/rejeep/evm/issues/125). Let's hope I got the travis.yml syntax right. * Minimal support for ecukes from invoke. * Cleaner server shutdowns, better ecukes support from invoke. Use the /api/shutdown REST API call now to shutdown running server. Also support more command line options for ecukes from invoke. * Almost full support of ecukes using invoke. But! Also disabling integration testing for the time being until I understand why ecukes fails even though everything else is working. * Just do integration and functional testing on appveyor. Better than nothing while I work out what is breaking the integration tests.
2019-07-28 18:20:13 -06:00
:sync t))
;;;###autoload
(defun ein:jupyter-server-stop (&optional force log)
(interactive)
Appveyor iterating (WIP) (#573) * ob-ein: Bring back old functionality. Bring back some old features to babel edit buffers while trying to respect recent addition of polymode support. * Override polymode if the user really wants. Polymode is really for notebook buffers in any case, but this will override whatever completion backmode a user has configured for python-mode. * Install cask using python2. For now python2 is the easiest option for testing on Windows since cask does not properly support python3 when in Windows. * Let's throw in the ert-runner, see what happens. * Can I use my fork of cask? Work around smartrep weirdness, try to live without command line wildcard expansion. * Get the url for the fork right. * Experiment with python37, use test_script. * Unstick appveyor, I hope. * Fix parsing error. * test_script is not executing. Why? * Add ert testing. But why are the test_script commands not executing? * tasks: Automate building and testing using invoke. Invoke leverages Python, which I hope will allow us to abstract out differences in platforms when it comes to building and testing ein. * Use invoke on appveyor. * appveyor: Use the environment python. So we can test versions other than python 2.7. * Parsing error. Is https://packaging.python.org/guides/supporting-windows-using-appveyor/#setting-up lying to me? * Quote commands, just in case. * Get python onto the path. * Appveyor is catching up to travis. * Parsing error. * Update pip, try to get quoted syntax right. * Still not liking my pip call. Last try, next step we go to a requirements.txt file. * Go to using a requirements file for pip. * ecukes needs bash to work. * Cleaning up and fiddling. Seems like the emacs-jupyter guy has his act together - maybe we can take some inspiration for our appveyor config. * Syntax error in environment. * More syntax errros. * Maybe we need quoting. * I give up. * Formatting and cleanup. * Add customization, yet another syntax error. New customizable variable `ob-ein-babel-edit-polymode-ignore' to override keybinding for \C-c\C-c in an org source code edit buffer. * John learned some Powershell today. * Fix the executable path. Sometimes there is more than one curl installed on the system, make sure we can account for that in testing. * Handle updating the path inside invoke. * Report which curl we are using before starting functional tests. * Enable RDP so we can see error logs. * Keep the build alive even when it finishes. * Fix #568. Apparently we need to specify the user agent when on windows, otherwise tornado will start throwing 403 responses. Currently using Mozilla/4.0 as the agent, but might be a good idea to make this value customizable. * Clean up emacs config. * Why is appveyor dropping the xsrf token? * xsrf cookie found, what does the header look like? * Try different user-agent header, reenable rdp. * JSON encoding issues on Python side, it appears. Let's try an older Python. Login works, contents query to get notebooklist works (i.e. GET on /contents/api), but creating a notebook (i.e. POST on /contents/api) fails with invalid JSON. ein and emacs-request appear to be generating the proper json, but jupyter notebook does not see the same thing that is being written. Could be bytes vs. text issue with modern v3.x python, so let us see how this all works with Python 2.7. * Python27 does not have pathlib out of the box. * Make amends with Python27 * Back to python37. Tornado/notebook still isn't reading the POST'ed json correctly. * Do we need to specify content type? * Must be selective in specifying application/json content. * Re-enable rdp. * Let's try a different curl. * Ensure most recent curl is on path * Try a different path. * Try to warn user if suspicious curl detected. * Remove debugging statements. * EVM depends on trusty for 26.x See issue #125 (https://github.com/rejeep/evm/issues/125). Let's hope I got the travis.yml syntax right. * Minimal support for ecukes from invoke. * Cleaner server shutdowns, better ecukes support from invoke. Use the /api/shutdown REST API call now to shutdown running server. Also support more command line options for ecukes from invoke. * Almost full support of ecukes using invoke. But! Also disabling integration testing for the time being until I understand why ecukes fails even though everything else is working. * Just do integration and functional testing on appveyor. Better than nothing while I work out what is breaking the integration tests.
2019-07-28 18:20:13 -06:00
(ein:and-let* ((url-or-port (first (ein:jupyter-server-conn-info)))
(_ok (or force (y-or-n-p "Stop server and close notebooks?"))))
(ein:notebook-close-notebooks t)
2020-01-02 20:09:42 -05:00
(cl-loop repeat 10
do (ein:query-running-process-table)
until (zerop (hash-table-count ein:query-running-process-table))
do (sleep-for 0 500))
(lexical-let* ((proc (ein:jupyter-server-process))
(pid (process-id proc)))
(ein:log 'info "Signaled %s with pid %s" proc pid)
(signal-process pid 15)
(run-at-time 2 nil
(lambda ()
(ein:log 'info "Resignaled %s with pid %s" proc pid)
(signal-process pid 15))))
;; `ein:notebooklist-sentinel' frequently does not trigger
Appveyor iterating (WIP) (#573) * ob-ein: Bring back old functionality. Bring back some old features to babel edit buffers while trying to respect recent addition of polymode support. * Override polymode if the user really wants. Polymode is really for notebook buffers in any case, but this will override whatever completion backmode a user has configured for python-mode. * Install cask using python2. For now python2 is the easiest option for testing on Windows since cask does not properly support python3 when in Windows. * Let's throw in the ert-runner, see what happens. * Can I use my fork of cask? Work around smartrep weirdness, try to live without command line wildcard expansion. * Get the url for the fork right. * Experiment with python37, use test_script. * Unstick appveyor, I hope. * Fix parsing error. * test_script is not executing. Why? * Add ert testing. But why are the test_script commands not executing? * tasks: Automate building and testing using invoke. Invoke leverages Python, which I hope will allow us to abstract out differences in platforms when it comes to building and testing ein. * Use invoke on appveyor. * appveyor: Use the environment python. So we can test versions other than python 2.7. * Parsing error. Is https://packaging.python.org/guides/supporting-windows-using-appveyor/#setting-up lying to me? * Quote commands, just in case. * Get python onto the path. * Appveyor is catching up to travis. * Parsing error. * Update pip, try to get quoted syntax right. * Still not liking my pip call. Last try, next step we go to a requirements.txt file. * Go to using a requirements file for pip. * ecukes needs bash to work. * Cleaning up and fiddling. Seems like the emacs-jupyter guy has his act together - maybe we can take some inspiration for our appveyor config. * Syntax error in environment. * More syntax errros. * Maybe we need quoting. * I give up. * Formatting and cleanup. * Add customization, yet another syntax error. New customizable variable `ob-ein-babel-edit-polymode-ignore' to override keybinding for \C-c\C-c in an org source code edit buffer. * John learned some Powershell today. * Fix the executable path. Sometimes there is more than one curl installed on the system, make sure we can account for that in testing. * Handle updating the path inside invoke. * Report which curl we are using before starting functional tests. * Enable RDP so we can see error logs. * Keep the build alive even when it finishes. * Fix #568. Apparently we need to specify the user agent when on windows, otherwise tornado will start throwing 403 responses. Currently using Mozilla/4.0 as the agent, but might be a good idea to make this value customizable. * Clean up emacs config. * Why is appveyor dropping the xsrf token? * xsrf cookie found, what does the header look like? * Try different user-agent header, reenable rdp. * JSON encoding issues on Python side, it appears. Let's try an older Python. Login works, contents query to get notebooklist works (i.e. GET on /contents/api), but creating a notebook (i.e. POST on /contents/api) fails with invalid JSON. ein and emacs-request appear to be generating the proper json, but jupyter notebook does not see the same thing that is being written. Could be bytes vs. text issue with modern v3.x python, so let us see how this all works with Python 2.7. * Python27 does not have pathlib out of the box. * Make amends with Python27 * Back to python37. Tornado/notebook still isn't reading the POST'ed json correctly. * Do we need to specify content type? * Must be selective in specifying application/json content. * Re-enable rdp. * Let's try a different curl. * Ensure most recent curl is on path * Try a different path. * Try to warn user if suspicious curl detected. * Remove debugging statements. * EVM depends on trusty for 26.x See issue #125 (https://github.com/rejeep/evm/issues/125). Let's hope I got the travis.yml syntax right. * Minimal support for ecukes from invoke. * Cleaner server shutdowns, better ecukes support from invoke. Use the /api/shutdown REST API call now to shutdown running server. Also support more command line options for ecukes from invoke. * Almost full support of ecukes using invoke. But! Also disabling integration testing for the time being until I understand why ecukes fails even though everything else is working. * Just do integration and functional testing on appveyor. Better than nothing while I work out what is breaking the integration tests.
2019-07-28 18:20:13 -06:00
(ein:notebooklist-list-remove url-or-port)
(kill-buffer (ein:notebooklist-get-buffer url-or-port))
(when log
2019-11-24 00:17:52 -05:00
(with-current-buffer *ein:jupyter-server-buffer-name*
(write-region (point-min) (point-max) log)))))
(provide 'ein-jupyter)