docs/api/scripting.rst | ●●●●● patch | view | raw | blame | history | |
docs/narr/commandline.rst | ●●●●● patch | view | raw | blame | history | |
pyramid/paster.py | ●●●●● patch | view | raw | blame | history | |
pyramid/scripting.py | ●●●●● patch | view | raw | blame | history | |
pyramid/tests/test_paster.py | ●●●●● patch | view | raw | blame | history | |
pyramid/tests/test_scripting.py | ●●●●● patch | view | raw | blame | history | |
pyramid/util.py | ●●●●● patch | view | raw | blame | history |
docs/api/scripting.rst
@@ -9,5 +9,3 @@ .. autofunction:: prepare .. autofunction:: make_request docs/narr/commandline.rst
@@ -294,7 +294,7 @@ All web applications are, at their hearts, systems which accept a request and return a response. When a request is accepted by a :app:`Pyramid` application, the system receives state from the request which is later relied on your application code. For example, one :term:`view callable` may assume on by your application code. For example, one :term:`view callable` may assume it's working against a request that has a ``request.matchdict`` of a particular composition, while another assumes a different composition of the matchdict. @@ -324,14 +324,14 @@ .. code-block:: python from pyramid.paster import bootstrap info = bootstrap('/path/to/my/development.ini') print info['request'].route_url('home') env = bootstrap('/path/to/my/development.ini') print env['request'].route_url('home') :func:`pyramid.paster.bootstrap` returns a dictionary containing framework-related information. This dictionary will always contain a :term:`request` object as its ``request`` key. The following keys are available in the ``info`` dictionary returned by The following keys are available in the ``env`` dictionary returned by :func:`pyramid.paster.bootstrap`: request @@ -386,43 +386,54 @@ .. code-block:: python from pyramid.paster import bootstrap info = bootstrap('/path/to/my/development.ini#another') print info['request'].route_url('home') env = bootstrap('/path/to/my/development.ini#another') print env['request'].route_url('home') The above example specifies the ``another`` ``app``, ``pipeline``, or ``composite`` section of your PasteDeploy configuration file. In the case that we're using a configuration file that looks like this: ``composite`` section of your PasteDeploy configuration file. The ``app`` object present in the ``env`` dictionary returned by :func:`pyramid.paster.bootstrap` will be a :app:`Pyramid` :term:`router`. .. code-block:: ini Changing the Request ~~~~~~~~~~~~~~~~~~~~ [pipeline:main] pipeline = egg:WebError#evalerror another By default, Pyramid will generate a request object in the ``env`` dictionary for the URL ``http://localhost:80/``. This means that any URLs generated by Pyramid during the execution of your script will be anchored here. This is generally not what you want. [app:another] use = egg:MyProject So how do we make Pyramid generate the correct URLs? It will mean that the ``/path/to/my/development.ini#another`` argument passed to bootstrap will imply the ``[app:another]`` section in our configuration file. Therefore, it will not wrap the WSGI application present in the info dictionary as ``app`` using WebError's ``evalerror`` middleware. The ``app`` object present in the info dictionary returned by :func:`pyramid.paster.bootstrap` will be a :app:`Pyramid` :term:`router` instead. By default, Pyramid will general a request object in the ``info`` dictionary anchored at the root path (``/``). You can alternately supply your own :class:`pyramid.request.Request` instance to the :func:`pyramid.paster.bootstrap` function, to set up request parameters beforehand: Assuming that you have a route configured in your application like so: .. code-block:: python from pyramid.request import Request request = Request.blank('/another/url') config.add_route('verify', '/verify/{code}') You need to inform the Pyramid environment that the WSGI application is handling requests from a certain base. For example, we want to mount our application at `example.com/prefix` and the generated URLs should use HTTPS. This can be done by mutating the request object: .. code-block:: python from pyramid.paster import bootstrap info = bootstrap('/path/to/my/development.ini#another', request=request) print info['request'].path_info # will print '/another/url' env = bootstrap('/path/to/my/development.ini#another') env['request'].host = 'example.com' env['request'].scheme = 'https' env['request'].script_name = '/prefix' print env['request'].application_url # will print 'https://example.com/prefix/another/url' Now you can readily use Pyramid's APIs for generating URLs: .. code-block:: python route_url('verify', env['request'], code='1337') # will return 'https://example.com/prefix/verify/1337' Cleanup ~~~~~~~ When your scripting logic finishes, it's good manners (but not required) to call the ``closer`` callback: @@ -430,10 +441,9 @@ .. code-block:: python from pyramid.paster import bootstrap info = bootstrap('/path/to/my/development.ini') env = bootstrap('/path/to/my/development.ini') # .. do stuff ... info['closer']() env['closer']() pyramid/paster.py
@@ -42,11 +42,12 @@ currently serving ``request``, leaving a natural environment in place to write scripts that can generate URLs and utilize renderers. This function returns a dictionary with ``app``, ``root`` and ``closer`` keys. ``app`` is the WSGI app loaded (based on the ``config_uri``), ``root`` is the traversal root resource of the Pyramid application, and ``closer`` is a parameterless callback that may be called when your script is complete (it pops a threadlocal stack). This function returns a dictionary with ``app``, ``root``, ``closer``, ``request``, and ``registry`` keys. ``app`` is the WSGI app loaded (based on the ``config_uri``), ``root`` is the traversal root resource of the Pyramid application, and ``closer`` is a parameterless callback that may be called when your script is complete (it pops a threadlocal stack). .. note:: Most operations within :app:`Pyramid` expect to be invoked within the context of a WSGI request, thus it's important when @@ -59,7 +60,7 @@ the context of the last-loaded :app:`Pyramid` application. You may load a specific application yourself by using the lower-level functions :meth:`pyramid.paster.get_app` and :meth:`pyramid.scripting.get_root2` in conjunction with :meth:`pyramid.scripting.prepare` in conjunction with :attr:`pyramid.config.global_registries`. ``config_uri`` -- specifies the PasteDeploy config file to use for the @@ -69,15 +70,17 @@ ``request`` -- specified to anchor the script to a given set of WSGI parameters. For example, most people would want to specify the host, scheme and port such that their script will generate URLs in relation to those parameters. to those parameters. A request with default parameters is constructed for you if none is provided. You can mutate the request's ``environ`` later to setup a specific host/port/scheme/etc. See :ref:`writing_a_script` for more information about how to use this function. """ app = get_app(config_uri) info = prepare(request) info['app'] = app return info env = prepare(request) env['app'] = app return env _marker = object() @@ -126,6 +129,7 @@ dest='disable_ipython', help="Don't use IPython even if it is available") bootstrap = (bootstrap,) # testing ConfigParser = ConfigParser.ConfigParser # testing def pshell_file_config(self, filename): @@ -149,72 +153,60 @@ from IPython.Shell import IPShell except ImportError: IPShell = None cprt = 'Type "help" for more information.' banner = "Python %s on %s\n%s" % (sys.version, sys.platform, cprt) config_uri = self.args[0] config_file = config_uri.split('#', 1)[0] self.logging_file_config(config_file) app = self.get_app(config_uri, loadapp=self.loadapp[0]) self.pshell_file_config(config_file) # load default globals shell_globals = { 'app': app, } default_variables = {'app': 'The WSGI Application'} if hasattr(app, 'registry'): root, closer = self.get_root(app) shell_globals.update({'root':root, 'registry':app.registry, 'settings': app.registry.settings}) default_variables.update({ 'root': 'The root of the default resource tree.', 'registry': 'The Pyramid registry object.', 'settings': 'The Pyramid settings object.', }) warning = '' else: # warn the user that this isn't actually the Pyramid app warning = """\n WARNING: You have loaded a generic WSGI application, therefore the "root", "registry", and "settings" global variables are not available. To correct this, run "pshell" again and specify the INI section containing your Pyramid application. For example, if your app is in the '[app:myapp]' config file section, use 'development.ini#myapp' instead of 'development.ini' or 'development.ini#main'.""" closer = lambda: None # bootstrap the environ env = self.bootstrap[0](config_uri) # remove the closer from the env closer = env.pop('closer') # setup help text for default environment env_help = dict(env) env_help['app'] = 'The WSGI application.' env_help['root'] = 'Root of the default resource tree.' env_help['registry'] = 'Active Pyramid registry.' env_help['request'] = 'Active request object.' env_help['root_factory'] = ( 'Default root factory used to create `root`.') # load the pshell section of the ini file self.pshell_file_config(config_file) shell_globals.update(self.loaded_objects) env.update(self.loaded_objects) # eliminate duplicates from default_variables # eliminate duplicates from env, allowing custom vars to override for k in self.loaded_objects: if k in default_variables: del default_variables[k] if k in env_help: del env_help[k] # append the loaded variables if default_variables: banner += '\n\nDefault Variables:' for var, txt in default_variables.iteritems(): banner += '\n %-12s %s' % (var, txt) # generate help text help = '\n' if env_help: help += 'Environment:' for var in sorted(env_help.keys()): help += '\n %-12s %s' % (var, env_help[var]) if self.object_help: banner += '\n\nCustom Variables:' help += '\n\nCustom Variables:' for var in sorted(self.object_help.keys()): banner += '\n %-12s %s' % (var, self.object_help[var]) help += '\n %-12s %s' % (var, self.object_help[var]) # append the warning banner += warning banner += '\n' help += '\n' if (IPShell is None) or self.options.disable_ipython: cprt = 'Type "help" for more information.' banner = "Python %s on %s\n%s" % (sys.version, sys.platform, cprt) banner += '\n' + help try: self.interact[0](banner, local=shell_globals) self.interact[0](banner, local=env) finally: closer() else: try: shell = IPShell(argv=[], user_ns=shell_globals) shell.IP.BANNER = shell.IP.BANNER + '\n\n' + banner shell = IPShell(argv=[], user_ns=env) shell.IP.BANNER = shell.IP.BANNER + help shell.mainloop() finally: closer() pyramid/scripting.py
@@ -1,4 +1,5 @@ from pyramid.config import global_registries from pyramid.exceptions import ConfigurationError from pyramid.request import Request from pyramid.interfaces import IRequestFactory from pyramid.interfaces import IRootFactory @@ -12,13 +13,14 @@ is a callable (accepting no arguments) that should be called when your scripting application is finished using the root. If ``request`` is not None, it is used as the request passed to the :app:`Pyramid` application root factory. A request is constructed using :meth:`pyramid.scripting.make_request` and passed to the root factory if ``request`` is None.""" ``request`` is passed to the :app:`Pyramid` application root factory to compute the root. If ``request`` is None, a default will be constructed using the registry's :term:`Request Factory` via the :meth:`pyramid.interfaces.IRequestFactory.blank` method. """ registry = app.registry if request is None: request = make_request('/', registry) request = _make_request('/', registry) threadlocals = {'registry':registry, 'request':request} app.threadlocal_manager.push(threadlocals) def closer(request=request): # keep request alive via this function default @@ -27,37 +29,43 @@ return root, closer def prepare(request=None, registry=None): """ This function pushes data onto the Pyramid threadlocal stack (request and registry), making those objects 'current'. It returns a dictionary useful for bootstrapping a Pyramid application in a scripting environment. """ This function pushes data onto the Pyramid threadlocal stack (request and registry), making those objects 'current'. It returns a dictionary useful for bootstrapping a Pyramid application in a scripting environment. If ``request`` is None, a default request is constructed using :meth:`pyramid.scripting.make_request`. The request passed to the :app:`Pyramid` application root factory to compute the root. ``request`` is passed to the :app:`Pyramid` application root factory to compute the root. If ``request`` is None, a default will be constructed using the registry's :term:`Request Factory` via the :meth:`pyramid.interfaces.IRequestFactory.blank` method. If ``registry`` is not supplied, the last registry loaded from :attr:`pyramid.config.global_registries` will be used. If you have loaded more than one :app:`Pyramid` application in the current process, you may not want to use the last registry loaded, thus you can search the ``global_registries`` and supply the appropriate one based on your own criteria. :attr:`pyramid.config.global_registries` will be used. If you have loaded more than one :app:`Pyramid` application in the current process, you may not want to use the last registry loaded, thus you can search the ``global_registries`` and supply the appropriate one based on your own criteria. The function returns a dictionary composed of ``root``, ``closer``, ``registry``, ``request`` and ``root_factory``. The ``root`` returned is the application's root resource object. The ``closer`` returned is a callable (accepting no arguments) that should be called when your scripting application is finished using the root. ``registry`` is the registry object passed or the last registry loaded into The function returns a dictionary composed of ``root``, ``closer``, ``registry``, ``request`` and ``root_factory``. The ``root`` returned is the application's root resource object. The ``closer`` returned is a callable (accepting no arguments) that should be called when your scripting application is finished using the root. ``registry`` is the registry object passed or the last registry loaded into :attr:`pyramid.config.global_registries` if no registry is passed. ``request`` is the request object passed or the constructed request if no request is passed. ``root_factory`` is the root factory used to construct the root. ``request`` is the request object passed or the constructed request if no request is passed. ``root_factory`` is the root factory used to construct the root. """ if registry is None: registry = getattr(request, 'registry', global_registries.last) if registry is None: raise ConfigurationError('No valid Pyramid applications could be ' 'found, make sure one has been created ' 'before trying to activate it.') if request is None: request = make_request('/', registry) request = _make_request('/', registry) request.registry = registry threadlocals = {'registry':registry, 'request':request} threadlocal_manager.push(threadlocals) @@ -69,14 +77,14 @@ return {'root':root, 'closer':closer, 'registry':registry, 'request':request, 'root_factory':root_factory} def make_request(path, registry=None): def _make_request(path, registry=None): """ Return a :meth:`pyramid.request.Request` object anchored at a given path. The object returned will be generated from the supplied registry's :term:`Request Factory` using the :meth:`pyramid.interfaces.IRequestFactory.blank` method. This request object can be passed to :meth:`pyramid.scripting.get_root` to initialize an application in This request object can be passed to :meth:`pyramid.scripting.get_root` or :meth:`pyramid.scripting.prepare` to initialize an application in preparation for executing a script with a proper environment setup. URLs can then be generated with the object, as well as rendering templates. pyramid/tests/test_paster.py
@@ -5,245 +5,117 @@ from pyramid.paster import PShellCommand return PShellCommand def _makeOne(self): return self._getTargetClass()('pshell') def _makeOne(self, patch_interact=True, patch_bootstrap=True, patch_config=True, patch_args=True, patch_options=True): cmd = self._getTargetClass()('pshell') if patch_interact: self.interact = DummyInteractor() cmd.interact = (self.interact,) if patch_bootstrap: self.bootstrap = DummyBootstrap() cmd.bootstrap = (self.bootstrap,) if patch_config: self.config_factory = DummyConfigParserFactory() cmd.ConfigParser = self.config_factory if patch_args: self.args = ('/foo/bar/myapp.ini#myapp',) cmd.args = self.args if patch_options: class Options(object): pass self.options = Options() self.options.disable_ipython = True cmd.options = self.options return cmd def test_command_ipshell_is_None_ipython_enabled(self): command = self._makeOne() interact = DummyInteractor() app = DummyApp() loadapp = DummyLoadApp(app) command.interact = (interact,) command.loadapp = (loadapp,) command.ConfigParser = makeDummyConfigParser({}) command.args = ('/foo/bar/myapp.ini#myapp',) class Options(object): pass command.options = Options() command.options.disable_ipython = False command.options.disable_ipython = True command.command(IPShell=None) self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') self.assertEqual(loadapp.section_name, 'myapp') self.assertTrue(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'].registry, dummy_registry) self.assertEqual(interact.local, {'app':app, 'root':dummy_root, 'registry':dummy_registry, 'settings':dummy_registry.settings}) self.assertTrue(interact.banner) self.assertEqual(len(app.threadlocal_manager.popped), 1) 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(self.interact.local, { '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(self.interact.banner) def test_command_ipshell_is_not_None_ipython_disabled(self): command = self._makeOne() interact = DummyInteractor() app = DummyApp() loadapp = DummyLoadApp(app) command.interact = (interact,) command.loadapp = (loadapp,) command.ConfigParser = makeDummyConfigParser({}) command.args = ('/foo/bar/myapp.ini#myapp',) class Options(object): pass command.options = Options() command.options.disable_ipython = True command.command(IPShell='notnone') self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') self.assertEqual(loadapp.section_name, 'myapp') self.assertTrue(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'].registry, dummy_registry) self.assertEqual(interact.local, {'app':app, 'root':dummy_root, 'registry':dummy_registry, 'settings':dummy_registry.settings}) self.assertTrue(interact.banner) self.assertEqual(len(app.threadlocal_manager.popped), 1) 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(self.interact.local, { '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(self.interact.banner) def test_command_ipython_enabled(self): command = self._makeOne() app = DummyApp() loadapp = DummyLoadApp(app) command.loadapp = (loadapp,) command.ConfigParser = makeDummyConfigParser({}) dummy_shell_factory = DummyIPShellFactory() command.args = ('/foo/bar/myapp.ini#myapp',) class Options(object): pass command.options = Options() command = self._makeOne(patch_interact=False) command.options.disable_ipython = False dummy_shell_factory = DummyIPShellFactory() command.command(IPShell=dummy_shell_factory) self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') self.assertEqual(loadapp.section_name, 'myapp') self.assertTrue(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'].registry, dummy_registry) self.assertEqual(dummy_shell_factory.shell.local_ns, {'app':app, 'root':dummy_root, 'registry':dummy_registry, 'settings':dummy_registry.settings}) 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(dummy_shell_factory.shell.local_ns, { 'app':self.bootstrap.app, 'root':self.bootstrap.root, 'registry':self.bootstrap.registry, 'request':self.bootstrap.request, 'root_factory':self.bootstrap.root_factory, }) self.assertEqual(dummy_shell_factory.shell.global_ns, {}) self.assertTrue('\n\n' in dummy_shell_factory.shell.IP.BANNER) self.assertEqual(len(app.threadlocal_manager.popped), 1) def test_command_get_app_hookable(self): from paste.deploy import loadapp command = self._makeOne() app = DummyApp() apped = [] def get_app(*arg, **kw): apped.append((arg, kw)) return app command.get_app = get_app interact = DummyInteractor() app = DummyApp() command.interact = (interact,) command.ConfigParser = makeDummyConfigParser({}) command.args = ('/foo/bar/myapp.ini#myapp',) class Options(object): pass command.options = Options() command.options.disable_ipython =True command.command(IPShell=None) self.assertEqual(len(app.threadlocal_manager.pushed), 1) pushed = app.threadlocal_manager.pushed[0] self.assertEqual(pushed['registry'], dummy_registry) self.assertEqual(pushed['request'].registry, dummy_registry) self.assertEqual(interact.local, {'app': app, 'root':dummy_root, 'registry':dummy_registry, 'settings':dummy_registry.settings}) self.assertTrue(interact.banner) self.assertEqual(len(app.threadlocal_manager.popped), 1) self.assertEqual(apped, [(('/foo/bar/myapp.ini#myapp',), {'loadapp': loadapp})]) def test_command_get_root_hookable(self): command = self._makeOne() interact = DummyInteractor() app = DummyApp() loadapp = DummyLoadApp(app) command.interact = (interact,) command.loadapp = (loadapp,) command.ConfigParser = makeDummyConfigParser({}) root = Dummy() apps = [] def get_root(app): apps.append(app) return root, lambda *arg: None command.get_root =get_root command.args = ('/foo/bar/myapp.ini#myapp',) class Options(object): pass command.options = Options() command.options.disable_ipython =True command.command(IPShell=None) self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') self.assertEqual(loadapp.section_name, 'myapp') self.assertTrue(loadapp.relative_to) self.assertEqual(len(app.threadlocal_manager.pushed), 0) self.assertEqual(interact.local, {'app':app, 'root':root, 'registry':dummy_registry, 'settings':dummy_registry.settings}) self.assertTrue(interact.banner) self.assertEqual(apps, [app]) self.assertTrue(self.bootstrap.closer.called) def test_command_loads_custom_items(self): command = self._makeOne() interact = DummyInteractor() app = DummyApp() loadapp = DummyLoadApp(app) command.interact = (interact,) command.loadapp = (loadapp,) model = Dummy() command.ConfigParser = makeDummyConfigParser([('m', model)]) command.args = ('/foo/bar/myapp.ini#myapp',) class Options(object): pass command.options = Options() command.options.disable_ipython = False self.config_factory.items = [('m', model)] command.options.disable_ipython = True command.command(IPShell=None) self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') self.assertEqual(loadapp.section_name, 'myapp') self.assertTrue(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'].registry, dummy_registry) self.assertEqual(interact.local, {'app':app, 'root':dummy_root, 'registry':dummy_registry, 'settings':dummy_registry.settings, 'm': model}) self.assertTrue(interact.banner) self.assertEqual(len(app.threadlocal_manager.popped), 1) def test_command_no_custom_section(self): command = self._makeOne() interact = DummyInteractor() app = DummyApp() loadapp = DummyLoadApp(app) command.interact = (interact,) command.loadapp = (loadapp,) command.ConfigParser = makeDummyConfigParser(None) command.args = ('/foo/bar/myapp.ini#myapp',) class Options(object): pass command.options = Options() command.options.disable_ipython = False command.command(IPShell=None) self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') self.assertEqual(loadapp.section_name, 'myapp') self.assertTrue(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'].registry, dummy_registry) self.assertEqual(interact.local, {'app':app, 'root':dummy_root, 'registry':dummy_registry, 'settings':dummy_registry.settings}) self.assertTrue(interact.banner) self.assertEqual(len(app.threadlocal_manager.popped), 1) 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(self.interact.local, { 'app':self.bootstrap.app, 'root':self.bootstrap.root, 'registry':self.bootstrap.registry, 'request':self.bootstrap.request, 'root_factory':self.bootstrap.root_factory, 'm':model, }) self.assertTrue(self.bootstrap.closer.called) self.assertTrue(self.interact.banner) def test_command_custom_section_override(self): command = self._makeOne() interact = DummyInteractor() app = Dummy() loadapp = DummyLoadApp(app) command.interact = (interact,) command.loadapp = (loadapp,) model = Dummy() command.ConfigParser = makeDummyConfigParser([('app', model)]) command.args = ('/foo/bar/myapp.ini#myapp',) class Options(object): pass command.options = Options() command.options.disable_ipython = False dummy = Dummy() self.config_factory.items = [('app', dummy), ('root', dummy), ('registry', dummy), ('request', dummy)] command.options.disable_ipython = True command.command(IPShell=None) self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') self.assertEqual(loadapp.section_name, 'myapp') self.assertTrue(loadapp.relative_to) self.assertEqual(interact.local, {'app':model}) self.assertTrue(interact.banner) def test_command_generic_wsgi_app(self): command = self._makeOne() interact = DummyInteractor() app = Dummy() loadapp = DummyLoadApp(app) command.interact = (interact,) command.loadapp = (loadapp,) command.ConfigParser = makeDummyConfigParser(None) command.args = ('/foo/bar/myapp.ini#myapp',) class Options(object): pass command.options = Options() command.options.disable_ipython = False command.command(IPShell=None) self.assertEqual(loadapp.config_name, 'config:/foo/bar/myapp.ini') self.assertEqual(loadapp.section_name, 'myapp') self.assertTrue(loadapp.relative_to) self.assertEqual(interact.local, {'app':app}) self.assertTrue(interact.banner) 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(self.interact.local, { 'app':dummy, 'root':dummy, 'registry':dummy, 'request':dummy, 'root_factory':self.bootstrap.root_factory, }) self.assertTrue(self.bootstrap.closer.called) self.assertTrue(self.interact.banner) class TestPRoutesCommand(unittest.TestCase): def _getTargetClass(self): @@ -1015,22 +887,7 @@ 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) class DummyMapper(object): def __init__(self, *routes): self.routes = routes @@ -1073,15 +930,49 @@ self.views = [(None, view, None) for view in views] self.__request_attrs__ = attrs def makeDummyConfigParser(items): class DummyConfigParser(object): def read(self, filename): self.filename = filename class DummyConfigParser(object): def __init__(self, result): self.result = result def items(self, section): self.section = section if items is None: from ConfigParser import NoSectionError raise NoSectionError, section return items return DummyConfigParser def read(self, filename): self.filename = filename def items(self, section): self.section = section if self.result is None: from ConfigParser import NoSectionError raise NoSectionError, section return self.result class DummyConfigParserFactory(object): items = None def __call__(self): self.parser = DummyConfigParser(self.items) return self.parser class DummyCloser(object): def __call__(self): self.called = True class DummyBootstrap(object): def __init__(self, app=None, registry=None, request=None, root=None, root_factory=None, closer=None): self.app = app or DummyApp() self.registry = registry or dummy_registry self.request = request or DummyRequest({}) self.root = root or dummy_root self.root_factory = root_factory or Dummy() self.closer = closer or DummyCloser() def __call__(self, *a, **kw): self.a = a self.kw = kw return { 'app': self.app, 'registry': self.registry, 'request': self.request, 'root': self.root, 'root_factory': self.root_factory, 'closer': self.closer, } pyramid/tests/test_scripting.py
@@ -48,6 +48,10 @@ self.manager = manager self.default = manager.get() def test_it_no_valid_apps(self): from pyramid.exceptions import ConfigurationError self.assertRaises(ConfigurationError, self._callFUT) def test_it_norequest(self): registry = self._makeRegistry() info = self._callFUT(registry=registry) @@ -85,10 +89,10 @@ closer() self.assertEqual(self.default, self.manager.get()) class TestMakeRequest(unittest.TestCase): class Test__make_request(unittest.TestCase): def _callFUT(self, path='/', registry=None): from pyramid.scripting import make_request return make_request(path, registry) from pyramid.scripting import _make_request return _make_request(path, registry) def test_it_with_registry(self): request = self._callFUT('/', dummy_registry) pyramid/util.py
@@ -151,6 +151,17 @@ The values may be iterated over or the last item added may be accessed via the ``last`` property. If items are added more than once, the most recent addition will be remembered in the order: order = WeakOrderedSet() order.add('1') order.add('2') order.add('1') list(order) == ['2', '1'] order.last == '1' """ def __init__(self): @@ -161,6 +172,8 @@ """ Add an item to the set.""" oid = id(item) if oid in self._items: self._order.remove(oid) self._order.append(oid) return ref = weakref.ref(item, lambda x: self.remove(item)) self._items[oid] = ref