Michael Merickel
2011-11-22 415d082e8a8f39d3a39ea5a96f05ace9d55ec1e4
Merge branch 'pull.356' into 1.2-branch
4 files modified
198 ■■■■ changed files
CHANGES.txt 17 ●●●●● patch | view | raw | blame | history
docs/narr/commandline.rst 22 ●●●● patch | view | raw | blame | history
pyramid/paster.py 48 ●●●● patch | view | raw | blame | history
pyramid/tests/test_paster.py 111 ●●●● patch | view | raw | blame | history
CHANGES.txt
@@ -1,3 +1,20 @@
Next Release
============
Features
--------
- ``bpython`` interpreter compatibility in ``pshell``. See the "Command-Line
  Pyramid" narrative docs chapter for more information.
Backward Incompatibilities
--------------------------
- The ``pshell`` command (see "paster pshell") no longer accepts a
  ``--disable-ipython`` command-line argument.  Instead, it accepts a ``-p``
  or ``--python-shell`` argument, which can be any of the values ``python``,
  ``ipython`` or ``bpython``.
1.2.3 (2011-11-20)
==================
docs/narr/commandline.rst
@@ -110,6 +110,7 @@
.. index::
   single: interactive shell
   single: IPython
   single: bpython
   single: paster pshell
   single: pshell
@@ -268,21 +269,22 @@
.. 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
pyramid/paster.py
@@ -127,10 +127,9 @@
    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 "
@@ -222,18 +221,36 @@
            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:
            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_default_shell()
            shell = self.make_shell()
        try:
            shell(env, help)
        finally:
            closer()
    def make_shell(self):
        shell = None
        user_shell = self.options.python_shell.lower()
        if not user_shell:
            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()
        elif user_shell == 'ipython':
            shell = self.make_ipython_v0_11_shell()
            if shell is None:
                shell = self.make_ipython_v0_10_shell()
        elif user_shell == 'bpython':
            shell = self.make_bpython_shell()
        if shell is None:
            shell = self.make_default_shell()
        return shell
    def make_default_shell(self, interact=interact):
        def shell(env, help):
@@ -243,6 +260,17 @@
            interact(banner, local=env)
        return shell
    def make_bpython_shell(self, 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
    def make_ipython_v0_11_shell(self, IPShellFactory=None):
        if IPShellFactory is None: # pragma: no cover
            try:
pyramid/tests/test_paster.py
@@ -20,8 +20,8 @@
        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
@@ -32,6 +32,14 @@
        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 = 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()
@@ -57,6 +65,7 @@
        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)
@@ -72,14 +81,15 @@
        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_unknown_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,
@@ -100,8 +110,9 @@
        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,
@@ -121,8 +132,9 @@
        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,
@@ -136,6 +148,76 @@
        })
        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_shell_ipython_ordering(self):
        command = self._makeOne()
        shell0_11 = DummyShell()
        shell0_10 = DummyShell()
        command.make_ipython_v0_11_shell = lambda: shell0_11
        command.make_ipython_v0_10_shell = lambda: shell0_10
        command.make_bpython_shell = lambda: None
        shell = command.make_shell()
        self.assertEqual(shell, shell0_11)
        command.options.python_shell = 'ipython'
        shell = command.make_shell()
        self.assertEqual(shell, shell0_11)
    def test_shell_ordering(self):
        command = self._makeOne()
        ipshell = DummyShell()
        bpshell = DummyShell()
        dshell = 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: dshell
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
        command.options.python_shell = 'ipython'
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
        command.options.python_shell = 'bpython'
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
        command.make_ipython_v0_11_shell = lambda: ipshell
        command.make_bpython_shell = lambda: bpshell
        command.options.python_shell = 'ipython'
        shell = command.make_shell()
        self.assertEqual(shell, ipshell)
        command.options.python_shell = 'bpython'
        shell = command.make_shell()
        self.assertEqual(shell, bpshell)
        command.options.python_shell = 'python'
        shell = command.make_shell()
        self.assertEqual(shell, dshell)
    def test_command_loads_custom_items(self):
        command = self._makeOne()
@@ -334,7 +416,7 @@
        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
@@ -371,7 +453,7 @@
        registry = Registry()
        result = command._get_mapper(registry)
        self.assertEqual(result.__class__, RoutesMapper)
class TestPViewsCommand(unittest.TestCase):
    def _getTargetClass(self):
        from pyramid.paster import PViewsCommand
@@ -570,7 +652,7 @@
        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
@@ -580,7 +662,7 @@
        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
@@ -590,7 +672,7 @@
        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()
@@ -953,7 +1035,7 @@
        self.name_to_alias = {}
    def implicit(self):
        return self._implicit
class Dummy:
    pass
@@ -978,6 +1060,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()
@@ -1030,7 +1117,7 @@
    def match(self, route):
        return self.matchdict
class DummyRequest:
    application_url = 'http://example.com:5432'
    script_name = ''