[mod_python] Getting request object

Graham Dumpleton grahamd at dscpl.com.au
Wed Dec 7 06:29:14 EST 2005


On 07/12/2005, at 7:21 PM, Radek Bartoň wrote:

> Hello, thanks for your reply.
>
>
>> If what it is that you want is that an instance of MyClass be created
>> specific for each request, before any URL mapping against methods is
>> being done, then using mod_python.publisher alone the answer is  
>> that no
>> it cannot be done easily. Unless my brain is overlooking something
>> obvious, you have to do something convoluted like:
>>
>> from mod_python import util, apache
>>
>> import types
>>
>> class Wrapper:
>>
>>   def __init__(self,function):
>>     self.__class = function.im_class
>>     self.__name = function.im_func.__name__
>>
>>   def __call__(self,req):
>>     instance = self.__class(req)
>>     function = getattr(instance,self.__name)
>>     return util.apply_fs_data(function,req.form)
>>
>> class MyClass:
>>
>>   def __init__(self,req):
>>     self.__req = req
>>
>>   def method1(self):
>>     return "method1"
>>
>>   def method2(self):
>>     return "method2"
>>
>> class Object: pass
>>
>> index = Object()
>> index.method1 = Wrapper(MyClass.method1)
>> index.method2 = Wrapper(MyClass.method2)
>>
>
>  I tried this wrapper. When I typed URL http://localhost/test.py/ 
> index page
> returned string representation of object so I could write __str__  
> function of
> Object class to make it working.

You are better off defining __call__() for the instance and not  
__str__()
as __call__() still allows you access to form parameters and the request
object. Thus you might have:

   class MyClass:

       ...

       def __call__(self):
           return "__call__"

...

index.__call__ = Wrapper(MyClass.__call__)

> But URLs
> http://localhost/test.py/index/method1 and
> http://localhost/test.py/index/method2 returned errors "Not Found".

You might need to be running mod_python 3.2.5b for it to work, but I  
would not
have expected that to be the case. This code was actual code I tried  
and tested
before I sent it, albeit on mod_python 3.2.5b.

>   Nevertheless I think that functionality of this wrapper was  
> mentioned same
> as functionality of my first example:
>
> class MyClass:
>    def __init__(self):
>       ...
>    def __str__(self):
>      ...
>    def method1(self, req):
>      ...
>    def method2(self, req):
>      ...
>
> index = MyClass():

The code I posted is not the same. In your code, there is one and  
only one
instance of MyClass created and all requested are handled within the
context of the one instance. This instance of MyClass is created at the
time the module is imported and is why it is not possible for the  
request
object to be available to the constructor of the class.

In the code I posted, the Wrapper instance __call__() method is  
called for
each request and an instance of MyClass is created for each request  
which
is received. The distinct request object for each request is passed  
to the
constructor for the instance of MyClass created specifically for each  
request.

> I don't know much about mod_python and its publisher internal  
> function but
> this one works because I think that publisher when parse request  
> URL looks
> first for matching file in web root and then it looks into this  
> file for
> index function or for index object. If index object has defined  
> __str__
> function publisher returns string representation of this object as  
> reply for
> request. If index object has methods and URL is containing  
> identifier of some
> method publisher call it. Repair me if this is bad idea.

More or less. If MyClass provides __call__() it will call that in  
preference to
converting the instance to a string, thus triggering execution of  
__str__().

>> Apart from that, if you were using Vampire, you could simply use  
>> basic
>> handlers are write:
>>
>> import vampire
>>
>> class MyClass:
>>
>>   def __init__(self,req):
>>     self.__req = req
>>
>>   def __call__(self):
>>     return "__call__"
>>
>>   def method1(self):
>>     return "method1",self.__req.filename
>>
>>   def method2(self, req):
>>     return "method2",req.filename
>>
>> handler = vampire.Publisher(MyClass)
>>
>> The vampire.Publisher() wrapper class handlers both creating an  
>> instance
>> of the class and mapping URLs onto methods of the instance. It only
>> supports callable methods in classes though. Ie., it will not map  
>> URLs
>> to __str__() or to basic data types which are a member of the class.
>>
>>
>
> This looks that it cold have functionality I want. But mayby it  
> will be
> sufficent to look how vampire gets request object and write this to  
> MyClass's
> constructor.

It is not that simple. The vampire.Publisher class and the code it  
relies on
to do what it does is not trivial. It in effect implements a complete  
mechanism
for mapping URLs onto objects, much like mod_python.publisher. It isn't
just a few lines that you could emulate.

>> Note that creating an instance of a class per request could be quite
>> inefficient. What is the original reason that you wanted to access  
>> the
>> request object in the constructor in the first place?
>>
>
> I didn' know that when I use
>
> def index(req):
>    instance = MyClass(req)
>
> mod_python creates only one instance of MyClass for every request  
> and when I
> use

It doesn't, it is creating an instance of MyClass per request.

> index = MyClass
>
> it creates instance for each.

You are starting to mix techniques here. If you are actually talking  
about basic
handlers and not mod_python.publisher, you can do this but for your  
MyClass
it will fail. If using basic handlers, you can say:

   class MyClass:

     def __call__(self,req):
         ....

   handler = MyClass

and mod_python will create an instance of MyClass for each request  
and then
call the instance, thus why it must define __call__(). With basic  
handlers as you
seem to realise though, there is no further URL mapping done by  
mod_python.

If using mod_python.publisher, as:

   index = MyClass

you should I believe get NotFound as it will not automatically create  
instances
of classes for you if a class type is referenced. I know Nicolas hand  
it in mind
to perhaps support this, but personally I don't think it is a good  
idea as it could
introduce other problems where people think methods are not  
accessible but
may actually. The authorisation schemes as written also would not  
work for the
instance created. Ie., authorisation could only be done at file scope.

> But creating instance isn't the purpose. Purpose
> is to have page witch is class. Its string representation or its  
> callable
> function returns main content with forms i. e. and its methost handles
> request connected with forms on main page.
>
> Hope that I make my self clear and thanks for response.

Not entirely, you still haven't explicitly said for what reason you  
want to access
the "req" object in the constructor of MyClass, which is basically  
what your original
question was about. If you can specify what information you are  
wanting to get
from the request object in the constructor, can perhaps say why you  
would not
want to do that or how you might do it.

Graham


More information about the Mod_python mailing list