##// END OF EJS Templates
Improve typing and MIME hook API for inspector (#14342)...
M Bussonnier -
r28661:2084e7f3 merge
parent child Browse files
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,21 +103,50 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]
115 # These won't be printed but will be used to determine how to
112 length: Optional[str]
116 # format the object
113 file: Optional[str]
117 'ismagic', 'isalias', 'isclass', 'found', 'name'
114 definition: Optional[str]
118 ]
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 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}
124 infodict.update(kw)
150 infodict.update(kw)
125 return infodict
151 return infodict
126
152
@@ -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,10 +796,33 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 )
771 for key, hook in self.mime_hooks.items():
799 if self.mime_hooks:
772 res = hook(obj, info)
800 hook_data = InspectorHookData(
773 if res is not None:
801 obj=obj,
774 bundle[key] = res
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 return self.format_mime(bundle)
826 return self.format_mime(bundle)
776
827
777 def pinfo(
828 def pinfo(
@@ -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[str, Any]:
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`. Keys are
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 = dict(
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'
977 if not detail_level and len(ostr) > string_max:
918 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 object_info(**out)
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