Show More
@@ -24,9 +24,7 b' import os' | |||
|
24 | 24 | import types |
|
25 | 25 | import warnings |
|
26 | 26 | |
|
27 | from typing import Any, Optional, Dict, Union, List, Tuple | |
|
28 | ||
|
29 | from typing import TypeAlias | |
|
27 | from typing import cast, Any, Optional, Dict, Union, List, TypedDict, TypeAlias, Tuple | |
|
30 | 28 | |
|
31 | 29 | import traitlets |
|
32 | 30 | |
@@ -42,7 +40,6 b' from IPython.utils.text import indent' | |||
|
42 | 40 | from IPython.utils.wildcard import list_namespace |
|
43 | 41 | from IPython.utils.wildcard import typestr2type |
|
44 | 42 | from IPython.utils.coloransi import TermColors |
|
45 | from IPython.utils.py3compat import cast_unicode | |
|
46 | 43 | from IPython.utils.colorable import Colorable |
|
47 | 44 | from IPython.utils.decorators import undoc |
|
48 | 45 | |
@@ -106,21 +103,50 b' InspectColors = PyColorize.ANSICodeColors' | |||
|
106 | 103 | #**************************************************************************** |
|
107 | 104 | # Auxiliary functions and objects |
|
108 | 105 | |
|
109 | # See the messaging spec for the definition of all these fields. This list | |
|
110 | # effectively defines the order of display | |
|
111 | info_fields = ['type_name', 'base_class', 'string_form', 'namespace', | |
|
112 | 'length', 'file', 'definition', 'docstring', 'source', | |
|
113 | 'init_definition', 'class_docstring', 'init_docstring', | |
|
114 | 'call_def', 'call_docstring', | |
|
115 | # These won't be printed but will be used to determine how to | |
|
116 | # format the object | |
|
117 | 'ismagic', 'isalias', 'isclass', 'found', 'name' | |
|
118 | ] | |
|
106 | ||
|
107 | class InfoDict(TypedDict): | |
|
108 | type_name: Optional[str] | |
|
109 | base_class: Optional[str] | |
|
110 | string_form: Optional[str] | |
|
111 | namespace: Optional[str] | |
|
112 | length: Optional[str] | |
|
113 | file: Optional[str] | |
|
114 | definition: Optional[str] | |
|
115 | docstring: Optional[str] | |
|
116 | source: Optional[str] | |
|
117 | init_definition: Optional[str] | |
|
118 | class_docstring: Optional[str] | |
|
119 | init_docstring: Optional[str] | |
|
120 | call_def: Optional[str] | |
|
121 | call_docstring: Optional[str] | |
|
122 | subclasses: Optional[str] | |
|
123 | # These won't be printed but will be used to determine how to | |
|
124 | # format the object | |
|
125 | ismagic: bool | |
|
126 | isalias: bool | |
|
127 | isclass: bool | |
|
128 | found: bool | |
|
129 | name: str | |
|
130 | ||
|
131 | ||
|
132 | info_fields = list(InfoDict.__annotations__.keys()) | |
|
133 | ||
|
134 | ||
|
135 | @dataclass | |
|
136 | class InspectorHookData: | |
|
137 | """Data passed to the mime hook""" | |
|
138 | ||
|
139 | obj: Any | |
|
140 | info: Optional[OInfo] | |
|
141 | info_dict: InfoDict | |
|
142 | detail_level: int | |
|
143 | omit_sections: list[str] | |
|
119 | 144 | |
|
120 | 145 | |
|
146 | @undoc | |
|
121 | 147 | def object_info(**kw): |
|
122 | 148 | """Make an object info dict with all fields present.""" |
|
123 | infodict = {k:None for k in info_fields} | |
|
149 | infodict = {k: None for k in info_fields} | |
|
124 | 150 | infodict.update(kw) |
|
125 | 151 | return infodict |
|
126 | 152 | |
@@ -148,6 +174,7 b' def get_encoding(obj):' | |||
|
148 | 174 | encoding, _lines = openpy.detect_encoding(buffer.readline) |
|
149 | 175 | return encoding |
|
150 | 176 | |
|
177 | ||
|
151 | 178 | def getdoc(obj) -> Union[str,None]: |
|
152 | 179 | """Stable wrapper around inspect.getdoc. |
|
153 | 180 | |
@@ -761,6 +788,7 b' class Inspector(Colorable):' | |||
|
761 | 788 | """ |
|
762 | 789 | |
|
763 | 790 | info_dict = self.info(obj, oname=oname, info=info, detail_level=detail_level) |
|
791 | ||
|
764 | 792 | bundle = self._make_info_unformatted( |
|
765 | 793 | obj, |
|
766 | 794 | info_dict, |
@@ -768,10 +796,33 b' class Inspector(Colorable):' | |||
|
768 | 796 | detail_level=detail_level, |
|
769 | 797 | omit_sections=omit_sections, |
|
770 | 798 | ) |
|
771 |
|
|
|
772 | res = hook(obj, info) | |
|
773 |
|
|
|
774 |
|
|
|
799 | if self.mime_hooks: | |
|
800 | hook_data = InspectorHookData( | |
|
801 | obj=obj, | |
|
802 | info=info, | |
|
803 | info_dict=info_dict, | |
|
804 | detail_level=detail_level, | |
|
805 | omit_sections=omit_sections, | |
|
806 | ) | |
|
807 | for key, hook in self.mime_hooks.items(): | |
|
808 | required_parameters = [ | |
|
809 | parameter | |
|
810 | for parameter in inspect.signature(hook).parameters.values() | |
|
811 | if parameter.default != inspect.Parameter.default | |
|
812 | ] | |
|
813 | if len(required_parameters) == 1: | |
|
814 | res = hook(hook_data) | |
|
815 | else: | |
|
816 | warnings.warn( | |
|
817 | "MIME hook format changed in IPython 8.22; hooks should now accept" | |
|
818 | " a single parameter (InspectorHookData); support for hooks requiring" | |
|
819 | " two-parameters (obj and info) will be removed in a future version", | |
|
820 | DeprecationWarning, | |
|
821 | stacklevel=2, | |
|
822 | ) | |
|
823 | res = hook(obj, info) | |
|
824 | if res is not None: | |
|
825 | bundle[key] = res | |
|
775 | 826 | return self.format_mime(bundle) |
|
776 | 827 | |
|
777 | 828 | def pinfo( |
@@ -830,7 +881,7 b' class Inspector(Colorable):' | |||
|
830 | 881 | ) |
|
831 | 882 | return self.info(obj, oname=oname, info=info, detail_level=detail_level) |
|
832 | 883 | |
|
833 |
def info(self, obj, oname="", info=None, detail_level=0) -> Dict |
|
|
884 | def info(self, obj, oname="", info=None, detail_level=0) -> InfoDict: | |
|
834 | 885 | """Compute a dict with detailed information about an object. |
|
835 | 886 | |
|
836 | 887 | Parameters |
@@ -847,8 +898,7 b' class Inspector(Colorable):' | |||
|
847 | 898 | |
|
848 | 899 | Returns |
|
849 | 900 | ------- |
|
850 |
An object info dict with known fields from `info_fields` |
|
|
851 | strings, values are string or None. | |
|
901 | An object info dict with known fields from `info_fields` (see `InfoDict`). | |
|
852 | 902 | """ |
|
853 | 903 | |
|
854 | 904 | if info is None: |
@@ -867,8 +917,18 b' class Inspector(Colorable):' | |||
|
867 | 917 | if info and info.parent is not None and hasattr(info.parent, HOOK_NAME): |
|
868 | 918 | parents_docs_dict = getattr(info.parent, HOOK_NAME) |
|
869 | 919 | parents_docs = parents_docs_dict.get(att_name, None) |
|
870 |
out = |
|
|
871 | name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None | |
|
920 | out: InfoDict = cast( | |
|
921 | InfoDict, | |
|
922 | { | |
|
923 | **{field: None for field in info_fields}, | |
|
924 | **{ | |
|
925 | "name": oname, | |
|
926 | "found": True, | |
|
927 | "isalias": isalias, | |
|
928 | "ismagic": ismagic, | |
|
929 | "subclasses": None, | |
|
930 | }, | |
|
931 | }, | |
|
872 | 932 | ) |
|
873 | 933 | |
|
874 | 934 | if parents_docs: |
@@ -914,12 +974,14 b' class Inspector(Colorable):' | |||
|
914 | 974 | if detail_level >= self.str_detail_level: |
|
915 | 975 | try: |
|
916 | 976 | ostr = str(obj) |
|
917 | str_head = 'string_form' | |
|
918 | if not detail_level and len(ostr)>string_max: | |
|
977 | if not detail_level and len(ostr) > string_max: | |
|
919 | 978 | ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] |
|
920 | ostr = ("\n" + " " * len(str_head.expandtabs())).\ | |
|
921 | join(q.strip() for q in ostr.split("\n")) | |
|
922 | out[str_head] = ostr | |
|
979 | # TODO: `'string_form'.expandtabs()` seems wrong, but | |
|
980 | # it was (nearly) like this since the first commit ever. | |
|
981 | ostr = ("\n" + " " * len("string_form".expandtabs())).join( | |
|
982 | q.strip() for q in ostr.split("\n") | |
|
983 | ) | |
|
984 | out["string_form"] = ostr | |
|
923 | 985 | except: |
|
924 | 986 | pass |
|
925 | 987 | |
@@ -1054,7 +1116,7 b' class Inspector(Colorable):' | |||
|
1054 | 1116 | if call_ds: |
|
1055 | 1117 | out['call_docstring'] = call_ds |
|
1056 | 1118 | |
|
1057 |
return |
|
|
1119 | return out | |
|
1058 | 1120 | |
|
1059 | 1121 | @staticmethod |
|
1060 | 1122 | def _source_contains_docstring(src, doc): |
General Comments 0
You need to be logged in to leave comments.
Login now