""" AUTHOR: Khushal P Soonderji DATE: Saturday, 24th Aug., 2024 OBJECTIVE: To provide an overview of any function or class in a string. The generated overview can then either be shown on the terminal, or transmitted over some other medium for collaborative work. REFERENCES: N/A DOWNLOADS: N/A """ # ***************************************************************************************************************** # ***** **** # *** IMPORT *** # ***** **** # ***************************************************************************************************************** # System-level activities: import io import inspect # ***************************************************************************************************************** # ***** **** # *** MACROS / ONE-TIME INIT *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** VARIABLES *** # ***** **** # ***************************************************************************************************************** # --- Nothing Yet # ***************************************************************************************************************** # ***** **** # *** FUNCTIONS *** # ***** **** # ***************************************************************************************************************** def get_help_for_class(cls, skip_methods = None): """ Returns the help documentation to use this class. :param cls: The class whose help string is desired. :param skip_methods: A list of methods to NOT include in the help text. :return: This help documentation. """ separator = "\n\n" + ("=" * 120) + "\n\n" if skip_methods is None: skip_methods = [] elif not isinstance(skip_methods, list): skip_methods = [skip_methods] # Get class name and docstring: class_name = cls.__name__ docstring = inspect.getdoc(cls) or "" help_string = "HELP FOR:\n\n" help_string += class_name + "\n\n" help_string += "This document has upto 120 chars per line.\n" help_string += "Best viewed with monospaced font :)" help_string += docstring + separator # Get all methods and their docstrings. # Then note the documentation of the methods while ignoring the blacklisted ones: members = inspect.getmembers(cls, predicate = inspect.isfunction) func_help = [] for name, method in members: # Ignore if asked, or extract the details: if name in skip_methods or name.startswith(f"_{class_name}__"): continue else: func_help.append(get_help_for_function(method)) # Put all the things together: func_help = separator.join(func_help) help_string += func_help # Done here: return help_string # --------------------------------------------------------------------------------------------------------------------- def get_help_for_function(func): """ Get the help string for one function. It could be a standalone function, or a method of a class. :param func: The function (or method) whose help string is needed. :return: The help string of the function. """ # Get the name and documentation: func_name = func.__name__ async_indicator = " (async)" if inspect.iscoroutinefunction(func) else "" func_doc = inspect.getdoc(func) or "" # Create the decorated header: func_decorator = "-" * (len(func_name) + 2) func_head = "." + func_decorator + f".\n| {func_name} |{async_indicator}\n`" + func_decorator + "`\n\n" # Add the 'args' and 'kwargs': func_args = [] for name, param in inspect.signature(func).parameters.items(): default = param.default if isinstance(default, str): default = f"\"{default}\"" if default == inspect.Parameter.empty: func_args.append(f"{name}") else: func_args.append(f"{name}: {type(default).__name__} = {default}") if len(func_args) > 0: func_args = f"{func_name} (\n\t" + "\n\t".join(func_args) + "\n):\n\n" else: func_args = f"{func_name} ():\n\n" # Get the params and return value part from the doc: params_start = func_doc.find(":param") return_start = func_doc.find(":return") func_params = "\n" + func_doc[params_start:return_start] if params_start >= 0 else "" func_return = "\n" + func_doc[return_start:] if return_start >= 0 else "" # Isolate the documentation part: if params_start >= 0: func_doc = func_doc[:params_start] elif return_start >= 0: func_doc = func_doc[:return_start] # Done here: return func_head + func_args + func_doc + func_params + func_return # --------------------------------------------------------------------------------------------------------------------- def get_help(entity, skip_methods = None): """ Get the help documentation for anything from its docstring. :param entity: The entity you want to get help for. :param skip_methods: A list of methods to ignore if inspecting a class. Not valid for standalone functions. :return: The help string. """ if inspect.isclass(entity): return get_help_for_class(entity, skip_methods = skip_methods) else: return get_help_for_function(entity) # ***************************************************************************************************************** # ***** **** # *** MAIN PROGRAM *** # ***** **** # ***************************************************************************************************************** if __name__ == "__main__": pass