def test_yaml_util_get_virtual_environment_from_yaml_custom(self): test_caos_yaml = "virtual_environment: 'custom_venv'" with open(file=os.path.abspath(get_current_dir() + "/" + "caos.yml"), mode="w") as file: file.write(test_caos_yaml) self.assertEqual("custom_venv", get_virtual_environment_from_yaml())
def create_virtual_env(current_dir: str): """ Raises: OpenCaosFileException InvalidCaosFileFormat WrongKeyTypeInYamlFile CreateVirtualEnvironmentException MissingBinaryException """ env_name = get_virtual_environment_from_yaml() env_path: str = os.path.abspath(current_dir + "/" + env_name) if os.path.isdir(env_path): caos_command_print( command=NAME, message=INFO_MESSAGE( "The virtual environment already exists so a new one won't be created" )) else: caos_command_print( command=NAME, message=INFO_MESSAGE("Creating a new virtual environment...")) create_env_process: subprocess.CompletedProcess = subprocess.run( [ sys.executable, "-m", DEFAULT_VIRTUAL_ENVIRONMENT_NAME, os.path.abspath(get_current_dir() + "/" + env_name) ], stderr=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) if create_env_process.returncode != 0: raise CreateVirtualEnvironmentException(create_env_process.stderr) caos_command_print( command=NAME, message=SUCCESS_MESSAGE("A new virtual environment was created")) if is_win_os(): pip_path: str = PIP_PATH_VENV_WIN.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, env_name) python_path: str = PYTHON_PATH_VENV_WIN.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, env_name) if is_posix_os(): pip_path: str = PIP_PATH_VENV_POSIX.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, env_name) python_path: str = PYTHON_PATH_VENV_POSIX.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, env_name) if not os.path.isfile(pip_path): caos_command_print( command=NAME, message=WARNING_MESSAGE( "The virtual environment does not have a 'pip' binary")) if not os.path.isfile(python_path): raise_missing_python_binary_exception(env_name=env_name)
def main(args: List[str]) -> ExitCode: current_dir: str = get_current_dir() if not os.path.isfile( os.path.abspath(current_dir + "/" + CAOS_YAML_FILE_NAME)): raise MissingYamlException( "No '{}' file found. Try running first 'caos init'".format( CAOS_YAML_FILE_NAME)) if len(args) < 1: raise MissingTaskArgument("No task name to execute was given") task_name: str = args[0] available_tasks: Tasks = get_tasks_from_yaml() if not task_name in available_tasks: raise TaskNotFound("No task named '{}' was found".format(task_name)) if len(args) > 1: caos_command_print( command=NAME, message=WARNING_MESSAGE("The tasks can't receive arguments")) steps: List[str] = available_tasks[task_name] is_unittest: bool = True if isinstance(sys.stdout, StringIO) else False for step in steps: if step in available_tasks: main(args=[step]) continue # The current Unittest for this redirects the stdout to a StringIO() buffer, which is not compatible with # subprocess, so for this scenario a subprocess.PIPE is used instead of the sys.stdout to be able to capture # the output in the unittests step_process: subprocess.CompletedProcess = subprocess.run( step, stdout=subprocess.PIPE if is_unittest else sys.stdout, stderr=subprocess.STDOUT, stdin=sys.stdin, universal_newlines=True, shell=True) if is_unittest and step_process.stdout: print(step_process.stdout, end="") if step_process.returncode != 0: raise StepExecutionError( "Within the task '{}' the step '{}' returned a non zero exit code" .format(task_name, step)) return ExitCode(0)
def main(args: List[str]) -> ExitCode: virtual_env_name: str = args[0] if len(args) >= 1 else None current_dir: str = get_current_dir() simple_yaml_template = None simple_init_args = ('--simple', '-s', '-S') if virtual_env_name in simple_init_args: simple_yaml_template = _CAOS_YAML_TEMPLATE_SIMPLE virtual_env_name = None create_caos_yaml(current_dir=current_dir, env_name=virtual_env_name, caos_yaml_template=simple_yaml_template) if not simple_yaml_template: create_virtual_env(current_dir=current_dir) return ExitCode(0)
def test_yaml_util_get_dependencies_from_yaml(self): test_caos_yaml = """\ dependencies: dep1: "latest" dep2: "^1.5.0" dep3: "~2" dep4: "./dep4-1.0.0-py3-none-any.whl" dep5: "./dep5-1.0.0-py3-none-any.dist-info" """ with open(file=os.path.abspath(get_current_dir() + "/" + "caos.yml"), mode="w") as file: file.write(test_caos_yaml) dependencies = get_dependencies_from_yaml() expected_result = { "dep1": "dep1", "dep2": "~=1.5", "dep3": "~=2.0.0", "dep4": "./dep4-1.0.0-py3-none-any.whl", "dep5": "./dep5-1.0.0-py3-none-any.dist-info" } self.assertEqual(expected_result, dependencies)
def test_yaml_util_get_tasks_from_yaml(self): test_caos_yaml = """\ tasks: test: - "caos unittest ./" run: - "caos python ./main.py" test_and_run: - test - run - "echo 'Done'" """ with open(file=os.path.abspath(get_current_dir() + "/" + "caos.yml"), mode="w") as file: file.write(test_caos_yaml) tasks = get_tasks_from_yaml() expected_result = { 'test': ['caos unittest ./'], 'run': ['caos python ./main.py'], 'test_and_run': ['test', 'run', "echo 'Done'"] } self.assertEqual(expected_result, tasks)
def main(args: List[str]) -> ExitCode: current_dir: str = get_current_dir() if not os.path.isfile( os.path.abspath(current_dir + "/" + CAOS_YAML_FILE_NAME)): raise_missing_yaml_exception() venv_name: str = get_virtual_environment_from_yaml() if not os.path.isdir(os.path.abspath(current_dir + "/" + venv_name)): raise_missing_virtual_environment_exception(env_name=venv_name) if is_win_os(): python_path: str = PYTHON_PATH_VENV_WIN.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) elif is_posix_os(): python_path: str = PYTHON_PATH_VENV_POSIX.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) if not os.path.isfile(python_path): raise_missing_python_binary_exception(env_name=venv_name) # The current Unittest for this redirects the stdout to a StringIO() buffer, which is not compatible with # subprocess, so for this scenario a subprocess.PIPE is used instead of the sys.stdout to be able to capture # the output in the unittests is_unittest: bool = True if isinstance(sys.stdout, StringIO) else False python_process: subprocess.CompletedProcess = subprocess.run( [python_path] + args, stdout=subprocess.PIPE if is_unittest else sys.stdout, stderr=subprocess.STDOUT, stdin=sys.stdin, universal_newlines=True) if is_unittest and python_process.stdout: print(python_process.stdout) return ExitCode(python_process.returncode)
def read_caos_yaml() -> CaosYaml: """ Raises: OpenCaosFileException InvalidCaosFileFormat """ try: yaml_path: str = os.path.abspath(get_current_dir() + "/" + CAOS_YAML_FILE_NAME) with open(file=yaml_path, mode="r") as caos_file: caos_file_content: str = caos_file.read() except Exception as e: raise OpenCaosFileException(str(e)) try: caos_yaml: CaosYaml = yaml.load(stream=caos_file_content, Loader=yaml.FullLoader) except RecursionError as e: raise RecursionError("Maximum recursion depth exceeded") except Exception as e: raise InvalidCaosFileFormat( "The file does not contain valid YAML syntax: " + str(e)) return caos_yaml
def main(args: List[str]) -> ExitCode: current_dir: str = get_current_dir() if not os.path.isfile(os.path.abspath(current_dir + "/" + CAOS_YAML_FILE_NAME)): raise_missing_yaml_exception() venv_name: str = get_virtual_environment_from_yaml() if not os.path.isdir(os.path.abspath(current_dir + "/" + venv_name)): raise_missing_virtual_environment_exception(env_name=venv_name) if is_win_os(): pip_path: str = PIP_PATH_VENV_WIN.replace(DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) python_path: str = PYTHON_PATH_VENV_WIN.replace(DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) elif is_posix_os(): pip_path: str = PIP_PATH_VENV_POSIX.replace(DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) python_path: str = PYTHON_PATH_VENV_POSIX.replace(DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) if not os.path.isfile(pip_path): raise_missing_pip_binary_exception(env_name=venv_name) if not os.path.isfile(python_path): raise_missing_python_binary_exception(env_name=venv_name) if args: caos_command_print( command=NAME, message=WARNING_MESSAGE("The update command does not support arguments") ) dependencies: Dependencies = get_dependencies_from_yaml() is_unittest: bool = True if isinstance(sys.stdout, StringIO) else False if "pip" in dependencies: if "pip" == dependencies.get("pip"): dep: str = "pip" else: dep: str = "pip{}".format(dependencies.get("pip")) caos_command_print( command=NAME, message=INFO_MESSAGE("Updating PIP...") ) del dependencies["pip"] install_pip_process: subprocess.CompletedProcess = subprocess.run( [python_path, "-m", "pip", "install", "--force-reinstall", dep], stdout=subprocess.PIPE if is_unittest else sys.stdout, stderr=subprocess.STDOUT, universal_newlines=True ) if install_pip_process.returncode != 0: caos_command_print( command=NAME, message=WARNING_MESSAGE("PIP could not be updated") ) else: caos_command_print( command=NAME, message=SUCCESS_MESSAGE("PIP was successfully updated") ) if not dependencies: caos_command_print( command=NAME, message=INFO_MESSAGE("No dependencies to install") ) return ExitCode(0) deps: List[str] = [] for dep_name, dep_version in dependencies.items(): if dep_name == dep_version: dep = dep_name elif dep_version.endswith(".whl") or dep_version.endswith(".dist-info") or dep_version.endswith(".tar.gz"): dep = dep_version else: dep = "{}{}".format(dep_name, dep_version) deps.append(dep) caos_command_print( command=NAME, message=INFO_MESSAGE("Installing dependencies...") ) install_deps_process: subprocess.CompletedProcess = subprocess.run( [python_path, "-m", "pip", "install", "--force-reinstall"] + deps, stdout=subprocess.PIPE if is_unittest else sys.stdout, stderr=subprocess.STDOUT, universal_newlines=True ) if install_deps_process.returncode != 0: caos_command_print( command=NAME, message=ERROR_MESSAGE("It was not possible to install the dependencies") ) return ExitCode(install_deps_process.returncode) caos_command_print( command=NAME, message=SUCCESS_MESSAGE("All dependencies have been installed") ) return ExitCode(0)
import os import sys import shutil import unittest from io import StringIO from caos._cli_commands import command_init, command_pip from caos._internal.console.tools import escape_ansi from caos._internal.exceptions import MissingBinaryException, MissingVirtualEnvironmentException from caos._internal.utils.os import is_posix_os, is_win_os from caos._internal.utils.working_directory import get_current_dir from caos._internal.constants import DEFAULT_VIRTUAL_ENVIRONMENT_NAME, PIP_PATH_VENV_POSIX, PIP_PATH_VENV_WIN _CURRENT_DIR = get_current_dir() _MISSING_PIP_BINARY_MESSAGE = "The virtual environment does not have a 'pip' binary. "\ "Try deleting the folder 'venv' and run 'caos init'" _MISSING_VIRTUAL_ENVIRONMENT_MESSAGE = "No virtual environment 'venv' could be found. Try running first 'caos init'" class TestCommandPip(unittest.TestCase): def _redirect_stdout(self): self.new_stdout, self.old_stdout = StringIO(), sys.stdout self.new_stderr, self.old_stderr = StringIO(), sys.stderr sys.stdout, sys.stderr = self.new_stdout, self.new_stderr def _restore_stdout(self): sys.stdout, sys.stderr = self.old_stdout, self.old_stderr def setUp(self) -> None: self._redirect_stdout() if os.path.isdir("tmp"): shutil.rmtree("tmp")
def main(args: List[str]) -> ExitCode: current_dir: str = get_current_dir() if not os.path.isfile( os.path.abspath(current_dir + "/" + CAOS_YAML_FILE_NAME)): raise_missing_yaml_exception() venv_name: str = get_virtual_environment_from_yaml() if not os.path.isdir(os.path.abspath(current_dir + "/" + venv_name)): raise_missing_virtual_environment_exception(env_name=venv_name) if is_win_os(): pip_path: str = PIP_PATH_VENV_WIN.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) python_path: str = PYTHON_PATH_VENV_WIN.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) elif is_posix_os(): pip_path: str = PIP_PATH_VENV_POSIX.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) python_path: str = PYTHON_PATH_VENV_POSIX.replace( DEFAULT_VIRTUAL_ENVIRONMENT_NAME, venv_name) if not os.path.isfile(pip_path): raise_missing_pip_binary_exception(env_name=venv_name) if not os.path.isfile(python_path): raise_missing_python_binary_exception(env_name=venv_name) if args: caos_command_print(command=NAME, message=WARNING_MESSAGE( "The check command does not support arguments")) yaml_deps: Dependencies = get_dependencies_from_yaml() if not yaml_deps: caos_command_print( command=NAME, message=WARNING_MESSAGE( "There are no dependencies defined in the '{}' file".format( CAOS_YAML_FILE_NAME))) return ExitCode(0) pip_list_process: subprocess.CompletedProcess = subprocess.run( [python_path, "-m", "pip", "list"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True) if pip_list_process.returncode != 0 and pip_list_process.stderr: caos_command_print( command=NAME, message=ERROR_MESSAGE( "It was not possible to check the virtual environment dependencies" )) return ExitCode(1) pip_list_dependency_regex = re.compile( "^(?P<name>.+)(( )+)(\()?(?P<version>((\d+)(\.\d+)?(\.\d+)?))(\))?$") pip_list_output_by_lines = [ line.strip() for line in pip_list_process.stdout.split("\n") ] installed_deps: Dependencies = {} for line in pip_list_output_by_lines: dep = pip_list_dependency_regex.match(line) if dep: installed_deps[dep.group("name").strip().lower()] = dep.group( "version").strip() not_installed_deps: List[str] = [] for dep in yaml_deps: pip_dep = dep.replace("_", "-") if pip_dep not in installed_deps: not_installed_deps.append(dep) if not_installed_deps: not_installed_deps = ["'{}'".format(dep) for dep in not_installed_deps] caos_command_print( command=NAME, message=ERROR_MESSAGE( "The following dependencies are not installed in the virtual environment: {}" .format(", ".join(not_installed_deps)))) return ExitCode(1) caos_command_print( command=NAME, message=SUCCESS_MESSAGE( "All dependencies are installed in the virtual environment")) return ExitCode(0)
def test_working_directory_util_current_directory(self): self.assertTrue(is_dev_environment()) self.assertIn("tmp", get_current_dir())