Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
panel.py318 linesDownload Raw Back to rich
1from typing import TYPE_CHECKING, Optional2 3from .align import AlignMethod4from .box import ROUNDED, Box5from .cells import cell_len6from .jupyter import JupyterMixin7from .measure import Measurement, measure_renderables8from .padding import Padding, PaddingDimensions9from .segment import Segment10from .style import Style, StyleType11from .text import Text, TextType12 13if TYPE_CHECKING:14    from .console import Console, ConsoleOptions, RenderableType, RenderResult15 16 17class Panel(JupyterMixin):18    """A console renderable that draws a border around its contents.19 20    Example:21        >>> console.print(Panel("Hello, World!"))22 23    Args:24        renderable (RenderableType): A console renderable object.25        box (Box): A Box instance that defines the look of the border (see :ref:`appendix_box`. Defaults to box.ROUNDED.26        title (Optional[TextType], optional): Optional title displayed in panel header. Defaults to None.27        title_align (AlignMethod, optional): Alignment of title. Defaults to "center".28        subtitle (Optional[TextType], optional): Optional subtitle displayed in panel footer. Defaults to None.29        subtitle_align (AlignMethod, optional): Alignment of subtitle. Defaults to "center".30        safe_box (bool, optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True.31        expand (bool, optional): If True the panel will stretch to fill the console width, otherwise it will be sized to fit the contents. Defaults to True.32        style (str, optional): The style of the panel (border and contents). Defaults to "none".33        border_style (str, optional): The style of the border. Defaults to "none".34        width (Optional[int], optional): Optional width of panel. Defaults to None to auto-detect.35        height (Optional[int], optional): Optional height of panel. Defaults to None to auto-detect.36        padding (Optional[PaddingDimensions]): Optional padding around renderable. Defaults to 0.37        highlight (bool, optional): Enable automatic highlighting of panel title (if str). Defaults to False.38    """39 40    def __init__(41        self,42        renderable: "RenderableType",43        box: Box = ROUNDED,44        *,45        title: Optional[TextType] = None,46        title_align: AlignMethod = "center",47        subtitle: Optional[TextType] = None,48        subtitle_align: AlignMethod = "center",49        safe_box: Optional[bool] = None,50        expand: bool = True,51        style: StyleType = "none",52        border_style: StyleType = "none",53        width: Optional[int] = None,54        height: Optional[int] = None,55        padding: PaddingDimensions = (0, 1),56        highlight: bool = False,57    ) -> None:58        self.renderable = renderable59        self.box = box60        self.title = title61        self.title_align: AlignMethod = title_align62        self.subtitle = subtitle63        self.subtitle_align = subtitle_align64        self.safe_box = safe_box65        self.expand = expand66        self.style = style67        self.border_style = border_style68        self.width = width69        self.height = height70        self.padding = padding71        self.highlight = highlight72 73    @classmethod74    def fit(75        cls,76        renderable: "RenderableType",77        box: Box = ROUNDED,78        *,79        title: Optional[TextType] = None,80        title_align: AlignMethod = "center",81        subtitle: Optional[TextType] = None,82        subtitle_align: AlignMethod = "center",83        safe_box: Optional[bool] = None,84        style: StyleType = "none",85        border_style: StyleType = "none",86        width: Optional[int] = None,87        height: Optional[int] = None,88        padding: PaddingDimensions = (0, 1),89        highlight: bool = False,90    ) -> "Panel":91        """An alternative constructor that sets expand=False."""92        return cls(93            renderable,94            box,95            title=title,96            title_align=title_align,97            subtitle=subtitle,98            subtitle_align=subtitle_align,99            safe_box=safe_box,100            style=style,101            border_style=border_style,102            width=width,103            height=height,104            padding=padding,105            highlight=highlight,106            expand=False,107        )108 109    @property110    def _title(self) -> Optional[Text]:111        if self.title:112            title_text = (113                Text.from_markup(self.title)114                if isinstance(self.title, str)115                else self.title.copy()116            )117            title_text.end = ""118            title_text.plain = title_text.plain.replace("\n", " ")119            title_text.no_wrap = True120            title_text.expand_tabs()121            title_text.pad(1)122            return title_text123        return None124 125    @property126    def _subtitle(self) -> Optional[Text]:127        if self.subtitle:128            subtitle_text = (129                Text.from_markup(self.subtitle)130                if isinstance(self.subtitle, str)131                else self.subtitle.copy()132            )133            subtitle_text.end = ""134            subtitle_text.plain = subtitle_text.plain.replace("\n", " ")135            subtitle_text.no_wrap = True136            subtitle_text.expand_tabs()137            subtitle_text.pad(1)138            return subtitle_text139        return None140 141    def __rich_console__(142        self, console: "Console", options: "ConsoleOptions"143    ) -> "RenderResult":144        _padding = Padding.unpack(self.padding)145        renderable = (146            Padding(self.renderable, _padding) if any(_padding) else self.renderable147        )148        style = console.get_style(self.style)149        border_style = style + console.get_style(self.border_style)150        width = (151            options.max_width152            if self.width is None153            else min(options.max_width, self.width)154        )155 156        safe_box: bool = console.safe_box if self.safe_box is None else self.safe_box157        box = self.box.substitute(options, safe=safe_box)158 159        def align_text(160            text: Text, width: int, align: str, character: str, style: Style161        ) -> Text:162            """Gets new aligned text.163 164            Args:165                text (Text): Title or subtitle text.166                width (int): Desired width.167                align (str): Alignment.168                character (str): Character for alignment.169                style (Style): Border style170 171            Returns:172                Text: New text instance173            """174            text = text.copy()175            text.truncate(width)176            excess_space = width - cell_len(text.plain)177            if text.style:178                text.stylize(console.get_style(text.style))179 180            if excess_space:181                if align == "left":182                    return Text.assemble(183                        text,184                        (character * excess_space, style),185                        no_wrap=True,186                        end="",187                    )188                elif align == "center":189                    left = excess_space // 2190                    return Text.assemble(191                        (character * left, style),192                        text,193                        (character * (excess_space - left), style),194                        no_wrap=True,195                        end="",196                    )197                else:198                    return Text.assemble(199                        (character * excess_space, style),200                        text,201                        no_wrap=True,202                        end="",203                    )204            return text205 206        title_text = self._title207        if title_text is not None:208            title_text.stylize_before(border_style)209 210        child_width = (211            width - 2212            if self.expand213            else console.measure(214                renderable, options=options.update_width(width - 2)215            ).maximum216        )217        child_height = self.height or options.height or None218        if child_height:219            child_height -= 2220        if title_text is not None:221            child_width = min(222                options.max_width - 2, max(child_width, title_text.cell_len + 2)223            )224 225        width = child_width + 2226        child_options = options.update(227            width=child_width, height=child_height, highlight=self.highlight228        )229        lines = console.render_lines(renderable, child_options, style=style)230 231        line_start = Segment(box.mid_left, border_style)232        line_end = Segment(f"{box.mid_right}", border_style)233        new_line = Segment.line()234        if title_text is None or width <= 4:235            yield Segment(box.get_top([width - 2]), border_style)236        else:237            title_text = align_text(238                title_text,239                width - 4,240                self.title_align,241                box.top,242                border_style,243            )244            yield Segment(box.top_left + box.top, border_style)245            yield from console.render(title_text, child_options.update_width(width - 4))246            yield Segment(box.top + box.top_right, border_style)247 248        yield new_line249        for line in lines:250            yield line_start251            yield from line252            yield line_end253            yield new_line254 255        subtitle_text = self._subtitle256        if subtitle_text is not None:257            subtitle_text.stylize_before(border_style)258 259        if subtitle_text is None or width <= 4:260            yield Segment(box.get_bottom([width - 2]), border_style)261        else:262            subtitle_text = align_text(263                subtitle_text,264                width - 4,265                self.subtitle_align,266                box.bottom,267                border_style,268            )269            yield Segment(box.bottom_left + box.bottom, border_style)270            yield from console.render(271                subtitle_text, child_options.update_width(width - 4)272            )273            yield Segment(box.bottom + box.bottom_right, border_style)274 275        yield new_line276 277    def __rich_measure__(278        self, console: "Console", options: "ConsoleOptions"279    ) -> "Measurement":280        _title = self._title281        _, right, _, left = Padding.unpack(self.padding)282        padding = left + right283        renderables = [self.renderable, _title] if _title else [self.renderable]284 285        if self.width is None:286            width = (287                measure_renderables(288                    console,289                    options.update_width(options.max_width - padding - 2),290                    renderables,291                ).maximum292                + padding293                + 2294            )295        else:296            width = self.width297        return Measurement(width, width)298 299 300if __name__ == "__main__":  # pragma: no cover301    from .console import Console302 303    c = Console()304 305    from .box import DOUBLE, ROUNDED306    from .padding import Padding307 308    p = Panel(309        "Hello, World!",310        title="rich.Panel",311        style="white on blue",312        box=DOUBLE,313        padding=1,314    )315 316    c.print()317    c.print(p)318 
codekingpro/portable-devtools · Team Ai