# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function
import re
import os
import six
from collections import deque # NOQA
from os.path import exists, dirname, join, expanduser, normpath
from utool import util_inject
print, rrr, profile = util_inject.inject2(__name__, '[autogen]')
[docs]class PythonStatement(object):
""" Thin wrapper around a string representing executable python code """
def __init__(self, stmt):
self.stmt = stmt
def __repr__(self):
return self.stmt
def __str__(self):
return self.stmt
[docs]def dump_autogen_code(fpath, autogen_text, codetype='python', fullprint=None):
"""
Helper that write a file if -w is given on command line, otherwise
it just prints it out. It has the opption of comparing a diff to the file.
"""
import utool as ut
dowrite = ut.get_argflag(('-w', '--write'))
show_diff = ut.get_argflag('--diff')
num_context_lines = ut.get_argval('--diff', type_=int, default=None)
show_diff = show_diff or num_context_lines is not None
num_context_lines = ut.get_argval('--diff', type_=int, default=None)
if fullprint is None:
fullprint = True
if fullprint is False:
fullprint = ut.get_argflag('--print')
print('[autogen] Autogenerated %s...\n+---\n' % (fpath,))
if not dowrite:
if fullprint:
ut.print_code(autogen_text, lexer_name=codetype)
print('\nL___')
else:
print('specify --print to write to stdout')
pass
print('specify -w to write, or --diff to compare')
print('...would write to: %s' % fpath)
if show_diff:
if ut.checkpath(fpath, verbose=True):
prev_text = ut.read_from(fpath)
textdiff = ut.get_textdiff(prev_text, autogen_text,
num_context_lines=num_context_lines)
ut.print_difftext(textdiff)
if dowrite:
print('WARNING: Not writing. Remove --diff from command line')
elif dowrite:
ut.write_to(fpath, autogen_text)
[docs]def makeinit(mod_dpath, exclude_modnames=[], use_star=False):
r"""
Args:
mod_dpath (str):
exclude_modnames (list): (default = [])
use_star (bool): (default = False)
Returns:
str: init_codeblock
CommandLine:
python -m utool.util_autogen --exec-makeinit --modname=ibeis.algo
Example:
>>> # SCRIPT
>>> from utool.util_autogen import * # NOQA
>>> import utool as ut
>>> modname = ut.get_argval('--modname', str, default=None)
>>> mod_dpath = (os.getcwd() if modname is None else
>>> ut.get_modpath_from_modname(modname, prefer_pkg=True))
>>> mod_dpath = ut.unixpath(mod_dpath)
>>> mod_fpath = join(mod_dpath, '__init__.py')
>>> exclude_modnames = ut.get_argval(('--exclude', '-x'), list, default=[])
>>> use_star = ut.get_argflag('--star')
>>> init_codeblock = makeinit(mod_dpath, exclude_modnames, use_star)
>>> ut.dump_autogen_code(mod_fpath, init_codeblock)
"""
from utool._internal import util_importer
import utool as ut
module_name = ut.get_modname_from_modpath(mod_dpath)
IMPORT_TUPLES = util_importer.make_import_tuples(mod_dpath, exclude_modnames=exclude_modnames)
initstr = util_importer.make_initstr(module_name, IMPORT_TUPLES)
regen_command = 'cd %s\n' % (mod_dpath)
regen_command += ' makeinit.py'
regen_command += ' --modname={modname}'.format(modname=module_name)
if use_star:
regen_command += ' --star'
if len(exclude_modnames ) > 0:
regen_command += ' -x ' + ' '.join(exclude_modnames)
regen_block = (ut.codeblock('''
"""
Regen Command:
{regen_command}
"""
''').format(regen_command=regen_command))
importstar_codeblock = ut.codeblock(
'''
"""
python -c "import {module_name}" --dump-{module_name}-init
python -c "import {module_name}" --update-{module_name}-init
"""
__DYNAMIC__ = True
if __DYNAMIC__:
# TODO: import all utool external prereqs. Then the imports will not import
# anything that has already in a toplevel namespace
# COMMENTED OUT FOR FROZEN __INIT__
# Dynamically import listed util libraries and their members.
from utool._internal import util_importer
# FIXME: this might actually work with rrrr, but things arent being
# reimported because they are already in the modules list
import_execstr = util_importer.dynamic_import(__name__, IMPORT_TUPLES)
exec(import_execstr)
DOELSE = False
else:
# Do the nonexec import (can force it to happen no matter what if alwyas set
# to True)
DOELSE = True
if DOELSE:
# <AUTOGEN_INIT>
pass
# </AUTOGEN_INIT>
'''.format(module_name=module_name)
)
ts_line = '# Autogenerated on {ts}'.format(ts=ut.get_timestamp('printable'))
init_codeblock_list = ['# -*- coding: utf-8 -*-', ts_line]
init_codeblock_list.append(initstr)
init_codeblock_list.append('\nIMPORT_TUPLES = ' + ut.list_str(IMPORT_TUPLES))
if use_star:
init_codeblock_list.append(importstar_codeblock)
init_codeblock_list.append(regen_block)
init_codeblock = '\n'.join(init_codeblock_list)
return init_codeblock
[docs]def write_modscript_alias(fpath, modname, args='', pyscript='python'):
"""
convinience function because $@ is annoying to paste into the terminal
"""
import utool as ut
from os.path import splitext
allargs_dict = {
'.sh': ' $@',
'.bat': ' %1', }
_, script_ext = splitext(fpath)
if script_ext not in ['.sh', '.bat']:
script_ext = '.bat' if ut.WIN32 else 'sh'
allargs = (args + allargs_dict[script_ext]).strip(' ')
if not modname.endswith('.py'):
fmtstr = '{pyscript} -m {modname} {allargs}'
else:
fmtstr = '{pyscript} {modname} {allargs}'
cmdstr = fmtstr.format(pyscript=pyscript, modname=modname, allargs=allargs)
ut.write_to(fpath, cmdstr)
os.system('chmod +x ' + fpath)
[docs]def autofix_codeblock(codeblock, max_line_len=80,
aggressive=False,
very_aggressive=False,
experimental=False):
r"""
Uses autopep8 to format a block of code
Example:
>>> import utool as ut
>>> codeblock = ut.codeblock(
'''
def func( with , some = 'Problems' ):
syntax ='Ok'
but = 'Its very messy'
if None:
# syntax might not be perfect due to being cut off
ommiting_this_line_still_works= True
''')
>>> fixed_codeblock = ut.autofix_codeblock(codeblock)
>>> print(fixed_codeblock)
"""
# FIXME idk how to remove the blank line following the function with
# autopep8. It seems to not be supported by them, but it looks bad.
import autopep8
arglist = ['--max-line-length', '80']
if aggressive:
arglist.extend(['-a'])
if very_aggressive:
arglist.extend(['-a', '-a'])
if experimental:
arglist.extend(['--experimental'])
arglist.extend([''])
autopep8_options = autopep8.parse_args(arglist)
fixed_codeblock = autopep8.fix_code(codeblock, options=autopep8_options)
return fixed_codeblock
[docs]def load_func_from_module(modname, funcname, verbose=True, moddir=None):
r"""
Args:
modname (str): module name
funcname (str): function name
verbose (bool): verbosity flag(default = True)
moddir (None): (default = None)
CommandLine:
python -m utool.util_autogen --exec-load_func_from_module
Example:
>>> # UNSTABLE_DOCTEST
>>> from utool.util_autogen import * # NOQA
>>> import utool as ut
>>> #modname = 'plottool.plots'
>>> #funcname = 'multi_plot'
>>> modname = 'utool.util_path'
>>> funcname = 'checkpath'
>>> verbose = True
>>> moddir = None
>>> func, module, error_str = load_func_from_module(modname, funcname, verbose, moddir)
>>> source = ut.get_func_sourcecode(func, strip_docstr=True, strip_comments=True)
>>> keyname = ut.named_field('keyname', ut.REGEX_VARNAME)
>>> default = ut.named_field('default', '[\'\"A-Za-z_][A-Za-z0-9_\'\"]*')
>>> pattern = re.escape('kwargs.get(\'') + keyname + re.escape('\',')
>>> kwarg_keys = [match.groupdict()['keyname'] for match in re.finditer(pattern, source)]
"""
import utool as ut
from os.path import join
import imp
func = None
module = None
error_str = None
print('modname = %r' % (modname,))
print('funcname = %r' % (funcname,))
print('moddir = %r' % (moddir,))
if not isinstance(modname, six.string_types):
error_str = 'modname=%r is not a string. bad input' % (modname,)
else:
if False:
basemodname_ = modname
basemodname = ''
parts = modname.split('.')
for index in range(len(parts)):
#print('index = %r' % (index,))
basemodname = '.'.join(parts[0:index + 1])
#print('basemodname = %r' % (basemodname,))
basemodule = __import__(basemodname)
#print('basemodule = %r' % (basemodule,))
#if hasattr(basemodule, 'rrrr'):
# basemodule.rrrr()
#imp.reload(basemodule)
try:
module = __import__(modname)
except ImportError:
if moddir is not None:
#parts =
# There can be a weird double import error thing happening here
# Rectify the dots in the filename
module = ut.import_module_from_fpath(join(moddir, modname.split('.')[-1] + '.py'))
else:
raise
#import inspect
try:
imp.reload(module)
except Exception as ex:
pass
if False:
# Try removing pyc if it exists
if module.__file__.endswith('.pyc'):
ut.delete(module.__file__, verbose=False)
try:
module = __import__(modname)
except ImportError:
if moddir is not None:
module = ut.import_module_from_fpath(join(moddir, modname.split('.')[-1] + '.py'))
else:
raise
try:
imp.reload(module)
except Exception as ex:
pass
try:
# FIXME: PYTHON 3
execstr = ut.codeblock(
'''
try:
import {modname}
module = {modname}
#print('Trying to reload module=%r' % (module,))
imp.reload(module)
except Exception:
# If it fails maybe the module is not in the path
if moddir is not None:
try:
import imp
import os
orig_dir = os.getcwd()
os.chdir(moddir)
modname_str = '{modname}'
modinfo = imp.find_module(modname_str, [moddir])
module = imp.load_module(modname_str, *modinfo)
#print('loaded module=%r' % (module,))
except Exception as ex:
ut.printex(ex, 'failed to imp.load_module')
pass
finally:
os.chdir(orig_dir)
import imp
import utool as ut
imp.reload(ut.util_autogen)
imp.reload(ut.util_inspect)
try:
func = module.{funcname}
except AttributeError:
docstr = 'Could not find attribute funcname={funcname} in modname={modname} This might be a reloading issue'
imp.reload(module)
'''
).format(**locals())
exec_locals = locals()
exec_globals = globals()
exec(execstr, exec_globals, exec_locals)
func = exec_locals.get('func', None)
module = exec_locals.get('module', None)
except Exception as ex2:
docstr = 'error ' + str(ex2)
if verbose:
import utool as ut
#ut.printex(ex1, 'ex1')
ut.printex(ex2, 'ex2', tb=True)
testcmd = 'python -c "import utool; print(utool.auto_docstr(\'%s\', \'%s\'))"' % (modname, funcname)
error_str = ut.formatex(ex2, 'ex2', tb=True, keys=['modname', 'funcname', 'testcmd'])
error_str += '---' + execstr
return func, module, error_str
[docs]def auto_docstr(modname, funcname, verbose=True, moddir=None, **kwargs):
r"""
called from vim. Uses strings of filename and modnames to build docstr
Args:
modname (str): name of a python module
funcname (str): name of a function in the module
Returns:
str: docstr
CommandLine:
python -m utool.util_autogen --exec-auto_docstr
python -m utool --tf auto_docstr
Example:
>>> import utool as ut
>>> from utool.util_autogen import * # NOQA
>>> ut.util_autogen.rrr(verbose=False)
>>> #docstr = ut.auto_docstr('ibeis.algo.hots.smk.smk_index', 'compute_negentropy_names')
>>> modname = ut.get_argval('--modname', default='utool.util_autogen')
>>> funcname = ut.get_argval('--funcname', default='auto_docstr')
>>> moddir = ut.get_argval('--moddir', type_=str, default=None)
>>> docstr = ut.util_autogen.auto_docstr(modname, funcname)
>>> print(docstr)
"""
#import utool as ut
func, module, error_str = load_func_from_module(
modname, funcname, verbose=verbose, moddir=moddir)
if error_str is None:
try:
docstr = make_default_docstr(func, **kwargs)
except Exception as ex:
import utool as ut
error_str = ut.formatex(ex, 'Caught Error in parsing docstr', tb=True)
#ut.printex(ex)
error_str += (
'\n\nReplicateCommand:\n '
'python -m utool --tf auto_docstr '
'--modname={modname} --funcname={funcname} --moddir={moddir}').format(
modname=modname, funcname=funcname, moddir=moddir)
error_str += '\n kwargs=' + ut.dict_str(kwargs)
return error_str
else:
docstr = error_str
return docstr
[docs]def print_auto_docstr(modname, funcname):
"""
python -c "import utool; utool.print_auto_docstr('ibeis.algo.hots.smk.smk_index', 'compute_negentropy_names')"
python -c "import utool;
utool.print_auto_docstr('ibeis.algo.hots.smk.smk_index', 'compute_negentropy_names')"
"""
docstr = auto_docstr(modname, funcname)
print(docstr)
# <INVIDIAL DOCSTR COMPONENTS>
[docs]def make_args_docstr(argname_list, argtype_list, argdesc_list, ismethod):
r"""
Builds the argument docstring
Args:
argname_list (list): names
argtype_list (list): types
argdesc_list (list): descriptions
Returns:
str: arg_docstr
Example:
>>> # ENABLE_DOCTEST
>>> from utool.util_autogen import * # NOQA
>>> argname_list = ['argname_list', 'argtype_list', 'argdesc_list']
>>> argtype_list = ['list', 'list', 'list']
>>> argdesc_list = ['names', 'types', 'descriptions']
>>> ismethod = False
>>> arg_docstr = make_args_docstr(argname_list, argtype_list, argdesc_list, ismethod)
>>> result = str(arg_docstr)
>>> print(result)
argname_list (list): names
argtype_list (list): types
argdesc_list (list): descriptions
"""
import utool as ut
if ismethod:
argname_list = argname_list[1:]
argtype_list = argtype_list[1:]
argdesc_list = argdesc_list[1:]
argdoc_list = [arg + ' (%s): %s' % (_type, desc)
for arg, _type, desc in zip(argname_list, argtype_list, argdesc_list)]
# align?
align_args = False
if align_args:
argdoc_aligned_list = ut.align_lines(argdoc_list, character='(')
arg_docstr = '\n'.join(argdoc_aligned_list)
else:
arg_docstr = '\n'.join(argdoc_list)
return arg_docstr
[docs]def make_returns_or_yeilds_docstr(return_type, return_name, return_desc):
return_doctr = return_type + ': '
if return_name is not None:
return_doctr += return_name
if len(return_desc) > 0:
return_doctr += ' - '
return_doctr += return_desc
return return_doctr
[docs]def make_example_docstr(funcname=None, modname=None, argname_list=None,
defaults=None, return_type=None, return_name=None,
ismethod=False):
"""
Creates skeleton code to build an example doctest
Args:
funcname (str): function name
modname (str): module name
argname_list (str): list of argument names
defaults (None):
return_type (None):
return_name (str): return variable name
ismethod (bool):
Returns:
str: examplecode
CommandLine:
python -m utool.util_autogen --test-make_example_docstr
Example:
>>> # ENABLE_DOCTEST
>>> from utool.util_autogen import * # NOQA
>>> # build test data
>>> funcname = 'make_example_docstr'
>>> modname = 'utool.util_autogen'
>>> argname_list = ['qaids', 'qreq_']
>>> defaults = None
>>> return_type = tuple
>>> return_name = 'foo'
>>> ismethod = False
>>> # execute function
>>> examplecode = make_example_docstr(funcname, modname, argname_list, defaults, return_type, return_name, ismethod)
>>> # verify results
>>> result = str(examplecode)
>>> print(result)
# DISABLE_DOCTEST
from utool.util_autogen import * # NOQA
import utool as ut
import ibeis
species = ibeis.const.TEST_SPECIES.ZEB_PLAIN
qaids = ibs.get_valid_aids(species=species)
qreq_ = ibeis.testdata_qreq_()
foo = make_example_docstr(qaids, qreq_)
result = ('foo = %s' % (ut.repr2(foo),))
print(result)
"""
import utool as ut
examplecode_lines = []
top_import_fmstr = 'from {modname} import * # NOQA'
top_import = top_import_fmstr.format(modname=modname)
import_lines = [top_import]
if modname.startswith('utool'):
import_lines += ['import utool as ut']
is_show_func = not modname.startswith('utool') and not modname.startswith('mtgmonte')
# TODO: Externally register these
default_argval_map = {
'ibs' : 'ibeis.opendb(defaultdb=\'testdb1\')',
'testres' : 'ibeis.testdata_expts(\'PZ_MTEST\')',
#'qreq_' : 'ibs.new_query_request(qaids, daids)',
'qreq_' : 'ibeis.testdata_qreq_()',
'qres_list' : 'ibs.query_chips([1], [2, 3, 4, 5], cfgdict=dict())',
'qres' : 'ibs.query_chips([1], [2, 3, 4, 5], cfgdict=dict())[0]',
'aid_list' : 'ibs.get_valid_aids()',
'nid_list' : 'ibs._get_all_known_nids()',
'qaids' : 'ibs.get_valid_aids(species=species)',
'daids' : 'ibs.get_valid_aids(species=species)',
'species' : 'ibeis.const.TEST_SPECIES.ZEB_PLAIN',
'kpts' : 'vt.dummy.get_dummy_kpts()',
'dodraw' : 'ut.show_was_requested()',
'img_fpath' : 'ut.grab_test_imgpath(\'carl.jpg\')',
'gfpath' : 'ut.grab_test_imgpath(\'carl.jpg\')',
'img' : 'vt.imread(img_fpath)',
'img_in' : 'vt.imread(img_fpath)',
'bbox' : '(10, 10, 50, 50)',
'theta' : '0.0',
'rng' : 'np.random.RandomState(0)',
}
import_depends_map = {
'ibeis': 'import ibeis',
'vt': 'import vtool as vt',
#'img': 'import vtool as vt', # TODO: remove. fix dependency
#'species': 'import ibeis',
}
var_depends_map = {
'species': ['ibeis'],
'ibs': ['ibeis'],
'testres': ['ibeis'],
'kpts': ['vt'],
#'qreq_': ['ibs', 'species', 'daids', 'qaids'],
'qreq_': ['ibeis'],
'qaids': ['ibs'],
'daids': ['ibs'],
'qaids': ['species'],
'daids': ['species'],
'img': ['img_fpath', 'vt'],
}
def find_arg_defaultrepr(argname, val):
import types
if val == '?':
if argname in default_argval_map:
val = ut.PythonStatement(default_argval_map[argname])
if argname in import_depends_map:
import_lines.append(import_depends_map[argname])
elif isinstance(val, types.ModuleType):
return val.__name__
return repr(val)
# augment argname list with dependencies
dependant_argnames = [] # deque()
def append_dependant_argnames(argnames, dependant_argnames):
""" use hints to add known dependencies for certain argument inputs """
for argname in argnames:
# Check if argname just implies an import
if argname in import_depends_map:
import_lines.append(import_depends_map[argname])
# Check if argname was already added as dependency
if (argname not in dependant_argnames and argname not in
argname_list and argname not in import_depends_map):
dependant_argnames.append(argname)
# Check if argname has dependants
if argname in var_depends_map:
argdeps = var_depends_map[argname]
# RECURSIVE CALL
append_dependant_argnames(argdeps, dependant_argnames)
append_dependant_argnames(argname_list, dependant_argnames)
# Define argnames and dependencies in example code
# argnames prefixed with dependeancies
argname_list_ = list(dependant_argnames) + argname_list
# Default example values
defaults_ = [] if defaults is None else defaults
num_unknown = (len(argname_list_) - len(defaults_))
default_vals = ['?'] * num_unknown + list(defaults_)
arg_val_iter = zip(argname_list_, default_vals)
infered_defaults = [find_arg_defaultrepr(argname, val)
for argname, val in arg_val_iter]
argdef_lines = ['%s = %s' % (argname, inferrepr)
for argname, inferrepr in
zip(argname_list_, infered_defaults)]
import_lines = ut.unique_ordered(import_lines)
if any([inferrepr == repr('?') for inferrepr in infered_defaults]):
examplecode_lines.append('# DISABLE_DOCTEST')
else:
# Enable the test if it can be run immediately
examplecode_lines.append('# DISABLE_DOCTEST')
examplecode_lines.extend(import_lines)
#examplecode_lines.append('# build test data')
examplecode_lines.extend(argdef_lines)
# Default example result assignment
result_assign = ''
result_print = None
if 'return_name' in vars():
if return_type is not None:
if return_name is None:
return_name = 'result'
result_assign = return_name + ' = '
result_print = 'print(result)' # + return_name + ')'
# Default example call
if ismethod:
selfname = argname_list[0]
methodargs = ', '.join(argname_list[1:])
tup = (selfname, '.', funcname, '(', methodargs, ')')
example_call = ''.join(tup)
else:
funcargs = ', '.join(argname_list)
tup = (funcname, '(', funcargs, ')')
example_call = ''.join(tup)
# Append call line
#examplecode_lines.append('# execute function')
examplecode_lines.append(result_assign + example_call)
#examplecode_lines.append('# verify results')
if result_print is not None:
if return_name != 'result':
#examplecode_lines.append('result = str(' + return_name + ')')
result_line_fmt = 'result = (\'{return_name} = %s\' % (ut.repr2({return_name}),))'
result_line = result_line_fmt.format(return_name=return_name)
examplecode_lines.append(result_line)
examplecode_lines.append(result_print)
# TODO: infer this
if is_show_func:
examplecode_lines += [
'ut.quit_if_noshow()',
'import plottool as pt',
'ut.show_if_requested()',
]
examplecode = '\n'.join(examplecode_lines)
return examplecode
[docs]def make_cmdline_docstr(funcname, modname):
#cmdline_fmtstr = 'python -m {modname} --test-{funcname}' # --enableall'
#cmdline_fmtstr = 'python -m {modname} --exec-{funcname}' # --enableall'
if False and '.' in modname and '.' not in funcname:
pkg = modname.split('.')[0]
# TODO check if __main__ exists with the necessary utool stuffs
# TODO check if --show should be given
cmdline_fmtstr = 'python -m {pkg} --tf {funcname}' # --enableall'
return cmdline_fmtstr.format(**locals())
else:
# TODO: infer this
is_show_func = True
if is_show_func:
cmdline_fmtstr = 'python -m {modname} --exec-{funcname} --show'
else:
cmdline_fmtstr = 'python -m {modname} --exec-{funcname}' # --enableall'
return cmdline_fmtstr.format(**locals())
# </INVIDIAL DOCSTR COMPONENTS>
[docs]def make_docstr_block(header, block):
import utool as ut
indented_block = '\n' + ut.indent(block)
docstr_block = ''.join([header, ':', indented_block])
return docstr_block
[docs]def make_default_docstr(func,
with_args=True,
with_ret=True,
with_commandline=True,
with_example=True,
with_header=False,
with_debug=False,
):
r"""
Tries to make a sensible default docstr so the user
can fill things in without typing too much
# TODO: Interleave old documentation with new documentation
Args:
func (function): live python function
with_args (bool):
with_ret (bool): (default = True)
with_commandline (bool): (default = True)
with_example (bool): (default = True)
with_header (bool): (default = False)
with_debug (bool): (default = False)
Returns:
tuple: (argname, val)
Ignore:
pass
CommandLine:
python -m utool.util_autogen --exec-make_default_docstr --show
Example:
>>> # ENABLE_DOCTEST
>>> from utool.util_autogen import * # NOQA
>>> import utool as ut
>>> func = ut.make_default_docstr
>>> #func = ut.make_args_docstr
>>> func = PythonStatement
>>> default_docstr = make_default_docstr(func)
>>> result = str(default_docstr)
>>> print(result)
"""
import utool as ut
#from utool import util_inspect
funcinfo = ut.util_inspect.infer_function_info(func)
argname_list = funcinfo.argname_list
argtype_list = funcinfo.argtype_list
argdesc_list = funcinfo.argdesc_list
return_header = funcinfo.return_header
return_type = funcinfo.return_type
return_name = funcinfo.return_name
return_desc = funcinfo.return_desc
funcname = funcinfo.funcname
modname = funcinfo.modname
defaults = funcinfo.defaults
num_indent = funcinfo.num_indent
needs_surround = funcinfo.needs_surround
funcname = funcinfo.funcname
ismethod = funcinfo.ismethod
kwarg_keys = funcinfo.kwarg_keys
docstr_parts = []
# Header part
if with_header:
header_block = funcname
docstr_parts.append(header_block)
# Args part
if with_args and len(argname_list) > 0:
argheader = 'Args'
arg_docstr = make_args_docstr(argname_list, argtype_list, argdesc_list, ismethod)
argsblock = make_docstr_block(argheader, arg_docstr)
docstr_parts.append(argsblock)
with_kw = with_args
if with_kw and len(kwarg_keys) > 0:
#ut.embed()
import textwrap
kwargs_docstr = ', '.join(kwarg_keys)
kwargs_docstr = '\n'.join(textwrap.wrap(kwargs_docstr))
kwargsblock = make_docstr_block('Kwargs', kwargs_docstr)
docstr_parts.append(kwargsblock)
# Return / Yeild part
if with_ret and return_header is not None:
if return_header is not None:
return_doctr = make_returns_or_yeilds_docstr(return_type, return_name, return_desc)
returnblock = make_docstr_block(return_header, return_doctr)
docstr_parts.append(returnblock)
# Example part
# try to generate a simple and unit testable example
if with_commandline:
cmdlineheader = 'CommandLine'
cmdlinecode = make_cmdline_docstr(funcname, modname)
cmdlineblock = make_docstr_block(cmdlineheader, cmdlinecode)
docstr_parts.append(cmdlineblock)
if with_example:
exampleheader = 'Example'
examplecode = make_example_docstr(funcname, modname, argname_list,
defaults, return_type, return_name,
ismethod)
examplecode_ = ut.indent(examplecode, '>>> ')
exampleblock = make_docstr_block(exampleheader, examplecode_)
docstr_parts.append(exampleblock)
# DEBUG part (in case something goes wrong)
if with_debug:
debugheader = 'Debug'
debugblock = ut.codeblock(
'''
num_indent = {num_indent}
'''
).format(num_indent=num_indent)
debugblock = make_docstr_block(debugheader, debugblock)
docstr_parts.append(debugblock)
# Enclosure / Indentation Parts
if needs_surround:
docstr_parts = ['r"""'] + ['\n\n'.join(docstr_parts)] + ['"""']
default_docstr = '\n'.join(docstr_parts)
else:
default_docstr = '\n\n'.join(docstr_parts)
docstr_indent = ' ' * (num_indent + 4)
default_docstr = ut.indent(default_docstr, docstr_indent)
return default_docstr
[docs]def remove_codeblock_syntax_sentinals(code_text):
r"""
Removes template comments and vim sentinals
Args:
code_text (str):
Returns:
str: code_text_
"""
flags = re.MULTILINE | re.DOTALL
code_text_ = code_text
code_text_ = re.sub(r'^ *# *REM [^\n]*$\n?', '', code_text_, flags=flags)
code_text_ = re.sub(r'^ *# STARTBLOCK *$\n', '', code_text_, flags=flags)
code_text_ = re.sub(r'^ *# ENDBLOCK *$\n?', '', code_text_, flags=flags)
code_text_ = code_text_.rstrip()
return code_text_
[docs]def make_default_module_maintest(modname, modpath=None):
"""
make_default_module_maintest
TODO: use path relative to home dir if the file is a script
Args:
modname (str): module name
Returns:
str: text source code
CommandLine:
python -m utool.util_autogen --test-make_default_module_maintest
References:
http://legacy.python.org/dev/peps/pep-0338/
Example:
>>> # ENABLE_DOCTEST
>>> from utool.util_autogen import * # NOQA
>>> modname = 'utool.util_autogen'
>>> text = make_default_module_maintest(modname)
>>> result = str(text)
>>> print(result)
"""
import utool as ut
# Need to use python -m to run a module
# otherwise their could be odd platform specific errors.
#python -c "import utool, {modname};
# ut.doctest_funcs({modname}, allexamples=True)"
#in_pythonpath, module_type, path = find_modname_in_pythonpath(modname)
# only use the -m if it is part of a package directory
if modpath is not None:
moddir = dirname(modpath)
pkginit_fpath = join(moddir, '__init__.py')
use_modrun = exists(pkginit_fpath)
else:
use_modrun = True
if use_modrun:
pyargs = '-m ' + modname
else:
if ut.WIN32:
modpath = normpath(modpath).replace(expanduser('~'), '%HOME%')
pyargs = '-B ' + ut.ensure_unixslash(modpath)
else:
modpath = normpath(modpath).replace(expanduser('~'), '~')
pyargs = modpath
cmdline = ut.codeblock(
'''
python {pyargs}
python {pyargs} --allexamples
# REM python {pyargs} --allexamples --noface --nosrc
''')
if not use_modrun:
if ut.WIN32:
augpath = 'set PYTHONPATH=%PYTHONPATH%' + os.pathsep + moddir
else:
augpath = 'export PYTHONPATH=$PYTHONPATH' + os.pathsep + moddir
cmdline = augpath + '\n' + cmdline
cmdline = ut.indent(cmdline, ' ' * 8).lstrip(' ').format(pyargs=pyargs)
text = ut.codeblock(
r'''
# STARTBLOCK
if __name__ == '__main__':
r"""
CommandLine:
{cmdline}
"""
import multiprocessing
multiprocessing.freeze_support() # for win32
import utool as ut # NOQA
ut.doctest_funcs()
# ENDBLOCK
'''
).format(cmdline=cmdline)
text = remove_codeblock_syntax_sentinals(text)
return text
[docs]def is_modname_in_pythonpath(modname):
in_pythonpath, module_type, path = find_modname_in_pythonpath(modname)
print(module_type)
return in_pythonpath
[docs]def find_modname_in_pythonpath(modname):
import sys
from os.path import exists, join
rel_modpath = modname.replace('.', '/')
in_pythonpath = False
module_type = None
path_list = sys.path
path_list = os.environ['PATH'].split(os.pathsep)
for path in path_list:
full_modpath = join(path, rel_modpath)
if exists(full_modpath + '.py'):
in_pythonpath = True
module_type = 'module'
break
if exists(join(full_modpath, '__init__.py')):
in_pythonpath = True
module_type = 'package'
break
return in_pythonpath, module_type, path
#ut.get_modpath_from_modname(modname)
#import imp
#tup = imp.find_module(modname)
#(file, filename, (suffix, mode, type))
if __name__ == '__main__':
"""
CommandLine:
python ibeis/control/template_generator.py --tbls annotations --Tflags getters native
python -c "import utool, utool.util_autogen; utool.doctest_funcs(utool.util_autogen, allexamples=True)"
python -m utool.util_autogen
python -m utool.util_autogen --allexamples
python -m utool.util_autogen --allexamples --noface --nosrc
"""
import multiprocessing
multiprocessing.freeze_support() # for win32
import utool as ut # NOQA
ut.doctest_funcs()