summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.txt13
-rw-r--r--docs/narr/commandline.rst43
-rw-r--r--pyramid/scripts/pshell.py78
-rw-r--r--pyramid/tests/test_scripts/test_pshell.py135
-rw-r--r--setup.py6
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)
-
diff --git a/setup.py b/setup.py
index f3f0524c3..c81956e7f 100644
--- a/setup.py
+++ b/setup.py
@@ -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