Загрузить файлы в «venv/Lib/site-packages/pip/_vendor/rich»
This commit is contained in:
88
venv/Lib/site-packages/pip/_vendor/rich/filesize.py
Normal file
88
venv/Lib/site-packages/pip/_vendor/rich/filesize.py
Normal file
@@ -0,0 +1,88 @@
|
||||
"""Functions for reporting filesizes. Borrowed from https://github.com/PyFilesystem/pyfilesystem2
|
||||
|
||||
The functions declared in this module should cover the different
|
||||
use cases needed to generate a string representation of a file size
|
||||
using several different units. Since there are many standards regarding
|
||||
file size units, three different functions have been implemented.
|
||||
|
||||
See Also:
|
||||
* `Wikipedia: Binary prefix <https://en.wikipedia.org/wiki/Binary_prefix>`_
|
||||
|
||||
"""
|
||||
|
||||
__all__ = ["decimal"]
|
||||
|
||||
from typing import Iterable, List, Optional, Tuple
|
||||
|
||||
|
||||
def _to_str(
|
||||
size: int,
|
||||
suffixes: Iterable[str],
|
||||
base: int,
|
||||
*,
|
||||
precision: Optional[int] = 1,
|
||||
separator: Optional[str] = " ",
|
||||
) -> str:
|
||||
if size == 1:
|
||||
return "1 byte"
|
||||
elif size < base:
|
||||
return f"{size:,} bytes"
|
||||
|
||||
for i, suffix in enumerate(suffixes, 2): # noqa: B007
|
||||
unit = base**i
|
||||
if size < unit:
|
||||
break
|
||||
return "{:,.{precision}f}{separator}{}".format(
|
||||
(base * size / unit),
|
||||
suffix,
|
||||
precision=precision,
|
||||
separator=separator,
|
||||
)
|
||||
|
||||
|
||||
def pick_unit_and_suffix(size: int, suffixes: List[str], base: int) -> Tuple[int, str]:
|
||||
"""Pick a suffix and base for the given size."""
|
||||
for i, suffix in enumerate(suffixes):
|
||||
unit = base**i
|
||||
if size < unit * base:
|
||||
break
|
||||
return unit, suffix
|
||||
|
||||
|
||||
def decimal(
|
||||
size: int,
|
||||
*,
|
||||
precision: Optional[int] = 1,
|
||||
separator: Optional[str] = " ",
|
||||
) -> str:
|
||||
"""Convert a filesize in to a string (powers of 1000, SI prefixes).
|
||||
|
||||
In this convention, ``1000 B = 1 kB``.
|
||||
|
||||
This is typically the format used to advertise the storage
|
||||
capacity of USB flash drives and the like (*256 MB* meaning
|
||||
actually a storage capacity of more than *256 000 000 B*),
|
||||
or used by **Mac OS X** since v10.6 to report file sizes.
|
||||
|
||||
Arguments:
|
||||
int (size): A file size.
|
||||
int (precision): The number of decimal places to include (default = 1).
|
||||
str (separator): The string to separate the value from the units (default = " ").
|
||||
|
||||
Returns:
|
||||
`str`: A string containing a abbreviated file size and units.
|
||||
|
||||
Example:
|
||||
>>> filesize.decimal(30000)
|
||||
'30.0 kB'
|
||||
>>> filesize.decimal(30000, precision=2, separator="")
|
||||
'30.00kB'
|
||||
|
||||
"""
|
||||
return _to_str(
|
||||
size,
|
||||
("kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"),
|
||||
1000,
|
||||
precision=precision,
|
||||
separator=separator,
|
||||
)
|
||||
232
venv/Lib/site-packages/pip/_vendor/rich/highlighter.py
Normal file
232
venv/Lib/site-packages/pip/_vendor/rich/highlighter.py
Normal file
@@ -0,0 +1,232 @@
|
||||
import re
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import List, Union
|
||||
|
||||
from .text import Span, Text
|
||||
|
||||
|
||||
def _combine_regex(*regexes: str) -> str:
|
||||
"""Combine a number of regexes in to a single regex.
|
||||
|
||||
Returns:
|
||||
str: New regex with all regexes ORed together.
|
||||
"""
|
||||
return "|".join(regexes)
|
||||
|
||||
|
||||
class Highlighter(ABC):
|
||||
"""Abstract base class for highlighters."""
|
||||
|
||||
def __call__(self, text: Union[str, Text]) -> Text:
|
||||
"""Highlight a str or Text instance.
|
||||
|
||||
Args:
|
||||
text (Union[str, ~Text]): Text to highlight.
|
||||
|
||||
Raises:
|
||||
TypeError: If not called with text or str.
|
||||
|
||||
Returns:
|
||||
Text: A test instance with highlighting applied.
|
||||
"""
|
||||
if isinstance(text, str):
|
||||
highlight_text = Text(text)
|
||||
elif isinstance(text, Text):
|
||||
highlight_text = text.copy()
|
||||
else:
|
||||
raise TypeError(f"str or Text instance required, not {text!r}")
|
||||
self.highlight(highlight_text)
|
||||
return highlight_text
|
||||
|
||||
@abstractmethod
|
||||
def highlight(self, text: Text) -> None:
|
||||
"""Apply highlighting in place to text.
|
||||
|
||||
Args:
|
||||
text (~Text): A text object highlight.
|
||||
"""
|
||||
|
||||
|
||||
class NullHighlighter(Highlighter):
|
||||
"""A highlighter object that doesn't highlight.
|
||||
|
||||
May be used to disable highlighting entirely.
|
||||
|
||||
"""
|
||||
|
||||
def highlight(self, text: Text) -> None:
|
||||
"""Nothing to do"""
|
||||
|
||||
|
||||
class RegexHighlighter(Highlighter):
|
||||
"""Applies highlighting from a list of regular expressions."""
|
||||
|
||||
highlights: List[str] = []
|
||||
base_style: str = ""
|
||||
|
||||
def highlight(self, text: Text) -> None:
|
||||
"""Highlight :class:`rich.text.Text` using regular expressions.
|
||||
|
||||
Args:
|
||||
text (~Text): Text to highlighted.
|
||||
|
||||
"""
|
||||
|
||||
highlight_regex = text.highlight_regex
|
||||
for re_highlight in self.highlights:
|
||||
highlight_regex(re_highlight, style_prefix=self.base_style)
|
||||
|
||||
|
||||
class ReprHighlighter(RegexHighlighter):
|
||||
"""Highlights the text typically produced from ``__repr__`` methods."""
|
||||
|
||||
base_style = "repr."
|
||||
highlights = [
|
||||
r"(?P<tag_start><)(?P<tag_name>[-\w.:|]*)(?P<tag_contents>[\w\W]*)(?P<tag_end>>)",
|
||||
r'(?P<attrib_name>[\w_]{1,50})=(?P<attrib_value>"?[\w_]+"?)?',
|
||||
r"(?P<brace>[][{}()])",
|
||||
_combine_regex(
|
||||
r"(?P<ipv4>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})",
|
||||
r"(?P<ipv6>([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})",
|
||||
r"(?P<eui64>(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})",
|
||||
r"(?P<eui48>(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})",
|
||||
r"(?P<uuid>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})",
|
||||
r"(?P<call>[\w.]*?)\(",
|
||||
r"\b(?P<bool_true>True)\b|\b(?P<bool_false>False)\b|\b(?P<none>None)\b",
|
||||
r"(?P<ellipsis>\.\.\.)",
|
||||
r"(?P<number_complex>(?<!\w)(?:\-?[0-9]+\.?[0-9]*(?:e[-+]?\d+?)?)(?:[-+](?:[0-9]+\.?[0-9]*(?:e[-+]?\d+)?))?j)",
|
||||
r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[-+]?\d+?)?\b|0x[0-9a-fA-F]*)",
|
||||
r"(?P<path>\B(/[-\w._+]+)*\/)(?P<filename>[-\w._+]*)?",
|
||||
r"(?<![\\\w])(?P<str>b?'''.*?(?<!\\)'''|b?'.*?(?<!\\)'|b?\"\"\".*?(?<!\\)\"\"\"|b?\".*?(?<!\\)\")",
|
||||
r"(?P<url>(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#~@]*)",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class JSONHighlighter(RegexHighlighter):
|
||||
"""Highlights JSON"""
|
||||
|
||||
# Captures the start and end of JSON strings, handling escaped quotes
|
||||
JSON_STR = r"(?<![\\\w])(?P<str>b?\".*?(?<!\\)\")"
|
||||
JSON_WHITESPACE = {" ", "\n", "\r", "\t"}
|
||||
|
||||
base_style = "json."
|
||||
highlights = [
|
||||
_combine_regex(
|
||||
r"(?P<brace>[\{\[\(\)\]\}])",
|
||||
r"\b(?P<bool_true>true)\b|\b(?P<bool_false>false)\b|\b(?P<null>null)\b",
|
||||
r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[\-\+]?\d+?)?\b|0x[0-9a-fA-F]*)",
|
||||
JSON_STR,
|
||||
),
|
||||
]
|
||||
|
||||
def highlight(self, text: Text) -> None:
|
||||
super().highlight(text)
|
||||
|
||||
# Additional work to handle highlighting JSON keys
|
||||
plain = text.plain
|
||||
append = text.spans.append
|
||||
whitespace = self.JSON_WHITESPACE
|
||||
for match in re.finditer(self.JSON_STR, plain):
|
||||
start, end = match.span()
|
||||
cursor = end
|
||||
while cursor < len(plain):
|
||||
char = plain[cursor]
|
||||
cursor += 1
|
||||
if char == ":":
|
||||
append(Span(start, end, "json.key"))
|
||||
elif char in whitespace:
|
||||
continue
|
||||
break
|
||||
|
||||
|
||||
class ISO8601Highlighter(RegexHighlighter):
|
||||
"""Highlights the ISO8601 date time strings.
|
||||
Regex reference: https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html
|
||||
"""
|
||||
|
||||
base_style = "iso8601."
|
||||
highlights = [
|
||||
#
|
||||
# Dates
|
||||
#
|
||||
# Calendar month (e.g. 2008-08). The hyphen is required
|
||||
r"^(?P<year>[0-9]{4})-(?P<month>1[0-2]|0[1-9])$",
|
||||
# Calendar date w/o hyphens (e.g. 20080830)
|
||||
r"^(?P<date>(?P<year>[0-9]{4})(?P<month>1[0-2]|0[1-9])(?P<day>3[01]|0[1-9]|[12][0-9]))$",
|
||||
# Ordinal date (e.g. 2008-243). The hyphen is optional
|
||||
r"^(?P<date>(?P<year>[0-9]{4})-?(?P<day>36[0-6]|3[0-5][0-9]|[12][0-9]{2}|0[1-9][0-9]|00[1-9]))$",
|
||||
#
|
||||
# Weeks
|
||||
#
|
||||
# Week of the year (e.g., 2008-W35). The hyphen is optional
|
||||
r"^(?P<date>(?P<year>[0-9]{4})-?W(?P<week>5[0-3]|[1-4][0-9]|0[1-9]))$",
|
||||
# Week date (e.g., 2008-W35-6). The hyphens are optional
|
||||
r"^(?P<date>(?P<year>[0-9]{4})-?W(?P<week>5[0-3]|[1-4][0-9]|0[1-9])-?(?P<day>[1-7]))$",
|
||||
#
|
||||
# Times
|
||||
#
|
||||
# Hours and minutes (e.g., 17:21). The colon is optional
|
||||
r"^(?P<time>(?P<hour>2[0-3]|[01][0-9]):?(?P<minute>[0-5][0-9]))$",
|
||||
# Hours, minutes, and seconds w/o colons (e.g., 172159)
|
||||
r"^(?P<time>(?P<hour>2[0-3]|[01][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9]))$",
|
||||
# Time zone designator (e.g., Z, +07 or +07:00). The colons and the minutes are optional
|
||||
r"^(?P<timezone>(Z|[+-](?:2[0-3]|[01][0-9])(?::?(?:[0-5][0-9]))?))$",
|
||||
# Hours, minutes, and seconds with time zone designator (e.g., 17:21:59+07:00).
|
||||
# All the colons are optional. The minutes in the time zone designator are also optional
|
||||
r"^(?P<time>(?P<hour>2[0-3]|[01][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9]))(?P<timezone>Z|[+-](?:2[0-3]|[01][0-9])(?::?(?:[0-5][0-9]))?)$",
|
||||
#
|
||||
# Date and Time
|
||||
#
|
||||
# Calendar date with hours, minutes, and seconds (e.g., 2008-08-30 17:21:59 or 20080830 172159).
|
||||
# A space is required between the date and the time. The hyphens and colons are optional.
|
||||
# This regex matches dates and times that specify some hyphens or colons but omit others.
|
||||
# This does not follow ISO 8601
|
||||
r"^(?P<date>(?P<year>[0-9]{4})(?P<hyphen>-)?(?P<month>1[0-2]|0[1-9])(?(hyphen)-)(?P<day>3[01]|0[1-9]|[12][0-9])) (?P<time>(?P<hour>2[0-3]|[01][0-9])(?(hyphen):)(?P<minute>[0-5][0-9])(?(hyphen):)(?P<second>[0-5][0-9]))$",
|
||||
#
|
||||
# XML Schema dates and times
|
||||
#
|
||||
# Date, with optional time zone (e.g., 2008-08-30 or 2008-08-30+07:00).
|
||||
# Hyphens are required. This is the XML Schema 'date' type
|
||||
r"^(?P<date>(?P<year>-?(?:[1-9][0-9]*)?[0-9]{4})-(?P<month>1[0-2]|0[1-9])-(?P<day>3[01]|0[1-9]|[12][0-9]))(?P<timezone>Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$",
|
||||
# Time, with optional fractional seconds and time zone (e.g., 01:45:36 or 01:45:36.123+07:00).
|
||||
# There is no limit on the number of digits for the fractional seconds. This is the XML Schema 'time' type
|
||||
r"^(?P<time>(?P<hour>2[0-3]|[01][0-9]):(?P<minute>[0-5][0-9]):(?P<second>[0-5][0-9])(?P<frac>\.[0-9]+)?)(?P<timezone>Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$",
|
||||
# Date and time, with optional fractional seconds and time zone (e.g., 2008-08-30T01:45:36 or 2008-08-30T01:45:36.123Z).
|
||||
# This is the XML Schema 'dateTime' type
|
||||
r"^(?P<date>(?P<year>-?(?:[1-9][0-9]*)?[0-9]{4})-(?P<month>1[0-2]|0[1-9])-(?P<day>3[01]|0[1-9]|[12][0-9]))T(?P<time>(?P<hour>2[0-3]|[01][0-9]):(?P<minute>[0-5][0-9]):(?P<second>[0-5][0-9])(?P<ms>\.[0-9]+)?)(?P<timezone>Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$",
|
||||
]
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
from .console import Console
|
||||
|
||||
console = Console()
|
||||
console.print("[bold green]hello world![/bold green]")
|
||||
console.print("'[bold green]hello world![/bold green]'")
|
||||
|
||||
console.print(" /foo")
|
||||
console.print("/foo/")
|
||||
console.print("/foo/bar")
|
||||
console.print("foo/bar/baz")
|
||||
|
||||
console.print("/foo/bar/baz?foo=bar+egg&egg=baz")
|
||||
console.print("/foo/bar/baz/")
|
||||
console.print("/foo/bar/baz/egg")
|
||||
console.print("/foo/bar/baz/egg.py")
|
||||
console.print("/foo/bar/baz/egg.py word")
|
||||
console.print(" /foo/bar/baz/egg.py word")
|
||||
console.print("foo /foo/bar/baz/egg.py word")
|
||||
console.print("foo /foo/bar/ba._++z/egg+.py word")
|
||||
console.print("https://example.org?foo=bar#header")
|
||||
|
||||
console.print(1234567.34)
|
||||
console.print(1 / 2)
|
||||
console.print(-1 / 123123123123)
|
||||
|
||||
console.print(
|
||||
"127.0.1.1 bar 192.168.1.4 2001:0db8:85a3:0000:0000:8a2e:0370:7334 foo"
|
||||
)
|
||||
import json
|
||||
|
||||
console.print_json(json.dumps(obj={"name": "apple", "count": 1}), indent=None)
|
||||
139
venv/Lib/site-packages/pip/_vendor/rich/json.py
Normal file
139
venv/Lib/site-packages/pip/_vendor/rich/json.py
Normal file
@@ -0,0 +1,139 @@
|
||||
from pathlib import Path
|
||||
from json import loads, dumps
|
||||
from typing import Any, Callable, Optional, Union
|
||||
|
||||
from .text import Text
|
||||
from .highlighter import JSONHighlighter, NullHighlighter
|
||||
|
||||
|
||||
class JSON:
|
||||
"""A renderable which pretty prints JSON.
|
||||
|
||||
Args:
|
||||
json (str): JSON encoded data.
|
||||
indent (Union[None, int, str], optional): Number of characters to indent by. Defaults to 2.
|
||||
highlight (bool, optional): Enable highlighting. Defaults to True.
|
||||
skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False.
|
||||
ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False.
|
||||
check_circular (bool, optional): Check for circular references. Defaults to True.
|
||||
allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True.
|
||||
default (Callable, optional): A callable that converts values that can not be encoded
|
||||
in to something that can be JSON encoded. Defaults to None.
|
||||
sort_keys (bool, optional): Sort dictionary keys. Defaults to False.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
json: str,
|
||||
indent: Union[None, int, str] = 2,
|
||||
highlight: bool = True,
|
||||
skip_keys: bool = False,
|
||||
ensure_ascii: bool = False,
|
||||
check_circular: bool = True,
|
||||
allow_nan: bool = True,
|
||||
default: Optional[Callable[[Any], Any]] = None,
|
||||
sort_keys: bool = False,
|
||||
) -> None:
|
||||
data = loads(json)
|
||||
json = dumps(
|
||||
data,
|
||||
indent=indent,
|
||||
skipkeys=skip_keys,
|
||||
ensure_ascii=ensure_ascii,
|
||||
check_circular=check_circular,
|
||||
allow_nan=allow_nan,
|
||||
default=default,
|
||||
sort_keys=sort_keys,
|
||||
)
|
||||
highlighter = JSONHighlighter() if highlight else NullHighlighter()
|
||||
self.text = highlighter(json)
|
||||
self.text.no_wrap = True
|
||||
self.text.overflow = None
|
||||
|
||||
@classmethod
|
||||
def from_data(
|
||||
cls,
|
||||
data: Any,
|
||||
indent: Union[None, int, str] = 2,
|
||||
highlight: bool = True,
|
||||
skip_keys: bool = False,
|
||||
ensure_ascii: bool = False,
|
||||
check_circular: bool = True,
|
||||
allow_nan: bool = True,
|
||||
default: Optional[Callable[[Any], Any]] = None,
|
||||
sort_keys: bool = False,
|
||||
) -> "JSON":
|
||||
"""Encodes a JSON object from arbitrary data.
|
||||
|
||||
Args:
|
||||
data (Any): An object that may be encoded in to JSON
|
||||
indent (Union[None, int, str], optional): Number of characters to indent by. Defaults to 2.
|
||||
highlight (bool, optional): Enable highlighting. Defaults to True.
|
||||
default (Callable, optional): Optional callable which will be called for objects that cannot be serialized. Defaults to None.
|
||||
skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False.
|
||||
ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False.
|
||||
check_circular (bool, optional): Check for circular references. Defaults to True.
|
||||
allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True.
|
||||
default (Callable, optional): A callable that converts values that can not be encoded
|
||||
in to something that can be JSON encoded. Defaults to None.
|
||||
sort_keys (bool, optional): Sort dictionary keys. Defaults to False.
|
||||
|
||||
Returns:
|
||||
JSON: New JSON object from the given data.
|
||||
"""
|
||||
json_instance: "JSON" = cls.__new__(cls)
|
||||
json = dumps(
|
||||
data,
|
||||
indent=indent,
|
||||
skipkeys=skip_keys,
|
||||
ensure_ascii=ensure_ascii,
|
||||
check_circular=check_circular,
|
||||
allow_nan=allow_nan,
|
||||
default=default,
|
||||
sort_keys=sort_keys,
|
||||
)
|
||||
highlighter = JSONHighlighter() if highlight else NullHighlighter()
|
||||
json_instance.text = highlighter(json)
|
||||
json_instance.text.no_wrap = True
|
||||
json_instance.text.overflow = None
|
||||
return json_instance
|
||||
|
||||
def __rich__(self) -> Text:
|
||||
return self.text
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
parser = argparse.ArgumentParser(description="Pretty print json")
|
||||
parser.add_argument(
|
||||
"path",
|
||||
metavar="PATH",
|
||||
help="path to file, or - for stdin",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-i",
|
||||
"--indent",
|
||||
metavar="SPACES",
|
||||
type=int,
|
||||
help="Number of spaces in an indent",
|
||||
default=2,
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
from pip._vendor.rich.console import Console
|
||||
|
||||
console = Console()
|
||||
error_console = Console(stderr=True)
|
||||
|
||||
try:
|
||||
if args.path == "-":
|
||||
json_data = sys.stdin.read()
|
||||
else:
|
||||
json_data = Path(args.path).read_text()
|
||||
except Exception as error:
|
||||
error_console.print(f"Unable to read {args.path!r}; {error}")
|
||||
sys.exit(-1)
|
||||
|
||||
console.print(JSON(json_data, indent=args.indent), soft_wrap=True)
|
||||
101
venv/Lib/site-packages/pip/_vendor/rich/jupyter.py
Normal file
101
venv/Lib/site-packages/pip/_vendor/rich/jupyter.py
Normal file
@@ -0,0 +1,101 @@
|
||||
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)
|
||||
442
venv/Lib/site-packages/pip/_vendor/rich/layout.py
Normal file
442
venv/Lib/site-packages/pip/_vendor/rich/layout.py
Normal file
@@ -0,0 +1,442 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from itertools import islice
|
||||
from operator import itemgetter
|
||||
from threading import RLock
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Dict,
|
||||
Iterable,
|
||||
List,
|
||||
NamedTuple,
|
||||
Optional,
|
||||
Sequence,
|
||||
Tuple,
|
||||
Union,
|
||||
)
|
||||
|
||||
from ._ratio import ratio_resolve
|
||||
from .align import Align
|
||||
from .console import Console, ConsoleOptions, RenderableType, RenderResult
|
||||
from .highlighter import ReprHighlighter
|
||||
from .panel import Panel
|
||||
from .pretty import Pretty
|
||||
from .region import Region
|
||||
from .repr import Result, rich_repr
|
||||
from .segment import Segment
|
||||
from .style import StyleType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pip._vendor.rich.tree import Tree
|
||||
|
||||
|
||||
class LayoutRender(NamedTuple):
|
||||
"""An individual layout render."""
|
||||
|
||||
region: Region
|
||||
render: List[List[Segment]]
|
||||
|
||||
|
||||
RegionMap = Dict["Layout", Region]
|
||||
RenderMap = Dict["Layout", LayoutRender]
|
||||
|
||||
|
||||
class LayoutError(Exception):
|
||||
"""Layout related error."""
|
||||
|
||||
|
||||
class NoSplitter(LayoutError):
|
||||
"""Requested splitter does not exist."""
|
||||
|
||||
|
||||
class _Placeholder:
|
||||
"""An internal renderable used as a Layout placeholder."""
|
||||
|
||||
highlighter = ReprHighlighter()
|
||||
|
||||
def __init__(self, layout: "Layout", style: StyleType = "") -> None:
|
||||
self.layout = layout
|
||||
self.style = style
|
||||
|
||||
def __rich_console__(
|
||||
self, console: Console, options: ConsoleOptions
|
||||
) -> RenderResult:
|
||||
width = options.max_width
|
||||
height = options.height or options.size.height
|
||||
layout = self.layout
|
||||
title = (
|
||||
f"{layout.name!r} ({width} x {height})"
|
||||
if layout.name
|
||||
else f"({width} x {height})"
|
||||
)
|
||||
yield Panel(
|
||||
Align.center(Pretty(layout), vertical="middle"),
|
||||
style=self.style,
|
||||
title=self.highlighter(title),
|
||||
border_style="blue",
|
||||
height=height,
|
||||
)
|
||||
|
||||
|
||||
class Splitter(ABC):
|
||||
"""Base class for a splitter."""
|
||||
|
||||
name: str = ""
|
||||
|
||||
@abstractmethod
|
||||
def get_tree_icon(self) -> str:
|
||||
"""Get the icon (emoji) used in layout.tree"""
|
||||
|
||||
@abstractmethod
|
||||
def divide(
|
||||
self, children: Sequence["Layout"], region: Region
|
||||
) -> Iterable[Tuple["Layout", Region]]:
|
||||
"""Divide a region amongst several child layouts.
|
||||
|
||||
Args:
|
||||
children (Sequence(Layout)): A number of child layouts.
|
||||
region (Region): A rectangular region to divide.
|
||||
"""
|
||||
|
||||
|
||||
class RowSplitter(Splitter):
|
||||
"""Split a layout region in to rows."""
|
||||
|
||||
name = "row"
|
||||
|
||||
def get_tree_icon(self) -> str:
|
||||
return "[layout.tree.row]⬌"
|
||||
|
||||
def divide(
|
||||
self, children: Sequence["Layout"], region: Region
|
||||
) -> Iterable[Tuple["Layout", Region]]:
|
||||
x, y, width, height = region
|
||||
render_widths = ratio_resolve(width, children)
|
||||
offset = 0
|
||||
_Region = Region
|
||||
for child, child_width in zip(children, render_widths):
|
||||
yield child, _Region(x + offset, y, child_width, height)
|
||||
offset += child_width
|
||||
|
||||
|
||||
class ColumnSplitter(Splitter):
|
||||
"""Split a layout region in to columns."""
|
||||
|
||||
name = "column"
|
||||
|
||||
def get_tree_icon(self) -> str:
|
||||
return "[layout.tree.column]⬍"
|
||||
|
||||
def divide(
|
||||
self, children: Sequence["Layout"], region: Region
|
||||
) -> Iterable[Tuple["Layout", Region]]:
|
||||
x, y, width, height = region
|
||||
render_heights = ratio_resolve(height, children)
|
||||
offset = 0
|
||||
_Region = Region
|
||||
for child, child_height in zip(children, render_heights):
|
||||
yield child, _Region(x, y + offset, width, child_height)
|
||||
offset += child_height
|
||||
|
||||
|
||||
@rich_repr
|
||||
class Layout:
|
||||
"""A renderable to divide a fixed height in to rows or columns.
|
||||
|
||||
Args:
|
||||
renderable (RenderableType, optional): Renderable content, or None for placeholder. Defaults to None.
|
||||
name (str, optional): Optional identifier for Layout. Defaults to None.
|
||||
size (int, optional): Optional fixed size of layout. Defaults to None.
|
||||
minimum_size (int, optional): Minimum size of layout. Defaults to 1.
|
||||
ratio (int, optional): Optional ratio for flexible layout. Defaults to 1.
|
||||
visible (bool, optional): Visibility of layout. Defaults to True.
|
||||
"""
|
||||
|
||||
splitters = {"row": RowSplitter, "column": ColumnSplitter}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
renderable: Optional[RenderableType] = None,
|
||||
*,
|
||||
name: Optional[str] = None,
|
||||
size: Optional[int] = None,
|
||||
minimum_size: int = 1,
|
||||
ratio: int = 1,
|
||||
visible: bool = True,
|
||||
) -> None:
|
||||
self._renderable = renderable or _Placeholder(self)
|
||||
self.size = size
|
||||
self.minimum_size = minimum_size
|
||||
self.ratio = ratio
|
||||
self.name = name
|
||||
self.visible = visible
|
||||
self.splitter: Splitter = self.splitters["column"]()
|
||||
self._children: List[Layout] = []
|
||||
self._render_map: RenderMap = {}
|
||||
self._lock = RLock()
|
||||
|
||||
def __rich_repr__(self) -> Result:
|
||||
yield "name", self.name, None
|
||||
yield "size", self.size, None
|
||||
yield "minimum_size", self.minimum_size, 1
|
||||
yield "ratio", self.ratio, 1
|
||||
|
||||
@property
|
||||
def renderable(self) -> RenderableType:
|
||||
"""Layout renderable."""
|
||||
return self if self._children else self._renderable
|
||||
|
||||
@property
|
||||
def children(self) -> List["Layout"]:
|
||||
"""Gets (visible) layout children."""
|
||||
return [child for child in self._children if child.visible]
|
||||
|
||||
@property
|
||||
def map(self) -> RenderMap:
|
||||
"""Get a map of the last render."""
|
||||
return self._render_map
|
||||
|
||||
def get(self, name: str) -> Optional["Layout"]:
|
||||
"""Get a named layout, or None if it doesn't exist.
|
||||
|
||||
Args:
|
||||
name (str): Name of layout.
|
||||
|
||||
Returns:
|
||||
Optional[Layout]: Layout instance or None if no layout was found.
|
||||
"""
|
||||
if self.name == name:
|
||||
return self
|
||||
else:
|
||||
for child in self._children:
|
||||
named_layout = child.get(name)
|
||||
if named_layout is not None:
|
||||
return named_layout
|
||||
return None
|
||||
|
||||
def __getitem__(self, name: str) -> "Layout":
|
||||
layout = self.get(name)
|
||||
if layout is None:
|
||||
raise KeyError(f"No layout with name {name!r}")
|
||||
return layout
|
||||
|
||||
@property
|
||||
def tree(self) -> "Tree":
|
||||
"""Get a tree renderable to show layout structure."""
|
||||
from pip._vendor.rich.styled import Styled
|
||||
from pip._vendor.rich.table import Table
|
||||
from pip._vendor.rich.tree import Tree
|
||||
|
||||
def summary(layout: "Layout") -> Table:
|
||||
icon = layout.splitter.get_tree_icon()
|
||||
|
||||
table = Table.grid(padding=(0, 1, 0, 0))
|
||||
|
||||
text: RenderableType = (
|
||||
Pretty(layout) if layout.visible else Styled(Pretty(layout), "dim")
|
||||
)
|
||||
table.add_row(icon, text)
|
||||
_summary = table
|
||||
return _summary
|
||||
|
||||
layout = self
|
||||
tree = Tree(
|
||||
summary(layout),
|
||||
guide_style=f"layout.tree.{layout.splitter.name}",
|
||||
highlight=True,
|
||||
)
|
||||
|
||||
def recurse(tree: "Tree", layout: "Layout") -> None:
|
||||
for child in layout._children:
|
||||
recurse(
|
||||
tree.add(
|
||||
summary(child),
|
||||
guide_style=f"layout.tree.{child.splitter.name}",
|
||||
),
|
||||
child,
|
||||
)
|
||||
|
||||
recurse(tree, self)
|
||||
return tree
|
||||
|
||||
def split(
|
||||
self,
|
||||
*layouts: Union["Layout", RenderableType],
|
||||
splitter: Union[Splitter, str] = "column",
|
||||
) -> None:
|
||||
"""Split the layout in to multiple sub-layouts.
|
||||
|
||||
Args:
|
||||
*layouts (Layout): Positional arguments should be (sub) Layout instances.
|
||||
splitter (Union[Splitter, str]): Splitter instance or name of splitter.
|
||||
"""
|
||||
_layouts = [
|
||||
layout if isinstance(layout, Layout) else Layout(layout)
|
||||
for layout in layouts
|
||||
]
|
||||
try:
|
||||
self.splitter = (
|
||||
splitter
|
||||
if isinstance(splitter, Splitter)
|
||||
else self.splitters[splitter]()
|
||||
)
|
||||
except KeyError:
|
||||
raise NoSplitter(f"No splitter called {splitter!r}")
|
||||
self._children[:] = _layouts
|
||||
|
||||
def add_split(self, *layouts: Union["Layout", RenderableType]) -> None:
|
||||
"""Add a new layout(s) to existing split.
|
||||
|
||||
Args:
|
||||
*layouts (Union[Layout, RenderableType]): Positional arguments should be renderables or (sub) Layout instances.
|
||||
|
||||
"""
|
||||
_layouts = (
|
||||
layout if isinstance(layout, Layout) else Layout(layout)
|
||||
for layout in layouts
|
||||
)
|
||||
self._children.extend(_layouts)
|
||||
|
||||
def split_row(self, *layouts: Union["Layout", RenderableType]) -> None:
|
||||
"""Split the layout in to a row (layouts side by side).
|
||||
|
||||
Args:
|
||||
*layouts (Layout): Positional arguments should be (sub) Layout instances.
|
||||
"""
|
||||
self.split(*layouts, splitter="row")
|
||||
|
||||
def split_column(self, *layouts: Union["Layout", RenderableType]) -> None:
|
||||
"""Split the layout in to a column (layouts stacked on top of each other).
|
||||
|
||||
Args:
|
||||
*layouts (Layout): Positional arguments should be (sub) Layout instances.
|
||||
"""
|
||||
self.split(*layouts, splitter="column")
|
||||
|
||||
def unsplit(self) -> None:
|
||||
"""Reset splits to initial state."""
|
||||
del self._children[:]
|
||||
|
||||
def update(self, renderable: RenderableType) -> None:
|
||||
"""Update renderable.
|
||||
|
||||
Args:
|
||||
renderable (RenderableType): New renderable object.
|
||||
"""
|
||||
with self._lock:
|
||||
self._renderable = renderable
|
||||
|
||||
def refresh_screen(self, console: "Console", layout_name: str) -> None:
|
||||
"""Refresh a sub-layout.
|
||||
|
||||
Args:
|
||||
console (Console): Console instance where Layout is to be rendered.
|
||||
layout_name (str): Name of layout.
|
||||
"""
|
||||
with self._lock:
|
||||
layout = self[layout_name]
|
||||
region, _lines = self._render_map[layout]
|
||||
(x, y, width, height) = region
|
||||
lines = console.render_lines(
|
||||
layout, console.options.update_dimensions(width, height)
|
||||
)
|
||||
self._render_map[layout] = LayoutRender(region, lines)
|
||||
console.update_screen_lines(lines, x, y)
|
||||
|
||||
def _make_region_map(self, width: int, height: int) -> RegionMap:
|
||||
"""Create a dict that maps layout on to Region."""
|
||||
stack: List[Tuple[Layout, Region]] = [(self, Region(0, 0, width, height))]
|
||||
push = stack.append
|
||||
pop = stack.pop
|
||||
layout_regions: List[Tuple[Layout, Region]] = []
|
||||
append_layout_region = layout_regions.append
|
||||
while stack:
|
||||
append_layout_region(pop())
|
||||
layout, region = layout_regions[-1]
|
||||
children = layout.children
|
||||
if children:
|
||||
for child_and_region in layout.splitter.divide(children, region):
|
||||
push(child_and_region)
|
||||
|
||||
region_map = {
|
||||
layout: region
|
||||
for layout, region in sorted(layout_regions, key=itemgetter(1))
|
||||
}
|
||||
return region_map
|
||||
|
||||
def render(self, console: Console, options: ConsoleOptions) -> RenderMap:
|
||||
"""Render the sub_layouts.
|
||||
|
||||
Args:
|
||||
console (Console): Console instance.
|
||||
options (ConsoleOptions): Console options.
|
||||
|
||||
Returns:
|
||||
RenderMap: A dict that maps Layout on to a tuple of Region, lines
|
||||
"""
|
||||
render_width = options.max_width
|
||||
render_height = options.height or console.height
|
||||
region_map = self._make_region_map(render_width, render_height)
|
||||
layout_regions = [
|
||||
(layout, region)
|
||||
for layout, region in region_map.items()
|
||||
if not layout.children
|
||||
]
|
||||
render_map: Dict["Layout", "LayoutRender"] = {}
|
||||
render_lines = console.render_lines
|
||||
update_dimensions = options.update_dimensions
|
||||
|
||||
for layout, region in layout_regions:
|
||||
lines = render_lines(
|
||||
layout.renderable, update_dimensions(region.width, region.height)
|
||||
)
|
||||
render_map[layout] = LayoutRender(region, lines)
|
||||
return render_map
|
||||
|
||||
def __rich_console__(
|
||||
self, console: Console, options: ConsoleOptions
|
||||
) -> RenderResult:
|
||||
with self._lock:
|
||||
width = options.max_width or console.width
|
||||
height = options.height or console.height
|
||||
render_map = self.render(console, options.update_dimensions(width, height))
|
||||
self._render_map = render_map
|
||||
layout_lines: List[List[Segment]] = [[] for _ in range(height)]
|
||||
_islice = islice
|
||||
for region, lines in render_map.values():
|
||||
_x, y, _layout_width, layout_height = region
|
||||
for row, line in zip(
|
||||
_islice(layout_lines, y, y + layout_height), lines
|
||||
):
|
||||
row.extend(line)
|
||||
|
||||
new_line = Segment.line()
|
||||
for layout_row in layout_lines:
|
||||
yield from layout_row
|
||||
yield new_line
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from pip._vendor.rich.console import Console
|
||||
|
||||
console = Console()
|
||||
layout = Layout()
|
||||
|
||||
layout.split_column(
|
||||
Layout(name="header", size=3),
|
||||
Layout(ratio=1, name="main"),
|
||||
Layout(size=10, name="footer"),
|
||||
)
|
||||
|
||||
layout["main"].split_row(Layout(name="side"), Layout(name="body", ratio=2))
|
||||
|
||||
layout["body"].split_row(Layout(name="content", ratio=2), Layout(name="s2"))
|
||||
|
||||
layout["s2"].split_column(
|
||||
Layout(name="top"), Layout(name="middle"), Layout(name="bottom")
|
||||
)
|
||||
|
||||
layout["side"].split_column(Layout(layout.tree, name="left1"), Layout(name="left2"))
|
||||
|
||||
layout["content"].update("foo")
|
||||
|
||||
console.print(layout)
|
||||
Reference in New Issue
Block a user