Exemple #1
0
    def infer(cls, name: str, packages: Packages, channels: ListLike = None):
        """create conda_env_tracker environment by inferring to existing conda environment"""
        if name == "base":
            raise CondaEnvTrackerCondaError(
                "Environment can not be created using default name base"
            )

        if name not in get_all_existing_environment():
            raise CondaEnvTrackerCondaError(
                f"Environment {name} can not be inferred, does not exist"
            )

        dependencies = get_dependencies(name=name)
        if "r-base" in dependencies["conda"]:
            dependencies["r"] = get_r_dependencies(name=name)

        user_packages = {"conda": Packages(), "pip": Packages()}
        for package in packages:
            if package.name in dependencies.get("conda", Packages()):
                user_packages["conda"].append(package)
            elif package.name in dependencies.get("pip", Packages()):
                user_packages["pip"].append(package)
            else:
                raise CondaEnvTrackerCondaError(
                    f"Environment {name} does not have {package.spec} installed"
                )

        conda_create_cmd = get_conda_create_command(
            name, user_packages["conda"], channels
        )

        specs = Actions.get_package_specs(
            packages=user_packages["conda"], dependencies=dependencies["conda"]
        )

        history = History.create(
            name=name,
            channels=Channels(channels),
            packages=PackageRevision.create(
                user_packages["conda"], dependencies=dependencies
            ),
            logs=Logs(conda_create_cmd),
            actions=Actions.create(name=name, specs=specs, channels=Channels(channels)),
            diff=Diff.create(
                packages=user_packages["conda"], dependencies=dependencies
            ),
            debug=Debug.create(name=name),
        )

        env = cls(name=name, history=history, dependencies=dependencies)
        if user_packages["pip"]:
            handler = PipHandler(env=env)
            handler.update_history_install(packages=user_packages["pip"])
            env = handler.env
        env.export()

        return env
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_get_packages_with_version_spec(mocker):
    mocker.patch(
        "conda_env_tracker.env.get_dependencies",
        return_value={
            "conda": {
                "pandas": Package("pandas", "pandas", "0.23", "py_36"),
                "numpy": Package("numpy", "numpy", "0.13", "py_36"),
            },
            "pip": {
                "pytest": Package("pytest", "pytest", "4.0")
            },
        },
    )
    local_packages = HistoryPackages.create(
        (Package.from_spec("pandas=0.23"), ))
    local_packages.update_packages(
        packages=(Package.from_spec("pytest==4.0"), ), source="pip")
    local_history = History(
        name=ENV_NAME,
        packages=local_packages,
        channels=Channels("defaults"),
        logs=Logs([]),
        actions=Actions(),
        debug=Debug(),
    )
    env = Environment(name=ENV_NAME, history=local_history)

    expected = {
        "conda": [Package("pandas", "pandas=0.23", "0.23", "py_36")],
        "pip": [Package("pytest", "pytest==4.0", "4.0")],
    }
    actual = get_packages(env)
    assert actual == expected
Exemple #4
0
    def _update_history(
        self,
        get_command: Callable,
        packages: Packages,
        channels: ListLike,
        strict_channel_priority: bool = True,
    ):
        self.env.update_dependencies()
        self.env.history.update_packages(packages=packages,
                                         dependencies=self.env.dependencies)

        self.env.validate_packages(packages)

        log = get_command(name=self.env.name, packages=packages)
        if channels:
            log = log + " " + Channels.format_channels(channels)

        specs = self.env.history.actions.get_package_specs(
            packages=packages, dependencies=self.env.dependencies["conda"])

        channel_string = self.env.history.channels.create_channel_command(
            preferred_channels=channels,
            strict_channel_priority=strict_channel_priority)
        command_with_specs = get_command(name=self.env.name,
                                         packages=Packages.from_specs(specs))
        action = f"{command_with_specs} {channel_string}"

        self.env.history.append(log=log, action=action)
Exemple #5
0
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
Exemple #6
0
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
Exemple #7
0
def test_extract_packages_from_actions(spec):
    """Test parsing the packges from action item"""
    action = Actions.create(
        name="test-extract",
        specs=[spec],
        channels=Channels(["conda-forge", "conda-remote"]),
    )
    packages = action.extract_packages(index=0)

    assert packages[0] == Package.from_spec(spec)
Exemple #8
0
def test_get_create_action():
    """Test create action string"""
    channels = Channels(["conda-forge", "main"])
    expected = [(
        "conda create --name test-create python=3.6.6=py_36 pandas=0.23.1=py_36 "
        "--override-channels --strict-channel-priority "
        "--channel conda-forge "
        "--channel main")]
    actual = Actions.create("test-create",
                            ["python=3.6.6=py_36", "pandas=0.23.1=py_36"],
                            channels=channels)
    assert expected == actual
def expected_update(mocker):
    """Set up for update function"""
    packages = Packages.from_specs("pandas")
    channel = "conda-forge"
    create_cmd = "conda install pandas"
    name = "test-update"
    mocker.patch("conda_env_tracker.gateways.io.Path.mkdir")
    mocker.patch("conda_env_tracker.gateways.io.Path.write_text")
    mocker.patch("conda_env_tracker.gateways.io.Path.iterdir")
    mocker.patch("conda_env_tracker.history.debug.get_pip_version",
                 return_value=None)
    dependencies = {
        "conda": {
            "pandas": Package("pandas", "pandas", "0.23", "py36"),
            "pytest": Package("pytest", "pytest", "0.1", "py36"),
        },
        "pip": {},
    }
    mocker.patch("conda_env_tracker.env.get_dependencies",
                 return_value=dependencies)
    mocker.patch("conda_env_tracker.env.EnvIO.export_packages")
    history = History.create(
        name=name,
        channels=Channels([channel]),
        packages=PackageRevision.create(packages, dependencies=dependencies),
        logs=Logs(create_cmd),
        actions=Actions.create(name="test-update",
                               specs=["pandas"],
                               channels=Channels([channel])),
        diff=Diff.create(packages, dependencies=dependencies),
        debug=Debug(),
    )
    mocker.patch(
        "conda_env_tracker.main.Environment.read",
        return_value=Environment(name=name, history=history),
    )
    return history
Exemple #10
0
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)
Exemple #11
0
 def parse(cls, history_content: dict):
     """Parse the history from the file."""
     try:
         sections = {
             "name": history_content.get("name"),
             "id": history_content.get("id"),
             "channels": Channels(history_content.get("channels")),
             "revisions": Revisions.parse(history_content.get("revisions")),
             "packages": PackageRevision.parse(history_content.get("packages")),
         }
         return cls(**sections)
     except Exception as err:
         raise CondaEnvTrackerParseHistoryError(
             f"Failed to parse history with error: {err}"
         ) from err
Exemple #12
0
def get_conda_create_command(
    name: str,
    packages: Packages,
    channels: ListLike = None,
    yes: bool = False,
    strict_channel_priority: bool = True,
) -> str:
    """Create the conda create command"""
    command = ["conda", "create"]
    if yes:
        command.append("-y")
    command.extend(["--name", name])
    command.append(_join_packages(packages))
    if channels:
        channel_command = Channels(channels).create_channel_command(
            strict_channel_priority=strict_channel_priority)
        command.append(channel_command)
    create_cmd = " ".join(command)
    return create_cmd
def test_get_packages_r(mocker):
    mocker.patch(
        "conda_env_tracker.env.get_dependencies",
        return_value={
            "conda": {
                "r-base":
                Package("r-base", "r-base", "3.5.1", "h539"),
                "r-devtools":
                Package("r-devtools", "r-devtools", "0.1.0", "r351_0"),
            }
        },
    )
    mocker.patch(
        "conda_env_tracker.env.get_r_dependencies",
        return_value={
            "trelliscopejs": Package("trelliscopejs", "trelliscopejs"
                                     "0.1.0")
        },
    )
    local_packages = HistoryPackages.create(
        Packages(
            (Package.from_spec("r-base"), Package.from_spec("r-devtools"))))
    local_packages.update_packages(
        packages=(Package.from_spec("trelliscopejs"), ), source="r")
    local_history = History(
        name=ENV_NAME,
        packages=local_packages,
        channels=Channels("defaults"),
        logs=Logs([]),
        actions=Actions(),
        debug=Debug(),
    )
    env = Environment(name=ENV_NAME, history=local_history)

    expected = {
        "conda": [
            Package("r-base", "r-base", "3.5.1", "h539"),
            Package("r-devtools", "r-devtools", "0.1.0", "r351_0"),
        ],
        "r": [Package("trelliscopejs", "trelliscopejs", "0.1.0")],
    }
    actual = get_packages(env)
    assert actual == expected
Exemple #14
0
 def create(
     cls,
     name: str,
     specs: ListLike,
     channels: Channels,
     yes: bool = False,
     strict_channel_priority: bool = True,
 ):
     """return the action string"""
     if not channels:
         raise CondaEnvTrackerChannelError("Could not find user channels.")
     channel_string = channels.create_channel_command(
         strict_channel_priority=strict_channel_priority)
     actions = cls()
     if yes:
         prefix_cmd = f"conda create -y --name {name} "
     else:
         prefix_cmd = f"conda create --name {name} "
     actions.append(prefix_cmd + " ".join(specs) + " " + channel_string)
     return actions
Exemple #15
0
    def update_history_remove(self,
                              packages: Packages,
                              channels: ListLike = None) -> None:
        """Update history for conda remove."""
        self.env.update_dependencies()
        self.env.history.remove_packages(packages=packages,
                                         dependencies=self.env.dependencies)
        self.env.validate_packages()

        remove_command = get_conda_remove_command(name=self.env.name,
                                                  packages=packages)
        if channels:
            log = remove_command + " " + Channels.format_channels(channels)
        else:
            log = remove_command

        channel_command = self._get_conda_remove_channel_command(
            channels=channels)
        action = f"{remove_command} {channel_command}"

        self.env.history.append(log=log, action=action)
Exemple #16
0
def test_export_empty(mocker):
    """Test package export"""
    mocker.patch(
        "conda_env_tracker.history.history.uuid4").return_value = "unique_uuid"
    expected = {
        "name": "",
        "id": "unique_uuid",
        "history-file-version": "1.0",
        "channels": [],
        "packages": {},
        "revisions": [],
    }
    actual = History.create(
        name="",
        channels=Channels(channels=[]),
        packages=PackageRevision(),
        logs=Logs(),
        actions=Actions([]),
        diff=Diff(),
        debug=[],
    ).export()
    assert expected == actual
def test_get_packages_conda(mocker):
    mocker.patch(
        "conda_env_tracker.env.get_dependencies",
        return_value={
            "conda": {
                "pandas": Package("pandas", "pandas", "0.23", "py_36"),
                "numpy": Package("numpy", "numpy", "0.13", "py_36"),
            }
        },
    )
    packages = (Package.from_spec("pandas"), )
    local_history = History(
        name=ENV_NAME,
        packages=HistoryPackages.create(packages),
        channels=Channels("defaults"),
        logs=Logs([]),
        actions=Actions(),
        debug=Debug(),
    )
    env = Environment(name=ENV_NAME, history=local_history)

    expected = {"conda": [Package("pandas", "pandas", "0.23", "py_36")]}
    actual = get_packages(env)
    assert actual == expected
def test_tuple_to_list():
    actual = Channels(("pro", "main"))
    expected = ["pro", "main"]
    assert actual == expected
def test_init_string():
    actual = Channels("conda-forge")
    expected = ["conda-forge"]

    assert actual == expected
Exemple #20
0
    def create(
        cls,
        name: str,
        packages: Packages,
        channels: ListLike = None,
        yes: bool = False,
        strict_channel_priority: bool = True,
    ):
        """Creating a conda environment from a list of packages."""
        if name == "base":
            raise CondaEnvTrackerCondaError(
                "Environment can not be created using default name base"
            )

        if name in get_all_existing_environment():
            message = (
                f"This environment {name} already exists. Would you like to replace it"
            )
            if prompt_yes_no(prompt_msg=message, default=False):
                delete_conda_environment(name=name)
                local_io = EnvIO(env_directory=USER_ENVS_DIR / name)
                if local_io.env_dir.exists():
                    local_io.delete_all()
            else:
                raise CondaEnvTrackerCondaError(f"Environment {name} already exists")
        logger.debug(f"creating conda env {name}")

        conda_create(
            name=name,
            packages=packages,
            channels=channels,
            yes=yes,
            strict_channel_priority=strict_channel_priority,
        )
        create_cmd = get_conda_create_command(
            name=name,
            packages=packages,
            channels=channels,
            strict_channel_priority=strict_channel_priority,
        )
        specs = Actions.get_package_specs(
            packages=packages, dependencies=get_dependencies(name=name)["conda"]
        )

        if not channels:
            channels = get_conda_channels()

        dependencies = get_dependencies(name=name)

        history = History.create(
            name=name,
            channels=Channels(channels),
            packages=PackageRevision.create(packages, dependencies=dependencies),
            logs=Logs(create_cmd),
            actions=Actions.create(
                name=name,
                specs=specs,
                channels=Channels(channels),
                strict_channel_priority=strict_channel_priority,
            ),
            diff=Diff.create(packages=packages, dependencies=dependencies),
            debug=Debug.create(name=name),
        )
        env = cls(name=name, history=history, dependencies=dependencies)
        env.export()

        return env