Pylons session in Model unit tests

10 views
Skip to first unread message

Pavel Skvazh

unread,
Apr 30, 2008, 3:27:19 AM4/30/08
to pylons-discuss
I've been searching throught the docs to figure it out but there's no
clue. I've got a set up like Using SQLAlchemy with Pylons suggests
and my model relies on session, where current user_id is stored.

Is there any way to access Pylons session in my model tests?

Thanks!

Alberto Valverde

unread,
Apr 30, 2008, 5:15:28 AM4/30/08
to pylons-...@googlegroups.com
Relying on the HTTP session (if you're not referring to this one please
stop reading now :) in the model is very bad coupling IMHO. As a
workaround you could try to mock a session with something like:

class MyMockSession(dict):
def save(*args, **kw):
pass
etc, ...

from pylons import session
session._push_object(MyMockSession(user_id="fooo"))

You might want to place that in the setUp method and place the
followiing in the tearDown this:

session._pop_object()

Alberto

Pavel Skvazh

unread,
Apr 30, 2008, 7:03:07 AM4/30/08
to pylons-discuss
Thanks a lot, Alberto!

That works just fine.

It's not a good practice indeed, but that's the best way, I could
figure to do with user-specific stuff.
For instance if we're dealing with mail, for get_incoming, get_sent,
get_drafts etc I'll have to
pass session['user_id'] from the controller to the model method, when
It's obvious that this is the
only value it'll ever be getting. Checking if the current user can
delete a certain letter (if he's the author of it)
should obviously be done inside the model, but where will I get the
user_id to check? Passing it to the
delete function looks just wrong to me.
Giving the model access to the session looks far from being good MVC
practice, but I couldn't figure a better way.
If anyone have any suggestions - i'd love to hear any advice :)

Jonathan Vanasco

unread,
Apr 30, 2008, 10:31:04 AM4/30/08
to pylons-discuss
On Apr 30, 7:03 am, Pavel Skvazh <pavel.skv...@gmail.com> wrote:
> Checking if the current user can
> delete a certain letter (if he's the author of it)
> should obviously be done inside the model, but where will I get the
> user_id to check? Passing it to the
> delete function looks just wrong to me.
> Giving the model access to the session looks far from being good MVC
> practice, but I couldn't figure a better way.

That is a bad design pattern for both MVC and OOP standpoints. The
model's core functions should not depend on Pylons or anything 'web'
oriented. You're not liberating the model class, you're creating a
dependency.

Personally, I think your code should be something like :

Controller - SentBox:
letter=
model.letter().load__by__userIdSender_letterId( session['user_id'],
letter_id )
if not letter:
return invalid_letter()
letter.is_deleted_by_sender= True

Model:
class letter():
def load__by__userIdSender_letterId( user_id , letter_id ):
sql= 'select * from letter where ( user_id_sender = %d ) and
( letter_id = %d ) and ( is_deleted_by_sender is not true )"
or
letter= Session.query(self.__class__).filter_by( letter_id =
letter_id ).first()
sql= 'select * from letter where ( letter_id = %d )"
if not letter:
raise ValueError('invalid letter')
if letter.sender_id is not user_id:
raise ValueError('not sender')
if letter. is_deleted_by_sender is true:
raise ValueError('deleted')
return letter

def load__by__userIdRecipient_letterId( user_id , letter_id ):
pass

you could also generate model functions like:
def mark_deleted__by__userIdSender_letterId( user_id , letter_id ):
affected_rows= 'update letter set is_deleted_by_sender = True
where ( user_id_sender = %d ) and ( letter_id = %d )"

but the idea is that, from an access control standpoint, you shouldn't
really do a simple 'load by id' on permissioned records during a write
session. you should always require the ownership data on the record
access and all update/delete object. you can also integrate multiple
db handles - with some being read-only and others being read-write.

mini rant:
i think ORMs and some rapid dev frameworks promote bad practices
with constant 'load by id then check later' actions in the
controller. i keep seeing a lot of controller functionality that
would be better put in the model classes -- where it functions more
like an internal API

think of it like a database view -- the tables/query that make up
the view change a lot, but you have one central interface to access
it. if you treat your models like that (and if you use views, you
already have this ingrained), you can update the 'can i admin'
requirements in a single place, deprecating outdated mechanisms and
avoiding db integrity issues.


Marin

unread,
Jun 28, 2008, 6:50:13 AM6/28/08
to pylons-discuss
> class MyMockSession(dict):
> def save(*args, **kw):
> pass
> etc, ...
>
> from pylons import session
> session._push_object(MyMockSession(user_id="fooo"))
>
> You might want to place that in the setUp method and place the
> followiing in the tearDown this:
>
> session._pop_object()

It sounds like it would work, but I get an empty session when I try
to pass a regular dict. Is there something that I am missing? (Using
pylons 0.9.6.2)
Reply all
Reply to author
Forward
0 new messages