Exemplo n.º 1
0
def _find_local_submodules(pkgpath):
    """
    Yields all children submodules in a package (non-recursively)

    Args:
        pkgpath (str): path to a package with an __init__.py file

    Example:
        >>> pkgpath = static.modname_to_modpath('mkinit')
        >>> import_paths = dict(_find_local_submodules(pkgpath))
        >>> print('import_paths = {!r}'.format(import_paths))
    """
    # Find all the children modules in this package (non recursive)
    pkgname = static.modpath_to_modname(pkgpath, check=False)
    if pkgname is None:
        raise Exception('cannot import {!r}'.format(pkgpath))
    # TODO:
    # DOES THIS NEED A REWRITE TO HANDLE THE CASE WHEN __init__ does not exist?

    try:
        # Hack to grab the root package
        a, b = static.split_modpath(pkgpath, check=False)
        root_pkgpath = join(a, b.replace('\\', '/').split('/')[0])
    except ValueError:
        # Assume that the path is the root package if split_modpath fails
        root_pkgpath = pkgpath

    for sub_modpath in static.package_modpaths(pkgpath,
                                               with_pkg=True,
                                               recursive=False,
                                               check=False):
        sub_modname = static.modpath_to_modname(sub_modpath,
                                                check=False,
                                                relativeto=root_pkgpath)
        rel_modname = sub_modname[len(pkgname) + 1:]
        if not rel_modname or rel_modname.startswith('_'):
            # Skip private modules
            pass
        else:
            yield rel_modname, sub_modpath
Exemplo n.º 2
0
def autogen_init(
    modpath_or_name,
    submodules=None,
    respect_all=True,
    options=None,
    dry=False,
    diff=False,
    recursive=False,
):
    """
    Autogenerates imports for a package __init__.py file.

    Args:
        modpath_or_name (PathLike | str):
            path to or name of a package module.  The path should reference the
            dirname not the __init__.py file.  If specified by name, must be
            findable from the PYTHONPATH.

        submodules (List[str], default=None):
            if specified, then only these specific submodules are used in
            package generation. Otherwise, all non underscore prefixed modules
            are used.

        respect_all (bool, default=True):
            if False the `__all__` attribute is ignored while parsing.

        options (dict):
            formatting options; customizes how output is formatted.
            See `formatting._ensure_options` for defaults.

        dry (bool, default=False):
            if True, the autogenerated string is not written

        recursive (bool, default=False):
            if True, we will autogenerate init files for all subpackages.

    Notes:
        This will partially override the __init__ file. By default everything
        up to the last comment / __future__ import is preserved, and everything
        after is overriden.  For more fine grained control, you can specify
        XML-like `# <AUTOGEN_INIT>` and `# </AUTOGEN_INIT>` comments around the
        volitle area. If specified only the area between these tags will be
        overwritten.

        To autogenerate a module on demand, its useful to keep a doctr comment
        in the __init__ file like this:
            python -m mkinit <your_module>

    Example:
        >>> init_fpath, new_text = autogen_init('mkinit', submodules=None,
        >>>                                     respect_all=True,
        >>>                                     dry=True)
        >>> assert 'autogen_init' in new_text
    """
    logger.info(
        "Autogenerating __init__ for modpath_or_name={}".format(modpath_or_name)
    )
    modpath = _rectify_to_modpath(modpath_or_name)

    if recursive:
        if submodules is not None:
            raise AssertionError("cannot specify submodules in recursive mode")
        all_init_fpaths = list(
            static.package_modpaths(modpath, with_pkg=True, with_mod=False)
        )
        all_init_fpaths = sorted(all_init_fpaths, key=lambda x: x.count(os.sep))
        for fpath in reversed(all_init_fpaths):
            autogen_init(
                fpath,
                submodules=None,
                respect_all=respect_all,
                options=options,
                dry=dry,
                diff=diff,
                recursive=False,
            )

    else:
        initstr = static_init(
            modpath, submodules=submodules, respect_all=respect_all, options=options
        )
        init_fpath, new_text = _insert_autogen_text(modpath, initstr)
        if dry:
            logger.info("(DRY) would write updated file: %r" % init_fpath)
            if diff:
                # Display difference
                try:
                    with open(init_fpath, "r") as file:
                        old_text = file.read()
                except Exception:
                    old_text = ""
                display_text = difftext(
                    old_text, new_text, colored=True, context_lines=3
                )
                print(display_text)
            else:
                print(new_text)
            return init_fpath, new_text
        else:
            logger.info("writing updated file: %r" % init_fpath)
            # print(new_text)
            with open(init_fpath, "w") as file_:
                file_.write(new_text)