On Sat, 2010-12-11 at 23:49 +0300, Andrey Popp wrote: > Hello, > > > it's looking just great! > > > How do you think, can this behavior be extracted into some pattern for > imperative configuration? I would like to have this in my toolchain in > addition to zope.configuration.
Not sure.. I haven't thought about how to generalize it. > > -- > Andrey Popp > > > On Thursday, December 9, 2010 at 11:19 AM, Chris McDonough wrote: > > > 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 configg.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 Respponse > > 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. > > > > > > -- > 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. -- 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.