def test_current_platform_unsupported_by_env_spec(monkeypatch):
    lock_set = CondaLockSet(package_specs_by_platform={'all': []},
                            platforms=conda_api.default_platforms)
    spec = EnvSpec(name='myenv',
                   conda_packages=['ipython'],
                   pip_packages=['flake8'],
                   channels=[],
                   platforms=['commodore-64', 'apple-2'],
                   lock_set=lock_set)

    def do_test(dirname):
        envdir = os.path.join(dirname, spec.name)

        manager = DefaultCondaManager(frontend=NullFrontend())

        deviations = manager.find_environment_deviations(envdir, spec)

        error = "Env spec 'myenv' does not support current platform %s (it supports: apple-2, commodore-64)" % \
                conda_api.current_platform()
        assert error == deviations.summary

        with pytest.raises(CondaManagerError) as excinfo:
            manager.fix_environment_deviations(envdir,
                                               spec,
                                               deviations=deviations)
        assert str(
            excinfo.value).startswith("Unable to update environment at ")

    with_directory_contents(dict(), do_test)
Esempio n. 2
0
 def default_env_specs_func():
     return [
         EnvSpec(name='abc',
                 conda_packages=['anaconda'],
                 pip_packages=[],
                 channels=['mychannel'],
                 description="ABC",
                 inherit_from_names=(),
                 inherit_from=()),
         EnvSpec(name='xyz',
                 conda_packages=['foo'],
                 pip_packages=[],
                 channels=['bar'],
                 description="XYZ",
                 inherit_from_names=(),
                 inherit_from=())
     ]
Esempio n. 3
0
    def check(dirname):
        prefix = os.path.join(dirname, "myenv")
        os.makedirs(os.path.join(prefix, 'conda-meta'))

        def mock_installed(prefix):
            return {'bokeh': ('bokeh', '0.12.4', '1')}

        monkeypatch.setattr('anaconda_project.internal.conda_api.installed', mock_installed)

        spec_with_matching_bokeh = EnvSpec(name='myenv',
                                           conda_packages=['bokeh=0.12.4=1'],
                                           pip_packages=[],
                                           channels=[])
        spec_with_more_vague_bokeh = EnvSpec(name='myenv', conda_packages=['bokeh=0.12'], pip_packages=[], channels=[])
        spec_with_unspecified_bokeh = EnvSpec(name='myenv', conda_packages=['bokeh'], pip_packages=[], channels=[])
        spec_with_wrong_version_bokeh = EnvSpec(name='myenv',
                                                conda_packages=['bokeh=0.12.3'],
                                                pip_packages=[],
                                                channels=[])
        spec_with_wrong_build_bokeh = EnvSpec(name='myenv',
                                              conda_packages=['bokeh=0.12.4=0'],
                                              pip_packages=[],
                                              channels=[])

        manager = DefaultCondaManager(frontend=NullFrontend())

        deviations = manager.find_environment_deviations(prefix, spec_with_matching_bokeh)
        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ()

        deviations = manager.find_environment_deviations(prefix, spec_with_more_vague_bokeh)
        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ()

        deviations = manager.find_environment_deviations(prefix, spec_with_unspecified_bokeh)
        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ()

        deviations = manager.find_environment_deviations(prefix, spec_with_wrong_version_bokeh)
        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ('bokeh', )

        deviations = manager.find_environment_deviations(prefix, spec_with_wrong_build_bokeh)
        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ('bokeh', )
def test_platforms_affect_hash():
    with_platforms_spec = EnvSpec(name="foo",
                                  conda_packages=['a', 'b'],
                                  pip_packages=['c', 'd'],
                                  channels=['x', 'y'],
                                  platforms=('linux-64', ))
    without_platforms_spec = EnvSpec(
        name=with_platforms_spec.name,
        conda_packages=with_platforms_spec.conda_packages,
        pip_packages=with_platforms_spec.pip_packages,
        channels=with_platforms_spec.channels,
        platforms=())

    assert with_platforms_spec.logical_hash != with_platforms_spec.locked_hash
    assert with_platforms_spec.logical_hash != with_platforms_spec.import_hash

    assert without_platforms_spec.logical_hash == without_platforms_spec.locked_hash
    assert without_platforms_spec.logical_hash == without_platforms_spec.import_hash
Esempio n. 5
0
def test_lock_set_affects_hash():
    lock_set = CondaLockSet({'all': ['a=1.0=1']}, platforms=['linux-32', 'linux-64', 'osx-64', 'win-32', 'win-64'])
    with_lock_spec = EnvSpec(
        name="foo", conda_packages=['a', 'b'], pip_packages=['c', 'd'], channels=['x', 'y'], lock_set=lock_set)
    without_lock_spec = EnvSpec(
        name=with_lock_spec.name,
        conda_packages=with_lock_spec.conda_packages,
        pip_packages=with_lock_spec.pip_packages,
        channels=with_lock_spec.channels,
        lock_set=None)

    assert with_lock_spec.conda_packages != with_lock_spec.conda_packages_for_create
    assert without_lock_spec.conda_packages == without_lock_spec.conda_packages_for_create

    assert without_lock_spec.logical_hash == without_lock_spec.locked_hash
    assert with_lock_spec.logical_hash != with_lock_spec.locked_hash
    assert with_lock_spec.logical_hash == without_lock_spec.logical_hash

    assert without_lock_spec.locked_hash == without_lock_spec.import_hash
    assert with_lock_spec.locked_hash != with_lock_spec.import_hash
 def check_missing_package(dirname):
     requirement = CondaEnvRequirement(
         registry=RequirementsRegistry(),
         env_specs=dict(default=EnvSpec(
             'default', ['boguspackage', 'boguspackage2'], [])))
     project_dir_disable_dedicated_env(dirname)
     local_state = LocalStateFile.load_for_directory(dirname)
     environ = minimal_environ(PROJECT_DIR=dirname)
     status = requirement.check_status(
         environ, local_state, 'default',
         UserConfigOverrides(inherited_env=environ.get(conda_env_var)))
     assert "Conda environment is missing packages: boguspackage, boguspackage2" == status.status_description
Esempio n. 7
0
def test_lock_set_affects_name_sets():
    lock_set = CondaLockSet({
        'all': ['a=1.0=1', 'q=2.0=2']
    },
                            platforms=['linux-32', 'linux-64', 'osx-64', 'win-32', 'win-64'])
    spec = EnvSpec(
        name="foo", conda_packages=['a', 'b'], pip_packages=['c', 'd'], channels=['x', 'y'], lock_set=lock_set)

    assert ('a', 'b') == spec.conda_packages
    assert ('a=1.0=1', 'q=2.0=2') == spec.conda_packages_for_create
    assert set(['a', 'b']) == spec.conda_package_names_set
    assert set(['a', 'q']) == spec.conda_package_names_for_create_set
def test_overwrite_packages_with_lock_set():
    lock_set = CondaLockSet(
        {'all': ['a=1.0=1']},
        platforms=['linux-32', 'linux-64', 'osx-64', 'win-32', 'win-64'])
    spec = EnvSpec(name="foo",
                   conda_packages=['a', 'b'],
                   pip_packages=['c', 'd'],
                   channels=['x', 'y'],
                   lock_set=lock_set)

    # package "b" is now ignored
    assert ('a=1.0=1', ) == spec.conda_packages_for_create
Esempio n. 9
0
    def check(filename):
        spec = _load_environment_yml(filename)

        assert spec is not None

        changed = EnvSpec(
            name=spec.name,
            conda_packages=spec.conda_packages[1:],
            pip_packages=spec.pip_packages,
            channels=spec.channels)

        (desynced, name) = _find_out_of_sync_importable_spec([changed], os.path.dirname(filename))
        assert desynced is not None
        assert desynced.logical_hash == spec.logical_hash
        assert name == os.path.basename(filename)
    def check_fails_while_listing_installed(dirname):
        def sabotaged_installed_command(prefix):
            from anaconda_project.internal import conda_api
            raise conda_api.CondaError("sabotage!")

        monkeypatch.setattr('anaconda_project.internal.conda_api.installed',
                            sabotaged_installed_command)

        project_dir_disable_dedicated_env(dirname)
        local_state = LocalStateFile.load_for_directory(dirname)

        requirement = CondaEnvRequirement(
            registry=RequirementsRegistry(),
            env_specs=dict(
                default=EnvSpec('default', ['not_a_real_package'], [])))
        environ = minimal_environ(PROJECT_DIR=dirname)
        status = requirement.check_status(
            environ, local_state, 'default',
            UserConfigOverrides(inherited_env=environ.get(conda_env_var)))
        assert status.status_description.startswith(
            "Conda failed while listing installed packages in ")
        assert status.status_description.endswith(": sabotage!")
Esempio n. 11
0
if platform.system() == 'Windows':
    PYTHON_BINARY = "python.exe"
    IPYTHON_BINARY = "Scripts\\ipython.exe"
    FLAKE8_BINARY = "Scripts\\flake8.exe"
    # Use a different package from the test env due to weird CI path/env errors
    PYINSTRUMENT_BINARY = "Scripts\\pyinstrument.exe"
else:
    PYTHON_BINARY = "bin/python"
    IPYTHON_BINARY = "bin/ipython"
    FLAKE8_BINARY = "bin/flake8"
    # Use a different package from the test env due to weird CI path/env errors
    PYINSTRUMENT_BINARY = "bin/pyinstrument"

test_spec = EnvSpec(name='myenv',
                    conda_packages=['ipython', 'python=3.8'],
                    pip_packages=['pyinstrument'],
                    channels=[])


def test_current_platform_unsupported_by_env_spec(monkeypatch):
    lock_set = CondaLockSet(package_specs_by_platform={'all': []},
                            platforms=conda_api.default_platforms)
    spec = EnvSpec(name='myenv',
                   conda_packages=['ipython'],
                   pip_packages=['flake8'],
                   channels=[],
                   platforms=['commodore-64', 'apple-2'],
                   lock_set=lock_set)

    def do_test(dirname):
        envdir = os.path.join(dirname, spec.name)
Esempio n. 12
0
def test_diff_from():
    spec1 = EnvSpec(name="foo", conda_packages=['a', 'b'], pip_packages=['c', 'd'], channels=['x', 'y'])
    spec2 = EnvSpec(name="bar", conda_packages=['a', 'b', 'q'], pip_packages=['c'], channels=['x', 'y', 'z'])
    diff = spec2.diff_from(spec1)

    assert '  channels:\n      x\n      y\n    + z\n  a\n  b\n+ q\n  pip:\n      c\n    - d' == diff
def _empty_default_requirement():
    return CondaEnvRequirement(
        registry=RequirementsRegistry(),
        env_specs=dict(default=EnvSpec('default', [], [])))
Esempio n. 14
0
def test_conda_create_and_install_and_remove(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    spec = test_spec
    assert spec.conda_packages == ('ipython', 'python=3.8')
    assert spec.pip_packages == ('pyinstrument', )

    spec_with_phony_pip_package = EnvSpec(
        name='myenv',
        conda_packages=['ipython'],
        pip_packages=['pyinstrument', 'nope_not_a_thing'],
        channels=[])
    assert spec_with_phony_pip_package.conda_packages == ('ipython', )
    assert spec_with_phony_pip_package.pip_packages == ('pyinstrument',
                                                        'nope_not_a_thing')
    assert spec_with_phony_pip_package.pip_package_names_set == set(
        ('pyinstrument', 'nope_not_a_thing'))

    # package url is supposed to be on a nonexistent port, if it
    # causes a problem we need to mock
    spec_with_bad_url_pip_package = EnvSpec(
        name='myenv',
        conda_packages=['ipython'],
        pip_packages=[
            'pyinstrument', 'https://127.0.0.1:24729/nope#egg=phony'
        ],
        channels=[])
    assert spec_with_bad_url_pip_package.conda_packages == ('ipython', )
    assert spec_with_bad_url_pip_package.pip_packages == (
        'pyinstrument', 'https://127.0.0.1:24729/nope#egg=phony')
    assert spec_with_bad_url_pip_package.pip_package_names_set == set(
        ('pyinstrument', 'phony'))

    spec_with_old_ipython = EnvSpec(name='myenv',
                                    conda_packages=['ipython=7.10.1'],
                                    pip_packages=['pyinstrument'],
                                    channels=[])
    assert spec_with_old_ipython.conda_packages == ('ipython=7.10.1', )

    spec_with_bokeh = EnvSpec(name='myenv',
                              conda_packages=['bokeh'],
                              pip_packages=['pyinstrument'],
                              channels=[])
    assert spec_with_bokeh.conda_packages == ('bokeh', )

    spec_with_bokeh_and_old_ipython = EnvSpec(
        name='myenv',
        conda_packages=['bokeh', 'ipython=7.10.1'],
        pip_packages=['pyinstrument'],
        channels=[])
    assert spec_with_bokeh_and_old_ipython.conda_packages == (
        'bokeh',
        'ipython=7.10.1',
    )

    def do_test(dirname):
        from codecs import open as real_open

        envdir = os.path.join(dirname, spec.name)

        manager = DefaultCondaManager(frontend=NullFrontend())

        is_readonly = dict(readonly=False)

        def mock_open(*args, **kwargs):
            if is_readonly['readonly']:
                raise IOError("did not open")
            return real_open(*args, **kwargs)

        monkeypatch.setattr('codecs.open', mock_open)

        assert not os.path.isdir(envdir)
        assert not os.path.exists(os.path.join(envdir, IPYTHON_BINARY))
        assert not os.path.exists(os.path.join(envdir, FLAKE8_BINARY))
        assert not manager._timestamp_file_up_to_date(envdir, spec)

        deviations = manager.find_environment_deviations(envdir, spec)

        assert set(deviations.missing_packages) == {'python', 'ipython'}
        assert deviations.missing_pip_packages == ('pyinstrument', )

        # with create=False, we won't create the env
        with pytest.raises(CondaManagerError) as excinfo:
            manager.fix_environment_deviations(envdir,
                                               spec,
                                               deviations,
                                               create=False)
            assert 'does not exist' in str(excinfo.value)

        assert not os.path.isdir(envdir)

        # now create the env
        manager.fix_environment_deviations(envdir, spec, deviations)

        assert os.path.isdir(envdir)
        assert os.path.isdir(os.path.join(envdir, "conda-meta"))
        assert os.path.exists(os.path.join(envdir, IPYTHON_BINARY))
        assert os.path.exists(os.path.join(envdir, PYINSTRUMENT_BINARY))

        assert manager._timestamp_file_up_to_date(envdir, spec)
        assert not manager._timestamp_file_up_to_date(
            envdir, spec_with_phony_pip_package)

        # test bad pip package throws error
        deviations = manager.find_environment_deviations(
            envdir, spec_with_phony_pip_package)

        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ()
        assert deviations.missing_pip_packages == ('nope_not_a_thing', )

        with pytest.raises(CondaManagerError) as excinfo:
            manager.fix_environment_deviations(envdir,
                                               spec_with_phony_pip_package,
                                               deviations)
        assert 'Failed to install missing pip packages' in str(excinfo.value)
        assert not manager._timestamp_file_up_to_date(
            envdir, spec_with_phony_pip_package)

        # test bad url package throws error
        deviations = manager.find_environment_deviations(
            envdir, spec_with_bad_url_pip_package)

        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ()
        assert deviations.missing_pip_packages == ('phony', )

        with pytest.raises(CondaManagerError) as excinfo:
            manager.fix_environment_deviations(envdir,
                                               spec_with_bad_url_pip_package,
                                               deviations)
        assert 'Failed to install missing pip packages' in str(excinfo.value)
        assert not manager._timestamp_file_up_to_date(
            envdir, spec_with_bad_url_pip_package)

        # test we notice wrong ipython version AND missing bokeh AND readonly environment
        is_readonly['readonly'] = True
        deviations = manager.find_environment_deviations(
            envdir, spec_with_bokeh_and_old_ipython)

        assert deviations.missing_packages == ('bokeh', )
        assert deviations.wrong_version_packages == ('ipython', )
        assert deviations.unfixable
        is_readonly['readonly'] = False

        # test we notice only missing bokeh
        deviations = manager.find_environment_deviations(
            envdir, spec_with_bokeh)

        assert deviations.missing_packages == ('bokeh', )
        assert deviations.wrong_version_packages == ()
        assert not deviations.unfixable

        # test we notice wrong ipython version and can downgrade
        deviations = manager.find_environment_deviations(
            envdir, spec_with_old_ipython)

        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ('ipython', )
        assert not deviations.unfixable

        manager.fix_environment_deviations(envdir, spec_with_old_ipython,
                                           deviations)

        assert manager._timestamp_file_up_to_date(envdir,
                                                  spec_with_old_ipython)

        deviations = manager.find_environment_deviations(
            envdir, spec_with_old_ipython)
        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ()

        # update timestamp; this doesn't re-upgrade because `spec` doesn't
        # specify an ipython version
        assert not manager._timestamp_file_up_to_date(envdir, spec)

        deviations = manager.find_environment_deviations(envdir, spec)

        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ()

        # fix_environment_deviations should be a no-op on readonly envs
        # with no deviations, in particular the time stamp file should
        # not be changed and therefore not be up to date
        is_readonly['readonly'] = True
        manager.fix_environment_deviations(envdir, spec, deviations)
        assert not manager._timestamp_file_up_to_date(envdir, spec)

        # when the environment is readwrite, the timestamp file should
        # be updated
        is_readonly['readonly'] = False
        manager.fix_environment_deviations(envdir, spec, deviations)
        assert manager._timestamp_file_up_to_date(envdir, spec)

        deviations = manager.find_environment_deviations(envdir, spec)
        assert deviations.missing_packages == ()
        assert deviations.wrong_version_packages == ()

        # test that we can remove a package
        assert manager._timestamp_file_up_to_date(envdir, spec)
        time.sleep(
            1)  # removal is fast enough to break our timestamp resolution
        manager.remove_packages(prefix=envdir, packages=['ipython'])
        assert not os.path.exists(os.path.join(envdir, IPYTHON_BINARY))
        assert not manager._timestamp_file_up_to_date(envdir, spec)

        # test for error removing
        with pytest.raises(CondaManagerError) as excinfo:
            manager.remove_packages(prefix=envdir, packages=['ipython'])
        # different versions of conda word this differently
        message = str(excinfo.value)
        valid_strings = ('no packages found to remove', 'Package not found',
                         "named 'ipython' found to remove",
                         'PackagesNotFoundError:',
                         "is missing from the environment")
        assert any(s in message for s in valid_strings)
        assert not manager._timestamp_file_up_to_date(envdir, spec)

        # test failure to exec pip
        def mock_call_pip(*args, **kwargs):
            raise pip_api.PipError("pip fail")

        monkeypatch.setattr('anaconda_project.internal.pip_api._call_pip',
                            mock_call_pip)

        with pytest.raises(CondaManagerError) as excinfo:
            deviations = manager.find_environment_deviations(envdir, spec)
        assert 'pip failed while listing' in str(excinfo.value)

    with_directory_contents(dict(), do_test)
Esempio n. 15
0
import anaconda_project.internal.pip_api as pip_api

from anaconda_project.internal.test.tmpfile_utils import with_directory_contents
from anaconda_project.internal.test.test_conda_api import monkeypatch_conda_not_to_use_links

if platform.system() == 'Windows':
    PYTHON_BINARY = "python.exe"
    IPYTHON_BINARY = "Scripts\ipython.exe"
    FLAKE8_BINARY = "Scripts\\flake8.exe"
else:
    PYTHON_BINARY = "bin/python"
    IPYTHON_BINARY = "bin/ipython"
    FLAKE8_BINARY = "bin/flake8"

test_spec = EnvSpec(name='myenv',
                    conda_packages=['ipython'],
                    pip_packages=['flake8'],
                    channels=[])


def test_conda_create_and_install_and_remove(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    spec = test_spec
    assert spec.conda_packages == ('ipython', )
    assert spec.pip_packages == ('flake8', )

    spec_with_phony_pip_package = EnvSpec(
        name='myenv',
        conda_packages=['ipython'],
        pip_packages=['flake8', 'nope_not_a_thing'],
        channels=[])
Esempio n. 16
0
def _empty_default_env_spec():
    return (EnvSpec(name="default", channels=[], conda_packages=()), )
Esempio n. 17
0
def test_conda_create_and_install_and_remove(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    spec = test_spec
    assert spec.conda_packages == ('ipython', )
    assert spec.pip_packages == ('flake8', )

    spec_with_phony_pip_package = EnvSpec(
        name='myenv',
        conda_packages=['ipython'],
        pip_packages=['flake8', 'nope_not_a_thing'],
        channels=[])
    assert spec_with_phony_pip_package.conda_packages == ('ipython', )
    assert spec_with_phony_pip_package.pip_packages == ('flake8',
                                                        'nope_not_a_thing')
    assert spec_with_phony_pip_package.pip_package_names_set == set(
        ('flake8', 'nope_not_a_thing'))

    # package url is supposed to be on a nonexistent port, if it
    # causes a problem we need to mock
    spec_with_bad_url_pip_package = EnvSpec(
        name='myenv',
        conda_packages=['ipython'],
        pip_packages=['flake8', 'https://127.0.0.1:24729/nope#egg=phony'],
        channels=[])
    assert spec_with_bad_url_pip_package.conda_packages == ('ipython', )
    assert spec_with_bad_url_pip_package.pip_packages == (
        'flake8', 'https://127.0.0.1:24729/nope#egg=phony')
    assert spec_with_bad_url_pip_package.pip_package_names_set == set(
        ('flake8', 'phony'))

    def do_test(dirname):
        envdir = os.path.join(dirname, spec.name)

        manager = DefaultCondaManager()

        assert not os.path.isdir(envdir)
        assert not os.path.exists(os.path.join(envdir, IPYTHON_BINARY))
        assert not os.path.exists(os.path.join(envdir, FLAKE8_BINARY))
        assert not manager._timestamp_file_up_to_date(envdir, spec)

        deviations = manager.find_environment_deviations(envdir, spec)

        assert deviations.missing_packages == ('ipython', )
        assert deviations.missing_pip_packages == ('flake8', )

        manager.fix_environment_deviations(envdir, spec, deviations)

        assert os.path.isdir(envdir)
        assert os.path.isdir(os.path.join(envdir, "conda-meta"))
        assert os.path.exists(os.path.join(envdir, IPYTHON_BINARY))
        assert os.path.exists(os.path.join(envdir, FLAKE8_BINARY))

        assert manager._timestamp_file_up_to_date(envdir, spec)
        assert not manager._timestamp_file_up_to_date(
            envdir, spec_with_phony_pip_package)

        # test bad pip package throws error
        deviations = manager.find_environment_deviations(
            envdir, spec_with_phony_pip_package)

        assert deviations.missing_packages == ()
        assert deviations.missing_pip_packages == ('nope_not_a_thing', )

        with pytest.raises(CondaManagerError) as excinfo:
            manager.fix_environment_deviations(envdir,
                                               spec_with_phony_pip_package,
                                               deviations)
        assert 'Failed to install missing pip packages' in str(excinfo.value)
        assert not manager._timestamp_file_up_to_date(
            envdir, spec_with_phony_pip_package)

        # test bad url package throws error
        deviations = manager.find_environment_deviations(
            envdir, spec_with_bad_url_pip_package)

        assert deviations.missing_packages == ()
        assert deviations.missing_pip_packages == ('phony', )

        with pytest.raises(CondaManagerError) as excinfo:
            manager.fix_environment_deviations(envdir,
                                               spec_with_bad_url_pip_package,
                                               deviations)
        assert 'Failed to install missing pip packages' in str(excinfo.value)
        assert not manager._timestamp_file_up_to_date(
            envdir, spec_with_bad_url_pip_package)

        # test that we can remove a package
        assert manager._timestamp_file_up_to_date(envdir, spec)
        manager.remove_packages(prefix=envdir, packages=['ipython'])
        assert not os.path.exists(os.path.join(envdir, IPYTHON_BINARY))
        assert not manager._timestamp_file_up_to_date(envdir, spec)

        # test for error removing
        with pytest.raises(CondaManagerError) as excinfo:
            manager.remove_packages(prefix=envdir, packages=['ipython'])
        # different versions of conda word this differently
        assert 'no packages found to remove' in str(
            excinfo.value) or 'Package not found' in str(excinfo.value)
        assert not manager._timestamp_file_up_to_date(envdir, spec)

        # test failure to exec pip
        def mock_call_pip(*args, **kwargs):
            raise pip_api.PipError("pip fail")

        monkeypatch.setattr('anaconda_project.internal.pip_api._call_pip',
                            mock_call_pip)

        with pytest.raises(CondaManagerError) as excinfo:
            deviations = manager.find_environment_deviations(envdir, spec)
        assert 'pip failed while listing' in str(excinfo.value)

    with_directory_contents(dict(), do_test)