Repository: conda/conda

Issue:
Document that $CONDA_BLD_PATH must end with "/conda-bld" (and stop breaking stuff with minor releases)
On September 30, @kalefranz inserted a new assertion (`name == 'conda-bld'`) into `context.py` ([see here](https://github.com/conda/conda/blame/master/conda/base/context.py#L299)) causing `conda info` to fail when `CONDA_BLD_PATH` does not end with `/conda-bld`:

``` console
$ CONDA_BLD_PATH=/tmp conda info
An unexpected error has occurred.
Please consider posting the following information to the
conda GitHub issue tracker at:

    https://github.com/conda/conda/issues



`$ /home/user/conda/bin/conda info`




    Traceback (most recent call last):
      File "/home/user/conda/lib/python3.5/site-packages/conda/exceptions.py", line 479, in conda_exception_handler
        return_value = func(*args, **kwargs)
      File "/home/user/conda/lib/python3.5/site-packages/conda/cli/main.py", line 145, in _main
        exit_code = args.func(args, p)
      File "/home/user/conda/lib/python3.5/site-packages/conda/cli/main_info.py", line 225, in execute
        channels = list(prioritize_channels(channels).keys())
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 380, in prioritize_channels
        channel = Channel(chn)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 161, in __call__
        c = Channel.from_value(value)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 211, in from_value
        return Channel.from_url(value)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 196, in from_url
        return parse_conda_channel_url(url)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 132, in parse_conda_channel_url
        configured_token) = _read_channel_configuration(scheme, host, port, path)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 97, in _read_channel_configuration
        for name, channel in sorted(context.custom_channels.items(), reverse=True,
      File "/home/user/conda/lib/python3.5/site-packages/conda/_vendor/auxlib/decorators.py", line 265, in new_fget
        cache[inner_attname] = func(self)
      File "/home/user/conda/lib/python3.5/site-packages/conda/base/context.py", line 265, in custom_channels
        all_sources = self.default_channels, (self.local_build_root_channel,), custom_channels
      File "/home/user/conda/lib/python3.5/site-packages/conda/_vendor/auxlib/decorators.py", line 265, in new_fget
        cache[inner_attname] = func(self)
      File "/home/user/conda/lib/python3.5/site-packages/conda/base/context.py", line 246, in local_build_root_channel
        assert name == 'conda-bld'
    AssertionError

```

This change was not documented and led to a hard to trace failure of our test suite (we set `$CONDA_BLD_PATH` in our test suite and `conda info` is, e.g., run by `conda build`). 

Unfortunately, this was not the first time that conda/conda-build introduced subtle, but breaking changes in a patch release.

Document that $CONDA_BLD_PATH must end with "/conda-bld" (and stop breaking stuff with minor releases)
On September 30, @kalefranz inserted a new assertion (`name == 'conda-bld'`) into `context.py` ([see here](https://github.com/conda/conda/blame/master/conda/base/context.py#L299)) causing `conda info` to fail when `CONDA_BLD_PATH` does not end with `/conda-bld`:

``` console
$ CONDA_BLD_PATH=/tmp conda info
An unexpected error has occurred.
Please consider posting the following information to the
conda GitHub issue tracker at:

    https://github.com/conda/conda/issues



`$ /home/user/conda/bin/conda info`




    Traceback (most recent call last):
      File "/home/user/conda/lib/python3.5/site-packages/conda/exceptions.py", line 479, in conda_exception_handler
        return_value = func(*args, **kwargs)
      File "/home/user/conda/lib/python3.5/site-packages/conda/cli/main.py", line 145, in _main
        exit_code = args.func(args, p)
      File "/home/user/conda/lib/python3.5/site-packages/conda/cli/main_info.py", line 225, in execute
        channels = list(prioritize_channels(channels).keys())
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 380, in prioritize_channels
        channel = Channel(chn)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 161, in __call__
        c = Channel.from_value(value)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 211, in from_value
        return Channel.from_url(value)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 196, in from_url
        return parse_conda_channel_url(url)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 132, in parse_conda_channel_url
        configured_token) = _read_channel_configuration(scheme, host, port, path)
      File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 97, in _read_channel_configuration
        for name, channel in sorted(context.custom_channels.items(), reverse=True,
      File "/home/user/conda/lib/python3.5/site-packages/conda/_vendor/auxlib/decorators.py", line 265, in new_fget
        cache[inner_attname] = func(self)
      File "/home/user/conda/lib/python3.5/site-packages/conda/base/context.py", line 265, in custom_channels
        all_sources = self.default_channels, (self.local_build_root_channel,), custom_channels
      File "/home/user/conda/lib/python3.5/site-packages/conda/_vendor/auxlib/decorators.py", line 265, in new_fget
        cache[inner_attname] = func(self)
      File "/home/user/conda/lib/python3.5/site-packages/conda/base/context.py", line 246, in local_build_root_channel
        assert name == 'conda-bld'
    AssertionError

```

This change was not documented and led to a hard to trace failure of our test suite (we set `$CONDA_BLD_PATH` in our test suite and `conda info` is, e.g., run by `conda build`). 

Unfortunately, this was not the first time that conda/conda-build introduced subtle, but breaking changes in a patch release.



Discussion:
Noting the origin is related to https://github.com/conda/conda/issues/3717, and specifically https://github.com/conda/conda/issues/3717#issuecomment-255830103 and subsequent discussion.

I also thought I posted one reply to this already.  I guess the comment didn't stick.

This is definitely a bug.  Any assertion error is a bug, and we let assertion errors slip through the exception handler and provide an ugly stack trace to emphasize that point.

An assertion error is a bug. Full stop. That's why we let assertion errors have the big ugly stack trace. 

I'll work on a fix today. 

> On Oct 26, 2016, at 3:58 AM, Stefan Scherfke notifications@github.com wrote:
> 
> On September 30, @kalefranz inserted a new assertion (name == 'conda-bld') into context.py (see here) causing conda info to fail when CONDA_BLD_PATH does not end with /conda-bld:
> 
> $ CONDA_BLD_PATH=/tmp conda info
> An unexpected error has occurred.
> Please consider posting the following information to the
> conda GitHub issue tracker at:
> 
> ```
> https://github.com/conda/conda/issues
> ```
> 
> `$ /home/user/conda/bin/conda info`
> 
> ```
> Traceback (most recent call last):
>   File "/home/user/conda/lib/python3.5/site-packages/conda/exceptions.py", line 479, in conda_exception_handler
>     return_value = func(*args, **kwargs)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/cli/main.py", line 145, in _main
>     exit_code = args.func(args, p)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/cli/main_info.py", line 225, in execute
>     channels = list(prioritize_channels(channels).keys())
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 380, in prioritize_channels
>     channel = Channel(chn)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 161, in __call__
>     c = Channel.from_value(value)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 211, in from_value
>     return Channel.from_url(value)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 196, in from_url
>     return parse_conda_channel_url(url)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 132, in parse_conda_channel_url
>     configured_token) = _read_channel_configuration(scheme, host, port, path)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 97, in _read_channel_configuration
>     for name, channel in sorted(context.custom_channels.items(), reverse=True,
>   File "/home/user/conda/lib/python3.5/site-packages/conda/_vendor/auxlib/decorators.py", line 265, in new_fget
>     cache[inner_attname] = func(self)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/base/context.py", line 265, in custom_channels
>     all_sources = self.default_channels, (self.local_build_root_channel,), custom_channels
>   File "/home/user/conda/lib/python3.5/site-packages/conda/_vendor/auxlib/decorators.py", line 265, in new_fget
>     cache[inner_attname] = func(self)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/base/context.py", line 246, in local_build_root_channel
>     assert name == 'conda-bld'
> AssertionError
> ```
> 
> This change was not documented and led to a hard to trace failure of our test suite (we set $CONDA_BLD_PATH in our test suite and conda info is, e.g., run by conda build).
> 
> Unfortunately, this was not the first time that conda/conda-build introduced subtle, but breaking changes in a patch release.
> 
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub, or mute the thread.

Noting the origin is related to https://github.com/conda/conda/issues/3717, and specifically https://github.com/conda/conda/issues/3717#issuecomment-255830103 and subsequent discussion.

I also thought I posted one reply to this already.  I guess the comment didn't stick.

This is definitely a bug.  Any assertion error is a bug, and we let assertion errors slip through the exception handler and provide an ugly stack trace to emphasize that point.

An assertion error is a bug. Full stop. That's why we let assertion errors have the big ugly stack trace. 

I'll work on a fix today. 

> On Oct 26, 2016, at 3:58 AM, Stefan Scherfke notifications@github.com wrote:
> 
> On September 30, @kalefranz inserted a new assertion (name == 'conda-bld') into context.py (see here) causing conda info to fail when CONDA_BLD_PATH does not end with /conda-bld:
> 
> $ CONDA_BLD_PATH=/tmp conda info
> An unexpected error has occurred.
> Please consider posting the following information to the
> conda GitHub issue tracker at:
> 
> ```
> https://github.com/conda/conda/issues
> ```
> 
> `$ /home/user/conda/bin/conda info`
> 
> ```
> Traceback (most recent call last):
>   File "/home/user/conda/lib/python3.5/site-packages/conda/exceptions.py", line 479, in conda_exception_handler
>     return_value = func(*args, **kwargs)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/cli/main.py", line 145, in _main
>     exit_code = args.func(args, p)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/cli/main_info.py", line 225, in execute
>     channels = list(prioritize_channels(channels).keys())
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 380, in prioritize_channels
>     channel = Channel(chn)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 161, in __call__
>     c = Channel.from_value(value)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 211, in from_value
>     return Channel.from_url(value)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 196, in from_url
>     return parse_conda_channel_url(url)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 132, in parse_conda_channel_url
>     configured_token) = _read_channel_configuration(scheme, host, port, path)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/models/channel.py", line 97, in _read_channel_configuration
>     for name, channel in sorted(context.custom_channels.items(), reverse=True,
>   File "/home/user/conda/lib/python3.5/site-packages/conda/_vendor/auxlib/decorators.py", line 265, in new_fget
>     cache[inner_attname] = func(self)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/base/context.py", line 265, in custom_channels
>     all_sources = self.default_channels, (self.local_build_root_channel,), custom_channels
>   File "/home/user/conda/lib/python3.5/site-packages/conda/_vendor/auxlib/decorators.py", line 265, in new_fget
>     cache[inner_attname] = func(self)
>   File "/home/user/conda/lib/python3.5/site-packages/conda/base/context.py", line 246, in local_build_root_channel
>     assert name == 'conda-bld'
> AssertionError
> ```
> 
> This change was not documented and led to a hard to trace failure of our test suite (we set $CONDA_BLD_PATH in our test suite and conda info is, e.g., run by conda build).
> 
> Unfortunately, this was not the first time that conda/conda-build introduced subtle, but breaking changes in a patch release.
> 
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub, or mute the thread.


Resolving patch:
diff --git a/conda/base/context.py b/conda/base/context.py
--- a/conda/base/context.py
+++ b/conda/base/context.py
@@ -243,7 +243,6 @@ def local_build_root_channel(self):
         location, name = url_parts.path.rsplit('/', 1)
         if not location:
             location = '/'
-        assert name == 'conda-bld'
         return Channel(scheme=url_parts.scheme, location=location, name=name)
 
     @memoizedproperty


Test patch:
diff --git a/tests/base/test_context.py b/tests/base/test_context.py
--- a/tests/base/test_context.py
+++ b/tests/base/test_context.py
@@ -1,6 +1,8 @@
 # -*- coding: utf-8 -*-
 from __future__ import absolute_import, division, print_function, unicode_literals
 
+from os.path import basename, dirname
+
 import os
 
 import pytest
@@ -8,6 +10,7 @@
 from conda.base.context import context, reset_context
 from conda.common.compat import odict
 from conda.common.configuration import YamlRawParameter
+from conda.common.url import path_to_url, join_url
 from conda.common.yaml import yaml_load
 from conda.models.channel import Channel
 from conda.utils import on_win
@@ -81,3 +84,96 @@ def test_conda_envs_path(self):
                 os.environ['CONDA_ENVS_PATH'] = saved_envs_path
             else:
                 del os.environ['CONDA_ENVS_PATH']
+
+
+    def test_conda_bld_path_1(self):
+        saved_envs_path = os.environ.get('CONDA_BLD_PATH')
+        beginning = "C:" + os.sep if on_win else os.sep
+        path = beginning + os.sep.join(['tmp', 'conda-bld'])
+        url = path_to_url(path)
+        try:
+            os.environ['CONDA_BLD_PATH'] = path
+            reset_context()
+
+            channel = Channel('local')
+            assert channel.channel_name == "local"
+            assert channel.channel_location is None
+            assert channel.platform is None
+            assert channel.package_filename is None
+            assert channel.auth is None
+            assert channel.token is None
+            assert channel.scheme is None
+            assert channel.canonical_name == "local"
+            assert channel.url() is None
+            assert channel.urls() == [
+                join_url(url, context.subdir),
+                join_url(url, 'noarch'),
+            ]
+
+            channel = Channel(url)
+            assert channel.canonical_name == "local"
+            assert channel.platform is None
+            assert channel.package_filename is None
+            assert channel.auth is None
+            assert channel.token is None
+            assert channel.scheme == "file"
+            assert channel.urls() == [
+                join_url(url, context.subdir),
+                join_url(url, 'noarch'),
+            ]
+            assert channel.url() == join_url(url, context.subdir)
+            assert channel.channel_name == basename(path)
+            assert channel.channel_location == path_to_url(dirname(path)).replace('file://', '', 1)
+            assert channel.canonical_name == "local"
+
+        finally:
+            if saved_envs_path:
+                os.environ['CONDA_BLD_PATH'] = saved_envs_path
+            else:
+                del os.environ['CONDA_BLD_PATH']
+
+    def test_conda_bld_path_2(self):
+        saved_envs_path = os.environ.get('CONDA_BLD_PATH')
+        beginning = "C:" + os.sep if on_win else os.sep
+        path = beginning + os.sep.join(['random', 'directory'])
+        url = path_to_url(path)
+        try:
+            os.environ['CONDA_BLD_PATH'] = path
+            reset_context()
+
+            channel = Channel('local')
+            assert channel.channel_name == "local"
+            assert channel.channel_location is None
+            assert channel.platform is None
+            assert channel.package_filename is None
+            assert channel.auth is None
+            assert channel.token is None
+            assert channel.scheme is None
+            assert channel.canonical_name == "local"
+            assert channel.url() is None
+            assert channel.urls() == [
+                join_url(url, context.subdir),
+                join_url(url, 'noarch'),
+            ]
+
+            channel = Channel(url)
+            assert channel.canonical_name == "local"
+            assert channel.platform is None
+            assert channel.package_filename is None
+            assert channel.auth is None
+            assert channel.token is None
+            assert channel.scheme == "file"
+            assert channel.urls() == [
+                join_url(url, context.subdir),
+                join_url(url, 'noarch'),
+            ]
+            assert channel.url() == join_url(url, context.subdir)
+            assert channel.channel_name == basename(path)
+            assert channel.channel_location == path_to_url(dirname(path)).replace('file://', '', 1)
+            assert channel.canonical_name == "local"
+
+        finally:
+            if saved_envs_path:
+                os.environ['CONDA_BLD_PATH'] = saved_envs_path
+            else:
+                del os.environ['CONDA_BLD_PATH']