Go to Google Groups Home    cherrypy-devel
Re: getitem access / parameter usage

Remco Boerma <remco.boe...@gmail.com>

Carlos Ribeiro wrote:
>It's an interesting generalization. getitem checking also works on
>dicts, so /foo/anything could be mapped to cpg.root.foo[anything]
>(where foo is a dict). We have to keep in mind that this may also
>cause some undesirable side effects as far as the current lookup
>works; if we can be sure that no such side effect exists, I'm +1 on
>it. If there's any side effect, -1.

Here is some strange behaviour:

 >>> d = {}
 >>> d.exposed = True
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'dict' object has no attribute 'exposed'
 >>> print getattr(d,'exposed')
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'dict' object has no attribute 'exposed'
 >>>

So checking if there is an exposed, would raise an error itself! (as it
should provide None as default)
So we'll have to use other means of checking, or we can't use
dictionaries right away. and keeping them all opened, doesn't seem safe
to me.

>(on the other hand, it can be argued that the user himself can convert
>the objects published to support getattr; for example, nothing stops a
>UserList or UserDict to support getattr with similar results to the
>ones achieved by getitem with similar arguments.)

Like i did in the ticket. With full control. We might write a recipe
about it, but i don't think it's something
to handle in the core. .

>This ticket also raises an interesting discussion: today it's
>difficult for a user to override the existing object mapping function.
>The current function is inside a module, and the only way to override
>it is to do some black magic and rebind the symbol inside the module
>to a new function. I guess we could make it a little bit easier to
>register such functions. One possibility is to bind such utility
>symbols directly to the cpg structure, at its top level; in this way
>it would be easier for the user to customize or override it.

Do we need to support that? If a user wants this to be changed, why
can't he/she change the core code?
It's a python module!! I don't think we need to , unless the need really
arises . .

>cpg.mapPathToObject = myObjMapperFunction

Well, i don't see the need that much, but if we will change the
structure for calling, i would be favouring this. . .

But i simply question how many people will be changing this.. Most of it
can be done using regular cp2 'pages'.

The ticket gave me another question:

This one bit me not long ago. .i'm trying to reconstruct the problem
while i'm at it. So if you don't have much time:
skip the rest of the email.

/Summary: it shows some odd behaviour using index, default and regular
methods.../
<flames state=off>
<start of large post about parameter usage. . if anyone can use this for
documentation purposes; go ahead>

What should, and will hapen using the following:
class Root(object);
    def index(self,*p):
          if p:
              print `p`
          else:
              print 'index!'
     index.exposed = True
cpg.root = Root()

Ok. if i go to "http://localhost'"  or http://localhost/" i will see
"index!" if i add anything to the location bar, it will fail:
http://localhost/bla/pir:

Traceback (most recent call last):
  File "C:\module\cp2\cherrypy\_cphttptools.py", line 206, in doRequest
    handleRequest(wfile)
  File "C:\module\cp2\cherrypy\_cphttptools.py", line 372, in handleRequest
    func, objectPathList, virtualPathList = mapPathToObject()
  File "C:\module\cp2\cherrypy\_cphttptools.py", line 504, in mapPathToObject
    raise cperror.NotFound # We didn't find anything
NotFound

So that doesn't work?!

now i add root.bla similar to index. .
    def bla(self,*p):
        if p:
            return  `p`
        else:
            return 'bla'
    bla.exposed = True

Okay. here goes: http://localhost/bla and http://localhost/bla/ work
fine. . it displays "bla". .
and going to /bla/pir shows ('pir',)  .. perfect!! _So something is
wrong with index?_. .

Now.

If if would change the bla, to expect 1 parameter, wich i would like to
be defaulted, it's becoming a keyword parameter.
 >>> bla()
 >>> def bla(first='first',*p):
...    print first,p
...
 >>> bla('pir')
pir ()
 >>>

that's nice. . (though one might not expect this to happen, as it's a
keyword parameter, but i like the behaviour)
So here's my new bla:
    def bla(self,first='first',*p):
        return  `first`,`p`
    bla.exposed = True

/bla returns ; ("'first'", '()')
/bla/pir/feedz/iz/doe returns ("'pir'", "('feedz', 'iz', 'doe')")
exactly what i want it to. .

Back to index.. .

i'll replace my index method with the following;
    def index(self,first='first',*p):
        return  `first`,`p`
    index.exposed = True

http://localhost:9000/index and http://localhost:9000/ both return:
("'first'", '()')
But if i move to /someothername it will crash, telling me:

Traceback (most recent call last):
  File "C:\module\cp2\cherrypy\_cphttptools.py", line 206, in doRequest
    handleRequest(wfile)
  File "C:\module\cp2\cherrypy\_cphttptools.py", line 372, in handleRequest
    func, objectPathList, virtualPathList = mapPathToObject()
  File "C:\module\cp2\cherrypy\_cphttptools.py", line 504, in mapPathToObject
    raise cperror.NotFound # We didn't find anything
NotFound

So we introduce root.default. . . This clearly solves the problem.
    def default(self,first='first',*p):
        return  'default:',`first`,`p`
    default.exposed = True

This solves nearly all of my problems!! now i will just delete the
root.index, cause my default is the catch all (i assume)..
Now, all unkown pages, i except to be cought by the default. . . this
would be perfect!!  (i was writing a wiki at the time,
so going to /wiki would come up with the wiki's frontpage.. that would
be nice. . but. .
no, this doesn't work. . if i go to http://localhost/ and i have no
root.index, i'm lost . . It is not caught by the default!!
so _default is not run when there is no root.index and the index would
be run if it was there..._!

Traceback (most recent call last):
  File "C:\module\cp2\cherrypy\_cphttptools.py", line 206, in doRequest
    handleRequest(wfile)
  File "C:\module\cp2\cherrypy\_cphttptools.py", line 372, in handleRequest
    func, objectPathList, virtualPathList = mapPathToObject()
  File "C:\module\cp2\cherrypy\_cphttptools.py", line 504, in mapPathToObject
    raise cperror.NotFound # We didn't find anything
NotFound

so now i need to redirect my root.index to root.default. . .
a. - how do i do it simple, if default would use generators (thus return
a generator) ?  cause
      root.index(self): return self.default() would clearly not be a
sollution then
b. - _can't default become the catch all, even for missing indexes_? As
i thing this behaviour would be more 'natural' and expected.

</start of large post about parameter usage. . if anyone can use this
for documentation purposes; go ahead>
</flames>

I hope this can serve both for documentation purposes, as well as for
feature request/bugreport . . .

and (okay, flame me for starting this infamous debate again). . .
_if default would become the catch all, even for missing indexes, can't
we simply drop default, and have index have the default behaviour as well?
_I think it would be much simpler then. .

Cheers!
Remco