Show More
@@ -24,9 +24,7 b' import os' | |||||
24 | import types |
|
24 | import types | |
25 | import warnings |
|
25 | import warnings | |
26 |
|
26 | |||
27 | from typing import Any, Optional, Dict, Union, List, Tuple |
|
27 | from typing import cast, Any, Optional, Dict, Union, List, TypedDict, TypeAlias, Tuple | |
28 |
|
||||
29 | from typing import TypeAlias |
|
|||
30 |
|
28 | |||
31 | import traitlets |
|
29 | import traitlets | |
32 |
|
30 | |||
@@ -42,7 +40,6 b' from IPython.utils.text import indent' | |||||
42 | from IPython.utils.wildcard import list_namespace |
|
40 | from IPython.utils.wildcard import list_namespace | |
43 | from IPython.utils.wildcard import typestr2type |
|
41 | from IPython.utils.wildcard import typestr2type | |
44 | from IPython.utils.coloransi import TermColors |
|
42 | from IPython.utils.coloransi import TermColors | |
45 | from IPython.utils.py3compat import cast_unicode |
|
|||
46 | from IPython.utils.colorable import Colorable |
|
43 | from IPython.utils.colorable import Colorable | |
47 | from IPython.utils.decorators import undoc |
|
44 | from IPython.utils.decorators import undoc | |
48 |
|
45 | |||
@@ -106,18 +103,47 b' InspectColors = PyColorize.ANSICodeColors' | |||||
106 | #**************************************************************************** |
|
103 | #**************************************************************************** | |
107 | # Auxiliary functions and objects |
|
104 | # Auxiliary functions and objects | |
108 |
|
105 | |||
109 | # See the messaging spec for the definition of all these fields. This list |
|
106 | ||
110 | # effectively defines the order of display |
|
107 | class InfoDict(TypedDict): | |
111 | info_fields = ['type_name', 'base_class', 'string_form', 'namespace', |
|
108 | type_name: Optional[str] | |
112 | 'length', 'file', 'definition', 'docstring', 'source', |
|
109 | base_class: Optional[str] | |
113 | 'init_definition', 'class_docstring', 'init_docstring', |
|
110 | string_form: Optional[str] | |
114 | 'call_def', 'call_docstring', |
|
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] | |||
115 |
|
|
123 | # These won't be printed but will be used to determine how to | |
116 |
|
|
124 | # format the object | |
117 | 'ismagic', 'isalias', 'isclass', 'found', 'name' |
|
125 | ismagic: bool | |
118 | ] |
|
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 | def object_info(**kw): |
|
147 | def object_info(**kw): | |
122 | """Make an object info dict with all fields present.""" |
|
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} | |
@@ -148,6 +174,7 b' def get_encoding(obj):' | |||||
148 | encoding, _lines = openpy.detect_encoding(buffer.readline) |
|
174 | encoding, _lines = openpy.detect_encoding(buffer.readline) | |
149 | return encoding |
|
175 | return encoding | |
150 |
|
176 | |||
|
177 | ||||
151 | def getdoc(obj) -> Union[str,None]: |
|
178 | def getdoc(obj) -> Union[str,None]: | |
152 | """Stable wrapper around inspect.getdoc. |
|
179 | """Stable wrapper around inspect.getdoc. | |
153 |
|
180 | |||
@@ -761,6 +788,7 b' class Inspector(Colorable):' | |||||
761 | """ |
|
788 | """ | |
762 |
|
789 | |||
763 | info_dict = self.info(obj, oname=oname, info=info, detail_level=detail_level) |
|
790 | info_dict = self.info(obj, oname=oname, info=info, detail_level=detail_level) | |
|
791 | ||||
764 | bundle = self._make_info_unformatted( |
|
792 | bundle = self._make_info_unformatted( | |
765 | obj, |
|
793 | obj, | |
766 | info_dict, |
|
794 | info_dict, | |
@@ -768,7 +796,30 b' class Inspector(Colorable):' | |||||
768 | detail_level=detail_level, |
|
796 | detail_level=detail_level, | |
769 | omit_sections=omit_sections, |
|
797 | omit_sections=omit_sections, | |
770 | ) |
|
798 | ) | |
|
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 | ) | |||
771 | for key, hook in self.mime_hooks.items(): |
|
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 | ) | |||
772 | res = hook(obj, info) |
|
823 | res = hook(obj, info) | |
773 | if res is not None: |
|
824 | if res is not None: | |
774 | bundle[key] = res |
|
825 | bundle[key] = res | |
@@ -830,7 +881,7 b' class Inspector(Colorable):' | |||||
830 | ) |
|
881 | ) | |
831 | return self.info(obj, oname=oname, info=info, detail_level=detail_level) |
|
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 | """Compute a dict with detailed information about an object. |
|
885 | """Compute a dict with detailed information about an object. | |
835 |
|
886 | |||
836 | Parameters |
|
887 | Parameters | |
@@ -847,8 +898,7 b' class Inspector(Colorable):' | |||||
847 |
|
898 | |||
848 | Returns |
|
899 | Returns | |
849 | ------- |
|
900 | ------- | |
850 |
An object info dict with known fields from `info_fields` |
|
901 | An object info dict with known fields from `info_fields` (see `InfoDict`). | |
851 | strings, values are string or None. |
|
|||
852 | """ |
|
902 | """ | |
853 |
|
903 | |||
854 | if info is None: |
|
904 | if info is None: | |
@@ -867,8 +917,18 b' class Inspector(Colorable):' | |||||
867 | if info and info.parent is not None and hasattr(info.parent, HOOK_NAME): |
|
917 | if info and info.parent is not None and hasattr(info.parent, HOOK_NAME): | |
868 | parents_docs_dict = getattr(info.parent, HOOK_NAME) |
|
918 | parents_docs_dict = getattr(info.parent, HOOK_NAME) | |
869 | parents_docs = parents_docs_dict.get(att_name, None) |
|
919 | parents_docs = parents_docs_dict.get(att_name, None) | |
870 |
out = |
|
920 | out: InfoDict = cast( | |
871 | name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None |
|
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 | if parents_docs: |
|
934 | if parents_docs: | |
@@ -914,12 +974,14 b' class Inspector(Colorable):' | |||||
914 | if detail_level >= self.str_detail_level: |
|
974 | if detail_level >= self.str_detail_level: | |
915 | try: |
|
975 | try: | |
916 | ostr = str(obj) |
|
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 | ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] |
|
978 | ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] | |
920 | ostr = ("\n" + " " * len(str_head.expandtabs())).\ |
|
979 | # TODO: `'string_form'.expandtabs()` seems wrong, but | |
921 | join(q.strip() for q in ostr.split("\n")) |
|
980 | # it was (nearly) like this since the first commit ever. | |
922 | out[str_head] = ostr |
|
981 | ostr = ("\n" + " " * len("string_form".expandtabs())).join( | |
|
982 | q.strip() for q in ostr.split("\n") | |||
|
983 | ) | |||
|
984 | out["string_form"] = ostr | |||
923 | except: |
|
985 | except: | |
924 | pass |
|
986 | pass | |
925 |
|
987 | |||
@@ -1054,7 +1116,7 b' class Inspector(Colorable):' | |||||
1054 | if call_ds: |
|
1116 | if call_ds: | |
1055 | out['call_docstring'] = call_ds |
|
1117 | out['call_docstring'] = call_ds | |
1056 |
|
1118 | |||
1057 |
return |
|
1119 | return out | |
1058 |
|
1120 | |||
1059 | @staticmethod |
|
1121 | @staticmethod | |
1060 | def _source_contains_docstring(src, doc): |
|
1122 | def _source_contains_docstring(src, doc): |
General Comments 0
You need to be logged in to leave comments.
Login now