Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_inspect.py271 linesDownload Raw Back to rich
1from __future__ import absolute_import2 3import inspect4from inspect import cleandoc, getdoc, getfile, isclass, ismodule, signature5from typing import Any, Collection, Iterable, Optional, Tuple, Type, Union6 7from .console import Group, RenderableType8from .control import escape_control_codes9from .highlighter import ReprHighlighter10from .jupyter import JupyterMixin11from .panel import Panel12from .pretty import Pretty13from .table import Table14from .text import Text, TextType15 16 17def _first_paragraph(doc: str) -> str:18    """Get the first paragraph from a docstring."""19    paragraph, _, _ = doc.partition("\n\n")20    return paragraph21 22 23class Inspect(JupyterMixin):24    """A renderable to inspect any Python Object.25 26    Args:27        obj (Any): An object to inspect.28        title (str, optional): Title to display over inspect result, or None use type. Defaults to None.29        help (bool, optional): Show full help text rather than just first paragraph. Defaults to False.30        methods (bool, optional): Enable inspection of callables. Defaults to False.31        docs (bool, optional): Also render doc strings. Defaults to True.32        private (bool, optional): Show private attributes (beginning with underscore). Defaults to False.33        dunder (bool, optional): Show attributes starting with double underscore. Defaults to False.34        sort (bool, optional): Sort attributes alphabetically. Defaults to True.35        all (bool, optional): Show all attributes. Defaults to False.36        value (bool, optional): Pretty print value of object. Defaults to True.37    """38 39    def __init__(40        self,41        obj: Any,42        *,43        title: Optional[TextType] = None,44        help: bool = False,45        methods: bool = False,46        docs: bool = True,47        private: bool = False,48        dunder: bool = False,49        sort: bool = True,50        all: bool = True,51        value: bool = True,52    ) -> None:53        self.highlighter = ReprHighlighter()54        self.obj = obj55        self.title = title or self._make_title(obj)56        if all:57            methods = private = dunder = True58        self.help = help59        self.methods = methods60        self.docs = docs or help61        self.private = private or dunder62        self.dunder = dunder63        self.sort = sort64        self.value = value65 66    def _make_title(self, obj: Any) -> Text:67        """Make a default title."""68        title_str = (69            str(obj)70            if (isclass(obj) or callable(obj) or ismodule(obj))71            else str(type(obj))72        )73        title_text = self.highlighter(title_str)74        return title_text75 76    def __rich__(self) -> Panel:77        return Panel.fit(78            Group(*self._render()),79            title=self.title,80            border_style="scope.border",81            padding=(0, 1),82        )83 84    def _get_signature(self, name: str, obj: Any) -> Optional[Text]:85        """Get a signature for a callable."""86        try:87            _signature = str(signature(obj)) + ":"88        except ValueError:89            _signature = "(...)"90        except TypeError:91            return None92 93        source_filename: Optional[str] = None94        try:95            source_filename = getfile(obj)96        except (OSError, TypeError):97            # OSError is raised if obj has no source file, e.g. when defined in REPL.98            pass99 100        callable_name = Text(name, style="inspect.callable")101        if source_filename:102            callable_name.stylize(f"link file://{source_filename}")103        signature_text = self.highlighter(_signature)104 105        qualname = name or getattr(obj, "__qualname__", name)106 107        # If obj is a module, there may be classes (which are callable) to display108        if inspect.isclass(obj):109            prefix = "class"110        elif inspect.iscoroutinefunction(obj):111            prefix = "async def"112        else:113            prefix = "def"114 115        qual_signature = Text.assemble(116            (f"{prefix} ", f"inspect.{prefix.replace(' ', '_')}"),117            (qualname, "inspect.callable"),118            signature_text,119        )120 121        return qual_signature122 123    def _render(self) -> Iterable[RenderableType]:124        """Render object."""125 126        def sort_items(item: Tuple[str, Any]) -> Tuple[bool, str]:127            key, (_error, value) = item128            return (callable(value), key.strip("_").lower())129 130        def safe_getattr(attr_name: str) -> Tuple[Any, Any]:131            """Get attribute or any exception."""132            try:133                return (None, getattr(obj, attr_name))134            except Exception as error:135                return (error, None)136 137        obj = self.obj138        keys = dir(obj)139        total_items = len(keys)140        if not self.dunder:141            keys = [key for key in keys if not key.startswith("__")]142        if not self.private:143            keys = [key for key in keys if not key.startswith("_")]144        not_shown_count = total_items - len(keys)145        items = [(key, safe_getattr(key)) for key in keys]146        if self.sort:147            items.sort(key=sort_items)148 149        items_table = Table.grid(padding=(0, 1), expand=False)150        items_table.add_column(justify="right")151        add_row = items_table.add_row152        highlighter = self.highlighter153 154        if callable(obj):155            signature = self._get_signature("", obj)156            if signature is not None:157                yield signature158                yield ""159 160        if self.docs:161            _doc = self._get_formatted_doc(obj)162            if _doc is not None:163                doc_text = Text(_doc, style="inspect.help")164                doc_text = highlighter(doc_text)165                yield doc_text166                yield ""167 168        if self.value and not (isclass(obj) or callable(obj) or ismodule(obj)):169            yield Panel(170                Pretty(obj, indent_guides=True, max_length=10, max_string=60),171                border_style="inspect.value.border",172            )173            yield ""174 175        for key, (error, value) in items:176            key_text = Text.assemble(177                (178                    key,179                    "inspect.attr.dunder" if key.startswith("__") else "inspect.attr",180                ),181                (" =", "inspect.equals"),182            )183            if error is not None:184                warning = key_text.copy()185                warning.stylize("inspect.error")186                add_row(warning, highlighter(repr(error)))187                continue188 189            if callable(value):190                if not self.methods:191                    continue192 193                _signature_text = self._get_signature(key, value)194                if _signature_text is None:195                    add_row(key_text, Pretty(value, highlighter=highlighter))196                else:197                    if self.docs:198                        docs = self._get_formatted_doc(value)199                        if docs is not None:200                            _signature_text.append("\n" if "\n" in docs else " ")201                            doc = highlighter(docs)202                            doc.stylize("inspect.doc")203                            _signature_text.append(doc)204 205                    add_row(key_text, _signature_text)206            else:207                add_row(key_text, Pretty(value, highlighter=highlighter))208        if items_table.row_count:209            yield items_table210        elif not_shown_count:211            yield Text.from_markup(212                f"[b cyan]{not_shown_count}[/][i] attribute(s) not shown.[/i] "213                f"Run [b][magenta]inspect[/]([not b]inspect[/])[/b] for options."214            )215 216    def _get_formatted_doc(self, object_: Any) -> Optional[str]:217        """218        Extract the docstring of an object, process it and returns it.219        The processing consists in cleaning up the doctring's indentation,220        taking only its 1st paragraph if `self.help` is not True,221        and escape its control codes.222 223        Args:224            object_ (Any): the object to get the docstring from.225 226        Returns:227            Optional[str]: the processed docstring, or None if no docstring was found.228        """229        docs = getdoc(object_)230        if docs is None:231            return None232        docs = cleandoc(docs).strip()233        if not self.help:234            docs = _first_paragraph(docs)235        return escape_control_codes(docs)236 237 238def get_object_types_mro(obj: Union[object, Type[Any]]) -> Tuple[type, ...]:239    """Returns the MRO of an object's class, or of the object itself if it's a class."""240    if not hasattr(obj, "__mro__"):241        # N.B. we cannot use `if type(obj) is type` here because it doesn't work with242        # some types of classes, such as the ones that use abc.ABCMeta.243        obj = type(obj)244    return getattr(obj, "__mro__", ())245 246 247def get_object_types_mro_as_strings(obj: object) -> Collection[str]:248    """249    Returns the MRO of an object's class as full qualified names, or of the object itself if it's a class.250 251    Examples:252        `object_types_mro_as_strings(JSONDecoder)` will return `['json.decoder.JSONDecoder', 'builtins.object']`253    """254    return [255        f'{getattr(type_, "__module__", "")}.{getattr(type_, "__qualname__", "")}'256        for type_ in get_object_types_mro(obj)257    ]258 259 260def is_object_one_of_types(261    obj: object, fully_qualified_types_names: Collection[str]262) -> bool:263    """264    Returns `True` if the given object's class (or the object itself, if it's a class) has one of the265    fully qualified names in its MRO.266    """267    for type_name in get_object_types_mro_as_strings(obj):268        if type_name in fully_qualified_types_names:269            return True270    return False271 
codekingpro/portable-devtools · Team Ai