tests fail because of g

7 views
Skip to first unread message

Jonathan Vanasco

unread,
Jul 5, 2008, 9:55:01 PM7/5/08
to pylons-discuss
I have several helper classes that use g from pylons

I get tons of errors when trying to run tests ( via python setup.py
nosetests ) as importing those packages causes this:

TypeError: No object (name: G) has been registered for this thread


Wichert Akkerman

unread,
Jul 6, 2008, 6:16:34 AM7/6/08
to Jonathan Vanasco, pylons-discuss

See the 'Testing with the session object' thread for examples on
how to deal with that.

Wichert.

--
Wichert Akkerman <wic...@wiggy.net> It is simple to make things.
http://www.wiggy.net/ It is hard to make things simple.

Jonathan Vanasco

unread,
Jul 6, 2008, 6:13:10 PM7/6/08
to pylons-discuss
your approach would make sense for inline code.

my issue is that any helper def or class method that references g will
cause an error when included

i don't think initializing with a setup routine in the controllers
will address that

Wichert Akkerman

unread,
Jul 7, 2008, 3:43:12 AM7/7/08
to Jonathan Vanasco, pylons-discuss

You removed all context from your reply so I'm not sure what exactly yo
uare replying to.

I suspect you are replying to my reference to the session thread. That
has example code for a TestCase class you can use for your tests that
sets up everything needed to use 'magic' variables like g. It works
just fine for helper methods or anything else.

Alberto Valverde

unread,
Jul 7, 2008, 10:56:41 AM7/7/08
to pylons-...@googlegroups.com
Jonathan Vanasco wrote:
> I have several helper classes that use g from pylons
>
You have a design problem then :) pylons.g is really a substitute for
module-level singletons so you can have them associated to an app's
instance and have several of these coexisting in the same process
without conflicts (eg: several blog instances each with it's own db
connection to a different database). This is actually the same problem
you would have if you depended on global state: More difficult to
isolate tests, more difficult to set them up, etc...

If you really want to go this route you can either mock it (using the
same pattern as has been suggested to mock pylons.session) or test the
whole stack so PylonsApp takes care of setting up and tearing down the
app context on every request.

app = paste.deploy.loadapp('config:mytestconfig.ini')
app = webtest.TestApp(app)

resp = app.get('/some/test/method')
assert resp.some_test_var == 'foo'

the controller action that responds to the above url can place variables
in environ['paste.testing_variables'] and they'd be bound to the test
response that TestApp.{get,post,put,etc...} returns:

def some_controller_method(self):*
if* *'paste.testing_variables'* *in* request.environ:
request.environ[*'paste.testing_variables'*][*'some_test_var'*]
= 'foo'

However, the "right" way to do it, IMHO, would be to separate the
functions/classes that depend on g in two. For example, say you needed a
pylons.g.db_connection inside a helper function "bar":

def side_effect_free_bar(db_connection):
# do something with db_connection and refrain from accessing global
state
# this should be pretty easy to unit-test since it's output depends
solely on it's arguments.
# You can easily pass a db_connection you've explicitly prepared for
testing

def bar():
# This one you would test inside functional/integration tests, if at
all.
return side_effect_free_bar(pylons.g.db_connection)

HTH,
Alberto

Jonathan Vanasco

unread,
Jul 7, 2008, 1:52:44 PM7/7/08
to pylons-discuss
hm...

in this instance, i use g for three things:

1- on startup, i pull constants out of the DB and stash them into g
2- misc form classes refer to g as the values to use for validation
3- templates use them to generate dropdowns

i guess i could use some sort of factory function to pull g on each
form init.

Mike Orr

unread,
Jul 7, 2008, 4:16:36 PM7/7/08
to pylons-...@googlegroups.com

What's wrong with using paste.loadapp to properly set 'g' for every
test that needs it? That way your test environment is the closest to
the production environment -- which is the purpose of having tests in
the first place.

--
Mike Orr <slugg...@gmail.com>

Wichert Akkerman

unread,
Jul 7, 2008, 4:33:23 PM7/7/08
to Mike Orr, pylons-...@googlegroups.com

Unit tests want as little as possible of the full environment. And you
want to be able to unit test code that uses things like g.

Mike Orr

unread,
Jul 7, 2008, 4:46:08 PM7/7/08
to pylons-...@googlegroups.com
On Mon, Jul 7, 2008 at 1:33 PM, Wichert Akkerman <wic...@wiggy.net> wrote:
>> What's wrong with using paste.loadapp to properly set 'g' for every
>> test that needs it? That way your test environment is the closest to
>> the production environment -- which is the purpose of having tests in
>> the first place.
>
> Unit tests want as little as possible of the full environment. And you
> want to be able to unit test code that uses things like g.

Well, unit tests (as opposed to functional tests) should test the
target routine as closely as possible, without the interference of
something like 'g' which should be tested separately. After all, a
value on 'g' is the same as the value standalone.

--
Mike Orr <slugg...@gmail.com>

Wichert Akkerman

unread,
Jul 7, 2008, 4:48:46 PM7/7/08
to Mike Orr, pylons-...@googlegroups.com

You might want to unittest a method that uses g in some way. More
typically you may want to unit test something that stuffs data in c.

Mike Orr

unread,
Jul 7, 2008, 4:53:22 PM7/7/08
to pylons-...@googlegroups.com
On Mon, Jul 7, 2008 at 1:48 PM, Wichert Akkerman <wic...@wiggy.net> wrote:
> Previously Mike Orr wrote:
>>
>> On Mon, Jul 7, 2008 at 1:33 PM, Wichert Akkerman <wic...@wiggy.net> wrote:
>> >> What's wrong with using paste.loadapp to properly set 'g' for every
>> >> test that needs it? That way your test environment is the closest to
>> >> the production environment -- which is the purpose of having tests in
>> >> the first place.
>> >
>> > Unit tests want as little as possible of the full environment. And you
>> > want to be able to unit test code that uses things like g.
>>
>> Well, unit tests (as opposed to functional tests) should test the
>> target routine as closely as possible, without the interference of
>> something like 'g' which should be tested separately. After all, a
>> value on 'g' is the same as the value standalone.
>
> You might want to unittest a method that uses g in some way. More
> typically you may want to unit test something that stuffs data in c.

True. I'm just saying if you can code to avoid 'g' and 'c' in your
lib routines, so much the better. I have never found a use for 'g',
except in one case to put a structure of static data that's parsed on
app startup (or read from a cache pickle).

--
Mike Orr <slugg...@gmail.com>

Jonathan Vanasco

unread,
Jul 7, 2008, 5:10:49 PM7/7/08
to pylons-discuss

On Jul 7, 4:53 pm, "Mike Orr" <sluggos...@gmail.com> wrote:
> True.  I'm just saying if you can code to avoid 'g' and 'c' in your
> lib routines, so much the better.  I have never found a use for 'g',
> except in one case to put a structure of static data that's parsed on
> app startup (or read from a cache pickle).

That is *exactly* what I use g for -- stashing 'static' data ( the
names and ids of 'options' that the database fkeys on . example:

query= "select * from _gender"
for row in rows:
g.gender.id[ row.id ]= row.name
g.gender.name[ row.name ]= row.id

i also have some other misc. config data -- like amazon s3 urls, etc
- which are initialized on startup based out of config values.

i'm a little less-than-enthusiastic by the built in testing with
Pylons. not having g,c,session is annoying. i've also noticed that
for every test it does a full app initialization - which means ( in my
case ) querying the database for 50 tables worth of data.

Mike Orr

unread,
Jul 7, 2008, 5:29:04 PM7/7/08
to pylons-...@googlegroups.com
On Mon, Jul 7, 2008 at 2:10 PM, Jonathan Vanasco <jona...@findmeon.com> wrote:
>
>
> On Jul 7, 4:53 pm, "Mike Orr" <sluggos...@gmail.com> wrote:
>> True. I'm just saying if you can code to avoid 'g' and 'c' in your
>> lib routines, so much the better. I have never found a use for 'g',
>> except in one case to put a structure of static data that's parsed on
>> app startup (or read from a cache pickle).
>
> That is *exactly* what I use g for -- stashing 'static' data ( the
> names and ids of 'options' that the database fkeys on . example:
>
> query= "select * from _gender"
> for row in rows:
> g.gender.id[ row.id ]= row.name
> g.gender.name[ row.name ]= row.id
>
> i also have some other misc. config data -- like amazon s3 urls, etc
> - which are initialized on startup based out of config values.
>
> i'm a little less-than-enthusiastic by the built in testing with
> Pylons. not having g,c,session is annoying.

You're not initializing the application completely and you're
wondering why it isn't working? Don't you see the contradiction
there?

> i've also noticed that
> for every test it does a full app initialization - which means ( in my
> case ) querying the database for 50 tables worth of data.

Unit tests always do that: setUp creates a full test environment,
which is discarded after each test. Generally that's considered a
good thing even if it's slow. Python apps have been testing this way
since long before Pylons was created. If you have to read 50 tables
worth of data, it's more a case that you have an unusual application
structure than that Python's testing is screwed up. You may have to
test this application by pre-reading the data at module level and
putting it in place. (And if it's place is in pylons.g, maybe have
some lightweight g-initialization routine that copies the variables
from their test module locations. There's a module_setup function
that may persist between tests, although I'm not sure.

--
Mike Orr <slugg...@gmail.com>

Jonathan Vanasco

unread,
Jul 7, 2008, 5:54:47 PM7/7/08
to pylons-discuss


On Jul 7, 5:29 pm, "Mike Orr" <sluggos...@gmail.com> wrote:
> You're not initializing the application completely and you're
> wondering why it isn't working?  Don't you see the contradiction
> there?

I'm questioning why its initializing for every test, and not 1x then
run all the tests in it.


> Unit tests always do that: setUp creates a full test environment,
> which is discarded after each test.  Generally that's considered a
> good thing even if it's slow.  Python apps have been testing this way
> since long before Pylons was created.
I don't have an issue with that ability of unit tests - but with the
way they're integrated into Pylons.


> If you have to read 50 tables
> worth of data, it's more a case that you have an unusual application
> structure than that Python's testing is screwed up.  You may have to
> test this application by pre-reading the data at module level and
> putting it in place.  (And if it's place is in pylons.g, maybe have
> some lightweight g-initialization routine that copies the variables
> from their test module locations.  There's a module_setup function
> that may persist between tests, although I'm not sure.

It's a fairly normal application structure and design concept for web
projects-- preload all database constants on initialization. I'm not
saying that Python screwed up - I just said that I'm not into the way
testing was integrated into Pylons.

Wichert Akkerman

unread,
Jul 7, 2008, 6:29:36 PM7/7/08
to pylons-...@googlegroups.com

Can we please make sure our test terminology is correct? A unit test
will never do that since it tests as little code as possible in an
isolated environment, preferably using mock objects.

Integration tests however do setup the whole application.

Mike Orr

unread,
Jul 7, 2008, 6:58:33 PM7/7/08
to pylons-...@googlegroups.com

That's my point. Unit tests should not be testing things that use
'g'. Low-level routines should not use 'g'. Only at the higher
integration layer (e.g., controllers) should 'g' get involved. That
way the low-level routines are decoupled from the rest of Pylons, so
they can be used and tested separately. That's the same reason I
added model.init_model() to the SQLAlchemy template, so that the model
could be used without depending on the rest of Pylons.

There's some differences of opinion on where
request/response/g/c/session/cache should properly be used, but by
limiting them to the controller and template as I usually do, it
eliminates unnecessary dependencies between the low-level routines and
the full Pylons environment. This makes it easer to test the routine
code itself without interference from the environment. Thus "def
a(important_value):" instead of "def a(): important_value =
g.important_value".

Obviously there will be some applications where this doesn't work,
where you need something available globally and 'g' is the only
reasonable place to put it. In that case those tests will need the
full environment loaded. Either that or you completely restructure
Pylons to eliminate 'g' and replace it with something else that's more
test-friendly. Or maybe there's a way to build a test structure that
loads a Pylons environment once and uses it for several tests.
However, the reason the environment is normally recreated for every
test is to prevent changes made by one test from leaking into another
test, which invalidates the test.


Putting database lookup values into 'g' was an idea I had not thought
of. When I've come across that situation, I put a function in the
model that returned or updated a cache dict (module global). It is
assumed this function will be valid only if init_model() has been
called. Of course it will fail with a predictable "no database engine
available" error if this is not the case. Now, this structure is safe
if the data does not vary across application instances coexisisting in
the same process, and is ideal if it's read-only. If the data does
vary across application instances, you'll have to put it on 'g'
because that's what 'g' is for -- as a safe place to put
application-instance-specific data.

--
Mike Orr <slugg...@gmail.com>

Shannon -jj Behrens

unread,
Jul 7, 2008, 7:51:37 PM7/7/08
to pylons-...@googlegroups.com
> I'm questioning why its initializing for every test, and not 1x then run all
> the tests in it.

If you use nose and *don't* use the unittest API, then you can have
module-level setup functions. Create a directory named test with a
file called test_foo. All your tests are normal functions like
test_bar(). You do setup and tear down in functions called
setup_module and teardown_module. It's an easy API to remember ;)

-jj

Jonathan Vanasco

unread,
Jul 7, 2008, 8:12:57 PM7/7/08
to pylons-discuss
On Jul 7, 6:58 pm, "Mike Orr" <sluggos...@gmail.com> wrote:
> That's my point.  Unit tests should not be testing things that use
> 'g'.  Low-level routines should not use 'g'.  Only at the higher
> integration layer (e.g., controllers) should 'g' get involved.

Let me rephrase this:

having this code in my Pylons app causes me lots of errors and
failures

class Form_Register(_Schema_Base):
email = formencode.validators.Email(not_empty=True)
us_state=
formencode.validators.OneOf( g.us_states.keys(),hideList=True)

I'm not testing g or accessing it during the test. I'm just having
the misfortune of referencing g in a module.


On Jul 7, 6:58 pm, "Mike Orr" <sluggos...@gmail.com> wrote:
> However, the reason the environment is normally recreated for every
> test is to prevent changes made by one test from leaking into another
> test, which invalidates the test.

I understand that, and to Wichert's point, I'm trying to do both unit
testing and integration testing. So I apologize for the mistake in
words.

> Putting database lookup values into 'g' was an idea I had not thought
> of.  When I've come across that situation, I put a function in the
> model that returned or updated a cache dict (module global).  It is
> assumed this function will be valid only if init_model() has been
> called.  Of course it will fail with a predictable "no database engine
> available" error if this is not the case.  Now, this structure is safe
> if the data does not vary across application instances coexisisting in
> the same process, and is ideal if it's read-only.  If the data does
> vary across application instances, you'll have to put it on 'g'
> because that's what 'g' is for -- as a safe place to put
> application-instance-specific data.

That could work - but at the expense of needless code.

I need these constants when:
- displaying a form
- validating a form
- validating API or other values
- printing information to the end user

doing a model call every time would work - but at the expense of
repetitive queries. for all intents , this data are static and a
dict.

i think the best solution right now is to stick this all in some
package namespace, then use middleware or something to populate G

Alberto Valverde

unread,
Jul 8, 2008, 4:43:43 AM7/8/08
to pylons-...@googlegroups.com

>
> On Jul 7, 6:58 pm, "Mike Orr" <sluggos...@gmail.com> wrote:
>> That's my point. Unit tests should not be testing things that use
>> 'g'. Low-level routines should not use 'g'. Only at the higher
>> integration layer (e.g., controllers) should 'g' get involved.
>
> Let me rephrase this:
>
> having this code in my Pylons app causes me lots of errors and
> failures
>
> class Form_Register(_Schema_Base):
> email = formencode.validators.Email(not_empty=True)
> us_stateformencode.validators.OneOf( g.us_states.keys(),hideList=True)

>
> I'm not testing g or accessing it during the test. I'm just having
> the misfortune of referencing g in a module.

It's not a misfortune, it is a bug. g is *contextual* to an app's
*instance* so there's no way you can expect to work properly at the module
level since you have little control over what g will be really pointing to
when the module is imported. The fix is as easy as:

def get_Form_Register():
class Form_Register(....):
... g.us_state_keys()
return Form_Register

And then call get_Form_Register() inside the controller's actions where
you know for sure g will be properly initialized.

Better still, don't use g for this. Use a cached query:

# Inside some module
@beaker_cache(...)
def us_states():
return model.States.query(model.States.c.country_code == 'us')


A rule of thumb I try to follow that has save me much troubles (after
causing me many more) is to make module imports as side-effect free as
possible.

(....)

>> Putting database lookup values into 'g' was an idea I had not thought
>> of. When I've come across that situation, I put a function in the
>> model that returned or updated a cache dict (module global). It is
>> assumed this function will be valid only if init_model() has been
>> called. Of course it will fail with a predictable "no database engine
>> available" error if this is not the case. Now, this structure is safe
>> if the data does not vary across application instances coexisisting in
>> the same process, and is ideal if it's read-only. If the data does
>> vary across application instances, you'll have to put it on 'g'
>> because that's what 'g' is for -- as a safe place to put
>> application-instance-specific data.
>
> That could work - but at the expense of needless code.

It's not needless if it is needed for the thing to work properly ;)

> I need these constants when:
> - displaying a form
> - validating a form
> - validating API or other values
> - printing information to the end user
>
> doing a model call every time would work - but at the expense of
> repetitive queries. for all intents , this data are static and a
> dict.

pylons.cache. It will even make your app scale more easily since you can
transparently switch to memcached once your app grows over more than one
machine and if, for any reason, the data your storing turns out to be less
static than you thought (eg: the admin interface is extended to allow to
edit the list of available languages)

Alberto

Mike Orr

unread,
Jul 8, 2008, 3:58:21 PM7/8/08
to pylons-...@googlegroups.com

I should point out that getting non-request data into the validators
is a general weakness in Pylons, one that we haven't found a
definitive answer for. So far I've seen these strategies:

- Pass the data in through the 'state' argument. That's what the
argument is for, yet it's impossible to do with @validate because the
wrapper is run before the action method has started, so there's no
opportunity to pass request-specific data such as the current database
record.

- You can inline @validate code into the action method so that it can
call the validator properly with 'state'. However, the current
structure of the @validate code makes it difficult to port because so
much of it has to do with contingencies in the arguments, making it
difficult to tell which code needs to be copied to the action. Or you
can try to piece together code based on the FormEncode manual, but
that's not Pylons-specific so there's the danger of missing an
important 'if' somewhere. There's a ticket to split @validate into
three parts which can be called individually by actions, and make
@validate a simple wrapper to the parts. I'm hoping this or something
similar will get into Pylons 0.9.8 (the second-next version).
http://pylonshq.com/project/pylonshq/ticket/405

- You can allow the validator to access the model directly and look up
database records. This is a possible violation of MVC and adds a
dependency from the validator to the model, but if the validator is
considered a "controller thing" or a "model thing" then it's arguably
legit. This can be combined with a cache accessor/updater in the
model as both I and Alberto have described, to minimize the number of
database queries for infrequently-changing lookup data.

- But how do you get the current record ID in the URL? The action
knows it, but the validator doesn't if you're using @validate. One
way is to look up the ID in 'c', using a little-known (and I think
undocumented) feature of Pylons that copies all routing args to 'c'
variables.

- But what if the ID is non-numeric, points to a nonexistent record,
or the user does not have permission to view the record? Oh dear,
this is all processing the action does. Does the validator have to
duplicate all this processing? Currently it does if you're using
@validate and letting the validator access the model directly. You
could inline the validation call into the action, but that gets into
our second problem above.

- And now we've seen that 'g' can also be used as a rendezvous point
for validators to find their control data. The pros and cons of this
have already been discussed in this thread so I won't repeat them.
But I do want to thank Jonathan for describing this strategy, because
as I said it's not one I'd thought of. Are you the same Jonathan who
posted the validate parts patch?

- There may be better strategies we haven't discovered yet.

--
Mike Orr <slugg...@gmail.com>

Reply all
Reply to author
Forward
0 new messages