pytermgui.inspector
This module provides introspection utilities.
The inspect
method can be used to create an Inspector
widget, which can
then be used to see what is happening inside any python object. This method is
usually preferred for instantiating an Inspector
, as it sets up overwriteable default
arguments passed to the new widget.
These defaults are meant to hide the non-important information when they are not needed,
in order to allow the least amount of code for the most usability. For example, by
default, when passed a class, inspect
will clip the docstrings to their first lines,
but show all methods. When an class' method is given it will hide show the full
docstring, and also use the method's fully qualified name.
View Source
0"""This module provides introspection utilities. 1 2The `inspect` method can be used to create an `Inspector` widget, which can 3then be used to see what is happening inside any python object. This method is 4usually preferred for instantiating an `Inspector`, as it sets up overwriteable default 5arguments passed to the new widget. 6 7These defaults are meant to hide the non-important information when they are not needed, 8in order to allow the least amount of code for the most usability. For example, by 9default, when passed a class, `inspect` will clip the docstrings to their first lines, 10but show all methods. When an class' method is given it will hide show the full 11docstring, and also use the method's fully qualified name. 12""" 13 14# pylint: disable=too-many-instance-attributes 15 16# Note: There are a lot of `type: ignore`-s in this file. These show up in places where 17# mypy sees potential for an error, but the possible error is already counteracted. 18 19from __future__ import annotations 20 21from enum import Enum, auto as _auto 22from typing import Any, Iterator 23 24from inspect import ( 25 signature, 26 isclass, 27 ismodule, 28 isfunction, 29 isbuiltin, 30 getdoc, 31 getfile, 32) 33 34from .parser import tim 35from .terminal import terminal 36from .prettifiers import prettify 37from .highlighters import highlight_python 38from .regex import real_length, RE_MARKUP 39from .widgets import Widget, Container, Label, boxes 40 41try: 42 from typing import get_origin # pylint: disable=ungrouped-imports 43 44except NameError: 45 46 def get_origin(_: object) -> Any: # type: ignore 47 """Spoofs typing.get_origin, which is used to determine type-hints. 48 49 Since this function is only available >=3.8, we need to have some 50 implementation on it for 3.7. The code checks for the origin to be 51 non-null, as that is the value returned by this method on non-typing 52 objects. 53 54 This will cause annotations to show up on 3.7, but not on 3.8+. 55 """ 56 57 return None 58 59 60__all__ = ["Inspector", "inspect"] 61 62 63class ObjectType(Enum): 64 """All types an object can be.""" 65 66 LIVE = _auto() 67 """An instance that does not fit the other types.""" 68 69 CLASS = _auto() 70 """A class object.""" 71 72 MODULE = _auto() 73 """A module object.""" 74 75 BUILTIN = _auto() 76 """Some sort of a builtin object. 77 78 As builtins are often implemented in C, a lot of the standard python APIs 79 won't work on them, so we need to treat them separately.""" 80 81 FUNCTION = _auto() 82 """A callable object, that is not a class.""" 83 84 85def _is_builtin(target: object) -> bool: 86 """Determines if the given target is a builtin.""" 87 88 try: 89 signature(target) # type: ignore 90 return False 91 92 except (ValueError, TypeError): 93 return True 94 95 96def _determine_type(target: object) -> ObjectType: 97 """Determines the type of an object.""" 98 99 if ismodule(target): 100 return ObjectType.MODULE 101 102 if _is_builtin(target): 103 return ObjectType.BUILTIN 104 105 if isclass(target): 106 return ObjectType.CLASS 107 108 if isfunction(target) or callable(target): 109 return ObjectType.FUNCTION 110 111 return ObjectType.LIVE 112 113 114def _is_type_alias(obj: object) -> bool: 115 """Determines whether the given object is (likely) a type alias.""" 116 117 return get_origin(obj) is not None 118 119 120INDENTED_EMPTY_BOX = boxes.Box( 121 [ 122 " ", 123 " x", 124 "", 125 ] 126) 127 128 129def inspect(target: object, **inspector_args) -> Inspector: 130 """Inspects an object. 131 132 Args: 133 obj: The object to inspect. 134 show_private: Whether `_private` attributes should be shown. 135 show_dunder: Whether `__dunder__` attributes should be shown. 136 show_methods: Whether methods should be shown when encountering a class. 137 show_full_doc: If not set, docstrings are cut to only include their first 138 line. 139 show_qualname: Show fully-qualified name, e.g. `module.submodule.name` 140 instead of `name`. 141 """ 142 143 def _conditionally_overwrite_kwarg(**kwargs) -> None: 144 for key, value in kwargs.items(): 145 if inspector_args.get(key) is None: 146 inspector_args[key] = value 147 148 if ismodule(target): 149 _conditionally_overwrite_kwarg( 150 show_dunder=False, 151 show_private=False, 152 show_full_doc=False, 153 show_methods=True, 154 show_qualname=False, 155 ) 156 157 elif isclass(target): 158 _conditionally_overwrite_kwarg( 159 show_dunder=False, 160 show_private=False, 161 show_full_doc=True, 162 show_methods=True, 163 show_qualname=False, 164 ) 165 166 elif callable(target) or isbuiltin(target): 167 _conditionally_overwrite_kwarg( 168 show_dunder=False, 169 show_private=False, 170 show_full_doc=True, 171 show_methods=False, 172 show_qualname=True, 173 ) 174 175 else: 176 _conditionally_overwrite_kwarg( 177 show_dunder=False, 178 show_private=False, 179 show_full_doc=True, 180 show_methods=True, 181 show_qualname=False, 182 ) 183 184 inspector = Inspector(**inspector_args).inspect(target) 185 186 return inspector 187 188 189class Inspector(Container): 190 """A widget to inspect any Python object.""" 191 192 def __init__( # pylint: disable=too-many-arguments 193 self, 194 target: object = None, 195 show_private: bool = False, 196 show_dunder: bool = False, 197 show_methods: bool = False, 198 show_full_doc: bool = False, 199 show_qualname: bool = True, 200 **attrs: Any, 201 ): 202 """Initializes an inspector. 203 204 Note that most of the time, using `inspect` to do this is going to be more 205 useful. 206 207 Some styles of the inspector can be changed using the `code.name`, 208 `code.file` and `code.keyword` markup aliases. The rest of the 209 highlighting is done using `pprint`, with all of its respective colors. 210 211 Args: 212 show_private: Whether `_private` attributes should be shown. 213 show_dunder: Whether `__dunder__` attributes should be shown. 214 show_methods: Whether methods should be shown when encountering a class. 215 show_full_doc: If not set, docstrings are cut to only include their first 216 line. 217 show_qualname: Show fully-qualified name, e.g. `module.submodule.name` 218 instead of `name`. 219 """ 220 221 if "box" not in attrs: 222 attrs["box"] = "EMPTY" 223 224 super().__init__(**attrs) 225 226 self.width = terminal.width 227 self.show_private = show_private 228 self.show_dunder = show_dunder 229 self.show_methods = show_methods 230 self.show_full_doc = show_full_doc 231 self.show_qualname = show_qualname 232 233 # TODO: Fix attr-showing 234 self.show_attrs = False 235 236 self.target: object 237 if target is not None: 238 self.inspect(target) 239 self.target = target 240 241 def _get_header(self) -> Container: 242 """Creates a header containing the name and location of the object.""" 243 244 header = Container(box="SINGLE") 245 246 line = "[code.name]" 247 if self.target_type is ObjectType.MODULE: 248 line += self.target.__name__ # type: ignore 249 250 else: 251 cls = ( 252 self.target 253 if isclass(self.target) or isfunction(self.target) 254 else self.target.__class__ 255 ) 256 line += cls.__module__ + "." + cls.__qualname__ # type: ignore 257 258 header += line 259 260 try: 261 file = getfile(self.target) # type: ignore 262 except TypeError: 263 return header 264 265 header += f"Located in [code.file !link(file://{file})]{file}[/]" 266 267 return header 268 269 def _get_definition(self) -> Label: 270 """Returns the definition str of self.target.""" 271 272 target = self.target 273 274 if self.show_qualname: 275 name = getattr(target, "__qualname__", type(target).__name__) 276 else: 277 name = getattr(target, "__name__", type(target).__name__) 278 279 if self.target_type == ObjectType.LIVE: 280 target = type(target) 281 282 otype = _determine_type(target) 283 284 keyword = "" 285 if otype == ObjectType.CLASS: 286 keyword = "class " 287 288 elif otype == ObjectType.FUNCTION: 289 keyword = "def " 290 291 try: 292 assert callable(target) 293 definition = self.highlight(keyword + name + str(signature(target)) + ":") 294 295 except (TypeError, ValueError, AssertionError): 296 definition = self.highlight(keyword + name + "(...)") 297 298 return Label(definition, parent_align=0, non_first_padding=4) 299 300 def _get_docs(self, padding: int) -> Iterator[Label]: 301 """Returns a list of Labels of the object's documentation.""" 302 303 if self.target.__doc__ is None: 304 return 305 306 doc = getdoc(self.target) 307 308 if doc is None: 309 return 310 311 for i, line in enumerate(doc.splitlines()): 312 if i == 1 and not self.show_full_doc: 313 return 314 315 line = line.replace("[", r"\[") 316 317 yield Label( 318 "[102]" + line, parent_align=0, padding=padding, non_first_padding=4 319 ) 320 321 def _get_keys(self) -> list[str]: 322 """Gets all inspectable keys of an object. 323 324 It first checks for an `__all__` attribute, and substitutes `dir` if not found. 325 Then, if there are too many keys and the given target is a module it tries to 326 list all of the present submodules. 327 """ 328 329 keys = getattr(self.target, "__all__", dir(self.target)) 330 331 if not self.show_dunder: 332 keys = [key for key in keys if not key.startswith("__")] 333 334 if not self.show_private: 335 keys = [key for key in keys if not (key.startswith("_") and key[1] != "_")] 336 337 if not self.show_methods: 338 keys = [ 339 key for key in keys if not callable(getattr(self.target, key, None)) 340 ] 341 342 keys.sort(key=lambda item: callable(getattr(self.target, item, None))) 343 344 return keys 345 346 def _get_preview(self) -> Container: 347 """Gets a Container with self.target inside.""" 348 349 preview = Container(static_width=self.width // 2, parent_align=0, box="SINGLE") 350 351 if isinstance(self.target, str) and RE_MARKUP.match(self.target) is not None: 352 preview += Label(prettify(self.target, parse=False), parent_align=0) 353 return preview 354 355 for line in prettify(self.target).splitlines(): 356 357 if real_length(line) > preview.width - preview.sidelength: 358 preview.width = real_length(line) + preview.sidelength 359 360 preview += Label("[str]" + tim.get_markup(line), parent_align=0) 361 362 preview.width = min(preview.width, self.terminal.width - preview.sidelength) 363 return preview 364 365 @staticmethod 366 def highlight(text: str) -> str: 367 """Applies highlighting to a given string. 368 369 This highlight includes keywords, builtin types and more. 370 371 Args: 372 text: The string to highlight. 373 374 Returns: 375 Unparsed markup. 376 """ 377 378 def _split(text: str, chars: str = " ,:|()[]{}") -> list[tuple[str, str]]: 379 """Splits given text by the given chars. 380 381 Args: 382 text: The text to split. 383 chars: A string of characters we will split by. 384 385 Returns: 386 A tuple of (delimiter, word) tuples. Delimiter is one of the characters 387 of `chars`. 388 """ 389 390 last_delim = "" 391 output = [] 392 word = "" 393 for char in text: 394 if char in chars: 395 output.append((last_delim, word)) 396 last_delim = char 397 word = "" 398 continue 399 400 word += char 401 402 output.append((last_delim, word)) 403 return output 404 405 buff = "" 406 for (delim, word) in _split(text): 407 stripped = word.strip("'") 408 highlighted = highlight_python(stripped) 409 410 if highlighted != stripped: 411 buff += delim + stripped 412 continue 413 414 buff += delim + stripped 415 416 return highlight_python(buff) 417 418 def inspect(self, target: object) -> Inspector: 419 """Inspects a given object, and sets self.target to it. 420 421 Returns: 422 Self, with the new content based on the inspection. 423 """ 424 425 self.target = target 426 self.target_type = _determine_type(target) 427 428 # Header 429 if self.box is not INDENTED_EMPTY_BOX: 430 self.lazy_add(self._get_header()) 431 432 # Body 433 if self.target_type is not ObjectType.MODULE: 434 self.lazy_add(self._get_definition()) 435 436 padding = 0 if self.target_type is ObjectType.MODULE else 4 437 438 for item in self._get_docs(padding): 439 self.lazy_add(item) 440 441 keys = self._get_keys() 442 443 for key in keys: 444 attr = getattr(target, key, None) 445 446 # Don't show type aliases 447 if _is_type_alias(attr): 448 continue 449 450 # Only show functions if they are not lambdas 451 if (isfunction(attr) or callable(attr)) and ( 452 hasattr(attr, "__name__") and not attr.__name__ == "<lambda>" 453 ): 454 self.lazy_add( 455 Inspector( 456 box=INDENTED_EMPTY_BOX, 457 show_dunder=self.show_dunder, 458 show_private=self.show_private, 459 show_full_doc=False, 460 show_qualname=self.show_qualname, 461 ).inspect(attr) 462 ) 463 continue 464 465 if not self.show_attrs: 466 continue 467 468 for i, line in enumerate(prettify(attr, parse=False).splitlines()): 469 if i == 0: 470 line = f"- {key}: {line}" 471 472 self.lazy_add(Label(line, parent_align=0)) 473 474 # Footer 475 if self.target_type in [ObjectType.LIVE, ObjectType.BUILTIN]: 476 self.lazy_add(self._get_preview()) 477 478 return self 479 480 def debug(self) -> str: 481 """Returns identifiable information used in repr.""" 482 483 if terminal.is_interactive and not terminal.displayhook_installed: 484 return "\n".join(self.get_lines()) 485 486 return Widget.debug(self)
View Source
190class Inspector(Container): 191 """A widget to inspect any Python object.""" 192 193 def __init__( # pylint: disable=too-many-arguments 194 self, 195 target: object = None, 196 show_private: bool = False, 197 show_dunder: bool = False, 198 show_methods: bool = False, 199 show_full_doc: bool = False, 200 show_qualname: bool = True, 201 **attrs: Any, 202 ): 203 """Initializes an inspector. 204 205 Note that most of the time, using `inspect` to do this is going to be more 206 useful. 207 208 Some styles of the inspector can be changed using the `code.name`, 209 `code.file` and `code.keyword` markup aliases. The rest of the 210 highlighting is done using `pprint`, with all of its respective colors. 211 212 Args: 213 show_private: Whether `_private` attributes should be shown. 214 show_dunder: Whether `__dunder__` attributes should be shown. 215 show_methods: Whether methods should be shown when encountering a class. 216 show_full_doc: If not set, docstrings are cut to only include their first 217 line. 218 show_qualname: Show fully-qualified name, e.g. `module.submodule.name` 219 instead of `name`. 220 """ 221 222 if "box" not in attrs: 223 attrs["box"] = "EMPTY" 224 225 super().__init__(**attrs) 226 227 self.width = terminal.width 228 self.show_private = show_private 229 self.show_dunder = show_dunder 230 self.show_methods = show_methods 231 self.show_full_doc = show_full_doc 232 self.show_qualname = show_qualname 233 234 # TODO: Fix attr-showing 235 self.show_attrs = False 236 237 self.target: object 238 if target is not None: 239 self.inspect(target) 240 self.target = target 241 242 def _get_header(self) -> Container: 243 """Creates a header containing the name and location of the object.""" 244 245 header = Container(box="SINGLE") 246 247 line = "[code.name]" 248 if self.target_type is ObjectType.MODULE: 249 line += self.target.__name__ # type: ignore 250 251 else: 252 cls = ( 253 self.target 254 if isclass(self.target) or isfunction(self.target) 255 else self.target.__class__ 256 ) 257 line += cls.__module__ + "." + cls.__qualname__ # type: ignore 258 259 header += line 260 261 try: 262 file = getfile(self.target) # type: ignore 263 except TypeError: 264 return header 265 266 header += f"Located in [code.file !link(file://{file})]{file}[/]" 267 268 return header 269 270 def _get_definition(self) -> Label: 271 """Returns the definition str of self.target.""" 272 273 target = self.target 274 275 if self.show_qualname: 276 name = getattr(target, "__qualname__", type(target).__name__) 277 else: 278 name = getattr(target, "__name__", type(target).__name__) 279 280 if self.target_type == ObjectType.LIVE: 281 target = type(target) 282 283 otype = _determine_type(target) 284 285 keyword = "" 286 if otype == ObjectType.CLASS: 287 keyword = "class " 288 289 elif otype == ObjectType.FUNCTION: 290 keyword = "def " 291 292 try: 293 assert callable(target) 294 definition = self.highlight(keyword + name + str(signature(target)) + ":") 295 296 except (TypeError, ValueError, AssertionError): 297 definition = self.highlight(keyword + name + "(...)") 298 299 return Label(definition, parent_align=0, non_first_padding=4) 300 301 def _get_docs(self, padding: int) -> Iterator[Label]: 302 """Returns a list of Labels of the object's documentation.""" 303 304 if self.target.__doc__ is None: 305 return 306 307 doc = getdoc(self.target) 308 309 if doc is None: 310 return 311 312 for i, line in enumerate(doc.splitlines()): 313 if i == 1 and not self.show_full_doc: 314 return 315 316 line = line.replace("[", r"\[") 317 318 yield Label( 319 "[102]" + line, parent_align=0, padding=padding, non_first_padding=4 320 ) 321 322 def _get_keys(self) -> list[str]: 323 """Gets all inspectable keys of an object. 324 325 It first checks for an `__all__` attribute, and substitutes `dir` if not found. 326 Then, if there are too many keys and the given target is a module it tries to 327 list all of the present submodules. 328 """ 329 330 keys = getattr(self.target, "__all__", dir(self.target)) 331 332 if not self.show_dunder: 333 keys = [key for key in keys if not key.startswith("__")] 334 335 if not self.show_private: 336 keys = [key for key in keys if not (key.startswith("_") and key[1] != "_")] 337 338 if not self.show_methods: 339 keys = [ 340 key for key in keys if not callable(getattr(self.target, key, None)) 341 ] 342 343 keys.sort(key=lambda item: callable(getattr(self.target, item, None))) 344 345 return keys 346 347 def _get_preview(self) -> Container: 348 """Gets a Container with self.target inside.""" 349 350 preview = Container(static_width=self.width // 2, parent_align=0, box="SINGLE") 351 352 if isinstance(self.target, str) and RE_MARKUP.match(self.target) is not None: 353 preview += Label(prettify(self.target, parse=False), parent_align=0) 354 return preview 355 356 for line in prettify(self.target).splitlines(): 357 358 if real_length(line) > preview.width - preview.sidelength: 359 preview.width = real_length(line) + preview.sidelength 360 361 preview += Label("[str]" + tim.get_markup(line), parent_align=0) 362 363 preview.width = min(preview.width, self.terminal.width - preview.sidelength) 364 return preview 365 366 @staticmethod 367 def highlight(text: str) -> str: 368 """Applies highlighting to a given string. 369 370 This highlight includes keywords, builtin types and more. 371 372 Args: 373 text: The string to highlight. 374 375 Returns: 376 Unparsed markup. 377 """ 378 379 def _split(text: str, chars: str = " ,:|()[]{}") -> list[tuple[str, str]]: 380 """Splits given text by the given chars. 381 382 Args: 383 text: The text to split. 384 chars: A string of characters we will split by. 385 386 Returns: 387 A tuple of (delimiter, word) tuples. Delimiter is one of the characters 388 of `chars`. 389 """ 390 391 last_delim = "" 392 output = [] 393 word = "" 394 for char in text: 395 if char in chars: 396 output.append((last_delim, word)) 397 last_delim = char 398 word = "" 399 continue 400 401 word += char 402 403 output.append((last_delim, word)) 404 return output 405 406 buff = "" 407 for (delim, word) in _split(text): 408 stripped = word.strip("'") 409 highlighted = highlight_python(stripped) 410 411 if highlighted != stripped: 412 buff += delim + stripped 413 continue 414 415 buff += delim + stripped 416 417 return highlight_python(buff) 418 419 def inspect(self, target: object) -> Inspector: 420 """Inspects a given object, and sets self.target to it. 421 422 Returns: 423 Self, with the new content based on the inspection. 424 """ 425 426 self.target = target 427 self.target_type = _determine_type(target) 428 429 # Header 430 if self.box is not INDENTED_EMPTY_BOX: 431 self.lazy_add(self._get_header()) 432 433 # Body 434 if self.target_type is not ObjectType.MODULE: 435 self.lazy_add(self._get_definition()) 436 437 padding = 0 if self.target_type is ObjectType.MODULE else 4 438 439 for item in self._get_docs(padding): 440 self.lazy_add(item) 441 442 keys = self._get_keys() 443 444 for key in keys: 445 attr = getattr(target, key, None) 446 447 # Don't show type aliases 448 if _is_type_alias(attr): 449 continue 450 451 # Only show functions if they are not lambdas 452 if (isfunction(attr) or callable(attr)) and ( 453 hasattr(attr, "__name__") and not attr.__name__ == "<lambda>" 454 ): 455 self.lazy_add( 456 Inspector( 457 box=INDENTED_EMPTY_BOX, 458 show_dunder=self.show_dunder, 459 show_private=self.show_private, 460 show_full_doc=False, 461 show_qualname=self.show_qualname, 462 ).inspect(attr) 463 ) 464 continue 465 466 if not self.show_attrs: 467 continue 468 469 for i, line in enumerate(prettify(attr, parse=False).splitlines()): 470 if i == 0: 471 line = f"- {key}: {line}" 472 473 self.lazy_add(Label(line, parent_align=0)) 474 475 # Footer 476 if self.target_type in [ObjectType.LIVE, ObjectType.BUILTIN]: 477 self.lazy_add(self._get_preview()) 478 479 return self 480 481 def debug(self) -> str: 482 """Returns identifiable information used in repr.""" 483 484 if terminal.is_interactive and not terminal.displayhook_installed: 485 return "\n".join(self.get_lines()) 486 487 return Widget.debug(self)
A widget to inspect any Python object.
View Source
193 def __init__( # pylint: disable=too-many-arguments 194 self, 195 target: object = None, 196 show_private: bool = False, 197 show_dunder: bool = False, 198 show_methods: bool = False, 199 show_full_doc: bool = False, 200 show_qualname: bool = True, 201 **attrs: Any, 202 ): 203 """Initializes an inspector. 204 205 Note that most of the time, using `inspect` to do this is going to be more 206 useful. 207 208 Some styles of the inspector can be changed using the `code.name`, 209 `code.file` and `code.keyword` markup aliases. The rest of the 210 highlighting is done using `pprint`, with all of its respective colors. 211 212 Args: 213 show_private: Whether `_private` attributes should be shown. 214 show_dunder: Whether `__dunder__` attributes should be shown. 215 show_methods: Whether methods should be shown when encountering a class. 216 show_full_doc: If not set, docstrings are cut to only include their first 217 line. 218 show_qualname: Show fully-qualified name, e.g. `module.submodule.name` 219 instead of `name`. 220 """ 221 222 if "box" not in attrs: 223 attrs["box"] = "EMPTY" 224 225 super().__init__(**attrs) 226 227 self.width = terminal.width 228 self.show_private = show_private 229 self.show_dunder = show_dunder 230 self.show_methods = show_methods 231 self.show_full_doc = show_full_doc 232 self.show_qualname = show_qualname 233 234 # TODO: Fix attr-showing 235 self.show_attrs = False 236 237 self.target: object 238 if target is not None: 239 self.inspect(target) 240 self.target = target
Initializes an inspector.
Note that most of the time, using inspect
to do this is going to be more
useful.
Some styles of the inspector can be changed using the code.name
,
code.file
and code.keyword
markup aliases. The rest of the
highlighting is done using pprint
, with all of its respective colors.
Args
- show_private: Whether
_private
attributes should be shown. - show_dunder: Whether
__dunder__
attributes should be shown. - show_methods: Whether methods should be shown when encountering a class.
- show_full_doc: If not set, docstrings are cut to only include their first line.
- show_qualname: Show fully-qualified name, e.g.
module.submodule.name
instead ofname
.
View Source
366 @staticmethod 367 def highlight(text: str) -> str: 368 """Applies highlighting to a given string. 369 370 This highlight includes keywords, builtin types and more. 371 372 Args: 373 text: The string to highlight. 374 375 Returns: 376 Unparsed markup. 377 """ 378 379 def _split(text: str, chars: str = " ,:|()[]{}") -> list[tuple[str, str]]: 380 """Splits given text by the given chars. 381 382 Args: 383 text: The text to split. 384 chars: A string of characters we will split by. 385 386 Returns: 387 A tuple of (delimiter, word) tuples. Delimiter is one of the characters 388 of `chars`. 389 """ 390 391 last_delim = "" 392 output = [] 393 word = "" 394 for char in text: 395 if char in chars: 396 output.append((last_delim, word)) 397 last_delim = char 398 word = "" 399 continue 400 401 word += char 402 403 output.append((last_delim, word)) 404 return output 405 406 buff = "" 407 for (delim, word) in _split(text): 408 stripped = word.strip("'") 409 highlighted = highlight_python(stripped) 410 411 if highlighted != stripped: 412 buff += delim + stripped 413 continue 414 415 buff += delim + stripped 416 417 return highlight_python(buff)
Applies highlighting to a given string.
This highlight includes keywords, builtin types and more.
Args
- text: The string to highlight.
Returns
Unparsed markup.
View Source
419 def inspect(self, target: object) -> Inspector: 420 """Inspects a given object, and sets self.target to it. 421 422 Returns: 423 Self, with the new content based on the inspection. 424 """ 425 426 self.target = target 427 self.target_type = _determine_type(target) 428 429 # Header 430 if self.box is not INDENTED_EMPTY_BOX: 431 self.lazy_add(self._get_header()) 432 433 # Body 434 if self.target_type is not ObjectType.MODULE: 435 self.lazy_add(self._get_definition()) 436 437 padding = 0 if self.target_type is ObjectType.MODULE else 4 438 439 for item in self._get_docs(padding): 440 self.lazy_add(item) 441 442 keys = self._get_keys() 443 444 for key in keys: 445 attr = getattr(target, key, None) 446 447 # Don't show type aliases 448 if _is_type_alias(attr): 449 continue 450 451 # Only show functions if they are not lambdas 452 if (isfunction(attr) or callable(attr)) and ( 453 hasattr(attr, "__name__") and not attr.__name__ == "<lambda>" 454 ): 455 self.lazy_add( 456 Inspector( 457 box=INDENTED_EMPTY_BOX, 458 show_dunder=self.show_dunder, 459 show_private=self.show_private, 460 show_full_doc=False, 461 show_qualname=self.show_qualname, 462 ).inspect(attr) 463 ) 464 continue 465 466 if not self.show_attrs: 467 continue 468 469 for i, line in enumerate(prettify(attr, parse=False).splitlines()): 470 if i == 0: 471 line = f"- {key}: {line}" 472 473 self.lazy_add(Label(line, parent_align=0)) 474 475 # Footer 476 if self.target_type in [ObjectType.LIVE, ObjectType.BUILTIN]: 477 self.lazy_add(self._get_preview()) 478 479 return self
Inspects a given object, and sets self.target to it.
Returns
Self, with the new content based on the inspection.
View Source
Returns identifiable information used in repr.
Inherited Members
- pytermgui.widgets.containers.Container
- styles
- chars
- keys
- serialized
- vertical_align
- allow_fullscreen
- overflow
- sidelength
- content_dimensions
- selectables
- selectables_length
- selected
- box
- get_change
- lazy_add
- get_lines
- set_widgets
- serialize
- pop
- remove
- set_recursive_depth
- select
- center
- handle_mouse
- execute_binding
- handle_key
- wipe
View Source
130def inspect(target: object, **inspector_args) -> Inspector: 131 """Inspects an object. 132 133 Args: 134 obj: The object to inspect. 135 show_private: Whether `_private` attributes should be shown. 136 show_dunder: Whether `__dunder__` attributes should be shown. 137 show_methods: Whether methods should be shown when encountering a class. 138 show_full_doc: If not set, docstrings are cut to only include their first 139 line. 140 show_qualname: Show fully-qualified name, e.g. `module.submodule.name` 141 instead of `name`. 142 """ 143 144 def _conditionally_overwrite_kwarg(**kwargs) -> None: 145 for key, value in kwargs.items(): 146 if inspector_args.get(key) is None: 147 inspector_args[key] = value 148 149 if ismodule(target): 150 _conditionally_overwrite_kwarg( 151 show_dunder=False, 152 show_private=False, 153 show_full_doc=False, 154 show_methods=True, 155 show_qualname=False, 156 ) 157 158 elif isclass(target): 159 _conditionally_overwrite_kwarg( 160 show_dunder=False, 161 show_private=False, 162 show_full_doc=True, 163 show_methods=True, 164 show_qualname=False, 165 ) 166 167 elif callable(target) or isbuiltin(target): 168 _conditionally_overwrite_kwarg( 169 show_dunder=False, 170 show_private=False, 171 show_full_doc=True, 172 show_methods=False, 173 show_qualname=True, 174 ) 175 176 else: 177 _conditionally_overwrite_kwarg( 178 show_dunder=False, 179 show_private=False, 180 show_full_doc=True, 181 show_methods=True, 182 show_qualname=False, 183 ) 184 185 inspector = Inspector(**inspector_args).inspect(target) 186 187 return inspector
Inspects an object.
Args
- obj: The object to inspect.
- show_private: Whether
_private
attributes should be shown. - show_dunder: Whether
__dunder__
attributes should be shown. - show_methods: Whether methods should be shown when encountering a class.
- show_full_doc: If not set, docstrings are cut to only include their first line.
- show_qualname: Show fully-qualified name, e.g.
module.submodule.name
instead ofname
.