Example #1
0
def test_init(runner, logged_in):
    name = get_random_string()
    dir = get_project_directory()
    with open(os.path.join(dir, 'my_script.py'), 'w') as script_fp:
        script_fp.write('# Hello')

    with requests_mock.mock() as m:
        m.post('https://app.valohai.com/api/v0/projects/', json={
            'id': str(uuid4()),
            'name': name,
        })
        result = runner.invoke(init, input='\n'.join([
            'y',  # correct directory
            'echo hello',  # command
            'y',  # yes, that's right
            '1',  # image number 1
            'n',  # no, actually
            '',  # erm what
            'docker',  # image called docker, yes
            'y',  # okay, that's better
            'y',  # confirm write
            'c',  # create new
            name,  # that's a nice name
        ]), catch_exceptions=False)
        assert result.exit_code == 0
        assert 'my_script.py' in result.output
        assert 'Happy (machine) learning!' in result.output

        assert os.path.exists(os.path.join(dir, 'valohai.yaml'))
        assert get_project(dir)
Example #2
0
def logged_in_and_linked(monkeypatch):
    data = dict(
        LOGGED_IN_DATA,
        links={get_project_directory(): PROJECT_DATA}
    )

    monkeypatch.setattr(settings, 'persistence', Persistence(data))
Example #3
0
def unlink(yes):
    """
    Unlink a linked Valohai project.
    """
    dir = get_project_directory()
    project = get_project()
    if not project:
        click.echo('{dir} or its parents do not seem linked to a project.'.format(dir=dir))
        return 1
    if not yes:
        click.confirm(
            'Unlink {dir} from {name}?'.format(
                dir=click.style(project.directory, bold=True),
                name=click.style(project.name, bold=True),
            ),
            abort=True,
        )
    links = settings.get('links', {})
    links.pop(dir)
    settings['links'] = links
    settings.save()
    success('Unlinked {dir} from {name}.'.format(
        dir=click.style(dir, bold=True),
        name=click.style(project.name, bold=True)
    ))
Example #4
0
def lint(filenames: List[str]) -> None:
    """
    Lint (syntax-check) a valohai.yaml file.

    The return code of this command will be the total number of errors found in all the files.
    """
    if not filenames:
        project = get_project()
        if project:
            project.refresh_details()
            yaml_path = project.get_yaml_path()
        else:
            yaml_path = 'valohai.yaml'
        directory = (project.directory if project else get_project_directory())
        config_file = os.path.join(directory, yaml_path)
        if not os.path.exists(config_file):
            raise CLIException(
                f'There is no {config_file} file. Pass in the names of configuration files to lint?'
            )
        filenames = [config_file]
    total_errors = 0
    for filename in filenames:
        total_errors += validate_file(filename)
    if total_errors:
        warn(f'There were {total_errors} total errors.')
    click.get_current_context().exit(total_errors)
Example #5
0
def unlink(yes: bool) -> None:
    """
    Unlink a linked Valohai project.
    """
    dir = get_project_directory()
    project = get_project()
    if not project:
        warn(f'{dir} or its parents do not seem linked to a project.')
        return
    if not yes:
        click.confirm(
            'Unlink {dir} from {name}?'.format(
                dir=click.style(project.directory, bold=True),
                name=click.style(project.name, bold=True),
            ),
            abort=True,
        )
    links = settings.links.copy()
    links.pop(dir)
    settings.persistence.set('links', links)
    settings.persistence.save()
    success('Unlinked {dir} from {name}.'.format(dir=click.style(dir,
                                                                 bold=True),
                                                 name=click.style(project.name,
                                                                  bold=True)))
Example #6
0
def create(name, description, link, yes):
    """Create a new project and optionally link it to the directory."""
    return create_project(
        directory=get_project_directory(),
        name=name,
        description=description,
        link=link,
        yes=yes,
    )
Example #7
0
def create(name: str, description: str, link: bool, owner: Optional[str], yes: bool) -> None:
    """Create a new project and optionally link it to the directory."""
    create_project(
        directory=get_project_directory(),
        name=name,
        description=description,
        link=link,
        owner=owner,
        yes=yes,
    )
Example #8
0
def init():
    """
    Interactively initialize a Valohai project.
    """
    project = get_project()
    if project:
        error(
            'The directory {directory} is already linked to {name}. Please unlink the directory first.'
            .format(
                directory=project.directory,
                name=project.name,
            ))
        sys.exit(1)

    click.secho(
        'Hello! This wizard will help you start a Valohai compatible project.',
        fg='green',
        bold=True)
    directory = get_project_directory()
    if not click.confirm(
            'First, let\'s make sure {dir} is the root directory of your project. Is that correct?'
            .format(dir=click.style(directory,
                                    bold=True), )):  # pragma: no cover
        click.echo(
            'Alright! Please change to the root directory of your project and try again.'
        )
        return

    valohai_yaml_path = os.path.join(directory, 'valohai.yaml')

    if not os.path.isfile(valohai_yaml_path):
        click.echo(
            'Looks like you don\'t have a Valohai.yaml file. Let\'s create one!'
        )
        yaml_wizard(directory)
    else:
        click.echo(
            'There is a Valohai.yaml file in this directory, so let\'s skip the creation wizard.'
        )

    try:
        get_host_and_token()
    except NotLoggedIn:  # pragma: no cover
        error('Please log in with `vh login` before continuing.')
        sys.exit(3)

    link_or_create_prompt(directory)

    width = min(70, click.get_terminal_size()[0])
    click.secho('*' * width, fg='green', bold=True)
    click.echo(DONE_TEXT.strip().format(command=click.style(
        'vh exec run --adhoc --watch execute', bold=True), ))
    click.secho('*' * width, fg='green', bold=True)
Example #9
0
def get_project(dir: Optional[str] = None, require: bool = False) -> Optional[ProjectOrRemoteProject]:
    """
    Get the Valohai project object for a directory context.

    The directory tree is walked upwards to find an actual linked directory.

    :param dir: Directory (defaults to cwd)
    :param require: Raise an exception if no project is found
    :return: Project object, or None.
    """
    dir = dir or get_project_directory()
    project = settings.get_project(dir)
    if not project and require:
        raise NoProject(f'No project is linked to {dir}')
    return project
Example #10
0
def test_parcel(runner, logged_in_and_linked, tmpdir):
    input_dir = get_project_directory()
    create_fake_project(input_dir)
    output_dir = str(tmpdir.mkdir('output'))

    with requests_mock.mock() as m:
        result = runner.invoke(parcel, ['-d', output_dir])
        assert result.exit_code == 0

    assert set(os.listdir(output_dir)) == {
        'docker-alpine.tar',
        'docker-busybox.tar',
        'git-repo.bundle',
        'python-archives',
        'unparcel.sh',
    }

    with open(os.path.join(output_dir, 'git-repo.bundle'), 'rb') as bundle_fp:
        assert bundle_fp.read(32).startswith(b'# v2 git bundle')
Example #11
0
def lint(filenames):
    """
    Lint (syntax-check) a valohai.yaml file.

    The return code of this command will be the total number of errors found in all the files.
    """
    if not filenames:
        project = get_project()
        directory = (project.directory if project else get_project_directory())
        config_file = os.path.join(directory, 'valohai.yaml')
        if not os.path.exists(config_file):
            raise CLIException(
                'There is no %s file. Pass in the names of configuration files to lint?'
                % config_file)
        filenames = [config_file]
    total_errors = 0
    for filename in filenames:
        total_errors += validate_file(filename)
    if total_errors:
        warn('There were %d total errors.' % total_errors)
    click.get_current_context().exit(total_errors)
Example #12
0
def link(project: Optional[str], yes: bool) -> Any:
    """
    Link a directory with a Valohai project.
    """
    dir = get_project_directory()
    current_project = get_project(dir)
    if current_project and not yes:
        click.confirm(
            (f'{click.style(current_project.directory, bold=True)} is already linked to '
             f'project {click.style(current_project.name, bold=True)}; continue?'
             ),
            abort=True,
        )
    try:
        project_obj = choose_project(dir, spec=project)
        if not project_obj:
            return 1
        set_project_link(dir, project_obj, inform=True)
    except NewProjectInstead:
        name = click.prompt('Name the new project')
        if name:
            create_project(dir, name, yes=yes)
Example #13
0
def link(project, yes):
    """
    Link a directory with a Valohai project.
    """
    dir = get_project_directory()
    current_project = get_project(dir)
    if current_project and not yes:
        click.confirm(
            text='{dir} is already linked to project {name}; continue?'.format(
                dir=click.style(current_project.directory, bold=True),
                name=click.style(current_project.name, bold=True),
            ),
            abort=True,
        )
    try:
        project = choose_project(dir, spec=project)
        if not project:
            return 1
        set_project_link(dir, project, inform=True)
    except NewProjectInstead:
        name = click.prompt('Name the new project')
        if name:
            create_project(dir, name, yes=yes)
Example #14
0
def get_project(dir=None, require=False):
    """
    Get the Valohai project object for a directory context.

    The object is augmented with the `dir` key.

    :param dir: Directory (defaults to cwd)
    :param require: Raise an exception if no project is found
    :return: Project object, or None.
    :rtype: valohai_cli.models.project.Project|None
    """
    links = settings.get('links') or {}
    if not links:
        if require:
            raise NoProject('No projects are configured')
        return None
    orig_dir = dir or get_project_directory()
    for dir in walk_directory_parents(orig_dir):
        project_obj = links.get(dir)
        if project_obj:
            return Project(data=project_obj, directory=dir)
    if require:
        raise NoProject('No project is linked to %s' % orig_dir)
    return None
Example #15
0
cases = {
    'valid': {
        'data': CONFIG_YAML,
        'output': 'No errors',
        'exit_code': 0,
    },
    'invalid': {
        'data': INVALID_CONFIG_YAML,
        'output': 'There were 5 total errors',
        'exit_code': 5,
    },
    'broken': {
        'data': BROKEN_CONFIG_YAML,
        'output': 'line 1, column 2',
        'exit_code': 1,
    },
}


@pytest.mark.parametrize('case', ('valid', 'invalid', 'broken'))
@pytest.mark.parametrize('pass_explicit', (False, True))
def test_lint(runner, case, pass_explicit):
    case = cases[case]
    filename = os.path.join(get_project_directory(), 'valohai.yaml')
    with open(filename, 'w') as yaml_fp:
        yaml_fp.write(case['data'])
    args = ([filename] if pass_explicit else [])
    rv = runner.invoke(lint, args, catch_exceptions=False)
    assert rv.exit_code == case['exit_code']
    assert case['output'] in rv.output