Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
panel.py313 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, optional): A Box instance that defines the look of the border (see :ref:`appendix_box`.26            Defaults to box.ROUNDED.27        safe_box (bool, optional): Disable box characters that don't display on windows legacy terminal with *raster* fonts. Defaults to True.28        expand (bool, optional): If True the panel will stretch to fill the console29            width, otherwise it will be sized to fit the contents. Defaults to True.30        style (str, optional): The style of the panel (border and contents). Defaults to "none".31        border_style (str, optional): The style of the border. Defaults to "none".32        width (Optional[int], optional): Optional width of panel. Defaults to None to auto-detect.33        height (Optional[int], optional): Optional height of panel. Defaults to None to auto-detect.34        padding (Optional[PaddingDimensions]): Optional padding around renderable. Defaults to 0.35        highlight (bool, optional): Enable automatic highlighting of panel title (if str). Defaults to False.36    """37 38    def __init__(39        self,40        renderable: "RenderableType",41        box: Box = ROUNDED,42        *,43        title: Optional[TextType] = None,44        title_align: AlignMethod = "center",45        subtitle: Optional[TextType] = None,46        subtitle_align: AlignMethod = "center",47        safe_box: Optional[bool] = None,48        expand: bool = True,49        style: StyleType = "none",50        border_style: StyleType = "none",51        width: Optional[int] = None,52        height: Optional[int] = None,53        padding: PaddingDimensions = (0, 1),54        highlight: bool = False,55    ) -> None:56        self.renderable = renderable57        self.box = box58        self.title = title59        self.title_align: AlignMethod = title_align60        self.subtitle = subtitle61        self.subtitle_align = subtitle_align62        self.safe_box = safe_box63        self.expand = expand64        self.style = style65        self.border_style = border_style66        self.width = width67        self.height = height68        self.padding = padding69        self.highlight = highlight70 71    @classmethod72    def fit(73        cls,74        renderable: "RenderableType",75        box: Box = ROUNDED,76        *,77        title: Optional[TextType] = None,78        title_align: AlignMethod = "center",79        subtitle: Optional[TextType] = None,80        subtitle_align: AlignMethod = "center",81        safe_box: Optional[bool] = None,82        style: StyleType = "none",83        border_style: StyleType = "none",84        width: Optional[int] = None,85        height: Optional[int] = None,86        padding: PaddingDimensions = (0, 1),87        highlight: bool = False,88    ) -> "Panel":89        """An alternative constructor that sets expand=False."""90        return cls(91            renderable,92            box,93            title=title,94            title_align=title_align,95            subtitle=subtitle,96            subtitle_align=subtitle_align,97            safe_box=safe_box,98            style=style,99            border_style=border_style,100            width=width,101            height=height,102            padding=padding,103            highlight=highlight,104            expand=False,105        )106 107    @property108    def _title(self) -> Optional[Text]:109        if self.title:110            title_text = (111                Text.from_markup(self.title)112                if isinstance(self.title, str)113                else self.title.copy()114            )115            title_text.end = ""116            title_text.plain = title_text.plain.replace("\n", " ")117            title_text.no_wrap = True118            title_text.expand_tabs()119            title_text.pad(1)120            return title_text121        return None122 123    @property124    def _subtitle(self) -> Optional[Text]:125        if self.subtitle:126            subtitle_text = (127                Text.from_markup(self.subtitle)128                if isinstance(self.subtitle, str)129                else self.subtitle.copy()130            )131            subtitle_text.end = ""132            subtitle_text.plain = subtitle_text.plain.replace("\n", " ")133            subtitle_text.no_wrap = True134            subtitle_text.expand_tabs()135            subtitle_text.pad(1)136            return subtitle_text137        return None138 139    def __rich_console__(140        self, console: "Console", options: "ConsoleOptions"141    ) -> "RenderResult":142        _padding = Padding.unpack(self.padding)143        renderable = (144            Padding(self.renderable, _padding) if any(_padding) else self.renderable145        )146        style = console.get_style(self.style)147        border_style = style + console.get_style(self.border_style)148        width = (149            options.max_width150            if self.width is None151            else min(options.max_width, self.width)152        )153 154        safe_box: bool = console.safe_box if self.safe_box is None else self.safe_box155        box = self.box.substitute(options, safe=safe_box)156 157        def align_text(158            text: Text, width: int, align: str, character: str, style: Style159        ) -> Text:160            """Gets new aligned text.161 162            Args:163                text (Text): Title or subtitle text.164                width (int): Desired width.165                align (str): Alignment.166                character (str): Character for alignment.167                style (Style): Border style168 169            Returns:170                Text: New text instance171            """172            text = text.copy()173            text.truncate(width)174            excess_space = width - cell_len(text.plain)175            if excess_space:176                if align == "left":177                    return Text.assemble(178                        text,179                        (character * excess_space, style),180                        no_wrap=True,181                        end="",182                    )183                elif align == "center":184                    left = excess_space // 2185                    return Text.assemble(186                        (character * left, style),187                        text,188                        (character * (excess_space - left), style),189                        no_wrap=True,190                        end="",191                    )192                else:193                    return Text.assemble(194                        (character * excess_space, style),195                        text,196                        no_wrap=True,197                        end="",198                    )199            return text200 201        title_text = self._title202        if title_text is not None:203            title_text.stylize_before(border_style)204 205        child_width = (206            width - 2207            if self.expand208            else console.measure(209                renderable, options=options.update_width(width - 2)210            ).maximum211        )212        child_height = self.height or options.height or None213        if child_height:214            child_height -= 2215        if title_text is not None:216            child_width = min(217                options.max_width - 2, max(child_width, title_text.cell_len + 2)218            )219 220        width = child_width + 2221        child_options = options.update(222            width=child_width, height=child_height, highlight=self.highlight223        )224        lines = console.render_lines(renderable, child_options, style=style)225 226        line_start = Segment(box.mid_left, border_style)227        line_end = Segment(f"{box.mid_right}", border_style)228        new_line = Segment.line()229        if title_text is None or width <= 4:230            yield Segment(box.get_top([width - 2]), border_style)231        else:232            title_text = align_text(233                title_text,234                width - 4,235                self.title_align,236                box.top,237                border_style,238            )239            yield Segment(box.top_left + box.top, border_style)240            yield from console.render(title_text, child_options.update_width(width - 4))241            yield Segment(box.top + box.top_right, border_style)242 243        yield new_line244        for line in lines:245            yield line_start246            yield from line247            yield line_end248            yield new_line249 250        subtitle_text = self._subtitle251        if subtitle_text is not None:252            subtitle_text.stylize_before(border_style)253 254        if subtitle_text is None or width <= 4:255            yield Segment(box.get_bottom([width - 2]), border_style)256        else:257            subtitle_text = align_text(258                subtitle_text,259                width - 4,260                self.subtitle_align,261                box.bottom,262                border_style,263            )264            yield Segment(box.bottom_left + box.bottom, border_style)265            yield from console.render(266                subtitle_text, child_options.update_width(width - 4)267            )268            yield Segment(box.bottom + box.bottom_right, border_style)269 270        yield new_line271 272    def __rich_measure__(273        self, console: "Console", options: "ConsoleOptions"274    ) -> "Measurement":275        _title = self._title276        _, right, _, left = Padding.unpack(self.padding)277        padding = left + right278        renderables = [self.renderable, _title] if _title else [self.renderable]279 280        if self.width is None:281            width = (282                measure_renderables(283                    console,284                    options.update_width(options.max_width - padding - 2),285                    renderables,286                ).maximum287                + padding288                + 2289            )290        else:291            width = self.width292        return Measurement(width, width)293 294 295if __name__ == "__main__":  # pragma: no cover296    from .console import Console297 298    c = Console()299 300    from .box import DOUBLE, ROUNDED301    from .padding import Padding302 303    p = Panel(304        "Hello, World!",305        title="rich.Panel",306        style="white on blue",307        box=DOUBLE,308        padding=1,309    )310 311    c.print()312    c.print(p)313 
codekingpro/portable-devtools · Team Ai