Repository: conda/conda

Issue:
deactivate bug
@kevinzzz007 your issue reported in #4275 is different than what #4275 is reporting.  I've created a new issue here.

> I have a similar problem, I created an env with a name that does not start with an underscore, first I can successfully activate this env, but when I type source deactivate when inside the env, I get an error as the following /Users/MyName/anaconda3/envs/EnvName/bin/deactivate:81: no such file or directory: /Users/MyName/anaconda3/envs/EnvName/bin/python, I looked at the /Users/MyName/anaconda3/envs/EnvName/bin directory and there is no python file in this directory, and after I typed the source deactivate command, my command prompt seems to be back to normal, but then the command prompt can't recognize simple commands like ls...

> my conda version is 4.3.4


Discussion:
This logic has changed recently, and it's also in the latest release of 4.2.  I'll try to fix this tomorrow.
@kalefranz thank you so much!

Resolving patch:
diff --git a/conda/cli/activate.py b/conda/cli/activate.py
--- a/conda/cli/activate.py
+++ b/conda/cli/activate.py
@@ -94,8 +94,26 @@ def pathlist_to_str(paths, escape_backslashes=True):
     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)
+
+    # prepend our new entries onto the existing path and make sure that the separator is native
+    path = shelldict['pathsep'].join(binpath)
+    return path
+
+
 def main():
-    from conda.base.context import context
     from conda.base.constants import ROOT_ENV_NAME
     from conda.utils import shells
     if '-h' in sys.argv or '--help' in sys.argv:
@@ -105,25 +123,26 @@ def main():
     if len(sys.argv) > 2:
         shell = sys.argv[2]
         shelldict = shells[shell]
+    else:
+        shelldict = {}
+
     if sys.argv[1] == '..activate':
-        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)
-
-        # prepend our new entries onto the existing path and make sure that the separator is native
-        path = shelldict['pathsep'].join(binpath)
-
-    # deactivation is handled completely in shell scripts - it restores backups of env variables.
-    #    It is done in shell scripts because they handle state much better than we can here.
+        print(get_activate_path(shelldict))
+        sys.exit(0)
+
+    elif sys.argv[1] == '..deactivate.path':
+        import re
+        activation_path = get_activate_path(shelldict)
+
+        if os.getenv('_CONDA_HOLD'):
+            new_path = re.sub(r'%s(:?)' % re.escape(activation_path),
+                              r'CONDA_PATH_PLACEHOLDER\1',
+                              os.environ['PATH'], 1)
+        else:
+            new_path = re.sub(r'%s(:?)' % re.escape(activation_path), r'', os.environ['PATH'], 1)
+
+        print(new_path)
+        sys.exit(0)
 
     elif sys.argv[1] == '..checkenv':
         if len(sys.argv) < 4:
@@ -143,6 +162,7 @@ def main():
 
         # Make sure an env always has the conda symlink
         try:
+            from conda.base.context import context
             import conda.install
             conda.install.symlink_conda(prefix, context.root_dir, shell)
         except (IOError, OSError) as e:
diff --git a/conda/cli/main.py b/conda/cli/main.py
--- a/conda/cli/main.py
+++ b/conda/cli/main.py
@@ -83,29 +83,8 @@ def generate_parser():
 def _main(*args):
     from ..base.constants import SEARCH_PATH
     from ..base.context import context
-    from ..common.compat import on_win
-    from ..gateways.logging import set_all_logger_level, set_verbosity
-    from ..exceptions import CommandNotFoundError
-    if not args:
-        args = sys.argv
-
-    if not args:
-        args = sys.argv
-
-    log.debug("conda.cli.main called with %s", args)
-    if len(args) > 1:
-        argv1 = args[1].strip()
-        if argv1 in ('..activate', '..deactivate', '..checkenv', '..changeps1'):
-            import conda.cli.activate as activate
-            activate.main()
-            return
-        if argv1 in ('activate', 'deactivate'):
-
-            message = "'%s' is not a conda command.\n" % argv1
-            if not on_win:
-                message += ' Did you mean "source %s" ?\n' % ' '.join(args[1:])
 
-            raise CommandNotFoundError(argv1, message)
+    from ..gateways.logging import set_all_logger_level, set_verbosity
 
     if len(args) == 1:
         args.append('-h')
@@ -161,6 +140,29 @@ def completer(prefix, **kwargs):
 
 
 def main(*args):
+    if not args:
+        args = sys.argv
+
+    if not args:
+        args = sys.argv
+
+    log.debug("conda.cli.main called with %s", args)
+    if len(args) > 1:
+        argv1 = args[1].strip()
+        if argv1.startswith('..'):
+            import conda.cli.activate as activate
+            activate.main()
+            return
+        if argv1 in ('activate', 'deactivate'):
+
+            message = "'%s' is not a conda command.\n" % argv1
+            from ..common.compat import on_win
+            if not on_win:
+                message += ' Did you mean "source %s" ?\n' % ' '.join(args[1:])
+
+            from ..exceptions import CommandNotFoundError
+            raise CommandNotFoundError(argv1, message)
+
     from ..exceptions import conda_exception_handler
     return conda_exception_handler(_main, *args)
 
diff --git a/conda/cli/main_info.py b/conda/cli/main_info.py
--- a/conda/cli/main_info.py
+++ b/conda/cli/main_info.py
@@ -245,7 +245,7 @@ def execute(args, parser):
         for option in options:
             setattr(args, option, True)
 
-    if args.all or all(not getattr(args, opt) for opt in options):
+    if (args.all or all(not getattr(args, opt) for opt in options)) and not context.json:
         for key in 'pkgs_dirs', 'envs_dirs', 'channels':
             info_dict['_' + key] = ('\n' + 26 * ' ').join(info_dict[key])
         info_dict['_rtwro'] = ('writable' if info_dict['root_writable'] else


Test patch: