Repository: conda/conda

Issue:
refactor conda/cli/activate.py to help menuinst
Let menuinst not have to work about shellsdict in conda 4.3.



Discussion:

Resolving patch:
diff --git a/conda/cli/activate.py b/conda/cli/activate.py
--- a/conda/cli/activate.py
+++ b/conda/cli/activate.py
@@ -1,14 +1,15 @@
-from __future__ import print_function, division, absolute_import, unicode_literals
+from __future__ import absolute_import, division, print_function, unicode_literals
 
 import errno
 import os
-import re
+from os.path import abspath, isdir
+import re as regex
 import sys
-from os.path import isdir, abspath
 
-from ..common.compat import text_type, on_win
-from ..exceptions import (CondaSystemExit, ArgumentError, CondaValueError, CondaEnvironmentError,
-                          TooManyArgumentsError, TooFewArgumentsError)
+from ..common.compat import on_win, text_type
+from ..exceptions import (ArgumentError, CondaEnvironmentError, CondaSystemExit, CondaValueError,
+                          TooFewArgumentsError, TooManyArgumentsError)
+from ..utils import shells
 
 
 def help(command, shell):
@@ -44,12 +45,13 @@ def help(command, shell):
         raise CondaSystemExit("No help available for command %s" % sys.argv[1])
 
 
-def prefix_from_arg(arg, shelldict):
+def prefix_from_arg(arg, shell):
+    shelldict = shells[shell] if shell else {}
     from ..base.context import context, locate_prefix_by_name
     'Returns a platform-native path'
     # MSYS2 converts Unix paths to Windows paths with unix seps
     # so we must check for the drive identifier too.
-    if shelldict['sep'] in arg and not re.match('[a-zA-Z]:', arg):
+    if shelldict['sep'] in arg and not regex.match('[a-zA-Z]:', arg):
         # strip is removing " marks, not \ - look carefully
         native_path = shelldict['path_from'](arg)
         if isdir(abspath(native_path.strip("\""))):
@@ -61,23 +63,23 @@ def prefix_from_arg(arg, shelldict):
     return prefix
 
 
-def binpath_from_arg(arg, shelldict):
-    # prefix comes back as platform-native path
-    prefix = prefix_from_arg(arg, shelldict=shelldict)
+def _get_prefix_paths(prefix):
     if on_win:
-        paths = [
-            prefix.rstrip("\\"),
-            os.path.join(prefix, 'Library', 'mingw-w64', 'bin'),
-            os.path.join(prefix, 'Library', 'usr', 'bin'),
-            os.path.join(prefix, 'Library', 'bin'),
-            os.path.join(prefix, 'Scripts'),
-                ]
+        yield prefix.rstrip("\\")
+        yield os.path.join(prefix, 'Library', 'mingw-w64', 'bin')
+        yield os.path.join(prefix, 'Library', 'usr', 'bin')
+        yield os.path.join(prefix, 'Library', 'bin')
+        yield os.path.join(prefix, 'Scripts')
     else:
-        paths = [
-            os.path.join(prefix, 'bin'),
-                ]
+        yield os.path.join(prefix, 'bin')
+
+
+def binpath_from_arg(arg, shell):
+    shelldict = shells[shell] if shell else {}
+    # prefix comes back as platform-native path
+    prefix = prefix_from_arg(arg, shell)
     # convert paths to shell-native paths
-    return [shelldict['path_to'](path) for path in paths]
+    return [shelldict['path_to'](path) for path in _get_prefix_paths(prefix)]
 
 
 def pathlist_to_str(paths, escape_backslashes=True):
@@ -88,25 +90,15 @@ def pathlist_to_str(paths, escape_backslashes=True):
     path = ' and '.join(paths)
     if on_win and escape_backslashes:
         # escape for printing to console - ends up as single \
-        path = re.sub(r'(?<!\\)\\(?!\\)', r'\\\\', path)
+        path = regex.sub(r'(?<!\\)\\(?!\\)', r'\\\\', path)
     else:
         path = path.replace("\\\\", "\\")
     return path
 
 
-def get_activate_path(shelldict):
-    arg_num = len(sys.argv)
-    if arg_num != 4:
-        num_expected = 2
-        if arg_num < 4:
-            raise TooFewArgumentsError(num_expected, arg_num - num_expected,
-                                       "..activate expected exactly two arguments:\
-                                        shell and env name")
-        if arg_num > 4:
-            raise TooManyArgumentsError(num_expected, arg_num - num_expected, sys.argv[2:],
-                                        "..activate expected exactly two arguments:\
-                                         shell and env name")
-    binpath = binpath_from_arg(sys.argv[3], shelldict=shelldict)
+def get_activate_path(prefix, shell):
+    shelldict = shells[shell] if shell else {}
+    binpath = binpath_from_arg(prefix, shell)
 
     # prepend our new entries onto the existing path and make sure that the separator is native
     path = shelldict['pathsep'].join(binpath)
@@ -115,32 +107,42 @@ def get_activate_path(shelldict):
 
 def main():
     from ..base.constants import ROOT_ENV_NAME
-    from ..utils import shells
     if '-h' in sys.argv or '--help' in sys.argv:
         # all execution paths sys.exit at end.
         help(sys.argv[1], sys.argv[2])
 
     if len(sys.argv) > 2:
         shell = sys.argv[2]
-        shelldict = shells[shell]
     else:
-        shelldict = {}
+        shell = ''
+
+    if regex.match('^..(?:de|)activate$', sys.argv[1]):
+        arg_num = len(sys.argv)
+        if arg_num != 4:
+            num_expected = 2
+            if arg_num < 4:
+                raise TooFewArgumentsError(num_expected, arg_num - num_expected,
+                                           "{} expected exactly two arguments:\
+                                            shell and env name".format(sys.argv[1]))
+            if arg_num > 4:
+                raise TooManyArgumentsError(num_expected, arg_num - num_expected, sys.argv[2:],
+                                            "{} expected exactly two arguments:\
+                                             shell and env name".format(sys.argv[1]))
 
     if sys.argv[1] == '..activate':
-        print(get_activate_path(shelldict))
+        print(get_activate_path(sys.argv[3], shell))
         sys.exit(0)
 
     elif sys.argv[1] == '..deactivate.path':
-        import re
-        activation_path = get_activate_path(shelldict)
+        activation_path = get_activate_path(sys.argv[3], shell)
 
         if os.getenv('_CONDA_HOLD'):
-            new_path = re.sub(r'%s(:?)' % re.escape(activation_path),
-                              r'CONDA_PATH_PLACEHOLDER\1',
-                              os.environ[str('PATH')], 1)
+            new_path = regex.sub(r'%s(:?)' % regex.escape(activation_path),
+                                 r'CONDA_PATH_PLACEHOLDER\1',
+                                 os.environ[str('PATH')], 1)
         else:
-            new_path = re.sub(r'%s(:?)' % re.escape(activation_path), r'',
-                              os.environ[str('PATH')], 1)
+            new_path = regex.sub(r'%s(:?)' % regex.escape(activation_path), r'',
+                                 os.environ[str('PATH')], 1)
 
         print(new_path)
         sys.exit(0)
@@ -157,7 +159,7 @@ def main():
 
         # this should throw an error and exit if the env or path can't be found.
         try:
-            prefix = prefix_from_arg(sys.argv[3], shelldict=shelldict)
+            prefix = prefix_from_arg(sys.argv[3], shell)
         except ValueError as e:
             raise CondaValueError(text_type(e))
 


Test patch:
diff --git a/tests/test_activate.py b/tests/test_activate.py
--- a/tests/test_activate.py
+++ b/tests/test_activate.py
@@ -1,26 +1,24 @@
 # -*- coding: utf-8 -*-
-from __future__ import print_function, absolute_import, unicode_literals
-
-import subprocess
-import tempfile
+from __future__ import absolute_import, print_function, unicode_literals
 
+from datetime import datetime
 import os
 from os.path import dirname
 import stat
+import subprocess
 import sys
+import tempfile
 
-from datetime import datetime
 import pytest
 
-from conda.compat import TemporaryDirectory, PY2
-from conda.config import root_dir, platform
+from conda.base.context import context
+from conda.cli.activate import _get_prefix_paths, binpath_from_arg
+from conda.compat import TemporaryDirectory
+from conda.config import platform, root_dir
 from conda.install import symlink_conda
-from conda.utils import path_identity, shells, on_win, translate_stream
-from conda.cli.activate import binpath_from_arg
-
+from conda.utils import on_win, shells, translate_stream
 from tests.helpers import assert_equals, assert_in, assert_not_in
 
-
 # ENVS_PREFIX = "envs" if PY2 else "envsßôç"
 ENVS_PREFIX = "envs"
 
@@ -38,22 +36,20 @@ def gen_test_env_paths(envs, shell, num_test_folders=5):
     paths = [converter(path) for path in paths]
     return paths
 
-def _envpaths(env_root, env_name="", shelldict={}):
+def _envpaths(env_root, env_name="", shell=None):
     """Supply the appropriate platform executable folders.  rstrip on root removes
        trailing slash if env_name is empty (the default)
 
     Assumes that any prefix used here exists.  Will not work on prefixes that don't.
     """
-    sep = shelldict['sep']
-    return binpath_from_arg(sep.join([env_root, env_name]), shelldict=shelldict)
+    sep = shells[shell]['sep']
+    return binpath_from_arg(sep.join([env_root, env_name]), shell)
 
 
 PYTHONPATH = os.path.dirname(os.path.dirname(__file__))
 
 # Make sure the subprocess activate calls this python
-syspath = os.pathsep.join(_envpaths(root_dir, shelldict={"path_to": path_identity,
-                                                         "path_from": path_identity,
-                                                         "sep": os.sep}))
+syspath = os.pathsep.join(_get_prefix_paths(context.root_prefix))
 
 def print_ps1(env_dirs, raw_ps, number):
     return (u"({}) ".format(env_dirs[number]) + raw_ps)
@@ -144,7 +140,7 @@ def test_activate_test1(shell):
         """).format(envs=envs, env_dirs=gen_test_env_paths(envs, shell), **shell_vars)
 
         stdout, stderr = run_in(commands, shell)
-        assert_in(shells[shell]['pathsep'].join(_envpaths(envs, 'test 1', shelldict=shells[shell])),
+        assert_in(shells[shell]['pathsep'].join(_envpaths(envs, 'test 1', shell)),
                  stdout, shell)
 
 
@@ -159,7 +155,7 @@ def test_activate_env_from_env_with_root_activate(shell):
         """).format(envs=envs, env_dirs=gen_test_env_paths(envs, shell), **shell_vars)
 
         stdout, stderr = run_in(commands, shell)
-        assert_in(shells[shell]['pathsep'].join(_envpaths(envs, 'test 2', shelldict=shells[shell])), stdout)
+        assert_in(shells[shell]['pathsep'].join(_envpaths(envs, 'test 2', shell)), stdout)
 
 
 @pytest.mark.installed
@@ -190,7 +186,7 @@ def test_activate_bad_env_keeps_existing_good_env(shell):
         """).format(envs=envs, env_dirs=gen_test_env_paths(envs, shell), **shell_vars)
 
         stdout, stderr = run_in(commands, shell)
-        assert_in(shells[shell]['pathsep'].join(_envpaths(envs, 'test 1', shelldict=shells[shell])),stdout)
+        assert_in(shells[shell]['pathsep'].join(_envpaths(envs, 'test 1', shell)),stdout)
 
 
 @pytest.mark.installed
@@ -222,7 +218,7 @@ def test_activate_root_simple(shell):
         """).format(envs=envs, **shell_vars)
 
         stdout, stderr = run_in(commands, shell)
-        assert_in(shells[shell]['pathsep'].join(_envpaths(root_dir, shelldict=shells[shell])), stdout, stderr)
+        assert_in(shells[shell]['pathsep'].join(_envpaths(root_dir, shell=shell)), stdout, stderr)
 
         commands = (shell_vars['command_setup'] + """
         {source} "{syspath}{binpath}activate" root
@@ -246,9 +242,9 @@ def test_activate_root_env_from_other_env(shell):
         """).format(envs=envs, env_dirs=gen_test_env_paths(envs, shell), **shell_vars)
 
         stdout, stderr = run_in(commands, shell)
-        assert_in(shells[shell]['pathsep'].join(_envpaths(root_dir, shelldict=shells[shell])),
+        assert_in(shells[shell]['pathsep'].join(_envpaths(root_dir, shell=shell)),
                   stdout)
-        assert_not_in(shells[shell]['pathsep'].join(_envpaths(envs, 'test 1', shelldict=shells[shell])), stdout)
+        assert_not_in(shells[shell]['pathsep'].join(_envpaths(envs, 'test 1', shell)), stdout)
 
 
 @pytest.mark.installed