diff options
| -rw-r--r-- | CHANGES.txt | 13 | ||||
| -rw-r--r-- | docs/narr/commandline.rst | 43 | ||||
| -rw-r--r-- | pyramid/scripts/pshell.py | 78 | ||||
| -rw-r--r-- | pyramid/tests/test_scripts/test_pshell.py | 135 | ||||
| -rw-r--r-- | setup.py | 6 |
5 files changed, 84 insertions, 191 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 4396c4356..8c1adc789 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,19 @@ 1.6 (2015-04-14) ================ +Backward Incompatibilities +-------------------------- + +- IPython and BPython support have been removed from pshell in the core. + To continue using them on Pyramid 1.6+ you must install the binding + packages explicitly:: + + $ pip install pyramid_ipython + + or + + $ pip install pyramid_bpython + Features -------- diff --git a/docs/narr/commandline.rst b/docs/narr/commandline.rst index c3791adf2..d466bed44 100644 --- a/docs/narr/commandline.rst +++ b/docs/narr/commandline.rst @@ -107,9 +107,7 @@ found* message. .. index:: single: interactive shell - single: IPython single: pshell - single: bpython .. _interactive_shell: @@ -263,18 +261,13 @@ request is configured to generate urls from the host >>> request.route_url('home') 'https://www.example.com/' -.. index:: - single: IPython - single: bpython - -.. _ipython_or_bpython: - Alternative Shells ~~~~~~~~~~~~~~~~~~ -If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ and/or `bpython -<http://bpython-interpreter.org/>`_ in the interpreter you use to invoke the -``pshell`` command, ``pshell`` will autodiscover and use the first one found. -However you could specifically invoke your choice with the ``-p choice`` or + +The ``pshell`` command can be easily extended with alternate REPLs if the +default python REPL is not satisfactory. Assuming you have a binding +installed such as ``pyramid_ipython`` it will normally be auto-selected and +used. You may also specifically invoke your choice with the ``-p choice`` or ``--python-shell choice`` option. .. code-block:: text @@ -287,7 +280,7 @@ You may use the ``--list-shells`` option to see the available shells. $ $VENV/bin/pshell --list-shells Available shells: - bpython [not available] + bpython ipython python @@ -309,29 +302,19 @@ arguments, ``env`` and ``help``, which would look like this: .. code-block:: python - def ptpython_shell_factory(): - try: - from ptpython.repl import embed - except ImportError: - # ptpython is not installed - return None + from ptpython.repl import embed - def PTPShell(banner, **kwargs): - print(banner) - return embed(**kwargs) - - def shell(env, help): - PTPShell(banner=help, locals=env) - - return shell - -If the factory returns ``None`` then it is assumed that the shell is not -supported. + def ptpython_shell_runner(env, help): + print(help) + return embed(locals=env) .. versionchanged:: 1.6 User-defined shells may be registered using entry points. Prior to this the only supported shells were ``ipython``, ``bpython`` and ``python``. + ``ipython`` and ``bpython`` have been moved into their respective + packages ``pyramid_ipython`` and ``pyramid_bpython``. + Setting a Default Shell ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/pyramid/scripts/pshell.py b/pyramid/scripts/pshell.py index 35c2245e3..0a7cfbbe5 100644 --- a/pyramid/scripts/pshell.py +++ b/pyramid/scripts/pshell.py @@ -21,6 +21,13 @@ def main(argv=sys.argv, quiet=False): return command.run() +def python_shell_runner(env, help, interact=interact): + cprt = 'Type "help" for more information.' + banner = "Python %s on %s\n%s" % (sys.version, sys.platform, cprt) + banner += '\n\n' + help + '\n' + interact(banner, local=env) + + class PShellCommand(object): usage = '%prog config_uri' description = """\ @@ -61,6 +68,7 @@ class PShellCommand(object): "[pshell] ini section.")) ConfigParser = configparser.ConfigParser # testing + default_runner = python_shell_runner # testing loaded_objects = {} object_help = {} @@ -186,23 +194,18 @@ class PShellCommand(object): def show_shells(self): shells = self.find_all_shells() - sorted_shells = sorted(shells.items(), key=lambda x: x[0].lower()) - max_name = max([len(s) for s in shells]) + sorted_names = sorted(shells.keys(), key=lambda x: x.lower()) self.out('Available shells:') - for name, factory in sorted_shells: - shell = factory() - if shell is not None: - self.out(' %s' % (name,)) - else: - self.out(' %s%s [not available]' % ( - name, - ' ' * (max_name - len(name)))) + for name in sorted_names: + self.out(' %s' % (name,)) return 0 def find_all_shells(self): + pkg_resources = self.pkg_resources + shells = {} - for ep in self.pkg_resources.iter_entry_points('pyramid.pshell'): + for ep in pkg_resources.iter_entry_points('pyramid.pshell_runner'): name = ep.name shell_factory = ep.load() shells[name] = shell_factory @@ -228,16 +231,15 @@ class PShellCommand(object): except ValueError: return 1 sorted_shells = sorted(shells.items(), key=order) - for name, factory in sorted_shells: - shell = factory() - if shell is not None: - break + if len(sorted_shells) > 0: + shell = sorted_shells[0][1] + else: - factory = shells.get(user_shell) + runner = shells.get(user_shell) - if factory is not None: - shell = factory() + if runner is not None: + shell = runner if shell is None: raise ValueError( @@ -245,45 +247,9 @@ class PShellCommand(object): ) if shell is None: - shell = self.make_default_shell() - - return shell + # should never happen, but just incase entry points are borked + shell = self.default_runner - @classmethod - def make_python_shell(cls, interact=interact): - def shell(env, help): - cprt = 'Type "help" for more information.' - banner = "Python %s on %s\n%s" % (sys.version, sys.platform, cprt) - banner += '\n\n' + help + '\n' - interact(banner, local=env) - return shell - - make_default_shell = make_python_shell - - @classmethod - def make_bpython_shell(cls, BPShell=None): - if BPShell is None: # pragma: no cover - try: - from bpython import embed - BPShell = embed - except ImportError: - return None - def shell(env, help): - BPShell(locals_=env, banner=help + '\n') - return shell - - @classmethod - def make_ipython_shell(cls, IPShellFactory=None): - if IPShellFactory is None: # pragma: no cover - try: - from IPython.terminal.embed import ( - InteractiveShellEmbed) - IPShellFactory = InteractiveShellEmbed - except ImportError: - return None - def shell(env, help): - IPShell = IPShellFactory(banner2=help + '\n', user_ns=env) - IPShell() return shell diff --git a/pyramid/tests/test_scripts/test_pshell.py b/pyramid/tests/test_scripts/test_pshell.py index d4ce315b8..19dd88693 100644 --- a/pyramid/tests/test_scripts/test_pshell.py +++ b/pyramid/tests/test_scripts/test_pshell.py @@ -37,44 +37,12 @@ class TestPShellCommand(unittest.TestCase): def _makeEntryPoints(self, command, shells): command.pkg_resources = dummy.DummyPkgResources(shells) - def test_make_default_shell(self): - command = self._makeOne() - interact = dummy.DummyInteractor() - shell = command.make_default_shell(interact) - shell({'foo': 'bar'}, 'a help message') - self.assertEqual(interact.local, {'foo': 'bar'}) - self.assertTrue('a help message' in interact.banner) - - def test_make_bpython_shell(self): - command = self._makeOne() - bpython = dummy.DummyBPythonShell() - shell = command.make_bpython_shell(bpython) - shell({'foo': 'bar'}, 'a help message') - self.assertEqual(bpython.locals_, {'foo': 'bar'}) - self.assertTrue('a help message' in bpython.banner) - - def test_make_ipython_shell(self): - command = self._makeOne() - ipshell_factory = dummy.DummyIPShellFactory() - shell = command.make_ipython_shell(ipshell_factory) - shell({'foo': 'bar'}, 'a help message') - self.assertEqual(ipshell_factory.kw['user_ns'], {'foo': 'bar'}) - self.assertTrue('a help message' in ipshell_factory.kw['banner2']) - self.assertTrue(ipshell_factory.shell.called) - def test_command_loads_default_shell(self): command = self._makeOne() shell = dummy.DummyShell() - self._makeEntryPoints( - command, - { - 'ipython': lambda: None, - 'bpython': lambda: None, - 'python': lambda: None, - } - ) + self._makeEntryPoints(command, {}) - command.make_default_shell = lambda: shell + command.default_runner = shell command.run() self.assertTrue(self.config_factory.parser) self.assertEqual(self.config_factory.parser.filename, @@ -99,17 +67,10 @@ class TestPShellCommand(unittest.TestCase): command.out = out shell = dummy.DummyShell() - bad_shell = dummy.DummyShell() - self._makeEntryPoints( - command, - { - 'ipython': lambda: bad_shell, - 'bpython': lambda: bad_shell, - } - ) + self._makeEntryPoints(command, {}) - command.make_default_shell = lambda: shell + command.default_runner = shell command.options.python_shell = 'unknown_python_shell' result = command.run() self.assertEqual(result, 1) @@ -129,8 +90,8 @@ class TestPShellCommand(unittest.TestCase): self._makeEntryPoints( command, { - 'ipython': lambda: shell, - 'bpython': lambda: bad_shell, + 'ipython': shell, + 'bpython': bad_shell, } ) @@ -150,33 +111,6 @@ class TestPShellCommand(unittest.TestCase): self.assertTrue(self.bootstrap.closer.called) self.assertTrue(shell.help) - def test_command_loads_bpython_shell(self): - command = self._makeOne() - shell = dummy.DummyBPythonShell() - - self._makeEntryPoints( - command, - { - 'ipython': lambda: None, - 'bpython': lambda: shell, - } - ) - - command.options.python_shell = 'bpython' - command.run() - self.assertTrue(self.config_factory.parser) - self.assertEqual(self.config_factory.parser.filename, - '/foo/bar/myapp.ini') - self.assertEqual(self.bootstrap.a[0], '/foo/bar/myapp.ini#myapp') - self.assertEqual(shell.locals_, { - 'app':self.bootstrap.app, 'root':self.bootstrap.root, - 'registry':self.bootstrap.registry, - 'request':self.bootstrap.request, - 'root_factory':self.bootstrap.root_factory, - }) - self.assertTrue(self.bootstrap.closer.called) - self.assertTrue(shell.banner) - def test_shell_entry_points(self): command = self._makeOne() dshell = dummy.DummyShell() @@ -184,12 +118,12 @@ class TestPShellCommand(unittest.TestCase): self._makeEntryPoints( command, { - 'ipython': lambda: dshell, - 'bpython': lambda: dshell, + 'ipython': dshell, + 'bpython': dshell, } ) - command.make_default_shell = lambda: None + command.default_runner = None shell = command.make_shell() self.assertEqual(shell, dshell) @@ -199,15 +133,9 @@ class TestPShellCommand(unittest.TestCase): bpshell = dummy.DummyShell() dshell = dummy.DummyShell() - self._makeEntryPoints( - command, - { - 'ipython': lambda: None, - 'bpython': lambda: None, - } - ) + self._makeEntryPoints(command, {}) - command.make_default_shell = lambda: dshell + command.default_runner = dshell shell = command.make_shell() self.assertEqual(shell, dshell) @@ -215,15 +143,12 @@ class TestPShellCommand(unittest.TestCase): command.options.python_shell = 'ipython' self.assertRaises(ValueError, command.make_shell) - command.options.python_shell = 'bpython' - self.assertRaises(ValueError, command.make_shell) - self._makeEntryPoints( command, { - 'ipython': lambda: ipshell, - 'bpython': lambda: bpshell, - 'python': lambda: dshell, + 'ipython': ipshell, + 'bpython': bpshell, + 'python': dshell, } ) @@ -248,13 +173,13 @@ class TestPShellCommand(unittest.TestCase): self._makeEntryPoints( command, { - 'ipython': lambda: ipshell, - 'bpython': lambda: bpshell, - 'python': lambda: dshell, + 'ipython': ipshell, + 'bpython': bpshell, + 'python': dshell, } ) - command.make_default_shell = lambda: dshell + command.default_runner = dshell command.preferred_shells = ['ipython', 'bpython'] shell = command.make_shell() @@ -319,9 +244,8 @@ class TestPShellCommand(unittest.TestCase): self._makeEntryPoints( command, { - 'ipython': lambda: ipshell, - 'bpython': lambda: None, - 'python': lambda: dshell, + 'ipython': ipshell, + 'python': dshell, } ) self.config_factory.items = [ @@ -434,9 +358,8 @@ class TestPShellCommand(unittest.TestCase): self._makeEntryPoints( command, { - 'ipython': lambda: dshell, - 'bpython': lambda: None, - 'python': lambda: dshell, + 'ipython': dshell, + 'python': dshell, } ) @@ -445,11 +368,22 @@ class TestPShellCommand(unittest.TestCase): self.assertEqual(result, 0) self.assertEqual(out_calls, [ 'Available shells:', - ' bpython [not available]', ' ipython', ' python', ]) + +class Test_python_shell_runner(unittest.TestCase): + def _callFUT(self, env, help, interact): + from pyramid.scripts.pshell import python_shell_runner + return python_shell_runner(env, help, interact=interact) + + def test_it(self): + interact = dummy.DummyInteractor() + self._callFUT({'foo': 'bar'}, 'a help message', interact) + self.assertEqual(interact.local, {'foo': 'bar'}) + self.assertTrue('a help message' in interact.banner) + class Test_main(unittest.TestCase): def _callFUT(self, argv): from pyramid.scripts.pshell import main @@ -458,4 +392,3 @@ class Test_main(unittest.TestCase): def test_it(self): result = self._callFUT(['pshell']) self.assertEqual(result, 2) - @@ -111,10 +111,8 @@ setup(name='pyramid', starter=pyramid.scaffolds:StarterProjectTemplate zodb=pyramid.scaffolds:ZODBProjectTemplate alchemy=pyramid.scaffolds:AlchemyProjectTemplate - [pyramid.pshell] - ipython=pyramid.scripts.pshell:PShellCommand.make_ipython_shell - bpython=pyramid.scripts.pshell:PShellCommand.make_bpython_shell - python=pyramid.scripts.pshell:PShellCommand.make_python_shell + [pyramid.pshell_runner] + python=pyramid.scripts.pshell:python_shell_runner [console_scripts] pcreate = pyramid.scripts.pcreate:main pserve = pyramid.scripts.pserve:main |
