Source code for utool.util_autogen

# -*- 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__)


[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, show_diff=None, dowrite=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 if dowrite is None: dowrite = ut.get_argflag(('-w', '--write')) if show_diff is None: 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 ) try: ut.print_difftext(textdiff) except UnicodeDecodeError: import unicodedata textdiff = unicodedata.normalize('NFKD', textdiff).encode( 'ascii', 'ignore' ) 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): (Defaults to []) use_star (bool): (Defaults to False) Returns: str: init_codeblock CommandLine: python -m utool.util_autogen makeinit --modname=wbia.algo Example: >>> # DISABLE_DOCTEST >>> # 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(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.repr4(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: >>> # DISABLE_DOCTEST >>> 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, modpath=None): r""" Args: modname (str): module name funcname (str): function name verbose (bool): verbosity flag(Defaults to True) moddir (None): (Defaults to None) CommandLine: python -m utool.util_autogen load_func_from_module Example: >>> # DISABLE_DOCTEST >>> # UNSTABLE_DOCTEST >>> from utool.util_autogen import * # NOQA >>> import utool as ut >>> #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,)) try: from xdoctest import static_analysis as static from xdoctest import utils print('modpath = {!r}'.format(modpath)) except ImportError: modpath = None else: if modpath is None: modpath = static.modname_to_modpath(modname) if modpath is None: modname = modname.split('.')[-1] if moddir is not None: modpath = join(moddir, modname + '.py') if not exists(modpath): modpath = None if modpath is None: raise Exception( 'Cannot find modname={} in moddir={}'.format(modname, moddir) ) print('modpath = {!r}'.format(modpath)) module = utils.import_module_from_path(modpath) print('module = {!r}'.format(module)) try: func = eval('module.{}'.format(funcname)) except AttributeError: imp.reload(module) func = eval('module.{}'.format(funcname)) print('func = {!r}'.format(func)) return func, module, error_str if not isinstance(modname, six.string_types): error_str = 'modname=%r is not a string. bad input' % (modname,) else: if False: # TODO: static analysis import jedi # NOQA modpath = ut.util_import.get_modpath_from_modname(modname) script = jedi.Script(path=modpath) mod = script._get_module() # monkeypatch func.script = script func = None for name in mod.names_dict[funcname]: if name.parent.type == 'funcdef': func = name.parent break return func, mod, error_str # ut.get_modpath_from_modname(modname) if module is None: 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, modpath=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 auto_docstr python -m utool --tf auto_docstr Example: >>> # DISABLE_DOCTEST >>> import utool as ut >>> from utool.util_autogen import * # NOQA >>> ut.util_autogen.rrr(verbose=False) >>> #docstr = ut.auto_docstr('wbia.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, modpath=modpath ) 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.repr4(kwargs) return error_str else: docstr = error_str return docstr
# <INVIDIAL DOCSTR COMPONENTS>
[docs]def make_args_docstr( argname_list, argtype_list, argdesc_list, ismethod, va_name=None, kw_name=None, kw_keys=[], ): r""" Builds the argument docstring Args: argname_list (list): names argtype_list (list): types argdesc_list (list): descriptions ismethod (bool): if generating docs for a method va_name (Optional[str]): varargs name kw_name (Optional[str]): kwargs name kw_keys (Optional[list]): accepted kwarg keys Returns: str: arg_docstr CommandLine: python -m utool.util_autogen make_args_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'] >>> va_name = 'args' >>> kw_name = 'kwargs' >>> kw_keys = [''] >>> ismethod = False >>> arg_docstr = make_args_docstr(argname_list, argtype_list, >>> argdesc_list, ismethod, va_name, >>> kw_name, kw_keys) >>> result = str(arg_docstr) >>> print(result) argname_list (list): names argtype_list (list): types argdesc_list (list): descriptions *args: **kwargs: """ import utool as ut if ismethod: # Remove self from the list 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) ] # Add in varargs and kwargs # References: # http://www.sphinx-doc.org/en/stable/ext/example_google.html#example-google if va_name is not None: argdoc_list.append('*' + va_name + ':') if kw_name is not None: import textwrap prefix = '**' + kw_name + ': ' wrapped_lines = textwrap.wrap(', '.join(kw_keys), width=70 - len(prefix)) sep = '\n' + (' ' * len(prefix)) kw_keystr = sep.join(wrapped_lines) argdoc_list.append((prefix + kw_keystr).strip()) # 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 >>> funcname = 'make_example_docstr' >>> modname = 'utool.util_autogen' >>> argname_list = ['qaids', 'qreq_'] >>> defaults = None >>> return_type = tuple >>> return_name = 'foo' >>> ismethod = False >>> examplecode = make_example_docstr(funcname, modname, argname_list, defaults, return_type, return_name, ismethod) >>> result = str(examplecode) >>> print(result) # DISABLE_DOCTEST from utool.util_autogen import * # NOQA import utool as ut import wbia species = wbia.const.TEST_SPECIES.ZEB_PLAIN qaids = ibs.get_valid_aids(species=species) qreq_ = wbia.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') is_show_func = modname.startswith('plottool') # TODO: Externally register these default_argval_map = { 'ibs': "wbia.opendb(defaultdb='testdb1')", 'testres': "wbia.testdata_expts('PZ_MTEST')", 'qreq_': 'wbia.testdata_qreq_()', 'cm_list': 'qreq_.execute()', 'cm': 'qreq_.execute()[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': 'wbia.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 = { 'wbia': 'import wbia', 'vt': 'import vtool as vt', #'img': 'import vtool as vt', # TODO: remove. fix dependency #'species': 'import wbia', } var_depends_map = { 'species': ['wbia'], 'ibs': ['wbia'], 'testres': ['wbia'], 'kpts': ['vt'], #'qreq_': ['ibs', 'species', 'daids', 'qaids'], 'qreq_': ['wbia'], '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) inferred_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_, inferred_defaults) ] import_lines = ut.unique_ordered(import_lines) if any([inferrepr == repr('?') for inferrepr in inferred_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.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(result_assign + example_call) 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 += [ '# xdoctest: +REQUIRES(--show)', ] 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 = 'draw' in funcname or 'show' in funcname if is_show_func: cmdline_fmtstr = 'python -m {modname} {funcname} --show' else: cmdline_fmtstr = 'python -m {modname} {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): (Defaults to True) with_commandline (bool): (Defaults to True) with_example (bool): (Defaults to True) with_header (bool): (Defaults to False) with_debug (bool): (Defaults to 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 >>> func = auto_docstr >>> 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 va_name = funcinfo.va_name kw_name = funcinfo.kw_name kw_keys = funcinfo.kw_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, va_name, kw_name, kw_keys ) argsblock = make_docstr_block(argheader, arg_docstr) docstr_parts.append(argsblock) # if False: # 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, test_code=None): """ make_default_module_maintest DEPRICATE 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} """ ) 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) if test_code is None: test_code = ut.codeblock( r""" import multiprocessing multiprocessing.freeze_support() # for win32 import utool as ut # NOQA ut.doctest_funcs() """ ) test_code = ut.indent(test_code, ' ' * 4).lstrip(' ') text = ut.codeblock( r''' # STARTBLOCK if __name__ == '__main__': r""" CommandLine: {cmdline} """ {test_code} # ENDBLOCK ''' ).format(cmdline=cmdline, test_code=test_code) print('test_code = {!r}'.format(test_code)) 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(modname) # import imp # tup = imp.find_module(modname) # (file, filename, (suffix, mode, type)) if __name__ == '__main__': """ CommandLine: python wbia/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()