diff options
Diffstat (limited to 'sources/pyside6/doc/import_inheritance.py')
-rw-r--r-- | sources/pyside6/doc/import_inheritance.py | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/sources/pyside6/doc/import_inheritance.py b/sources/pyside6/doc/import_inheritance.py new file mode 100644 index 000000000..e694941c9 --- /dev/null +++ b/sources/pyside6/doc/import_inheritance.py @@ -0,0 +1,152 @@ +import inspect +import sys + +"""Helpers for determining base classes by importing the class. +When passed something like: + PySide6.QtCore.QStateMachine.SignalEvent +try to import the underlying module and return a +handle to the object. In a loop, import + PySide6.QtCore.QStateMachine.SignalEvent + PySide6.QtCore.QStateMachine + PySide6.QtCore +until the import succeeds and walk up the attributes +to obtain the object.""" + + +TEST_DRIVER_USAGE = """Usage: import_inheritance.py class_name [current_module] + +Example: +python import_inheritance.py PySide6.QtWidgets.QWizard PySide6.QtWidgets +""" + + +class InheritanceException(Exception): + pass + + +def _importClassOrModule(name): + components = name.split('.') + for i in range(len(components), 0, -1): + importPath = '.'.join(components[: i]) + try: + __import__(importPath) + except ImportError: + continue + if i == len(components): + return sys.modules[importPath] + remaining = components[i:] + cls = sys.modules[importPath] + for component in remaining: + try: + cls = getattr(cls, component) + except Exception: # No such attribute + return None + return cls + return None + + +def _import_class_or_module(name, currmodule): + """ + Import a class using its fully-qualified *name*. + """ + todoc = _importClassOrModule(name) + if not todoc and currmodule is not None: + todoc = _importClassOrModule(f"{currmodule}.{name}") + if not todoc: + moduleStr = f'(module {currmodule})' if currmodule else '' + raise InheritanceException(f'Could not import class {name} specified for ' + f'inheritance diagram {moduleStr}.') + if inspect.isclass(todoc): + return [todoc] + elif inspect.ismodule(todoc): + classes = [] + for cls in todoc.__dict__.values(): + if inspect.isclass(cls) and cls.__module__ == todoc.__name__: + classes.append(cls) + return classes + raise InheritanceException(f'{name} specified for inheritance diagram is ' + 'not a class or module') + + +def _import_classes(class_names, currmodule): + """Import a list of classes.""" + classes = [] + for name in class_names: + classes.extend(_import_class_or_module(name, currmodule)) + return classes + + +def _class_name(cls, parts=0): + """Given a class object, return a fully-qualified name. + + This works for things I've tested in matplotlib so far, but may not be + completely general. + """ + module = cls.__module__ + if module == '__builtin__': + fullname = cls.__name__ + else: + fullname = f"{module}.{cls.__qualname__}" + if parts == 0: + return fullname + name_parts = fullname.split('.') + return '.'.join(name_parts[-parts:]) + + +def _class_info(classes, builtins=None, show_builtins=False, parts=0): + """Return name and bases for all classes that are ancestors of + *classes*. + + *parts* gives the number of dotted name parts that is removed from the + displayed node names. + """ + all_classes = {} + builtins_list = builtins.values() if builtins else [] + + def recurse(cls): + if not show_builtins and cls in builtins_list: + return + + nodename = _class_name(cls, parts) + fullname = _class_name(cls, 0) + + baselist = [] + all_classes[cls] = (nodename, fullname, baselist) + for base in cls.__bases__: + if not show_builtins and base in builtins_list: + continue + if base.__name__ == "Object" and base.__module__ == "Shiboken": + continue + baselist.append(_class_name(base, parts)) + if base not in all_classes: + recurse(base) + + for cls in classes: + recurse(cls) + + return list(all_classes.values()) + + +def get_inheritance_entries_by_import(class_names, currmodule, + builtins=None, + show_builtins=False, parts=0): + classes = _import_classes(class_names, currmodule) + class_info = _class_info(classes, builtins, show_builtins, parts) + if not class_info: + raise InheritanceException('No classes found for ' + 'inheritance diagram') + return class_info + + +if __name__ == "__main__": + module = None + if len(sys.argv) < 2: + print(TEST_DRIVER_USAGE) + sys.exit(-1) + class_name = sys.argv[1] + if len(sys.argv) >= 3: + module = sys.argv[2] + entries = get_inheritance_entries_by_import([class_name], module, None, + False, 2) + for e in entries: + print(e) |