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)
def logged_in_and_linked(monkeypatch): data = dict( LOGGED_IN_DATA, links={get_project_directory(): PROJECT_DATA} ) monkeypatch.setattr(settings, 'persistence', Persistence(data))
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) ))
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)
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)))
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, )
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, )
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)
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
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')
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)
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)
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)
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
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