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.

-- 
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 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.
> 
> 
> 
> 


-- 
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.

Reply via email to