Source code for pynsive.reflection

import sys
import os.path
import inspect

from .common import *


def _list_classes(module, cls_filter):
    found = list()
    for name, module_obj in inspect.getmembers(module):
        if inspect.isclass(module_obj):
            append = not cls_filter or cls_filter(module_obj)
            if append:
                found.append(module_obj)
    return found


def _scan_paths_for(mname, paths):
    mpath_part = mname.replace(MODULE_PATH_SEP, os.sep)
    for mpath in paths:
        scan_target = os.path.join(mpath, mpath_part)
        is_dir = os.path.isdir(scan_target)
        is_file = os.path.isfile('{}.py'.format(scan_target))
        if is_dir or is_file:
            return mpath


def _should_use_module_path(module):
    """
    Checks to make sure that the passed module has the correct hidden
    variables set.
    """
    return hasattr(module, PATH_ATTRUBITE) and len(module.__path__) > 0


def _search_for_modules(directory, recursive=False, prefix=None):
    found = list()

    # Scan only if there's an __init__.py file
    if os.path.isfile(os.path.join(directory, MODULE_INIT_FILE)):
        for entry in os.listdir(directory):
            # Skip the init file
            if entry == MODULE_INIT_FILE:
                continue

            # Skip the pycache folder
            if entry == PYCACHE_FOLDER:
                continue

            if entry.endswith('.py'):
                module = entry.rstrip('.py')

                if prefix:
                    found.append(MODULE_PATH_SEP.join((prefix, module)))
                else:
                    found.append(module)
            elif recursive:
                next_dir = os.path.join(directory, entry)

                if os.path.isdir(next_dir):
                    if prefix:
                        next_mod = MODULE_PATH_SEP.join((prefix, entry))
                    else:
                        next_mod = entry

                    found.append(next_mod)
                    found.extend(_search_for_modules(next_dir, True, next_mod))
    return found


def _discover_modules(directory, recursive=False):
    found = list()

    if os.path.isdir(directory):
        for entry in os.listdir(directory):
            next_dir = os.path.join(directory, entry)

            # Scan only if there's an __init__.py file
            if os.path.isfile(os.path.join(next_dir, MODULE_INIT_FILE)):
                modules = _search_for_modules(next_dir, recursive, entry)
                found.extend(modules)

    return found


[docs]def discover_modules(directory): """ Attempts to list all of the modules and submodules found within a given directory tree. This function searches the top-level of the directory tree for potential python modules and returns a list of candidate names. **Note:** This function returns a list of strings representing discovered module names, not the actual, loaded modules. :param directory: the directory to search for modules. """ return _discover_modules(directory)
[docs]def rdiscover_modules(directory): """ Attempts to list all of the modules and submodules found within a given directory tree. This function recursively searches the directory tree for potential python modules and returns a list of candidate names. **Note:** This function returns a list of strings representing discovered module names, not the actual, loaded modules. :param directory: the directory to search for modules. """ return _discover_modules(directory, recursive=True)
[docs]def list_modules(mname): """ Attempts to list all of the submodules under a module. This function works for modules located in the default path as well as extended paths via the sys.meta_path hooks. This function carries the expectation that the hidden module variable '__path__' has been set correctly. :param mname: the module name to descend into """ module = import_module(mname) if not module: raise ImportError('Unable to load module {}'.format(mname)) found = list() if _should_use_module_path(module): mpath = module.__path__[0] else: mpaths = sys.path mpath = _scan_paths_for(mname, mpaths) if mpath: for pmname in _search_for_modules(mpath): found_mod = MODULE_PATH_SEP.join((mname, pmname)) found.append(found_mod) return found
[docs]def rlist_modules(mname): """ Attempts to the submodules under a module recursively. This function works for modules located in the default path as well as extended paths via the sys.meta_path hooks. This function carries the expectation that the hidden module variable '__path__' has been set correctly. :param mname: the module name to descend into """ module = import_module(mname) if not module: raise ImportError('Unable to load module {}'.format(mname)) found = list() if _should_use_module_path(module): mpath = module.__path__[0] else: mpaths = sys.path mpath = _scan_paths_for(mname, mpaths) if mpath: for pmname in _search_for_modules(mpath, recursive=True): found_mod = MODULE_PATH_SEP.join((mname, pmname)) found.append(found_mod) return found
[docs]def list_classes(mname, cls_filter=None): """ Attempts to list all of the classes within a specified module. This function works for modules located in the default path as well as extended paths via the sys.meta_path hooks. If a class filter is set, it will be called with each class as its parameter. This filter's return value must be interpretable as a boolean. Results that evaluate as True will include the type in the list of returned classes. Results that evaluate as False will exclude the type in the list of returned classes. :param mname: of the module to descend into :param cls_filter: a function to call to determine what classes should be included. """ found = list() module = import_module(mname) if inspect.ismodule(module): [found.append(mod) for mod in _list_classes(module, cls_filter)] return found
[docs]def rlist_classes(module, cls_filter=None): """ Attempts to list all of the classes within a given module namespace. This method, unlike list_classes, will recurse into discovered submodules. If a type filter is set, it will be called with each class as its parameter. This filter's return value must be interpretable as a boolean. Results that evaluate as True will include the type in the list of returned classes. Results that evaluate as False will exclude the type in the list of returned classes. :param mname: of the module to descend into :param cls_filter: a function to call to determine what classes should be included. """ found = list() mnames = rlist_modules(module) for mname in mnames: [found.append(c) for c in list_classes(mname, cls_filter)] return found
Read the Docs v: latest
Versions
latest
Downloads
PDF
HTML
Epub
On Read the Docs
Project Home
Builds

Free document hosting provided by Read the Docs.