Steady as a rock

…or so they say

 

Messing with the stack in python

One thing I don’t like in django is that there is no from input firld that’s automatically set to the current logged in user (like the auto_now datetimefield). Problem with such a field is that there isn’t always a current user, since you can also manipulate django objects on the command line (which is great!). But given that there sometimes is a user, why not take advantage of that and inspect the request? Problem is that you don’t have access to the current request from everywhere, but it’s somewhere on the call stack. Fortunately, you don’t have to do ASM hacking to access the python callstack, python has a neat little gem called sys._getframe which works real pythonic and doesn’t even run off the stack but raises a ValueError if you try and access a non-existing frame. Don’t forget to del(frame) though, otherwise python (and in the case of mod_python: apache) segfaults.

def get_user():
    i=1
    user = None
    while True:
        try:
            frame = sys._getframe(i)
        except ValueError: # Stack isn't this deep
            break
        if 'request' in frame.f_locals and
           issubclass(type(frame.f_locals['request']) , HttpRequest):
            user = frame.f_locals['request'].user
            del(frame)
            break
        del(frame)
        i += 1
    return user
Filed under : Uncategorized, python
By Dennis Kaarsemaker
On January 11, 2007
At 13:48
Comments :
 

8 Comments for this post

 
Koen Bollen Says:

Sweet! This is something I’ve been looking a long time for.
Thanks bro!

Cheers, iKoen.

 
 
Stefaan Says:

I think it’s interesting to note *why* a “del frame” is needed (sidenote: paratheses are not needed, because del is a keyword and not a function in python).

from http://docs.python.org/lib/inspect-stack.html :

Warning: Keeping references to frame objects, as found in the first element of the frame records these functions return, can cause your program to create reference cycles. Once a reference cycle has been created, the lifespan of all objects which can be accessed from the objects which form the cycle can become much longer even if Python’s optional cycle detector is enabled. If such cycles must be created, it is important to ensure they are explicitly broken to avoid the delayed destruction of objects and increased memory consumption which occurs.

 
 
S. Kochen Says:

Wasn’t Guido van Rossum complaining about this functionality not really being Pythonic at all when he saw usage of it in web.py? :)

 
 
Armin Ronacher Says:

I would solve that using a django middleware: http://paste.pocoo.org/

just register the RequestPublisher as middleware and you can use the `get_request()` function of the same module to get the current request object.

Regards,
Armin

 
 
Adrian Holovaty Says:

That is the hack to end all hacks! I wouldn’t touch it with a 10-foot pole personally, but if it works for you, great. :)

 
 
 
Dennis Kaarsemaker Says:

Armin: Thanks!
Adrian: Then please, please, pretty please give us an AutoCurrentUser and AutoCurrentUserAdd fields, maybe with the middlewa Armin wrote :)

 

Leave a Reply