Repository: conda/conda

Issue:
prioritize channels within multi-channels



Discussion:

Resolving patch:
diff --git a/conda/models/channel.py b/conda/models/channel.py
--- a/conda/models/channel.py
+++ b/conda/models/channel.py
@@ -4,8 +4,7 @@
 from itertools import chain
 from logging import getLogger
 
-from ..base.constants import (DEFAULTS_CHANNEL_NAME, DEFAULT_CHANNELS_UNIX, DEFAULT_CHANNELS_WIN,
-                              MAX_CHANNEL_PRIORITY, UNKNOWN_CHANNEL)
+from ..base.constants import (DEFAULTS_CHANNEL_NAME, MAX_CHANNEL_PRIORITY, UNKNOWN_CHANNEL)
 from ..base.context import context
 from ..common.compat import ensure_text_type, isiterable, iteritems, odict, with_metaclass
 from ..common.path import is_path, win_path_backout
@@ -14,10 +13,10 @@
 
 try:
     from cytoolz.functoolz import excepts
-    from cytoolz.itertoolz import concatv, topk
+    from cytoolz.itertoolz import concat, concatv, topk
 except ImportError:
     from .._vendor.toolz.functoolz import excepts  # NOQA
-    from .._vendor.toolz.itertoolz import concatv, topk  # NOQA
+    from .._vendor.toolz.itertoolz import concat, concatv, topk  # NOQA
 
 log = getLogger(__name__)
 
@@ -387,13 +386,6 @@ def canonical_name(self):
 
     def urls(self, with_credentials=False, subdirs=None):
         _channels = self._channels
-        if self.name == 'defaults':
-            platform = next((s for s in reversed(subdirs or context.subdirs) if s != 'noarch'), '')
-            if platform != context.subdir:
-                # necessary shenanigan because different platforms have different default channels
-                urls = DEFAULT_CHANNELS_WIN if 'win' in platform else DEFAULT_CHANNELS_UNIX
-                ca = context.channel_alias
-                _channels = tuple(Channel.make_simple_channel(ca, v) for v in urls)
         return list(chain.from_iterable(c.urls(with_credentials, subdirs) for c in _channels))
 
     @property
@@ -409,13 +401,15 @@ def prioritize_channels(channels, with_credentials=True, subdirs=None):
     #   urls as the key, and a tuple of canonical channel name and channel priority
     #   number as the value
     # ('https://conda.anaconda.org/conda-forge/osx-64/', ('conda-forge', 1))
+    channels = concat((Channel(cc) for cc in c._channels) if isinstance(c, MultiChannel) else (c,)
+                      for c in (Channel(c) for c in channels))
     result = odict()
-    for channel_priority, chn in enumerate(channels):
+    for priority_counter, chn in enumerate(channels):
         channel = Channel(chn)
         for url in channel.urls(with_credentials, subdirs):
             if url in result:
                 continue
-            result[url] = channel.canonical_name, min(channel_priority, MAX_CHANNEL_PRIORITY - 1)
+            result[url] = channel.canonical_name, min(priority_counter, MAX_CHANNEL_PRIORITY - 1)
     return result
 
 


Test patch:
diff --git a/tests/models/test_channel.py b/tests/models/test_channel.py
--- a/tests/models/test_channel.py
+++ b/tests/models/test_channel.py
@@ -800,7 +800,7 @@ def test_subdirs_env_var(self):
         subdirs = ('linux-highest', 'linux-64', 'noarch')
 
         def _channel_urls(channels=None):
-            for channel in channels or DEFAULT_CHANNELS_UNIX:
+            for channel in channels or DEFAULT_CHANNELS:
                 channel = Channel(channel)
                 for subdir in subdirs:
                     yield join_url(channel.base_url, subdir)
@@ -919,3 +919,47 @@ def test_channels_with_dashes(self):
             ('http://test/conda/anaconda-cluster/noarch', ('http://test/conda/anaconda-cluster', 0)),
         ))
 
+
+def test_multichannel_priority():
+    channels = ['conda-test', 'defaults', 'conda-forge']
+    subdirs = ['new-optimized-subdir', 'linux-32', 'noarch']
+    channel_priority_map = prioritize_channels(channels, with_credentials=True, subdirs=subdirs)
+    if on_win:
+        assert channel_priority_map == OrderedDict([
+            ('https://conda.anaconda.org/conda-test/new-optimized-subdir', ('conda-test', 0)),
+            ('https://conda.anaconda.org/conda-test/linux-32', ('conda-test', 0)),
+            ('https://conda.anaconda.org/conda-test/noarch', ('conda-test', 0)),
+            ('https://repo.continuum.io/pkgs/free/new-optimized-subdir', ('defaults', 1)),
+            ('https://repo.continuum.io/pkgs/free/linux-32', ('defaults', 1)),
+            ('https://repo.continuum.io/pkgs/free/noarch', ('defaults', 1)),
+            ('https://repo.continuum.io/pkgs/r/new-optimized-subdir', ('defaults', 2)),
+            ('https://repo.continuum.io/pkgs/r/linux-32', ('defaults', 2)),
+            ('https://repo.continuum.io/pkgs/r/noarch', ('defaults', 2)),
+            ('https://repo.continuum.io/pkgs/pro/new-optimized-subdir', ('defaults', 3)),
+            ('https://repo.continuum.io/pkgs/pro/linux-32', ('defaults', 3)),
+            ('https://repo.continuum.io/pkgs/pro/noarch', ('defaults', 3)),
+            ('https://repo.continuum.io/pkgs/msys2/new-optimized-subdir', ('defaults', 4)),
+            ('https://repo.continuum.io/pkgs/msys2/linux-32', ('defaults', 4)),
+            ('https://repo.continuum.io/pkgs/msys2/noarch', ('defaults', 4)),
+            ('https://conda.anaconda.org/conda-forge/new-optimized-subdir', ('conda-forge', 5)),
+            ('https://conda.anaconda.org/conda-forge/linux-32', ('conda-forge', 5)),
+            ('https://conda.anaconda.org/conda-forge/noarch', ('conda-forge', 5)),
+        ])
+    else:
+        assert channel_priority_map == OrderedDict([
+            ('https://conda.anaconda.org/conda-test/new-optimized-subdir', ('conda-test', 0)),
+            ('https://conda.anaconda.org/conda-test/linux-32', ('conda-test', 0)),
+            ('https://conda.anaconda.org/conda-test/noarch', ('conda-test', 0)),
+            ('https://repo.continuum.io/pkgs/free/new-optimized-subdir', ('defaults', 1)),
+            ('https://repo.continuum.io/pkgs/free/linux-32', ('defaults', 1)),
+            ('https://repo.continuum.io/pkgs/free/noarch', ('defaults', 1)),
+            ('https://repo.continuum.io/pkgs/r/new-optimized-subdir', ('defaults', 2)),
+            ('https://repo.continuum.io/pkgs/r/linux-32', ('defaults', 2)),
+            ('https://repo.continuum.io/pkgs/r/noarch', ('defaults', 2)),
+            ('https://repo.continuum.io/pkgs/pro/new-optimized-subdir', ('defaults', 3)),
+            ('https://repo.continuum.io/pkgs/pro/linux-32', ('defaults', 3)),
+            ('https://repo.continuum.io/pkgs/pro/noarch', ('defaults', 3)),
+            ('https://conda.anaconda.org/conda-forge/new-optimized-subdir', ('conda-forge', 4)),
+            ('https://conda.anaconda.org/conda-forge/linux-32', ('conda-forge', 4)),
+            ('https://conda.anaconda.org/conda-forge/noarch', ('conda-forge', 4)),
+        ])
diff --git a/tests/test_activate.py b/tests/test_activate.py
--- a/tests/test_activate.py
+++ b/tests/test_activate.py
@@ -191,7 +191,7 @@ def test_activate_bad_env_keeps_existing_good_env(shell):
 
 @pytest.mark.installed
 def test_activate_deactivate(shell):
-    if shell == "bash.exe" and datetime.now() < datetime(2017, 9, 1):
+    if shell == "bash.exe" and datetime.now() < datetime(2017, 10, 1):
         pytest.xfail("fix this soon")
     shell_vars = _format_vars(shell)
     with TemporaryDirectory(prefix=ENVS_PREFIX, dir=dirname(__file__)) as envs:
@@ -208,7 +208,7 @@ def test_activate_deactivate(shell):
 
 @pytest.mark.installed
 def test_activate_root_simple(shell):
-    if shell == "bash.exe" and datetime.now() < datetime(2017, 9, 1):
+    if shell == "bash.exe" and datetime.now() < datetime(2017, 10, 1):
         pytest.xfail("fix this soon")
     shell_vars = _format_vars(shell)
     with TemporaryDirectory(prefix=ENVS_PREFIX, dir=dirname(__file__)) as envs:
diff --git a/tests/test_create.py b/tests/test_create.py
--- a/tests/test_create.py
+++ b/tests/test_create.py
@@ -686,7 +686,7 @@ def test_update_deps_flag_absent(self):
             assert package_is_installed(prefix, 'itsdangerous-0.23')
             assert package_is_installed(prefix, 'flask')
 
-    @pytest.mark.xfail(datetime.now() < datetime(2017, 9, 1), reason="#5263", strict=True)
+    @pytest.mark.xfail(datetime.now() < datetime(2017, 10, 1), reason="#5263", strict=True)
     def test_update_deps_flag_present(self):
         with make_temp_env("python=2 itsdangerous=0.23") as prefix:
             assert package_is_installed(prefix, 'python-2')
@@ -887,7 +887,10 @@ def test_search_gawk_not_win(self):
     def test_search_gawk_not_win_filter(self):
         with make_temp_env() as prefix:
             stdout, stderr = run_command(
-                Commands.SEARCH, prefix, "gawk", "--platform", "win-64", "--json", use_exception_handler=True)
+                Commands.SEARCH, prefix, "gawk", "--platform", "win-64", "--json",
+                "-c", "https://repo.continuum.io/pkgs/msys2 --json",
+                use_exception_handler=True,
+            )
             json_obj = json_loads(stdout.replace("Fetching package metadata ...", "").strip())
             assert "gawk" in json_obj.keys()
             assert "m2-gawk" in json_obj.keys()
diff --git a/tests/test_export.py b/tests/test_export.py
--- a/tests/test_export.py
+++ b/tests/test_export.py
@@ -31,7 +31,7 @@ def test_basic(self):
             output2, error= run_command(Commands.LIST, prefix2, "-e")
             self.assertEqual(output, output2)
 
-    @pytest.mark.xfail(datetime.now() < datetime(2017, 9, 1), reason="Bring back `conda list --export` #3445", strict=True)
+    @pytest.mark.xfail(datetime.now() < datetime(2017, 10, 1), reason="Bring back `conda list --export` #3445", strict=True)
     def test_multi_channel_export(self):
         """
             When try to import from txt
diff --git a/tests/test_priority.py b/tests/test_priority.py
--- a/tests/test_priority.py
+++ b/tests/test_priority.py
@@ -1,5 +1,6 @@
 from unittest import TestCase
 
+from conda.common.compat import on_win
 import pytest
 
 from conda.base.context import context
@@ -10,6 +11,7 @@
 @pytest.mark.integration
 class PriorityIntegrationTests(TestCase):
 
+    @pytest.mark.skipif(on_win, reason="xz packages are different on windows than unix")
     def test_channel_order_channel_priority_true(self):
         with make_temp_env("python=3.5 pycosat==0.6.1") as prefix:
             assert_package_is_installed(prefix, 'python')
@@ -22,16 +24,16 @@ def test_channel_order_channel_priority_true(self):
             # update --all
             update_stdout, _ = run_command(Commands.UPDATE, prefix, '--all')
 
-            # pycosat should be in the SUPERSEDED list
+            # xz should be in the SUPERSEDED list
             superceded_split = update_stdout.split('SUPERSEDED')
             assert len(superceded_split) == 2
-            assert 'pycosat' in superceded_split[1]
+            assert 'xz' in superceded_split[1]
 
             # python sys.version should show conda-forge python
             python_tuple = get_conda_list_tuple(prefix, "python")
             assert python_tuple[3] == 'conda-forge'
-            # conda list should show pycosat coming from conda-forge
-            pycosat_tuple = get_conda_list_tuple(prefix, "pycosat")
+            # conda list should show xz coming from conda-forge
+            pycosat_tuple = get_conda_list_tuple(prefix, "xz")
             assert pycosat_tuple[3] == 'conda-forge'
 
     def test_channel_priority_update(self):