Example #1
0
def load_facts():
    fact_fpath = ub.Path('~/misc/facts/facts.toml').expand()
    with open(fact_fpath, 'r') as file:
        fact_data = toml.load(file)

    if 0:
        with open(ub.Path('~/misc/facts/internal.toml').expand(), 'r') as file:
            fact_data['facts'].extend(toml.load(file)['facts'])
    return fact_data
Example #2
0
    def __init__(self, config):
        self.config = config
        self.repo_dpath = ub.Path(self.config['repodir'])
        if self.config['repo_name'] is None:
            self.config['repo_name'] = self.repo_dpath.name
        self.repo_name = self.config['repo_name']
        self._tmpdir = tempfile.TemporaryDirectory(prefix=self.repo_name)

        self.template_infos = None
        self.template_dpath = ub.Path('~/misc/templates/PYPKG').expand()
        self.staging_dpath = ub.Path(self._tmpdir.name)
Example #3
0
def remove_old_python2_headers():
    import re
    import ubelt as ub
    from xdev import search_replace
    from xdev import patterns

    lines_to_remove = [
        patterns.Pattern.from_regex(re.escape('from __future__ import absolute_import, ') + '.*', dotall=True),
        patterns.Pattern.from_regex(re.escape('# -*- coding: utf-8 -*-') + '.*', dotall=True),
    ]

    fpaths = set(ub.Path('~/code/watch/').expand().glob('**/*.py'))
    fpaths = fpaths - {ub.Path('~/code/ubelt/dev/remove_ancient_constructs.py').expand()}

    dry = 0

    for fpath in fpaths:
        # x = fpath.read_text().split('\n')[0:1][0]
        for pat in lines_to_remove:
            search_replace.sedfile(fpath, regexpr=pat, repl='', dry=dry, verbose=3)
Example #4
0
 def main(cls, cmdline=False, **kwargs):
     from xdev.cli import docstr_stubgen
     import ubelt as ub
     config = cls(cmdline=cmdline, data=kwargs)
     print(f'config={config}')
     modname_or_path = config['module']
     print(f'modname_or_path={modname_or_path}')
     if modname_or_path is None:
         raise ValueError('Must specify the module')
     modpath = docstr_stubgen.modpath_coerce(modname_or_path)
     modpath = ub.Path(modpath)
     generated = docstr_stubgen.generate_typed_stubs(modpath)
     for fpath, text in generated.items():
         fpath = ub.Path(fpath)
         print(f'Write fpath={fpath}')
         fpath.write_text(text)
     # Generate a py.typed file to mark the package as typed
     if modpath.is_dir():
         pytyped_fpath = (modpath / 'py.typed')
         print(f'touch pytyped_fpath={pytyped_fpath}')
         pytyped_fpath.touch()
Example #5
0
def main():
    import ubelt as ub
    root_dpath = ub.Path('/etc')

    import timerit
    ti = timerit.Timerit(100, bestof=10, verbose=2)
    for timer in ti.reset('time'):
        with timer:
            items1 = sorted(walk_with_scandir(root_dpath))

    for timer in ti.reset('time'):
        with timer:
            items2 = sorted(walk_with_walk(root_dpath))

    len(items1)
    len(items2)
Example #6
0
def render_facts():
    """
    Render facts to a latex document
    """
    import pylatex
    from pylatex.base_classes.command import Options  # NOQA
    import pyqrcode

    fact_data = load_facts()

    class MDFramed(pylatex.base_classes.Environment):
        _latex_name = 'mdframed'
        packages = [pylatex.Package('mdframed')]

    class SamePage(pylatex.base_classes.Environment):
        _latex_name = 'samepage'

    class ComposeContexts:
        def __init__(self, *contexts):
            self.contexts = contexts

        def __enter__(self):
            return [c.__enter__() for c in self.contexts]

        def __exit__(self, a, b, c):
            return [c.__exit__(a, b, c) for c in self.contexts[::-1]]

    # class NewUnicodeChar(pylatex.base_classes.CommandBase):
    #     pass

    # Dont use fontenc, lmodern, or textcomp
    # https://tex.stackexchange.com/questions/179778/xelatex-under-ubuntu
    doc = pylatex.Document('fact_document',
                           inputenc=None,
                           page_numbers=False,
                           indent=False,
                           fontenc=None,
                           lmodern=False,
                           textcomp=False)

    doc.preamble.append(pylatex.Package('graphicx'))  # For PNG images
    # doc.preamble.append(pylatex.Package('svg', options=dict(inkscapearea='page')))
    # doc.preamble.append(pylatex.Command('title', 'Facts'))
    # doc.preamble.append(pylatex.Command('author', 'Anonymous author'))
    # doc.preamble.append(pylatex.Command('date', pylatex.NoEscape(r'\today')))
    # doc.append(pylatex.NoEscape(r'\maketitle'))

    # doc.preamble.append(pylatex.Package('newunicodechar'))
    # doc.preamble.append(pylatex.NoEscape(r'\newunicodechar{±}{$\pm$}'))

    # doc.append(pylatex.NoEscape('13.787±0.020'))
    # print(doc.dumps())
    # doc.generate_pdf(clean_tex=False, compiler='xelatex')
    # return

    QR_REFERENCE = True
    stop_flag = 0

    image_dpath = ub.Path('~/misc/facts/images').expand().ensuredir()
    # image_dpath =

    for fact in ub.ProgIter(fact_data['facts']):
        contexts = ComposeContexts(
            # doc.create(SamePage()),
            doc.create(MDFramed()),
            doc.create(pylatex.MiniPage(width=r'0.99\textwidth')))
        # with doc.create(pylatex.MiniPage(width=r'\textwidth')):
        with contexts:
            doc.append(pylatex.NoEscape(r'\paragraph{Fact:}'))
            text = ub.paragraph(fact['text'])

            if r'\[' in text:
                found = list(
                    re.finditer(
                        '(' + re.escape(r'\[') + '|' + re.escape(r'\]') + ')',
                        text))
                prev_x = 0
                for a, b in ub.iter_window(found, step=2):
                    part = text[prev_x:a.span()[0]]
                    doc.append(part)
                    ax, bx = a.span()[1], b.span()[0]
                    part = pylatex.NoEscape(r'$' + text[ax:bx] + r'$ ')
                    doc.append(part)
                    prev_x = b.span()[1]
                part = text[prev_x:]
                doc.append(part)
            else:
                # if '$' in text:
                #     parts = text.split('$')
                #     for idx, p in enumerate(parts):
                #         if idx % 2 == 1:
                #             doc.append(pylatex.NoEscape('$' + p + '$ '))
                #         else:
                #             doc.append(p)
                # else:
                doc.append(text)
            if QR_REFERENCE:
                doc.append('\n')
                num_refs = 0
                for refline in fact['references'].split('\n'):
                    if refline.startswith('http'):
                        found = refline
                        image_fname = ub.hash_data(found,
                                                   base='abc')[0:16] + '.png'
                        image_fpath = image_dpath / image_fname
                        if not image_fpath.exists():
                            # pyqrcode.create(found).svg(fpath, scale=6)
                            pyqrcode.create(found).png(str(image_fpath),
                                                       scale=2)
                        doc.append(
                            pylatex.NoEscape(r'\includegraphics[width=90px]{' +
                                             str(image_fpath) + '}'))
                        # doc.append(pylatex.NoEscape(r'\includesvg[width=120px]{' + fpath + '}'))
                        num_refs += 1
                        if num_refs > 3:
                            break
            else:
                doc.append(pylatex.NoEscape(r'\paragraph{References:}'))
                with doc.create(pylatex.Itemize()) as itemize:
                    for refline in fact['references'].split('\n'):
                        if refline:
                            refline = refline.strip()
                            itemize.add_item(refline)

        doc.append(pylatex.NoEscape(r'\bigskip'))
        if stop_flag:
            break

    print(doc.dumps())
    print('generate pdf')
    doc.generate_pdf(str(ub.Path('~/misc/facts/fact_document').expand()),
                     clean_tex=True)
Example #7
0
def benchmark_ubelt_import_time_robust():
    import pandas as pd
    import ubelt as ub
    import kwplot
    sns = kwplot.autosns(force='Qt5Agg')

    prog = ub.codeblock(r'''
        def _main():
            import subprocess
            import ubelt as ub
            measurements = []
            for i in range(200):
                row = {}
                # info = ub.cmd('python -X importtime -c "import ubelt"')
                # text = info['err']
                prog = subprocess.Popen('python -X importtime -c "import ubelt"', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                _, text = prog.communicate()
                text = text.decode()
                final_line = text.rstrip().split('\n')[-1]
                partial = final_line.split(':')[1].split('|')
                row['self_us'] = float(partial[0].strip())
                row['cummulative'] = float(partial[1].strip())
                measurements.append(row)
            import pandas as pd
            df = pd.DataFrame(measurements)
            stats = pd.DataFrame({
                'mean': df.mean(),
                'std': df.std(),
                'min': df.min(),
                'max': df.max(),
                'total': df.sum(),
            })
            info = stats.to_dict()
            info['version'] = ub.__version__
            print(info)
            # print(stats)
        _main()
        ''')

    dpath = ub.Path(ub.ensure_app_cache_dir('ubelt/tests/test_version_import'))
    fpath = dpath / 'do_test.py'
    fpath.write_text(prog)

    repo_root = ub.Path('$HOME/code/ubelt').expand()

    info = ub.cmd('git tag', cwd=repo_root)

    versions = [p for p in info['out'].split('\n') if p]
    branches = ['dev/1.0.1', 'main'] + versions

    fig = kwplot.figure(doclf=True)
    ax = fig.gca()

    bname_to_info = {}
    rows = []
    for bname in branches:
        print('bname = {!r}'.format(bname))
        ub.cmd('git checkout {}'.format(bname),
               cwd=repo_root,
               verbose=3,
               check=True)
        info = ub.cmd('python {}'.format(fpath), verbose=2)
        dict_info = eval(info['out'])
        bname_to_info[bname] = dict_info
        for stat in ['mean', 'min', 'max']:
            for type in ['self_us', 'cummulative']:
                rows.append({
                    'version': dict_info['version'],
                    'stat': stat,
                    'type': type,
                    'time': dict_info[stat][type],
                })
        df = pd.DataFrame(rows[-1:])
        print(df)
        # ax.cla()
        # sns.lineplot(data=df, x='version', y='time', hue='stat', style='type', ax=ax)

    ub.cmd('git checkout {}'.format('dev/1.0.1'), cwd=repo_root)
    df = pd.DataFrame(rows)
    from distutils.version import LooseVersion
    unique_versions = list(
        map(str, sorted(map(LooseVersion, df['version'].unique()))))
    df['release_index'] = df['version'].apply(
        lambda x: unique_versions.index(x))
    ax.cla()
    kwplot.figure(fnum=2, pnum=(2, 1, 1), doclf=True)
    ax = sns.lineplot(data=df[df['type'] == 'cummulative'],
                      x='release_index',
                      y='time',
                      hue='stat',
                      style='type',
                      marker='o')
    ax.set_title('Ubelt import time over release history')
    kwplot.figure(fnum=2, pnum=(2, 1, 2))
    sns.lineplot(data=df[df['type'] == 'self_us'],
                 x='release_index',
                 y='time',
                 hue='stat',
                 style='type',
                 marker='o')
Example #8
0
def multiple_items_from_a_dictionary():
    """
    Spotlight:
        ubelt.take

    Modivation:
        Working with Lists of Dictionaries

    Requires:
        kwimage
    """
    ...
    """
    When working with data, a common pattern is to iterate through it, and
    gather information about the work to be done, so a you can make a final
    structured pass through the data.

    In python we might do this by initializing an empty list and appending
    **dictionary of information**, to the list. (or you might yield
    dictionaries of information from a generator instead, either way you have a
    flat list).

    Some people might use lists of tuples instead of Lists of dictionaries, but
    using dictionaries makes it easy to add new information later (and it works
    very will with pandas).
    """
    import ubelt as ub
    import kwimage
    kwimage_test_image_names = [
        'airport', 'amazon', 'astro', 'carl', 'lowcontrast'
    ]
    rows = []
    for test_image in kwimage_test_image_names:
        fpath = ub.Path(kwimage.grab_test_image_fpath(test_image))
        imdata = kwimage.imread(fpath)
        row = {
            'mean': imdata.mean(),
            'std': imdata.std(),
            'sum': imdata.sum(),
            'max': imdata.max(),
            'min': imdata.min(),
        }
        rows.append(row)
    """
    For each row, you might want to grab multiple specific items from it.

    But having a separate assignment on each row wastes a lot of vertical
    space.
    """

    for row in rows:
        mean = row['mean']
        std = row['std']
        sum = row['sum']
        min = row['min']
        max = row['max']
    """
    You might put them one line explicitly, but that wastes a lot of horizontal
    space
    """
    for row in rows:
        mean, std, sum, min, max = row['mean'], row['std'], row['sum'], row[
            'min'], row['max']
    """
    What if we try to be clever? We can use a list comprehension
    """
    for row in rows:
        mean, std, sum, min, max = [
            row[k] for k in ['mean', 'std', 'sum', 'min', 'max']
        ]
    """
    That's not too bad, but we can do better
    """
    for row in rows:
        mean, std, sum, min, max = ub.take(
            row, ['mean', 'std', 'sum', 'min', 'max'])
Example #9
0
def generate_typed_stubs(modpath):
    """
    Attempt to use google-style docstrings, xdoctest, and mypy to generate
    typed stub files.

    Does not overwrite anything by itself.

    Args:
        modpath (PathLike): path to the module to generate types for

    Returns:
        Dict[PathLike, str]:
            A dictionary mapping the path of each file to write to the text to
            be written.

    Notes:
        FIXME: This currently requires my hacked version of mypy

    Example:
        >>> # xdoctest: +SKIP
        >>> # xdoctest: +REQUIRES(module:mypy)
        >>> # xdoctest: +REQUIRES(--hacked)
        >>> from xdev.cli.docstr_stubgen import *  # NOQA
        >>> import xdev
        >>> import ubelt as ub
        >>> from xdev.cli import docstr_stubgen
        >>> modpath = ub.Path(docstr_stubgen.__file__)
        >>> generated = generate_typed_stubs(modpath)
        >>> text = generated[ub.peek(generated.keys())]
        >>> assert 'PathLike' in text
        >>> assert 'Dict' in text
        >>> print(text)

    Ignore:
        pyfile mypy.stubgen
        # Delete compiled verisons so we can hack it

        # ls $VIRTUAL_ENV/lib/*/site-packages/mypy/*.so
        # rm $VIRTUAL_ENV/lib/*/site-packages/mypy/*.so
        # rm ~/.pyenv/versions/3.8.6/envs/pyenv3.8.6/lib/python3.8/site-packages/mypy/*.cpython-38-x86_64-linux-gnu.so

        # This works I think?
        if [[ ! -e "$HOME/code/mypy" ]];  then
            git clone https://github.com/python/mypy.git $HOME/code/mypy
        fi
        (cd $HOME/code/mypy && git pull)
        pip install -e $HOME/code/mypy


        pip install MonkeyType

        monkeytype run run_tests.py
        monkeytype stub ubelt.util_dict

        from typing import TypeVar
        from mypy.applytype import get_target_type
        z = TypeVar('Iterable')
        get_target_type(z)

        from mypy.expandtype import expand_type
        expand_type(z, env={})

        from mypy.types import get_proper_type
        get_proper_type(z)
        get_proper_type(dict)
        import typing
        get_proper_type(typing.Iterable)

        from mypy.types import deserialize_type, UnboundType
        import mypy.types as mypy_types
        z = UnboundType('Iterable')
        get_proper_type(dict)

        from mypy.fastparse import parse_type_string
        parse_type_string('dict', 'dict', 0, 0)
        z = parse_type_string('typing.Iterator', 'Any', 0, 0)
        get_proper_type(z)

    """
    # import pathlib
    # import ubelt as ub
    import os
    from mypy import stubgen
    from mypy import defaults
    from xdoctest import static_analysis
    from os.path import join
    import ubelt as ub

    # modname = 'scriptconfig'
    # module = ub.import_module_from_name(modname)
    # modpath = ub.Path(module.__file__).parent

    # for p in pathlib.Path(modpath).glob('*.pyi'):
    #     p.unlink()
    modpath = ub.Path(modpath)

    files = list(
        static_analysis.package_modpaths(modpath,
                                         recursive=True,
                                         with_libs=1,
                                         with_pkg=0))

    # files = [f for f in files if 'deprecated' not in f]
    # files = [join(ubelt_dpath, 'util_dict.py')]

    if modpath.is_file():
        output_dir = modpath.parent.parent
    else:
        output_dir = modpath.parent

    options = stubgen.Options(pyversion=defaults.PYTHON3_VERSION,
                              no_import=True,
                              doc_dir='',
                              search_path=[],
                              interpreter=sys.executable,
                              ignore_errors=False,
                              parse_only=True,
                              include_private=False,
                              output_dir=output_dir,
                              modules=[],
                              packages=[],
                              files=files,
                              verbose=False,
                              quiet=False,
                              export_less=True)
    # generate_stubs(options)

    mypy_opts = stubgen.mypy_options(options)
    py_modules, c_modules = stubgen.collect_build_targets(options, mypy_opts)

    # Collect info from docs (if given):
    sigs = class_sigs = None  # type: Optional[Dict[str, str]]
    if options.doc_dir:
        sigs, class_sigs = stubgen.collect_docs_signatures(options.doc_dir)

    # Use parsed sources to generate stubs for Python modules.
    stubgen.generate_asts_for_modules(py_modules, options.parse_only,
                                      mypy_opts, options.verbose)

    generated = {}

    for mod in py_modules:
        assert mod.path is not None, "Not found module was not skipped"
        target = mod.module.replace('.', '/')
        if os.path.basename(mod.path) == '__init__.py':
            target += '/__init__.pyi'
        else:
            target += '.pyi'
        target = join(options.output_dir, target)
        files.append(target)
        with stubgen.generate_guarded(mod.module, target,
                                      options.ignore_errors, options.verbose):
            stubgen.generate_stub_from_ast(mod, target, options.parse_only,
                                           options.pyversion,
                                           options.include_private,
                                           options.export_less)

            gen = ExtendedStubGenerator(
                mod.runtime_all,
                pyversion=options.pyversion,
                include_private=options.include_private,
                analyzed=not options.parse_only,
                export_less=options.export_less)
            assert mod.ast is not None, "This function must be used only with analyzed modules"
            mod.ast.accept(gen)
            # print('gen.import_tracker.required_names = {!r}'.format(gen.import_tracker.required_names))
            # print(gen.import_tracker.import_lines())

            # print('mod.path = {!r}'.format(mod.path))

            known_one_letter_types = {
                # 'T', 'K', 'A', 'B', 'C', 'V',
                'DT',
                'KT',
                'VT',
                'T'
            }
            for type_var_name in set(gen.import_tracker.required_names) & set(
                    known_one_letter_types):
                gen.add_typing_import('TypeVar')
                # gen.add_import_line('from typing import {}\n'.format('TypeVar'))
                gen._output = [
                    '{} = TypeVar("{}")\n'.format(type_var_name, type_var_name)
                ] + gen._output

            custom_types = {'Hasher'}
            for type_var_name in set(
                    gen.import_tracker.required_names) & set(custom_types):
                gen.add_typing_import('TypeVar')
                # gen.add_import_line('from typing import {}\n'.format('TypeVar'))
                gen._output = [
                    '{} = TypeVar("{}")\n'.format(type_var_name, type_var_name)
                ] + gen._output

            # Hack for specific module
            # if mod.path.endswith('util_path.py'):
            #     gen.add_typing_import('TypeVar')
            #     # hack for variable inheritence
            #     gen._output = ['import pathlib\nimport os\n', "_PathBase = pathlib.WindowsPath if os.name == 'nt' else pathlib.PosixPath\n"] + gen._output

            text = ''.join(gen.output())
            text = postprocess_hacks(text, mod)

            # Write output to file.
            # subdir = ub.Path(target).parent
            # if subdir and not os.path.isdir(subdir):
            #     os.makedirs(subdir)
            generated[target] = text
            # with open(target, 'w') as file:
            #     file.write(text)
    return generated
Example #10
0
def count_ubelt_usage():
    config = UsageConfig(cmdline=True)

    import ubelt as ub
    import glob
    from os.path import join
    names = [
        'xdoctest', 'netharn', 'xdev', 'xinspect', 'ndsampler',
        'kwarray', 'kwimage', 'kwplot', 'kwcoco',
        'scriptconfig', 'vimtk',
        'mkinit', 'futures_actors', 'graphid',

        'ibeis', 'plottool_ibeis', 'guitool_ibeis', 'utool', 'dtool_ibeis',
        'vtool_ibeis', 'hesaff', 'torch_liberator', 'liberator',
    ] + config['extra_modnames']

    code_repos = [ub.Path('~/code').expand() / name for name in names]
    repo_dpaths = code_repos + [
        # ub.Path('~/local').expand(),
        ub.Path('~/misc').expand(),
    ]
    all_fpaths = []
    for repo_dpath in repo_dpaths:
        name = repo_dpath.stem
        fpaths = glob.glob(join(repo_dpath, '**', '*.py'), recursive=True)
        for fpath in fpaths:
            all_fpaths.append((name, fpath))

    import re
    pat = re.compile(r'\bub\.(?P<attr>[a-zA-Z_][A-Za-z_0-9]*)\b')

    import ubelt as ub

    pkg_to_hist = ub.ddict(lambda: ub.ddict(int))
    for name, fpath in ub.ProgIter(all_fpaths):
        with open(fpath, 'r') as file:
            text = file.read()
        for match in pat.finditer(text):
            attr = match.groupdict()['attr']
            if attr in ub.__all__:
                pkg_to_hist[name][attr] += 1

    hist_iter = iter(pkg_to_hist.values())
    usage = next(hist_iter).copy()
    for other in hist_iter:
        for k, v in other.items():
            usage[k] += v
    for attr in ub.__all__:
        usage[attr] += 0

    for name in pkg_to_hist.keys():
        pkg_to_hist[name] = ub.odict(sorted(pkg_to_hist[name].items(), key=lambda t: t[1])[::-1])

    usage = ub.odict(sorted(usage.items(), key=lambda t: t[1])[::-1])

    if config['print_packages']:
        print(ub.repr2(pkg_to_hist, nl=2))

    if config['remove_zeros']:
        for k, v in list(usage.items()):
            if v == 0:
                usage.pop(k)

    if config['hardcoded_ubelt_hack']:
        blocklist = [
            'progiter', 'timerit', 'orderedset',
        ]
        for k in list(usage):
            if k in blocklist:
                usage.pop(k, None)
            elif k.startswith('util_'):
                usage.pop(k, None)
            elif k.startswith('_util_'):
                usage.pop(k, None)
            # ub._util_deprecated
            from ubelt import _util_deprecated
            if k in dir(_util_deprecated):
                usage.pop(k, None)

    print(ub.repr2(usage, nl=1))
    return usage
Example #11
0
    def main(cls, cmdline=0, **kwargs):
        """
        Ignore:
            repodir = ub.Path('~/code/pyflann_ibeis').expand()
            kwargs = {
                'repodir': repodir,
                'tags': ['binpy', 'erotemic', 'github'],
            }
            cmdline = 0

        Example:
            repodir = ub.Path.appdir('pypkg/demo/my_new_repo')
            import sys, ubelt
            sys.path.append(ubelt.expandpath('~/misc/templates/PYPKG'))
            from apply_template import *  # NOQA
            kwargs = {
                'repodir': repodir,
            }
            cmdline = 0
        """
        import ubelt as ub
        config = TemplateConfig(cmdline=cmdline, data=kwargs)
        repo_dpath = ub.Path(config['repodir'])
        repo_dpath.ensuredir()

        IS_NEW_REPO = 0

        create_new_repo_info = ub.codeblock('''
            # TODO:
            # At least instructions on how to create a new repo, or maybe an
            # API call
            https://github.com/new

            git init
            ''')
        print(create_new_repo_info)

        if IS_NEW_REPO:
            # TODO: git init
            # TODO: github or gitlab register
            pass

        self = TemplateApplier(config)
        self.setup().gather_tasks()

        self.setup().apply()

        if config['setup_secrets']:
            setup_secrets_fpath = self.repo_dpath / 'dev/setup_secrets.sh'
            if 'erotemic' in self.config['tags']:
                environ_export = 'setup_package_environs_github_erotemic'
                upload_secret_cmd = 'upload_github_secrets'
            elif 'pyutils' in self.config['tags']:
                environ_export = 'setup_package_environs_github_pyutils'
                upload_secret_cmd = 'upload_github_secrets'
            elif 'kitware' in self.config['tags']:
                environ_export = 'setup_package_environs_gitlab_kitware'
                upload_secret_cmd = 'upload_gitlab_repo_secrets'
            else:
                raise Exception

            import cmd_queue
            script = cmd_queue.Queue.create()
            script.submit(
                ub.codeblock(f'''
                cd {self.repo_dpath}
                source {setup_secrets_fpath}
                {environ_export}
                load_secrets
                export_encrypted_code_signing_keys
                git commit -am "Updated secrets"
                {upload_secret_cmd}
                '''))
            script.rprint()