diff options
| -rw-r--r-- | CHANGES.txt | 6 | ||||
| -rw-r--r-- | docs/narr/project.rst | 18 | ||||
| -rw-r--r-- | repoze/bfg/paster.py | 31 | ||||
| -rw-r--r-- | repoze/bfg/tests/test_paster.py | 47 |
4 files changed, 91 insertions, 11 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 48921432f..9f8a850e7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,6 +1,12 @@ Next release ============ +Features +-------- + +- ``paster bfgshell`` now supports IPython if it's available for + import. Thanks to Daniel Holth for the initial patch. + Documentation ------------- diff --git a/docs/narr/project.rst b/docs/narr/project.rst index dc3385fcd..cb69fdc0e 100644 --- a/docs/narr/project.rst +++ b/docs/narr/project.rst @@ -200,7 +200,7 @@ the name ``main`` as a section name: .. code-block:: bash :linenos: - [chrism@vitaminf bfgshellenv]$ ../bin/paster bfgshell MyProject.ini main + [chrism@vitaminf bfgshellenv]$ ../bin/paster bfgshell --plugin=repoze.bfg MyProject.ini main Python 2.4.5 (#1, Aug 29 2008, 12:27:37) [GCC 4.0.1 (Apple Inc. build 5465)] on darwin @@ -208,10 +208,18 @@ the name ``main`` as a section name: >>> root <foo.models.MyModel object at 0x445270> -If that command fails because ``paster`` claims it knows nothing about -the "bfgshell" command (this happens under certain conditions that are -not yet well-understood) try passing the flag ``--plugin=repoze.bfg`` -before the filename: +... note:: You *might* get away without passing + ``--plugin=repoze.bfg`` to the bfgshell command; the + ``--plugin=repoze.bfg`` option is required under conditions + that are not yet well-understood. + +If you have `IPython <http://en.wikipedia.org/wiki/IPython>`_ +installed in the interpreter you use to invoke the ``paster`` command, +the ``bfgshell`` 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 ``bfgshell`` command to use a +standard Python interpreter shell unconditionally. .. code-block:: bash :linenos: diff --git a/repoze/bfg/paster.py b/repoze/bfg/paster.py index c60d0b437..de5dc1f79 100644 --- a/repoze/bfg/paster.py +++ b/repoze/bfg/paster.py @@ -9,6 +9,12 @@ from paste.util.template import paste_script_template_renderer from repoze.bfg.scripting import get_root +try: + from IPython.Shell import IPShellEmbed +except ImportError: + IPShellEmbed = None + + class StarterProjectTemplate(Template): _template_dir = 'paster_templates/starter' summary = 'repoze.bfg starter project' @@ -66,8 +72,14 @@ class BFGShellCommand(Command): group_name = 'bfg' 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") + interact = (interact,) # for testing loadapp = (loadapp,) # for testing + IPShellEmbed = IPShellEmbed # for testing verbose = 3 def command(self): @@ -77,8 +89,17 @@ class BFGShellCommand(Command): config_file, section_name = self.args app = get_app(config_file, section_name, loadapp=self.loadapp[0]) root, closer = get_root(app) - try: - self.interact[0](banner, local={'root':root}) - finally: - closer() - + if self.IPShellEmbed is not None and not self.options.disable_ipython: + shell = self.IPShellEmbed(argv=self.args) + shell.set_banner(shell.IP.BANNER + '\n\n' + banner) + try: + shell(local_ns={'root':root}, global_ns={}) + finally: + closer() + else: + try: + self.interact[0](banner, local={'root':root}) + finally: + closer() + + diff --git a/repoze/bfg/tests/test_paster.py b/repoze/bfg/tests/test_paster.py index 0119e3313..4650f04cd 100644 --- a/repoze/bfg/tests/test_paster.py +++ b/repoze/bfg/tests/test_paster.py @@ -8,14 +8,18 @@ class TestBFGShellCommand(unittest.TestCase): def _makeOne(self): return self._getTargetClass()('bfgshell') - def test_command(self): + def test_command_ipython_disabled(self): command = self._makeOne() interact = DummyInteractor() app = DummyApp() loadapp = DummyLoadApp(app) command.interact = (interact,) command.loadapp = (loadapp,) + command.IPShellEmbed = True # fake out command.args = ('/foo/bar/myapp.ini', 'myapp') + class Options(object): pass + command.options = Options() + command.options.disable_ipython =True command.command() self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') self.assertEqual(loadapp.section_name, 'myapp') @@ -28,6 +32,31 @@ class TestBFGShellCommand(unittest.TestCase): self.failUnless(interact.banner) self.assertEqual(len(app.threadlocal_manager.popped), 1) + def test_command_ipython_enabled(self): + command = self._makeOne() + interact = DummyInteractor() + app = DummyApp() + loadapp = DummyLoadApp(app) + command.loadapp = (loadapp,) + dummy_shell_factory = DummyIPShellFactory() + command.IPShellEmbed = dummy_shell_factory + command.args = ('/foo/bar/myapp.ini', 'myapp') + class Options(object): pass + command.options = Options() + command.options.disable_ipython = False + command.command() + self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') + self.assertEqual(loadapp.section_name, 'myapp') + self.failUnless(loadapp.relative_to) + self.assertEqual(len(app.threadlocal_manager.pushed), 1) + pushed = app.threadlocal_manager.pushed[0] + self.assertEqual(pushed['registry'], dummy_registry) + self.assertEqual(pushed['request'], None) + self.assertEqual(dummy_shell_factory.shell.local_ns,{'root':dummy_root}) + self.assertEqual(dummy_shell_factory.shell.global_ns, {}) + self.failUnless(dummy_shell_factory.shell.banner) + self.assertEqual(len(app.threadlocal_manager.popped), 1) + class TestGetApp(unittest.TestCase): def _callFUT(self, config_file, section_name, loadapp): from repoze.bfg.paster import get_app @@ -46,6 +75,22 @@ class TestGetApp(unittest.TestCase): class Dummy: pass +class DummyIPShellFactory(object): + def __call__(self, argv): + shell = DummyIPShell() + self.shell = shell + return shell + +class DummyIPShell(object): + IP = Dummy() + IP.BANNER = 'foo' + def set_banner(self, banner): + self.banner = banner + + def __call__(self, local_ns, global_ns): + self.local_ns = local_ns + self.global_ns = global_ns + dummy_root = Dummy() dummy_registry = Dummy() |
