python (3.12.0)

(root)/
lib/
python3.12/
site-packages/
pip/
_vendor/
rich/
console.py
       1  import inspect
       2  import os
       3  import platform
       4  import sys
       5  import threading
       6  import zlib
       7  from abc import ABC, abstractmethod
       8  from dataclasses import dataclass, field
       9  from datetime import datetime
      10  from functools import wraps
      11  from getpass import getpass
      12  from html import escape
      13  from inspect import isclass
      14  from itertools import islice
      15  from math import ceil
      16  from time import monotonic
      17  from types import FrameType, ModuleType, TracebackType
      18  from typing import (
      19      IO,
      20      TYPE_CHECKING,
      21      Any,
      22      Callable,
      23      Dict,
      24      Iterable,
      25      List,
      26      Mapping,
      27      NamedTuple,
      28      Optional,
      29      TextIO,
      30      Tuple,
      31      Type,
      32      Union,
      33      cast,
      34  )
      35  
      36  from pip._vendor.rich._null_file import NULL_FILE
      37  
      38  if sys.version_info >= (3, 8):
      39      from typing import Literal, Protocol, runtime_checkable
      40  else:
      41      from pip._vendor.typing_extensions import (
      42          Literal,
      43          Protocol,
      44          runtime_checkable,
      45      )  # pragma: no cover
      46  
      47  from . import errors, themes
      48  from ._emoji_replace import _emoji_replace
      49  from ._export_format import CONSOLE_HTML_FORMAT, CONSOLE_SVG_FORMAT
      50  from ._fileno import get_fileno
      51  from ._log_render import FormatTimeCallable, LogRender
      52  from .align import Align, AlignMethod
      53  from .color import ColorSystem, blend_rgb
      54  from .control import Control
      55  from .emoji import EmojiVariant
      56  from .highlighter import NullHighlighter, ReprHighlighter
      57  from .markup import render as render_markup
      58  from .measure import Measurement, measure_renderables
      59  from .pager import Pager, SystemPager
      60  from .pretty import Pretty, is_expandable
      61  from .protocol import rich_cast
      62  from .region import Region
      63  from .scope import render_scope
      64  from .screen import Screen
      65  from .segment import Segment
      66  from .style import Style, StyleType
      67  from .styled import Styled
      68  from .terminal_theme import DEFAULT_TERMINAL_THEME, SVG_EXPORT_THEME, TerminalTheme
      69  from .text import Text, TextType
      70  from .theme import Theme, ThemeStack
      71  
      72  if TYPE_CHECKING:
      73      from ._windows import WindowsConsoleFeatures
      74      from .live import Live
      75      from .status import Status
      76  
      77  JUPYTER_DEFAULT_COLUMNS = 115
      78  JUPYTER_DEFAULT_LINES = 100
      79  WINDOWS = platform.system() == "Windows"
      80  
      81  HighlighterType = Callable[[Union[str, "Text"]], "Text"]
      82  JustifyMethod = Literal["default", "left", "center", "right", "full"]
      83  OverflowMethod = Literal["fold", "crop", "ellipsis", "ignore"]
      84  
      85  
      86  class ESC[4;38;5;81mNoChange:
      87      pass
      88  
      89  
      90  NO_CHANGE = NoChange()
      91  
      92  try:
      93      _STDIN_FILENO = sys.__stdin__.fileno()
      94  except Exception:
      95      _STDIN_FILENO = 0
      96  try:
      97      _STDOUT_FILENO = sys.__stdout__.fileno()
      98  except Exception:
      99      _STDOUT_FILENO = 1
     100  try:
     101      _STDERR_FILENO = sys.__stderr__.fileno()
     102  except Exception:
     103      _STDERR_FILENO = 2
     104  
     105  _STD_STREAMS = (_STDIN_FILENO, _STDOUT_FILENO, _STDERR_FILENO)
     106  _STD_STREAMS_OUTPUT = (_STDOUT_FILENO, _STDERR_FILENO)
     107  
     108  
     109  _TERM_COLORS = {
     110      "kitty": ColorSystem.EIGHT_BIT,
     111      "256color": ColorSystem.EIGHT_BIT,
     112      "16color": ColorSystem.STANDARD,
     113  }
     114  
     115  
     116  class ESC[4;38;5;81mConsoleDimensions(ESC[4;38;5;149mNamedTuple):
     117      """Size of the terminal."""
     118  
     119      width: int
     120      """The width of the console in 'cells'."""
     121      height: int
     122      """The height of the console in lines."""
     123  
     124  
     125  @dataclass
     126  class ESC[4;38;5;81mConsoleOptions:
     127      """Options for __rich_console__ method."""
     128  
     129      size: ConsoleDimensions
     130      """Size of console."""
     131      legacy_windows: bool
     132      """legacy_windows: flag for legacy windows."""
     133      min_width: int
     134      """Minimum width of renderable."""
     135      max_width: int
     136      """Maximum width of renderable."""
     137      is_terminal: bool
     138      """True if the target is a terminal, otherwise False."""
     139      encoding: str
     140      """Encoding of terminal."""
     141      max_height: int
     142      """Height of container (starts as terminal)"""
     143      justify: Optional[JustifyMethod] = None
     144      """Justify value override for renderable."""
     145      overflow: Optional[OverflowMethod] = None
     146      """Overflow value override for renderable."""
     147      no_wrap: Optional[bool] = False
     148      """Disable wrapping for text."""
     149      highlight: Optional[bool] = None
     150      """Highlight override for render_str."""
     151      markup: Optional[bool] = None
     152      """Enable markup when rendering strings."""
     153      height: Optional[int] = None
     154  
     155      @property
     156      def ascii_only(self) -> bool:
     157          """Check if renderables should use ascii only."""
     158          return not self.encoding.startswith("utf")
     159  
     160      def copy(self) -> "ConsoleOptions":
     161          """Return a copy of the options.
     162  
     163          Returns:
     164              ConsoleOptions: a copy of self.
     165          """
     166          options: ConsoleOptions = ConsoleOptions.__new__(ConsoleOptions)
     167          options.__dict__ = self.__dict__.copy()
     168          return options
     169  
     170      def update(
     171          self,
     172          *,
     173          width: Union[int, NoChange] = NO_CHANGE,
     174          min_width: Union[int, NoChange] = NO_CHANGE,
     175          max_width: Union[int, NoChange] = NO_CHANGE,
     176          justify: Union[Optional[JustifyMethod], NoChange] = NO_CHANGE,
     177          overflow: Union[Optional[OverflowMethod], NoChange] = NO_CHANGE,
     178          no_wrap: Union[Optional[bool], NoChange] = NO_CHANGE,
     179          highlight: Union[Optional[bool], NoChange] = NO_CHANGE,
     180          markup: Union[Optional[bool], NoChange] = NO_CHANGE,
     181          height: Union[Optional[int], NoChange] = NO_CHANGE,
     182      ) -> "ConsoleOptions":
     183          """Update values, return a copy."""
     184          options = self.copy()
     185          if not isinstance(width, NoChange):
     186              options.min_width = options.max_width = max(0, width)
     187          if not isinstance(min_width, NoChange):
     188              options.min_width = min_width
     189          if not isinstance(max_width, NoChange):
     190              options.max_width = max_width
     191          if not isinstance(justify, NoChange):
     192              options.justify = justify
     193          if not isinstance(overflow, NoChange):
     194              options.overflow = overflow
     195          if not isinstance(no_wrap, NoChange):
     196              options.no_wrap = no_wrap
     197          if not isinstance(highlight, NoChange):
     198              options.highlight = highlight
     199          if not isinstance(markup, NoChange):
     200              options.markup = markup
     201          if not isinstance(height, NoChange):
     202              if height is not None:
     203                  options.max_height = height
     204              options.height = None if height is None else max(0, height)
     205          return options
     206  
     207      def update_width(self, width: int) -> "ConsoleOptions":
     208          """Update just the width, return a copy.
     209  
     210          Args:
     211              width (int): New width (sets both min_width and max_width)
     212  
     213          Returns:
     214              ~ConsoleOptions: New console options instance.
     215          """
     216          options = self.copy()
     217          options.min_width = options.max_width = max(0, width)
     218          return options
     219  
     220      def update_height(self, height: int) -> "ConsoleOptions":
     221          """Update the height, and return a copy.
     222  
     223          Args:
     224              height (int): New height
     225  
     226          Returns:
     227              ~ConsoleOptions: New Console options instance.
     228          """
     229          options = self.copy()
     230          options.max_height = options.height = height
     231          return options
     232  
     233      def reset_height(self) -> "ConsoleOptions":
     234          """Return a copy of the options with height set to ``None``.
     235  
     236          Returns:
     237              ~ConsoleOptions: New console options instance.
     238          """
     239          options = self.copy()
     240          options.height = None
     241          return options
     242  
     243      def update_dimensions(self, width: int, height: int) -> "ConsoleOptions":
     244          """Update the width and height, and return a copy.
     245  
     246          Args:
     247              width (int): New width (sets both min_width and max_width).
     248              height (int): New height.
     249  
     250          Returns:
     251              ~ConsoleOptions: New console options instance.
     252          """
     253          options = self.copy()
     254          options.min_width = options.max_width = max(0, width)
     255          options.height = options.max_height = height
     256          return options
     257  
     258  
     259  @runtime_checkable
     260  class ESC[4;38;5;81mRichCast(ESC[4;38;5;149mProtocol):
     261      """An object that may be 'cast' to a console renderable."""
     262  
     263      def __rich__(
     264          self,
     265      ) -> Union["ConsoleRenderable", "RichCast", str]:  # pragma: no cover
     266          ...
     267  
     268  
     269  @runtime_checkable
     270  class ESC[4;38;5;81mConsoleRenderable(ESC[4;38;5;149mProtocol):
     271      """An object that supports the console protocol."""
     272  
     273      def __rich_console__(
     274          self, console: "Console", options: "ConsoleOptions"
     275      ) -> "RenderResult":  # pragma: no cover
     276          ...
     277  
     278  
     279  # A type that may be rendered by Console.
     280  RenderableType = Union[ConsoleRenderable, RichCast, str]
     281  
     282  # The result of calling a __rich_console__ method.
     283  RenderResult = Iterable[Union[RenderableType, Segment]]
     284  
     285  _null_highlighter = NullHighlighter()
     286  
     287  
     288  class ESC[4;38;5;81mCaptureError(ESC[4;38;5;149mException):
     289      """An error in the Capture context manager."""
     290  
     291  
     292  class ESC[4;38;5;81mNewLine:
     293      """A renderable to generate new line(s)"""
     294  
     295      def __init__(self, count: int = 1) -> None:
     296          self.count = count
     297  
     298      def __rich_console__(
     299          self, console: "Console", options: "ConsoleOptions"
     300      ) -> Iterable[Segment]:
     301          yield Segment("\n" * self.count)
     302  
     303  
     304  class ESC[4;38;5;81mScreenUpdate:
     305      """Render a list of lines at a given offset."""
     306  
     307      def __init__(self, lines: List[List[Segment]], x: int, y: int) -> None:
     308          self._lines = lines
     309          self.x = x
     310          self.y = y
     311  
     312      def __rich_console__(
     313          self, console: "Console", options: ConsoleOptions
     314      ) -> RenderResult:
     315          x = self.x
     316          move_to = Control.move_to
     317          for offset, line in enumerate(self._lines, self.y):
     318              yield move_to(x, offset)
     319              yield from line
     320  
     321  
     322  class ESC[4;38;5;81mCapture:
     323      """Context manager to capture the result of printing to the console.
     324      See :meth:`~rich.console.Console.capture` for how to use.
     325  
     326      Args:
     327          console (Console): A console instance to capture output.
     328      """
     329  
     330      def __init__(self, console: "Console") -> None:
     331          self._console = console
     332          self._result: Optional[str] = None
     333  
     334      def __enter__(self) -> "Capture":
     335          self._console.begin_capture()
     336          return self
     337  
     338      def __exit__(
     339          self,
     340          exc_type: Optional[Type[BaseException]],
     341          exc_val: Optional[BaseException],
     342          exc_tb: Optional[TracebackType],
     343      ) -> None:
     344          self._result = self._console.end_capture()
     345  
     346      def get(self) -> str:
     347          """Get the result of the capture."""
     348          if self._result is None:
     349              raise CaptureError(
     350                  "Capture result is not available until context manager exits."
     351              )
     352          return self._result
     353  
     354  
     355  class ESC[4;38;5;81mThemeContext:
     356      """A context manager to use a temporary theme. See :meth:`~rich.console.Console.use_theme` for usage."""
     357  
     358      def __init__(self, console: "Console", theme: Theme, inherit: bool = True) -> None:
     359          self.console = console
     360          self.theme = theme
     361          self.inherit = inherit
     362  
     363      def __enter__(self) -> "ThemeContext":
     364          self.console.push_theme(self.theme)
     365          return self
     366  
     367      def __exit__(
     368          self,
     369          exc_type: Optional[Type[BaseException]],
     370          exc_val: Optional[BaseException],
     371          exc_tb: Optional[TracebackType],
     372      ) -> None:
     373          self.console.pop_theme()
     374  
     375  
     376  class ESC[4;38;5;81mPagerContext:
     377      """A context manager that 'pages' content. See :meth:`~rich.console.Console.pager` for usage."""
     378  
     379      def __init__(
     380          self,
     381          console: "Console",
     382          pager: Optional[Pager] = None,
     383          styles: bool = False,
     384          links: bool = False,
     385      ) -> None:
     386          self._console = console
     387          self.pager = SystemPager() if pager is None else pager
     388          self.styles = styles
     389          self.links = links
     390  
     391      def __enter__(self) -> "PagerContext":
     392          self._console._enter_buffer()
     393          return self
     394  
     395      def __exit__(
     396          self,
     397          exc_type: Optional[Type[BaseException]],
     398          exc_val: Optional[BaseException],
     399          exc_tb: Optional[TracebackType],
     400      ) -> None:
     401          if exc_type is None:
     402              with self._console._lock:
     403                  buffer: List[Segment] = self._console._buffer[:]
     404                  del self._console._buffer[:]
     405                  segments: Iterable[Segment] = buffer
     406                  if not self.styles:
     407                      segments = Segment.strip_styles(segments)
     408                  elif not self.links:
     409                      segments = Segment.strip_links(segments)
     410                  content = self._console._render_buffer(segments)
     411              self.pager.show(content)
     412          self._console._exit_buffer()
     413  
     414  
     415  class ESC[4;38;5;81mScreenContext:
     416      """A context manager that enables an alternative screen. See :meth:`~rich.console.Console.screen` for usage."""
     417  
     418      def __init__(
     419          self, console: "Console", hide_cursor: bool, style: StyleType = ""
     420      ) -> None:
     421          self.console = console
     422          self.hide_cursor = hide_cursor
     423          self.screen = Screen(style=style)
     424          self._changed = False
     425  
     426      def update(
     427          self, *renderables: RenderableType, style: Optional[StyleType] = None
     428      ) -> None:
     429          """Update the screen.
     430  
     431          Args:
     432              renderable (RenderableType, optional): Optional renderable to replace current renderable,
     433                  or None for no change. Defaults to None.
     434              style: (Style, optional): Replacement style, or None for no change. Defaults to None.
     435          """
     436          if renderables:
     437              self.screen.renderable = (
     438                  Group(*renderables) if len(renderables) > 1 else renderables[0]
     439              )
     440          if style is not None:
     441              self.screen.style = style
     442          self.console.print(self.screen, end="")
     443  
     444      def __enter__(self) -> "ScreenContext":
     445          self._changed = self.console.set_alt_screen(True)
     446          if self._changed and self.hide_cursor:
     447              self.console.show_cursor(False)
     448          return self
     449  
     450      def __exit__(
     451          self,
     452          exc_type: Optional[Type[BaseException]],
     453          exc_val: Optional[BaseException],
     454          exc_tb: Optional[TracebackType],
     455      ) -> None:
     456          if self._changed:
     457              self.console.set_alt_screen(False)
     458              if self.hide_cursor:
     459                  self.console.show_cursor(True)
     460  
     461  
     462  class ESC[4;38;5;81mGroup:
     463      """Takes a group of renderables and returns a renderable object that renders the group.
     464  
     465      Args:
     466          renderables (Iterable[RenderableType]): An iterable of renderable objects.
     467          fit (bool, optional): Fit dimension of group to contents, or fill available space. Defaults to True.
     468      """
     469  
     470      def __init__(self, *renderables: "RenderableType", fit: bool = True) -> None:
     471          self._renderables = renderables
     472          self.fit = fit
     473          self._render: Optional[List[RenderableType]] = None
     474  
     475      @property
     476      def renderables(self) -> List["RenderableType"]:
     477          if self._render is None:
     478              self._render = list(self._renderables)
     479          return self._render
     480  
     481      def __rich_measure__(
     482          self, console: "Console", options: "ConsoleOptions"
     483      ) -> "Measurement":
     484          if self.fit:
     485              return measure_renderables(console, options, self.renderables)
     486          else:
     487              return Measurement(options.max_width, options.max_width)
     488  
     489      def __rich_console__(
     490          self, console: "Console", options: "ConsoleOptions"
     491      ) -> RenderResult:
     492          yield from self.renderables
     493  
     494  
     495  def group(fit: bool = True) -> Callable[..., Callable[..., Group]]:
     496      """A decorator that turns an iterable of renderables in to a group.
     497  
     498      Args:
     499          fit (bool, optional): Fit dimension of group to contents, or fill available space. Defaults to True.
     500      """
     501  
     502      def decorator(
     503          method: Callable[..., Iterable[RenderableType]]
     504      ) -> Callable[..., Group]:
     505          """Convert a method that returns an iterable of renderables in to a Group."""
     506  
     507          @wraps(method)
     508          def _replace(*args: Any, **kwargs: Any) -> Group:
     509              renderables = method(*args, **kwargs)
     510              return Group(*renderables, fit=fit)
     511  
     512          return _replace
     513  
     514      return decorator
     515  
     516  
     517  def _is_jupyter() -> bool:  # pragma: no cover
     518      """Check if we're running in a Jupyter notebook."""
     519      try:
     520          get_ipython  # type: ignore[name-defined]
     521      except NameError:
     522          return False
     523      ipython = get_ipython()  # type: ignore[name-defined]
     524      shell = ipython.__class__.__name__
     525      if (
     526          "google.colab" in str(ipython.__class__)
     527          or os.getenv("DATABRICKS_RUNTIME_VERSION")
     528          or shell == "ZMQInteractiveShell"
     529      ):
     530          return True  # Jupyter notebook or qtconsole
     531      elif shell == "TerminalInteractiveShell":
     532          return False  # Terminal running IPython
     533      else:
     534          return False  # Other type (?)
     535  
     536  
     537  COLOR_SYSTEMS = {
     538      "standard": ColorSystem.STANDARD,
     539      "256": ColorSystem.EIGHT_BIT,
     540      "truecolor": ColorSystem.TRUECOLOR,
     541      "windows": ColorSystem.WINDOWS,
     542  }
     543  
     544  _COLOR_SYSTEMS_NAMES = {system: name for name, system in COLOR_SYSTEMS.items()}
     545  
     546  
     547  @dataclass
     548  class ESC[4;38;5;81mConsoleThreadLocals(ESC[4;38;5;149mthreadingESC[4;38;5;149m.ESC[4;38;5;149mlocal):
     549      """Thread local values for Console context."""
     550  
     551      theme_stack: ThemeStack
     552      buffer: List[Segment] = field(default_factory=list)
     553      buffer_index: int = 0
     554  
     555  
     556  class ESC[4;38;5;81mRenderHook(ESC[4;38;5;149mABC):
     557      """Provides hooks in to the render process."""
     558  
     559      @abstractmethod
     560      def process_renderables(
     561          self, renderables: List[ConsoleRenderable]
     562      ) -> List[ConsoleRenderable]:
     563          """Called with a list of objects to render.
     564  
     565          This method can return a new list of renderables, or modify and return the same list.
     566  
     567          Args:
     568              renderables (List[ConsoleRenderable]): A number of renderable objects.
     569  
     570          Returns:
     571              List[ConsoleRenderable]: A replacement list of renderables.
     572          """
     573  
     574  
     575  _windows_console_features: Optional["WindowsConsoleFeatures"] = None
     576  
     577  
     578  def get_windows_console_features() -> "WindowsConsoleFeatures":  # pragma: no cover
     579      global _windows_console_features
     580      if _windows_console_features is not None:
     581          return _windows_console_features
     582      from ._windows import get_windows_console_features
     583  
     584      _windows_console_features = get_windows_console_features()
     585      return _windows_console_features
     586  
     587  
     588  def detect_legacy_windows() -> bool:
     589      """Detect legacy Windows."""
     590      return WINDOWS and not get_windows_console_features().vt
     591  
     592  
     593  class ESC[4;38;5;81mConsole:
     594      """A high level console interface.
     595  
     596      Args:
     597          color_system (str, optional): The color system supported by your terminal,
     598              either ``"standard"``, ``"256"`` or ``"truecolor"``. Leave as ``"auto"`` to autodetect.
     599          force_terminal (Optional[bool], optional): Enable/disable terminal control codes, or None to auto-detect terminal. Defaults to None.
     600          force_jupyter (Optional[bool], optional): Enable/disable Jupyter rendering, or None to auto-detect Jupyter. Defaults to None.
     601          force_interactive (Optional[bool], optional): Enable/disable interactive mode, or None to auto detect. Defaults to None.
     602          soft_wrap (Optional[bool], optional): Set soft wrap default on print method. Defaults to False.
     603          theme (Theme, optional): An optional style theme object, or ``None`` for default theme.
     604          stderr (bool, optional): Use stderr rather than stdout if ``file`` is not specified. Defaults to False.
     605          file (IO, optional): A file object where the console should write to. Defaults to stdout.
     606          quiet (bool, Optional): Boolean to suppress all output. Defaults to False.
     607          width (int, optional): The width of the terminal. Leave as default to auto-detect width.
     608          height (int, optional): The height of the terminal. Leave as default to auto-detect height.
     609          style (StyleType, optional): Style to apply to all output, or None for no style. Defaults to None.
     610          no_color (Optional[bool], optional): Enabled no color mode, or None to auto detect. Defaults to None.
     611          tab_size (int, optional): Number of spaces used to replace a tab character. Defaults to 8.
     612          record (bool, optional): Boolean to enable recording of terminal output,
     613              required to call :meth:`export_html`, :meth:`export_svg`, and :meth:`export_text`. Defaults to False.
     614          markup (bool, optional): Boolean to enable :ref:`console_markup`. Defaults to True.
     615          emoji (bool, optional): Enable emoji code. Defaults to True.
     616          emoji_variant (str, optional): Optional emoji variant, either "text" or "emoji". Defaults to None.
     617          highlight (bool, optional): Enable automatic highlighting. Defaults to True.
     618          log_time (bool, optional): Boolean to enable logging of time by :meth:`log` methods. Defaults to True.
     619          log_path (bool, optional): Boolean to enable the logging of the caller by :meth:`log`. Defaults to True.
     620          log_time_format (Union[str, TimeFormatterCallable], optional): If ``log_time`` is enabled, either string for strftime or callable that formats the time. Defaults to "[%X] ".
     621          highlighter (HighlighterType, optional): Default highlighter.
     622          legacy_windows (bool, optional): Enable legacy Windows mode, or ``None`` to auto detect. Defaults to ``None``.
     623          safe_box (bool, optional): Restrict box options that don't render on legacy Windows.
     624          get_datetime (Callable[[], datetime], optional): Callable that gets the current time as a datetime.datetime object (used by Console.log),
     625              or None for datetime.now.
     626          get_time (Callable[[], time], optional): Callable that gets the current time in seconds, default uses time.monotonic.
     627      """
     628  
     629      _environ: Mapping[str, str] = os.environ
     630  
     631      def __init__(
     632          self,
     633          *,
     634          color_system: Optional[
     635              Literal["auto", "standard", "256", "truecolor", "windows"]
     636          ] = "auto",
     637          force_terminal: Optional[bool] = None,
     638          force_jupyter: Optional[bool] = None,
     639          force_interactive: Optional[bool] = None,
     640          soft_wrap: bool = False,
     641          theme: Optional[Theme] = None,
     642          stderr: bool = False,
     643          file: Optional[IO[str]] = None,
     644          quiet: bool = False,
     645          width: Optional[int] = None,
     646          height: Optional[int] = None,
     647          style: Optional[StyleType] = None,
     648          no_color: Optional[bool] = None,
     649          tab_size: int = 8,
     650          record: bool = False,
     651          markup: bool = True,
     652          emoji: bool = True,
     653          emoji_variant: Optional[EmojiVariant] = None,
     654          highlight: bool = True,
     655          log_time: bool = True,
     656          log_path: bool = True,
     657          log_time_format: Union[str, FormatTimeCallable] = "[%X]",
     658          highlighter: Optional["HighlighterType"] = ReprHighlighter(),
     659          legacy_windows: Optional[bool] = None,
     660          safe_box: bool = True,
     661          get_datetime: Optional[Callable[[], datetime]] = None,
     662          get_time: Optional[Callable[[], float]] = None,
     663          _environ: Optional[Mapping[str, str]] = None,
     664      ):
     665          # Copy of os.environ allows us to replace it for testing
     666          if _environ is not None:
     667              self._environ = _environ
     668  
     669          self.is_jupyter = _is_jupyter() if force_jupyter is None else force_jupyter
     670          if self.is_jupyter:
     671              if width is None:
     672                  jupyter_columns = self._environ.get("JUPYTER_COLUMNS")
     673                  if jupyter_columns is not None and jupyter_columns.isdigit():
     674                      width = int(jupyter_columns)
     675                  else:
     676                      width = JUPYTER_DEFAULT_COLUMNS
     677              if height is None:
     678                  jupyter_lines = self._environ.get("JUPYTER_LINES")
     679                  if jupyter_lines is not None and jupyter_lines.isdigit():
     680                      height = int(jupyter_lines)
     681                  else:
     682                      height = JUPYTER_DEFAULT_LINES
     683  
     684          self.tab_size = tab_size
     685          self.record = record
     686          self._markup = markup
     687          self._emoji = emoji
     688          self._emoji_variant: Optional[EmojiVariant] = emoji_variant
     689          self._highlight = highlight
     690          self.legacy_windows: bool = (
     691              (detect_legacy_windows() and not self.is_jupyter)
     692              if legacy_windows is None
     693              else legacy_windows
     694          )
     695  
     696          if width is None:
     697              columns = self._environ.get("COLUMNS")
     698              if columns is not None and columns.isdigit():
     699                  width = int(columns) - self.legacy_windows
     700          if height is None:
     701              lines = self._environ.get("LINES")
     702              if lines is not None and lines.isdigit():
     703                  height = int(lines)
     704  
     705          self.soft_wrap = soft_wrap
     706          self._width = width
     707          self._height = height
     708  
     709          self._color_system: Optional[ColorSystem]
     710  
     711          self._force_terminal = None
     712          if force_terminal is not None:
     713              self._force_terminal = force_terminal
     714  
     715          self._file = file
     716          self.quiet = quiet
     717          self.stderr = stderr
     718  
     719          if color_system is None:
     720              self._color_system = None
     721          elif color_system == "auto":
     722              self._color_system = self._detect_color_system()
     723          else:
     724              self._color_system = COLOR_SYSTEMS[color_system]
     725  
     726          self._lock = threading.RLock()
     727          self._log_render = LogRender(
     728              show_time=log_time,
     729              show_path=log_path,
     730              time_format=log_time_format,
     731          )
     732          self.highlighter: HighlighterType = highlighter or _null_highlighter
     733          self.safe_box = safe_box
     734          self.get_datetime = get_datetime or datetime.now
     735          self.get_time = get_time or monotonic
     736          self.style = style
     737          self.no_color = (
     738              no_color if no_color is not None else "NO_COLOR" in self._environ
     739          )
     740          self.is_interactive = (
     741              (self.is_terminal and not self.is_dumb_terminal)
     742              if force_interactive is None
     743              else force_interactive
     744          )
     745  
     746          self._record_buffer_lock = threading.RLock()
     747          self._thread_locals = ConsoleThreadLocals(
     748              theme_stack=ThemeStack(themes.DEFAULT if theme is None else theme)
     749          )
     750          self._record_buffer: List[Segment] = []
     751          self._render_hooks: List[RenderHook] = []
     752          self._live: Optional["Live"] = None
     753          self._is_alt_screen = False
     754  
     755      def __repr__(self) -> str:
     756          return f"<console width={self.width} {self._color_system!s}>"
     757  
     758      @property
     759      def file(self) -> IO[str]:
     760          """Get the file object to write to."""
     761          file = self._file or (sys.stderr if self.stderr else sys.stdout)
     762          file = getattr(file, "rich_proxied_file", file)
     763          if file is None:
     764              file = NULL_FILE
     765          return file
     766  
     767      @file.setter
     768      def file(self, new_file: IO[str]) -> None:
     769          """Set a new file object."""
     770          self._file = new_file
     771  
     772      @property
     773      def _buffer(self) -> List[Segment]:
     774          """Get a thread local buffer."""
     775          return self._thread_locals.buffer
     776  
     777      @property
     778      def _buffer_index(self) -> int:
     779          """Get a thread local buffer."""
     780          return self._thread_locals.buffer_index
     781  
     782      @_buffer_index.setter
     783      def _buffer_index(self, value: int) -> None:
     784          self._thread_locals.buffer_index = value
     785  
     786      @property
     787      def _theme_stack(self) -> ThemeStack:
     788          """Get the thread local theme stack."""
     789          return self._thread_locals.theme_stack
     790  
     791      def _detect_color_system(self) -> Optional[ColorSystem]:
     792          """Detect color system from env vars."""
     793          if self.is_jupyter:
     794              return ColorSystem.TRUECOLOR
     795          if not self.is_terminal or self.is_dumb_terminal:
     796              return None
     797          if WINDOWS:  # pragma: no cover
     798              if self.legacy_windows:  # pragma: no cover
     799                  return ColorSystem.WINDOWS
     800              windows_console_features = get_windows_console_features()
     801              return (
     802                  ColorSystem.TRUECOLOR
     803                  if windows_console_features.truecolor
     804                  else ColorSystem.EIGHT_BIT
     805              )
     806          else:
     807              color_term = self._environ.get("COLORTERM", "").strip().lower()
     808              if color_term in ("truecolor", "24bit"):
     809                  return ColorSystem.TRUECOLOR
     810              term = self._environ.get("TERM", "").strip().lower()
     811              _term_name, _hyphen, colors = term.rpartition("-")
     812              color_system = _TERM_COLORS.get(colors, ColorSystem.STANDARD)
     813              return color_system
     814  
     815      def _enter_buffer(self) -> None:
     816          """Enter in to a buffer context, and buffer all output."""
     817          self._buffer_index += 1
     818  
     819      def _exit_buffer(self) -> None:
     820          """Leave buffer context, and render content if required."""
     821          self._buffer_index -= 1
     822          self._check_buffer()
     823  
     824      def set_live(self, live: "Live") -> None:
     825          """Set Live instance. Used by Live context manager.
     826  
     827          Args:
     828              live (Live): Live instance using this Console.
     829  
     830          Raises:
     831              errors.LiveError: If this Console has a Live context currently active.
     832          """
     833          with self._lock:
     834              if self._live is not None:
     835                  raise errors.LiveError("Only one live display may be active at once")
     836              self._live = live
     837  
     838      def clear_live(self) -> None:
     839          """Clear the Live instance."""
     840          with self._lock:
     841              self._live = None
     842  
     843      def push_render_hook(self, hook: RenderHook) -> None:
     844          """Add a new render hook to the stack.
     845  
     846          Args:
     847              hook (RenderHook): Render hook instance.
     848          """
     849          with self._lock:
     850              self._render_hooks.append(hook)
     851  
     852      def pop_render_hook(self) -> None:
     853          """Pop the last renderhook from the stack."""
     854          with self._lock:
     855              self._render_hooks.pop()
     856  
     857      def __enter__(self) -> "Console":
     858          """Own context manager to enter buffer context."""
     859          self._enter_buffer()
     860          return self
     861  
     862      def __exit__(self, exc_type: Any, exc_value: Any, traceback: Any) -> None:
     863          """Exit buffer context."""
     864          self._exit_buffer()
     865  
     866      def begin_capture(self) -> None:
     867          """Begin capturing console output. Call :meth:`end_capture` to exit capture mode and return output."""
     868          self._enter_buffer()
     869  
     870      def end_capture(self) -> str:
     871          """End capture mode and return captured string.
     872  
     873          Returns:
     874              str: Console output.
     875          """
     876          render_result = self._render_buffer(self._buffer)
     877          del self._buffer[:]
     878          self._exit_buffer()
     879          return render_result
     880  
     881      def push_theme(self, theme: Theme, *, inherit: bool = True) -> None:
     882          """Push a new theme on to the top of the stack, replacing the styles from the previous theme.
     883          Generally speaking, you should call :meth:`~rich.console.Console.use_theme` to get a context manager, rather
     884          than calling this method directly.
     885  
     886          Args:
     887              theme (Theme): A theme instance.
     888              inherit (bool, optional): Inherit existing styles. Defaults to True.
     889          """
     890          self._theme_stack.push_theme(theme, inherit=inherit)
     891  
     892      def pop_theme(self) -> None:
     893          """Remove theme from top of stack, restoring previous theme."""
     894          self._theme_stack.pop_theme()
     895  
     896      def use_theme(self, theme: Theme, *, inherit: bool = True) -> ThemeContext:
     897          """Use a different theme for the duration of the context manager.
     898  
     899          Args:
     900              theme (Theme): Theme instance to user.
     901              inherit (bool, optional): Inherit existing console styles. Defaults to True.
     902  
     903          Returns:
     904              ThemeContext: [description]
     905          """
     906          return ThemeContext(self, theme, inherit)
     907  
     908      @property
     909      def color_system(self) -> Optional[str]:
     910          """Get color system string.
     911  
     912          Returns:
     913              Optional[str]: "standard", "256" or "truecolor".
     914          """
     915  
     916          if self._color_system is not None:
     917              return _COLOR_SYSTEMS_NAMES[self._color_system]
     918          else:
     919              return None
     920  
     921      @property
     922      def encoding(self) -> str:
     923          """Get the encoding of the console file, e.g. ``"utf-8"``.
     924  
     925          Returns:
     926              str: A standard encoding string.
     927          """
     928          return (getattr(self.file, "encoding", "utf-8") or "utf-8").lower()
     929  
     930      @property
     931      def is_terminal(self) -> bool:
     932          """Check if the console is writing to a terminal.
     933  
     934          Returns:
     935              bool: True if the console writing to a device capable of
     936              understanding terminal codes, otherwise False.
     937          """
     938          if self._force_terminal is not None:
     939              return self._force_terminal
     940  
     941          if hasattr(sys.stdin, "__module__") and sys.stdin.__module__.startswith(
     942              "idlelib"
     943          ):
     944              # Return False for Idle which claims to be a tty but can't handle ansi codes
     945              return False
     946  
     947          if self.is_jupyter:
     948              # return False for Jupyter, which may have FORCE_COLOR set
     949              return False
     950  
     951          # If FORCE_COLOR env var has any value at all, we assume a terminal.
     952          force_color = self._environ.get("FORCE_COLOR")
     953          if force_color is not None:
     954              self._force_terminal = True
     955              return True
     956  
     957          isatty: Optional[Callable[[], bool]] = getattr(self.file, "isatty", None)
     958          try:
     959              return False if isatty is None else isatty()
     960          except ValueError:
     961              # in some situation (at the end of a pytest run for example) isatty() can raise
     962              # ValueError: I/O operation on closed file
     963              # return False because we aren't in a terminal anymore
     964              return False
     965  
     966      @property
     967      def is_dumb_terminal(self) -> bool:
     968          """Detect dumb terminal.
     969  
     970          Returns:
     971              bool: True if writing to a dumb terminal, otherwise False.
     972  
     973          """
     974          _term = self._environ.get("TERM", "")
     975          is_dumb = _term.lower() in ("dumb", "unknown")
     976          return self.is_terminal and is_dumb
     977  
     978      @property
     979      def options(self) -> ConsoleOptions:
     980          """Get default console options."""
     981          return ConsoleOptions(
     982              max_height=self.size.height,
     983              size=self.size,
     984              legacy_windows=self.legacy_windows,
     985              min_width=1,
     986              max_width=self.width,
     987              encoding=self.encoding,
     988              is_terminal=self.is_terminal,
     989          )
     990  
     991      @property
     992      def size(self) -> ConsoleDimensions:
     993          """Get the size of the console.
     994  
     995          Returns:
     996              ConsoleDimensions: A named tuple containing the dimensions.
     997          """
     998  
     999          if self._width is not None and self._height is not None:
    1000              return ConsoleDimensions(self._width - self.legacy_windows, self._height)
    1001  
    1002          if self.is_dumb_terminal:
    1003              return ConsoleDimensions(80, 25)
    1004  
    1005          width: Optional[int] = None
    1006          height: Optional[int] = None
    1007  
    1008          if WINDOWS:  # pragma: no cover
    1009              try:
    1010                  width, height = os.get_terminal_size()
    1011              except (AttributeError, ValueError, OSError):  # Probably not a terminal
    1012                  pass
    1013          else:
    1014              for file_descriptor in _STD_STREAMS:
    1015                  try:
    1016                      width, height = os.get_terminal_size(file_descriptor)
    1017                  except (AttributeError, ValueError, OSError):
    1018                      pass
    1019                  else:
    1020                      break
    1021  
    1022          columns = self._environ.get("COLUMNS")
    1023          if columns is not None and columns.isdigit():
    1024              width = int(columns)
    1025          lines = self._environ.get("LINES")
    1026          if lines is not None and lines.isdigit():
    1027              height = int(lines)
    1028  
    1029          # get_terminal_size can report 0, 0 if run from pseudo-terminal
    1030          width = width or 80
    1031          height = height or 25
    1032          return ConsoleDimensions(
    1033              width - self.legacy_windows if self._width is None else self._width,
    1034              height if self._height is None else self._height,
    1035          )
    1036  
    1037      @size.setter
    1038      def size(self, new_size: Tuple[int, int]) -> None:
    1039          """Set a new size for the terminal.
    1040  
    1041          Args:
    1042              new_size (Tuple[int, int]): New width and height.
    1043          """
    1044          width, height = new_size
    1045          self._width = width
    1046          self._height = height
    1047  
    1048      @property
    1049      def width(self) -> int:
    1050          """Get the width of the console.
    1051  
    1052          Returns:
    1053              int: The width (in characters) of the console.
    1054          """
    1055          return self.size.width
    1056  
    1057      @width.setter
    1058      def width(self, width: int) -> None:
    1059          """Set width.
    1060  
    1061          Args:
    1062              width (int): New width.
    1063          """
    1064          self._width = width
    1065  
    1066      @property
    1067      def height(self) -> int:
    1068          """Get the height of the console.
    1069  
    1070          Returns:
    1071              int: The height (in lines) of the console.
    1072          """
    1073          return self.size.height
    1074  
    1075      @height.setter
    1076      def height(self, height: int) -> None:
    1077          """Set height.
    1078  
    1079          Args:
    1080              height (int): new height.
    1081          """
    1082          self._height = height
    1083  
    1084      def bell(self) -> None:
    1085          """Play a 'bell' sound (if supported by the terminal)."""
    1086          self.control(Control.bell())
    1087  
    1088      def capture(self) -> Capture:
    1089          """A context manager to *capture* the result of print() or log() in a string,
    1090          rather than writing it to the console.
    1091  
    1092          Example:
    1093              >>> from rich.console import Console
    1094              >>> console = Console()
    1095              >>> with console.capture() as capture:
    1096              ...     console.print("[bold magenta]Hello World[/]")
    1097              >>> print(capture.get())
    1098  
    1099          Returns:
    1100              Capture: Context manager with disables writing to the terminal.
    1101          """
    1102          capture = Capture(self)
    1103          return capture
    1104  
    1105      def pager(
    1106          self, pager: Optional[Pager] = None, styles: bool = False, links: bool = False
    1107      ) -> PagerContext:
    1108          """A context manager to display anything printed within a "pager". The pager application
    1109          is defined by the system and will typically support at least pressing a key to scroll.
    1110  
    1111          Args:
    1112              pager (Pager, optional): A pager object, or None to use :class:`~rich.pager.SystemPager`. Defaults to None.
    1113              styles (bool, optional): Show styles in pager. Defaults to False.
    1114              links (bool, optional): Show links in pager. Defaults to False.
    1115  
    1116          Example:
    1117              >>> from rich.console import Console
    1118              >>> from rich.__main__ import make_test_card
    1119              >>> console = Console()
    1120              >>> with console.pager():
    1121                      console.print(make_test_card())
    1122  
    1123          Returns:
    1124              PagerContext: A context manager.
    1125          """
    1126          return PagerContext(self, pager=pager, styles=styles, links=links)
    1127  
    1128      def line(self, count: int = 1) -> None:
    1129          """Write new line(s).
    1130  
    1131          Args:
    1132              count (int, optional): Number of new lines. Defaults to 1.
    1133          """
    1134  
    1135          assert count >= 0, "count must be >= 0"
    1136          self.print(NewLine(count))
    1137  
    1138      def clear(self, home: bool = True) -> None:
    1139          """Clear the screen.
    1140  
    1141          Args:
    1142              home (bool, optional): Also move the cursor to 'home' position. Defaults to True.
    1143          """
    1144          if home:
    1145              self.control(Control.clear(), Control.home())
    1146          else:
    1147              self.control(Control.clear())
    1148  
    1149      def status(
    1150          self,
    1151          status: RenderableType,
    1152          *,
    1153          spinner: str = "dots",
    1154          spinner_style: StyleType = "status.spinner",
    1155          speed: float = 1.0,
    1156          refresh_per_second: float = 12.5,
    1157      ) -> "Status":
    1158          """Display a status and spinner.
    1159  
    1160          Args:
    1161              status (RenderableType): A status renderable (str or Text typically).
    1162              spinner (str, optional): Name of spinner animation (see python -m rich.spinner). Defaults to "dots".
    1163              spinner_style (StyleType, optional): Style of spinner. Defaults to "status.spinner".
    1164              speed (float, optional): Speed factor for spinner animation. Defaults to 1.0.
    1165              refresh_per_second (float, optional): Number of refreshes per second. Defaults to 12.5.
    1166  
    1167          Returns:
    1168              Status: A Status object that may be used as a context manager.
    1169          """
    1170          from .status import Status
    1171  
    1172          status_renderable = Status(
    1173              status,
    1174              console=self,
    1175              spinner=spinner,
    1176              spinner_style=spinner_style,
    1177              speed=speed,
    1178              refresh_per_second=refresh_per_second,
    1179          )
    1180          return status_renderable
    1181  
    1182      def show_cursor(self, show: bool = True) -> bool:
    1183          """Show or hide the cursor.
    1184  
    1185          Args:
    1186              show (bool, optional): Set visibility of the cursor.
    1187          """
    1188          if self.is_terminal:
    1189              self.control(Control.show_cursor(show))
    1190              return True
    1191          return False
    1192  
    1193      def set_alt_screen(self, enable: bool = True) -> bool:
    1194          """Enables alternative screen mode.
    1195  
    1196          Note, if you enable this mode, you should ensure that is disabled before
    1197          the application exits. See :meth:`~rich.Console.screen` for a context manager
    1198          that handles this for you.
    1199  
    1200          Args:
    1201              enable (bool, optional): Enable (True) or disable (False) alternate screen. Defaults to True.
    1202  
    1203          Returns:
    1204              bool: True if the control codes were written.
    1205  
    1206          """
    1207          changed = False
    1208          if self.is_terminal and not self.legacy_windows:
    1209              self.control(Control.alt_screen(enable))
    1210              changed = True
    1211              self._is_alt_screen = enable
    1212          return changed
    1213  
    1214      @property
    1215      def is_alt_screen(self) -> bool:
    1216          """Check if the alt screen was enabled.
    1217  
    1218          Returns:
    1219              bool: True if the alt screen was enabled, otherwise False.
    1220          """
    1221          return self._is_alt_screen
    1222  
    1223      def set_window_title(self, title: str) -> bool:
    1224          """Set the title of the console terminal window.
    1225  
    1226          Warning: There is no means within Rich of "resetting" the window title to its
    1227          previous value, meaning the title you set will persist even after your application
    1228          exits.
    1229  
    1230          ``fish`` shell resets the window title before and after each command by default,
    1231          negating this issue. Windows Terminal and command prompt will also reset the title for you.
    1232          Most other shells and terminals, however, do not do this.
    1233  
    1234          Some terminals may require configuration changes before you can set the title.
    1235          Some terminals may not support setting the title at all.
    1236  
    1237          Other software (including the terminal itself, the shell, custom prompts, plugins, etc.)
    1238          may also set the terminal window title. This could result in whatever value you write
    1239          using this method being overwritten.
    1240  
    1241          Args:
    1242              title (str): The new title of the terminal window.
    1243  
    1244          Returns:
    1245              bool: True if the control code to change the terminal title was
    1246                  written, otherwise False. Note that a return value of True
    1247                  does not guarantee that the window title has actually changed,
    1248                  since the feature may be unsupported/disabled in some terminals.
    1249          """
    1250          if self.is_terminal:
    1251              self.control(Control.title(title))
    1252              return True
    1253          return False
    1254  
    1255      def screen(
    1256          self, hide_cursor: bool = True, style: Optional[StyleType] = None
    1257      ) -> "ScreenContext":
    1258          """Context manager to enable and disable 'alternative screen' mode.
    1259  
    1260          Args:
    1261              hide_cursor (bool, optional): Also hide the cursor. Defaults to False.
    1262              style (Style, optional): Optional style for screen. Defaults to None.
    1263  
    1264          Returns:
    1265              ~ScreenContext: Context which enables alternate screen on enter, and disables it on exit.
    1266          """
    1267          return ScreenContext(self, hide_cursor=hide_cursor, style=style or "")
    1268  
    1269      def measure(
    1270          self, renderable: RenderableType, *, options: Optional[ConsoleOptions] = None
    1271      ) -> Measurement:
    1272          """Measure a renderable. Returns a :class:`~rich.measure.Measurement` object which contains
    1273          information regarding the number of characters required to print the renderable.
    1274  
    1275          Args:
    1276              renderable (RenderableType): Any renderable or string.
    1277              options (Optional[ConsoleOptions], optional): Options to use when measuring, or None
    1278                  to use default options. Defaults to None.
    1279  
    1280          Returns:
    1281              Measurement: A measurement of the renderable.
    1282          """
    1283          measurement = Measurement.get(self, options or self.options, renderable)
    1284          return measurement
    1285  
    1286      def render(
    1287          self, renderable: RenderableType, options: Optional[ConsoleOptions] = None
    1288      ) -> Iterable[Segment]:
    1289          """Render an object in to an iterable of `Segment` instances.
    1290  
    1291          This method contains the logic for rendering objects with the console protocol.
    1292          You are unlikely to need to use it directly, unless you are extending the library.
    1293  
    1294          Args:
    1295              renderable (RenderableType): An object supporting the console protocol, or
    1296                  an object that may be converted to a string.
    1297              options (ConsoleOptions, optional): An options object, or None to use self.options. Defaults to None.
    1298  
    1299          Returns:
    1300              Iterable[Segment]: An iterable of segments that may be rendered.
    1301          """
    1302  
    1303          _options = options or self.options
    1304          if _options.max_width < 1:
    1305              # No space to render anything. This prevents potential recursion errors.
    1306              return
    1307          render_iterable: RenderResult
    1308  
    1309          renderable = rich_cast(renderable)
    1310          if hasattr(renderable, "__rich_console__") and not isclass(renderable):
    1311              render_iterable = renderable.__rich_console__(self, _options)  # type: ignore[union-attr]
    1312          elif isinstance(renderable, str):
    1313              text_renderable = self.render_str(
    1314                  renderable, highlight=_options.highlight, markup=_options.markup
    1315              )
    1316              render_iterable = text_renderable.__rich_console__(self, _options)
    1317          else:
    1318              raise errors.NotRenderableError(
    1319                  f"Unable to render {renderable!r}; "
    1320                  "A str, Segment or object with __rich_console__ method is required"
    1321              )
    1322  
    1323          try:
    1324              iter_render = iter(render_iterable)
    1325          except TypeError:
    1326              raise errors.NotRenderableError(
    1327                  f"object {render_iterable!r} is not renderable"
    1328              )
    1329          _Segment = Segment
    1330          _options = _options.reset_height()
    1331          for render_output in iter_render:
    1332              if isinstance(render_output, _Segment):
    1333                  yield render_output
    1334              else:
    1335                  yield from self.render(render_output, _options)
    1336  
    1337      def render_lines(
    1338          self,
    1339          renderable: RenderableType,
    1340          options: Optional[ConsoleOptions] = None,
    1341          *,
    1342          style: Optional[Style] = None,
    1343          pad: bool = True,
    1344          new_lines: bool = False,
    1345      ) -> List[List[Segment]]:
    1346          """Render objects in to a list of lines.
    1347  
    1348          The output of render_lines is useful when further formatting of rendered console text
    1349          is required, such as the Panel class which draws a border around any renderable object.
    1350  
    1351          Args:
    1352              renderable (RenderableType): Any object renderable in the console.
    1353              options (Optional[ConsoleOptions], optional): Console options, or None to use self.options. Default to ``None``.
    1354              style (Style, optional): Optional style to apply to renderables. Defaults to ``None``.
    1355              pad (bool, optional): Pad lines shorter than render width. Defaults to ``True``.
    1356              new_lines (bool, optional): Include "\n" characters at end of lines.
    1357  
    1358          Returns:
    1359              List[List[Segment]]: A list of lines, where a line is a list of Segment objects.
    1360          """
    1361          with self._lock:
    1362              render_options = options or self.options
    1363              _rendered = self.render(renderable, render_options)
    1364              if style:
    1365                  _rendered = Segment.apply_style(_rendered, style)
    1366  
    1367              render_height = render_options.height
    1368              if render_height is not None:
    1369                  render_height = max(0, render_height)
    1370  
    1371              lines = list(
    1372                  islice(
    1373                      Segment.split_and_crop_lines(
    1374                          _rendered,
    1375                          render_options.max_width,
    1376                          include_new_lines=new_lines,
    1377                          pad=pad,
    1378                          style=style,
    1379                      ),
    1380                      None,
    1381                      render_height,
    1382                  )
    1383              )
    1384              if render_options.height is not None:
    1385                  extra_lines = render_options.height - len(lines)
    1386                  if extra_lines > 0:
    1387                      pad_line = [
    1388                          [Segment(" " * render_options.max_width, style), Segment("\n")]
    1389                          if new_lines
    1390                          else [Segment(" " * render_options.max_width, style)]
    1391                      ]
    1392                      lines.extend(pad_line * extra_lines)
    1393  
    1394              return lines
    1395  
    1396      def render_str(
    1397          self,
    1398          text: str,
    1399          *,
    1400          style: Union[str, Style] = "",
    1401          justify: Optional[JustifyMethod] = None,
    1402          overflow: Optional[OverflowMethod] = None,
    1403          emoji: Optional[bool] = None,
    1404          markup: Optional[bool] = None,
    1405          highlight: Optional[bool] = None,
    1406          highlighter: Optional[HighlighterType] = None,
    1407      ) -> "Text":
    1408          """Convert a string to a Text instance. This is called automatically if
    1409          you print or log a string.
    1410  
    1411          Args:
    1412              text (str): Text to render.
    1413              style (Union[str, Style], optional): Style to apply to rendered text.
    1414              justify (str, optional): Justify method: "default", "left", "center", "full", or "right". Defaults to ``None``.
    1415              overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to ``None``.
    1416              emoji (Optional[bool], optional): Enable emoji, or ``None`` to use Console default.
    1417              markup (Optional[bool], optional): Enable markup, or ``None`` to use Console default.
    1418              highlight (Optional[bool], optional): Enable highlighting, or ``None`` to use Console default.
    1419              highlighter (HighlighterType, optional): Optional highlighter to apply.
    1420          Returns:
    1421              ConsoleRenderable: Renderable object.
    1422  
    1423          """
    1424          emoji_enabled = emoji or (emoji is None and self._emoji)
    1425          markup_enabled = markup or (markup is None and self._markup)
    1426          highlight_enabled = highlight or (highlight is None and self._highlight)
    1427  
    1428          if markup_enabled:
    1429              rich_text = render_markup(
    1430                  text,
    1431                  style=style,
    1432                  emoji=emoji_enabled,
    1433                  emoji_variant=self._emoji_variant,
    1434              )
    1435              rich_text.justify = justify
    1436              rich_text.overflow = overflow
    1437          else:
    1438              rich_text = Text(
    1439                  _emoji_replace(text, default_variant=self._emoji_variant)
    1440                  if emoji_enabled
    1441                  else text,
    1442                  justify=justify,
    1443                  overflow=overflow,
    1444                  style=style,
    1445              )
    1446  
    1447          _highlighter = (highlighter or self.highlighter) if highlight_enabled else None
    1448          if _highlighter is not None:
    1449              highlight_text = _highlighter(str(rich_text))
    1450              highlight_text.copy_styles(rich_text)
    1451              return highlight_text
    1452  
    1453          return rich_text
    1454  
    1455      def get_style(
    1456          self, name: Union[str, Style], *, default: Optional[Union[Style, str]] = None
    1457      ) -> Style:
    1458          """Get a Style instance by its theme name or parse a definition.
    1459  
    1460          Args:
    1461              name (str): The name of a style or a style definition.
    1462  
    1463          Returns:
    1464              Style: A Style object.
    1465  
    1466          Raises:
    1467              MissingStyle: If no style could be parsed from name.
    1468  
    1469          """
    1470          if isinstance(name, Style):
    1471              return name
    1472  
    1473          try:
    1474              style = self._theme_stack.get(name)
    1475              if style is None:
    1476                  style = Style.parse(name)
    1477              return style.copy() if style.link else style
    1478          except errors.StyleSyntaxError as error:
    1479              if default is not None:
    1480                  return self.get_style(default)
    1481              raise errors.MissingStyle(
    1482                  f"Failed to get style {name!r}; {error}"
    1483              ) from None
    1484  
    1485      def _collect_renderables(
    1486          self,
    1487          objects: Iterable[Any],
    1488          sep: str,
    1489          end: str,
    1490          *,
    1491          justify: Optional[JustifyMethod] = None,
    1492          emoji: Optional[bool] = None,
    1493          markup: Optional[bool] = None,
    1494          highlight: Optional[bool] = None,
    1495      ) -> List[ConsoleRenderable]:
    1496          """Combine a number of renderables and text into one renderable.
    1497  
    1498          Args:
    1499              objects (Iterable[Any]): Anything that Rich can render.
    1500              sep (str): String to write between print data.
    1501              end (str): String to write at end of print data.
    1502              justify (str, optional): One of "left", "right", "center", or "full". Defaults to ``None``.
    1503              emoji (Optional[bool], optional): Enable emoji code, or ``None`` to use console default.
    1504              markup (Optional[bool], optional): Enable markup, or ``None`` to use console default.
    1505              highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use console default.
    1506  
    1507          Returns:
    1508              List[ConsoleRenderable]: A list of things to render.
    1509          """
    1510          renderables: List[ConsoleRenderable] = []
    1511          _append = renderables.append
    1512          text: List[Text] = []
    1513          append_text = text.append
    1514  
    1515          append = _append
    1516          if justify in ("left", "center", "right"):
    1517  
    1518              def align_append(renderable: RenderableType) -> None:
    1519                  _append(Align(renderable, cast(AlignMethod, justify)))
    1520  
    1521              append = align_append
    1522  
    1523          _highlighter: HighlighterType = _null_highlighter
    1524          if highlight or (highlight is None and self._highlight):
    1525              _highlighter = self.highlighter
    1526  
    1527          def check_text() -> None:
    1528              if text:
    1529                  sep_text = Text(sep, justify=justify, end=end)
    1530                  append(sep_text.join(text))
    1531                  text.clear()
    1532  
    1533          for renderable in objects:
    1534              renderable = rich_cast(renderable)
    1535              if isinstance(renderable, str):
    1536                  append_text(
    1537                      self.render_str(
    1538                          renderable, emoji=emoji, markup=markup, highlighter=_highlighter
    1539                      )
    1540                  )
    1541              elif isinstance(renderable, Text):
    1542                  append_text(renderable)
    1543              elif isinstance(renderable, ConsoleRenderable):
    1544                  check_text()
    1545                  append(renderable)
    1546              elif is_expandable(renderable):
    1547                  check_text()
    1548                  append(Pretty(renderable, highlighter=_highlighter))
    1549              else:
    1550                  append_text(_highlighter(str(renderable)))
    1551  
    1552          check_text()
    1553  
    1554          if self.style is not None:
    1555              style = self.get_style(self.style)
    1556              renderables = [Styled(renderable, style) for renderable in renderables]
    1557  
    1558          return renderables
    1559  
    1560      def rule(
    1561          self,
    1562          title: TextType = "",
    1563          *,
    1564          characters: str = "─",
    1565          style: Union[str, Style] = "rule.line",
    1566          align: AlignMethod = "center",
    1567      ) -> None:
    1568          """Draw a line with optional centered title.
    1569  
    1570          Args:
    1571              title (str, optional): Text to render over the rule. Defaults to "".
    1572              characters (str, optional): Character(s) to form the line. Defaults to "─".
    1573              style (str, optional): Style of line. Defaults to "rule.line".
    1574              align (str, optional): How to align the title, one of "left", "center", or "right". Defaults to "center".
    1575          """
    1576          from .rule import Rule
    1577  
    1578          rule = Rule(title=title, characters=characters, style=style, align=align)
    1579          self.print(rule)
    1580  
    1581      def control(self, *control: Control) -> None:
    1582          """Insert non-printing control codes.
    1583  
    1584          Args:
    1585              control_codes (str): Control codes, such as those that may move the cursor.
    1586          """
    1587          if not self.is_dumb_terminal:
    1588              with self:
    1589                  self._buffer.extend(_control.segment for _control in control)
    1590  
    1591      def out(
    1592          self,
    1593          *objects: Any,
    1594          sep: str = " ",
    1595          end: str = "\n",
    1596          style: Optional[Union[str, Style]] = None,
    1597          highlight: Optional[bool] = None,
    1598      ) -> None:
    1599          """Output to the terminal. This is a low-level way of writing to the terminal which unlike
    1600          :meth:`~rich.console.Console.print` won't pretty print, wrap text, or apply markup, but will
    1601          optionally apply highlighting and a basic style.
    1602  
    1603          Args:
    1604              sep (str, optional): String to write between print data. Defaults to " ".
    1605              end (str, optional): String to write at end of print data. Defaults to "\\\\n".
    1606              style (Union[str, Style], optional): A style to apply to output. Defaults to None.
    1607              highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use
    1608                  console default. Defaults to ``None``.
    1609          """
    1610          raw_output: str = sep.join(str(_object) for _object in objects)
    1611          self.print(
    1612              raw_output,
    1613              style=style,
    1614              highlight=highlight,
    1615              emoji=False,
    1616              markup=False,
    1617              no_wrap=True,
    1618              overflow="ignore",
    1619              crop=False,
    1620              end=end,
    1621          )
    1622  
    1623      def print(
    1624          self,
    1625          *objects: Any,
    1626          sep: str = " ",
    1627          end: str = "\n",
    1628          style: Optional[Union[str, Style]] = None,
    1629          justify: Optional[JustifyMethod] = None,
    1630          overflow: Optional[OverflowMethod] = None,
    1631          no_wrap: Optional[bool] = None,
    1632          emoji: Optional[bool] = None,
    1633          markup: Optional[bool] = None,
    1634          highlight: Optional[bool] = None,
    1635          width: Optional[int] = None,
    1636          height: Optional[int] = None,
    1637          crop: bool = True,
    1638          soft_wrap: Optional[bool] = None,
    1639          new_line_start: bool = False,
    1640      ) -> None:
    1641          """Print to the console.
    1642  
    1643          Args:
    1644              objects (positional args): Objects to log to the terminal.
    1645              sep (str, optional): String to write between print data. Defaults to " ".
    1646              end (str, optional): String to write at end of print data. Defaults to "\\\\n".
    1647              style (Union[str, Style], optional): A style to apply to output. Defaults to None.
    1648              justify (str, optional): Justify method: "default", "left", "right", "center", or "full". Defaults to ``None``.
    1649              overflow (str, optional): Overflow method: "ignore", "crop", "fold", or "ellipsis". Defaults to None.
    1650              no_wrap (Optional[bool], optional): Disable word wrapping. Defaults to None.
    1651              emoji (Optional[bool], optional): Enable emoji code, or ``None`` to use console default. Defaults to ``None``.
    1652              markup (Optional[bool], optional): Enable markup, or ``None`` to use console default. Defaults to ``None``.
    1653              highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use console default. Defaults to ``None``.
    1654              width (Optional[int], optional): Width of output, or ``None`` to auto-detect. Defaults to ``None``.
    1655              crop (Optional[bool], optional): Crop output to width of terminal. Defaults to True.
    1656              soft_wrap (bool, optional): Enable soft wrap mode which disables word wrapping and cropping of text or ``None`` for
    1657                  Console default. Defaults to ``None``.
    1658              new_line_start (bool, False): Insert a new line at the start if the output contains more than one line. Defaults to ``False``.
    1659          """
    1660          if not objects:
    1661              objects = (NewLine(),)
    1662  
    1663          if soft_wrap is None:
    1664              soft_wrap = self.soft_wrap
    1665          if soft_wrap:
    1666              if no_wrap is None:
    1667                  no_wrap = True
    1668              if overflow is None:
    1669                  overflow = "ignore"
    1670              crop = False
    1671          render_hooks = self._render_hooks[:]
    1672          with self:
    1673              renderables = self._collect_renderables(
    1674                  objects,
    1675                  sep,
    1676                  end,
    1677                  justify=justify,
    1678                  emoji=emoji,
    1679                  markup=markup,
    1680                  highlight=highlight,
    1681              )
    1682              for hook in render_hooks:
    1683                  renderables = hook.process_renderables(renderables)
    1684              render_options = self.options.update(
    1685                  justify=justify,
    1686                  overflow=overflow,
    1687                  width=min(width, self.width) if width is not None else NO_CHANGE,
    1688                  height=height,
    1689                  no_wrap=no_wrap,
    1690                  markup=markup,
    1691                  highlight=highlight,
    1692              )
    1693  
    1694              new_segments: List[Segment] = []
    1695              extend = new_segments.extend
    1696              render = self.render
    1697              if style is None:
    1698                  for renderable in renderables:
    1699                      extend(render(renderable, render_options))
    1700              else:
    1701                  for renderable in renderables:
    1702                      extend(
    1703                          Segment.apply_style(
    1704                              render(renderable, render_options), self.get_style(style)
    1705                          )
    1706                      )
    1707              if new_line_start:
    1708                  if (
    1709                      len("".join(segment.text for segment in new_segments).splitlines())
    1710                      > 1
    1711                  ):
    1712                      new_segments.insert(0, Segment.line())
    1713              if crop:
    1714                  buffer_extend = self._buffer.extend
    1715                  for line in Segment.split_and_crop_lines(
    1716                      new_segments, self.width, pad=False
    1717                  ):
    1718                      buffer_extend(line)
    1719              else:
    1720                  self._buffer.extend(new_segments)
    1721  
    1722      def print_json(
    1723          self,
    1724          json: Optional[str] = None,
    1725          *,
    1726          data: Any = None,
    1727          indent: Union[None, int, str] = 2,
    1728          highlight: bool = True,
    1729          skip_keys: bool = False,
    1730          ensure_ascii: bool = False,
    1731          check_circular: bool = True,
    1732          allow_nan: bool = True,
    1733          default: Optional[Callable[[Any], Any]] = None,
    1734          sort_keys: bool = False,
    1735      ) -> None:
    1736          """Pretty prints JSON. Output will be valid JSON.
    1737  
    1738          Args:
    1739              json (Optional[str]): A string containing JSON.
    1740              data (Any): If json is not supplied, then encode this data.
    1741              indent (Union[None, int, str], optional): Number of spaces to indent. Defaults to 2.
    1742              highlight (bool, optional): Enable highlighting of output: Defaults to True.
    1743              skip_keys (bool, optional): Skip keys not of a basic type. Defaults to False.
    1744              ensure_ascii (bool, optional): Escape all non-ascii characters. Defaults to False.
    1745              check_circular (bool, optional): Check for circular references. Defaults to True.
    1746              allow_nan (bool, optional): Allow NaN and Infinity values. Defaults to True.
    1747              default (Callable, optional): A callable that converts values that can not be encoded
    1748                  in to something that can be JSON encoded. Defaults to None.
    1749              sort_keys (bool, optional): Sort dictionary keys. Defaults to False.
    1750          """
    1751          from pip._vendor.rich.json import JSON
    1752  
    1753          if json is None:
    1754              json_renderable = JSON.from_data(
    1755                  data,
    1756                  indent=indent,
    1757                  highlight=highlight,
    1758                  skip_keys=skip_keys,
    1759                  ensure_ascii=ensure_ascii,
    1760                  check_circular=check_circular,
    1761                  allow_nan=allow_nan,
    1762                  default=default,
    1763                  sort_keys=sort_keys,
    1764              )
    1765          else:
    1766              if not isinstance(json, str):
    1767                  raise TypeError(
    1768                      f"json must be str. Did you mean print_json(data={json!r}) ?"
    1769                  )
    1770              json_renderable = JSON(
    1771                  json,
    1772                  indent=indent,
    1773                  highlight=highlight,
    1774                  skip_keys=skip_keys,
    1775                  ensure_ascii=ensure_ascii,
    1776                  check_circular=check_circular,
    1777                  allow_nan=allow_nan,
    1778                  default=default,
    1779                  sort_keys=sort_keys,
    1780              )
    1781          self.print(json_renderable, soft_wrap=True)
    1782  
    1783      def update_screen(
    1784          self,
    1785          renderable: RenderableType,
    1786          *,
    1787          region: Optional[Region] = None,
    1788          options: Optional[ConsoleOptions] = None,
    1789      ) -> None:
    1790          """Update the screen at a given offset.
    1791  
    1792          Args:
    1793              renderable (RenderableType): A Rich renderable.
    1794              region (Region, optional): Region of screen to update, or None for entire screen. Defaults to None.
    1795              x (int, optional): x offset. Defaults to 0.
    1796              y (int, optional): y offset. Defaults to 0.
    1797  
    1798          Raises:
    1799              errors.NoAltScreen: If the Console isn't in alt screen mode.
    1800  
    1801          """
    1802          if not self.is_alt_screen:
    1803              raise errors.NoAltScreen("Alt screen must be enabled to call update_screen")
    1804          render_options = options or self.options
    1805          if region is None:
    1806              x = y = 0
    1807              render_options = render_options.update_dimensions(
    1808                  render_options.max_width, render_options.height or self.height
    1809              )
    1810          else:
    1811              x, y, width, height = region
    1812              render_options = render_options.update_dimensions(width, height)
    1813  
    1814          lines = self.render_lines(renderable, options=render_options)
    1815          self.update_screen_lines(lines, x, y)
    1816  
    1817      def update_screen_lines(
    1818          self, lines: List[List[Segment]], x: int = 0, y: int = 0
    1819      ) -> None:
    1820          """Update lines of the screen at a given offset.
    1821  
    1822          Args:
    1823              lines (List[List[Segment]]): Rendered lines (as produced by :meth:`~rich.Console.render_lines`).
    1824              x (int, optional): x offset (column no). Defaults to 0.
    1825              y (int, optional): y offset (column no). Defaults to 0.
    1826  
    1827          Raises:
    1828              errors.NoAltScreen: If the Console isn't in alt screen mode.
    1829          """
    1830          if not self.is_alt_screen:
    1831              raise errors.NoAltScreen("Alt screen must be enabled to call update_screen")
    1832          screen_update = ScreenUpdate(lines, x, y)
    1833          segments = self.render(screen_update)
    1834          self._buffer.extend(segments)
    1835          self._check_buffer()
    1836  
    1837      def print_exception(
    1838          self,
    1839          *,
    1840          width: Optional[int] = 100,
    1841          extra_lines: int = 3,
    1842          theme: Optional[str] = None,
    1843          word_wrap: bool = False,
    1844          show_locals: bool = False,
    1845          suppress: Iterable[Union[str, ModuleType]] = (),
    1846          max_frames: int = 100,
    1847      ) -> None:
    1848          """Prints a rich render of the last exception and traceback.
    1849  
    1850          Args:
    1851              width (Optional[int], optional): Number of characters used to render code. Defaults to 100.
    1852              extra_lines (int, optional): Additional lines of code to render. Defaults to 3.
    1853              theme (str, optional): Override pygments theme used in traceback
    1854              word_wrap (bool, optional): Enable word wrapping of long lines. Defaults to False.
    1855              show_locals (bool, optional): Enable display of local variables. Defaults to False.
    1856              suppress (Iterable[Union[str, ModuleType]]): Optional sequence of modules or paths to exclude from traceback.
    1857              max_frames (int): Maximum number of frames to show in a traceback, 0 for no maximum. Defaults to 100.
    1858          """
    1859          from .traceback import Traceback
    1860  
    1861          traceback = Traceback(
    1862              width=width,
    1863              extra_lines=extra_lines,
    1864              theme=theme,
    1865              word_wrap=word_wrap,
    1866              show_locals=show_locals,
    1867              suppress=suppress,
    1868              max_frames=max_frames,
    1869          )
    1870          self.print(traceback)
    1871  
    1872      @staticmethod
    1873      def _caller_frame_info(
    1874          offset: int,
    1875          currentframe: Callable[[], Optional[FrameType]] = inspect.currentframe,
    1876      ) -> Tuple[str, int, Dict[str, Any]]:
    1877          """Get caller frame information.
    1878  
    1879          Args:
    1880              offset (int): the caller offset within the current frame stack.
    1881              currentframe (Callable[[], Optional[FrameType]], optional): the callable to use to
    1882                  retrieve the current frame. Defaults to ``inspect.currentframe``.
    1883  
    1884          Returns:
    1885              Tuple[str, int, Dict[str, Any]]: A tuple containing the filename, the line number and
    1886                  the dictionary of local variables associated with the caller frame.
    1887  
    1888          Raises:
    1889              RuntimeError: If the stack offset is invalid.
    1890          """
    1891          # Ignore the frame of this local helper
    1892          offset += 1
    1893  
    1894          frame = currentframe()
    1895          if frame is not None:
    1896              # Use the faster currentframe where implemented
    1897              while offset and frame is not None:
    1898                  frame = frame.f_back
    1899                  offset -= 1
    1900              assert frame is not None
    1901              return frame.f_code.co_filename, frame.f_lineno, frame.f_locals
    1902          else:
    1903              # Fallback to the slower stack
    1904              frame_info = inspect.stack()[offset]
    1905              return frame_info.filename, frame_info.lineno, frame_info.frame.f_locals
    1906  
    1907      def log(
    1908          self,
    1909          *objects: Any,
    1910          sep: str = " ",
    1911          end: str = "\n",
    1912          style: Optional[Union[str, Style]] = None,
    1913          justify: Optional[JustifyMethod] = None,
    1914          emoji: Optional[bool] = None,
    1915          markup: Optional[bool] = None,
    1916          highlight: Optional[bool] = None,
    1917          log_locals: bool = False,
    1918          _stack_offset: int = 1,
    1919      ) -> None:
    1920          """Log rich content to the terminal.
    1921  
    1922          Args:
    1923              objects (positional args): Objects to log to the terminal.
    1924              sep (str, optional): String to write between print data. Defaults to " ".
    1925              end (str, optional): String to write at end of print data. Defaults to "\\\\n".
    1926              style (Union[str, Style], optional): A style to apply to output. Defaults to None.
    1927              justify (str, optional): One of "left", "right", "center", or "full". Defaults to ``None``.
    1928              overflow (str, optional): Overflow method: "crop", "fold", or "ellipsis". Defaults to None.
    1929              emoji (Optional[bool], optional): Enable emoji code, or ``None`` to use console default. Defaults to None.
    1930              markup (Optional[bool], optional): Enable markup, or ``None`` to use console default. Defaults to None.
    1931              highlight (Optional[bool], optional): Enable automatic highlighting, or ``None`` to use console default. Defaults to None.
    1932              log_locals (bool, optional): Boolean to enable logging of locals where ``log()``
    1933                  was called. Defaults to False.
    1934              _stack_offset (int, optional): Offset of caller from end of call stack. Defaults to 1.
    1935          """
    1936          if not objects:
    1937              objects = (NewLine(),)
    1938  
    1939          render_hooks = self._render_hooks[:]
    1940  
    1941          with self:
    1942              renderables = self._collect_renderables(
    1943                  objects,
    1944                  sep,
    1945                  end,
    1946                  justify=justify,
    1947                  emoji=emoji,
    1948                  markup=markup,
    1949                  highlight=highlight,
    1950              )
    1951              if style is not None:
    1952                  renderables = [Styled(renderable, style) for renderable in renderables]
    1953  
    1954              filename, line_no, locals = self._caller_frame_info(_stack_offset)
    1955              link_path = None if filename.startswith("<") else os.path.abspath(filename)
    1956              path = filename.rpartition(os.sep)[-1]
    1957              if log_locals:
    1958                  locals_map = {
    1959                      key: value
    1960                      for key, value in locals.items()
    1961                      if not key.startswith("__")
    1962                  }
    1963                  renderables.append(render_scope(locals_map, title="[i]locals"))
    1964  
    1965              renderables = [
    1966                  self._log_render(
    1967                      self,
    1968                      renderables,
    1969                      log_time=self.get_datetime(),
    1970                      path=path,
    1971                      line_no=line_no,
    1972                      link_path=link_path,
    1973                  )
    1974              ]
    1975              for hook in render_hooks:
    1976                  renderables = hook.process_renderables(renderables)
    1977              new_segments: List[Segment] = []
    1978              extend = new_segments.extend
    1979              render = self.render
    1980              render_options = self.options
    1981              for renderable in renderables:
    1982                  extend(render(renderable, render_options))
    1983              buffer_extend = self._buffer.extend
    1984              for line in Segment.split_and_crop_lines(
    1985                  new_segments, self.width, pad=False
    1986              ):
    1987                  buffer_extend(line)
    1988  
    1989      def _check_buffer(self) -> None:
    1990          """Check if the buffer may be rendered. Render it if it can (e.g. Console.quiet is False)
    1991          Rendering is supported on Windows, Unix and Jupyter environments. For
    1992          legacy Windows consoles, the win32 API is called directly.
    1993          This method will also record what it renders if recording is enabled via Console.record.
    1994          """
    1995          if self.quiet:
    1996              del self._buffer[:]
    1997              return
    1998          with self._lock:
    1999              if self.record:
    2000                  with self._record_buffer_lock:
    2001                      self._record_buffer.extend(self._buffer[:])
    2002  
    2003              if self._buffer_index == 0:
    2004                  if self.is_jupyter:  # pragma: no cover
    2005                      from .jupyter import display
    2006  
    2007                      display(self._buffer, self._render_buffer(self._buffer[:]))
    2008                      del self._buffer[:]
    2009                  else:
    2010                      if WINDOWS:
    2011                          use_legacy_windows_render = False
    2012                          if self.legacy_windows:
    2013                              fileno = get_fileno(self.file)
    2014                              if fileno is not None:
    2015                                  use_legacy_windows_render = (
    2016                                      fileno in _STD_STREAMS_OUTPUT
    2017                                  )
    2018  
    2019                          if use_legacy_windows_render:
    2020                              from pip._vendor.rich._win32_console import LegacyWindowsTerm
    2021                              from pip._vendor.rich._windows_renderer import legacy_windows_render
    2022  
    2023                              buffer = self._buffer[:]
    2024                              if self.no_color and self._color_system:
    2025                                  buffer = list(Segment.remove_color(buffer))
    2026  
    2027                              legacy_windows_render(buffer, LegacyWindowsTerm(self.file))
    2028                          else:
    2029                              # Either a non-std stream on legacy Windows, or modern Windows.
    2030                              text = self._render_buffer(self._buffer[:])
    2031                              # https://bugs.python.org/issue37871
    2032                              # https://github.com/python/cpython/issues/82052
    2033                              # We need to avoid writing more than 32Kb in a single write, due to the above bug
    2034                              write = self.file.write
    2035                              # Worse case scenario, every character is 4 bytes of utf-8
    2036                              MAX_WRITE = 32 * 1024 // 4
    2037                              try:
    2038                                  if len(text) <= MAX_WRITE:
    2039                                      write(text)
    2040                                  else:
    2041                                      batch: List[str] = []
    2042                                      batch_append = batch.append
    2043                                      size = 0
    2044                                      for line in text.splitlines(True):
    2045                                          if size + len(line) > MAX_WRITE and batch:
    2046                                              write("".join(batch))
    2047                                              batch.clear()
    2048                                              size = 0
    2049                                          batch_append(line)
    2050                                          size += len(line)
    2051                                      if batch:
    2052                                          write("".join(batch))
    2053                                          batch.clear()
    2054                              except UnicodeEncodeError as error:
    2055                                  error.reason = f"{error.reason}\n*** You may need to add PYTHONIOENCODING=utf-8 to your environment ***"
    2056                                  raise
    2057                      else:
    2058                          text = self._render_buffer(self._buffer[:])
    2059                          try:
    2060                              self.file.write(text)
    2061                          except UnicodeEncodeError as error:
    2062                              error.reason = f"{error.reason}\n*** You may need to add PYTHONIOENCODING=utf-8 to your environment ***"
    2063                              raise
    2064  
    2065                      self.file.flush()
    2066                      del self._buffer[:]
    2067  
    2068      def _render_buffer(self, buffer: Iterable[Segment]) -> str:
    2069          """Render buffered output, and clear buffer."""
    2070          output: List[str] = []
    2071          append = output.append
    2072          color_system = self._color_system
    2073          legacy_windows = self.legacy_windows
    2074          not_terminal = not self.is_terminal
    2075          if self.no_color and color_system:
    2076              buffer = Segment.remove_color(buffer)
    2077          for text, style, control in buffer:
    2078              if style:
    2079                  append(
    2080                      style.render(
    2081                          text,
    2082                          color_system=color_system,
    2083                          legacy_windows=legacy_windows,
    2084                      )
    2085                  )
    2086              elif not (not_terminal and control):
    2087                  append(text)
    2088  
    2089          rendered = "".join(output)
    2090          return rendered
    2091  
    2092      def input(
    2093          self,
    2094          prompt: TextType = "",
    2095          *,
    2096          markup: bool = True,
    2097          emoji: bool = True,
    2098          password: bool = False,
    2099          stream: Optional[TextIO] = None,
    2100      ) -> str:
    2101          """Displays a prompt and waits for input from the user. The prompt may contain color / style.
    2102  
    2103          It works in the same way as Python's builtin :func:`input` function and provides elaborate line editing and history features if Python's builtin :mod:`readline` module is previously loaded.
    2104  
    2105          Args:
    2106              prompt (Union[str, Text]): Text to render in the prompt.
    2107              markup (bool, optional): Enable console markup (requires a str prompt). Defaults to True.
    2108              emoji (bool, optional): Enable emoji (requires a str prompt). Defaults to True.
    2109              password: (bool, optional): Hide typed text. Defaults to False.
    2110              stream: (TextIO, optional): Optional file to read input from (rather than stdin). Defaults to None.
    2111  
    2112          Returns:
    2113              str: Text read from stdin.
    2114          """
    2115          if prompt:
    2116              self.print(prompt, markup=markup, emoji=emoji, end="")
    2117          if password:
    2118              result = getpass("", stream=stream)
    2119          else:
    2120              if stream:
    2121                  result = stream.readline()
    2122              else:
    2123                  result = input()
    2124          return result
    2125  
    2126      def export_text(self, *, clear: bool = True, styles: bool = False) -> str:
    2127          """Generate text from console contents (requires record=True argument in constructor).
    2128  
    2129          Args:
    2130              clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``.
    2131              styles (bool, optional): If ``True``, ansi escape codes will be included. ``False`` for plain text.
    2132                  Defaults to ``False``.
    2133  
    2134          Returns:
    2135              str: String containing console contents.
    2136  
    2137          """
    2138          assert (
    2139              self.record
    2140          ), "To export console contents set record=True in the constructor or instance"
    2141  
    2142          with self._record_buffer_lock:
    2143              if styles:
    2144                  text = "".join(
    2145                      (style.render(text) if style else text)
    2146                      for text, style, _ in self._record_buffer
    2147                  )
    2148              else:
    2149                  text = "".join(
    2150                      segment.text
    2151                      for segment in self._record_buffer
    2152                      if not segment.control
    2153                  )
    2154              if clear:
    2155                  del self._record_buffer[:]
    2156          return text
    2157  
    2158      def save_text(self, path: str, *, clear: bool = True, styles: bool = False) -> None:
    2159          """Generate text from console and save to a given location (requires record=True argument in constructor).
    2160  
    2161          Args:
    2162              path (str): Path to write text files.
    2163              clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``.
    2164              styles (bool, optional): If ``True``, ansi style codes will be included. ``False`` for plain text.
    2165                  Defaults to ``False``.
    2166  
    2167          """
    2168          text = self.export_text(clear=clear, styles=styles)
    2169          with open(path, "wt", encoding="utf-8") as write_file:
    2170              write_file.write(text)
    2171  
    2172      def export_html(
    2173          self,
    2174          *,
    2175          theme: Optional[TerminalTheme] = None,
    2176          clear: bool = True,
    2177          code_format: Optional[str] = None,
    2178          inline_styles: bool = False,
    2179      ) -> str:
    2180          """Generate HTML from console contents (requires record=True argument in constructor).
    2181  
    2182          Args:
    2183              theme (TerminalTheme, optional): TerminalTheme object containing console colors.
    2184              clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``.
    2185              code_format (str, optional): Format string to render HTML. In addition to '{foreground}',
    2186                  '{background}', and '{code}', should contain '{stylesheet}' if inline_styles is ``False``.
    2187              inline_styles (bool, optional): If ``True`` styles will be inlined in to spans, which makes files
    2188                  larger but easier to cut and paste markup. If ``False``, styles will be embedded in a style tag.
    2189                  Defaults to False.
    2190  
    2191          Returns:
    2192              str: String containing console contents as HTML.
    2193          """
    2194          assert (
    2195              self.record
    2196          ), "To export console contents set record=True in the constructor or instance"
    2197          fragments: List[str] = []
    2198          append = fragments.append
    2199          _theme = theme or DEFAULT_TERMINAL_THEME
    2200          stylesheet = ""
    2201  
    2202          render_code_format = CONSOLE_HTML_FORMAT if code_format is None else code_format
    2203  
    2204          with self._record_buffer_lock:
    2205              if inline_styles:
    2206                  for text, style, _ in Segment.filter_control(
    2207                      Segment.simplify(self._record_buffer)
    2208                  ):
    2209                      text = escape(text)
    2210                      if style:
    2211                          rule = style.get_html_style(_theme)
    2212                          if style.link:
    2213                              text = f'<a href="{style.link}">{text}</a>'
    2214                          text = f'<span style="{rule}">{text}</span>' if rule else text
    2215                      append(text)
    2216              else:
    2217                  styles: Dict[str, int] = {}
    2218                  for text, style, _ in Segment.filter_control(
    2219                      Segment.simplify(self._record_buffer)
    2220                  ):
    2221                      text = escape(text)
    2222                      if style:
    2223                          rule = style.get_html_style(_theme)
    2224                          style_number = styles.setdefault(rule, len(styles) + 1)
    2225                          if style.link:
    2226                              text = f'<a class="r{style_number}" href="{style.link}">{text}</a>'
    2227                          else:
    2228                              text = f'<span class="r{style_number}">{text}</span>'
    2229                      append(text)
    2230                  stylesheet_rules: List[str] = []
    2231                  stylesheet_append = stylesheet_rules.append
    2232                  for style_rule, style_number in styles.items():
    2233                      if style_rule:
    2234                          stylesheet_append(f".r{style_number} {{{style_rule}}}")
    2235                  stylesheet = "\n".join(stylesheet_rules)
    2236  
    2237              rendered_code = render_code_format.format(
    2238                  code="".join(fragments),
    2239                  stylesheet=stylesheet,
    2240                  foreground=_theme.foreground_color.hex,
    2241                  background=_theme.background_color.hex,
    2242              )
    2243              if clear:
    2244                  del self._record_buffer[:]
    2245          return rendered_code
    2246  
    2247      def save_html(
    2248          self,
    2249          path: str,
    2250          *,
    2251          theme: Optional[TerminalTheme] = None,
    2252          clear: bool = True,
    2253          code_format: str = CONSOLE_HTML_FORMAT,
    2254          inline_styles: bool = False,
    2255      ) -> None:
    2256          """Generate HTML from console contents and write to a file (requires record=True argument in constructor).
    2257  
    2258          Args:
    2259              path (str): Path to write html file.
    2260              theme (TerminalTheme, optional): TerminalTheme object containing console colors.
    2261              clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``.
    2262              code_format (str, optional): Format string to render HTML. In addition to '{foreground}',
    2263                  '{background}', and '{code}', should contain '{stylesheet}' if inline_styles is ``False``.
    2264              inline_styles (bool, optional): If ``True`` styles will be inlined in to spans, which makes files
    2265                  larger but easier to cut and paste markup. If ``False``, styles will be embedded in a style tag.
    2266                  Defaults to False.
    2267  
    2268          """
    2269          html = self.export_html(
    2270              theme=theme,
    2271              clear=clear,
    2272              code_format=code_format,
    2273              inline_styles=inline_styles,
    2274          )
    2275          with open(path, "wt", encoding="utf-8") as write_file:
    2276              write_file.write(html)
    2277  
    2278      def export_svg(
    2279          self,
    2280          *,
    2281          title: str = "Rich",
    2282          theme: Optional[TerminalTheme] = None,
    2283          clear: bool = True,
    2284          code_format: str = CONSOLE_SVG_FORMAT,
    2285          font_aspect_ratio: float = 0.61,
    2286          unique_id: Optional[str] = None,
    2287      ) -> str:
    2288          """
    2289          Generate an SVG from the console contents (requires record=True in Console constructor).
    2290  
    2291          Args:
    2292              title (str, optional): The title of the tab in the output image
    2293              theme (TerminalTheme, optional): The ``TerminalTheme`` object to use to style the terminal
    2294              clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``
    2295              code_format (str, optional): Format string used to generate the SVG. Rich will inject a number of variables
    2296                  into the string in order to form the final SVG output. The default template used and the variables
    2297                  injected by Rich can be found by inspecting the ``console.CONSOLE_SVG_FORMAT`` variable.
    2298              font_aspect_ratio (float, optional): The width to height ratio of the font used in the ``code_format``
    2299                  string. Defaults to 0.61, which is the width to height ratio of Fira Code (the default font).
    2300                  If you aren't specifying a different font inside ``code_format``, you probably don't need this.
    2301              unique_id (str, optional): unique id that is used as the prefix for various elements (CSS styles, node
    2302                  ids). If not set, this defaults to a computed value based on the recorded content.
    2303          """
    2304  
    2305          from pip._vendor.rich.cells import cell_len
    2306  
    2307          style_cache: Dict[Style, str] = {}
    2308  
    2309          def get_svg_style(style: Style) -> str:
    2310              """Convert a Style to CSS rules for SVG."""
    2311              if style in style_cache:
    2312                  return style_cache[style]
    2313              css_rules = []
    2314              color = (
    2315                  _theme.foreground_color
    2316                  if (style.color is None or style.color.is_default)
    2317                  else style.color.get_truecolor(_theme)
    2318              )
    2319              bgcolor = (
    2320                  _theme.background_color
    2321                  if (style.bgcolor is None or style.bgcolor.is_default)
    2322                  else style.bgcolor.get_truecolor(_theme)
    2323              )
    2324              if style.reverse:
    2325                  color, bgcolor = bgcolor, color
    2326              if style.dim:
    2327                  color = blend_rgb(color, bgcolor, 0.4)
    2328              css_rules.append(f"fill: {color.hex}")
    2329              if style.bold:
    2330                  css_rules.append("font-weight: bold")
    2331              if style.italic:
    2332                  css_rules.append("font-style: italic;")
    2333              if style.underline:
    2334                  css_rules.append("text-decoration: underline;")
    2335              if style.strike:
    2336                  css_rules.append("text-decoration: line-through;")
    2337  
    2338              css = ";".join(css_rules)
    2339              style_cache[style] = css
    2340              return css
    2341  
    2342          _theme = theme or SVG_EXPORT_THEME
    2343  
    2344          width = self.width
    2345          char_height = 20
    2346          char_width = char_height * font_aspect_ratio
    2347          line_height = char_height * 1.22
    2348  
    2349          margin_top = 1
    2350          margin_right = 1
    2351          margin_bottom = 1
    2352          margin_left = 1
    2353  
    2354          padding_top = 40
    2355          padding_right = 8
    2356          padding_bottom = 8
    2357          padding_left = 8
    2358  
    2359          padding_width = padding_left + padding_right
    2360          padding_height = padding_top + padding_bottom
    2361          margin_width = margin_left + margin_right
    2362          margin_height = margin_top + margin_bottom
    2363  
    2364          text_backgrounds: List[str] = []
    2365          text_group: List[str] = []
    2366          classes: Dict[str, int] = {}
    2367          style_no = 1
    2368  
    2369          def escape_text(text: str) -> str:
    2370              """HTML escape text and replace spaces with nbsp."""
    2371              return escape(text).replace(" ", "&#160;")
    2372  
    2373          def make_tag(
    2374              name: str, content: Optional[str] = None, **attribs: object
    2375          ) -> str:
    2376              """Make a tag from name, content, and attributes."""
    2377  
    2378              def stringify(value: object) -> str:
    2379                  if isinstance(value, (float)):
    2380                      return format(value, "g")
    2381                  return str(value)
    2382  
    2383              tag_attribs = " ".join(
    2384                  f'{k.lstrip("_").replace("_", "-")}="{stringify(v)}"'
    2385                  for k, v in attribs.items()
    2386              )
    2387              return (
    2388                  f"<{name} {tag_attribs}>{content}</{name}>"
    2389                  if content
    2390                  else f"<{name} {tag_attribs}/>"
    2391              )
    2392  
    2393          with self._record_buffer_lock:
    2394              segments = list(Segment.filter_control(self._record_buffer))
    2395              if clear:
    2396                  self._record_buffer.clear()
    2397  
    2398          if unique_id is None:
    2399              unique_id = "terminal-" + str(
    2400                  zlib.adler32(
    2401                      ("".join(repr(segment) for segment in segments)).encode(
    2402                          "utf-8",
    2403                          "ignore",
    2404                      )
    2405                      + title.encode("utf-8", "ignore")
    2406                  )
    2407              )
    2408          y = 0
    2409          for y, line in enumerate(Segment.split_and_crop_lines(segments, length=width)):
    2410              x = 0
    2411              for text, style, _control in line:
    2412                  style = style or Style()
    2413                  rules = get_svg_style(style)
    2414                  if rules not in classes:
    2415                      classes[rules] = style_no
    2416                      style_no += 1
    2417                  class_name = f"r{classes[rules]}"
    2418  
    2419                  if style.reverse:
    2420                      has_background = True
    2421                      background = (
    2422                          _theme.foreground_color.hex
    2423                          if style.color is None
    2424                          else style.color.get_truecolor(_theme).hex
    2425                      )
    2426                  else:
    2427                      bgcolor = style.bgcolor
    2428                      has_background = bgcolor is not None and not bgcolor.is_default
    2429                      background = (
    2430                          _theme.background_color.hex
    2431                          if style.bgcolor is None
    2432                          else style.bgcolor.get_truecolor(_theme).hex
    2433                      )
    2434  
    2435                  text_length = cell_len(text)
    2436                  if has_background:
    2437                      text_backgrounds.append(
    2438                          make_tag(
    2439                              "rect",
    2440                              fill=background,
    2441                              x=x * char_width,
    2442                              y=y * line_height + 1.5,
    2443                              width=char_width * text_length,
    2444                              height=line_height + 0.25,
    2445                              shape_rendering="crispEdges",
    2446                          )
    2447                      )
    2448  
    2449                  if text != " " * len(text):
    2450                      text_group.append(
    2451                          make_tag(
    2452                              "text",
    2453                              escape_text(text),
    2454                              _class=f"{unique_id}-{class_name}",
    2455                              x=x * char_width,
    2456                              y=y * line_height + char_height,
    2457                              textLength=char_width * len(text),
    2458                              clip_path=f"url(#{unique_id}-line-{y})",
    2459                          )
    2460                      )
    2461                  x += cell_len(text)
    2462  
    2463          line_offsets = [line_no * line_height + 1.5 for line_no in range(y)]
    2464          lines = "\n".join(
    2465              f"""<clipPath id="{unique_id}-line-{line_no}">
    2466      {make_tag("rect", x=0, y=offset, width=char_width * width, height=line_height + 0.25)}
    2467              </clipPath>"""
    2468              for line_no, offset in enumerate(line_offsets)
    2469          )
    2470  
    2471          styles = "\n".join(
    2472              f".{unique_id}-r{rule_no} {{ {css} }}" for css, rule_no in classes.items()
    2473          )
    2474          backgrounds = "".join(text_backgrounds)
    2475          matrix = "".join(text_group)
    2476  
    2477          terminal_width = ceil(width * char_width + padding_width)
    2478          terminal_height = (y + 1) * line_height + padding_height
    2479          chrome = make_tag(
    2480              "rect",
    2481              fill=_theme.background_color.hex,
    2482              stroke="rgba(255,255,255,0.35)",
    2483              stroke_width="1",
    2484              x=margin_left,
    2485              y=margin_top,
    2486              width=terminal_width,
    2487              height=terminal_height,
    2488              rx=8,
    2489          )
    2490  
    2491          title_color = _theme.foreground_color.hex
    2492          if title:
    2493              chrome += make_tag(
    2494                  "text",
    2495                  escape_text(title),
    2496                  _class=f"{unique_id}-title",
    2497                  fill=title_color,
    2498                  text_anchor="middle",
    2499                  x=terminal_width // 2,
    2500                  y=margin_top + char_height + 6,
    2501              )
    2502          chrome += f"""
    2503              <g transform="translate(26,22)">
    2504              <circle cx="0" cy="0" r="7" fill="#ff5f57"/>
    2505              <circle cx="22" cy="0" r="7" fill="#febc2e"/>
    2506              <circle cx="44" cy="0" r="7" fill="#28c840"/>
    2507              </g>
    2508          """
    2509  
    2510          svg = code_format.format(
    2511              unique_id=unique_id,
    2512              char_width=char_width,
    2513              char_height=char_height,
    2514              line_height=line_height,
    2515              terminal_width=char_width * width - 1,
    2516              terminal_height=(y + 1) * line_height - 1,
    2517              width=terminal_width + margin_width,
    2518              height=terminal_height + margin_height,
    2519              terminal_x=margin_left + padding_left,
    2520              terminal_y=margin_top + padding_top,
    2521              styles=styles,
    2522              chrome=chrome,
    2523              backgrounds=backgrounds,
    2524              matrix=matrix,
    2525              lines=lines,
    2526          )
    2527          return svg
    2528  
    2529      def save_svg(
    2530          self,
    2531          path: str,
    2532          *,
    2533          title: str = "Rich",
    2534          theme: Optional[TerminalTheme] = None,
    2535          clear: bool = True,
    2536          code_format: str = CONSOLE_SVG_FORMAT,
    2537          font_aspect_ratio: float = 0.61,
    2538          unique_id: Optional[str] = None,
    2539      ) -> None:
    2540          """Generate an SVG file from the console contents (requires record=True in Console constructor).
    2541  
    2542          Args:
    2543              path (str): The path to write the SVG to.
    2544              title (str, optional): The title of the tab in the output image
    2545              theme (TerminalTheme, optional): The ``TerminalTheme`` object to use to style the terminal
    2546              clear (bool, optional): Clear record buffer after exporting. Defaults to ``True``
    2547              code_format (str, optional): Format string used to generate the SVG. Rich will inject a number of variables
    2548                  into the string in order to form the final SVG output. The default template used and the variables
    2549                  injected by Rich can be found by inspecting the ``console.CONSOLE_SVG_FORMAT`` variable.
    2550              font_aspect_ratio (float, optional): The width to height ratio of the font used in the ``code_format``
    2551                  string. Defaults to 0.61, which is the width to height ratio of Fira Code (the default font).
    2552                  If you aren't specifying a different font inside ``code_format``, you probably don't need this.
    2553              unique_id (str, optional): unique id that is used as the prefix for various elements (CSS styles, node
    2554                  ids). If not set, this defaults to a computed value based on the recorded content.
    2555          """
    2556          svg = self.export_svg(
    2557              title=title,
    2558              theme=theme,
    2559              clear=clear,
    2560              code_format=code_format,
    2561              font_aspect_ratio=font_aspect_ratio,
    2562              unique_id=unique_id,
    2563          )
    2564          with open(path, "wt", encoding="utf-8") as write_file:
    2565              write_file.write(svg)
    2566  
    2567  
    2568  def _svg_hash(svg_main_code: str) -> str:
    2569      """Returns a unique hash for the given SVG main code.
    2570  
    2571      Args:
    2572          svg_main_code (str): The content we're going to inject in the SVG envelope.
    2573  
    2574      Returns:
    2575          str: a hash of the given content
    2576      """
    2577      return str(zlib.adler32(svg_main_code.encode()))
    2578  
    2579  
    2580  if __name__ == "__main__":  # pragma: no cover
    2581      console = Console(record=True)
    2582  
    2583      console.log(
    2584          "JSONRPC [i]request[/i]",
    2585          5,
    2586          1.3,
    2587          True,
    2588          False,
    2589          None,
    2590          {
    2591              "jsonrpc": "2.0",
    2592              "method": "subtract",
    2593              "params": {"minuend": 42, "subtrahend": 23},
    2594              "id": 3,
    2595          },
    2596      )
    2597  
    2598      console.log("Hello, World!", "{'a': 1}", repr(console))
    2599  
    2600      console.print(
    2601          {
    2602              "name": None,
    2603              "empty": [],
    2604              "quiz": {
    2605                  "sport": {
    2606                      "answered": True,
    2607                      "q1": {
    2608                          "question": "Which one is correct team name in NBA?",
    2609                          "options": [
    2610                              "New York Bulls",
    2611                              "Los Angeles Kings",
    2612                              "Golden State Warriors",
    2613                              "Huston Rocket",
    2614                          ],
    2615                          "answer": "Huston Rocket",
    2616                      },
    2617                  },
    2618                  "maths": {
    2619                      "answered": False,
    2620                      "q1": {
    2621                          "question": "5 + 7 = ?",
    2622                          "options": [10, 11, 12, 13],
    2623                          "answer": 12,
    2624                      },
    2625                      "q2": {
    2626                          "question": "12 - 8 = ?",
    2627                          "options": [1, 2, 3, 4],
    2628                          "answer": 4,
    2629                      },
    2630                  },
    2631              },
    2632          }
    2633      )