Aluode/PerceptionLabPortable
0
1from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Sequence2 3if TYPE_CHECKING:4 from pip._vendor.rich.console import ConsoleRenderable5 6from . import get_console7from .segment import Segment8from .terminal_theme import DEFAULT_TERMINAL_THEME9 10if TYPE_CHECKING:11 from pip._vendor.rich.console import ConsoleRenderable12 13JUPYTER_HTML_FORMAT = """\14<pre style="white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace">{code}</pre>15"""16 17 18class JupyterRenderable:19 """A shim to write html to Jupyter notebook."""20 21 def __init__(self, html: str, text: str) -> None:22 self.html = html23 self.text = text24 25 def _repr_mimebundle_(26 self, include: Sequence[str], exclude: Sequence[str], **kwargs: Any27 ) -> Dict[str, str]:28 data = {"text/plain": self.text, "text/html": self.html}29 if include:30 data = {k: v for (k, v) in data.items() if k in include}31 if exclude:32 data = {k: v for (k, v) in data.items() if k not in exclude}33 return data34 35 36class JupyterMixin:37 """Add to an Rich renderable to make it render in Jupyter notebook."""38 39 __slots__ = ()40 41 def _repr_mimebundle_(42 self: "ConsoleRenderable",43 include: Sequence[str],44 exclude: Sequence[str],45 **kwargs: Any,46 ) -> Dict[str, str]:47 console = get_console()48 segments = list(console.render(self, console.options))49 html = _render_segments(segments)50 text = console._render_buffer(segments)51 data = {"text/plain": text, "text/html": html}52 if include:53 data = {k: v for (k, v) in data.items() if k in include}54 if exclude:55 data = {k: v for (k, v) in data.items() if k not in exclude}56 return data57 58 59def _render_segments(segments: Iterable[Segment]) -> str:60 def escape(text: str) -> str:61 """Escape html."""62 return text.replace("&", "&").replace("<", "<").replace(">", ">")63 64 fragments: List[str] = []65 append_fragment = fragments.append66 theme = DEFAULT_TERMINAL_THEME67 for text, style, control in Segment.simplify(segments):68 if control:69 continue70 text = escape(text)71 if style:72 rule = style.get_html_style(theme)73 text = f'<span style="{rule}">{text}</span>' if rule else text74 if style.link:75 text = f'<a href="{style.link}" target="_blank">{text}</a>'76 append_fragment(text)77 78 code = "".join(fragments)79 html = JUPYTER_HTML_FORMAT.format(code=code)80 81 return html82 83 84def display(segments: Iterable[Segment], text: str) -> None:85 """Render segments to Jupyter."""86 html = _render_segments(segments)87 jupyter_renderable = JupyterRenderable(html, text)88 try:89 from IPython.display import display as ipython_display90 91 ipython_display(jupyter_renderable)92 except ModuleNotFoundError:93 # Handle the case where the Console has force_jupyter=True,94 # but IPython is not installed.95 pass96 97 98def print(*args: Any, **kwargs: Any) -> None:99 """Proxy for Console print."""100 console = get_console()101 return console.print(*args, **kwargs)102 