예제 #1
0
def test_mw_unres():
    def unres_cmd(unresolved_arg):
        return unresolved_arg

    cmd = Command(unres_cmd)
    assert cmd.func is unres_cmd

    with pytest.raises(
            NameError,
            match=
            "unresolved middleware or handler arguments: .*unresolved_arg.*"):
        cmd.run(['unres_cmd'])

    def inner_mw(next_, arg):
        return next_()

    @face_middleware(provides='arg', flags=[Flag('--verbose', parse_as=True)])
    def outer_mw(next_):
        return next_(arg=1)

    def ok_cmd(arg):
        return None

    cmd = Command(ok_cmd, middlewares=[outer_mw])
    cmd.add_middleware(inner_mw)

    with pytest.raises(
            NameError,
            match=
            "unresolved middleware or handler arguments: .*arg.* check middleware order."
    ):
        cmd.run(['ok_cmd'])
    return
예제 #2
0
def test_cmd_name():
    def handler():
        return 0

    Command(handler, name='ok_cmd')

    name_err_map = {
        '':
        'non-zero length string',
        5:
        'non-zero length string',
        'name_':
        'without trailing dashes or underscores',
        'name--':
        'without trailing dashes or underscores',
        'n?me': ('valid subcommand name must begin with a letter, and'
                 ' consist only of letters, digits, underscores, and'
                 ' dashes')
    }

    for name, err in name_err_map.items():
        with pytest.raises(ValueError, match=err):
            Command(handler, name=name)

    return
예제 #3
0
def test_next_reserved():
    def bad_cmd(next_):
        return

    cmd = Command(bad_cmd)

    with pytest.raises(NameError):
        cmd.run(['bad_cmd'])
def test_help_subcmd():
    hhandler = HelpHandler(flag=False, subcmd='help')
    cmd = Command(None, 'cmd', help=hhandler)

    try:
        cmd.run(['cmd', 'help'])
    except SystemExit as se:
        assert se.code == 0

    with pytest.raises(ValueError, match='requires a handler function or help handler'):
        Command(None, help=None)
예제 #5
0
def test_post_posargs():
    cmd = Command(lambda posargs, post_posargs: None, name='cmd')

    res = cmd.parse(['cmd'])
    assert res.posargs == ()
    assert res.post_posargs == None
    # TODO: if this ^ isn't a useful signal, it would be more convenient to have the
    # behavior be the same as below

    res = cmd.parse(['cmd', '--'])
    assert res.posargs == ()
    assert res.post_posargs == ()
예제 #6
0
def test_err_subcmd_prog_name():
    cmd = Command(lambda: print("foo"), "foo")
    subcmd = Command(lambda: print("bar"), "bar")
    subcmd.add(Command(lambda: print("baz"), "baz"))
    cmd.add(subcmd)

    cc = CommandChecker(cmd)
    res = cc.fail('fred.py bar ba')
    assert 'fred.py' in res.stderr
    assert 'foo' not in res.stderr
def get_subcmd_cmd():
    subcmd = Command(None, name='subcmd', doc='the subcmd help')
    subcmd.add(_subsubcmd, name='subsubcmd', posargs={'count': 2, 'name': 'posarg_item'})
    cmd = Command(None, 'halp', doc='halp help')
    cmd.add(subcmd)

    return cmd
예제 #8
0
def test_bad_posargspec():
    # issue #11
    assert PosArgSpec(name=None).display.name is not None
    assert PosArgDisplay(name=None).name is not None

    posargs_args = [{
        'name': None
    }, {
        'provides': 'x'
    }, {
        'display': {
            'doc': 'wee'
        }
    }, {
        'display': {
            'name': 'better_name'
        }
    }]

    for arg in posargs_args:
        cmd = Command(lambda targs: None, name='cmd', posargs=arg)
        cmd_chk = CommandChecker(cmd, mix_stderr=True)
        res = cmd_chk.run(['cmd', '-h'])
        assert res.stdout.startswith('Usage')

    return
예제 #9
0
def test_flag_hidden():
    # TODO: is display='' sufficient for hiding (do we need hidden=True)
    cmd = Command(lambda tiger, dragon: None, 'cmd')
    cmd.add('--tiger', display='')
    flags = cmd.get_flags(with_hidden=False)
    assert 'tiger' not in [f.name for f in flags]

    cmd.add('--dragon', display={'label': ''})
    flags = cmd.get_flags(with_hidden=False)
    assert 'dragon' not in [f.name for f in flags]
예제 #10
0
def test_flag_init():
    cmd = Command(lambda flag, part: None, name='cmd')

    with pytest.raises(ValueError,
                       match='cannot make an argument-less flag required'):
        cmd.add('--flag', missing=ERROR, parse_as=True)

    # test custom callable multi
    cmd.add(Flag('--part', multi=lambda flag, vals: ''.join(vals)))
    res = cmd.parse(['cmd', '--part', 'a', '--part', 'b'])
    assert res.flags['part'] == 'ab'

    with pytest.raises(ValueError,
                       match='multi expected callable, bool, or one of.*'):
        cmd.add('--badflag', multi='nope')
예제 #11
0
def get_vcs_cmd(as_parser=False):
    cmd = Command(None, 'vcs')

    cmd.add(_add_cmd, name='add', posargs={'min_count': 1}, post_posargs=True)
    cmd.add(_checkout_cmd, name='checkout', posargs={'max_count': 1})

    if as_parser:
        cmd.__class__ = Parser

    return cmd
예제 #12
0
def test_char_missing_error():
    # testing required flags
    cmd = Command(lambda req_flag: None, name='cmd')
    cmd.add('--req-flag', char='-R', missing=ERROR)
    res = cmd.parse(['cmd', '--req-flag', 'val'])
    assert res.flags['req_flag'] == 'val'

    res = cmd.parse(['cmd', '-R', 'val'])
    assert res.flags['req_flag'] == 'val'

    with pytest.raises(ArgumentParseError, match='--req-flag'):
        cmd.parse(['cmd'])

    return
예제 #13
0
def test_posargspec_init():
    with pytest.raises(TypeError, match='expected callable or ERROR'):
        PosArgSpec(parse_as=object())
    with pytest.raises(TypeError, match='unexpected keyword'):
        PosArgSpec(badkw='val')

    with pytest.raises(ValueError, match='expected min_count >= 0'):
        PosArgSpec(min_count=-1)

    with pytest.raises(ValueError, match='expected max_count > 0'):
        PosArgSpec(max_count=-1)

    with pytest.raises(ValueError, match='expected min_count > max_count'):
        PosArgSpec(max_count=3, min_count=4)

    with pytest.raises(TypeError, match='.*PosArgDisplay instance.*'):
        PosArgSpec(display=object())
    with pytest.raises(TypeError, match='unexpected keyword'):
        PosArgSpec(display={'badkw': 'val'})

    # cmd = Command(lambda posargs_: posargs_, posargs=PosArgSpec(display=False))
    assert PosArgSpec(display=False).display.hidden == True
    assert PosArgSpec(display=PosArgDisplay(name='posargs'))

    cmd = Command(lambda: None, name='cmd', posargs=1)
    assert cmd.posargs.min_count == 1
    assert cmd.posargs.max_count == 1

    cmd = Command(lambda targs: None, name='cmd', posargs='targs')
    assert cmd.posargs.display.name == 'targs'
    assert cmd.posargs.provides == 'targs'

    cmd = Command(lambda targs: None, name='cmd', posargs=int)
    assert cmd.posargs.parse_as == int

    with pytest.raises(TypeError, match='.*instance of PosArgSpec.*'):
        Command(lambda targs: None, name='cmd', posargs=object())

    return
예제 #14
0
def test_multi_extend():
    cmd = Command(lambda override: None, name='cmd')
    cmd.add('--override', char='o', multi=True)
    res = cmd.parse(['cmd', '-o', 'x=y', '-o', 'a=b'])

    assert res.flags['override'] == ['x=y', 'a=b']

    res = cmd.parse(['cmd'])
    assert res.flags['override'] == []

    res = cmd.parse(['cmd', '-o=x'])
    assert res.flags['override'] == ['x']
예제 #15
0
def _get_cmd(prepare=False):
    cmd = Command(name='pocket_protector', func=None, doc=__doc__)  # func=None means output help

    # add flags
    cmd.add('--file', missing='protected.yaml',
            doc='path to the PocketProtector-managed file, defaults to protected.yaml in the working directory')
    cmd.add('--confirm', parse_as=True,
            doc='show diff and prompt for confirmation before modifying the file')
    cmd.add('--non-interactive', parse_as=True,
            doc='disable falling back to interactive authentication, useful for automation')
    cmd.add('--ignore-env', parse_as=True, display=False,  # TODO: keep?
            doc='ignore environment variables like PPROTECT_PASSPHRASE')
    cmd.add('--user', char='-u',
            doc="the acting user's email credential")
    cmd.add('--passphrase-file',
            doc='path to a file containing only the passphrase, likely provided by a deployment system')

    # add middlewares, outermost first ("first added, first called")
    cmd.add(mw_verify_creds)
    cmd.add(mw_write_kf)
    cmd.add(mw_ensure_kf)
    cmd.add(mw_exit_handler)

    # add subcommands
    cmd.add(add_key_custodian, name='init', doc='create a new protected')
    cmd.add(add_key_custodian)

    cmd.add(add_domain)
    cmd.add(rm_domain)

    cmd.add(add_owner)
    cmd.add(rm_owner)

    cmd.add(add_secret)
    cmd.add(update_secret)
    cmd.add(rm_secret)

    cmd.add(set_key_custodian_passphrase)
    cmd.add(rotate_domain_keys)

    cmd.add(decrypt_domain, posargs={'count': 1, 'provides': 'domain_name'})

    cmd.add(list_domains)
    cmd.add(list_domain_secrets, posargs={'count': 1, 'provides': 'domain_name'})
    cmd.add(list_all_secrets)
    cmd.add(list_audit_log)

    cmd.add(print_version, name='version')

    if prepare:
        cmd.prepare()  # an optional check on all subcommands, not just the one being executed

    return cmd
예제 #16
0
def test_bad_subprs():
    with pytest.raises(
            ValueError,
            match=
            'commands accepting positional arguments cannot take subcommands'):
        posarg_cmd = Command(lambda: None, 'pa', posargs=True)
        posarg_cmd.add(lambda: None, 'bad_subcmd')

    cmd = Command(lambda: None, 'base')
    cmd.add(lambda: None, 'twin')
    with pytest.raises(ValueError, match='conflicting subcommand name'):
        cmd.add(lambda: None, 'twin')

    with pytest.raises(TypeError, match='expected Command instance'):
        cmd.add_command(object())
예제 #17
0
파일: admin.py 프로젝트: baturin/montage
def main():
    """
    The main entrypoint, setting up a face application, with middleware, common flags, and subcommands.
    """
    cmd = Command(name='montage-admin',
                  func=None,
                  doc="CLI tools for administrating Montage.")

    # middleware
    cmd.add(_admin_dao_mw)
    cmd.add(_rdb_session_mw)

    cmd.add('--username', missing=ERROR)
    cmd.add('--debug',
            parse_as=True,
            doc='get extra output, enable debug console before db commit')
    cmd.add('--force',
            parse_as=True,
            doc='skip some confirmations, use with caution')
    cmd.add('--campaign-id', parse_as=int, missing=ERROR)
    cmd.add('--round-id', parse_as=int, missing=ERROR)
    cmd.add('--csv-path', missing=ERROR)
    cmd.add('--url', missing=ERROR)

    cmd.add(
        add_organizer
    )  # , posargs={'count': 1, 'name': 'username'})  # TODO: figure out if we want posarg/flag overriding

    ser_cmd = Command(name='series',
                      func=None,
                      doc='tools for administrating Montage series')
    ser_cmd.add(add_series, name='add')

    cmd.add(ser_cmd)

    cmp_cmd = Command(name='campaign',
                      func=None,
                      doc='tools for administrating Montage campaigns')
    cmp_cmd.add(list_campaigns, name='list')
    cmp_cmd.add(create_campaign, name='create')
    cmp_cmd.add(add_coordinator, name='add-coordinator')
    cmp_cmd.add(cancel_campaign, name='cancel')
    cmp_cmd.add(backfill_series)

    cmd.add(cmp_cmd)

    rnd_cmd = Command(name='round',
                      func=None,
                      doc='tools for administrating Montage rounds')
    rnd_cmd.add(create_round, name='create')
    rnd_cmd.add(import_gist, name='import-gist')
    rnd_cmd.add(activate_round, name='activate')
    rnd_cmd.add(pause_round, name='pause')
    rnd_cmd.add(advance_round, name='advance')
    rnd_cmd.add(edit_round_quorum, name='edit-quorum')
    rnd_cmd.add(check_round_dupes, name='check-dupes')
    rnd_cmd.add(apply_round_ratings, name='apply-ratings')
    rnd_cmd.add(retask_duplicate_ratings, name='retask-dupes')
    rnd_cmd.add(shuffle_round_assignments, name='shuffle-tasks')
    rnd_cmd.add(cancel_round, name='cancel')

    cmd.add(rnd_cmd)

    cmd.add(rdb_console)
    cmd.prepare()
    return cmd.run()
예제 #18
0
def test_command_misc_api():
    with pytest.raises(TypeError, match='unexpected keyword'):
        Command(lambda: None, name='ok', bad_kwarg=True)
예제 #19
0
def get_search_command(as_parser=False):
    """A command which provides various subcommands mimicking popular
    command-line text search tools to test power, compatiblity, and
    flexibility.

    """
    cmd = Command(None, 'search')
    cmd.add('--verbose', char='-V', parse_as=True)

    rg_subcmd = Command(_rg, 'rg')
    rg_subcmd.add('--glob',
                  char='-g',
                  multi=True,
                  parse_as=str,
                  doc='Include or exclude files/directories for searching'
                  ' that match the given glob. Precede with ! to exclude.')
    rg_subcmd.add('--max-count',
                  char='-m',
                  parse_as=int,
                  doc='Limit the number of matching lines per file.')
    rg_subcmd.add('--filetype', ChoicesParam(['py', 'js', 'html']))
    rg_subcmd.add('--extensions', ListParam(strip=True))

    cmd.add(rg_subcmd)

    cmd.add(_timestamp_mw)

    if as_parser:
        cmd.__class__ = Parser

    return cmd
예제 #20
0
파일: cli.py 프로젝트: antoine-gallix/glom
def main(argv):
    posargs = PosArgSpec(str, max_count=2, display={'label': '[spec [target]]'})
    cmd = Command(glom_cli, posargs=posargs, middlewares=[mw_get_target])
    cmd.add('--target-file', str, missing=None, doc='path to target data source')
    cmd.add('--target-format', str, missing='json',
            doc='format of the source data (json or python)')
    cmd.add('--spec-file', str, missing=None, doc='path to glom spec definition')
    cmd.add('--spec-format', str, missing='python',
            doc='format of the glom spec definition (json, python, python-full)')

    cmd.add('--indent', int, missing=2,
            doc='number of spaces to indent the result, 0 to disable pretty-printing')

    cmd.add('--debug', parse_as=True, doc='interactively debug any errors that come up')
    cmd.add('--inspect', parse_as=True, doc='interactively explore the data')

    return cmd.run(argv) or 0
예제 #21
0
파일: cli.py 프로젝트: mcgyver5/apatite
def main(argv=None):
    """\
    automation and analytics for curated lists of awesome software.

    Normal analysis workflow:

      * apatite pull-repos  (can take 3-4 hours, 25GB on the full APA, use --targets to limit)
      * apatite collect-metrics
      * apatite export-metrics
      * apatite analyze  # TODO
    """
    cmd = Command(name='apatite', func=None,
                  doc=main.__doc__)  # func=None means output help

    # add flags
    cmd.add('--file',
            missing='projects.yaml',
            doc='path to the project listing YAML file')
    cmd.add(
        '--confirm',
        parse_as=True,
        doc='show diff and prompt for confirmation before modifying the file')
    cmd.add(
        '--non-interactive',
        parse_as=True,
        doc=
        'disable falling back to interactive authentication, useful for automation'
    )
    cmd.add('--targets',
            parse_as=ListParam(str),
            missing=[],
            doc='specific target projects')
    cmd.add('--metrics',
            parse_as=ListParam(str),
            missing=[],
            doc='specific metrics to collect')
    cmd.add('--dry-run', parse_as=True, doc='do not save results')
    two_weeks_ago = _date_param('-2w')
    cmd.add(
        '--earliest',
        parse_as=_date_param,
        missing=two_weeks_ago,
        doc=(
            'minimum datetime value to accept (isodate or negative timedelta).'
            ' defaults to two weeks ago (-2w)'))
    cmd.add('--no-progress', parse_as=True)

    # add middlewares, outermost first ("first added, first called")
    cmd.add(mw_exit_handler)
    cmd.add(mw_ensure_project_listing)
    cmd.add(mw_ensure_work_dir)

    # add subcommands
    cmd.add(render)
    cmd.add(normalize)
    cmd.add(pull_repos)
    cmd.add(collect_metrics)
    cmd.add(show_recent_metrics)
    cmd.add(export_metrics)
    cmd.add(show_exportable_metrics)
    cmd.add(set_repo_added_dates)
    cmd.add(console)
    cmd.add(print_version, name='version')

    cmd.prepare(
    )  # an optional check on all subcommands, not just the one being executed

    try:
        cmd.run(argv=argv)  # exit behavior is handled by mw_exit_handler
    except Exception:
        if os.getenv('APATITE_DEBUG'):
            import pdb
            pdb.post_mortem()
        raise

    return
예제 #22
0
def main():
    cmd = Command(cut_mp4)

    cmd.add('--input', missing=ERROR, doc='path to the input mp4 file')
    cmd.add('--output', missing=ERROR, doc='path to write the output mp4 file')
    cmd.add('--start', doc='starting timestamp in hh:mm:ss format')
    cmd.add('--end', doc='ending timestamp in hh:mm:ss format')

    cmd.add('--no-align-keyframes',
            parse_as=True,
            doc="don't align to the nearest keyframe, potentially"
            " creating an unclean cut with video artifacts")

    cmd.run()
예제 #23
0
def get_calc_cmd(as_parser=False):
    cmd = Command(None, 'calc')

    cmd.add(_add_cmd, name='add', posargs={'min_count': 2, 'parse_as': float})
    cmd.add(_add_two_ints, name='add_two_ints', posargs={'count': 2, 'parse_as': int, 'provides': 'ints'})
    cmd.add(_is_odd, name='is_odd', posargs={'count': 1, 'parse_as': int, 'provides': 'target_int'})
    cmd.add(_ask_halve, name='halve', posargs=False)
    cmd.add(_ask_blackjack, name='blackjack')

    if as_parser:
        cmd.__class__ = Parser

    return cmd
예제 #24
0
파일: cli.py 프로젝트: sanjaysiddhanti/glom
def main(argv):
    posargs = PosArgSpec(str,
                         max_count=2,
                         display={'label': '[spec [target]]'})
    cmd = Command(glom_cli, posargs=posargs, middlewares=[mw_get_target])
    cmd.add('--target-file',
            str,
            missing=None,
            doc='path to target data source')
    cmd.add('--target-format',
            str,
            missing='json',
            doc='format of the source data (json or python)')
    cmd.add('--spec-file',
            str,
            missing=None,
            doc='path to glom spec definition')
    cmd.add(
        '--spec-format',
        str,
        missing='python',
        doc='format of the glom spec definition (json, python, python-full)')

    cmd.add(
        '--indent',
        int,
        missing=2,
        doc=
        'number of spaces to indent the result, 0 to disable pretty-printing')

    cmd.add('--debug',
            parse_as=True,
            doc='interactively debug any errors that come up')
    cmd.add('--inspect', parse_as=True, doc='interactively explore the data')

    return cmd.run(argv) or 0
예제 #25
0
def main():
    cmd = Command(cut_mp4)

    cmd.add('--input', missing=ERROR, doc='path to the input mp4 file')
    cmd.add('--output', missing=ERROR, doc='path to write the output mp4 file')
    cmd.add('--start', doc='starting timestamp in hh:mm:ss format')
    cmd.add('--end', doc='ending timestamp in hh:mm:ss format')

    cmd.add('--filter-audio',
            parse_as=True,
            doc='do high-pass/low-pass noise filtration of audio.'
            ' good for noisy meetup recordings.')
    cmd.add('--no-align-keyframes',
            parse_as=True,
            doc="don't align to the nearest keyframe, potentially"
            " creating an unclean cut with video artifacts")

    cmd.run()
예제 #26
0
파일: cli.py 프로젝트: mahmoud/chert
def main():
    cmd = Command(name='chert', func=None)

    cmd.add(init, posargs={'min_count': 1, 'max_count': 1, 'display': 'target_dir', 'provides': 'target_dir'})
    cmd.add(serve)
    cmd.add(render)
    cmd.add(publish)
    cmd.add(clean)
    cmd.add(version)

    # cmd.add('--target-dir', doc='path to generate new chert site')

    cmd.add(_cur_input_path_mw)
    cmd.run()
예제 #27
0
파일: cli.py 프로젝트: hatnote/pacetrack
def main(argv=None):
    cmd = Command(name='pacetrack', func=None)

    # subcommands
    update_subcmd = Command(update, posargs={'min_count': 1, 'display': 'campaign_id', 'provides': 'campaign_ids'})
    # update_subcmd.add('campaign_name')
    cmd.add(update_subcmd)
    cmd.add(update_all)
    cmd.add(render_all)
    cmd.add(list_campaigns)
    cmd.add(print_version, name='version')
    # cmd.add(prune)  # mostly for testing

    cmd.add('--jsub', parse_as=True, doc='run commands through the WMF Labs job grid (for production use only)')
    cmd.add('--force', parse_as=True, doc='ignore configured fetch frequency and force updates')
    cmd.add('--dry-run', parse_as=True, doc='log actions without performing them (e.g., do not remove files)')

    # flags
    cmd.add('--debug', doc='increase logging level', parse_as=True, missing=DEBUG)

    # middlewares
    cmd.add(mw_cli_log)

    try:
        cmd.run()
    except Exception:
        # TODO: once face is stable, this can become part of the middleware
        if os.getenv('PACETRACK_ENABLE_DEBUG'):
            import pdb;pdb.post_mortem()
        raise
예제 #28
0
def main():
    cmd = Command(name='chert', func=None)

    cmd.add(init, posargs={'count': 1, 'name': 'target_dir'})
    cmd.add(serve)
    cmd.add(render)
    cmd.add(publish)
    cmd.add(clean)
    cmd.add(version)

    # cmd.add('--target-dir', doc='path to generate new chert site')

    cmd.add(_cur_input_path_mw)
    cmd.run()
예제 #29
0
def main():
    cmd = Command(busy_loop, 'cmd', middlewares=[output_streams_mw])

    sum_subcmd = Command(sum_func, 'sum')
    sum_subcmd.add(
        '--num',
        parse_as=ListParam(int),
        missing=(0, ),
        doc='a number to include in the sum, expects integers at the moment'
        ' because it is fun to change things later')
    sum_subcmd.add(
        '--grummmmmmmmmmmmmmmmmmm',
        parse_as=int,
        multi=True,
        missing=0,
        doc='a bizarre creature, shrek-like, does nothing, but is here to'
        ' make the help longer and less helpful but still good for wraps.')

    cmd.add(sum_subcmd)

    cmd.add(verbose_mw)

    cmd.add(subtract, doc='', posargs=float)

    cmd.add(print_args, 'print', '', posargs=True)

    cmd.add('--loop-count', parse_as=int)

    return cmd.run()  # execute