Skip to content

Commit

Permalink
Merge branch '1.2-branch' of https://github.com/jpcw/pyramid into pul…
Browse files Browse the repository at this point in the history
…l.356
  • Loading branch information
mmerickel committed Nov 22, 2011
2 parents 4a572dc + 02b6046 commit cdc3b98
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 27 deletions.
22 changes: 12 additions & 10 deletions docs/narr/commandline.rst
Expand Up @@ -110,6 +110,7 @@ out a *Not found* message.
.. index::
single: interactive shell
single: IPython
single: bpython
single: paster pshell
single: pshell

Expand Down Expand Up @@ -268,21 +269,22 @@ exposed, and the request is configured to generate urls from the host
.. index::
single: IPython
single: bpython

IPython
~~~~~~~
IPython or bpython
~~~~~~~~~~~~~~~~~~

If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ installed in
the interpreter you use to invoke the ``paster`` command, the ``pshell``
command will use an IPython interactive shell instead of a standard Python
interpreter shell. If you don't want this to happen, even if you have
IPython installed, you can pass the ``--disable-ipython`` flag to the
``pshell`` command to use a standard Python interpreter shell
unconditionally.
If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ or
`bpython <http://bpython-interpreter.org/>`_ or both installed in
the interpreter you use to invoke the ``pshell`` command, ``pshell`` will
autodiscover them and use the first respectively found in this order :
IPython, bpython, standard Python interpreter. However you could
specifically invoke one of your choice with the ``-p choice`` or
``--python-shell choice`` option.

.. code-block:: text
[chrism@vitaminf shellenv]$ ../bin/paster pshell --disable-ipython \
[chrism@vitaminf shellenv]$ ../bin/pshell -p ipython | bpython | python \
development.ini#MyProject
Expand Down
32 changes: 27 additions & 5 deletions pyramid/paster.py
Expand Up @@ -127,10 +127,9 @@ class PShellCommand(PCommand):
max_args = 1

parser = Command.standard_parser(simulate=True)
parser.add_option('-d', '--disable-ipython',
action='store_true',
dest='disable_ipython',
help="Don't use IPython even if it is available")
parser.add_option('-p', '--python-shell',
action='store', type='string', dest='python_shell',
default = '', help='ipython | bpython | python')
parser.add_option('--setup',
dest='setup',
help=("A callable that will be passed the environment "
Expand Down Expand Up @@ -222,11 +221,23 @@ def command(self, shell=None):
for var in sorted(self.object_help.keys()):
help += '\n %-12s %s' % (var, self.object_help[var])

if shell is None and not self.options.disable_ipython:
user_shell = self.options.python_shell.lower()
if not user_shell:
if shell is None:
shell = self.make_ipython_v0_11_shell()
if shell is None:
shell = self.make_ipython_v0_10_shell()
if shell is None:
shell = self.make_bpython_shell()

if shell is None and user_shell == 'ipython':
shell = self.make_ipython_v0_11_shell()
if shell is None:
shell = self.make_ipython_v0_10_shell()

if shell is None and user_shell == 'bpython':
shell = self.make_bpython_shell()

if shell is None:
shell = self.make_default_shell()

Expand All @@ -243,6 +254,17 @@ def shell(env, help):
interact(banner, local=env)
return shell

def make_bpython_shell(self, BPShellFactory=None):
if BPShellFactory is None: # pragma: no cover
try:
from bpython import embed
BPShellFactory = embed
except ImportError:
return None
def shell(env, help):
BPShell = BPShellFactory(locals_=env, banner=help + '\n')
return shell

def make_ipython_v0_11_shell(self, IPShellFactory=None):
if IPShellFactory is None: # pragma: no cover
try:
Expand Down
62 changes: 50 additions & 12 deletions pyramid/tests/test_paster.py
Expand Up @@ -20,8 +20,8 @@ def _makeOne(self, patch_bootstrap=True, patch_config=True,
if patch_options:
class Options(object): pass
self.options = Options()
self.options.disable_ipython = True
self.options.setup = None
self.options.python_shell = ''
cmd.options = self.options
return cmd

Expand All @@ -33,6 +33,14 @@ def test_make_default_shell(self):
self.assertEqual(interact.local, {'foo': 'bar'})
self.assertTrue('a help message' in interact.banner)

def test_make_bpython_shell(self):
command = self._makeOne()
bpython = 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_v0_11_shell(self):
command = self._makeOne()
ipshell_factory = DummyIPShellFactory()
Expand All @@ -57,6 +65,7 @@ def test_command_loads_default_shell(self):
shell = DummyShell()
command.make_ipython_v0_11_shell = lambda: None
command.make_ipython_v0_10_shell = lambda: None
command.make_bpython_shell = lambda: None
command.make_default_shell = lambda: shell
command.command()
self.assertTrue(self.config_factory.parser)
Expand All @@ -72,14 +81,15 @@ def test_command_loads_default_shell(self):
self.assertTrue(self.bootstrap.closer.called)
self.assertTrue(shell.help)

def test_command_loads_default_shell_with_ipython_disabled(self):
def test_command_loads_default_shell_with_unknow_shell(self):
command = self._makeOne()
shell = DummyShell()
bad_shell = DummyShell()
command.make_ipython_v0_11_shell = lambda: bad_shell
command.make_ipython_v0_10_shell = lambda: bad_shell
command.make_bpython_shell = lambda: bad_shell
command.make_default_shell = lambda: shell
command.options.disable_ipython = True
command.options.python_shell = 'unknow_python_shell'
command.command()
self.assertTrue(self.config_factory.parser)
self.assertEqual(self.config_factory.parser.filename,
Expand All @@ -100,8 +110,9 @@ def test_command_loads_ipython_v0_11(self):
shell = DummyShell()
command.make_ipython_v0_11_shell = lambda: shell
command.make_ipython_v0_10_shell = lambda: None
command.make_bpython_shell = lambda: None
command.make_default_shell = lambda: None
command.options.disable_ipython = False
command.options.python_shell = 'ipython'
command.command()
self.assertTrue(self.config_factory.parser)
self.assertEqual(self.config_factory.parser.filename,
Expand All @@ -121,8 +132,9 @@ def test_command_loads_ipython_v0_10(self):
shell = DummyShell()
command.make_ipython_v0_11_shell = lambda: None
command.make_ipython_v0_10_shell = lambda: shell
command.make_bpython_shell = lambda: None
command.make_default_shell = lambda: None
command.options.disable_ipython = False
command.options.python_shell = 'ipython'
command.command()
self.assertTrue(self.config_factory.parser)
self.assertEqual(self.config_factory.parser.filename,
Expand All @@ -137,6 +149,27 @@ def test_command_loads_ipython_v0_10(self):
self.assertTrue(self.bootstrap.closer.called)
self.assertTrue(shell.help)

def test_command_loads_bpython_shell(self):
command = self._makeOne()
shell = DummyBPythonShell()
command.make_ipython_v0_11_shell = lambda: None
command.make_ipython_v0_10_shell = lambda: None
command.make_bpython_shell = lambda: shell
command.options.python_shell = 'bpython'
command.command()
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_command_loads_custom_items(self):
command = self._makeOne()
model = Dummy()
Expand Down Expand Up @@ -334,7 +367,7 @@ class IMyRoute(Interface):
self.assertEqual(result, None)
self.assertEqual(len(L), 3)
self.assertEqual(L[-1].split()[:4], ['a', '/a', '<function', 'view'])

def test_single_route_one_view_registered_with_factory(self):
from zope.interface import Interface
from pyramid.registry import Registry
Expand Down Expand Up @@ -371,7 +404,7 @@ def test__get_mapper(self):
registry = Registry()
result = command._get_mapper(registry)
self.assertEqual(result.__class__, RoutesMapper)

class TestPViewsCommand(unittest.TestCase):
def _getTargetClass(self):
from pyramid.paster import PViewsCommand
Expand Down Expand Up @@ -570,7 +603,7 @@ def factory(request): pass
result = command._find_multi_routes(mapper, request)
self.assertEqual(result, [{'match':{}, 'route':routes[0]},
{'match':{}, 'route':routes[1]}])

def test__find_multi_routes_some_match(self):
command = self._makeOne()
def factory(request): pass
Expand All @@ -580,7 +613,7 @@ def factory(request): pass
request = DummyRequest({'PATH_INFO':'/a'})
result = command._find_multi_routes(mapper, request)
self.assertEqual(result, [{'match':{}, 'route':routes[1]}])

def test__find_multi_routes_none_match(self):
command = self._makeOne()
def factory(request): pass
Expand All @@ -590,7 +623,7 @@ def factory(request): pass
request = DummyRequest({'PATH_INFO':'/a'})
result = command._find_multi_routes(mapper, request)
self.assertEqual(result, [])

def test_views_command_not_found(self):
from pyramid.registry import Registry
registry = Registry()
Expand Down Expand Up @@ -953,7 +986,7 @@ def __init__(self, implicit, explicit):
self.name_to_alias = {}
def implicit(self):
return self._implicit

class Dummy:
pass

Expand All @@ -979,6 +1012,11 @@ def __call__(self, banner, local):
self.banner = banner
self.local = local

class DummyBPythonShell:
def __call__(self, locals_, banner):
self.locals_ = locals_
self.banner = banner

class DummyIPShell(object):
IP = Dummy()
IP.BANNER = 'foo'
Expand Down Expand Up @@ -1030,7 +1068,7 @@ def __init__(self, name, pattern, factory=None,

def match(self, route):
return self.matchdict

class DummyRequest:
application_url = 'http://example.com:5432'
script_name = ''
Expand Down

0 comments on commit cdc3b98

Please sign in to comment.