15
15
import contextlib
16
16
import collections
17
17
18
+ from tempfile import TemporaryDirectory
19
+
18
20
from xonsh .ply import ply
19
21
20
22
import xonsh .wizard as wiz
141
143
lambda : "source-foreign" , bash = "source-bash" , cmd = "source-cmd" , zsh = "source-zsh"
142
144
)
143
145
146
+ XONSH_JUPYTER_KERNEL = "xonsh"
147
+
144
148
145
149
def _dump_xonfig_foreign_shell (path , value ):
146
150
shell = value ["shell" ]
@@ -523,6 +527,21 @@ def _info(ns):
523
527
("encoding errors" , env .get ("XONSH_ENCODING_ERRORS" )),
524
528
]
525
529
)
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
+
526
545
formatter = _xonfig_format_json if ns .json else _xonfig_format_human
527
546
s = formatter (data )
528
547
return s
@@ -623,6 +642,53 @@ def _web(args):
623
642
subprocess .run ([sys .executable , "-m" , "xonsh.webconfig" ] + args .orig_args [1 :])
624
643
625
644
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
+
626
692
@functools .lru_cache (1 )
627
693
def _xonfig_create_parser ():
628
694
p = argparse .ArgumentParser (
@@ -662,6 +728,22 @@ def _xonfig_create_parser():
662
728
"style" , nargs = "?" , default = None , help = "style to preview, default: <current>"
663
729
)
664
730
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
+
665
747
return p
666
748
667
749
@@ -672,6 +754,7 @@ def _xonfig_create_parser():
672
754
"styles" : _styles ,
673
755
"colors" : _colors ,
674
756
"tutorial" : _tutorial ,
757
+ "kernel" : _kernel ,
675
758
}
676
759
677
760
0 commit comments