Skip to content

Commit bed0011

Browse files
author
Bob Hyman
committed
Move jup kernel spec from setup to xonfig; add doc.
1 parent d42b414 commit bed0011

File tree

7 files changed

+152
-72
lines changed

7 files changed

+152
-72
lines changed

docs/appimage.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ You can get the xonsh AppImage from GitHub and run it on your Linux machine with
1717
1818
If you don't have Python on your host, you may want to get it from AppImage:
1919

20-
.. code-block:: xonsh
20+
.. code-block:: xonshcon
2121
2222
./xonsh
2323
$PATH = [f'{$APPDIR}/usr/bin'] + $PATH

docs/installation.rst

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Xonsh can be installed via package manager, via appimage or just run from a pre-
2121
appimage
2222
containers
2323
editors
24+
jupyter
2425

2526
Configuration and Customization
2627
================================

docs/jupyter.rst

+38-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,42 @@ Xonsh provides a kernel for Jupyter Notebook and Lab so you can execute xonsh co
66
Installation
77
-------------
88

9-
[ed note: this is a stub and the topic is excluded from docs
10-
till I or someone can get a consistent install procedure to work!]
9+
Install Jupyter and Xonsh in the same environment, then configure the Xonsh kernel for Jupyter:
10+
11+
.. code-block:: xonshcon
12+
13+
$ xonfig kernel
14+
Installing Jupyter kernel spec:
15+
root: None
16+
prefix: <env_prefix>
17+
as user: False
18+
19+
_<Env_prefix>_ is the path prefix of the Jupyter and Xonsh environment. ``xonfig kernel --help`` shows options
20+
for installing the kernel spec in the user config folder or in a non-standard environment prefix.
21+
22+
You can confirm the status of the installation:
23+
24+
.. code-block:: xonshcon
25+
26+
$ xonfig info
27+
+------------------+-----------------------------------------------------+
28+
| xonsh | 0.9.21 |
29+
| Git SHA | d42b4140 |
30+
31+
. . . . .
32+
33+
| on jupyter | True |
34+
| jupyter kernel | <env_prefix>\share\jupyter\kernels\xonsh |
35+
+------------------+-----------------------------------------------------+
36+
37+
Or:
38+
39+
.. code-block:: xonshcon
40+
41+
$ jupyter kernelspec list
42+
Available kernels:
43+
python3 <env_prefix>\share\jupyter\kernels\python3
44+
xonsh <env_prefix>\share\jupyter\kernels\xonsh
45+
46+
1147

docs/packages.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ use the Python ``readline`` module (which reads configuration file ``.inputrc``
8686
To ensure xonsh uses ``readline`` even if ``prompt-toolkit`` is installed, configure this in your
8787
``.xonshrc`` file:
8888

89-
.. code-block:: xonsh
89+
.. code-block:: xonshcon
9090
9191
$SHELL_TYPE = 'readline'
9292

news/xonfig-kernel.rst

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
**Added:**
2+
3+
* ``xonfig kernel`` new subcommand to generate xonsh kernel spec for jupyter.
4+
5+
**Changed:**
6+
7+
* ``xonfig info`` displays whether jupyter detected in environment and
8+
also path of xonsh jupyter kernel spec, if any.
9+
10+
**Deprecated:**
11+
12+
* <news item>
13+
14+
**Removed:**
15+
16+
* setup no longer (tries to) install jupyter kernel automatically,
17+
user must run ``xonfig kernel`` manually.
18+
19+
**Fixed:**
20+
21+
* Setup wasn't consistently detecting jupyter in environment; ``python setup.py install`` worked, but
22+
``pip install .`` wouldn't (because pip mucks with ``sys.path``),
23+
nor would install from wheel (because it doesn't run ``setup.py``).
24+
25+
**Security:**
26+
27+
* <news item>

setup.py

+1-68
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,13 @@
88
import json
99
import subprocess
1010

11-
try:
12-
from tempfile import TemporaryDirectory
13-
except ImportError:
14-
pass
15-
1611
from setuptools import setup, find_packages
1712
from setuptools.command.sdist import sdist
1813
from setuptools.command.install import install
1914
from setuptools.command.develop import develop
2015
from setuptools.command.build_py import build_py
2116
from setuptools.command.install_scripts import install_scripts
2217

23-
try:
24-
from jupyter_client.kernelspec import KernelSpecManager
25-
26-
HAVE_JUPYTER = True
27-
except ImportError:
28-
HAVE_JUPYTER = False
29-
30-
3118
TABLES = [
3219
"xonsh/lexer_table.py",
3320
"xonsh/parser_table.py",
@@ -86,50 +73,6 @@ def build_tables():
8673
sys.path.pop(0)
8774

8875

89-
def install_jupyter_hook(prefix=None, root=None):
90-
"""Make xonsh available as a Jupyter kernel."""
91-
if not HAVE_JUPYTER:
92-
print(
93-
"Could not install Jupyter kernel spec, please install " "Jupyter/IPython."
94-
)
95-
return
96-
spec = {
97-
"argv": [
98-
sys.executable,
99-
"-m",
100-
"xonsh.jupyter_kernel",
101-
"-f",
102-
"{connection_file}",
103-
],
104-
"display_name": "Xonsh",
105-
"language": "xonsh",
106-
"codemirror_mode": "shell",
107-
}
108-
with TemporaryDirectory() as d:
109-
os.chmod(d, 0o755) # Starts off as 700, not user readable
110-
if sys.platform == "win32":
111-
# Ensure that conda-build detects the hard coded prefix
112-
spec["argv"][0] = spec["argv"][0].replace(os.sep, os.altsep)
113-
with open(os.path.join(d, "kernel.json"), "w") as f:
114-
json.dump(spec, f, sort_keys=True)
115-
if "CONDA_BUILD" in os.environ:
116-
prefix = sys.prefix
117-
if sys.platform == "win32":
118-
prefix = prefix.replace(os.sep, os.altsep)
119-
user = "--user" in sys.argv
120-
print("Installing Jupyter kernel spec:")
121-
print(" root: {0!r}".format(root))
122-
print(" prefix: {0!r}".format(prefix))
123-
print(" as user: {0}".format(user))
124-
if root and prefix:
125-
# os.path.join isn't used since prefix is probably absolute
126-
prefix = root + prefix
127-
print(" combined prefix {0!r}".format(prefix))
128-
KernelSpecManager().install_kernel_spec(
129-
d, "xonsh", user=user, replace=True, prefix=prefix
130-
)
131-
132-
13376
def dirty_version():
13477
"""
13578
If install/sdist is run from a git directory (not a conda install), add
@@ -222,16 +165,6 @@ def run(self):
222165
amalgamate_source()
223166
# add dirty version number
224167
dirty = dirty_version()
225-
# install Jupyter hook
226-
root = self.root if self.root else None
227-
prefix = self.prefix if self.prefix else None
228-
try:
229-
install_jupyter_hook(prefix=prefix, root=root)
230-
except Exception:
231-
import traceback
232-
233-
traceback.print_exc()
234-
print("Installing Jupyter hook failed.")
235168

236169
super().run()
237170
if dirty:
@@ -412,7 +345,7 @@ def main():
412345
"linux": ["distro"],
413346
"proctitle": ["setproctitle"],
414347
"zipapp": ['importlib_resources; python_version < "3.7"'],
415-
"full" : ["ptk", "pygments", "distro"]
348+
"full": ["ptk", "pygments", "distro"],
416349
}
417350
skw["python_requires"] = ">=3.6"
418351
setup(**skw)

xonsh/xonfig.py

+83
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import contextlib
1616
import collections
1717

18+
from tempfile import TemporaryDirectory
19+
1820
from xonsh.ply import ply
1921

2022
import xonsh.wizard as wiz
@@ -141,6 +143,8 @@
141143
lambda: "source-foreign", bash="source-bash", cmd="source-cmd", zsh="source-zsh"
142144
)
143145

146+
XONSH_JUPYTER_KERNEL = "xonsh"
147+
144148

145149
def _dump_xonfig_foreign_shell(path, value):
146150
shell = value["shell"]
@@ -523,6 +527,21 @@ def _info(ns):
523527
("encoding errors", env.get("XONSH_ENCODING_ERRORS")),
524528
]
525529
)
530+
jup_ksm = jup_kernel = None
531+
try:
532+
from jupyter_client.kernelspec import KernelSpecManager
533+
534+
jup_ksm = KernelSpecManager()
535+
jup_kernel = jup_ksm.find_kernel_specs()[XONSH_JUPYTER_KERNEL]
536+
except (ImportError, KeyError):
537+
pass
538+
data.extend(
539+
[
540+
("on jupyter", jup_ksm is not None),
541+
("jupyter kernel", jup_kernel),
542+
]
543+
)
544+
526545
formatter = _xonfig_format_json if ns.json else _xonfig_format_human
527546
s = formatter(data)
528547
return s
@@ -623,6 +642,53 @@ def _web(args):
623642
subprocess.run([sys.executable, "-m", "xonsh.webconfig"] + args.orig_args[1:])
624643

625644

645+
def _kernel(args):
646+
"""Make xonsh available as a Jupyter kernel."""
647+
try:
648+
from jupyter_client.kernelspec import KernelSpecManager
649+
except ImportError:
650+
raise ImportError("Jupyter not found in current Python environment")
651+
652+
root = args.root
653+
prefix = args.prefix
654+
user = args.user
655+
spec = {
656+
"argv": [
657+
sys.executable,
658+
"-m",
659+
"xonsh.jupyter_kernel",
660+
"-f",
661+
"{connection_file}",
662+
],
663+
"display_name": "Xonsh",
664+
"language": "xonsh",
665+
"codemirror_mode": "shell",
666+
}
667+
with TemporaryDirectory() as d:
668+
os.chmod(d, 0o755) # Starts off as 700, not user readable
669+
if sys.platform == "win32":
670+
# Ensure that conda-build detects the hard coded prefix
671+
spec["argv"][0] = spec["argv"][0].replace(os.sep, os.altsep)
672+
with open(os.path.join(d, "kernel.json"), "w") as f:
673+
json.dump(spec, f, sort_keys=True)
674+
if "CONDA_BUILD" in os.environ or "VIRTUAL_ENV" in os.environ:
675+
prefix = sys.prefix
676+
if sys.platform == "win32":
677+
prefix = prefix.replace(os.sep, os.altsep)
678+
print("Installing Jupyter kernel spec:")
679+
print(" root: {0!r}".format(root))
680+
print(" prefix: {0!r}".format(prefix))
681+
print(" as user: {0}".format(user))
682+
if root and prefix:
683+
# os.path.join isn't used since prefix is probably absolute
684+
prefix = root + prefix
685+
print(" combined prefix {0!r}".format(prefix))
686+
KernelSpecManager().install_kernel_spec(
687+
d, XONSH_JUPYTER_KERNEL, user=user, prefix=prefix
688+
)
689+
return 0
690+
691+
626692
@functools.lru_cache(1)
627693
def _xonfig_create_parser():
628694
p = argparse.ArgumentParser(
@@ -662,6 +728,22 @@ def _xonfig_create_parser():
662728
"style", nargs="?", default=None, help="style to preview, default: <current>"
663729
)
664730
subp.add_parser("tutorial", help="Launch tutorial in browser.")
731+
kern = subp.add_parser("kernel", help="Generate xonsh kernel for jupyter.")
732+
kern.add_argument(
733+
"--user",
734+
action="store_true",
735+
default=False,
736+
help="Install kernel in user config.",
737+
)
738+
kern.add_argument(
739+
"--root",
740+
default=None,
741+
help="Install relative to this alternate root directory.",
742+
)
743+
kern.add_argument(
744+
"--prefix", default=None, help="Installation prefix for bin, lib, etc."
745+
)
746+
665747
return p
666748

667749

@@ -672,6 +754,7 @@ def _xonfig_create_parser():
672754
"styles": _styles,
673755
"colors": _colors,
674756
"tutorial": _tutorial,
757+
"kernel": _kernel,
675758
}
676759

677760

0 commit comments

Comments
 (0)