Repository: conda/conda

Issue:
Lower version platform pkgs preferred to newer noarch. 4.3.17 regression
With `conda 4.3.17` the solver prefers ~~Windows~~ platform-specific packages over `noarch` even if the `noarch` version has a higher version number. This ~~is not observable on a Linux and also~~ works fine ~~on Windows~~ for `conda 4.3.16`.
See the following:
```batch

(C:\home\maba\conda\miniconda-win64) C:\home\maba\conda\miniconda-win64\maba>conda create --dry-run -n tmp -c genomeinformatics amplikyzer2
Fetching package metadata ...............
Solving package specifications: .

Package plan for installation in environment C:\home\maba\conda\miniconda-win64\envs\tmp:

The following NEW packages will be INSTALLED:

    amplikyzer2:     1.2.0-0            genomeinformatics
    cycler:          0.10.0-py36_0
    icu:             57.1-vc14_0                          [vc14]
    jpeg:            9b-vc14_0                            [vc14]
    libpng:          1.6.27-vc14_0                        [vc14]
    llvmlite:        0.17.0-py36_0
    matplotlib:      2.0.0-np112py36_0
    mkl:             2017.0.1-0
    numba:           0.32.0-np112py36_0
    numpy:           1.12.1-py36_0
    openssl:         1.0.2k-vc14_0                        [vc14]
    pip:             9.0.1-py36_1
    pyparsing:       2.1.4-py36_0
    pyqt:            5.6.0-py36_2
    python:          3.6.1-0
    python-dateutil: 2.6.0-py36_0
    pytz:            2017.2-py36_0
    qt:              5.6.2-vc14_3                         [vc14]
    setuptools:      27.2.0-py36_1
    sip:             4.18-py36_0
    six:             1.10.0-py36_0
    tk:              8.5.18-vc14_0                        [vc14]
    vs2015_runtime:  14.0.25123-0
    wheel:           0.29.0-py36_0
    zlib:            1.2.8-vc14_3                         [vc14]


(C:\home\maba\conda\miniconda-win64) C:\home\maba\conda\miniconda-win64\maba>conda --version
conda 4.3.16
```
`amplikyzer2 1.2.0` is the most recent version and uses `noarch: python`.
After updating to `conda 4.3.17`, an outdated version is selected:
```batch
(C:\home\maba\conda\miniconda-win64) C:\home\maba\conda\miniconda-win64\maba>conda update conda
Fetching package metadata ...............
Solving package specifications: .

Package plan for installation in environment C:\home\maba\conda\miniconda-win64:

The following packages will be UPDATED:

    conda: 4.3.16-py35_0 --> 4.3.17-py35_0

Proceed ([y]/n)?

conda-4.3.17-p 100% |###############################| Time: 0:00:00   2.42 MB/s

(C:\home\maba\conda\miniconda-win64) C:\home\maba\conda\miniconda-win64\maba>conda create --dry-run -n tmp -c genomeinformatics amplikyzer2
Fetching package metadata ...............
Solving package specifications: .

Package plan for installation in environment C:\home\maba\conda\miniconda-win64\envs\tmp:

The following NEW packages will be INSTALLED:

    amplikyzer2:     1.1.2-0            genomeinformatics
    cycler:          0.10.0-py36_0
    icu:             57.1-vc14_0                          [vc14]
    jpeg:            9b-vc14_0                            [vc14]
    libpng:          1.6.27-vc14_0                        [vc14]
    llvmlite:        0.17.0-py36_0
    matplotlib:      2.0.0-np112py36_0
    mkl:             2017.0.1-0
    numba:           0.32.0-np112py36_0
    numpy:           1.12.1-py36_0
    openssl:         1.0.2k-vc14_0                        [vc14]
    pip:             9.0.1-py36_1
    pyparsing:       2.1.4-py36_0
    pyqt:            5.6.0-py36_2
    python:          3.6.1-0
    python-dateutil: 2.6.0-py36_0
    pytz:            2017.2-py36_0
    qt:              5.6.2-vc14_3                         [vc14]
    setuptools:      27.2.0-py36_1
    sip:             4.18-py36_0
    six:             1.10.0-py36_0
    tk:              8.5.18-vc14_0                        [vc14]
    vs2015_runtime:  14.0.25123-0
    wheel:           0.29.0-py36_0
    zlib:            1.2.8-vc14_3                         [vc14]

```
`amplikyzer2 1.1.2-0` is the last platform-specific Windows build, but of course is superseded by `1.2.0`.

The same also happens for `conda install amplikyzer2` and `conda update amplikyzer2`. If the version is explicitly given, e.g., `conda install amplikyzer2=1.2.0`, the newest version is correctly installed. Running `conda update amplikyzer2` afterwards will try to downgrade to `1.1.2-0` again.


Discussion:
Scratch that about being Windows-specific -- I accidentally didn't really update to `conda 4.3.17` on Linux.
Now with properly updated to `4.3.17` the same behavior is shown on Linux too.
I see #5030 introduced this. As I understand this, after #5030 the platform-specific and `noarch` directory in effect get treated as separate channels with `noarch` always having a lower priority.
Thus adding `--no-channel-priority` shows the expected result:
```bash
$ conda --version
conda 4.3.17
```
```bash
$ conda create --dry-run -n tmp -c genomeinformatics amplikyzer2
Fetching package metadata ...........
Solving package specifications: .

Package plan for installation in environment /home/maba/miniconda3/envs/tmp:

The following NEW packages will be INSTALLED:

    amplikyzer2:      1.1.5-py36_8       genomeinformatics
...
```
```bash
$ conda create --dry-run -n tmp -c genomeinformatics amplikyzer2 --no-channel-priority
Fetching package metadata ...........
Solving package specifications: .

Package plan for installation in environment /home/maba/miniconda3/envs/tmp:

The following NEW packages will be INSTALLED:

    amplikyzer2:      1.2.0-0            genomeinformatics
...
```
I strongly feel this is undesirable behavior and that *inside a single channel*, the package version must have the highest priority. Only on a version number tie should the platform-dependent build be preferred.

Resolving patch:
diff --git a/conda/models/channel.py b/conda/models/channel.py
--- a/conda/models/channel.py
+++ b/conda/models/channel.py
@@ -410,14 +410,12 @@ def prioritize_channels(channels, with_credentials=True, subdirs=None):
     #   number as the value
     # ('https://conda.anaconda.org/conda-forge/osx-64/', ('conda-forge', 1))
     result = odict()
-    q = -1  # channel priority counter
-    for chn in channels:
+    for channel_priority, chn in enumerate(channels):
         channel = Channel(chn)
         for url in channel.urls(with_credentials, subdirs):
             if url in result:
                 continue
-            q += 1
-            result[url] = channel.canonical_name, min(q, MAX_CHANNEL_PRIORITY - 1)
+            result[url] = channel.canonical_name, min(channel_priority, 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
@@ -789,11 +789,11 @@ def test_env_var_file_urls(self):
             prioritized = prioritize_channels(new_context.channels)
             assert prioritized == OrderedDict((
                 ("file://network_share/shared_folder/path/conda/%s" % context.subdir, ("file://network_share/shared_folder/path/conda", 0)),
-                ("file://network_share/shared_folder/path/conda/noarch", ("file://network_share/shared_folder/path/conda", 1)),
-                ("https://some.url/ch_name/%s" % context.subdir, ("https://some.url/ch_name", 2)),
-                ("https://some.url/ch_name/noarch", ("https://some.url/ch_name", 3)),
-                ("file:///some/place/on/my/machine/%s" % context.subdir, ("file:///some/place/on/my/machine", 4)),
-                ("file:///some/place/on/my/machine/noarch", ("file:///some/place/on/my/machine", 5)),
+                ("file://network_share/shared_folder/path/conda/noarch", ("file://network_share/shared_folder/path/conda", 0)),
+                ("https://some.url/ch_name/%s" % context.subdir, ("https://some.url/ch_name", 1)),
+                ("https://some.url/ch_name/noarch", ("https://some.url/ch_name", 1)),
+                ("file:///some/place/on/my/machine/%s" % context.subdir, ("file:///some/place/on/my/machine", 2)),
+                ("file:///some/place/on/my/machine/noarch", ("file:///some/place/on/my/machine", 2)),
             ))
 
     def test_subdirs(self):
@@ -816,19 +816,19 @@ def _channel_urls(channels=None):
             prioritized = prioritize_channels(channels)
             assert prioritized == OrderedDict((
                 ("https://conda.anaconda.org/bioconda/linux-highest", ("bioconda", 0)),
-                ("https://conda.anaconda.org/bioconda/linux-64", ("bioconda", 1)),
-                ("https://conda.anaconda.org/bioconda/noarch", ("bioconda", 2)),
-                ("https://conda.anaconda.org/conda-forge/linux-highest", ("conda-forge", 3)),
-                ("https://conda.anaconda.org/conda-forge/linux-64", ("conda-forge", 4)),
-                ("https://conda.anaconda.org/conda-forge/noarch", ("conda-forge", 5)),
+                ("https://conda.anaconda.org/bioconda/linux-64", ("bioconda", 0)),
+                ("https://conda.anaconda.org/bioconda/noarch", ("bioconda", 0)),
+                ("https://conda.anaconda.org/conda-forge/linux-highest", ("conda-forge", 1)),
+                ("https://conda.anaconda.org/conda-forge/linux-64", ("conda-forge", 1)),
+                ("https://conda.anaconda.org/conda-forge/noarch", ("conda-forge", 1)),
             ))
 
             prioritized = prioritize_channels(channels, subdirs=('linux-again', 'noarch'))
             assert prioritized == OrderedDict((
                 ("https://conda.anaconda.org/bioconda/linux-again", ("bioconda", 0)),
-                ("https://conda.anaconda.org/bioconda/noarch", ("bioconda", 1)),
-                ("https://conda.anaconda.org/conda-forge/linux-again", ("conda-forge", 2)),
-                ("https://conda.anaconda.org/conda-forge/noarch", ("conda-forge", 3)),
+                ("https://conda.anaconda.org/bioconda/noarch", ("bioconda", 0)),
+                ("https://conda.anaconda.org/conda-forge/linux-again", ("conda-forge", 1)),
+                ("https://conda.anaconda.org/conda-forge/noarch", ("conda-forge", 1)),
             ))