def test_r_install(setup_env, mocker): command = 'install.packages("h2o")' escaped_command = command.replace('"', r"\"") env = setup_env["env"] env_io = setup_env["env_io"] expected = copy.deepcopy(setup_env["expected"]) run_mock = mocker.patch("conda_env_tracker.gateways.r.run_command") run_mock.configure_mock(**{ "return_value.failed": False, "return_value.stderr": "" }) mocker.patch( "conda_env_tracker.env.get_r_dependencies", mocker.Mock(return_value={"h2o": Package("h2o", "h2o", "3.24.0.3")}), ) h2o = Package("h2o", command) packages = Packages([h2o]) RHandler(env=env).install(packages=packages) expected["logs"].append(f'R --quiet --vanilla -e "{escaped_command}"') expected["packages"]["r"] = {"h2o": h2o} actual = env_io.get_history() assert actual.logs == expected["logs"] assert actual.packages == expected["packages"] assert actual.actions[-1] == expected["logs"][-1] actual_install_r = (env_io.env_dir / "install.R").read_text() assert actual_install_r == command
def get_dependencies(name: str) -> dict: """Get the information about pip and conda packages in the environment using `conda list`. Package information includes: name and version """ completed_process = subprocess.run( f"conda list --name {name}", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, encoding="UTF-8", ) if completed_process.returncode != 0: error_message = completed_process.stderr.strip() raise CondaEnvTrackerCondaError(error_message) lines = completed_process.stdout.strip().split("\n") dependencies = {"conda": {}} for line in lines: if not line.startswith("#"): dep = line.strip().split() name = dep[0] spec = name version = dep[1] if dep[-1] in ["pip", "pypi"]: dependencies["pip"] = dependencies.get("pip", {}) dependencies["pip"][name] = Package(name, spec, version) else: build = dep[2] dependencies["conda"][name] = Package(name, spec, version, build) return dependencies
def test_pip_custom_install(setup_env, mocker): pip_package_url = "https://s3.amazonaws.com/h2o-release/h2o/master/4765/Python/h2o-3.26.0.4765-py2.py3-none-any.whl" pip_dependencies = {"h2o": Package("h2o", pip_package_url)} package = Package("h2o", pip_package_url) env = setup_env["env"] env_io = setup_env["env_io"] expected = copy.deepcopy(setup_env["expected"]) get_package_mock = setup_env["get_package_mock"] initial_conda_packages = setup_env["initial_conda_packages"] get_package_mock.configure_mock(**{ "return_value": { "conda": initial_conda_packages, "pip": pip_dependencies } }) mocker.patch("conda_env_tracker.pip.pip_custom_install") PipHandler(env=env).custom_install(package=package) install_command = f"pip install {pip_package_url}" expected["logs"].append(install_command) expected["packages"]["pip"] = pip_dependencies action_command = install_command actual = env_io.get_history() assert actual.logs == expected["logs"] assert actual.packages == expected["packages"] assert actual.actions[-1] == action_command
def test_install_with_default_version_success(setup_env, packages, mocker): env = setup_env["env"] env_io = setup_env["env_io"] expected = setup_env["expected"] get_package_mock = setup_env["get_package_mock"] get_package_mock.configure_mock( return_value={ "conda": { "pyspark": Package("pyspark", "pyspark", "0.21", "py_36"), "pandas": Package("pandas", "pandas", "0.23", "py_36"), } }) mocker.patch("conda_env_tracker.conda.conda_install") CondaHandler(env=env).install(packages=packages) history = env_io.get_history() expected_log = expected["logs"].copy() expected_action = expected["actions"].copy() expected_packages = copy.deepcopy(expected["packages"]) package = packages[0] expected_packages["conda"]["pyspark"] = package expected_log.append(f"conda install --name {env.name} {package.spec}") assert history.packages == expected_packages channel_string = "--override-channels --strict-channel-priority " + " ".join( [f"--channel " + channel for channel in expected["channels"]]) expected_action.append( f"conda install --name {env.name} pyspark=0.21=py_36 {channel_string}") assert history.actions == expected_action assert history.logs == expected_log
def test_pip_custom_install_github(setup_env, mocker): pip_package_url = "git+ssh://[email protected]/pandas-dev/pandas" pip_dependencies = {"pandas": Package("pandas", pip_package_url)} package = Package("pandas", pip_package_url) env = setup_env["env"] env_io = setup_env["env_io"] expected = copy.deepcopy(setup_env["expected"]) get_package_mock = setup_env["get_package_mock"] initial_conda_packages = setup_env["initial_conda_packages"] get_package_mock.configure_mock(**{ "return_value": { "conda": initial_conda_packages, "pip": pip_dependencies } }) mocker.patch("conda_env_tracker.pip.pip_custom_install") PipHandler(env=env).custom_install(package=package) install_command = f"pip install {pip_package_url}" expected["logs"].append(install_command) expected["packages"]["pip"] = pip_dependencies action_command = install_command actual = env_io.get_history() assert actual.logs == expected["logs"] assert actual.packages == expected["packages"] assert actual.actions[-1] == action_command
def test_export_success(mocker): """Test package export""" mocker.patch( "conda_env_tracker.history.history.uuid4").return_value = "unique_uuid" expected = { "name": "environment-name", "id": "unique_uuid", "history-file-version": "1.0", "channels": ["conda-forge", "main"], "packages": { "conda": { "pytest": "*" } }, "revisions": [{ "log": "conda create --name test pytest", "action": "conda create --name test pytest=4.0=py36_0 " "--channel conda-forge " "--channel main", "debug": { "platform": "osx", "conda_version": "4.5.10" }, "packages": { "conda": { "pytest": "*" } }, "diff": { "conda": { "upsert": ["pytest=4.0"] } }, }], } actual = History.create( name="environment-name", channels=Channels(["conda-forge", "main"]), packages=PackageRevision(conda=dict( pytest=Package.from_spec("pytest"))), logs=Logs(["conda create --name test pytest"]), actions=Actions([ "conda create --name test pytest=4.0=py36_0 " "--channel conda-forge " "--channel main" ]), diff=Diff(conda=dict(upsert=dict( pytest=Package("pytest", version="4.0")))), debug=[{ "platform": "osx", "conda_version": "4.5.10" }], ).export() assert expected == actual
def test_ignore_empty_pip_packages(mocker): """When a user installs a pip package and then removes it, the pip packages is an empty dictionry which does not need to show up in the history file. """ mocker.patch( "conda_env_tracker.history.history.uuid4").return_value = "unique_uuid" expected = { "name": "environment-name", "id": "unique_uuid", "history-file-version": "1.0", "channels": ["main"], "packages": { "conda": { "pytest": "*" } }, "revisions": [{ "log": "conda create --name test pytest", "action": "conda create --name test pytest=4.0=py36_0 " "--channel main", "debug": { "platform": "osx", "conda_version": "4.5.10" }, "packages": { "conda": { "pytest": "*" } }, "diff": { "conda": { "upsert": ["pytest=4.0"] } }, }], } actual = History.create( name="environment-name", channels=Channels(["main"]), packages=PackageRevision( conda=dict(pytest=Package.from_spec("pytest")), pip={}), logs=Logs(["conda create --name test pytest"]), actions=Actions( ["conda create --name test pytest=4.0=py36_0 " "--channel main"]), diff=Diff( dict(conda=dict(upsert=dict( pytest=Package("pytest", version="4.0"))))), debug=[{ "platform": "osx", "conda_version": "4.5.10" }], ).export() assert expected == actual
def setup(mocker, request): """Set up for diff function""" local_packages = request.param["local_packages"] local_logs = request.param["local_logs"] local_actions = request.param["local_actions"] env_name = request.param["env_name"] remote_packages = request.param["remote_packages"] remote_logs = request.param["remote_logs"] remote_actions = request.param["remote_actions"] dependencies = { "conda": { "pandas": Package("pandas", "pandas", version="0.23.0"), "pytest": Package("pytest", "pytest", version="4.0.0"), } } mocker.patch( "conda_env_tracker.env.get_dependencies", mocker.Mock(return_value=dependencies) ) history = History.create( name=env_name, packages=PackageRevision.create(local_packages, dependencies=dependencies), channels=Channels(["conda-forge"]), logs=Logs([log for log in local_logs]), actions=local_actions, diff=Diff(), debug=Debug(), ) env = Environment(name=env_name, history=history) mocker.patch("conda_env_tracker.main.Environment.read", return_value=env) mocker.patch( "conda_env_tracker.gateways.io.EnvIO.get_remote_dir", return_value="~/path/to/remote", ) mocker.patch("pathlib.Path.is_dir", return_value=True) history = History.create( name=env_name, channels=Channels(["conda-forge"]), packages=PackageRevision.create(remote_packages, dependencies=dependencies), logs=Logs([log for log in remote_logs]), actions=remote_actions, diff=Diff(), debug=Debug(), ) mocker.patch( "conda_env_tracker.gateways.io.EnvIO.get_history", return_value=history ) mocker.patch("pathlib.Path.write_text") yield env, request.param["push_should_fail"] if (USER_ENVS_DIR / env_name).exists(): shutil.rmtree(USER_ENVS_DIR / env_name)
def test_export_install_r_multiple(): custom_command_h2o = 'install.packages("h2o")' custom_command_trelliscopejs = ( 'library("devtools"); install_github("hafen/treslliscopejs")' ) packages = { "h2o": Package("h2o", custom_command_h2o), "trelliscopejs": Package("trelliscopejs", custom_command_trelliscopejs), } actual = r.export_install_r(packages) expected = "\n".join([custom_command_h2o, custom_command_trelliscopejs]) assert actual == expected
def test_parse_with_package(): """Test to parse yaml file without any package""" history = History.parse({ "channels": ["conda-forge", "main"], "packages": { "conda": { "pytest": "*" } }, "revisions": [{ "log": "conda create --name test pytest", "action": "conda create --name test pytest=4.0=py36_0 " "--channel conda-forge " "--channel main", "debug": { "platform": "linux", "conda_version": "4.5.11" }, "packages": { "conda": { "pytest": "*" } }, "diff": { "conda": { "upsert": ["pytest=4.0"] } }, }], }) assert ["conda-forge", "main"] == history.channels assert { "conda": { "pytest": Package.from_spec("pytest") } } == history.packages assert ["conda create --name test pytest"] == history.logs assert [ "conda create --name test pytest=4.0=py36_0 " "--channel conda-forge " "--channel main" ] == history.actions assert [{"platform": "linux", "conda_version": "4.5.11"}] == history.debug assert [{ "conda": { "upsert": { "pytest": Package("pytest", "pytest", "4.0") } } }] == history.revisions.diffs
def setup_tests(mocker): """Set up for pull function""" remote_packages = (Package.from_spec("pandas"), Package.from_spec("pytest")) remote_logs = [ "conda create --name pull_testing_environment pandas", "conda install --name pull_testing_environment pytest", ] remote_actions = [ "conda create --name pull_testing_environment pandas=0.23=py36", "conda install --name pull_testing_environment pytest=0.1=py36_3", ] remote_history = History( name=ENV_NAME, channels=CHANNELS, packages=HistoryPackages.create(remote_packages), logs=Logs([log for log in remote_logs]), actions=Actions(remote_actions), debug=Debug(), ) mocker.patch("conda_env_tracker.conda.conda_install") mocker.patch("conda_env_tracker.conda.conda_update_all") mocker.patch("conda_env_tracker.conda.conda_remove") mocker.patch("conda_env_tracker.pip.pip_install") mocker.patch("conda_env_tracker.pip.pip_remove") mocker.patch("conda_env_tracker.history.get_pip_version") get_dependencies = mocker.patch("conda_env_tracker.env.get_dependencies") overwrite_mock = mocker.patch( "conda_env_tracker.pull.EnvIO.overwrite_local") mocker.patch("conda_env_tracker.pull.EnvIO.get_remote_dir", return_value="~/path/to/remote") mocker.patch("conda_env_tracker.pull.EnvIO.get_history", return_value=remote_history) mocker.patch("conda_env_tracker.pull.prompt_yes_no", return_value=True) mocker.patch("conda_env_tracker.pull.update_conda_environment") mocker.patch("conda_env_tracker.pull.update_r_environment") mocker.patch("conda_env_tracker.pull.Environment.export") mocker.patch("conda_env_tracker.pull.Environment.validate") mocker.patch( "conda_env_tracker.pull.Environment.validate_installed_packages") yield { "get_dependencies": get_dependencies, "overwrite_mock": overwrite_mock, "remote_history": remote_history, } env_dir = USER_ENVS_DIR / ENV_NAME if env_dir.exists(): shutil.rmtree(env_dir)
def test_package_install_with_custom_channel(setup_env, channels, mocker): """The user can specify a list of channels that will override the channel precedence order or they can specify a custom channel that is not previously in the environment's channel list""" env = setup_env["env"] env_io = setup_env["env_io"] expected = setup_env["expected"] get_package_mock = setup_env["get_package_mock"] get_package_mock.configure_mock( return_value={ "conda": { "pyspark": Package("pyspark", "pyspark", "0.21", "py_36"), "pandas": Package("pandas", "pandas", "0.23", "py_36"), } } ) mocker.patch("conda_env_tracker.conda.conda_install") CondaHandler(env=env).install( packages=Packages.from_specs("pyspark"), channels=channels ) history = env_io.get_history() expected_log = expected["logs"].copy() expected_action = expected["actions"].copy() expected_packages = copy.deepcopy(expected["packages"]) expected_packages["conda"]["pyspark"] = Package.from_spec("pyspark") channel_log_string = " ".join(["--channel " + channel for channel in channels]) expected_log.append(f"conda install --name {env.name} pyspark {channel_log_string}") computed_channels = channels.copy() for channel in expected["channels"]: if not channel in computed_channels: computed_channels.append(channel) install_channel_string = ( "--override-channels --strict-channel-priority " + " ".join([f"--channel " + channel for channel in computed_channels]) ) assert history.packages == expected_packages expected_action.append( f"conda install --name {env.name} pyspark=0.21=py_36 {install_channel_string}" ) assert history.actions == expected_action assert history.logs == expected_log
def test_write_history_file(env_io): """Test to create history yaml file and test get history""" env_io.write_history_file( History.create( name="test-env", channels=Channels(["main"]), packages=PackageRevision( {"conda": { "python": Package.from_spec("python") }}), logs=Logs(["conda create -n test-env python"]), actions=Actions([ "conda create -n test-env python=3.7.3=buildstring --override-channels --channel main" ]), diff=Diff({ "conda": { "upsert": { "python": Package("python", version="3.7.3") } } }), debug=["blah"], )) assert ["main"] == env_io.get_history().channels assert { "conda": { "python": Package.from_spec("python") } } == env_io.get_history().packages assert (Revisions( **{ "logs": ["conda create -n test-env python"], "actions": [ "conda create -n test-env python=3.7.3=buildstring --override-channels --channel main" ], "packages": [{ "conda": { "python": Package.from_spec("python") } }], "diffs": [{ "conda": { "upsert": { "python": Package("python", "python", version="3.7.3") } } }], "debug": ["blah"], }) == env_io.get_history().revisions)
def test_replace_existing_env_success(mocker): mocker.patch("conda_env_tracker.env.delete_conda_environment") mocker.patch("conda_env_tracker.env.prompt_yes_no").return_value = True env_name = "conda_env_tracker-test-create-history" create_cmd = f"conda create --name {env_name} pandas" channels = ["conda-forge", "main"] packages = Packages.from_specs("pandas") action = "pandas=0.23=py_36" mocker.patch( "conda_env_tracker.env.get_all_existing_environment").return_value = [ env_name ] mocker.patch("conda_env_tracker.env.conda_create", mocker.Mock(return_value=create_cmd)) mocker.patch( "conda_env_tracker.env.get_dependencies", mocker.Mock(return_value={ "conda": { "pandas": Package("pandas", "*", "0.23=py_36") }, "pip": {}, }), ) mocker.patch( "conda_env_tracker.history.debug.get_pip_version", mocker.Mock(return_value="18.1"), ) mocker.patch("conda_env_tracker.env.get_conda_channels", mocker.Mock(return_value=channels)) Environment.create(name=env_name, packages=packages) writer = EnvIO(env_directory=USER_ENVS_DIR / env_name) history = writer.get_history() channel_string = "--override-channels --strict-channel-priority " + " ".join( "--channel " + channel for channel in channels) assert history.actions == [ f"conda create --name {env_name} {action} {channel_string}" ] assert history.packages == { "conda": { "pandas": Package.from_spec("pandas") } } assert history.channels == channels assert history.logs == [create_cmd] env_dir = Path(USER_ENVS_DIR) / env_name shutil.rmtree(env_dir)
def test_infer_environment_with_pip_package_success(mocker): env_name = "infer-test" dependencies = { "conda": { "pandas": Package("pandas", "pandas", "0.23", "py_36") }, "pip": { "pytest": Package("pytest", "pytest", "0.11") }, } mocker.patch( "conda_env_tracker.history.debug.get_pip_version", mocker.Mock(return_value="18.1"), ) mocker.patch("conda_env_tracker.env.get_all_existing_environment", return_value=[env_name]) mocker.patch("conda_env_tracker.env.get_dependencies", mocker.Mock(return_value=dependencies)) mocker.patch("conda_env_tracker.env.get_r_dependencies") env = Environment.infer( name=env_name, packages=Packages.from_specs(["pandas", "pytest"]), channels=["conda-forge", "main"], ) assert env.history.packages == { "conda": { "pandas": Package("pandas", "pandas", "0.23", "py_36") }, "pip": { "pytest": Package("pytest", "pytest", "0.11") }, } assert env.history.channels == ["conda-forge", "main"] assert env.history.logs == [ f"conda create --name {env_name} pandas --override-channels --strict-channel-priority " "--channel conda-forge " "--channel main", "pip install pytest --index-url https://pypi.org/simple", ] assert env.history.actions == [ f"conda create --name {env_name} pandas=0.23=py_36 " "--override-channels --strict-channel-priority " "--channel conda-forge " "--channel main", "pip install pytest==0.11 --index-url" " https://pypi.org/simple", ]
def test_remove_r_package(setup_env, mocker): env = setup_env["env"] env_io = setup_env["env_io"] expected = copy.deepcopy(setup_env["expected"]) r_command = 'install.packages("h2o")' run_mock = mocker.patch("conda_env_tracker.gateways.r.run_command") run_mock.configure_mock(**{ "return_value.failed": False, "return_value.stderr": "" }) mocker.patch( "conda_env_tracker.env.get_r_dependencies", mocker.Mock(return_value={"h2o": Package("h2o", "h2o", "3.24.0.3")}), ) handler = RHandler(env=env) h2o = Package("h2o", r_command) packages = Packages([h2o]) handler.install(packages=packages) install_log = f"R --quiet --vanilla -e '{r_command}'" expected["logs"].append(install_log) expected["packages"]["r"] = {"h2o": h2o} actual = env_io.get_history() assert actual.logs == expected["logs"] assert actual.packages == expected["packages"] assert actual.actions[-1] == install_log expected_install_r = r_command actual_install_r = (env_io.env_dir / "install.R").read_text() assert actual_install_r == expected_install_r mocker.patch("conda_env_tracker.r.r_remove") handler.remove(packages=packages) actual = env_io.get_history() command = 'remove.packages(c("h2o"))' expected["packages"].pop("r") expected["logs"].append(f"R --quiet --vanilla -e '{command}'") assert actual.logs == expected["logs"] assert actual.packages == expected["packages"] assert actual.actions[-1] == expected["logs"][-1] assert not (env_io.env_dir / "install.R").exists()
def test_pull_no_new_action_in_local(setup_tests): overwrite_mock = setup_tests["overwrite_mock"] remote_history = setup_tests["remote_history"] local_packages = (Package.from_spec("pandas"), ) local_logs = ["conda create --name pull_testing_environment pandas"] local_actions = [ "conda create --name pull_testing_environment pandas=0.23=py36" ] local_history = History( name=ENV_NAME, packages=HistoryPackages.create(local_packages), channels=Channels(), logs=Logs([log for log in local_logs]), actions=Actions(local_actions), debug=Debug(), ) env = Environment(name=ENV_NAME, history=local_history) pull(env=env) assert env.history.packages == remote_history.packages assert env.history.logs == remote_history.logs assert env.history.actions == remote_history.actions overwrite_mock.called_once()
def test_jupyter_kernel_install_query_user_says_no(mocker): run_mock = mocker.patch( "conda_env_tracker.gateways.jupyter.subprocess.run") run_mock.configure_mock( **{ "return_value.returncode": 0, "return_value.stdout": ("Available kernels:\n" " arl /home/username/.local/share/jupyter/kernels/arl\n" " test-env /home/username/.local/share/jupyter/kernels/test-env\n" " rasterstats /home/username/.local/share/jupyter/kernels/rasterstats" ), }) mocker.patch( "conda_env_tracker.gateways.jupyter.prompt_yes_no", new=mocker.Mock(return_value=False), ) debug_mock = mocker.patch( "conda_env_tracker.gateways.jupyter.logger.debug") jupyter_kernel_install_query(name="myenv", packages=[Package.from_spec("jupyter")]) debug_mock.assert_not_called() assert len(run_mock.call_args_list) == 1
def test_parse_with_package_with_version(): """Test to parse yaml file without any package""" history = History.parse({ "name": "environment-name", "channels": ["conda-forge", "main"], "packages": { "conda": { "pytest": "3.7=py36_0" } }, "logs": ["conda create --name test pytest=3.7=py36_0"], "actions": ["conda create --name test pytest=3.7=py36_0"], "debug": [{ "platform": "osx", "conda_version": "4.5.12" }], }) assert history.name == "environment-name" assert history.channels == ["conda-forge", "main"] assert history.packages == { "conda": { "pytest": Package.from_spec("pytest=3.7=py36_0") } } assert history.logs == ["conda create --name test pytest=3.7=py36_0"] assert history.actions == ["conda create --name test pytest=3.7=py36_0"] assert history.debug == [{"platform": "osx", "conda_version": "4.5.12"}]
def test_pip_remove(setup_pip_env, mocker): env = setup_pip_env["env"] env_io = setup_pip_env["env_io"] mocker.patch("conda_env_tracker.pip.pip_remove") PipHandler(env=env).remove(packages=Packages.from_specs("pytest"), yes=True) actual = env_io.get_history() assert actual.logs[-1] == "pip uninstall pytest" assert actual.actions[-1] == "pip uninstall pytest" assert actual.packages["pip"] == { "pandas": Package(name="pandas", spec="git+ssh://[email protected]/pandas-dev/pandas") } PipHandler(env=env).remove(packages=Packages.from_specs("pandas"), yes=True) actual = env_io.get_history() assert actual.logs[-1] == "pip uninstall pandas" assert actual.actions[-1] == "pip uninstall pandas" assert "pip" not in actual.packages
def test_infer_environment_package_does_not_exist(mocker): env_name = "infer-test" dependencies = { "conda": { "pandas": Package("pandas", "pandas", "0.23", "py_36") } } mocker.patch( "conda_env_tracker.history.debug.get_pip_version", mocker.Mock(return_value="18.1"), ) mocker.patch("conda_env_tracker.env.get_all_existing_environment", return_value=[env_name]) mocker.patch("conda_env_tracker.env.get_dependencies", mocker.Mock(return_value=dependencies)) mocker.patch("conda_env_tracker.env.get_r_dependencies") with pytest.raises(Exception) as err: Environment.infer( name=env_name, packages=Packages.from_specs("pytest"), channels=["conda-forge", "main"], ) assert str( err.value) == "Environment infer-test does not have pytest installed"
def test_extract_packages_from_logs(spec): """Test parsing the packges from action item""" log = Logs(f"conda install --name test {spec}") packages = log.extract_packages(index=0, packages=Packages.from_specs(spec)) assert packages[0] == Package.from_spec(spec)
def history_diff(env_name: str, env, env_reader) -> ListLike: """return the difference between history and local environment""" version_diff_pkges: ListLike = [] new_pkges: ListLike = [] missing_pkges: ListLike = [] history_conda_pkges = env_reader.get_environment()["dependencies"] history_conda_pkges_dict = {} for spec in history_conda_pkges: name, package = Package.from_spec(spec) history_conda_pkges_dict[name] = package local_conda_pkges = get_dependencies(name=env_name)["conda"] for name, package in local_conda_pkges.items(): if name in history_conda_pkges_dict: if package.version != history_conda_pkges_dict[name].version: version_diff_pkges.append("-" + name + "=" + history_conda_pkges_dict[name]) version_diff_pkges.append("+" + name + "=" + package.version) else: new_pkges.append("+" + name + "=" + package.version) for package in env.history.packages["conda"]: if package not in local_conda_pkges.keys(): missing_pkges.append("-" + package) return version_diff_pkges, new_pkges, missing_pkges
def test_two_same_package_r_install(setup_env, mocker): """Test that the second command replaces the first command (and updates the version of the package)""" command_h2o_1 = 'install.packages("h2o")' escaped_command_1 = command_h2o_1.replace('"', r"\"") command_h2o_2 = 'install.packages("h2o", type="source", repos=(c("http://h2o-release.s3.amazonaws.com/h2o/latest_stable_R")))' escaped_command_2 = command_h2o_2.replace('"', r"\"") env = setup_env["env"] env_io = setup_env["env_io"] expected = copy.deepcopy(setup_env["expected"]) run_mock = mocker.patch("conda_env_tracker.gateways.r.run_command") run_mock.configure_mock(**{ "return_value.failed": False, "return_value.stderr": "" }) mocker.patch( "conda_env_tracker.env.get_r_dependencies", side_effect=[ { "h2o": Package("h2o", "h2o", "3.4.0.1") }, { "h2o": Package("h2o", "h2o", "3.24.0.5") }, ], ) h2o_1 = Package("h2o", command_h2o_1) h2o_2 = Package("h2o", command_h2o_2) packages_1 = Packages([h2o_1]) packages_2 = Packages([h2o_2]) RHandler(env=env).install(packages=packages_1) RHandler(env=env).install(packages=packages_2) expected["logs"].append(f'R --quiet --vanilla -e "{escaped_command_1}"') expected["logs"].append(f'R --quiet --vanilla -e "{escaped_command_2}"') expected["packages"]["r"] = {"h2o": h2o_2} actual = env_io.get_history() assert actual.logs == expected["logs"] assert actual.packages == expected["packages"] assert actual.actions[-1] == expected["logs"][-1] actual_install_r = (env_io.env_dir / "install.R").read_text() assert actual_install_r == command_h2o_2
def get_pip_version(name: str) -> Optional[str]: """Check for the version of pip (if installed).""" if is_current_conda_env(name): import pip return pip.__version__ dependencies = get_dependencies(name=name) return dependencies["conda"].get("pip", Package(name="pip")).version
def test_strict_channel_priority_update_all(setup_env, use_package, mocker): env = setup_env["env"] env_io = setup_env["env_io"] expected = setup_env["expected"] get_package_mock = setup_env["get_package_mock"] get_package_mock.configure_mock( return_value={ "conda": { "pyspark": Package("pyspark", "pyspark", "0.21", "py_36"), "pandas": Package("pandas", "pandas", "0.23", "py_36"), } } ) mocker.patch("conda_env_tracker.conda.conda_update_all") expected_packages = copy.deepcopy(expected["packages"]) update_all_channel_string = "--override-channels " + " ".join( f"--channel {channel}" for channel in expected["channels"] ) if use_package: CondaHandler(env=env).update_all( packages=Packages.from_specs("pyspark"), strict_channel_priority=False ) expected_packages["conda"]["pyspark"] = Package.from_spec("pyspark") log = f"conda update --all --name {env.name} pyspark" action = f"conda update --all --name {env.name} pyspark=0.21=py_36 {update_all_channel_string}" else: CondaHandler(env=env).update_all(strict_channel_priority=False) log = f"conda update --all --name {env.name}" action = f"conda update --all --name {env.name} {update_all_channel_string}" history = env_io.get_history() expected_logs = expected["logs"].copy() expected_logs.append(log) expected_actions = expected["actions"].copy() expected_actions.append(action) assert history.packages == expected_packages assert history.actions == expected_actions assert history.logs == expected_logs
def test_export_install_r_single_package(): packages = Packages( Package( "jsonlite", 'library("devtools"); install_version("jsonlite",version="1.6")')) actual = r.export_install_r(packages) expected = 'library("devtools"); install_version("jsonlite",version="1.6")' assert actual == expected
def test_export_install_r_multiple_installs(): packages = Packages([ Package( "jsonlite", 'library("devtools"); install_version("jsonlite",version="1.6")', ), Package( "praise", 'library("devtools"); install_version("praise",version="1.0.0")', ), ]) actual = r.export_install_r(packages) expected = "\n".join([ 'library("devtools"); install_version("jsonlite",version="1.6")', 'library("devtools"); install_version("praise",version="1.0.0")', ]) assert actual == expected
def test_jupyter_kernel_install_query_jupyter_not_in_packages(mocker): run_mock = mocker.patch( "conda_env_tracker.gateways.jupyter.subprocess.run") jupyter_kernel_install_query(name="myenv", packages=[Package.from_spec("numpy")]) run_mock.assert_not_called()
def test_pull_different_actions_in_both_r(setup_r_tests): remote_history = setup_r_tests["remote_history"] get_r_dependencies = setup_r_tests["get_r_dependencies"] get_r_dependencies.configure_mock( **{ "return_value": { "praise": Package("praise", "praise", "1.0.0"), "jsonlite": Package("jsonlite", "jsonlite", "1.6"), } }) local_history = copy.deepcopy(remote_history) local_history.packages.update_packages(packages=Packages( Package("praise", 'install.packages("praise")')), source="r") local_history.logs.append(f"{R_COMMAND} -e 'install.packages(\"praise\")'") local_history.actions.append( f"{R_COMMAND} -e 'install.packages(\"praise\")'") env = Environment(name=local_history.name, history=local_history) remote_history.packages.update_packages( packages=Packages(Package("jsonlite", 'install.packages("jsonlite")')), source="r", ) remote_history.logs.append( f"{R_COMMAND} -e 'install.packages(\"jsonlite\")'") remote_history.actions.append( f"{R_COMMAND} -e 'install.packages(\"jsonlite\")'") expected_history = copy.deepcopy(remote_history) expected_history.packages.update_packages(packages=Packages( Package("praise", 'install.packages("praise")')), source="r") expected_history.logs.append( f"{R_COMMAND} -e 'install.packages(\"praise\")'") expected_history.actions.append( f"{R_COMMAND} -e 'install.packages(\"praise\")'") final_env = pull(env=env) assert final_env.history.packages == expected_history.packages assert final_env.history.logs == expected_history.logs assert final_env.history.actions == expected_history.actions