[mod_python] "TypeError: argument 2 must be a mapping" and other things

Jorey Bump list at joreybump.com
Wed Sep 21 09:47:20 EDT 2005


Daniel Winkler wrote:

> index.py: ***********************************
> 
> from mod_python import psp
> import dirigent

What's in dirigent?

> import chor
> [...]
> 
> def startseite(req, chorid=0): #called startseite?chorid=1 or so

I prefer to get form variables and query string arguments from req.form. 
  Pass req around to your functions and test for the presence of the 
variable:

def check(req):
     if req.form.has_key('chorid'):
         ...do stuff

Note that if a variable appears multiple times in the form and/or the 
querystring, it will be returned as a list. If this is a possibility, 
your code needs to check for it and process it accordingly.

>     dirigent.id = dirigent.ermittle_dirigent(req)
>     chor.id = chor.ermittle_chor(chorid, dirigent.id)
> [...]

Things like this will work consistently in the interpreter, but not in 
all apache MPMs. Do you really need to alter this module attribute in 
place? I'd look for an alternative, as it's not reliable across 
environments. Can you simply store it in a normal variable within the 
function, and return it or process it further?

     d = dirigent.ermittle_dirigent(req)
     c = chor.ermittle_chor(chorid, d)
     ...do stuff with c and d
     return stuff

> datenbank.py: ********************************
> 
> import MySQLdb
> db = MySQLdb.connect(host="localhost",
>                      user="chordb",
>                      passwd="somethingsecret",
>                      db="chordatenbank")
> 
> 
> chor.py: *************************************
> 
> from datenbank import db

This looks good, so far. You'll get some reuse from the db handle.

> [...]
> 
> id = 0

If your code depends on this being updated externally and accessed 
globally by other modules, it might be where the problem is.

> def _acltest_ok(chorID, dirigentID):

Try setting defaults here, just in case:

def _acltest_ok(chorID = 0, dirigentID = 0):

But I'm getting the sense that dirigentID may be the suspect. It's 
interesting that you're trying to set dirigent.id globally, but don't 
attempt to take advantage of it here. While I'm not advocating it, why 
aren't you importing dirigent.id directly, instead of passing it as an 
argument?

>     acl = db.cursor()
> (*) acl.execute("SELECT chor FROM acl WHERE chor = %s AND dirigent = %s", (chorID, dirigentID))
>     return (int(acl.rowcount) > 0)
> 
> 
> def ermittle_chor(chorID, dirigentID):
>     if ( (chorID > 0)
>          and _acltest_ok(chorID, dirigentID) ):
>         return chorID
>     else:
>         choere = db.cursor()
> (*)     choere.execute("SELECT chor FROM acl WHERE dirigent = %s;", (dirigentID))
> 
>         if int(choere.rowcount) == 1:
>             chor = choere.fetchone()
>             return chor[0]
>         else:
>             return 0
> 
> 
> The (*) marked lines are those where the error occurs most at the
> moment. E.g.:
> 
> ******************************************
> od_python error: "PythonHandler mod_python.publisher"
> 
> Traceback (most recent call last):
> 
>   File "/usr/lib/python2.3/site-packages/mod_python/apache.py", line 299, in HandlerDispatch
>     result = object(req)
> 
>   File "/usr/lib/python2.3/site-packages/mod_python/publisher.py", line 136, in handler
>     result = util.apply_fs_data(object, req.form, req=req)
> 
>   File "/usr/lib/python2.3/site-packages/mod_python/util.py", line 361, in apply_fs_data
>     return object(**args)
> 
>   File "<somewhere>/index.py", line 49, in lied
>     chor.id = chor.ermittle_chor(chorid, dirigent.id)
> 
>   File "<somewhere>/chor.py", line 18, in ermittle_chor
>     if ( (chorID > 0)
> 
>   File "<somewhere>/chor.py", line 11, in _acltest_ok
>     acl.execute("SELECT chor FROM acl WHERE chor = %s AND dirigent = %s", (chorID, dirigentID))
> 
>   File "/usr/lib/python2.3/site-packages/MySQLdb/cursors.py", line 132, in execute
>     self.errorhandler(self, TypeError, m)
> 
>   File "/usr/lib/python2.3/site-packages/MySQLdb/connections.py", line 33, in defaulterrorhandler
>     raise errorclass, errorvalue
> 
> TypeError: argument 2 must be a mapping
> *********************************
> 
> The first time I load the page, everything is fine. This error occurs
> after the first or second page reload (same code, same parameters).
> Don't ask me why ...
> 
> I had even more strange errors like "syntax errors" in a line called
> "c = 1" in a PSP file, but I cannot reproduce them at the moment. (maybe
> after the problem above is fixed :-)
> BTW, I am new to Python so if you have additional hints what can be done
> better: everything is welcome.
> Okay, yes, I know that global variables aren't very nice, but I thought
> it is not necessary to build a class just for one object ... ;-)

You may not get the same results from your attempts to set globals in 
mod_python as you would in the interpreter. You definitely can't rely on 
this method across platforms for truly global values, so I'd abandon it 
and use a persistent storage mechanism.

Also, your logic is a little circuitous, and you've mixed ways of 
dealing with what you expect to be the same variables. Try to be more 
consistent with how you pass variables (use only req.form for variables 
coming from the browser, for example) and with your naming of them 
(permutations on chorid, chorID, etc. aren't necessary when the scoping 
rules handle this automatically for you), which will make your code a 
little more readable and easier to debug.

Just some suggestions, I hope they are helpful.




More information about the Mod_python mailing list