Repository: conda/conda

Issue:
Clean up activate.py using proper OO inheritence
See

* https://github.com/conda/conda/pull/6585#issuecomment-354178822
* https://github.com/conda/conda/pull/6585#issuecomment-354303897


Discussion:
Good first issue for someone comfortable with object oriented programming.

Resolving patch:
diff --git a/conda/activate.py b/conda/activate.py
--- a/conda/activate.py
+++ b/conda/activate.py
@@ -9,7 +9,7 @@
 from tempfile import NamedTemporaryFile
 
 from .base.context import ROOT_ENV_NAME, context, locate_prefix_by_name
-context.__init__()  # oOn import, context does not include SEARCH_PATH. This line fixes that.
+context.__init__()  # On import, context does not include SEARCH_PATH. This line fixes that.
 
 try:
     from cytoolz.itertoolz import concatv, drop
@@ -17,7 +17,7 @@
     from ._vendor.toolz.itertoolz import concatv, drop  # NOQA
 
 
-class Activator(object):
+class _Activator(object):
     # Activate and deactivate have three tasks
     #   1. Set and unset environment variables
     #   2. Execute/source activate.d/deactivate.d scripts
@@ -39,8 +39,21 @@ class Activator(object):
     # To implement support for a new shell, ideally one would only need to add shell-specific
     # information to the __init__ method of this class.
 
-    def __init__(self, shell, arguments=None):
-        self.shell = shell
+    # The following instance variables must be defined by each implementation.
+    shell = None
+    pathsep_join = None
+    path_conversion = None
+    script_extension = None
+    tempfile_extension = None  # None means write instructions to stdout rather than a temp file
+    shift_args = None
+    command_join = None
+
+    unset_var_tmpl = None
+    export_var_tmpl = None
+    set_var_tmpl = None
+    run_script_tmpl = None
+
+    def __init__(self, arguments=None):
         self._raw_arguments = arguments
 
         if PY2:
@@ -49,83 +62,6 @@ def __init__(self, shell, arguments=None):
         else:
             self.environ = os.environ.copy()
 
-        if shell == 'posix':
-            self.pathsep_join = ':'.join
-            self.path_conversion = native_path_to_unix
-            self.script_extension = '.sh'
-            self.tempfile_extension = None  # write instructions to stdout rather than a temp file
-            self.shift_args = 0
-            self.command_join = '\n'
-
-            self.unset_var_tmpl = '\\unset %s'
-            self.export_var_tmpl = "\\export %s='%s'"
-            self.set_var_tmpl = "%s='%s'"
-            self.run_script_tmpl = '\\. "%s"'
-
-        elif shell == 'csh':
-            self.pathsep_join = ':'.join
-            self.path_conversion = native_path_to_unix
-            self.script_extension = '.csh'
-            self.tempfile_extension = None  # write instructions to stdout rather than a temp file
-            self.shift_args = 0
-            self.command_join = ';\n'
-
-            self.unset_var_tmpl = 'unsetenv %s'
-            self.export_var_tmpl = 'setenv %s "%s"'
-            self.set_var_tmpl = "set %s='%s'"
-            self.run_script_tmpl = 'source "%s"'
-
-        elif shell == 'xonsh':
-            self.pathsep_join = ':'.join
-            self.path_conversion = native_path_to_unix
-            self.script_extension = '.xsh'
-            self.tempfile_extension = '.xsh'
-            self.shift_args = 0
-            self.command_join = '\n'
-
-            self.unset_var_tmpl = 'del $%s'
-            self.export_var_tmpl = "$%s = '%s'"
-            self.run_script_tmpl = 'source "%s"'
-
-        elif shell == 'cmd.exe':
-            self.pathsep_join = ';'.join
-            self.path_conversion = path_identity
-            self.script_extension = '.bat'
-            self.tempfile_extension = '.bat'
-            self.shift_args = 1
-            self.command_join = '\r\n' if on_win else '\n'
-
-            self.unset_var_tmpl = '@SET %s='
-            self.export_var_tmpl = '@SET "%s=%s"'
-            self.run_script_tmpl = '@CALL "%s"'
-
-        elif shell == 'fish':
-            self.pathsep_join = '" "'.join
-            self.path_conversion = native_path_to_unix
-            self.script_extension = '.fish'
-            self.tempfile_extension = None  # write instructions to stdout rather than a temp file
-            self.shift_args = 0
-            self.command_join = ';\n'
-
-            self.unset_var_tmpl = 'set -e %s'
-            self.export_var_tmpl = 'set -gx %s "%s"'
-            self.run_script_tmpl = 'source "%s"'
-
-        elif shell == 'powershell':
-            self.pathsep_join = ';'.join
-            self.path_conversion = path_identity
-            self.script_extension = '.ps1'
-            self.tempfile_extension = None  # write instructions to stdout rather than a temp file
-            self.shift_args = 0
-            self.command_join = '\n'
-
-            self.unset_var_tmpl = 'Remove-Variable %s'
-            self.export_var_tmpl = '$env:%s = "%s"'
-            self.run_script_tmpl = '. "%s"'
-
-        else:
-            raise NotImplementedError()
-
     def _finalize(self, commands, ext):
         commands = concatv(commands, ('',))  # add terminating newline
         if ext is None:
@@ -273,13 +209,10 @@ def build_activate(self, env_name_or_prefix):
             }
             deactivate_scripts = ()
 
-        self._update_prompt(set_vars, conda_prompt_modifier)
+        if context.changeps1:
+            self._update_prompt(set_vars, conda_prompt_modifier)
 
-        if on_win and self.shell == 'cmd.exe':
-            import ctypes
-            export_vars.update({
-                "PYTHONIOENCODING": ctypes.cdll.kernel32.GetACP(),
-            })
+        self._build_activate_shell_custom(export_vars)
 
         return {
             'unset_vars': (),
@@ -340,7 +273,8 @@ def build_deactivate(self):
             }
             activate_scripts = self._get_activate_scripts(new_prefix)
 
-        self._update_prompt(set_vars, conda_prompt_modifier)
+        if context.changeps1:
+            self._update_prompt(set_vars, conda_prompt_modifier)
 
         return {
             'unset_vars': unset_vars,
@@ -366,7 +300,8 @@ def build_reactivate(self):
         new_path = self.pathsep_join(self._replace_prefix_in_path(conda_prefix, conda_prefix))
         set_vars = {}
         conda_prompt_modifier = self._prompt_modifier(conda_default_env)
-        self._update_prompt(set_vars, conda_prompt_modifier)
+        if context.changeps1:
+            self._update_prompt(set_vars, conda_prompt_modifier)
         # environment variables are set only to aid transition from conda 4.3 to conda 4.4
         return {
             'unset_vars': (),
@@ -457,30 +392,13 @@ def _replace_prefix_in_path(self, old_prefix, new_prefix, starting_path_dirs=Non
                 path_list.insert(idx, join(new_prefix, 'bin'))
         return self.path_conversion(path_list)
 
+    def _build_activate_shell_custom(self, export_vars):
+        # A method that can be overriden by shell-specific implementations.
+        # The signature of this method may change in the future.
+        pass
+
     def _update_prompt(self, set_vars, conda_prompt_modifier):
-        if not context.changeps1:
-            return
-
-        if self.shell == 'posix':
-            ps1 = self.environ.get('PS1', '')
-            current_prompt_modifier = self.environ.get('CONDA_PROMPT_MODIFIER')
-            if current_prompt_modifier:
-                ps1 = re.sub(re.escape(current_prompt_modifier), r'', ps1)
-            # Because we're using single-quotes to set shell variables, we need to handle the
-            # proper escaping of single quotes that are already part of the string.
-            # Best solution appears to be https://stackoverflow.com/a/1250279
-            ps1 = ps1.replace("'", "'\"'\"'")
-            set_vars.update({
-                'PS1': conda_prompt_modifier + ps1,
-            })
-        elif self.shell == 'csh':
-            prompt = self.environ.get('prompt', '')
-            current_prompt_modifier = self.environ.get('CONDA_PROMPT_MODIFIER')
-            if current_prompt_modifier:
-                prompt = re.sub(re.escape(current_prompt_modifier), r'', prompt)
-            set_vars.update({
-                'prompt': conda_prompt_modifier + prompt,
-            })
+        pass
 
     def _default_env(self, prefix):
         if prefix == context.root_prefix:
@@ -570,6 +488,153 @@ def iteritems(d, **kw):
         return iter(d.items(**kw))
 
 
+class PosixActivator(_Activator):
+
+    def __init__(self, arguments=None):
+        self.pathsep_join = ':'.join
+        self.path_conversion = native_path_to_unix
+        self.script_extension = '.sh'
+        self.tempfile_extension = None  # write instructions to stdout rather than a temp file
+        self.shift_args = 0
+        self.command_join = '\n'
+
+        self.unset_var_tmpl = '\\unset %s'
+        self.export_var_tmpl = "\\export %s='%s'"
+        self.set_var_tmpl = "%s='%s'"
+        self.run_script_tmpl = '\\. "%s"'
+
+        super(PosixActivator, self).__init__(arguments)
+
+    def _update_prompt(self, set_vars, conda_prompt_modifier):
+        ps1 = self.environ.get('PS1', '')
+        current_prompt_modifier = self.environ.get('CONDA_PROMPT_MODIFIER')
+        if current_prompt_modifier:
+            ps1 = re.sub(re.escape(current_prompt_modifier), r'', ps1)
+        # Because we're using single-quotes to set shell variables, we need to handle the
+        # proper escaping of single quotes that are already part of the string.
+        # Best solution appears to be https://stackoverflow.com/a/1250279
+        ps1 = ps1.replace("'", "'\"'\"'")
+        set_vars.update({
+            'PS1': conda_prompt_modifier + ps1,
+        })
+
+
+class CshActivator(_Activator):
+
+    def __init__(self, arguments=None):
+        self.pathsep_join = ':'.join
+        self.path_conversion = native_path_to_unix
+        self.script_extension = '.csh'
+        self.tempfile_extension = None  # write instructions to stdout rather than a temp file
+        self.shift_args = 0
+        self.command_join = ';\n'
+
+        self.unset_var_tmpl = 'unsetenv %s'
+        self.export_var_tmpl = 'setenv %s "%s"'
+        self.set_var_tmpl = "set %s='%s'"
+        self.run_script_tmpl = 'source "%s"'
+
+        super(CshActivator, self).__init__(arguments)
+
+    def _update_prompt(self, set_vars, conda_prompt_modifier):
+        prompt = self.environ.get('prompt', '')
+        current_prompt_modifier = self.environ.get('CONDA_PROMPT_MODIFIER')
+        if current_prompt_modifier:
+            prompt = re.sub(re.escape(current_prompt_modifier), r'', prompt)
+        set_vars.update({
+            'prompt': conda_prompt_modifier + prompt,
+        })
+
+
+class XonshActivator(_Activator):
+
+    def __init__(self, arguments=None):
+        self.pathsep_join = ':'.join
+        self.path_conversion = native_path_to_unix
+        self.script_extension = '.xsh'
+        self.tempfile_extension = '.xsh'
+        self.shift_args = 0
+        self.command_join = '\n'
+
+        self.unset_var_tmpl = 'del $%s'
+        self.export_var_tmpl = "$%s = '%s'"
+        self.set_var_tmpl = "$%s = '%s'"  # TODO: determine if different than export_var_tmpl
+        self.run_script_tmpl = 'source "%s"'
+
+        super(XonshActivator, self).__init__(arguments)
+
+
+class CmdExeActivator(_Activator):
+
+    def __init__(self, arguments=None):
+        self.pathsep_join = ';'.join
+        self.path_conversion = path_identity
+        self.script_extension = '.bat'
+        self.tempfile_extension = '.bat'
+        self.shift_args = 1
+        self.command_join = '\r\n' if on_win else '\n'
+
+        self.unset_var_tmpl = '@SET %s='
+        self.export_var_tmpl = '@SET "%s=%s"'
+        self.set_var_tmpl = '@SET "%s=%s"'  # TODO: determine if different than export_var_tmpl
+        self.run_script_tmpl = '@CALL "%s"'
+
+        super(CmdExeActivator, self).__init__(arguments)
+
+    def _build_activate_shell_custom(self, export_vars):
+        if on_win:
+            import ctypes
+            export_vars.update({
+                "PYTHONIOENCODING": ctypes.cdll.kernel32.GetACP(),
+            })
+
+
+class FishActivator(_Activator):
+
+    def __init__(self, arguments=None):
+        self.pathsep_join = '" "'.join
+        self.path_conversion = native_path_to_unix
+        self.script_extension = '.fish'
+        self.tempfile_extension = None  # write instructions to stdout rather than a temp file
+        self.shift_args = 0
+        self.command_join = ';\n'
+
+        self.unset_var_tmpl = 'set -e %s'
+        self.export_var_tmpl = 'set -gx %s "%s"'
+        self.set_var_tmpl = 'set -gx %s "%s"'  # TODO: determine if different than export_var_tmpl
+        self.run_script_tmpl = 'source "%s"'
+
+        super(FishActivator, self).__init__(arguments)
+
+
+class PowershellActivator(_Activator):
+
+    def __init__(self, arguments=None):
+        self.pathsep_join = ';'.join
+        self.path_conversion = path_identity
+        self.script_extension = '.ps1'
+        self.tempfile_extension = None  # write instructions to stdout rather than a temp file
+        self.shift_args = 0
+        self.command_join = '\n'
+
+        self.unset_var_tmpl = 'Remove-Variable %s'
+        self.export_var_tmpl = '$env:%s = "%s"'
+        self.set_var_tmpl = '$env:%s = "%s"'  # TODO: determine if different than export_var_tmpl
+        self.run_script_tmpl = '. "%s"'
+
+        super(PowershellActivator, self).__init__(arguments)
+
+
+activator_map = {
+    'posix': PosixActivator,
+    'csh': CshActivator,
+    'xonsh': XonshActivator,
+    'cmd.exe': CmdExeActivator,
+    'fish': FishActivator,
+    'powershell': PowershellActivator,
+}
+
+
 def main(argv=None):
     from .common.compat import init_std_stream_encoding
 
@@ -579,7 +644,12 @@ def main(argv=None):
     assert argv[1].startswith('shell.')
     shell = argv[1].replace('shell.', '', 1)
     activator_args = argv[2:]
-    activator = Activator(shell, activator_args)
+    try:
+        activator_cls = activator_map[shell]
+    except KeyError:
+        from . import CondaError
+        raise CondaError("%s is not a supported shell." % shell)
+    activator = activator_cls(activator_args)
     try:
         print(activator.execute(), end='')
         return 0


Test patch:
diff --git a/tests/test_activate.py b/tests/test_activate.py
--- a/tests/test_activate.py
+++ b/tests/test_activate.py
@@ -3,7 +3,7 @@
 
 from logging import getLogger
 import os
-from os.path import basename, dirname, isdir, join
+from os.path import dirname, isdir, join
 import sys
 from tempfile import gettempdir
 from unittest import TestCase
@@ -14,7 +14,8 @@
 from conda import CONDA_PACKAGE_ROOT
 from conda._vendor.auxlib.ish import dals
 from conda._vendor.toolz.itertoolz import concatv
-from conda.activate import Activator, main as activate_main, native_path_to_unix
+from conda.activate import CmdExeActivator, CshActivator, FishActivator, PosixActivator, \
+    PowershellActivator, XonshActivator, activator_map, main as activate_main, native_path_to_unix
 from conda.base.constants import ROOT_ENV_NAME
 from conda.base.context import context, reset_context
 from conda.common.compat import iteritems, on_win, string_types
@@ -63,7 +64,7 @@ def tearDown(self):
         os.environ.update(self.hold_environ)
 
     def test_activate_environment_not_found(self):
-        activator = Activator('posix')
+        activator = PosixActivator()
 
         with tempdir() as td:
             with pytest.raises(EnvironmentLocationNotFound):
@@ -83,7 +84,7 @@ def test_activate_help(self):
 
     def test_PS1(self):
         with env_var("CONDA_CHANGEPS1", "yes", reset_context):
-            activator = Activator('posix')
+            activator = PosixActivator()
             assert activator._prompt_modifier(ROOT_ENV_NAME) == '(%s) ' % ROOT_ENV_NAME
 
             instructions = activator.build_activate("base")
@@ -91,14 +92,14 @@ def test_PS1(self):
 
     def test_PS1_no_changeps1(self):
         with env_var("CONDA_CHANGEPS1", "no", reset_context):
-            activator = Activator('posix')
+            activator = PosixActivator()
             assert activator._prompt_modifier('root') == ''
 
             instructions = activator.build_activate("base")
             assert instructions['export_vars']['CONDA_PROMPT_MODIFIER'] == ''
 
     def test_add_prefix_to_path(self):
-        activator = Activator('posix')
+        activator = PosixActivator()
 
         path_dirs = activator.path_conversion(['/path1/bin', '/path2/bin', '/usr/local/bin', '/usr/bin', '/bin'])
         assert len(path_dirs) == 5
@@ -111,7 +112,7 @@ def test_add_prefix_to_path(self):
         assert new_path == added_paths + path_dirs
 
     def test_remove_prefix_from_path_1(self):
-        activator = Activator('posix')
+        activator = PosixActivator()
         original_path = tuple(activator._get_starting_path_list())
         keep_path = activator.path_conversion('/keep/this/path')
         final_path = (keep_path,) + original_path
@@ -125,7 +126,7 @@ def test_remove_prefix_from_path_1(self):
 
     def test_remove_prefix_from_path_2(self):
         # this time prefix doesn't actually exist in path
-        activator = Activator('posix')
+        activator = PosixActivator()
         original_path = tuple(activator._get_starting_path_list())
         keep_path = activator.path_conversion('/keep/this/path')
         final_path = (keep_path,) + original_path
@@ -138,7 +139,7 @@ def test_remove_prefix_from_path_2(self):
         assert final_path == new_path
 
     def test_replace_prefix_in_path_1(self):
-        activator = Activator('posix')
+        activator = PosixActivator()
         original_path = tuple(activator._get_starting_path_list())
         new_prefix = join(os.getcwd(), 'mytestpath-new')
         new_paths = activator.path_conversion(activator._get_path_dirs(new_prefix))
@@ -156,7 +157,7 @@ def test_replace_prefix_in_path_1(self):
         assert final_path == new_path
 
     def test_default_env(self):
-        activator = Activator('posix')
+        activator = PosixActivator()
         assert ROOT_ENV_NAME == activator._default_env(context.root_prefix)
 
         with tempdir() as td:
@@ -176,7 +177,7 @@ def test_build_activate_shlvl_0(self):
 
             with env_var('CONDA_SHLVL', '0'):
                 with env_var('CONDA_PREFIX', ''):
-                    activator = Activator('posix')
+                    activator = PosixActivator()
                     builder = activator.build_activate(td)
                     new_path = activator.pathsep_join(activator._add_prefix_to_path(td))
                     conda_prompt_modifier = "(%s) " % td
@@ -213,7 +214,7 @@ def test_build_activate_shlvl_1(self):
             old_prefix = '/old/prefix'
             with env_var('CONDA_SHLVL', '1'):
                 with env_var('CONDA_PREFIX', old_prefix):
-                    activator = Activator('posix')
+                    activator = PosixActivator()
                     builder = activator.build_activate(td)
                     new_path = activator.pathsep_join(activator._add_prefix_to_path(td))
                     conda_prompt_modifier = "(%s) " % td
@@ -255,7 +256,7 @@ def test_build_activate_shlvl_2(self):
 
             with env_var('CONDA_SHLVL', '2'):
                 with env_var('CONDA_PREFIX', old_prefix):
-                    activator = Activator('posix')
+                    activator = PosixActivator()
                     builder = activator.build_activate(td)
                     new_path = activator.pathsep_join(activator._add_prefix_to_path(td))
                     conda_prompt_modifier = "(%s) " % td
@@ -295,7 +296,7 @@ def test_activate_same_environment(self):
 
             with env_var('CONDA_SHLVL', '1'):
                 with env_var('CONDA_PREFIX', old_prefix):
-                    activator = Activator('posix')
+                    activator = PosixActivator()
 
                     builder = activator.build_activate(td)
 
@@ -336,7 +337,7 @@ def test_build_deactivate_shlvl_2(self):
             with env_var('CONDA_SHLVL', '2'):
                 with env_var('CONDA_PREFIX_1', old_prefix):
                     with env_var('CONDA_PREFIX', td):
-                        activator = Activator('posix')
+                        activator = PosixActivator()
                         original_path = tuple(activator._get_starting_path_list())
 
                         builder = activator.build_deactivate()
@@ -373,7 +374,7 @@ def test_build_deactivate_shlvl_1(self):
 
             with env_var('CONDA_SHLVL', '1'):
                 with env_var('CONDA_PREFIX', td):
-                    activator = Activator('posix')
+                    activator = PosixActivator()
                     original_path = tuple(activator._get_starting_path_list())
                     builder = activator.build_deactivate()
 
@@ -449,7 +450,7 @@ def assert_unix_path(path):
             assert native_path_to_unix(paths) == paths
 
     def test_posix_basic(self):
-        activator = Activator('posix')
+        activator = PosixActivator()
         self.make_dot_d_files(activator.script_extension)
 
         with captured() as c:
@@ -484,7 +485,7 @@ def test_posix_basic(self):
             'CONDA_SHLVL': '1',
             'PATH': os.pathsep.join(concatv(new_path_parts, (os.environ['PATH'],))),
         }):
-            activator = Activator('posix')
+            activator = PosixActivator()
             with captured() as c:
                 rc = activate_main(('', 'shell.posix', 'reactivate'))
             assert not c.stderr
@@ -532,7 +533,7 @@ def test_posix_basic(self):
 
     @pytest.mark.skipif(not on_win, reason="cmd.exe only on Windows")
     def test_cmd_exe_basic(self):
-        activator = Activator('cmd.exe')
+        activator = CmdExeActivator()
         self.make_dot_d_files(activator.script_extension)
 
         with captured() as c:
@@ -571,7 +572,7 @@ def test_cmd_exe_basic(self):
             'CONDA_SHLVL': '1',
             'PATH': os.pathsep.join(concatv(new_path_parts, (os.environ['PATH'],))),
         }):
-            activator = Activator('cmd.exe')
+            activator = CmdExeActivator()
             with captured() as c:
                 assert activate_main(('', 'shell.cmd.exe', 'reactivate')) == 0
             assert not c.stderr
@@ -620,7 +621,7 @@ def test_cmd_exe_basic(self):
             }
 
     def test_csh_basic(self):
-        activator = Activator('csh')
+        activator = CshActivator()
         self.make_dot_d_files(activator.script_extension)
 
         with captured() as c:
@@ -655,7 +656,7 @@ def test_csh_basic(self):
             'CONDA_SHLVL': '1',
             'PATH': os.pathsep.join(concatv(new_path_parts, (os.environ['PATH'],))),
         }):
-            activator = Activator('csh')
+            activator = CshActivator()
             with captured() as c:
                 rc = activate_main(('', 'shell.csh', 'reactivate'))
             assert not c.stderr
@@ -702,7 +703,7 @@ def test_csh_basic(self):
             }
 
     def test_xonsh_basic(self):
-        activator = Activator('xonsh')
+        activator = XonshActivator()
         self.make_dot_d_files(activator.script_extension)
 
         with captured() as c:
@@ -739,7 +740,7 @@ def test_xonsh_basic(self):
             'CONDA_SHLVL': '1',
             'PATH': os.pathsep.join(concatv(new_path_parts, (os.environ['PATH'],))),
         }):
-            activator = Activator('xonsh')
+            activator = XonshActivator()
             with captured() as c:
                 assert activate_main(('', 'shell.xonsh', 'reactivate')) == 0
             assert not c.stderr
@@ -788,7 +789,7 @@ def test_xonsh_basic(self):
             }
 
     def test_fish_basic(self):
-        activator = Activator('fish')
+        activator = FishActivator()
         self.make_dot_d_files(activator.script_extension)
 
         with captured() as c:
@@ -821,7 +822,7 @@ def test_fish_basic(self):
             'CONDA_SHLVL': '1',
             'PATH': os.pathsep.join(concatv(new_path_parts, (os.environ['PATH'],))),
         }):
-            activator = Activator('fish')
+            activator = FishActivator()
             with captured() as c:
                 rc = activate_main(('', 'shell.fish', 'reactivate'))
             assert not c.stderr
@@ -865,7 +866,7 @@ def test_fish_basic(self):
             }
 
     def test_powershell_basic(self):
-        activator = Activator('powershell')
+        activator = PowershellActivator()
         self.make_dot_d_files(activator.script_extension)
 
         with captured() as c:
@@ -897,7 +898,7 @@ def test_powershell_basic(self):
             'CONDA_SHLVL': '1',
             'PATH': os.pathsep.join(concatv(new_path_parts, (os.environ['PATH'],))),
         }):
-            activator = Activator('powershell')
+            activator = PowershellActivator()
             with captured() as c:
                 rc = activate_main(('', 'shell.powershell', 'reactivate'))
             assert not c.stderr
@@ -998,7 +999,7 @@ def __init__(self, shell_name):
         shell_vals.update(self.shells[shell_name])
         for key, value in iteritems(shell_vals):
             setattr(self, key, value)
-        self.activator = Activator(shell_vals['activator'])
+        self.activator = activator_map[shell_vals['activator']]()
 
     def __enter__(self):
         from pexpect.popen_spawn import PopenSpawn