def test_getsupportedinterpreter(monkeypatch, newconfig, mocksession): config = newconfig([], """ [testenv:python] basepython=%s """ % sys.executable) venv = VirtualEnv(config.envconfigs['python'], session=mocksession) interp = venv.getsupportedinterpreter() # realpath needed for debian symlinks assert py.path.local(interp).realpath() == py.path.local( sys.executable).realpath() monkeypatch.setattr(sys, 'platform', "win32") monkeypatch.setattr(venv.envconfig, 'basepython', 'jython') pytest.raises(tox.exception.UnsupportedInterpreter, venv.getsupportedinterpreter) monkeypatch.undo() monkeypatch.setattr(venv.envconfig, "envname", "py1") monkeypatch.setattr(venv.envconfig, 'basepython', 'notexistingpython') pytest.raises(tox.exception.InterpreterNotFound, venv.getsupportedinterpreter) monkeypatch.undo() # check that we properly report when no version_info is present info = NoInterpreterInfo(name=venv.name) info.executable = "something" monkeypatch.setattr(config.interpreters, "get_info", lambda *args, **kw: info) pytest.raises(tox.exception.InvocationError, venv.getsupportedinterpreter)
def test_create(mocksession, newconfig): config = newconfig( [], """ [testenv:py123] """, ) envconfig = config.envconfigs["py123"] venv = VirtualEnv(envconfig, session=mocksession) assert venv.path == envconfig.envdir assert not venv.path.check() action = mocksession.newaction(venv, "getenv") tox_testenv_create(action=action, venv=venv) pcalls = mocksession._pcalls assert len(pcalls) >= 1 args = pcalls[0].args assert "virtualenv" == str(args[2]) if not tox.INFO.IS_WIN: # realpath is needed for stuff like the debian symlinks our_sys_path = py.path.local(sys.executable).realpath() assert our_sys_path == py.path.local(args[0]).realpath() # assert Envconfig.toxworkdir in args assert venv.getcommandpath("easy_install", cwd=py.path.local()) interp = venv._getliveconfig().base_resolved_python_path assert interp == venv.envconfig.python_info.executable assert venv.path_config.check(exists=False)
def test_create(monkeypatch, mocksession, newconfig): config = newconfig([], """ [testenv:py123] """) envconfig = config.envconfigs['py123'] venv = VirtualEnv(envconfig, session=mocksession) assert venv.path == envconfig.envdir assert not venv.path.check() action = mocksession.newaction(venv, "getenv") tox_testenv_create(action=action, venv=venv) pcalls = mocksession._pcalls assert len(pcalls) >= 1 args = pcalls[0].args module = 'venv' if use_builtin_venv(venv) else 'virtualenv' assert module == str(args[2]) if sys.platform != "win32": executable = sys.executable if use_builtin_venv(venv) and hasattr(sys, 'real_prefix'): # workaround virtualenv prefixing issue w/ venv on python3 _, executable = executable.rsplit('bin/', 1) executable = os.path.join(sys.real_prefix, 'bin/', executable) # realpath is needed for stuff like the debian symlinks assert py.path.local(executable).realpath() == py.path.local(args[0]).realpath() # assert Envconfig.toxworkdir in args assert venv.getcommandpath("easy_install", cwd=py.path.local()) interp = venv._getliveconfig().python assert interp == venv.envconfig.python_info.executable assert venv.path_config.check(exists=False)
def test_env_variables_added_to_needs_reinstall(tmpdir, mocksession, newconfig, monkeypatch): tmpdir.ensure("setup.py") monkeypatch.setenv("TEMP_PASS_VAR", "123") monkeypatch.setenv("TEMP_NOPASS_VAR", "456") config = newconfig([], """ [testenv:python] passenv = temp_pass_var setenv = CUSTOM_VAR = 789 """) venv = VirtualEnv(config.envconfigs['python'], session=mocksession) action = mocksession.newaction(venv, "hello") venv._needs_reinstall(tmpdir, action) pcalls = mocksession._pcalls assert len(pcalls) == 2 env = pcalls[0].env # should have access to setenv vars assert 'CUSTOM_VAR' in env assert env['CUSTOM_VAR'] == '789' # should have access to passenv vars assert 'TEMP_PASS_VAR' in env assert env['TEMP_PASS_VAR'] == "123" # should also have access to full invocation environment, # for backward compatibility, and to match behavior of venv.run_install_command() assert 'TEMP_NOPASS_VAR' in env assert env["TEMP_NOPASS_VAR"] == "456"
def tox_testenv_create(venv: VirtualEnv, action: action.Action) -> Any: clone_pdm_files(str(venv.path), str(venv.envconfig.config.toxinidir)) config_interpreter = venv.getsupportedinterpreter() def patch_getcommandpath(getcommandpath): @functools.wraps(getcommandpath) def patched(self, cmd, *args, **kwargs): if cmd == "python": return config_interpreter return getcommandpath(self, cmd, *args, **kwargs) return patched VirtualEnv.getcommandpath = patch_getcommandpath(VirtualEnv.getcommandpath) if not venv.path.join(".pdm.toml").exists(): venv._pcall( [ venv.envconfig.config.option.pdm, "use", "-f", config_interpreter ], cwd=venv.path, venv=False, action=action, ) return True
def test_create_sitepackages(monkeypatch, mocksession, newconfig): config = newconfig([], """ [testenv:site] sitepackages=True [testenv:nosite] sitepackages=False """) envconfig = config.envconfigs['site'] venv = VirtualEnv(envconfig, session=mocksession) action = mocksession.newaction(venv, "getenv") tox_testenv_create(action=action, venv=venv) pcalls = mocksession._pcalls assert len(pcalls) >= 1 args = pcalls[0].args assert "--system-site-packages" in map(str, args) mocksession._clearmocks() envconfig = config.envconfigs['nosite'] venv = VirtualEnv(envconfig, session=mocksession) action = mocksession.newaction(venv, "getenv") tox_testenv_create(action=action, venv=venv) pcalls = mocksession._pcalls assert len(pcalls) >= 1 args = pcalls[0].args assert "--system-site-packages" not in map(str, args) assert "--no-site-packages" not in map(str, args)
def test_getsupportedinterpreter(monkeypatch, newconfig, mocksession): config = newconfig( [], """ [testenv:python] basepython={} """.format( sys.executable ), ) venv = VirtualEnv(config.envconfigs["python"], session=mocksession) interp = venv.getsupportedinterpreter() # realpath needed for debian symlinks assert py.path.local(interp).realpath() == py.path.local(sys.executable).realpath() monkeypatch.setattr(tox.INFO, "IS_WIN", True) monkeypatch.setattr(venv.envconfig, "basepython", "jython") with pytest.raises(tox.exception.UnsupportedInterpreter): venv.getsupportedinterpreter() monkeypatch.undo() monkeypatch.setattr(venv.envconfig, "envname", "py1") monkeypatch.setattr(venv.envconfig, "basepython", "notexistingpython") with pytest.raises(tox.exception.InterpreterNotFound): venv.getsupportedinterpreter() monkeypatch.undo() # check that we properly report when no version_info is present info = NoInterpreterInfo(name=venv.name) info.executable = "something" monkeypatch.setattr(config.interpreters, "get_info", lambda *args, **kw: info) with pytest.raises(tox.exception.InvocationError): venv.getsupportedinterpreter()
def test_python_recreation(self, tmpdir, newconfig, mocksession): pkg = tmpdir.ensure("package.tar.gz") config = newconfig([], "") envconfig = config.envconfigs['python'] venv = VirtualEnv(envconfig, session=mocksession) cconfig = venv._getliveconfig() action = mocksession.newaction(venv, "update") venv.update(action) assert not venv.path_config.check() mocksession.installpkg(venv, pkg) assert venv.path_config.check() assert mocksession._pcalls args1 = map(str, mocksession._pcalls[0].args) assert 'virtualenv' in " ".join(args1) mocksession.report.expect("*", "*create*") # modify config and check that recreation happens mocksession._clearmocks() action = mocksession.newaction(venv, "update") venv.update(action) mocksession.report.expect("*", "*reusing*") mocksession._clearmocks() action = mocksession.newaction(venv, "update") cconfig.python = py.path.local("balla") cconfig.writeconfig(venv.path_config) venv.update(action) mocksession.report.expect("verbosity0", "*recreate*")
def tox_testenv_install_deps(venv: VirtualEnv, action: Action) -> None: config = venv.envconfig distributions = config.pytorch_distributions if not distributions: return None links = find_links(distributions, computation_backend=config.pytorch_computation_backend) action.setactivity("installdeps-pytorch", ", ".join(links)) venv._install(links, action=action)
def test_basic(self, newconfig, mocksession, tmpdir): config = newconfig([], "") envconfig = config.envconfigs['python'] venv = VirtualEnv(envconfig, session=mocksession) cconfig = venv._getliveconfig() assert cconfig.matches(cconfig) path = tmpdir.join("configdump") cconfig.writeconfig(path) newconfig = CreationConfig.readconfig(path) assert newconfig.matches(cconfig) assert cconfig.matches(newconfig)
def test_commandpath_venv_precedence(tmpdir, monkeypatch, mocksession, newconfig): config = newconfig([], """ [testenv:py123] """) envconfig = config.envconfigs['py123'] venv = VirtualEnv(envconfig, session=mocksession) tmpdir.ensure("easy_install") monkeypatch.setenv("PATH", str(tmpdir), prepend=os.pathsep) envconfig.envbindir.ensure("easy_install") p = venv.getcommandpath("easy_install") assert py.path.local(p).relto(envconfig.envbindir), p
def test_matchingdependencies_latest(self, newconfig, mocksession): config = newconfig([], """ [tox] distshare={toxworkdir}/distshare [testenv] deps={distshare}/xyz-* """) config.distshare.ensure("xyz-1.2.0.zip") xyz2 = config.distshare.ensure("xyz-1.2.1.zip") envconfig = config.envconfigs['python'] venv = VirtualEnv(envconfig, session=mocksession) cconfig = venv._getliveconfig() md5, path = cconfig.deps[0] assert path == xyz2 assert md5 == path.computehash()
def tox_package(session: session.Session, venv: VirtualEnv) -> Any: with venv.new_action("buildpkg") as action: tox_testenv_create(venv, action) if not detect_pdm_files(venv.path): return if not hasattr(session, "package"): session.package, session.dist = get_package(session, venv) # Patch the install command to install to local __pypackages__ folder for i, arg in enumerate(venv.envconfig.install_command): if arg == "python": venv.envconfig.install_command[i] = venv.getsupportedinterpreter() venv.envconfig.install_command.extend( ["-t", get_env_lib_path(venv.envconfig.config.option.pdm, venv.path)]) return session.package
def test_conda_create_args(newconfig, mocksession): config = newconfig( [], """ [testenv:py123] conda_create_args= --override-channels """, ) venv = VirtualEnv(config.envconfigs["py123"]) assert venv.path == config.envconfigs["py123"].envdir with mocksession.newaction(venv.name, "getenv") as action: tox_testenv_create(action=action, venv=venv) pcalls = mocksession._pcalls assert len(pcalls) >= 1 call = pcalls[-1] assert "conda" in call.args[0] assert "create" == call.args[1] assert "--yes" == call.args[2] assert "-p" == call.args[3] assert venv.path == call.args[4] assert call.args[5] == "--override-channels" assert call.args[6].startswith("python=")
def test_matchingdependencies_file(self, newconfig, mocksession): config = newconfig([], """ [tox] distshare={toxworkdir}/distshare [testenv] deps=abc {distshare}/xyz.zip """) xyz = config.distshare.join("xyz.zip") xyz.ensure() envconfig = config.envconfigs['python'] venv = VirtualEnv(envconfig, session=mocksession) cconfig = venv._getliveconfig() assert cconfig.matches(cconfig) xyz.write("hello") newconfig = venv._getliveconfig() assert not cconfig.matches(newconfig)
def _makevenv(self, name): envconfig = self.config.envconfigs.get(name, None) if envconfig is None: self.report.error("unknown environment %r" % name) raise LookupError(name) venv = VirtualEnv(envconfig=envconfig, session=self) self._name2venv[name] = venv return venv
def tox_runtest(venv: VirtualEnv, redirect): """ Create a temporary directory, symlink the test directory into it, and chdir into that directory. """ envconfig: TestenvConfig = venv.envconfig if envconfig.isolate_dirs: # venv.envconfig.setenv["COVERAGE_HOME"] = str(venv.path / "lib") # venv.envconfig.setenv["COVERAGE_HOME"] = envconfig.get_envsitepackagesdir() print( Style.BRIGHT( f"{envconfig.envname} run-test-pre: isolating test environment" )) source_dir = pathlib.Path.cwd() with TemporaryDirectory() as tmpdir: for directory in envconfig.isolate_dirs: if os.path.isabs(directory): os.symlink( directory, pathlib.Path(tmpdir) / os.path.relpath(directory, source_dir)) else: os.symlink(source_dir / directory, pathlib.Path(tmpdir) / directory) venv.envconfig.changedir = py.path.local(tmpdir) venv.test(redirect=redirect) # copy .coverage from tmp dir back into root if (pathlib.Path(tmpdir) / ".coverage").is_file(): shutil.copy2( pathlib.Path(tmpdir) / ".coverage", source_dir / ".coverage") fixup_coverage(old_base=envconfig.get_envsitepackagesdir(), new_base=source_dir, coverage_filename=source_dir / ".coverage") return True # Return non-None to indicate plugin has completed return None
def test_env_variables_added_to_pcall(tmpdir, mocksession, newconfig, monkeypatch): monkeypatch.delenv("PYTHONPATH", raising=False) pkg = tmpdir.ensure("package.tar.gz") monkeypatch.setenv("X123", "123") monkeypatch.setenv("YY", "456") config = newconfig( [], """ [testenv:python] commands=python -V passenv = x123 setenv = ENV_VAR = value PYTHONPATH = value """, ) mocksession._clearmocks() venv = VirtualEnv(config.envconfigs["python"], session=mocksession) mocksession.installpkg(venv, pkg) venv.test() pcalls = mocksession._pcalls assert len(pcalls) == 2 for x in pcalls: env = x.env assert env is not None assert "ENV_VAR" in env assert env["ENV_VAR"] == "value" assert env["VIRTUAL_ENV"] == str(venv.path) assert env["X123"] == "123" assert "PYTHONPATH" in env assert env["PYTHONPATH"] == "value" # all env variables are passed for installation assert pcalls[0].env["YY"] == "456" assert "YY" not in pcalls[1].env assert {"ENV_VAR", "VIRTUAL_ENV", "PYTHONHASHSEED", "X123", "PATH"}.issubset(pcalls[1].env) # setenv does not trigger PYTHONPATH warnings mocksession.report.not_expect("warning", "*Discarding $PYTHONPATH from environment*")
def create_test_env(config, mocksession, envname): venv = VirtualEnv(config.envconfigs[envname]) with mocksession.newaction(venv.name, "getenv") as action: tox_testenv_create(action=action, venv=venv) pcalls = mocksession._pcalls assert len(pcalls) >= 1 pcalls[:] = [] return venv, action, pcalls
def acquire_package(config: config.Config, venv: VirtualEnv) -> py.path.local: target_dir: py.path.local = config.toxworkdir.join( config.isolated_build_env) ensure_empty_dir(target_dir) args = [ venv.envconfig.config.option.pdm, "build", "--no-wheel", "-d", target_dir, ] with venv.new_action("buildpkg") as action: venv._pcall(args, cwd=venv.envconfig.config.toxinidir, venv=False, action=action) path = next(target_dir.visit("*.tar.gz")) action.setactivity("buildpkg", path) return path
def tox_runenvreport(venv: VirtualEnv, action: action.Action): if not detect_pdm_files(venv.path): return command = venv.envconfig.list_dependencies_command for i, arg in enumerate(command): if arg == "python": command[i] = venv.getsupportedinterpreter() venv.envconfig.list_dependencies_command.extend([ "--path", get_env_lib_path(venv.envconfig.config.option.pdm, venv.path) ])
def _makevenv(self, name): envconfig = self.config.envconfigs.get(name, None) if envconfig is None: self.report.error("unknown environment %r" % name) raise LookupError(name) elif envconfig.envdir == self.config.toxinidir: self.report.error( "venv %r in %s would delete project" % (name, envconfig.envdir)) raise tox.exception.ConfigError('envdir must not equal toxinidir') venv = VirtualEnv(envconfig=envconfig, session=self) self._name2venv[name] = venv return venv
def tox_testenv_install_deps(venv: VirtualEnv, action: action.Action) -> Any: if not detect_pdm_files(venv.path): return groups = venv.envconfig.groups or [] if not venv.envconfig.skip_install or groups: action.setactivity("pdminstall", groups) args = [ venv.envconfig.config.option.pdm, "install", "-p", str(venv.path) ] if "default" in groups: groups.remove("default") elif venv.envconfig.skip_install: args.append("--no-default") for group in groups: args.extend(["--group", group]) args.append("--no-self") venv._pcall( args, cwd=venv.envconfig.config.toxinidir, venv=False, action=action, ) deps = venv.get_resolved_dependencies() if deps: depinfo = ", ".join(map(str, deps)) action.setactivity("installdeps", depinfo) venv._install(deps, action=action) lib_path = get_env_lib_path(venv.envconfig.config.option.pdm, venv.path) bin_dir = os.path.join(lib_path, "bin") scripts_dir = os.path.join(os.path.dirname(lib_path), ("Scripts" if os.name == "nt" else "bin")) if os.path.exists(bin_dir): for item in os.listdir(bin_dir): bin_item = os.path.join(bin_dir, item) shutil.move(bin_item, os.path.join(scripts_dir, item)) return True
def test_env_variables_added_to_pcall(tmpdir, mocksession, newconfig, monkeypatch): pkg = tmpdir.ensure("package.tar.gz") monkeypatch.setenv("X123", "123") monkeypatch.setenv("YY", "456") config = newconfig([], """ [testenv:python] commands=python -V passenv = x123 setenv = ENV_VAR = value PYTHONPATH = value """) mocksession._clearmocks() venv = VirtualEnv(config.envconfigs['python'], session=mocksession) mocksession.installpkg(venv, pkg) venv.test() l = mocksession._pcalls assert len(l) == 2 for x in l: env = x.env assert env is not None assert 'ENV_VAR' in env assert env['ENV_VAR'] == 'value' assert env['VIRTUAL_ENV'] == str(venv.path) assert env['X123'] == "123" assert 'PYTHONPATH' in env assert env['PYTHONPATH'] == 'value' # all env variables are passed for installation assert l[0].env["YY"] == "456" assert "YY" not in l[1].env assert set(["ENV_VAR", "VIRTUAL_ENV", "PYTHONHASHSEED", "X123", "PATH"])\ .issubset(l[1].env) # setenv does not trigger PYTHONPATH warnings mocksession.report.not_expect("warning", "*Discarding $PYTHONPATH from environment*")
def test_create(monkeypatch, mocksession, newconfig): config = newconfig([], """ [testenv:py123] """) envconfig = config.envconfigs['py123'] venv = VirtualEnv(envconfig, session=mocksession) assert venv.path == envconfig.envdir assert not venv.path.check() action = mocksession.newaction(venv, "getenv") tox_testenv_create(action=action, venv=venv) pcalls = mocksession._pcalls assert len(pcalls) >= 1 args = pcalls[0].args assert "virtualenv" == str(args[2]) if sys.platform != "win32": # realpath is needed for stuff like the debian symlinks assert py.path.local(sys.executable).realpath() == py.path.local(args[0]).realpath() # assert Envconfig.toxworkdir in args assert venv.getcommandpath("easy_install", cwd=py.path.local()) interp = venv._getliveconfig().python assert interp == venv.envconfig.python_info.executable assert venv.path_config.check(exists=False)
def getvenv(self, name): if name in self.existing_venvs: return self.existing_venvs[name] env_config = self.config.envconfigs.get(name, None) if env_config is None: reporter.error("unknown environment {!r}".format(name)) raise LookupError(name) elif env_config.envdir == self.config.toxinidir: reporter.error("venv {!r} in {} would delete project".format(name, env_config.envdir)) raise tox.exception.ConfigError("envdir must not equal toxinidir") env_log = self.resultlog.get_envlog(name) venv = VirtualEnv(envconfig=env_config, popen=self.popen, env_log=env_log) self.existing_venvs[name] = venv return venv
def test_develop_recreation(self, newconfig, mocksession): config = newconfig([], "") envconfig = config.envconfigs['python'] venv = VirtualEnv(envconfig, session=mocksession) action = mocksession.newaction(venv, "update") venv.update(action) cconfig = venv._getliveconfig() cconfig.usedevelop = True cconfig.writeconfig(venv.path_config) mocksession._clearmocks() action = mocksession.newaction(venv, "update") venv.update(action) mocksession.report.expect("verbosity0", "*recreate*")
def test_dep_recreation(self, newconfig, mocksession): config = newconfig([], "") envconfig = config.envconfigs['python'] venv = VirtualEnv(envconfig, session=mocksession) action = mocksession.newaction(venv, "update") venv.update(action) cconfig = venv._getliveconfig() cconfig.deps[:] = [("1" * 32, "xyz.zip")] cconfig.writeconfig(venv.path_config) mocksession._clearmocks() action = mocksession.newaction(venv, "update") venv.update(action) mocksession.report.expect("*", "*recreate*")
def tox_runtest_pre(venv: VirtualEnv) -> None: envconfig = venv.envconfig container_names = envconfig.docker log = make_logger(venv) env_container_configs = [] seen = set() for container_name in container_names: if container_name not in CONTAINER_CONFIGS: raise ValueError(f"Missing [docker:{container_name}] in tox.ini") if container_name in seen: raise ValueError(f"Container {container_name!r} specified more than once") seen.add(container_name) env_container_configs.append(CONTAINER_CONFIGS[container_name]) for container_config in env_container_configs: docker_pull(container_config, log) ENV_CONTAINERS.setdefault(venv, {}) running_containers = ENV_CONTAINERS[venv] for container_config in env_container_configs: container = docker_run(container_config, running_containers, log) running_containers[container_config.runas_name] = container for running_name, container in running_containers.items(): container_name = _config_name(running_name) container_config = CONTAINER_CONFIGS[container_name] try: docker_health_check(container_config, container, log) except HealthCheckFailed: msg = f"{container_config.image!r} (from {container_name!r}) failed health check" venv.status = msg tox_runtest_post(venv) raise for running_name, container in running_containers.items(): container_name = _config_name(running_name) container_config = CONTAINER_CONFIGS[container_name] for key, val in get_env_vars(container_config, container).items(): venv.envconfig.setenv[key] = val
def test_conda_create(newconfig, mocksession): config = newconfig( [], """ [testenv:py123] """, ) venv = VirtualEnv(config.envconfigs["py123"], session=mocksession) assert venv.path == config.envconfigs['py123'].envdir action = mocksession.newaction(venv, "getenv") tox_testenv_create(action=action, venv=venv) pcalls = mocksession._pcalls assert len(pcalls) == 1 assert 'conda' in pcalls[0].args[0] assert 'create' == pcalls[0].args[1] assert '--yes' == pcalls[0].args[2] assert '-p' == pcalls[0].args[3] assert venv.path == pcalls[0].args[4] assert pcalls[0].args[5].startswith('python=')