Fetching registry (settings) outside of the view

74 views
Skip to first unread message

Vlad K.

unread,
Dec 1, 2011, 11:30:16 AM12/1/11
to pylons-...@googlegroups.com

Hello all!


What is the recommended way to fetch registry (settings) for read only
outside of the view (where request object is not available)? I was
looking at the threadlocal.get_current_registry() but the docs say it
should not be used except maybe in unit tests.

I understand that the request object should be passed around, but what
are my options if I want to avoid that?


Thanks!

--

.oO V Oo.

Chris McDonough

unread,
Dec 1, 2011, 11:42:56 AM12/1/11
to pylons-...@googlegroups.com

To avoid passing deployment settings values around, your options are:

- Use get_current_registry()

- Use a pattern like
http://docs.pylonsproject.org/projects/pyramid_cookbook/en/latest/configuration.html#django-style-settings-py-configuration

You're encouraged to pass per-request values around to make writing unit
tests pleasant and to make it possible to use more than one Pyramid app
per process. But...

If you don't care about testing but you do care about being able to run
more than one instance of the application in the same process:

def get_setting(setting_name, default=None):
return get_current_registry().settings.get('a', default)

def somefunction(a, b):
beinghosed = get_setting('i-am-hosing-myself')

If you care neither about testing nor about being able to run more than
one Pyramid application per process, the "django-style settings"
cookbook entry linked above puts the gun in your hands; it's pre-pointed
at your feet.

- C


Vlad K.

unread,
Dec 1, 2011, 12:17:24 PM12/1/11
to pylons-...@googlegroups.com

Excellent suggestions, thanks!

The globals are not my cup of tea so my feet are currently safe from
that Django pattern. :) I do care about testing and have written unit
tests (although the code I need this in is currently not covered by the
tests), but just to understand the issue at hand, what can go wrong if I
only read the setting like in your get_setting def example?

I know about thread safety and writing shared data, and I know from C
that even reading data which is in the middle of a write by another
thread can produce corrupt results (especially with nonatomic data
types). Is that the case even in Python? The settings I need to read are
some custom config values that never change in the life of the
application (and I say this fully aware of the fact that almost
everything in Python is a reference, especially when dealing with lists
and dictionaries which can be changed "accidentally").

Basically my problem is only that of the separation of concerns. I have
a database model that logs certain operational stuff (not python logger)
and I want it to mail the error entries to the admin, so I want it
"agnostic" to the request chain and views used, because it can be called
in views, or command line scripts (using pyramid.paster.bootstrap),
etc... It requires admin address and smpt server data given in the
config files.

Thanks!


.oO V Oo.

Iain Duncan

unread,
Dec 1, 2011, 12:28:15 PM12/1/11
to pylons-...@googlegroups.com
Hi Vlad, I'd recommend taking a look at your architecture and figure out why request is not available and whether you can fix that. We've (re)designed our system so request is *always* available, as well as tightly controlled ( custom request factory to build it,  and end of life callback to close it down ) and it makes everything much much easier to trace and to test. So for example, our db layer is wrapped up an AbstractModel class, no db calls happen except through that object, and it gets instantiated at the beginning in the request factory, and cleaned up at the end by the request finished callback. Any code, anywhere knows to get persistence data through request.model, which is guaranteed to be local only to that thread. The only registry access outside of request availability is in the app start up where we use it alongside the configurator. We've followed the same thing for other components too.

Just a though, as I used to have registry calls happening elsewhere, but have saved lots of pain but tying it all to the request lifecycle now.

hth
iain

--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To post to this group, send email to pylons-...@googlegroups.com.
To unsubscribe from this group, send email to pylons-discus...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/pylons-discuss?hl=en.


Iain Duncan

unread,
Dec 1, 2011, 12:31:24 PM12/1/11
to pylons-...@googlegroups.com
BTW, pyramid is pretty much designed so that you can eliminate all magic globals and thread locals by keeping a locally passed reference to  request everywhere. I'm curious where you are finding it not accessible? For us, we pass it into formencode validators as part of the state variable, it's already in the root factories, available to templates, and in any views. Where else do you have code that needs the registry? ( curious, not saying you've necessarily done something wrong )

thanks
Iain

Chris McDonough

unread,
Dec 1, 2011, 1:00:09 PM12/1/11
to pylons-...@googlegroups.com
On Thu, 2011-12-01 at 18:17 +0100, Vlad K. wrote:
> Excellent suggestions, thanks!
>
> The globals are not my cup of tea so my feet are currently safe from
> that Django pattern. :) I do care about testing and have written unit
> tests (although the code I need this in is currently not covered by the
> tests), but just to understand the issue at hand, what can go wrong if I
> only read the setting like in your get_setting def example?

It means in test code you will need to do stupid things.

For example, to test this function:

def thething():
return get_current_registry().settings['a']

You will need to write this:

import unittest
from pyramid import testing

class TheTest(unittest.TestCase):
def setUp(self):
self.config = testing.setUp()
self.config.settings['a'] = 1

def tearDown(self):
testing.tearDown()

def test_the_thing(self):
from mycode import thething
result = thething()
self.assertEqual(result, 1)

If you had just created a "thething" function which accepted settings,
it would look more like this:

def thething(settings):
return settings['a']

And the test for it would be less dumb:

import unittest
from pyramid import testing

class TheTest(unittest.TestCase):
def test_the_thing(self):
from mycode import thething
result = thething({'a':1})
self.assertEqual(result, 1)

> I know about thread safety and writing shared data, and I know from C
> that even reading data which is in the middle of a write by another
> thread can produce corrupt results (especially with nonatomic data
> types). Is that the case even in Python? The settings I need to read are
> some custom config values that never change in the life of the
> application (and I say this fully aware of the fact that almost
> everything in Python is a reference, especially when dealing with lists
> and dictionaries which can be changed "accidentally").

You wont have any problem reading these values if they never change;
it's just a design concern.

> Basically my problem is only that of the separation of concerns. I have
> a database model that logs certain operational stuff (not python logger)
> and I want it to mail the error entries to the admin, so I want it
> "agnostic" to the request chain and views used, because it can be called
> in views, or command line scripts (using pyramid.paster.bootstrap),
> etc... It requires admin address and smpt server data given in the
> config files.

Even bootstrap returns a "request" object. The deployment settings can
be obtained via request.registry.settings.

- C

Vlad K.

unread,
Dec 1, 2011, 1:15:25 PM12/1/11
to pylons-...@googlegroups.com

Hi, thanks for your feedback.

It's just a matter of the separation of concerns. The code I need it in
is confined to the model, defined in a "pluggable" model module. It's
not that I can't redesign the chain of calls in order to pass the
request object around, I was just looking at feasible alternatives to
the required refactoring if the request object was to be passed around.


.oO V Oo.

Iain Duncan

unread,
Dec 1, 2011, 2:19:36 PM12/1/11
to pylons-...@googlegroups.com
Vlad, it sounds like you might want to learn about Zope Component Architecture adapters. We use them extensively for situation like you're describing, where you have some pluggable component that has life outside of pyramid ( if I'm reading you correctly ), and you want to get it hooked cleanly into your Pyramid lifecycle. They are super powerful, behind the scenes Pyramid views *are* multi-adapters of context and request. For me, learning how to use the underlying ZCA made Pyramid way more powerful for large projects. The nice thing is that the registry is available everywhere in a pyramid app, so the ZCA makes for a fantastic central train station to hook components to each other.

There's good material on them online, and also in the Plone and Zope books.

HTH
Iain

Chris McDonough

unread,
Dec 1, 2011, 2:29:53 PM12/1/11
to pylons-...@googlegroups.com
On Thu, 2011-12-01 at 11:19 -0800, Iain Duncan wrote:
> Vlad, it sounds like you might want to learn about Zope Component
> Architecture adapters. We use them extensively for situation like
> you're describing, where you have some pluggable component that has
> life outside of pyramid ( if I'm reading you correctly ), and you want
> to get it hooked cleanly into your Pyramid lifecycle. They are super
> powerful, behind the scenes Pyramid views *are* multi-adapters of
> context and request. For me, learning how to use the underlying ZCA
> made Pyramid way more powerful for large projects. The nice thing is
> that the registry is available everywhere in a pyramid app, so the ZCA
> makes for a fantastic central train station to hook components to each
> other.
>
>
>
> There's good material on them online, and also in the Plone and Zope
> books.

Style concerns aside, I think using or disusing the ZCA is not relevant
here; Vlad wants to be able to access deployment settings without
passing any contextual values around. He could use a global ZCA
registry to obtain global settings, but it's still a global, and has all
the downsides of using any other global.

- C

> To unsubscribe from this group, send email to pylons-discuss
> +unsub...@googlegroups.com.


> For more options, visit this group at
> http://groups.google.com/group/pylons-discuss?hl=en.
>
>
>
> --
> You received this message because you are subscribed to the Google
> Groups "pylons-discuss" group.
> To post to this group, send email to pylons-...@googlegroups.com.

> To unsubscribe from this group, send email to pylons-discuss
> +unsub...@googlegroups.com.

Iain Duncan

unread,
Dec 1, 2011, 8:00:53 PM12/1/11
to pylons-...@googlegroups.com
Style concerns aside, I think using or disusing the ZCA is not relevant
here; Vlad wants to be able to access deployment settings without
passing any contextual values around.  He could use a global ZCA
registry to obtain global settings, but it's still a global, and has all
the downsides of using any other global.

I guess I was unclear, that wasn't what I meant at all. I was referring to his comment about pluggable modules and wondering how much refactoring would be necessary.

We're using the zca as the way our components interact, by instantiating them inside adapters of request, context, and sometimes view. This is still being done using the registry attached to request, so it's not the global zca registry or global zca api. ie we get them by doing:

# get the right kind of Foobar for current context & view
adapter_of_foobar = request.registry.queryAdapter(request, context, view)

I realize that may have been misleading as in the past I asked you about using the global zca registry, but we arent' doing that anymore. This was more meant as a comment that if you are looking for ways to plug components together, and wanting to avoid huge refactorings of these components that were designed outside of the context of pyramid,  and you want them to easily get access to deployment settings in one clear point, you can wrap your components in zca adapters of request/context/view and this gives you a very clean way of having them get config values *without* resorting to globals or threadlocals.

class AdapterOfFooBar:

   def __init__(self, request, context, view):
      self.foobar = Foobar()
      # inject config value without having to refactor Foobar
      self.foobar.setWithFoobarOldApi( request.registry.get('myconfig_value') )

  etc

I also realize that I am in a minority in my liking working with pyramid in a very ZCA centric fashion, but for me, it's a great way to connect packages we use for all jobs, and packages/modules specific to our individual client apps. Opinions certainly differ, but I think ZCA adapters are freaking awesome and more people in Pyramid land would love them if they learned how to use them. YMMV!

HTH
Iain

Wyatt Baldwin

unread,
Dec 1, 2011, 9:08:44 PM12/1/11
to pylons-...@googlegroups.com
On Thursday, December 1, 2011 5:00:53 PM UTC-8, Iain Duncan wrote:

[...]


We're using the zca as the way our components interact, by instantiating them inside adapters of request, context, and sometimes view. This is still being done using the registry attached to request, so it's not the global zca registry or global zca api. ie we get them by doing:

# get the right kind of Foobar for current context & view
adapter_of_foobar = request.registry.queryAdapter(request, context, view)

I guess we're going off on a tangent here, but how does queryAdapter know how to get the right kind of Foobar?

Iain Duncan

unread,
Dec 1, 2011, 10:25:19 PM12/1/11
to pylons-...@googlegroups.com
We're using the zca as the way our components interact, by instantiating them inside adapters of request, context, and sometimes view. This is still being done using the registry attached to request, so it's not the global zca registry or global zca api. ie we get them by doing:

# get the right kind of Foobar for current context & view
adapter_of_foobar = request.registry.queryAdapter(request, context, view)

I guess we're going off on a tangent here, but how does queryAdapter know how to get the right kind of Foobar?

Apologies, I was responding too quickly, and didn't put the signature in correctly, it gets looked up according to which interfaces the adapter is registered as adapting, and which interfaces the adaptees provide. So to get a multi adapter adapting context, view, and request, where the adapter itself provides the IFoobar interface, we'd do something like this:

# called from a view, where request and context have been set as attributes of the view object
request.registry.queryMultiAdapter( (self.context, self, self.request), IFoobar )

The specification of which interfaces are adapted and provided can be done either in the adapter class itself, or in ZCML.
For example, this adapter class would get found and instantiated by the above, when asking for an object providing the IFoobar interface,  and the args passed in provide the IContent, IRequest, and IEditView interfaces respectively. 

class FoobarAdapter(object):
  implements(IFoobar)
  adapts( IContent, IRequest, IEditView )

The great thing is the look up is smart about interface inheritance, and you can optionally provide string name keys too. I can definitely not do it justice, but it's absolutely worth learning about. I heard it referred to somewhere as being "like dependency injection on steroids". =)

A good explanation with examples is here:

There's also good stuff in "Web Component Development with Zope 3" by Weitershausen, and Professional Plone Development by Aspeli.

HTH
iain










--
You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To view this discussion on the web visit https://groups.google.com/d/msg/pylons-discuss/-/EqyPEdN-B2YJ.

To post to this group, send email to pylons-...@googlegroups.com.
To unsubscribe from this group, send email to pylons-discus...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages