def test_invalid_specs():
    invalids = ['=', 'foo 1.0', '>']
    for invalid in invalids:
        assert conda_api.parse_spec(invalid) is None

    with pytest.raises(TypeError) as excinfo:
        conda_api.parse_spec(42)
    assert 'Expected a string' in str(excinfo.value)
def _conda_combine_key(spec):
    parsed = conda_api.parse_spec(spec)
    if parsed is None:
        # this is broken but we complain about it in project.py, carry on here
        return spec
    else:
        return parsed.name
    def _find_conda_deviations(self, prefix, env_spec):
        try:
            installed = conda_api.installed(prefix)
        except conda_api.CondaError as e:
            raise CondaManagerError("Conda failed while listing installed packages in %s: %s" % (prefix, str(e)))

        missing = set()
        wrong_version = set()

        for spec_string in env_spec.conda_packages_for_create:
            spec = conda_api.parse_spec(spec_string)
            name = spec.name

            if name not in installed:
                missing.add(name)
            else:

                def version_match(wanted, installed):
                    if wanted == installed:
                        return True
                    else:
                        return installed.startswith(wanted + ".")

                # The only constraint we are smart enough to understand is
                # the one we put in the lock file, which is plain =.
                # We can't do version comparisons, which is a bug.
                # We won't notice if non-= constraints are unmet.
                (_, installed_version, installed_build) = installed[name]
                if spec.exact_version is not None and not version_match(spec.exact_version, installed_version):
                    wrong_version.add(name)
                elif spec.exact_build_string is not None and not version_match(spec.exact_build_string,
                                                                               installed_build):
                    wrong_version.add(name)

        return (sorted(list(missing)), sorted(list(wrong_version)))
Exemple #4
0
def test_resolve_dependencies_with_actual_conda():
    manager = DefaultCondaManager(frontend=NullFrontend())

    lock_set = manager.resolve_dependencies(['bokeh'], channels=(), platforms=(conda_api.current_platform(), ))
    specs = lock_set.package_specs_for_current_platform
    pprint(specs)
    names = [conda_api.parse_spec(spec).name for spec in specs]
    assert 'bokeh' in names
    assert len(specs) > 5  # 5 is an arbitrary number of deps that surely bokeh has
    def __init__(self,
                 name,
                 conda_packages,
                 channels,
                 pip_packages=(),
                 description=None,
                 inherit_from_names=(),
                 inherit_from=()):
        """Construct a package set with the given name and packages.

        Args:
            name (str): name of the package set
            conda_packages (list): list of package specs to pass to conda install
            channels (list): list of channel names
            pip_packages (list): list of pip package specs to pass to pip
            description (str or None): one-sentence-ish summary of what this env is
            inherit_from_name (str or None): name of what we inherit from
            inherit_from (EnvSpec or None): pull in packages and channels from
        """
        assert inherit_from_names is not None
        assert inherit_from is not None

        self._name = name
        self._conda_packages = tuple(conda_packages)
        self._channels = tuple(channels)
        self._pip_packages = tuple(pip_packages)
        self._description = description
        self._channels_and_packages_hash = None
        self._inherit_from_names = inherit_from_names
        self._inherit_from = inherit_from

        # inherit_from must be a subset of inherit_from_names
        # except that we can have an anonymous base env spec for
        # the global packages/channels sections; if there was an
        # error that kept us from creating one of the specs we
        # name as a parent, then self._inherit_from would be a
        # subset rather than equal.
        for name in tuple([spec.name for spec in self._inherit_from]):
            assert name is None or name in self._inherit_from_names

        conda_specs_by_name = dict()
        for spec in self.conda_packages:
            # we quietly skip invalid specs here and let them fail
            # somewhere we can more easily report an error message.
            parsed = conda_api.parse_spec(spec)
            if parsed is not None:
                conda_specs_by_name[parsed.name] = spec
        self._conda_specs_by_name = conda_specs_by_name

        pip_specs_by_name = dict()
        for spec in self.pip_packages:
            # we quietly skip invalid specs here and let them fail
            # somewhere we can more easily report an error message.
            parsed = pip_api.parse_spec(spec)
            if parsed is not None:
                pip_specs_by_name[parsed.name] = spec
        self._pip_specs_by_name = pip_specs_by_name
 def replace_spec(old):
     name = parse_spec(old).name
     for (replaced_name, new_spec) in updated_specs:
         if replaced_name == name:
             return new_spec
     return old
def _update_env_spec(project, name, packages, channels, create):
    failed = project.problems_status()
    if failed is not None:
        return failed

    if packages is None:
        packages = []
    if channels is None:
        channels = []

    if not create and (name is not None):
        if name not in project.env_specs:
            problem = "Environment spec {} doesn't exist.".format(name)
            return SimpleStatus(success=False, description=problem)

    if name is None:
        env_dict = project.project_file.root
    else:
        env_dict = project.project_file.get_value(['env_specs', name])
        if env_dict is None:
            env_dict = dict()
            project.project_file.set_value(['env_specs', name], env_dict)

    # packages may be a "CommentedSeq" and we don't want to lose the comments,
    # so don't convert this thing to a regular list.
    old_packages = env_dict.get('packages', [])
    old_packages_set = set(parse_spec(dep).name for dep in old_packages)
    bad_specs = []
    updated_specs = []
    new_specs = []
    for dep in packages:
        if dep in old_packages:
            # no-op adding the EXACT same thing (don't move it around)
            continue
        parsed = parse_spec(dep)
        if parsed is None:
            bad_specs.append(dep)
        else:
            if parsed.name in old_packages_set:
                updated_specs.append((parsed.name, dep))
            else:
                new_specs.append(dep)

    if len(bad_specs) > 0:
        bad_specs_string = ", ".join(bad_specs)
        return SimpleStatus(success=False,
                            description="Could not add packages.",
                            errors=[("Bad package specifications: %s." %
                                     bad_specs_string)])

    # remove everything that we are changing the spec for
    def replace_spec(old):
        name = parse_spec(old).name
        for (replaced_name, new_spec) in updated_specs:
            if replaced_name == name:
                return new_spec
        return old

    _map_inplace(replace_spec, old_packages)
    # add all the new ones
    for added in new_specs:
        old_packages.append(added)

    env_dict['packages'] = old_packages

    # channels may be a "CommentedSeq" and we don't want to lose the comments,
    # so don't convert this thing to a regular list.
    new_channels = env_dict.get('channels', [])
    old_channels_set = set(new_channels)
    for channel in channels:
        if channel not in old_channels_set:
            new_channels.append(channel)
    env_dict['channels'] = new_channels

    status = _commit_requirement_if_it_works(project,
                                             CondaEnvRequirement,
                                             env_spec_name=name)

    return status
Exemple #8
0
    def __init__(self,
                 name,
                 conda_packages,
                 channels,
                 pip_packages=(),
                 description=None,
                 inherit_from_names=(),
                 inherit_from=(),
                 platforms=(),
                 lock_set=None):
        """Construct a package set with the given name and packages.

        Args:
            name (str): name of the package set
            conda_packages (list): list of package specs to pass to conda install
            channels (list): list of channel names
            pip_packages (list): list of pip package specs to pass to pip
            description (str or None): one-sentence-ish summary of what this env is
            inherit_from_name (str or None): name of what we inherit from
            inherit_from (EnvSpec or None): pull in packages and channels from
            lock_set (CondaLockSet): locked packages or None
        """
        assert inherit_from_names is not None
        assert inherit_from is not None

        self._name = name
        self._path = None
        self._readonly = None
        self._conda_packages = tuple(conda_packages)
        self._channels = tuple(channels)
        self._pip_packages = tuple(pip_packages)
        self._description = description
        self._logical_hash = None
        self._locked_hash = None
        self._import_hash = None
        self._inherit_from_names = inherit_from_names
        self._inherit_from = inherit_from
        self._lock_set = lock_set
        self._platforms = tuple(conda_api.sort_platform_list(platforms))

        # inherit_from must be a subset of inherit_from_names
        # except that we can have an anonymous base env spec for
        # the global packages/channels sections; if there was an
        # error that kept us from creating one of the specs we
        # name as a parent, then self._inherit_from would be a
        # subset rather than equal.
        for name in tuple([spec.name for spec in self._inherit_from]):
            assert name is None or name in self._inherit_from_names

        conda_specs_by_name = dict()
        for spec in self.conda_packages_for_create:
            # we quietly skip invalid specs here and let them fail
            # somewhere we can more easily report an error message.
            parsed = conda_api.parse_spec(spec)
            if parsed is not None:
                conda_specs_by_name[parsed.name] = spec
        self._conda_specs_for_create_by_name = conda_specs_by_name

        name_set = set()
        conda_constrained_packages = []
        for spec in self.conda_packages:
            parsed = conda_api.parse_spec(spec)
            if parsed is not None:
                name_set.add(parsed.name)
                if parsed.conda_constraint is not None or parsed.pip_constraint is not None:
                    conda_constrained_packages.append(spec)
        self._conda_logical_specs_name_set = name_set
        self.conda_constrained_packages = sorted(conda_constrained_packages)

        pip_specs_by_name = dict()
        for spec in self.pip_packages_for_create:
            # we quietly skip invalid specs here and let them fail
            # somewhere we can more easily report an error message.
            parsed = pip_api.parse_spec(spec)
            if parsed is not None:
                pip_specs_by_name[parsed.name] = spec
        self._pip_specs_for_create_by_name = pip_specs_by_name

        name_set = set()
        for spec in self.pip_packages:
            parsed = pip_api.parse_spec(spec)
            if parsed is not None:
                name_set.add(parsed.name)
        self._pip_logical_specs_name_set = name_set

        self._conda = conda_manager.new_conda_manager()
def test_invalid_specs():
    invalids = ['=', 'foo 1.0', '>']
    for invalid in invalids:
        assert conda_api.parse_spec(invalid) is None