summaryrefslogtreecommitdiff
path: root/repoze
diff options
context:
space:
mode:
authorChris McDonough <chrism@agendaless.com>2009-05-27 15:47:11 +0000
committerChris McDonough <chrism@agendaless.com>2009-05-27 15:47:11 +0000
commit156375861f191f51f4e97ce25cd4d39f8025f90b (patch)
treeead4a91f8781cc26b6754e496d5e52399568edbe /repoze
parent711b60c05b9573f688994233ec1baac3f89bc45a (diff)
downloadpyramid-156375861f191f51f4e97ce25cd4d39f8025f90b.tar.gz
pyramid-156375861f191f51f4e97ce25cd4d39f8025f90b.tar.bz2
pyramid-156375861f191f51f4e97ce25cd4d39f8025f90b.zip
- A paster command has been added named "bfgshell". This command can
be used to get an interactive prompt with your BFG root object in the global namespace. E.g.:: bin/paster bfgshell /path/to/myapp.ini myapp See the ``Project`` chapter in the BFG documentation for more information.
Diffstat (limited to 'repoze')
-rw-r--r--repoze/bfg/paster.py68
-rw-r--r--repoze/bfg/registry.py10
-rw-r--r--repoze/bfg/scripting.py18
-rw-r--r--repoze/bfg/tests/test_paster.py71
-rw-r--r--repoze/bfg/tests/test_scripting.py31
5 files changed, 143 insertions, 55 deletions
diff --git a/repoze/bfg/paster.py b/repoze/bfg/paster.py
index df8bfecb4..bc339fd4c 100644
--- a/repoze/bfg/paster.py
+++ b/repoze/bfg/paster.py
@@ -1,4 +1,14 @@
+import os
+import sys
+
+from code import interact
+
+from paste.deploy import loadapp
+
from paste.script.templates import Template
+from paste.script.command import Command
+from paste.script.command import BadCommand
+
from paste.util.template import paste_script_template_renderer
class StarterProjectTemplate(Template):
@@ -20,3 +30,61 @@ class AlchemyProjectTemplate(Template):
_template_dir = 'paster_templates/alchemy'
summary = 'repoze.bfg SQLAlchemy project using traversal'
template_renderer = staticmethod(paste_script_template_renderer)
+
+class BFGShellCommand(Command):
+ """Open an interactive shell with a repoze.bfg app loaded.
+
+ This command accepts two positional arguments:
+
+ ``config_file`` -- specifies the PasteDeploy config file to use
+ for the interactive shell.
+
+ ``section_name`` -- specifies the section name in the PasteDeploy
+ config file that represents the application.
+
+ Example::
+
+ $ paster bfgshell myapp.ini main
+
+ .. note:: You should use a ``section_name`` that refers to the
+ actual ``app`` section in the config file that points at
+ your BFG app without any middleware wrapping, or this
+ command will almost certainly fail.
+
+ """
+ summary = "Open an interactive shell with a repoze.bfg app loaded"
+ usage = '\n' + __doc__
+
+ min_args = 2
+ max_args = 2
+ group_name = 'bfg'
+
+ parser = Command.standard_parser(simulate=True)
+ environ = {}
+ interact = (interact,) # for testing
+ loadapp = (loadapp,) # for testing
+ verbose = 3
+
+ def __init__(self, name):
+ Command.__init__(self, name)
+
+ def command(self):
+ cprt =('Type "help" for more information. "root" is the BFG app '
+ 'root object.')
+ banner = "Python %s on %s\n%s" % (sys.version, sys.platform, cprt)
+
+ config_file, section_name = self.args
+ config_name = 'config:%s' % config_file
+ here_dir = os.getcwd()
+
+ app = self.loadapp[0](config_name,
+ name=section_name, relative_to=here_dir)
+ registry = app.registry
+ threadlocals = {'registry':registry, 'request':None}
+ try:
+ app.threadlocal_manager.push(threadlocals)
+ root = app.root_factory(self.environ)
+ self.interact[0](banner, local={'root':root})
+ finally:
+ app.threadlocal_manager.pop()
+
diff --git a/repoze/bfg/registry.py b/repoze/bfg/registry.py
index b9397e7da..46db57c9e 100644
--- a/repoze/bfg/registry.py
+++ b/repoze/bfg/registry.py
@@ -112,9 +112,7 @@ registry_manager = FakeRegistryManager()
deprecated('registry_manager',
'As of repoze.bfg 0.9, any import of registry_manager from'
'``repoze.bfg.registry`` is '
- 'deprecated. Instead, if you are trying to push a BFG '
- 'application registry into a registry_manager within a "debug" '
- 'script, call ``app.get_root(environ)``, which has the side '
- 'effect of pushing the current registry into a thread local '
- 'stack. ``registry_manager`` will disappear in a later '
- 'release of repoze.bfg')
+ 'deprecated. If you are trying to use the registry manager '
+ 'within a "debug" script of your own making, use the ``bfgshell`` '
+ 'paster command instead ``registry_manager`` will disappear in '
+ 'a later release of repoze.bfg')
diff --git a/repoze/bfg/scripting.py b/repoze/bfg/scripting.py
deleted file mode 100644
index 9e83e2fe8..000000000
--- a/repoze/bfg/scripting.py
+++ /dev/null
@@ -1,18 +0,0 @@
-_GET_ROOT_ENVIRON = {}
-
-def get_root(router):
- """ Given a :mod:`repoze.bfg` Router application instance as its
- ``router`` argument, this callable returns the traversal root of
- graph as defined by the application's root factory. It also has
- the effect of pushing a new registry and request on to the
- internal thread local stack managed by BFG so that registry
- lookups work properly.
-
- .. warning:: This function should never be called from *within* a
- BFG model or view, only from top-level scripts which wish to
- get the root of a graph to do offline processing."""
- registry = router.registry
- threadlocals = {'registry':registry, 'request':None}
- router.threadlocal_manager.push(threadlocals)
- return router.root_factory(_GET_ROOT_ENVIRON)
-
diff --git a/repoze/bfg/tests/test_paster.py b/repoze/bfg/tests/test_paster.py
new file mode 100644
index 000000000..3339fe498
--- /dev/null
+++ b/repoze/bfg/tests/test_paster.py
@@ -0,0 +1,71 @@
+import unittest
+
+class TestBFGShellCommand(unittest.TestCase):
+ def _getTargetClass(self):
+ from repoze.bfg.paster import BFGShellCommand
+ return BFGShellCommand
+
+ def _makeOne(self):
+ return self._getTargetClass()('bfgshell')
+
+ def test_command(self):
+ command = self._makeOne()
+ interact = DummyInteractor()
+ app = DummyApp()
+ loadapp = DummyLoadApp(app)
+ command.interact = (interact,)
+ command.loadapp = (loadapp,)
+ command.args = ('/foo/bar/myapp.ini', 'myapp')
+ 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(interact.local, {'root':dummy_root})
+ self.failUnless(interact.banner)
+ self.assertEqual(len(app.threadlocal_manager.popped), 1)
+
+class Dummy:
+ pass
+
+dummy_root = Dummy()
+
+dummy_registry = Dummy()
+
+class DummyInteractor:
+ def __call__(self, banner, local):
+ self.banner = banner
+ self.local = local
+
+class DummyLoadApp:
+ def __init__(self, app):
+ self.app = app
+
+ def __call__(self, config_name, name=None, relative_to=None):
+ self.config_name = config_name
+ self.section_name = name
+ self.relative_to = relative_to
+ return self.app
+
+class DummyApp:
+ def __init__(self):
+ self.registry = dummy_registry
+ self.threadlocal_manager = DummyThreadLocalManager()
+
+ def root_factory(self, environ):
+ return dummy_root
+
+class DummyThreadLocalManager:
+ def __init__(self):
+ self.pushed = []
+ self.popped = []
+
+ def push(self, item):
+ self.pushed.append(item)
+
+ def pop(self):
+ self.popped.append(True)
+
diff --git a/repoze/bfg/tests/test_scripting.py b/repoze/bfg/tests/test_scripting.py
deleted file mode 100644
index a54b4b7d9..000000000
--- a/repoze/bfg/tests/test_scripting.py
+++ /dev/null
@@ -1,31 +0,0 @@
-import unittest
-
-class TestGetRoot(unittest.TestCase):
- def _callFUT(self, router):
- from repoze.bfg.scripting import get_root
- return get_root(router)
-
- def test_it(self):
- router = DummyRouter()
- result = self._callFUT(router)
- self.assertEqual(result, router)
- self.assertEqual(len(router.threadlocal_manager.pushed), 1)
- self.assertEqual(router.threadlocal_manager.pushed[0],
- {'registry':None, 'request':None})
-
-
-class DummyThreadLocalManager:
- def __init__(self):
- self.pushed = []
-
- def push(self, val):
- self.pushed.append(val)
-
-class DummyRouter:
- def __init__(self):
- self.registry = None
- self.threadlocal_manager = DummyThreadLocalManager()
-
- def root_factory(self, environ):
- return self
-