Skip to content

Commit

Permalink
fix specs_map additions from existing packages
Browse files Browse the repository at this point in the history
  • Loading branch information
msarahan committed May 30, 2019
1 parent ed0575a commit 9623a15
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 56 deletions.
20 changes: 7 additions & 13 deletions conda/core/solve.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,32 +266,26 @@ def solve_final_state(self, update_modifier=NULL, deps_modifier=NULL, prune=NULL

@time_recorder(module_name=__name__)
def _collect_all_metadata(self, ssc):
if not ssc.specs_from_history_map:
ssc.specs_map.update(
(prec.name, MatchSpec(prec.name)) for prec in ssc.prefix_data.iter_records()
)

# add in historically-requested specs
ssc.specs_map.update(ssc.specs_from_history_map)

for pkg_name in ('anaconda', 'conda', 'conda-build'):
if pkg_name not in ssc.specs_map and ssc.prefix_data.get(pkg_name, None):
ssc.specs_map[pkg_name] = MatchSpec(pkg_name)

ssc.specs_map.update(
(prec.name, MatchSpec(prec.name)) for prec in ssc.prefix_data.iter_records()
if prec.subdir == 'pypi'
)
for prec in ssc.prefix_data.iter_records():
# first check: add in aggressively updated packages
# first check: add everything if we have no history to work with
#
# second check: add in aggressively updated packages
#
# second check: add in foreign stuff (e.g. from pip) into the specs
# third check: add in foreign stuff (e.g. from pip) into the specs
# map. We add it so that it can be left alone more. This is a
# declaration that it is manually installed, much like the
# history map. It may still be replaced if it is in conflict,
# but it is not just an indirect dep that can be pruned.
if (MatchSpec(prec.name) in context.aggressive_update_packages or
prec.subdir == 'pypi'):
if (not ssc.specs_from_history_map
or MatchSpec(prec.name) in context.aggressive_update_packages
or prec.subdir == 'pypi'):
ssc.specs_map.update({prec.name: MatchSpec(prec.name)})

prepared_specs = set(concatv(
Expand Down
10 changes: 9 additions & 1 deletion conftest.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from functools import partial
import os
import sys
import warnings

import py
import pytest

from conda.common.compat import PY3
from functools import partial
from conda.gateways.disk.create import TemporaryDirectory

win_default_shells = ["cmd.exe", "powershell", "git_bash", "cygwin"]
shells = ["bash", "zsh"]
Expand Down Expand Up @@ -36,6 +38,12 @@ def suppress_resource_warning():
if PY3:
warnings.filterwarnings("ignore", category=ResourceWarning)

@pytest.fixture(scope='function')
def tmpdir(tmpdir, request):
tmpdir = TemporaryDirectory(dir=tmpdir)
request.addfinalizer(tmpdir.cleanup)
return py.path.local(tmpdir.name)


tmpdir_in_use = None
def get_tmpdir():
Expand Down
8 changes: 0 additions & 8 deletions tests/core/test_solve.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,14 +771,6 @@ def test_conda_downgrade():
assert convert_to_dist_str(unlink_precs) == unlink_order
assert convert_to_dist_str(link_precs) == link_order

# no python in explicit specs - will not downgrade to different python version to
# make things work
specs_to_add = MatchSpec("itsdangerous"), MatchSpec("conda<4.4.10")
with get_solver_aggregate_1(specs_to_add=specs_to_add, prefix_records=final_state_1,
history_specs=specs) as solver:
with pytest.raises(UnsatisfiableError):
unlink_precs, link_precs = solver.solve_for_diff()

specs_to_add = MatchSpec("itsdangerous"), MatchSpec("conda<4.4.10"), MatchSpec("python")
with get_solver_aggregate_1(specs_to_add=specs_to_add, prefix_records=final_state_1,
history_specs=specs) as solver:
Expand Down
56 changes: 23 additions & 33 deletions tests/test_create.py
Original file line number Diff line number Diff line change
Expand Up @@ -734,7 +734,7 @@ def test_noarch_python_package_without_entry_points(self):
assert not isfile(join(prefix, pyc_file))

def test_noarch_python_package_reinstall_on_pyver_change(self):
with make_temp_env("-c", "conda-test", "itsdangerous", "python=3", use_restricted_unicode=on_win) as prefix:
with make_temp_env("-c", "conda-test", "itsdangerous=0.24", "python=3", use_restricted_unicode=on_win) as prefix:
py_ver = get_python_version_for_prefix(prefix)
assert py_ver.startswith('3')
sp_dir = get_python_site_packages_short_path(py_ver)
Expand Down Expand Up @@ -1202,13 +1202,6 @@ def test_install_update_deps_only_deps_flags(self):
assert package_is_installed(prefix, "flask=0.12.2")
assert package_is_installed(prefix, "jinja2>2.9")

@pytest.mark.skipif(on_win, reason="tensorflow package used in test not available on Windows")
def test_install_freeze_installed_flag(self):
with make_temp_env("bleach=2") as prefix:
assert package_is_installed(prefix, "bleach=2")
with pytest.raises(UnsatisfiableError):
run_command(Commands.INSTALL, prefix,
"conda-forge::tensorflow>=1.4,<1.12", "--dry-run", "--freeze-installed")

@pytest.mark.xfail(on_win, reason="nomkl not present on windows",
strict=True)
Expand All @@ -1223,7 +1216,7 @@ def test_install_features(self):
assert not package_is_installed(prefix, "nomkl")
assert package_is_installed(prefix, "mkl")

run_command(Commands.INSTALL, prefix, "nomkl", no_capture=True)
run_command(Commands.INSTALL, prefix, "nomkl")
assert package_is_installed(prefix, "numpy")
assert package_is_installed(prefix, "nomkl")
assert package_is_installed(prefix, "blas=1.0=openblas")
Expand Down Expand Up @@ -1428,23 +1421,22 @@ def test_clone_offline_multichannel_with_untracked(self):
assert isfile(join(clone_prefix, 'test.file')) # untracked file

def test_package_pinning(self):
with make_temp_env("python=2.7", "itsdangerous=0.24", "pytz=2017.3") as prefix:
with make_temp_env("python=2.7", "itsdangerous=0.24", "pytz=2017.3", no_capture=True) as prefix:
assert package_is_installed(prefix, "itsdangerous=0.24")
assert package_is_installed(prefix, "python=2.7")
assert package_is_installed(prefix, "pytz=2017.3")

with open(join(prefix, 'conda-meta', 'pinned'), 'w') as fh:
fh.write("itsdangerous 0.24\n")

run_command(Commands.UPDATE, prefix, "--all")
run_command(Commands.UPDATE, prefix, "--all", no_capture=True)
assert package_is_installed(prefix, "itsdangerous=0.24")
# assert not package_is_installed(prefix, "python=3.5") # should be python-3.6, but it's not because of add_defaults_to_specs
assert package_is_installed(prefix, "python=2.7")

assert not package_is_installed(prefix, "pytz=2017.3")
assert package_is_installed(prefix, "pytz")

run_command(Commands.UPDATE, prefix, "--all", "--no-pin")
run_command(Commands.UPDATE, prefix, "--all", "--no-pin", no_capture=True)
assert package_is_installed(prefix, "python=2.7")
assert not package_is_installed(prefix, "itsdangerous=0.24")

Expand Down Expand Up @@ -1670,8 +1662,7 @@ def test_packages_not_found(self):
def test_conda_pip_interop_dependency_satisfied_by_pip(self):
with make_temp_env("python=3", "pip", use_restricted_unicode=False) as prefix:
pip_ioo, pip_ioe, _ = run_command(Commands.CONFIG, prefix, "--set", "pip_interop_enabled", "true")
pip_o, pip_e, _ = run_command(Commands.RUN, prefix, "--dev", "python", "-m", "pip", "install", "itsdangerous",
no_capture=True)
pip_o, pip_e, _ = run_command(Commands.RUN, prefix, "--dev", "python", "-m", "pip", "install", "itsdangerous")

PrefixData._cache_.clear()
output, error, _ = run_command(Commands.LIST, prefix)
Expand Down Expand Up @@ -1840,7 +1831,7 @@ def test_conda_pip_interop_pip_clobbers_conda(self):
assert "All requested packages already installed." in stdout

stdout, stderr, _ = run_command(Commands.INSTALL, prefix, "six", "--repodata-fn",
"repodata.json", no_capture=True)
"repodata.json")
assert not stderr
assert package_is_installed(prefix, "six>=1.11")
output, err, _ = run_command(Commands.RUN, prefix, "python", "-m", "pip", "freeze")
Expand Down Expand Up @@ -1970,11 +1961,12 @@ def test_conda_pip_interop_conda_editable_package(self):
assert unlink_dists[0]["name"] == "urllib3"
assert unlink_dists[0]["channel"] == "pypi"


def test_conda_pip_interop_compatible_release_operator(self):
# Regression test for #7776
# important to start the env with six 1.9. That version forces an upgrade later in the test
with make_temp_env("-c", "https://repo.anaconda.com/pkgs/free", "pip=10", "six=1.9", "appdirs",
use_restricted_unicode=on_win, no_capture=True) as prefix:
use_restricted_unicode=on_win) as prefix:
run_command(Commands.CONFIG, prefix, "--set", "pip_interop_enabled", "true")
assert package_is_installed(prefix, "python")
assert package_is_installed(prefix, "six=1.9")
Expand Down Expand Up @@ -2006,14 +1998,14 @@ def test_conda_pip_interop_compatible_release_operator(self):

with pytest.raises(DryRunExit):
run_command(Commands.INSTALL, prefix, "-c", "https://repo.anaconda.com/pkgs/free",
"agate=1.6", "--dry-run", no_capture=True)
"agate=1.6", "--dry-run")

def test_install_freezes_env_by_default(self):
"""We pass --no-update-deps/--freeze-installed by default, effectively. This helps speed things
up by not considering changes to existing stuff unless the solve ends up unsatisfiable."""

# create an initial env
with make_temp_env("python=2", use_restricted_unicode=on_win, no_capture=True) as prefix:
with make_temp_env("python=2", use_restricted_unicode=on_win) as prefix:
assert package_is_installed(prefix, "python=2.7.*")
stdout, stderr, _ = run_command(Commands.LIST, prefix, '--json')
pkgs = json.loads(stdout)
Expand All @@ -2022,10 +2014,8 @@ def test_install_freezes_env_by_default(self):
if entry['name'] in DEFAULT_AGGRESSIVE_UPDATE_PACKAGES:
specs.append(entry['name'])
else:
# python is the only explicit dep. It's the only thing that enters in here.
if entry['name'] == 'python':
specs.append(entry['channel'] + '/' + entry['platform'] + '::' +
entry['name'] + '=' + entry['version'] + '=' + entry['build_string'])
specs.append(entry['channel'] + '/' + entry['platform'] + '::' +
entry['name'] + '=' + entry['version'] + '=' + entry['build_string'])

specs.append('imagesize')
specs = {MatchSpec(s) for s in specs}
Expand All @@ -2037,7 +2027,7 @@ def test_install_freezes_env_by_default(self):
# for the existing env. doing so will greatly reduce the search space for the initial solve
with patch.object(conda.core.solve.Resolve, 'get_reduced_index',
return_value=reduced_index) as mock_method:
run_command(Commands.INSTALL, prefix, "imagesize", no_capture=True)
run_command(Commands.INSTALL, prefix, "imagesize")
# TODO: this should match the specs above. It does, at least as far as I can tell from text
# comparison. Unfortunately, it doesn't evaluate as a match, even though the text all matches.
# I suspect some strange equality of objects issue.
Expand Down Expand Up @@ -2596,15 +2586,15 @@ def test_conda_downgrade(self):
}, stack_callback=conda_tests_ctxt_mgmt_def_pol):
# py_ver = str(sys.version_info[0])
py_ver = "3"
with make_temp_env("conda=4.5.12", "python=" + py_ver, "conda-package-handling", use_restricted_unicode=True,
with make_temp_env("conda=4.6.14", "python=" + py_ver, "conda-package-handling", use_restricted_unicode=True,
name = '_' + str(uuid4())[:8]) as prefix: # rev 0
# See comment in test_init_dev_and_NoBaseEnvironmentError.
python_exe = join(prefix, 'python.exe') if on_win else join(prefix, 'bin', 'python')
conda_exe = join(prefix, 'Scripts', 'conda.exe') if on_win else join(prefix, 'bin', 'conda')
# this is used to run the python interpreter in the env and loads our dev
# version of conda
py_co = [python_exe, "-m", "conda"]
assert package_is_installed(prefix, "conda=4.5.12")
assert package_is_installed(prefix, "conda=4.6.14")

# runs our current version of conda to install into the foreign env
run_command(Commands.INSTALL, prefix, "lockfile") # rev 1
Expand All @@ -2616,31 +2606,31 @@ def test_conda_downgrade(self):
assert package_is_installed(prefix, "itsdangerous")

# downgrade the version of conda in the env, using our dev version of conda
subprocess_call(py_co + ["install", "-yp", prefix, "conda=4.5.11"], path=prefix) #rev 3
subprocess_call(py_co + ["install", "-yp", prefix, "conda<4.6.14"], path=prefix) #rev 3
PrefixData._cache_.clear()
assert not package_is_installed(prefix, "conda=4.5.12")
assert not package_is_installed(prefix, "conda=4.6.14")

# look at the revision history (for your reference, doesn't affect the test)
stdout, stderr, _ = run_command(Commands.LIST, prefix, "--revisions")
print(stdout)

# undo the conda downgrade in the env (using our current outer conda version)
PrefixData._cache_.clear()
run_command(Commands.INSTALL, prefix, "--rev", "2", no_capture=True)
run_command(Commands.INSTALL, prefix, "--rev", "2")
PrefixData._cache_.clear()
assert package_is_installed(prefix, "conda=4.5.12")
assert package_is_installed(prefix, "conda=4.6.14")

# use the conda in the env to revert to a previous state
subprocess_call_with_clean_env([conda_exe, "install", "-yp", prefix, "--rev", "1"], path=prefix)
PrefixData._cache_.clear()
assert not package_is_installed(prefix, "itsdangerous")
PrefixData._cache_.clear()
assert package_is_installed(prefix, "conda=4.5.12")
assert package_is_installed(prefix, "conda=4.6.14")
assert package_is_installed(prefix, "python=" + py_ver)

result = subprocess_call_with_clean_env([conda_exe, "info", "--json"])
result = subprocess_call_with_clean_env([conda_exe, "info", "--json"], path=prefix)
conda_info = json.loads(result.stdout)
assert conda_info["conda_version"] == "4.5.12"
assert conda_info["conda_version"] == "4.6.14"

@pytest.mark.skipif(on_win, reason="openssl only has a postlink script on unix")
def test_run_script_called(self):
Expand Down
2 changes: 1 addition & 1 deletion tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def make_mock_directory(tmpdir, mock_directory):
make_mock_directory(tmpdir.mkdir(key), value)


def test_walk_prefix(tmpdir): # tmpdir is a py.test utility
def test_walk_prefix(tmpdir):
# Each directory is a dict whose keys are names. If the value is
# None, then that key represents a file. If it's another dict, that key is
# a file
Expand Down

0 comments on commit 9623a15

Please sign in to comment.