diff --git a/pecan/commands/shell.py b/pecan/commands/shell.py index 78039e1..dee6aa5 100644 --- a/pecan/commands/shell.py +++ b/pecan/commands/shell.py @@ -3,14 +3,60 @@ Shell command for Pecan. """ from pecan.commands import BaseCommand from webtest import TestApp +from warnings import warn import sys +class NativePythonShell(object): + + @classmethod + def invoke(cls, ns, banner): + import code + py_prefix = sys.platform.startswith('java') and 'J' or 'P' + shell_banner = 'Pecan Interactive Shell\n%sython %s\n\n' % \ + (py_prefix, sys.version) + shell = code.InteractiveConsole(locals=ns) + try: + import readline # noqa + except ImportError: + pass + shell.interact(shell_banner + banner) + + +class IPythonShell(object): + + @classmethod + def invoke(cls, ns, banner): + try: + from IPython.frontend.terminal.embed import ( + InteractiveShellEmbed + ) + shell = InteractiveShellEmbed(banner2=banner) + shell(local_ns=ns) + except ImportError: + from IPython.Shell import IPShellEmbed + shell = IPShellEmbed(argv=self.args) + shell.set_banner(shell.IP.BANNER + '\n\n' + banner) + shell(local_ns=ns, global_ns={}) + + class ShellCommand(BaseCommand): """ Open an interactive shell with the Pecan app loaded. """ + SHELLS = { + 'python': NativePythonShell, + 'ipython': IPythonShell + } + + arguments = BaseCommand.arguments + ({ + 'command': '--shell', + 'help': 'which Python shell to use', + 'choices': SHELLS.keys(), + 'default': 'python' + },) + def run(self, args): super(ShellCommand, self).run(args) @@ -44,23 +90,21 @@ class ShellCommand(BaseCommand): ) banner += ' %-10s - Models from %s\n' % ('model', model_name) - # launch the shell, using IPython if available + self.invoke_shell(locs, banner) + + def invoke_shell(self, locs, banner): + shell = self.SHELLS[self.args.shell] try: - from IPython.Shell import IPShellEmbed - shell = IPShellEmbed(argv=self.args) - shell.set_banner(shell.IP.BANNER + '\n\n' + banner) - shell(local_ns=locs, global_ns={}) - except ImportError: - import code - py_prefix = sys.platform.startswith('java') and 'J' or 'P' - shell_banner = 'Pecan Interactive Shell\n%sython %s\n\n' % \ - (py_prefix, sys.version) - shell = code.InteractiveConsole(locals=locs) - try: - import readline # noqa - except ImportError: - pass - shell.interact(shell_banner + banner) + shell().invoke(locs, banner) + except ImportError, e: + warn( + ("%s is not installed, `%s`, " + "falling back to native shell") % (self.args.shell, e), + RuntimeWarning + ) + if shell == NativePythonShell: + raise + NativePythonShell().invoke(locs, banner) def load_model(self, config): for package_name in getattr(config.app, 'modules', []): diff --git a/setup.py b/setup.py index 850fcc4..13e8172 100644 --- a/setup.py +++ b/setup.py @@ -76,11 +76,8 @@ setup( 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3.2', - 'Programming Language :: Python :: Implementation :: PyPy', 'Topic :: Internet :: WWW/HTTP :: WSGI', 'Topic :: Software Development :: Libraries :: Application Frameworks' ],