Ejemplo n.º 1
0
def test_conda_create_and_install_and_remove_pip_stuff(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    def do_test(dirname):
        envdir = os.path.join(dirname, "myenv")
        # don't specify a python version so we use the one we already have
        # in the root env, otherwise this might take forever.
        conda_api.create(prefix=envdir, pkgs=['python'])

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

        # test that we can install a package via pip
        assert not os.path.exists(os.path.join(envdir, FLAKE8_BINARY))
        pip_api.install(prefix=envdir, pkgs=['flake8'])
        assert os.path.exists(os.path.join(envdir, FLAKE8_BINARY))

        # list what was installed
        installed = pip_api.installed(prefix=envdir)
        assert 'flake8' in installed
        assert installed['flake8'][0] == 'flake8'
        assert installed['flake8'][1] is not None

        # test that we can remove it again
        pip_api.remove(prefix=envdir, pkgs=['flake8'])
        assert not os.path.exists(os.path.join(envdir, FLAKE8_BINARY))

        # no longer in the installed list
        installed = pip_api.installed(prefix=envdir)
        assert 'flake8' not in installed

    with_directory_contents(dict(), do_test)
Ejemplo n.º 2
0
def test_prepare_project_scoped_env_with_packages(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    def prepare_project_scoped_env_with_packages(dirname):
        project = Project(dirname)
        environ = minimal_environ(PROJECT_DIR=dirname)
        result = prepare_without_interaction(project, environ=environ, env_spec_name='bootstrap-env')
        assert result

        envs_dir = os.path.join(dirname, "envs")
        env_name = 'bootstrap-env'
        prefix = os.path.join(envs_dir, env_name)
        installed = conda_api.installed(prefix)

        assert 'bokeh' not in installed

        deps = ['ipython', 'numpy', 'pip']
        for pkg in deps:
            assert pkg in installed

        deps += ['bokeh']

        # Preparing it again with new packages added should add those
        project.project_file.set_value('packages', deps)
        project.project_file.save()
        environ = minimal_environ(PROJECT_DIR=dirname)
        result = prepare_without_interaction(project, environ=environ)
        assert result

        prefix = result.environ[conda_env_var]
        installed = conda_api.installed(prefix)

        for pkg in deps:
            assert pkg in installed

        installed_pip = pip_api.installed(prefix)
        assert 'flake8' in installed_pip

        # Preparing it again with a bogus package should fail
        deps = project.project_file.get_value('packages')
        project.project_file.set_value(['packages'], deps + ['boguspackage'])
        project.project_file.save()
        environ = minimal_environ(PROJECT_DIR=dirname)
        result = prepare_without_interaction(project, environ=environ)
        assert not result

    with_directory_contents_completing_project_file({
        DEFAULT_PROJECT_FILENAME:
        """
env_specs:
  bootstrap-env:
    packages:
        - python=3.7
        - ipython
        - numpy=1.15
        - pip:
            - flake8
"""
    }, prepare_project_scoped_env_with_packages)
def test_prepare_and_unprepare_project_scoped_env(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    def prepare_project_scoped_env(dirname):
        project = Project(dirname)
        fake_old_path = "foo" + os.pathsep + "bar"
        environ = dict(PROJECT_DIR=dirname, PATH=fake_old_path)
        result = prepare_without_interaction(project, environ=environ)
        assert result
        expected_env = os.path.join(dirname, "envs", "default")
        if platform.system() == 'Windows':
            expected_new_path = expected_env + os.pathsep + os.path.join(
                expected_env, script_dir) + os.pathsep + os.path.join(
                    expected_env, "Library",
                    "bin") + os.pathsep + "foo" + os.pathsep + "bar"
        else:
            expected_new_path = os.path.join(
                expected_env,
                script_dir) + os.pathsep + "foo" + os.pathsep + "bar"
        expected = dict(PROJECT_DIR=project.directory_path,
                        PATH=expected_new_path)
        conda_api.environ_set_prefix(expected, expected_env)

        expected == result.environ
        assert os.path.exists(os.path.join(expected_env, "conda-meta"))
        conda_meta_mtime = os.path.getmtime(
            os.path.join(expected_env, "conda-meta"))

        # bare minimum default env shouldn't include these
        # (contrast with the test later where we list them in
        # requirements)
        installed = conda_api.installed(expected_env)
        assert 'ipython' not in installed
        assert 'numpy' not in installed

        # Prepare it again should no-op (use the already-existing environment)
        environ = dict(PROJECT_DIR=dirname, PATH=fake_old_path)
        result = prepare_without_interaction(project, environ=environ)
        assert result
        expected = dict(PROJECT_DIR=project.directory_path,
                        PATH=expected_new_path)
        conda_api.environ_set_prefix(expected, expected_env)
        assert expected == result.environ
        assert conda_meta_mtime == os.path.getmtime(
            os.path.join(expected_env, "conda-meta"))

        # Now unprepare
        status = unprepare(project, result)
        assert status, status.errors
        assert status.status_description == (
            'Deleted environment files in %s.' % (expected_env))
        assert status.errors == []
        assert not os.path.exists(expected_env)

    with_directory_contents_completing_project_file(
        dict(), prepare_project_scoped_env)
Ejemplo n.º 4
0
def test_prepare_and_unprepare_project_scoped_env(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    def prepare_project_scoped_env(dirname):
        project = Project(dirname)
        fake_old_path = "foo" + os.pathsep + "bar"
        environ = dict(PROJECT_DIR=dirname, PATH=fake_old_path)
        result = prepare_without_interaction(project, environ=environ)
        assert result
        expected_env = os.path.join(dirname, "envs", "bootstrap-env")
        if platform.system() == 'Windows':
            expected_new_path = expected_env + os.pathsep + os.path.join(
                expected_env, script_dir) + os.pathsep + os.path.join(expected_env, "Library",
                                                                      "bin") + os.pathsep + "foo" + os.pathsep + "bar"
        else:
            expected_new_path = os.path.join(expected_env, script_dir) + os.pathsep + "foo" + os.pathsep + "bar"
        expected = dict(PROJECT_DIR=project.directory_path, PATH=expected_new_path, BOOTSTRAP_ENV_PREFIX=expected_env)
        conda_api.environ_set_prefix(expected, expected_env)

        expected == result.environ
        assert os.path.exists(os.path.join(expected_env, "conda-meta"))
        conda_meta_mtime = os.path.getmtime(os.path.join(expected_env, "conda-meta"))

        # bare minimum bootstrap-env env shouldn't include these
        # (contrast with the test later where we list them in
        # requirements)
        installed = conda_api.installed(expected_env)
        assert 'ipython' not in installed
        assert 'numpy' not in installed

        # Prepare it again should no-op (use the already-existing environment)
        environ = dict(PROJECT_DIR=dirname, PATH=fake_old_path)
        result = prepare_without_interaction(project, environ=environ)
        assert result
        expected = dict(PROJECT_DIR=project.directory_path, PATH=expected_new_path)
        conda_api.environ_set_prefix(expected, expected_env)
        assert conda_meta_mtime == os.path.getmtime(os.path.join(expected_env, "conda-meta"))

        # Now unprepare
        status = unprepare(project, result)
        assert status

        # todo: this differs from standard CondaEnvProvider
        assert status.status_description == 'Success.'
        assert status.errors == []
        assert not os.path.exists(expected_env)

    with_directory_contents_completing_project_file(
        {
            DEFAULT_PROJECT_FILENAME: """
env_specs:
  bootstrap-env:
    packages:
        - python
"""
        }, prepare_project_scoped_env)
def test_prepare_project_scoped_env_with_packages(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    def prepare_project_scoped_env_with_packages(dirname):
        project = Project(dirname)
        environ = minimal_environ(PROJECT_DIR=dirname)
        result = prepare_without_interaction(project, environ=environ)
        assert result

        prefix = result.environ[conda_env_var]
        installed = conda_api.installed(prefix)

        assert 'ipython' in installed
        assert 'numpy' in installed
        assert 'bokeh' not in installed

        # Preparing it again with new packages added should add those
        deps = project.project_file.get_value('packages')
        project.project_file.set_value('packages', deps + ['bokeh'])
        project.project_file.save()
        environ = minimal_environ(PROJECT_DIR=dirname)
        result = prepare_without_interaction(project, environ=environ)
        assert result

        prefix = result.environ[conda_env_var]
        installed = conda_api.installed(prefix)

        assert 'ipython' in installed
        assert 'numpy' in installed
        assert 'bokeh' in installed

        installed_pip = pip_api.installed(prefix)
        assert 'flake8' in installed_pip

        # Preparing it again with a bogus package should fail
        deps = project.project_file.get_value('packages')
        project.project_file.set_value(['packages'], deps + ['boguspackage'])
        project.project_file.save()
        environ = minimal_environ(PROJECT_DIR=dirname)
        result = prepare_without_interaction(project, environ=environ)
        assert not result

    with_directory_contents_completing_project_file(
        {
            DEFAULT_PROJECT_FILENAME:
            """
packages:
    - python=3.7
    - ipython
    - numpy=1.15
    - pip
    - pip:
      - flake8
"""
        }, prepare_project_scoped_env_with_packages)
Ejemplo n.º 6
0
def test_timestamp_file_ignores_failed_write(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    spec = test_spec

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

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

        manager = DefaultCondaManager(frontend=NullFrontend())

        counts = dict(calls=0)

        def mock_open(*args, **kwargs):
            counts['calls'] += 1
            if counts['calls'] == 1:
                raise IOError("did not open")
            else:
                return real_open(*args, **kwargs)

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

        # this should NOT throw but also should not write the
        # timestamp file (we ignore errors)
        filename = manager._timestamp_file(envdir, spec)
        assert filename.startswith(envdir)
        assert not os.path.exists(filename)
        manager._write_timestamp_file(envdir, spec)
        assert not os.path.exists(filename)
        # the second time we really wsrite it (this is to prove we
        # are looking at the right filename)
        manager._write_timestamp_file(envdir, spec)
        assert os.path.exists(filename)

        # check on the file contents
        with real_open(filename, 'r', encoding='utf-8') as f:
            content = json.loads(f.read())
            assert dict(anaconda_project_version=version) == content

    with_directory_contents(dict(), do_test)
Ejemplo n.º 7
0
def test_pip_errors(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    def do_test(dirname):
        envdir = os.path.join(dirname, "myenv")

        conda_api.create(prefix=envdir, pkgs=['python'])

        # no packages to install
        with pytest.raises(TypeError) as excinfo:
            pip_api.install(prefix=envdir, pkgs=[])
        assert 'must specify a list' in repr(excinfo.value)

        # no packages to remove
        with pytest.raises(TypeError) as excinfo:
            pip_api.remove(prefix=envdir, pkgs=[])
        assert 'must specify a list' in repr(excinfo.value)

        # pip command not installed
        from os.path import exists as real_exists

        def mock_exists(path):
            if path.endswith("pip") or path.endswith("pip.exe"):
                return False
            else:
                return real_exists(path)

        monkeypatch.setattr('os.path.exists', mock_exists)
        with pytest.raises(pip_api.PipNotInstalledError) as excinfo:
            pip_api.install(prefix=envdir, pkgs=['foo'])
        assert 'command is not installed in the environment' in repr(
            excinfo.value)

        installed = pip_api.installed(prefix=envdir)
        assert dict(
        ) == installed  # with pip not installed, no packages are listed.

        # pip command exits nonzero
        error_script = """from __future__ import print_function
import sys
print("TEST_ERROR", file=sys.stderr)
sys.exit(1)
"""

        def get_failed_command(prefix, extra_args):
            return tmp_script_commandline(error_script)

        monkeypatch.setattr(
            'anaconda_project.internal.pip_api._get_pip_command',
            get_failed_command)
        with pytest.raises(pip_api.PipError) as excinfo:
            pip_api.install(prefix=envdir, pkgs=['flake8'])
        assert 'TEST_ERROR' in repr(excinfo.value)

        # pip command exits zero printing stuff on stderr
        error_message_but_success_script = """from __future__ import print_function
import sys
print("TEST_ERROR", file=sys.stderr)
sys.exit(0)
"""

        def get_failed_command(prefix, extra_args):
            return tmp_script_commandline(error_message_but_success_script)

        monkeypatch.setattr(
            'anaconda_project.internal.pip_api._get_pip_command',
            get_failed_command)
        pip_api.install(prefix=envdir, pkgs=['flake8'])

        # cannot exec pip
        def mock_popen(args, stdout=None, stderr=None):
            raise OSError("failed to exec")

        monkeypatch.setattr('subprocess.Popen', mock_popen)
        with pytest.raises(pip_api.PipError) as excinfo:
            pip_api.install(prefix=envdir, pkgs=['flake8'])
        assert 'failed to exec' in repr(excinfo.value)

    with_directory_contents(dict(), do_test)
Ejemplo n.º 8
0
def test_timestamp_file_works(monkeypatch):
    monkeypatch_conda_not_to_use_links(monkeypatch)

    spec = test_spec

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

        manager = DefaultCondaManager(frontend=NullFrontend())

        def print_timestamps(when):
            newest_in_prefix = 0
            for d in manager._timestamp_comparison_directories(envdir):
                try:
                    t = os.path.getmtime(d)
                except Exception:
                    t = 0
                if t > newest_in_prefix:
                    newest_in_prefix = t
            timestamp_fname = manager._timestamp_file(envdir, spec)
            try:
                timestamp_file = os.path.getmtime(timestamp_fname)
            except Exception:
                timestamp_file = 0
            print("%s: timestamp file %d prefix %d diff %g" %
                  (when, timestamp_file, newest_in_prefix,
                   newest_in_prefix - timestamp_file))

        print_timestamps("before env creation")

        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, PYINSTRUMENT_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', )
        assert not deviations.ok

        manager.fix_environment_deviations(envdir, spec, deviations)

        print_timestamps("after fixing 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)

        called = []
        from anaconda_project.internal.pip_api import installed as real_pip_installed
        from anaconda_project.internal.conda_api import installed as real_conda_installed

        def traced_pip_installed(*args, **kwargs):
            called.append(("pip_api.installed", args, kwargs))
            return real_pip_installed(*args, **kwargs)

        monkeypatch.setattr('anaconda_project.internal.pip_api.installed',
                            traced_pip_installed)

        def trace_conda_installed(*args, **kwargs):
            called.append(("conda_api.installed", args, kwargs))
            return real_conda_installed(*args, **kwargs)

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

        deviations = manager.find_environment_deviations(envdir, spec)

        assert [] == called

        assert deviations.missing_packages == ()
        assert deviations.missing_pip_packages == ()
        assert deviations.ok

        assert manager._timestamp_file_up_to_date(envdir, spec)

        # now modify conda-meta and check that we DO call the package managers
        time.sleep(1.1)  # be sure we are in a new second
        conda_meta_dir = os.path.join(envdir, "conda-meta")
        print("conda-meta original timestamp: %d" %
              os.path.getmtime(conda_meta_dir))
        inside_conda_meta = os.path.join(conda_meta_dir, "thing.txt")
        with codecs.open(inside_conda_meta, 'w', encoding='utf-8') as f:
            f.write(u"This file should change the mtime on conda-meta\n")
        print("file inside conda-meta %d and conda-meta itself %d" %
              (os.path.getmtime(inside_conda_meta),
               os.path.getmtime(conda_meta_dir)))
        os.remove(inside_conda_meta)

        print_timestamps("after touching conda-meta")

        assert not manager._timestamp_file_up_to_date(envdir, spec)

        deviations = manager.find_environment_deviations(envdir, spec)

        assert len(called) == 2

        assert deviations.missing_packages == ()
        assert deviations.missing_pip_packages == ()
        # deviations should not be ok (due to timestamp)
        assert not deviations.ok

        assert not manager._timestamp_file_up_to_date(envdir, spec)

        # we want to be sure we update the timestamp file even though
        # there wasn't any actual work to do
        manager.fix_environment_deviations(envdir, spec, deviations)

        print_timestamps("after fixing deviations 2")

        assert manager._timestamp_file_up_to_date(envdir, spec)

    with_directory_contents(dict(), do_test)
Ejemplo n.º 9
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)
Ejemplo n.º 10
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)