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 129 130 131 132 133 134 135
|
import os
import re
import sys
import configparser
import html2text
import subprocess
from metakernel.process_metakernel import ProcessMetaKernel
from metakernel.replwrap import REPLWrapper
from IPython.display import HTML
from .symbols import completion_symbols
from .mode_magic import ModeMagic
from ._version import __version__
class HTMLWithTextFallback(HTML):
"Provide text fallback for html output outside of web browsers."
def __repr__(self):
return html2text.html2text(self._repr_html_())
class M2Kernel(ProcessMetaKernel):
implementation = "macaulay2_jupyter_kernel"
implementation_version = __version__
@property
def banner(self):
return (
f"Jupyter Kernel for Macaulay2 (v{__version__})\n" +
f"Running Macaulay2 v{self.version}")
@property
def language_info(self):
return {
"name": "Macaulay2",
"mimetype": "text/x-macaulay2",
"file_extension": ".m2",
"version": self.version
}
kernel_json = {
"argv": [
sys.executable,
"-m", "m2_kernel",
"-f", "{connection_file}"],
"display_name": "Macaulay2",
"name": "M2",
}
def __init__(self, *args, **kwargs):
ProcessMetaKernel.__init__(self, *args, **kwargs)
self.execpath = "M2"
self.mode = "webapp"
init_file = f"{os.path.dirname(__file__)}/assets/m2-code/JupyterKernel.m2"
self.init_cmd = f'load \"{init_file}\"'
config = configparser.ConfigParser()
configpath = os.getenv("M2JK_CONFIG")
if configpath:
config.read(configpath)
if "magic" in config:
if "execpath" in config["magic"]:
self.execpath = config["magic"]["execpath"]
if "mode" in config["magic"]:
mode = config["magic"]["mode"]
if mode in ModeMagic.modes:
self.mode = mode
self.init_cmd += f"; changeJupyterMode {ModeMagic.modes[mode]}"
else:
raise ValueError(f"expected one of {list(ModeMagic.modes.keys())}")
self.version = subprocess.check_output(
[self.execpath, "--version"], text=True).strip()
self.register_magics(ModeMagic)
def makeWrapper(self):
return REPLWrapper(
f"{self.execpath} --no-readline -e '{self.init_cmd}'",
r"i+\d+ :\s*$",
None,
continuation_prompt_regex=r"\.\.\. : $")
webapp_regex = re.compile(
r"""
\x0e([^\x12]*)\x12([^\x11]*)\x11([^\x12]*)\x12 # with prompt
| \x11([^\x12]*)\x12 # without prompt
""",
re.DOTALL | re.VERBOSE
)
texmacs_regex = re.compile(r"\x02html:([^\x05]*)\x05", re.DOTALL)
def do_execute_direct(self, code, silent=False):
# run parent do_execute_direct silently so we can modify the output
output = super().do_execute_direct(code, True)
if self.mode == "webapp":
output = repr(output)
html = []
pos = 0
for m in self.webapp_regex.finditer(output):
pre = output[pos:m.start()].strip()
if pre:
html.append(f"<pre>{pre}</pre>\n")
p = re.sub(r"[\x0e\x11\x12]", "", m.group(0))
html.append(f"<p>{p}</p>\n")
pos = m.end()
pre = output[pos:].strip()
if pre:
html.append(f"<pre>{pre}</pre>\n")
return HTMLWithTextFallback("".join(html))
elif self.mode == "texmacs":
output = repr(output)
html = []
pos = 0
for m in self.texmacs_regex.finditer(output):
pre = output[pos:m.start()].strip()
if pre:
html.append(f"<pre>{pre}</pre>\n")
p = re.sub(r"\x02html:|\x05", "", m.group(0))
html.append(f"<p>{p}</p>\n")
pos = m.end()
pre = output[pos:].strip()
if pre:
html.append(f"<pre>{pre}</pre>\n")
return HTMLWithTextFallback("".join(html))
else:
self.Write(repr(output))
def get_completions(self, info):
return [s for s in completion_symbols if s.startswith(info["obj"])]
|