Skip to content

Commit

Permalink
Merge pull request #388 from Anaconda-Platform/nodefaults
Browse files Browse the repository at this point in the history
implicit use of "defaults" channel
  • Loading branch information
AlbertDeFusco authored Aug 9, 2022
2 parents e16ae68 + 7ade3a8 commit 6bc61a5
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 13 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

We [keep a changelog.](http://keepachangelog.com/)

## Version 0.11.1

### Bug fixes

* [PR 388](https://github.com/Anaconda-Platform/anaconda-project/pull/388) implicit use of "defaults" channel. Resolves
[387](https://github.com/Anaconda-Platform/anaconda-project/issues/387)

## Version 0.11.0

### Bug fixes
Expand Down
27 changes: 22 additions & 5 deletions anaconda_project/internal/conda_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ class CondaEnvMissingError(CondaError):
pass


def _implicit_defaults(channels):
trimmed = [c for c in channels if c != 'nodefaults']

if ('nodefaults' not in channels) and ('defaults' not in channels):
trimmed.append('defaults')

return trimmed


# this function exists so we can monkeypatch it in tests
def _get_conda_command(extra_args):
# just use whatever conda is on the path
Expand Down Expand Up @@ -167,7 +176,7 @@ def create(prefix, pkgs=None, channels=(), stdout_callback=None, stderr_callback
cmd_list.insert(1, '--override-channels')

if channels:
for channel in channels:
for channel in _implicit_defaults(channels):
cmd_list.extend(['--channel', channel])
else:
cmd_list.extend(['--channel', 'defaults'])
Expand Down Expand Up @@ -196,11 +205,15 @@ def install(prefix, pkgs=None, channels=(), stdout_callback=None, stderr_callbac
raise TypeError('must specify a list of one or more packages to install into existing environment, not %r',
pkgs)

cmd_list = ['install', '--override-channels', '--yes']
cmd_list = ['install', '--yes']
cmd_list.extend(['--prefix', prefix])

disable_override_channels = os.environ.get('ANACONDA_PROJECT_DISABLE_OVERRIDE_CHANNELS', False)
if not disable_override_channels:
cmd_list.insert(1, '--override-channels')

if channels:
for channel in channels:
for channel in _implicit_defaults(channels):
cmd_list.extend(['--channel', channel])
else:
cmd_list.extend(['--channel', 'defaults'])
Expand Down Expand Up @@ -275,10 +288,14 @@ def resolve_dependencies(pkgs, channels=(), platform=None):
# after we remove it, and then conda's mkdir would fail.
os.rmdir(prefix)

cmd_list = ['create', '--override-channels', '--yes', '--quiet', '--json', '--dry-run', '--prefix', prefix]
cmd_list = ['create', '--yes', '--quiet', '--json', '--dry-run', '--prefix', prefix]

disable_override_channels = os.environ.get('ANACONDA_PROJECT_DISABLE_OVERRIDE_CHANNELS', False)
if not disable_override_channels:
cmd_list.insert(1, '--override-channels')

if channels:
for channel in channels:
for channel in _implicit_defaults(channels):
cmd_list.extend(['--channel', channel])
else:
cmd_list.extend(['--channel', 'defaults'])
Expand Down
44 changes: 40 additions & 4 deletions anaconda_project/internal/test/test_conda_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,30 +251,66 @@ def test_conda_create_disable_override_channels(monkeypatch):
monkeypatch.setenv('ANACONDA_PROJECT_DISABLE_OVERRIDE_CHANNELS', True)

def mock_call_conda(extra_args, json_mode=False, platform=None, stdout_callback=None, stderr_callback=None):
assert ['create', '--yes', '--prefix', '/prefix', '--channel', 'foo', 'python'] == extra_args
assert ['create', '--yes', '--prefix', '/prefix', '--channel', 'foo', '--channel', 'defaults',
'python'] == extra_args

monkeypatch.setattr('anaconda_project.internal.conda_api._call_conda', mock_call_conda)
conda_api.create(prefix='/prefix', pkgs=['python'], channels=['foo'])


def test_conda_create_gets_channels(monkeypatch):
def test_conda_create_nodefaults(monkeypatch):
def mock_call_conda(extra_args, json_mode=False, platform=None, stdout_callback=None, stderr_callback=None):
assert ['create', '--override-channels', '--yes', '--prefix', '/prefix', '--channel', 'foo',
'python'] == extra_args

monkeypatch.setattr('anaconda_project.internal.conda_api._call_conda', mock_call_conda)
conda_api.create(prefix='/prefix', pkgs=['python'], channels=['foo', 'nodefaults'])


def test_conda_create_gets_channels(monkeypatch):
def mock_call_conda(extra_args, json_mode=False, platform=None, stdout_callback=None, stderr_callback=None):
assert [
'create', '--override-channels', '--yes', '--prefix', '/prefix', '--channel', 'foo', '--channel',
'defaults', 'python'
] == extra_args

monkeypatch.setattr('anaconda_project.internal.conda_api._call_conda', mock_call_conda)
conda_api.create(prefix='/prefix', pkgs=['python'], channels=['foo'])


def test_conda_create_with_defaults(monkeypatch):
def mock_call_conda(extra_args, json_mode=False, platform=None, stdout_callback=None, stderr_callback=None):
assert [
'create', '--override-channels', '--yes', '--prefix', '/prefix', '--channel', 'defaults', '--channel',
'foo', 'python'
] == extra_args

monkeypatch.setattr('anaconda_project.internal.conda_api._call_conda', mock_call_conda)
conda_api.create(prefix='/prefix', pkgs=['python'], channels=['defaults', 'foo'])


def test_conda_install_gets_channels(monkeypatch):
def mock_call_conda(extra_args, json_mode=False, platform=None, stdout_callback=None, stderr_callback=None):
assert ['install', '--override-channels', '--yes', '--prefix', '/prefix', '--channel', 'foo',
'python'] == extra_args
assert [
'install', '--override-channels', '--yes', '--prefix', '/prefix', '--channel', 'foo', '--channel',
'defaults', 'python'
] == extra_args

monkeypatch.setattr('anaconda_project.internal.conda_api._call_conda', mock_call_conda)
conda_api.install(prefix='/prefix', pkgs=['python'], channels=['foo'])


def test_conda_install_with_defaults(monkeypatch):
def mock_call_conda(extra_args, json_mode=False, platform=None, stdout_callback=None, stderr_callback=None):
assert [
'install', '--override-channels', '--yes', '--prefix', '/prefix', '--channel', 'defaults', '--channel',
'foo', 'python'
] == extra_args

monkeypatch.setattr('anaconda_project.internal.conda_api._call_conda', mock_call_conda)
conda_api.install(prefix='/prefix', pkgs=['python'], channels=['defaults', 'foo'])


def test_resolve_root_prefix():
prefix = conda_api.resolve_env_to_prefix('root')
assert prefix is not None
Expand Down
41 changes: 38 additions & 3 deletions docs/source/user-guide/tasks/work-with-packages.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,16 @@ Package Channels
*Breaking Change in version 0.11.0*. All channels you wish to search through for packages must be supplied on the CLI
or in the project YAML file. To support reproducible projects that build the same way for different users, Anaconda Project will not respect channels declared in your ``.condarc`` file.

.. note::
*Backwards compatibility fix in version 0.11.1*. The ``defaults`` channel is always appended to the list of channels
even if it is not specified in the ``channels:`` list in the project file or with the ``-c`` flag using the CLI.
If the ``defaults`` channel is specified no change is made. To avoid including the ``defaults`` channel add the
channel name ``nodefaults``.


Up till now we have not instructed Conda to install packages from specific channels, so all packages are installed from
the Conda default channels. The default channels
will be used if there is no specific channel requested with ``anaconda-project add-packages`` and
no ``channels:`` key in the ``anaconda-project.yml`` file, as in this example:
the Conda default channels. If no channels are speicified in the project file or on the command line then the
``defaults`` channel is used.

.. code-block:: yaml
Expand Down Expand Up @@ -162,6 +168,35 @@ The resulting ``anaconda-project.yml`` file is now
default: {}
If you wish to avoid using the ``defaults`` channel you must add the channel ``nodefaults``. This will instruct
Anaconda Project to not append the ``defaults`` channel automatically. The order in which ``nodefaults`` appears
does not matter.

For example to install packages only from the ``conda-forge`` channel::

anaconda-project add-packages -c conda-forge -c nodefaults fastapi

The resulting ``anaconda-project.yml`` file is now

.. code-block:: yaml
name: ExampleProject
packages:
- python=3.8
- notebook
- pandas
- pip:
- requests
channels:
- conda-forge
- nodefaults
env_specs:
default: {}
*****************
Removing packages
*****************
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ parentdir_prefix = anaconda_project-
[tool:pytest]
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
norecursedirs= .* *.egg* build bin dist conda.recipe scripts examples
norecursedirs= .* *.egg* build bin dist conda.recipe scripts examples env
addopts =
-vvrfe
--durations=10
Expand Down

0 comments on commit 6bc61a5

Please sign in to comment.