Tipragot
628be439b8
Cela permet de ne pas avoir de problèmes de compatibilité car python est dans le git.
102 lines
3.2 KiB
Python
102 lines
3.2 KiB
Python
from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Sequence
|
|
|
|
if TYPE_CHECKING:
|
|
from pip._vendor.rich.console import ConsoleRenderable
|
|
|
|
from . import get_console
|
|
from .segment import Segment
|
|
from .terminal_theme import DEFAULT_TERMINAL_THEME
|
|
|
|
if TYPE_CHECKING:
|
|
from pip._vendor.rich.console import ConsoleRenderable
|
|
|
|
JUPYTER_HTML_FORMAT = """\
|
|
<pre style="white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace">{code}</pre>
|
|
"""
|
|
|
|
|
|
class JupyterRenderable:
|
|
"""A shim to write html to Jupyter notebook."""
|
|
|
|
def __init__(self, html: str, text: str) -> None:
|
|
self.html = html
|
|
self.text = text
|
|
|
|
def _repr_mimebundle_(
|
|
self, include: Sequence[str], exclude: Sequence[str], **kwargs: Any
|
|
) -> Dict[str, str]:
|
|
data = {"text/plain": self.text, "text/html": self.html}
|
|
if include:
|
|
data = {k: v for (k, v) in data.items() if k in include}
|
|
if exclude:
|
|
data = {k: v for (k, v) in data.items() if k not in exclude}
|
|
return data
|
|
|
|
|
|
class JupyterMixin:
|
|
"""Add to an Rich renderable to make it render in Jupyter notebook."""
|
|
|
|
__slots__ = ()
|
|
|
|
def _repr_mimebundle_(
|
|
self: "ConsoleRenderable",
|
|
include: Sequence[str],
|
|
exclude: Sequence[str],
|
|
**kwargs: Any,
|
|
) -> Dict[str, str]:
|
|
console = get_console()
|
|
segments = list(console.render(self, console.options))
|
|
html = _render_segments(segments)
|
|
text = console._render_buffer(segments)
|
|
data = {"text/plain": text, "text/html": html}
|
|
if include:
|
|
data = {k: v for (k, v) in data.items() if k in include}
|
|
if exclude:
|
|
data = {k: v for (k, v) in data.items() if k not in exclude}
|
|
return data
|
|
|
|
|
|
def _render_segments(segments: Iterable[Segment]) -> str:
|
|
def escape(text: str) -> str:
|
|
"""Escape html."""
|
|
return text.replace("&", "&").replace("<", "<").replace(">", ">")
|
|
|
|
fragments: List[str] = []
|
|
append_fragment = fragments.append
|
|
theme = DEFAULT_TERMINAL_THEME
|
|
for text, style, control in Segment.simplify(segments):
|
|
if control:
|
|
continue
|
|
text = escape(text)
|
|
if style:
|
|
rule = style.get_html_style(theme)
|
|
text = f'<span style="{rule}">{text}</span>' if rule else text
|
|
if style.link:
|
|
text = f'<a href="{style.link}" target="_blank">{text}</a>'
|
|
append_fragment(text)
|
|
|
|
code = "".join(fragments)
|
|
html = JUPYTER_HTML_FORMAT.format(code=code)
|
|
|
|
return html
|
|
|
|
|
|
def display(segments: Iterable[Segment], text: str) -> None:
|
|
"""Render segments to Jupyter."""
|
|
html = _render_segments(segments)
|
|
jupyter_renderable = JupyterRenderable(html, text)
|
|
try:
|
|
from IPython.display import display as ipython_display
|
|
|
|
ipython_display(jupyter_renderable)
|
|
except ModuleNotFoundError:
|
|
# Handle the case where the Console has force_jupyter=True,
|
|
# but IPython is not installed.
|
|
pass
|
|
|
|
|
|
def print(*args: Any, **kwargs: Any) -> None:
|
|
"""Proxy for Console print."""
|
|
console = get_console()
|
|
return console.print(*args, **kwargs)
|