[docs]
def main():
"""
The mkinit CLI main
"""
import argparse
import logging
import textwrap
from mkinit import static_mkinit
description = textwrap.dedent(
"""
Autogenerate an `__init__.py` that exposes a top-level API.
Behavior is modified depending on the existing content of the
`__init__.py` file (subsequent runs of mkinit are idempotent).
The following `__init__.py` variables modify autogeneration behavior.
All filtering variables support glob patterns (e.g., 'test_*', '*Base'):
`__submodules__` (List[str] | Dict[str, List[str])) -
Indicates the list of submodules to be introspected, if
unspecified all submodules are introspected. Can be a list
of submodule names, or a dictionary mapping each submodule name
to a list of attribute names to expose. If the value is None,
then all attributes are exposed (or __all__) is respected).
`__external__` - Specify external modules to expose the attributes of.
`__explicit__` - Add custom explicitly defined names to this, and
they will be automatically added to the __all__ variable.
`__protected__` - Protected modules are exposed, but their attributes are not.
Supports glob patterns: e.g., ['Abstract*', '*Base']
`__private__` - Private modules and their attributes are not exposed.
Supports glob patterns: e.g., ['test_*', '_internal*', 'conftest']
`__ignore__` - Tells mkinit to ignore particular attributes.
Supports glob patterns: e.g., ['DEPRECATED_*', '_*']
`__module_properties__` - can be a class with properties that will
be exposed on a module level if using mkinits lazy boilerplate.
"""
).strip('\n')
parser = argparse.ArgumentParser(
prog='python -m mkinit',
description=description,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
'modname_or_path',
nargs='?',
help='module or path to generate __init__.py for',
default='.',
)
parser.add_argument(
'--dry', dest='_dry_old', action='store_true', default=True
)
parser.add_argument(
*('-i', '-w', '--write', '--inplace'),
dest='dry',
action='store_false',
help='modify / write to the file inplace',
default=True,
)
parser.add_argument(
'--diff',
dest='diff',
action='store_true',
help='show the diff (forces dry mode)',
default=False,
)
parser.add_argument(
'--noattrs',
dest='with_attrs',
action='store_false',
default=True,
help='Do not generate attribute from imports',
)
parser.add_argument(
'--nomods',
dest='with_mods',
action='store_false',
default=True,
help='Do not generate modules imports',
)
parser.add_argument(
'--noall',
dest='with_all',
action='store_false',
default=True,
help='Do not generate an __all__ variable',
)
parser.add_argument(
'--relative',
action='store_true',
default=False,
help='Use relative . imports instead of <modname>',
)
lazy_group = parser.add_mutually_exclusive_group()
lazy_group.add_argument(
'--lazy',
action='store_true',
default=False,
help='Use lazy imports with more boilerplate but no dependencies',
)
lazy_group.add_argument(
'--lazy_loader',
'--lazy-loader',
action='store_true',
default=False,
help='Use lazy imports with less boilerplate but requires the lazy_loader module',
)
lazy_group.add_argument(
'--lazy_loader_typed',
action='store_true',
default=False,
help=(
'Use lazy imports with the lazy_loader module, additionally generating '
'``__init__.pyi`` files for static typing (e.g. with mypy or pyright) (Python >= 3.7 only!)'
),
)
parser.add_argument(
'--black',
action='store_true',
default=False,
help='Use black formatting',
)
parser.add_argument(
'--lazy_boilerplate',
'--lazy-boilerplate',
default=None,
help='Code that defines a custom lazy_import callable',
)
parser.add_argument(
'--recursive',
dest='recursive',
action='store_true',
default=False,
help='If specified, runs mkinit on all subpackages in a package',
)
parser.add_argument(
'--norespect_all',
'--norespect-all',
dest='respect_all',
action='store_false',
default=True,
help='if False does not respect __all__ attributes of submodules when parsing',
)
parser.add_argument(
'--verbose', nargs='?', default=0, type=int, help='Verbosity level'
)
parser.add_argument(
'--version', action='store_true', help='print version and exit'
)
import os
if os.environ.get('MKINIT_ARGPARSE_LOOSE', ''):
args, unknown = parser.parse_known_args()
else:
args = parser.parse_args()
ns = args.__dict__.copy()
if ns['version']:
import mkinit
print(mkinit.__version__)
return
modname_or_path = ns['modname_or_path']
if ns['verbose'] is None:
ns['verbose'] = 1
respect_all = ns['respect_all']
verbose = ns['verbose']
dry = ns['dry']
if ns['lazy_boilerplate'] and (
ns['lazy_loader'] or ns['lazy_loader_typed']
):
raise ValueError(
'--lazy_boilerplate cannot be specified with --lazy_loader or --lazy_loader_typed. Use --lazy instead.'
)
if not ns['with_all'] and ns['lazy_loader_typed']:
raise ValueError('--noall cannot be combined with --lazy_loader_typed')
if ns['lazy_loader_typed'] and not ns['relative']:
print(
'WARNING: specifying --lazy-loader-typed implicitly enables --relative, as '
'`lazy-loader` stub support requires relative imports. (Explicitly specify '
'--relative to remove this warning.)'
)
# Formatting options
options = {
'with_attrs': ns['with_attrs'],
'with_mods': ns['with_mods'],
'with_all': ns['with_all'],
'relative': ns['relative'] or ns['lazy_loader_typed'],
'lazy_import': ns['lazy'],
'lazy_loader': ns['lazy_loader'] or ns['lazy_loader_typed'],
'lazy_loader_typed': ns['lazy_loader_typed'],
'lazy_boilerplate': ns['lazy_boilerplate'],
'use_black': ns['black'],
}
diff = ns['diff']
if diff:
dry = True
if verbose == 0:
level = logging.WARNING
elif verbose == 1:
level = logging.INFO
elif verbose >= 2:
level = logging.DEBUG
if verbose:
print('verbose = {!r}'.format(verbose))
logging.basicConfig(
format='%(levelname)s: %(message)s',
level=level,
)
# print('ns = {!r}'.format(ns))
static_mkinit.autogen_init(
modname_or_path,
respect_all=respect_all,
options=options,
dry=dry,
diff=diff,
recursive=ns['recursive'],
)
if __name__ == '__main__':
main()