Hi all, I just merged a branch I've been working on for some time to the Pyramid master branch on Github. The branch was named "twophase", and its goal was to provide imperative configuration extensibility and two-phase configuration much like that currently offered by ZCML.
As a result, the ``pyramid.configuration`` module has been deprecated and exists now only to support backwards compatibility. In its place a new ``pyramid.config`` module exists with fundamentally the same API. Paster template authors beware. What does this change get us? Imperative extensibility was the primary goal (the ability to write "extensible" applications by including configuration from other non-local sources). This was always a feature offered to us by ZCML, but now folks don't have to use ZCML to get it. Here's an example of using imperative configuration to include configuration from a non-local source. If the ``configure`` function below lives in a module named ``myapp.myconfig``: # myapp.myconfig module def my_view(request): from pyramid.response import Response return Response('OK') def configure(config): config.add_view(my_view) You might cause it be included within your Pyramid application like so: from pyramid.config import Configurator def main(global_config, **settings): config = Configurator() config.include('myapp.myconfig.configure') return config.make_wsgi_app() When application extensibility of this kind is used, often configuration conflicts are an issue. When you reuse some configuration from another module, it's more likely that the configuration in that module will conflict with configuration statements you execute "locally" or other configuration statements executed as the result of including some other configuration. For this reason, *configuration conflict detection* is now a feature by default. Included configuration statements will be overridden by local configuration statements if an included callable causes a configuration conflict by registering something with the same configuration parameters. So for instance, in the below, the local "add_view" call will "win" even though both views are registered for the same thing: from pyramid.config import Configurator def someview(request): from pyramid.response import Response return Response('OK') def main(global_config, **settings): config = Configurator() config.add_view(someview) config.include('myapp.myconfig.configure') return config.make_wsgi_app() However, if two *included* configuration callables register the same configuration parameters, a ConfigurationConflictError will now occur. For example: # myapp.myconfig module def my_view(request): from pyramid.response import Response return Response('OK') def configure(config): config.add_view(my_view) # myapp.myconfig2 module def my_view(request): from pyramid.response import Response return Response('OK') def configure(config): config.add_view(my_view) # your application's __init__ from pyramid.config import Configurator def main(global_config, **settings): config = Configurator() config.include('myapp.myconfig.configure') config.include('myapp.myconfig2.configure') return config.make_wsgi_app() When ``make_wsgi_app`` is called, the configuration will be "committed", and a conflict will be detected, because both myapp.myconfig.configure and myapp.myconfig2.configure registered a view with the same configuration parameters. To avoid a conflict, and make "myapp.myconfig2.configure" "win", you can call "commit" between the calls to "include": # your application's __init__ from pyramid.config import Configurator def main(global_config, **settings): config = Configurator() config.include('myapp.myconfig.configure') config.commit() config.include('myapp.myconfig2.configure') return config.make_wsgi_app() Calling "commit" executes all pending configuration and clears the configuration stack. It is safe to call commit() at any time. "make_wsgi_app" calls commit on your behalf usually, but you can issue commits at any time. A conflict error will now occur if you register two configuration statements for the same set of arguments locally too: from pyramid.config import Configurator def someview(request): from pyramid.response import Response return Response('OK') def someotherview(request): from pyramid.response import Response return Response('OK') def main(global_config, **settings): config = Configurator() config.add_view(someview) config.add_view(someotherview) return config.make_wsgi_app() Because both calls to "add_view" above are registered for the same set of circumstances, a ConfigurationConflictError will occur when "make_wsgi_app" is run. To avoid this, use commit between those calls: from pyramid.config import Configurator def someview(request): from pyramid.response import Response return Response('OK') def someotherview(request): from pyramid.response import Response return Response('OK') def main(global_config, **settings): config = Configurator() config.add_view(someview) config.commit() config.add_view(someotherview) return config.make_wsgi_app() By default, the pyramid.config.Configurator behaves like this, deferring configuration actions until "commit" or "make_wsgi_app" is called. If you want the older behavior back (no conflicts, every configuration method executes immediately, later configuration statements override earlier ones), you can use an "autocommitting" configurator: from pyramid.config import Configurator def someview(request): from pyramid.response import Response return Response('OK') def someotherview(request): from pyramid.response import Response return Response('OK') def main(global_config, **settings): config = Configurator(autocommit=True) config.add_view(someview) config.add_view(someotherview) return config.make_wsgi_app() The "someotherview" registered above will "win" in this circumstance. I've used "add_view" in all the examples above, but all methods of the configurator make use of this feature (add_route, add_handler, set_session_factory, etc). If you can imagine a future where folks factor reusable configuration into these configuration callables, and those callables are included by your application, you can imagine a future where applications can be composed of other applications more cleanly than today. This isn't exactly a "reusable application" story (reusable applications require more "rails" than just this can provide), but it does allow configuration to live cleanly outside of the main() function, and allows for composability of multiple applications written by the same person or organization fairly cleanly without ZCML. - C -- You received this message because you are subscribed to the Google Groups "pylons-devel" group. To post to this group, send email to pylons-de...@googlegroups.com. To unsubscribe from this group, send email to pylons-devel+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/pylons-devel?hl=en.