Repository: conda/conda

Issue:
conda default packages do not work with conda env
<!--
Hi!  Read this; it's important.

This is an issue tracker for conda -- the package manager.  File feature requests
for conda here, as well as bug reports about something conda has messed up.

If your issue is a bug report for:
  * a specific conda package from Anaconda ('defaults' channel):
      ==> file at https://github.com/ContinuumIO/anaconda-issues
  * a specific conda package from conda-forge:
      ==> file at the corresponding feedstock under https://github.com/conda-forge
  * repo.anaconda.com access and service:
      ==> file at https://github.com/ContinuumIO/anaconda-issues
  * anaconda.org access and service:
      ==> file at https://anaconda.org/contact/report
  * commands under 'conda build':
      ==> file at https://github.com/conda/conda-build
  * commands under 'conda env':
      ==> please file it here!
  * all other conda commands that start with 'conda':
      ==> please file it here!

If you continue on,

   **please include all requested information below.**

If a maintainer determines the information is required to understand 
your issue, and if it is not provided, your issue may be
closed automatically.

-->

## Current Behavior
<!-- What actually happens?
     If you want to include console output, please use "Steps to Reproduce" below. -->

The expected behavior for default packages (set in my `.condarc` file) works when I create an environment like `conda create -n testenv <name of package>` but it doesn't work when I create an environment using `conda env create -f <environment file>`.

### Steps to Reproduce
<!-- If the current behavior is a bug, please provide specific, minimal steps to independently reproduce.
     Include the exact conda commands that reproduce the issue and their output between the ticks below. -->
.condarc file
```
channels:
  - conda-forge
  - bioconda
  - defaults

create_default_packages:
  - python-language-server
  - r-languageserver
```
environment.yml
```
name: test-env-file
dependencies:
  - pandas
```
commands
```
conda create -n test-env pandas
conda activate test-env
conda list # shows python-language-server and r-languageserver
conda deactivate
conda env create -f environment.yml
conda activate test-env-file
conda list # does not show python-language-server and r-languageserver
```


## Expected Behavior
<!-- What do you think should happen? -->


## Environment Information
<details open><summary><code>`conda info`</code></summary><p>
<!-- between the ticks below, paste the output of 'conda info' -->

```
     active environment : None
            shell level : 0
       user config file : /Users/robinsonwi/.condarc
 populated config files : /Users/robinsonwi/.condarc
          conda version : 4.8.1
    conda-build version : not installed
         python version : 3.7.3.final.0
       virtual packages : __osx=10.14.6
       base environment : //miniconda3  (writable)
           channel URLs : https://conda.anaconda.org/conda-forge/osx-64
                          https://conda.anaconda.org/conda-forge/noarch
                          https://conda.anaconda.org/bioconda/osx-64
                          https://conda.anaconda.org/bioconda/noarch
                          https://repo.anaconda.com/pkgs/main/osx-64
                          https://repo.anaconda.com/pkgs/main/noarch
                          https://repo.anaconda.com/pkgs/r/osx-64
                          https://repo.anaconda.com/pkgs/r/noarch
          package cache : //miniconda3/pkgs
                          /Users/robinsonwi/.conda/pkgs
       envs directories : //miniconda3/envs
                          /Users/robinsonwi/.conda/envs
               platform : osx-64
             user-agent : conda/4.8.1 requests/2.22.0 CPython/3.7.3 Darwin/18.7.0 OSX/10.14.6
                UID:GID : 185593938:1360859114
             netrc file : None
           offline mode : False
```
</p></details>


<details open><summary><code>`conda config --show-sources`</code></summary><p>
<!-- between the ticks below, paste the output of 'conda config --show-sources' -->

```
==> /Users/robinsonwi/.condarc <==
create_default_packages:
  - python-language-server
  - r-languageserver
channels:
  - conda-forge
  - bioconda
  - defaults
```
</p></details>


<details><summary><code>`conda list --show-channel-urls`</code></summary><p>
<!-- between the ticks below, paste the output of 'conda list --show-channel-urls' -->

```
# packages in environment at //miniconda3:
#
# Name                    Version                   Build  Channel
asn1crypto                1.2.0                    py37_0    defaults
blas                      1.0                         mkl    defaults
ca-certificates           2019.11.27                    0    defaults
certifi                   2019.11.28               py37_0    defaults
cffi                      1.13.2           py37hb5b8e2f_0    defaults
chardet                   3.0.4                 py37_1003    defaults
conda                     4.8.1                    py37_0    defaults
conda-package-handling    1.6.0            py37h1de35cc_0    defaults
cryptography              2.8              py37ha12b0ac_0    defaults
idna                      2.8                      py37_0    defaults
intel-openmp              2019.4                      233    defaults
libcxx                    4.0.1                hcfea43d_1    defaults
libcxxabi                 4.0.1                hcfea43d_1    defaults
libedit                   3.1.20181209         hb402a30_0    defaults
libffi                    3.2.1                h475c297_4    defaults
libgfortran               3.0.1                h93005f0_2    defaults
mkl                       2019.4                      233    defaults
mkl-service               2.3.0            py37hfbe908c_0    defaults
mkl_fft                   1.0.15           py37h5e564d8_0    defaults
mkl_random                1.1.0            py37ha771720_0    defaults
ncurses                   6.1                  h0a44026_1    defaults
numpy                     1.17.4           py37h890c691_0    defaults
numpy-base                1.17.4           py37h6575580_0    defaults
openssl                   1.1.1d               h1de35cc_3    defaults
pandas                    0.25.2           py37h0a44026_0    defaults
pycosat                   0.6.3            py37h1de35cc_0    defaults
pycparser                 2.19                     py37_0    defaults
pyopenssl                 19.1.0                   py37_0    defaults
pysocks                   1.7.1                    py37_0    defaults
python                    3.7.3                h359304d_0    defaults
python-dateutil           2.8.1                      py_0    defaults
pytz                      2019.3                     py_0    defaults
readline                  7.0                  h1de35cc_5    defaults
requests                  2.22.0                   py37_1    defaults
ruamel_yaml               0.15.87          py37h1de35cc_0    defaults
setuptools                44.0.0                   py37_0    defaults
six                       1.13.0                   py37_0    defaults
sqlite                    3.30.1               ha441bb4_0    defaults
tk                        8.6.8                ha441bb4_0    defaults
tqdm                      4.40.2                     py_0    defaults
urllib3                   1.25.7                   py37_0    defaults
xz                        5.2.4                h1de35cc_4    defaults
yaml                      0.1.7                hc338f04_2    defaults
zlib                      1.2.11               h1de35cc_3    defaults
```
</p></details>



Discussion:
I was also surprised by this behavior. Is there a plan to implement or fix this @soapy1 ?
shouldn't that be the default behavior though?
If I have a yaml defining my environment, I would want it to be recreated as specified in the yaml, and not depend on other settings hidden in a .condarc
Yes, agreed, the expectation that the environment created from an environment file should be the same everywhere is a sane default behaviour.

Nevertheless there are situations, where having an extra argument for `env create` that would automatically extend the listed dependencies by what is in the `create_default_packages` setting would be very helpful. For example to enforce adding an `ipython`, `python-languageserver` dependency to environments. 

I suggest to call this argument `--with-default-packages`.

I just got bitten by this, so I'll add another use case that makes this really desirable. When running on an air-gapped network on Windows machines, and using the Windows Certificate Store, the `python-certifi-win32` package must be installed in every environment in order for things wanting to verify SSL certs to use the Windows Certificate Store to be able to do so. Having the ability to automatically enforce that package gets added every time is pretty important when the conda channel server requires SSL verification.
@chenghlee  If no one started working on this, I'd be happy to 

Resolving patch:
diff --git a/conda/cli/conda_argparse.py b/conda/cli/conda_argparse.py
--- a/conda/cli/conda_argparse.py
+++ b/conda/cli/conda_argparse.py
@@ -536,11 +536,7 @@ def configure_parser_create(sub_parsers):
         metavar='ENV',
     )
     solver_mode_options, package_install_options = add_parser_create_install_update(p)
-    solver_mode_options.add_argument(
-        "--no-default-packages",
-        action="store_true",
-        help='Ignore create_default_packages in the .condarc file.',
-    )
+    add_parser_default_packages(solver_mode_options)
     p.add_argument(
         '-m', "--mkdir",
         action="store_true",
@@ -1669,3 +1665,10 @@ def add_parser_known(p):
         dest='unknown',
         help=SUPPRESS,
     )
+
+def add_parser_default_packages(p):
+    p.add_argument(
+        "--no-default-packages",
+        action="store_true",
+        help='Ignore create_default_packages in the .condarc file.',
+    )
diff --git a/conda_env/cli/main_create.py b/conda_env/cli/main_create.py
--- a/conda_env/cli/main_create.py
+++ b/conda_env/cli/main_create.py
@@ -10,7 +10,8 @@
 
 from conda._vendor.auxlib.path import expand
 from conda.cli import install as cli_install
-from conda.cli.conda_argparse import add_parser_json, add_parser_prefix, add_parser_networking
+from conda.cli.conda_argparse import add_parser_default_packages, add_parser_json, \
+    add_parser_prefix, add_parser_networking
 from conda.core.prefix_data import PrefixData
 from conda.gateways.connection.session import CONDA_SESSION_SCHEMES
 from conda.gateways.disk.delete import rm_rf
@@ -69,6 +70,7 @@ def configure_parser(sub_parsers):
         action='store_true',
         default=False,
     )
+    add_parser_default_packages(p)
     add_parser_json(p)
     p.set_defaults(func='.main_create.execute')
 
@@ -106,6 +108,13 @@ def execute(args, parser):
     # channel_urls = args.channel or ()
 
     result = {"conda": None, "pip": None}
+
+    args_packages = context.create_default_packages if not args.no_default_packages else []
+    if args_packages:
+        installer_type = "conda"
+        installer = get_installer(installer_type)
+        result[installer_type] = installer.install(prefix, args_packages, args, env)
+
     if len(env.dependencies.items()) == 0:
         installer_type = "conda"
         pkg_specs = []


Test patch:
diff --git a/tests/conda_env/support/env_with_dependencies.yml b/tests/conda_env/support/env_with_dependencies.yml
new file mode 100644
--- /dev/null
+++ b/tests/conda_env/support/env_with_dependencies.yml
@@ -0,0 +1,7 @@
+channels:
+  - conda-forge
+  - defaults
+
+dependencies:
+  - python=2
+  - pytz
\ No newline at end of file
diff --git a/tests/conda_env/test_create.py b/tests/conda_env/test_create.py
--- a/tests/conda_env/test_create.py
+++ b/tests/conda_env/test_create.py
@@ -3,6 +3,7 @@
 
 from logging import Handler, getLogger
 from os.path import exists, join
+from shutil import rmtree
 from unittest import TestCase
 from uuid import uuid4
 
@@ -10,12 +11,15 @@
 
 from conda.base.context import conda_tests_ctxt_mgmt_def_pol
 from conda.common.io import dashlist, env_var, env_vars
+from conda.common.serialize import yaml_round_trip_load
 from conda.core.prefix_data import PrefixData
 from conda.install import on_win
 from conda.models.enums import PackageType
 from conda.models.match_spec import MatchSpec
 from . import support_file
 from .utils import make_temp_envs_dir, Commands, run_command
+from ..test_create import run_command as run_conda_command, \
+    Commands as CondaCommands
 
 PYTHON_BINARY = 'python.exe' if on_win else 'bin/python'
 from tests.test_utils import is_prefix_activated_PATHwise
@@ -134,3 +138,47 @@ def test_create_empty_env(self):
                 run_command(Commands.CREATE, env_name, support_file('empty_env.yml'))
                 assert exists(prefix)
 
+
+    def test_create_env_default_packages(self):
+        with make_temp_envs_dir() as envs_dir:
+            with env_var('CONDA_ENVS_DIRS', envs_dir, stack_callback=conda_tests_ctxt_mgmt_def_pol):
+                # set packages
+                run_conda_command(CondaCommands.CONFIG, envs_dir, "--add", "create_default_packages", "pip")
+                run_conda_command(CondaCommands.CONFIG, envs_dir, "--add", "create_default_packages", "flask")
+                stdout, stderr, _ = run_conda_command(CondaCommands.CONFIG, envs_dir, "--show")
+                yml_obj = yaml_round_trip_load(stdout)
+                assert yml_obj['create_default_packages'] == ['flask', 'pip']
+
+                assert not package_is_installed(envs_dir, 'python=2')
+                assert not package_is_installed(envs_dir, 'pytz')
+                assert not package_is_installed(envs_dir, 'flask')
+
+                env_name = str(uuid4())[:8]
+                prefix = join(envs_dir, env_name)
+                run_command(Commands.CREATE, env_name, support_file('env_with_dependencies.yml'))
+                assert exists(prefix)
+                assert package_is_installed(prefix, 'python=2')
+                assert package_is_installed(prefix, 'pytz')
+                assert package_is_installed(prefix, 'flask')
+
+    def test_create_env_no_default_packages(self):
+        with make_temp_envs_dir() as envs_dir:
+            with env_var('CONDA_ENVS_DIRS', envs_dir, stack_callback=conda_tests_ctxt_mgmt_def_pol):
+                # set packages
+                run_conda_command(CondaCommands.CONFIG, envs_dir, "--add", "create_default_packages", "pip")
+                run_conda_command(CondaCommands.CONFIG, envs_dir, "--add", "create_default_packages", "flask")
+                stdout, stderr, _ = run_conda_command(CondaCommands.CONFIG, envs_dir, "--show")
+                yml_obj = yaml_round_trip_load(stdout)
+                assert yml_obj['create_default_packages'] == ['flask', 'pip']
+
+                assert not package_is_installed(envs_dir, 'python=2')
+                assert not package_is_installed(envs_dir, 'pytz')
+                assert not package_is_installed(envs_dir, 'flask')
+
+                env_name = str(uuid4())[:8]
+                prefix = join(envs_dir, env_name)
+                run_command(Commands.CREATE, env_name, support_file('env_with_dependencies.yml'), "--no-default-packages")
+                assert exists(prefix)
+                assert package_is_installed(prefix, 'python=2')
+                assert package_is_installed(prefix, 'pytz')
+                assert not package_is_installed(prefix, 'flask')