mirror of https://github.com/Textualize/rich.git
Merge pull request #368 from willmcgugan/safe-box-encoding
Safe box encoding
This commit is contained in:
commit
b0a68d3341
|
@ -8,14 +8,15 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||||
python-version: [3.6, 3.7, 3.8]
|
python-version: [3.6, 3.7, 3.8, 3.9]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: actions/setup-python@v1
|
uses: actions/setup-python@v2
|
||||||
with:
|
with:
|
||||||
python-version: ${{ matrix.python-version }}
|
python-version: ${{ matrix.python-version }}
|
||||||
|
architecture: x64
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: |
|
run: |
|
||||||
python -m pip install --upgrade pip
|
python -m pip install --upgrade pip
|
||||||
|
|
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -5,15 +5,22 @@ All notable changes to this project will be documented in this file.
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
## [8.1.0] - unreleased
|
## [9.0.0] - unreleased
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Progress download column now displays decimal units
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Added legacy_windows to ConsoleOptions
|
||||||
|
- Added ascii_only to ConsoleOptions
|
||||||
|
- Addded box.SQUARE_DOUBLE_HEAD
|
||||||
- Added highlighting of EUI-48 and EUI-64 (MAC addresses)
|
- Added highlighting of EUI-48 and EUI-64 (MAC addresses)
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Change the render prefix to correspond to the decimal units in progress
|
- Dropped box.get_safe_box function in favor of Box.substitute
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -146,7 +146,7 @@ You can also set overflow to "ignore" which allows text to run on to the next li
|
||||||
Soft Wrapping
|
Soft Wrapping
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
Rich word wraps text you print by inserting line breaks. You can disable this behavior by setting ``soft_wrap=True`` when calling :meth:`~rich.console.Console.print`. With *soft wrapping* enabled text any text that doesn't fit will run on to the following line(s), just like the builtin ``print``.
|
Rich word wraps text you print by inserting line breaks. You can disable this behavior by setting ``soft_wrap=True`` when calling :meth:`~rich.console.Console.print`. With *soft wrapping* enabled any text that doesn't fit will run on to the following line(s), just like the builtin ``print``.
|
||||||
|
|
||||||
|
|
||||||
Cropping
|
Cropping
|
||||||
|
|
|
@ -17,6 +17,7 @@ classifiers = [
|
||||||
"Programming Language :: Python :: 3.6",
|
"Programming Language :: Python :: 3.6",
|
||||||
"Programming Language :: Python :: 3.7",
|
"Programming Language :: Python :: 3.7",
|
||||||
"Programming Language :: Python :: 3.8",
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
]
|
]
|
||||||
include = ["rich/py.typed"]
|
include = ["rich/py.typed"]
|
||||||
|
|
||||||
|
|
26
rich/bar.py
26
rich/bar.py
|
@ -1,7 +1,7 @@
|
||||||
from functools import lru_cache
|
|
||||||
import math
|
import math
|
||||||
|
from functools import lru_cache
|
||||||
from time import monotonic
|
from time import monotonic
|
||||||
from typing import Iterable, Optional, List
|
from typing import Iterable, List, Optional
|
||||||
|
|
||||||
from .color import Color, blend_rgb
|
from .color import Color, blend_rgb
|
||||||
from .color_triplet import ColorTriplet
|
from .color_triplet import ColorTriplet
|
||||||
|
@ -11,7 +11,6 @@ from .measure import Measurement
|
||||||
from .segment import Segment
|
from .segment import Segment
|
||||||
from .style import Style, StyleType
|
from .style import Style, StyleType
|
||||||
|
|
||||||
|
|
||||||
# Number of characters before 'pulse' animation repeats
|
# Number of characters before 'pulse' animation repeats
|
||||||
PULSE_SIZE = 20
|
PULSE_SIZE = 20
|
||||||
|
|
||||||
|
@ -71,14 +70,14 @@ class Bar(JupyterMixin):
|
||||||
fore_style: Style,
|
fore_style: Style,
|
||||||
back_style: Style,
|
back_style: Style,
|
||||||
color_system: str,
|
color_system: str,
|
||||||
legacy_windows: bool,
|
ascii: bool = False,
|
||||||
) -> List[Segment]:
|
) -> List[Segment]:
|
||||||
"""Get a list of segments to render a pulse animation.
|
"""Get a list of segments to render a pulse animation.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Segment]: A list of segments, one segment per character.
|
List[Segment]: A list of segments, one segment per character.
|
||||||
"""
|
"""
|
||||||
bar = "─" if legacy_windows else "━"
|
bar = "-" if ascii else "━"
|
||||||
segments: List[Segment] = []
|
segments: List[Segment] = []
|
||||||
|
|
||||||
if color_system != "truecolor":
|
if color_system != "truecolor":
|
||||||
|
@ -122,7 +121,9 @@ class Bar(JupyterMixin):
|
||||||
self.completed = completed
|
self.completed = completed
|
||||||
self.total = total if total is not None else self.total
|
self.total = total if total is not None else self.total
|
||||||
|
|
||||||
def _render_pulse(self, console: Console, width: int) -> Iterable[Segment]:
|
def _render_pulse(
|
||||||
|
self, console: Console, width: int, ascii: bool = False
|
||||||
|
) -> Iterable[Segment]:
|
||||||
"""Renders the pulse animation.
|
"""Renders the pulse animation.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -139,7 +140,7 @@ class Bar(JupyterMixin):
|
||||||
back_style = console.get_style(self.style, default="black")
|
back_style = console.get_style(self.style, default="black")
|
||||||
|
|
||||||
pulse_segments = self._get_pulse_segments(
|
pulse_segments = self._get_pulse_segments(
|
||||||
fore_style, back_style, console.color_system, console.legacy_windows
|
fore_style, back_style, console.color_system, ascii=ascii
|
||||||
)
|
)
|
||||||
segment_count = len(pulse_segments)
|
segment_count = len(pulse_segments)
|
||||||
current_time = (
|
current_time = (
|
||||||
|
@ -155,15 +156,16 @@ class Bar(JupyterMixin):
|
||||||
) -> RenderResult:
|
) -> RenderResult:
|
||||||
|
|
||||||
width = min(self.width or options.max_width, options.max_width)
|
width = min(self.width or options.max_width, options.max_width)
|
||||||
|
ascii = options.legacy_windows or options.ascii_only
|
||||||
if self.pulse:
|
if self.pulse:
|
||||||
yield from self._render_pulse(console, width)
|
yield from self._render_pulse(console, width, ascii=ascii)
|
||||||
return
|
return
|
||||||
|
|
||||||
completed = min(self.total, max(0, self.completed))
|
completed = min(self.total, max(0, self.completed))
|
||||||
legacy_windows = console.legacy_windows
|
|
||||||
bar = "─" if legacy_windows else "━"
|
bar = "-" if ascii else "━"
|
||||||
half_bar_right = " " if legacy_windows else "╸"
|
half_bar_right = " " if ascii else "╸"
|
||||||
half_bar_left = " " if legacy_windows else "╺"
|
half_bar_left = " " if ascii else "╺"
|
||||||
complete_halves = (
|
complete_halves = (
|
||||||
int(width * 2 * completed / self.total) if self.total else width * 2
|
int(width * 2 * completed / self.total) if self.total else width * 2
|
||||||
)
|
)
|
||||||
|
|
82
rich/box.py
82
rich/box.py
|
@ -1,8 +1,12 @@
|
||||||
from typing import Iterable, List, Optional, overload
|
from typing import TYPE_CHECKING, Iterable, List
|
||||||
|
|
||||||
from typing_extensions import Literal
|
from typing_extensions import Literal
|
||||||
|
|
||||||
from ._loop import loop_last
|
from ._loop import loop_last
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from rich.console import ConsoleOptions
|
||||||
|
|
||||||
|
|
||||||
class Box:
|
class Box:
|
||||||
"""Defines characters to render boxes.
|
"""Defines characters to render boxes.
|
||||||
|
@ -16,11 +20,14 @@ class Box:
|
||||||
│ ││ foot
|
│ ││ foot
|
||||||
└─┴┘ bottom
|
└─┴┘ bottom
|
||||||
|
|
||||||
|
Args:
|
||||||
|
box (str): Characters making up box.
|
||||||
|
ascii (bool, optional): True if this box uses ascii characters only. Default is False.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, box: str) -> None:
|
def __init__(self, box: str, *, ascii: bool = False) -> None:
|
||||||
self._box = box
|
self._box = box
|
||||||
|
self.ascii = ascii
|
||||||
line1, line2, line3, line4, line5, line6, line7, line8 = box.splitlines()
|
line1, line2, line3, line4, line5, line6, line7, line8 = box.splitlines()
|
||||||
# top
|
# top
|
||||||
self.top_left, self.top, self.top_divider, self.top_right = iter(line1)
|
self.top_left, self.top, self.top_divider, self.top_right = iter(line1)
|
||||||
|
@ -58,6 +65,24 @@ class Box:
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
return self._box
|
return self._box
|
||||||
|
|
||||||
|
def substitute(self, options: "ConsoleOptions", safe: bool = True) -> "Box":
|
||||||
|
"""Substitute this box for another if it won't render due to platform issues.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
options (ConsoleOptions): Console options used in rendering.
|
||||||
|
safe (bool, optional): Substitute this for another Box if there are known problems
|
||||||
|
displaying on the platform (currently only relevant on Windows). Default is True.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Box: A different Box or the same Box.
|
||||||
|
"""
|
||||||
|
box = self
|
||||||
|
if options.legacy_windows and safe:
|
||||||
|
box = LEGACY_WINDOWS_SUBSTITUTIONS.get(box, box)
|
||||||
|
if options.ascii_only:
|
||||||
|
box = ASCII
|
||||||
|
return box
|
||||||
|
|
||||||
def get_top(self, widths: Iterable[int]) -> str:
|
def get_top(self, widths: Iterable[int]) -> str:
|
||||||
"""Get the top of a simple box.
|
"""Get the top of a simple box.
|
||||||
|
|
||||||
|
@ -158,7 +183,8 @@ ASCII: Box = Box(
|
||||||
|-+|
|
|-+|
|
||||||
| ||
|
| ||
|
||||||
+--+
|
+--+
|
||||||
"""
|
""",
|
||||||
|
ascii=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
ASCII2: Box = Box(
|
ASCII2: Box = Box(
|
||||||
|
@ -171,7 +197,8 @@ ASCII2: Box = Box(
|
||||||
+-++
|
+-++
|
||||||
| ||
|
| ||
|
||||||
+-++
|
+-++
|
||||||
"""
|
""",
|
||||||
|
ascii=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
ASCII_DOUBLE_HEAD: Box = Box(
|
ASCII_DOUBLE_HEAD: Box = Box(
|
||||||
|
@ -184,7 +211,8 @@ ASCII_DOUBLE_HEAD: Box = Box(
|
||||||
+-++
|
+-++
|
||||||
| ||
|
| ||
|
||||||
+-++
|
+-++
|
||||||
"""
|
""",
|
||||||
|
ascii=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
SQUARE: Box = Box(
|
SQUARE: Box = Box(
|
||||||
|
@ -200,6 +228,18 @@ SQUARE: Box = Box(
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SQUARE_DOUBLE_HEAD: Box = Box(
|
||||||
|
"""\
|
||||||
|
┌─┬┐
|
||||||
|
│ ││
|
||||||
|
╞═╪╡
|
||||||
|
│ ││
|
||||||
|
├─┼┤
|
||||||
|
├─┼┤
|
||||||
|
│ ││
|
||||||
|
└─┴┘
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
MINIMAL: Box = Box(
|
MINIMAL: Box = Box(
|
||||||
"""\
|
"""\
|
||||||
|
@ -385,40 +425,15 @@ LEGACY_WINDOWS_SUBSTITUTIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@overload
|
|
||||||
def get_safe_box(box: None, legacy_windows: bool) -> None:
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
@overload
|
|
||||||
def get_safe_box(box: Box, legacy_windows: bool) -> Box:
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
def get_safe_box(box: Optional[Box], legacy_windows: bool) -> Optional[Box]:
|
|
||||||
"""Substitute Box constants that don't render on windows legacy.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
box (Optional[Box]): A Box instance.
|
|
||||||
legacy_windows (bool): Enable legacy Windows.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Optional[Box]: A Box instance (potentially a new instance).
|
|
||||||
"""
|
|
||||||
if legacy_windows and box is not None:
|
|
||||||
return LEGACY_WINDOWS_SUBSTITUTIONS.get(box, box)
|
|
||||||
else:
|
|
||||||
return box
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__": # pragma: no cover
|
if __name__ == "__main__": # pragma: no cover
|
||||||
|
|
||||||
from rich.columns import Columns
|
from rich.columns import Columns
|
||||||
from rich.panel import Panel
|
from rich.panel import Panel
|
||||||
|
|
||||||
|
from . import box
|
||||||
from .console import Console
|
from .console import Console
|
||||||
from .table import Table
|
from .table import Table
|
||||||
from .text import Text
|
from .text import Text
|
||||||
from . import box
|
|
||||||
|
|
||||||
console = Console(record=True)
|
console = Console(record=True)
|
||||||
|
|
||||||
|
@ -427,6 +442,7 @@ if __name__ == "__main__": # pragma: no cover
|
||||||
"ASCII2",
|
"ASCII2",
|
||||||
"ASCII_DOUBLE_HEAD",
|
"ASCII_DOUBLE_HEAD",
|
||||||
"SQUARE",
|
"SQUARE",
|
||||||
|
"SQUARE_DOUBLE_HEAD",
|
||||||
"MINIMAL",
|
"MINIMAL",
|
||||||
"MINIMAL_HEAVY_HEAD",
|
"MINIMAL_HEAVY_HEAD",
|
||||||
"MINIMAL_DOUBLE_HEAD",
|
"MINIMAL_DOUBLE_HEAD",
|
||||||
|
|
|
@ -81,6 +81,8 @@ _TERM_COLORS = {"256color": ColorSystem.EIGHT_BIT, "16color": ColorSystem.STANDA
|
||||||
class ConsoleOptions:
|
class ConsoleOptions:
|
||||||
"""Options for __rich_console__ method."""
|
"""Options for __rich_console__ method."""
|
||||||
|
|
||||||
|
legacy_windows: bool
|
||||||
|
"""legacy_windows: flag for legacy windows."""
|
||||||
min_width: int
|
min_width: int
|
||||||
"""Minimum width of renderable."""
|
"""Minimum width of renderable."""
|
||||||
max_width: int
|
max_width: int
|
||||||
|
@ -96,6 +98,11 @@ class ConsoleOptions:
|
||||||
no_wrap: Optional[bool] = False
|
no_wrap: Optional[bool] = False
|
||||||
""""Disable wrapping for text."""
|
""""Disable wrapping for text."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ascii_only(self) -> bool:
|
||||||
|
"""Check if renderables should use ascii only."""
|
||||||
|
return not self.encoding.startswith("utf")
|
||||||
|
|
||||||
def update(
|
def update(
|
||||||
self,
|
self,
|
||||||
width: int = None,
|
width: int = None,
|
||||||
|
@ -341,7 +348,7 @@ class Console:
|
||||||
force_terminal (Optional[bool], optional): Enable/disable terminal control codes, or None to auto-detect terminal. Defaults to None.
|
force_terminal (Optional[bool], optional): Enable/disable terminal control codes, or None to auto-detect terminal. Defaults to None.
|
||||||
force_jupyter (Optional[bool], optional): Enable/disable Jupyter rendering, or None to auto-detect Jupyter. Defaults to None.
|
force_jupyter (Optional[bool], optional): Enable/disable Jupyter rendering, or None to auto-detect Jupyter. Defaults to None.
|
||||||
theme (Theme, optional): An optional style theme object, or ``None`` for default theme.
|
theme (Theme, optional): An optional style theme object, or ``None`` for default theme.
|
||||||
file (IO, optional): A file object where the console should write to. Defaults to stdoutput.
|
file (IO, optional): A file object where the console should write to. Defaults to stdout.
|
||||||
width (int, optional): The width of the terminal. Leave as default to auto-detect width.
|
width (int, optional): The width of the terminal. Leave as default to auto-detect width.
|
||||||
height (int, optional): The height of the terminal. Leave as default to auto-detect height.
|
height (int, optional): The height of the terminal. Leave as default to auto-detect height.
|
||||||
record (bool, optional): Boolean to enable recording of terminal output,
|
record (bool, optional): Boolean to enable recording of terminal output,
|
||||||
|
@ -568,7 +575,7 @@ class Console:
|
||||||
Returns:
|
Returns:
|
||||||
str: A standard encoding string.
|
str: A standard encoding string.
|
||||||
"""
|
"""
|
||||||
return getattr(self.file, "encoding", "utf-8")
|
return (getattr(self.file, "encoding", "utf-8") or "utf-8").lower()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_terminal(self) -> bool:
|
def is_terminal(self) -> bool:
|
||||||
|
@ -599,6 +606,7 @@ class Console:
|
||||||
def options(self) -> ConsoleOptions:
|
def options(self) -> ConsoleOptions:
|
||||||
"""Get default console options."""
|
"""Get default console options."""
|
||||||
return ConsoleOptions(
|
return ConsoleOptions(
|
||||||
|
legacy_windows=self.legacy_windows,
|
||||||
min_width=1,
|
min_width=1,
|
||||||
max_width=self.width,
|
max_width=self.width,
|
||||||
encoding=self.encoding,
|
encoding=self.encoding,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from typing import Optional, TYPE_CHECKING
|
from typing import Optional, TYPE_CHECKING
|
||||||
|
|
||||||
from .box import get_safe_box, Box, SQUARE, ROUNDED
|
from .box import Box, ROUNDED
|
||||||
|
|
||||||
from .align import AlignValues
|
from .align import AlignValues
|
||||||
from .jupyter import JupyterMixin
|
from .jupyter import JupyterMixin
|
||||||
|
@ -113,7 +113,7 @@ class Panel(JupyterMixin):
|
||||||
width = options.max_width if self.width is None else self.width
|
width = options.max_width if self.width is None else self.width
|
||||||
|
|
||||||
safe_box: bool = console.safe_box if self.safe_box is None else self.safe_box # type: ignore
|
safe_box: bool = console.safe_box if self.safe_box is None else self.safe_box # type: ignore
|
||||||
box = get_safe_box(self.box, console.legacy_windows) if safe_box else self.box
|
box = self.box.substitute(options, safe=safe_box)
|
||||||
|
|
||||||
title_text = self._title
|
title_text = self._title
|
||||||
if title_text is not None:
|
if title_text is not None:
|
||||||
|
|
|
@ -299,9 +299,7 @@ class DownloadColumn(ProgressColumn):
|
||||||
completed = int(task.completed)
|
completed = int(task.completed)
|
||||||
total = int(task.total)
|
total = int(task.total)
|
||||||
unit, suffix = filesize.pick_unit_and_suffix(
|
unit, suffix = filesize.pick_unit_and_suffix(
|
||||||
total,
|
total, ["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], 1000
|
||||||
["bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],
|
|
||||||
1000,
|
|
||||||
)
|
)
|
||||||
completed_ratio = completed / unit
|
completed_ratio = completed / unit
|
||||||
total_ratio = total / unit
|
total_ratio = total / unit
|
||||||
|
|
|
@ -3,6 +3,7 @@ from typing import TYPE_CHECKING, Iterable, List, NamedTuple, Optional, Tuple, U
|
||||||
|
|
||||||
from . import box, errors
|
from . import box, errors
|
||||||
from ._loop import loop_first_last, loop_last
|
from ._loop import loop_first_last, loop_last
|
||||||
|
from ._pick import pick_bool
|
||||||
from ._ratio import ratio_distribute, ratio_reduce
|
from ._ratio import ratio_distribute, ratio_reduce
|
||||||
from .jupyter import JupyterMixin
|
from .jupyter import JupyterMixin
|
||||||
from .measure import Measurement
|
from .measure import Measurement
|
||||||
|
@ -609,9 +610,12 @@ class Table(JupyterMixin):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
safe_box: bool = console.safe_box if self.safe_box is None else self.safe_box # type: ignore
|
|
||||||
_box = (
|
_box = (
|
||||||
box.get_safe_box(self.box, console.legacy_windows) if safe_box else self.box
|
self.box.substitute(
|
||||||
|
options, safe=pick_bool(self.safe_box, console.safe_box)
|
||||||
|
)
|
||||||
|
if self.box
|
||||||
|
else None
|
||||||
)
|
)
|
||||||
|
|
||||||
# _box = self.box
|
# _box = self.box
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from rich.box import get_safe_box, ASCII, DOUBLE, ROUNDED, HEAVY, SQUARE
|
from rich.console import ConsoleOptions
|
||||||
|
from rich.box import ASCII, DOUBLE, ROUNDED, HEAVY, SQUARE
|
||||||
|
|
||||||
|
|
||||||
def test_str():
|
def test_str():
|
||||||
|
@ -35,8 +36,18 @@ def test_get_bottom():
|
||||||
assert bottom == "┗━┻━━┻━━━┛"
|
assert bottom == "┗━┻━━┻━━━┛"
|
||||||
|
|
||||||
|
|
||||||
def test_get_safe_box():
|
def test_box_substitute():
|
||||||
assert get_safe_box(HEAVY, True) == SQUARE
|
options = ConsoleOptions(
|
||||||
assert get_safe_box(HEAVY, False) == HEAVY
|
legacy_windows=True,
|
||||||
assert get_safe_box(None, True) is None
|
min_width=1,
|
||||||
assert get_safe_box(None, False) is None
|
max_width=100,
|
||||||
|
is_terminal=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
assert HEAVY.substitute(options) == SQUARE
|
||||||
|
|
||||||
|
options.legacy_windows = False
|
||||||
|
assert HEAVY.substitute(options) == HEAVY
|
||||||
|
|
||||||
|
options.encoding = "ascii"
|
||||||
|
assert HEAVY.substitute(options) == ASCII
|
||||||
|
|
|
@ -43,7 +43,11 @@ def test_truecolor_terminal():
|
||||||
|
|
||||||
def test_console_options_update():
|
def test_console_options_update():
|
||||||
options = ConsoleOptions(
|
options = ConsoleOptions(
|
||||||
min_width=10, max_width=20, is_terminal=False, encoding="utf-8"
|
legacy_windows=False,
|
||||||
|
min_width=10,
|
||||||
|
max_width=20,
|
||||||
|
is_terminal=False,
|
||||||
|
encoding="utf-8",
|
||||||
)
|
)
|
||||||
options1 = options.update(width=15)
|
options1 = options.update(width=15)
|
||||||
assert options1.min_width == 15 and options1.max_width == 15
|
assert options1.min_width == 15 and options1.max_width == 15
|
||||||
|
|
|
@ -103,12 +103,8 @@ def test_inspect_empty_dict():
|
||||||
"│ in the keyword argument list. For │\n"
|
"│ in the keyword argument list. For │\n"
|
||||||
"│ example: dict(one=1, two=2) │\n"
|
"│ example: dict(one=1, two=2) │\n"
|
||||||
"│ │\n"
|
"│ │\n"
|
||||||
"│ 30 attribute(s) not shown. Use │\n"
|
|
||||||
"│ inspect(<OBJECT>, all=True) to see all │\n"
|
|
||||||
"│ attributes. │\n"
|
|
||||||
"╰────────────────────────────────────────────────╯\n"
|
|
||||||
)
|
)
|
||||||
assert expected == render({})
|
assert render({}).startswith(expected)
|
||||||
|
|
||||||
|
|
||||||
def test_inspect_builtin_function():
|
def test_inspect_builtin_function():
|
||||||
|
|
Loading…
Reference in New Issue