def find_source_lines(obj): """Find the line number in a file where an object was defined. This is essentially a robust wrapper around `inspect.getsourcelines`. Returns None if no file can be found. Parameters ---------- obj : any Python object Returns ------- lineno : int The line number where the object definition starts. """ # get source if obj was decorated with @decorator if safe_hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ try: try: lineno = inspect.getsourcelines(obj)[1] except TypeError: # For instances, try the class object like getsource() does if hasattr(obj, '__class__'): lineno = inspect.getsourcelines(obj.__class__)[1] else: lineno = None except: return None return lineno
def find_file(obj): """Find the absolute path to the file where an object was defined. This is essentially a robust wrapper around `inspect.getabsfile`. Returns None if no file can be found. Parameters ---------- obj : any Python object Returns ------- fname : str The absolute path to the file where the object was defined. """ # get source if obj was decorated with @decorator if safe_hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ fname = None try: fname = inspect.getabsfile(obj) except TypeError: # For an instance, the file that matters is where its class was # declared. if hasattr(obj, '__class__'): try: fname = inspect.getabsfile(obj.__class__) except TypeError: # Can happen for builtins pass except: pass return cast_unicode(fname)
def find_file(obj): """Find the absolute path to the file where an object was defined. This is essentially a robust wrapper around `inspect.getabsfile`. Returns None if no file can be found. Parameters ---------- obj : any Python object Returns ------- fname : str The absolute path to the file where the object was defined. """ # get source if obj was decorated with @decorator if safe_hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ fname = None try: fname = inspect.getabsfile(obj) except TypeError: # For an instance, the file that matters is where its class was # declared. if hasattr(obj, '__class__'): try: fname = inspect.getabsfile(obj.__class__) except TypeError: # Can happen for builtins pass except: pass return cast_unicode(fname)
def find_source_lines(obj): """Find the line number in a file where an object was defined. This is essentially a robust wrapper around `inspect.getsourcelines`. Returns None if no file can be found. Parameters ---------- obj : any Python object Returns ------- lineno : int The line number where the object definition starts. """ # get source if obj was decorated with @decorator if safe_hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ try: try: lineno = inspect.getsourcelines(obj)[1] except TypeError: # For instances, try the class object like getsource() does if hasattr(obj, '__class__'): lineno = inspect.getsourcelines(obj.__class__)[1] else: lineno = None except: return None return lineno
def getargspec(obj): """Wrapper around :func:`inspect.getfullargspec` on Python 3, and :func:inspect.getargspec` on Python 2. In addition to functions and methods, this can also handle objects with a ``__call__`` attribute. """ if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): obj = obj.__call__ return inspect.getfullargspec(obj)
def getargspec(obj): """Wrapper around :func:`inspect.getfullargspec` on Python 3, and :func:inspect.getargspec` on Python 2. In addition to functions and methods, this can also handle objects with a ``__call__`` attribute. """ if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): obj = obj.__call__ return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
def getargspec(obj): """Wrapper around :func:`inspect.getfullargspec` on Python 3, and :func:inspect.getargspec` on Python 2. In addition to functions and methods, this can also handle objects with a ``__call__`` attribute. """ if not (inspect.isfunction(obj) or inspect.ismethod(obj)) \ and safe_hasattr(obj, '__call__'): obj = obj.__call__ return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
def _get_wrapped(obj): """Get the original object if wrapped in one or more @decorators Some objects automatically construct similar objects on any unrecognised attribute access (e.g. unittest.mock.call). To protect against infinite loops, this will arbitrarily cut off after 100 levels of obj.__wrapped__ attribute access. --TK, Jan 2016 """ orig_obj = obj i = 0 while safe_hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ i += 1 if i > 100: # __wrapped__ is probably a lie, so return the thing we started with return orig_obj return obj
def _get_wrapped(obj): """Get the original object if wrapped in one or more @decorators Some objects automatically construct similar objects on any unrecognised attribute access (e.g. unittest.mock.call). To protect against infinite loops, this will arbitrarily cut off after 100 levels of obj.__wrapped__ attribute access. --TK, Jan 2016 """ orig_obj = obj i = 0 while safe_hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ i += 1 if i > 100: # __wrapped__ is probably a lie, so return the thing we started with return orig_obj return obj
def getargspec(obj): """Wrapper around :func:`inspect.getfullargspec` In addition to functions and methods, this can also handle objects with a ``__call__`` attribute. DEPRECATED: Deprecated since 7.10. Do not use, will be removed. """ warnings.warn( '`getargspec` function is deprecated as of IPython 7.10' 'and will be removed in future versions.', DeprecationWarning, stacklevel=2) if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): obj = obj.__call__ return inspect.getfullargspec(obj)
def _get_source_definition(obj): """Get a source representation of the function definition.""" try: obj = _unwrap(obj) if dir2.safe_hasattr( obj, '__call__') and not oinspect.is_simple_callable(obj): obj = obj.__call__ lines, lnum = inspect.findsource(obj) block = inspect.getblock(lines[lnum:]) # Trim leading whitespace for all lines. prefix = re.match('^([ \t]*)', block[0]).group() trimmed = [] for line in block: if line.startswith(prefix): line = line[len(prefix):] trimmed.append(line) # Override the default join to avoid wrapping. def join_lines(source): return ''.join(source) module = ast.parse('\n'.join(trimmed), mode='exec') function = module.body[0] # Remove 'self' if it's the first arg. if function.args.args and function.args.args[0].arg == 'self': function.args.args.pop(0) function.body = [] decl = astor.to_source(function, indent_with='', pretty_source=join_lines).strip() # Strip the trailing `:` if decl.endswith(':'): decl = decl[:-1] return decl except Exception: # pylint: disable=broad-except return None
def info(self, obj, oname='', formatter=None, info=None, detail_level=0): """Compute a dict with detailed information about an object. Optional arguments: - oname: name of the variable pointing to the object. - formatter: special formatter for docstrings (see pdoc) - info: a structure with some information fields which may have been precomputed already. - detail_level: if set to 1, more information is given. """ obj_type = type(obj) if info is None: ismagic = 0 isalias = 0 ospace = '' else: ismagic = info.ismagic isalias = info.isalias ospace = info.namespace # Get docstring, special-casing aliases: if isalias: if not callable(obj): try: ds = "Alias to the system command:\n %s" % obj[1] except: ds = "Alias: " + str(obj) else: ds = "Alias to " + str(obj) if obj.__doc__: ds += "\nDocstring:\n" + obj.__doc__ else: ds = getdoc(obj) if ds is None: ds = '<no docstring>' if formatter is not None: ds = formatter(ds) # store output in a dict, we initialize it here and fill it as we go out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic) string_max = 200 # max size of strings to show (snipped if longer) shalf = int((string_max -5)/2) if ismagic: obj_type_name = 'Magic function' elif isalias: obj_type_name = 'System alias' else: obj_type_name = obj_type.__name__ out['type_name'] = obj_type_name try: bclass = obj.__class__ out['base_class'] = str(bclass) except: pass # String form, but snip if too long in ? form (full in ??) if detail_level >= self.str_detail_level: try: ostr = str(obj) str_head = 'string_form' if not detail_level and len(ostr)>string_max: ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] ostr = ("\n" + " " * len(str_head.expandtabs())).\ join(q.strip() for q in ostr.split("\n")) out[str_head] = ostr except: pass if ospace: out['namespace'] = ospace # Length (for strings and lists) try: out['length'] = str(len(obj)) except: pass # Filename where object was defined binary_file = False fname = find_file(obj) if fname is None: # if anything goes wrong, we don't want to show source, so it's as # if the file was binary binary_file = True else: if fname.endswith(('.so', '.dll', '.pyd')): binary_file = True elif fname.endswith('<string>'): fname = 'Dynamically generated function. No source code available.' out['file'] = fname # Docstrings only in detail 0 mode, since source contains them (we # avoid repetitions). If source fails, we add them back, see below. if ds and detail_level == 0: out['docstring'] = ds # Original source code for any callable if detail_level: # Flush the source cache because inspect can return out-of-date # source linecache.checkcache() source = None try: try: source = getsource(obj, binary_file) except TypeError: if hasattr(obj, '__class__'): source = getsource(obj.__class__, binary_file) if source is not None: out['source'] = source.rstrip() except Exception: pass if ds and source is None: out['docstring'] = ds # Constructor docstring for classes if inspect.isclass(obj): out['isclass'] = True # reconstruct the function definition and print it: try: obj_init = obj.__init__ except AttributeError: init_def = init_ds = None else: init_def = self._getdef(obj_init,oname) init_ds = getdoc(obj_init) # Skip Python's auto-generated docstrings if init_ds == _object_init_docstring: init_ds = None if init_def or init_ds: if init_def: out['init_definition'] = self.format(init_def) if init_ds: out['init_docstring'] = init_ds # and class docstring for instances: else: # reconstruct the function definition and print it: defln = self._getdef(obj, oname) if defln: out['definition'] = self.format(defln) # First, check whether the instance docstring is identical to the # class one, and print it separately if they don't coincide. In # most cases they will, but it's nice to print all the info for # objects which use instance-customized docstrings. if ds: try: cls = getattr(obj,'__class__') except: class_ds = None else: class_ds = getdoc(cls) # Skip Python's auto-generated docstrings if class_ds in _builtin_type_docstrings: class_ds = None if class_ds and ds != class_ds: out['class_docstring'] = class_ds # Next, try to show constructor docstrings try: init_ds = getdoc(obj.__init__) # Skip Python's auto-generated docstrings if init_ds == _object_init_docstring: init_ds = None except AttributeError: init_ds = None if init_ds: out['init_docstring'] = init_ds # Call form docstring for callable instances if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): call_def = self._getdef(obj.__call__, oname) if call_def: call_def = self.format(call_def) # it may never be the case that call def and definition differ, # but don't include the same signature twice if call_def != out.get('definition'): out['call_def'] = call_def call_ds = getdoc(obj.__call__) # Skip Python's auto-generated docstrings if call_ds == _func_call_docstring: call_ds = None if call_ds: out['call_docstring'] = call_ds # Compute the object's argspec as a callable. The key is to decide # whether to pull it from the object itself, from its __init__ or # from its __call__ method. if inspect.isclass(obj): # Old-style classes need not have an __init__ callable_obj = getattr(obj, "__init__", None) elif callable(obj): callable_obj = obj else: callable_obj = None if callable_obj: try: argspec = getargspec(callable_obj) except (TypeError, AttributeError): # For extensions/builtins we can't retrieve the argspec pass else: # named tuples' _asdict() method returns an OrderedDict, but we # we want a normal out['argspec'] = argspec_dict = dict(argspec._asdict()) # We called this varkw before argspec became a named tuple. # With getfullargspec it's also called varkw. if 'varkw' not in argspec_dict: argspec_dict['varkw'] = argspec_dict.pop('keywords') return object_info(**out)
def _get_wrapped(obj): """Get the original object if wrapped in one or more @decorators""" while safe_hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ return obj
def _get_wrapped(obj): """Get the original object if wrapped in one or more @decorators""" while safe_hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ return obj
def info(self, obj, oname='', formatter=None, info=None, detail_level=0): """Compute a dict with detailed information about an object. Optional arguments: - oname: name of the variable pointing to the object. - formatter: special formatter for docstrings (see pdoc) - info: a structure with some information fields which may have been precomputed already. - detail_level: if set to 1, more information is given. """ obj_type = type(obj) header = self.__head if info is None: ismagic = 0 isalias = 0 ospace = '' else: ismagic = info.ismagic isalias = info.isalias ospace = info.namespace # Get docstring, special-casing aliases: if isalias: if not callable(obj): try: ds = "Alias to the system command:\n %s" % obj[1] except: ds = "Alias: " + str(obj) else: ds = "Alias to " + str(obj) if obj.__doc__: ds += "\nDocstring:\n" + obj.__doc__ else: ds = getdoc(obj) if ds is None: ds = '<no docstring>' if formatter is not None: ds = formatter(ds) # store output in a dict, we initialize it here and fill it as we go out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic) string_max = 200 # max size of strings to show (snipped if longer) shalf = int((string_max - 5) / 2) if ismagic: obj_type_name = 'Magic function' elif isalias: obj_type_name = 'System alias' else: obj_type_name = obj_type.__name__ out['type_name'] = obj_type_name try: bclass = obj.__class__ out['base_class'] = str(bclass) except: pass # String form, but snip if too long in ? form (full in ??) if detail_level >= self.str_detail_level: try: ostr = str(obj) str_head = 'string_form' if not detail_level and len(ostr) > string_max: ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] ostr = ("\n" + " " * len(str_head.expandtabs())).\ join(q.strip() for q in ostr.split("\n")) out[str_head] = ostr except: pass if ospace: out['namespace'] = ospace # Length (for strings and lists) try: out['length'] = str(len(obj)) except: pass # Filename where object was defined binary_file = False fname = find_file(obj) if fname is None: # if anything goes wrong, we don't want to show source, so it's as # if the file was binary binary_file = True else: if fname.endswith(('.so', '.dll', '.pyd')): binary_file = True elif fname.endswith('<string>'): fname = 'Dynamically generated function. No source code available.' out['file'] = fname # reconstruct the function definition and print it: defln = self._getdef(obj, oname) if defln: out['definition'] = self.format(defln) # Docstrings only in detail 0 mode, since source contains them (we # avoid repetitions). If source fails, we add them back, see below. if ds and detail_level == 0: out['docstring'] = ds # Original source code for any callable if detail_level: # Flush the source cache because inspect can return out-of-date # source linecache.checkcache() source = None try: try: source = getsource(obj, binary_file) except TypeError: if hasattr(obj, '__class__'): source = getsource(obj.__class__, binary_file) if source is not None: out['source'] = source.rstrip() except Exception: pass if ds and source is None: out['docstring'] = ds # Constructor docstring for classes if inspect.isclass(obj): out['isclass'] = True # reconstruct the function definition and print it: try: obj_init = obj.__init__ except AttributeError: init_def = init_ds = None else: init_def = self._getdef(obj_init, oname) init_ds = getdoc(obj_init) # Skip Python's auto-generated docstrings if init_ds and \ init_ds.startswith('x.__init__(...) initializes'): init_ds = None if init_def or init_ds: if init_def: out['init_definition'] = self.format(init_def) if init_ds: out['init_docstring'] = init_ds # and class docstring for instances: else: # First, check whether the instance docstring is identical to the # class one, and print it separately if they don't coincide. In # most cases they will, but it's nice to print all the info for # objects which use instance-customized docstrings. if ds: try: cls = getattr(obj, '__class__') except: class_ds = None else: class_ds = getdoc(cls) # Skip Python's auto-generated docstrings if class_ds and \ (class_ds.startswith('function(code, globals[,') or \ class_ds.startswith('instancemethod(function, instance,') or \ class_ds.startswith('module(name[,') ): class_ds = None if class_ds and ds != class_ds: out['class_docstring'] = class_ds # Next, try to show constructor docstrings try: init_ds = getdoc(obj.__init__) # Skip Python's auto-generated docstrings if init_ds and \ init_ds.startswith('x.__init__(...) initializes'): init_ds = None except AttributeError: init_ds = None if init_ds: out['init_docstring'] = init_ds # Call form docstring for callable instances if safe_hasattr(obj, '__call__'): call_def = self._getdef(obj.__call__, oname) if call_def is not None: out['call_def'] = self.format(call_def) call_ds = getdoc(obj.__call__) # Skip Python's auto-generated docstrings if call_ds and call_ds.startswith( 'x.__call__(...) <==> x(...)'): call_ds = None if call_ds: out['call_docstring'] = call_ds # Compute the object's argspec as a callable. The key is to decide # whether to pull it from the object itself, from its __init__ or # from its __call__ method. if inspect.isclass(obj): # Old-style classes need not have an __init__ callable_obj = getattr(obj, "__init__", None) elif callable(obj): callable_obj = obj else: callable_obj = None if callable_obj: try: args, varargs, varkw, defaults = getargspec(callable_obj) except (TypeError, AttributeError): # For extensions/builtins we can't retrieve the argspec pass else: out['argspec'] = dict(args=args, varargs=varargs, varkw=varkw, defaults=defaults) return object_info(**out)
def _info(self, obj, oname='', info=None, detail_level=0) -> dict: """Compute a dict with detailed information about an object. Parameters ========== obj: any An object to find information about oname: str (default: ''): Name of the variable pointing to `obj`. info: (default: None) A struct (dict like with attr access) with some information fields which may have been precomputed already. detail_level: int (default:0) If set to 1, more information is given. Returns ======= An object info dict with known fields from `info_fields`. """ if info is None: ismagic = False isalias = False ospace = '' else: ismagic = info.ismagic isalias = info.isalias ospace = info.namespace # Get docstring, special-casing aliases: if isalias: if not callable(obj): try: ds = "Alias to the system command:\n %s" % obj[1] except: ds = "Alias: " + str(obj) else: ds = "Alias to " + str(obj) if obj.__doc__: ds += "\nDocstring:\n" + obj.__doc__ else: ds = getdoc(obj) if ds is None: ds = '<no docstring>' # store output in a dict, we initialize it here and fill it as we go out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None) string_max = 200 # max size of strings to show (snipped if longer) shalf = int((string_max - 5) / 2) if ismagic: out['type_name'] = 'Magic function' elif isalias: out['type_name'] = 'System alias' else: out['type_name'] = type(obj).__name__ try: bclass = obj.__class__ out['base_class'] = str(bclass) except: pass # String form, but snip if too long in ? form (full in ??) if detail_level >= self.str_detail_level: try: ostr = str(obj) str_head = 'string_form' if not detail_level and len(ostr)>string_max: ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] ostr = ("\n" + " " * len(str_head.expandtabs())).\ join(q.strip() for q in ostr.split("\n")) out[str_head] = ostr except: pass if ospace: out['namespace'] = ospace # Length (for strings and lists) try: out['length'] = str(len(obj)) except Exception: pass # Filename where object was defined binary_file = False fname = find_file(obj) if fname is None: # if anything goes wrong, we don't want to show source, so it's as # if the file was binary binary_file = True else: if fname.endswith(('.so', '.dll', '.pyd')): binary_file = True elif fname.endswith('<string>'): fname = 'Dynamically generated function. No source code available.' out['file'] = compress_user(fname) # Original source code for a callable, class or property. if detail_level: # Flush the source cache because inspect can return out-of-date # source linecache.checkcache() try: if isinstance(obj, property) or not binary_file: src = getsource(obj, oname) if src is not None: src = src.rstrip() out['source'] = src except Exception: pass # Add docstring only if no source is to be shown (avoid repetitions). if ds and not self._source_contains_docstring(out.get('source'), ds): out['docstring'] = ds # Constructor docstring for classes if inspect.isclass(obj): out['isclass'] = True # get the init signature: try: init_def = self._getdef(obj, oname) except AttributeError: init_def = None # get the __init__ docstring try: obj_init = obj.__init__ except AttributeError: init_ds = None else: if init_def is None: # Get signature from init if top-level sig failed. # Can happen for built-in types (list, etc.). try: init_def = self._getdef(obj_init, oname) except AttributeError: pass init_ds = getdoc(obj_init) # Skip Python's auto-generated docstrings if init_ds == _object_init_docstring: init_ds = None if init_def: out['init_definition'] = init_def if init_ds: out['init_docstring'] = init_ds names = [sub.__name__ for sub in obj.__subclasses__()] if len(names) < 10: all_names = ', '.join(names) else: all_names = ', '.join(names[:10]+['...']) out['subclasses'] = all_names # and class docstring for instances: else: # reconstruct the function definition and print it: defln = self._getdef(obj, oname) if defln: out['definition'] = defln # First, check whether the instance docstring is identical to the # class one, and print it separately if they don't coincide. In # most cases they will, but it's nice to print all the info for # objects which use instance-customized docstrings. if ds: try: cls = getattr(obj,'__class__') except: class_ds = None else: class_ds = getdoc(cls) # Skip Python's auto-generated docstrings if class_ds in _builtin_type_docstrings: class_ds = None if class_ds and ds != class_ds: out['class_docstring'] = class_ds # Next, try to show constructor docstrings try: init_ds = getdoc(obj.__init__) # Skip Python's auto-generated docstrings if init_ds == _object_init_docstring: init_ds = None except AttributeError: init_ds = None if init_ds: out['init_docstring'] = init_ds # Call form docstring for callable instances if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): call_def = self._getdef(obj.__call__, oname) if call_def and (call_def != out.get('definition')): # it may never be the case that call def and definition differ, # but don't include the same signature twice out['call_def'] = call_def call_ds = getdoc(obj.__call__) # Skip Python's auto-generated docstrings if call_ds == _func_call_docstring: call_ds = None if call_ds: out['call_docstring'] = call_ds # Compute the object's argspec as a callable. The key is to decide # whether to pull it from the object itself, from its __init__ or # from its __call__ method. if inspect.isclass(obj): # Old-style classes need not have an __init__ callable_obj = getattr(obj, "__init__", None) elif callable(obj): callable_obj = obj else: callable_obj = None if callable_obj is not None: try: argspec = getargspec(callable_obj) except Exception: # For extensions/builtins we can't retrieve the argspec pass else: # named tuples' _asdict() method returns an OrderedDict, but we # we want a normal out['argspec'] = argspec_dict = dict(argspec._asdict()) # We called this varkw before argspec became a named tuple. # With getfullargspec it's also called varkw. if 'varkw' not in argspec_dict: argspec_dict['varkw'] = argspec_dict.pop('keywords') return object_info(**out)
def _info(self, obj, oname='', info=None, detail_level=0) -> dict: """Compute a dict with detailed information about an object. Parameters ========== obj: any An object to find information about oname: str (default: ''): Name of the variable pointing to `obj`. info: (default: None) A struct (dict like with attr access) with some information fields which may have been precomputed already. detail_level: int (default:0) If set to 1, more information is given. Returns ======= An object info dict with known fields from `info_fields`. """ if info is None: ismagic = False isalias = False ospace = '' else: ismagic = info.ismagic isalias = info.isalias ospace = info.namespace # Get docstring, special-casing aliases: if isalias: if not callable(obj): try: ds = "Alias to the system command:\n %s" % obj[1] except: ds = "Alias: " + str(obj) else: ds = "Alias to " + str(obj) if obj.__doc__: ds += "\nDocstring:\n" + obj.__doc__ else: ds = getdoc(obj) if ds is None: ds = '<no docstring>' # store output in a dict, we initialize it here and fill it as we go out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic, subclasses=None) string_max = 200 # max size of strings to show (snipped if longer) shalf = int((string_max - 5) / 2) if ismagic: out['type_name'] = 'Magic function' elif isalias: out['type_name'] = 'System alias' else: out['type_name'] = type(obj).__name__ try: bclass = obj.__class__ out['base_class'] = str(bclass) except: pass # String form, but snip if too long in ? form (full in ??) if detail_level >= self.str_detail_level: try: ostr = str(obj) str_head = 'string_form' if not detail_level and len(ostr) > string_max: ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:] ostr = ("\n" + " " * len(str_head.expandtabs())).\ join(q.strip() for q in ostr.split("\n")) out[str_head] = ostr except: pass if ospace: out['namespace'] = ospace # Length (for strings and lists) try: out['length'] = str(len(obj)) except Exception: pass # Filename where object was defined binary_file = False fname = find_file(obj) if fname is None: # if anything goes wrong, we don't want to show source, so it's as # if the file was binary binary_file = True else: if fname.endswith(('.so', '.dll', '.pyd')): binary_file = True elif fname.endswith('<string>'): fname = 'Dynamically generated function. No source code available.' out['file'] = compress_user(fname) # Original source code for a callable, class or property. if detail_level: # Flush the source cache because inspect can return out-of-date # source linecache.checkcache() try: if isinstance(obj, property) or not binary_file: src = getsource(obj, oname) if src is not None: src = src.rstrip() out['source'] = src except Exception: pass # Add docstring only if no source is to be shown (avoid repetitions). if ds and not self._source_contains_docstring(out.get('source'), ds): out['docstring'] = ds # Constructor docstring for classes if inspect.isclass(obj): out['isclass'] = True # get the init signature: try: init_def = self._getdef(obj, oname) except AttributeError: init_def = None # get the __init__ docstring try: obj_init = obj.__init__ except AttributeError: init_ds = None else: if init_def is None: # Get signature from init if top-level sig failed. # Can happen for built-in types (list, etc.). try: init_def = self._getdef(obj_init, oname) except AttributeError: pass init_ds = getdoc(obj_init) # Skip Python's auto-generated docstrings if init_ds == _object_init_docstring: init_ds = None if init_def: out['init_definition'] = init_def if init_ds: out['init_docstring'] = init_ds names = [sub.__name__ for sub in type.__subclasses__(obj)] if len(names) < 10: all_names = ', '.join(names) else: all_names = ', '.join(names[:10] + ['...']) out['subclasses'] = all_names # and class docstring for instances: else: # reconstruct the function definition and print it: defln = self._getdef(obj, oname) if defln: out['definition'] = defln # First, check whether the instance docstring is identical to the # class one, and print it separately if they don't coincide. In # most cases they will, but it's nice to print all the info for # objects which use instance-customized docstrings. if ds: try: cls = getattr(obj, '__class__') except: class_ds = None else: class_ds = getdoc(cls) # Skip Python's auto-generated docstrings if class_ds in _builtin_type_docstrings: class_ds = None if class_ds and ds != class_ds: out['class_docstring'] = class_ds # Next, try to show constructor docstrings try: init_ds = getdoc(obj.__init__) # Skip Python's auto-generated docstrings if init_ds == _object_init_docstring: init_ds = None except AttributeError: init_ds = None if init_ds: out['init_docstring'] = init_ds # Call form docstring for callable instances if safe_hasattr(obj, '__call__') and not is_simple_callable(obj): call_def = self._getdef(obj.__call__, oname) if call_def and (call_def != out.get('definition')): # it may never be the case that call def and definition differ, # but don't include the same signature twice out['call_def'] = call_def call_ds = getdoc(obj.__call__) # Skip Python's auto-generated docstrings if call_ds == _func_call_docstring: call_ds = None if call_ds: out['call_docstring'] = call_ds # Compute the object's argspec as a callable. The key is to decide # whether to pull it from the object itself, from its __init__ or # from its __call__ method. if inspect.isclass(obj): # Old-style classes need not have an __init__ callable_obj = getattr(obj, "__init__", None) elif callable(obj): callable_obj = obj else: callable_obj = None if callable_obj is not None: try: argspec = getargspec(callable_obj) except Exception: # For extensions/builtins we can't retrieve the argspec pass else: # named tuples' _asdict() method returns an OrderedDict, but we # we want a normal out['argspec'] = argspec_dict = dict(argspec._asdict()) # We called this varkw before argspec became a named tuple. # With getfullargspec it's also called varkw. if 'varkw' not in argspec_dict: argspec_dict['varkw'] = argspec_dict.pop('keywords') return object_info(**out)