forked from emacs-jupyter/jupyter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jupyter-env.el
128 lines (105 loc) · 5 KB
/
jupyter-env.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
;;; jupyter-env.el --- Query the jupyter shell command for information -*- lexical-binding: t -*-
;; Copyright (C) 2019-2020 Nathaniel Nicandro
;; Author: Nathaniel Nicandro <[email protected]>
;; Created: 27 Jun 2019
;; This program 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, or (at
;; your option) any later version.
;; This program 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 GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; Custom variables and functions related to calling the jupyter shell command
;; and its sub-commands for information.
;;; Code:
(require 'jupyter-base)
(eval-when-compile (require 'subr-x))
(defvar jupyter-runtime-directory nil
"The Jupyter runtime directory.
When a new kernel is started through `jupyter-start-kernel', this
directory is where kernel connection files are written to.
This variable should not be used. To obtain the runtime directory
call the function `jupyter-runtime-directory'.")
(defun jupyter-command (&rest args)
"Run a Jupyter shell command synchronously, return its output.
The shell command run is
jupyter ARGS...
If the command fails or the jupyter shell command doesn't exist,
return nil."
(with-temp-buffer
(when (zerop (apply #'process-file "jupyter" nil t nil args))
(string-trim-right (buffer-string)))))
(defun jupyter-runtime-directory ()
"Return the runtime directory used by Jupyter.
Create the directory if necessary. If `default-directory' is a
remote directory, return the runtime directory on that remote.
As a side effect, the variable `jupyter-runtime-directory' is set
to the local runtime directory if it is nil."
(unless jupyter-runtime-directory
(setq jupyter-runtime-directory
(let ((default-directory (expand-file-name "~" user-emacs-directory)))
(jupyter-command "--runtime-dir"))))
(let ((dir (if (file-remote-p default-directory)
(jupyter-command "--runtime-dir")
jupyter-runtime-directory)))
(unless dir
(error "Can't obtain runtime directory from jupyter shell command"))
(prog1 (setq dir (concat (file-remote-p default-directory) dir))
(make-directory dir 'parents))))
(defun jupyter-locate-python ()
"Return the path to the python executable in use by Jupyter.
If the `default-directory' is a remote directory, search on that
remote. Raise an error if the executable could not be found.
The paths examined are the data paths of \"jupyter --paths\" in
the order specified.
This function always returns the `file-local-name' of the path."
(let* ((remote (file-remote-p default-directory))
(paths (mapcar (lambda (x) (concat remote x))
(or (plist-get
(jupyter-read-plist-from-string
(jupyter-command "--paths" "--json"))
:data)
(error "Can't get search paths"))))
(path nil))
(cl-loop
with programs = '("bin/python3" "bin/python"
;; Need to also check Windows since paths can be
;; pointing to local or remote files.
"python3.exe" "python.exe")
with pred = (lambda (dir)
(cl-loop
for program in programs
for spath = (expand-file-name program dir)
thereis (setq path (and (file-exists-p spath) spath))))
for path in paths
thereis (locate-dominating-file path pred)
finally (error "No `python' found in search paths"))
(file-local-name path)))
(cl-defmethod jupyter-write-connection-file ((session jupyter-session) (obj jupyter-finalized-object))
"Write a connection file based on SESSION to `jupyter-runtime-directory'.
Return the path to the connection file.
Also register a finalizer on OBJ to delete the file when OBJ is
garbage collected. The file is also deleted when Emacs exits if
it hasn't been already."
(let* ((temporary-file-directory (jupyter-runtime-directory))
(json-encoding-pretty-print t)
(file (make-temp-file "emacs-kernel-" nil ".json"))
(kill-hook (lambda () (when (and file (file-exists-p file))
(delete-file file)))))
(add-hook 'kill-emacs-hook kill-hook)
(jupyter-add-finalizer obj
(lambda ()
(funcall kill-hook)
(remove-hook 'kill-emacs-hook kill-hook)))
(prog1 file
(with-temp-file file
(insert (json-encode-plist
(jupyter-session-conn-info session)))))))
(provide 'jupyter-env)
;;; jupyter-env.el ends here