I do not have immediate comment on what you're doing, but I do have a tangential comment:
Never having looked at the mod_python.util.fs_apply_data code, your email prompted me to. I noticed that the code uses "object" as a function argument name. While this works, shouldn't the argument name be changed to "obj" or something else? While "object" is not a python keyword it is the name of the superclass of new-style classes. I was very confused reading your sample code below until I realized the overloading. Also, and most annoying, emacs highlights "object" everywhere in fs_apply_data as a keyword. :-) Not exactly a bug. An obfuscation? Daniel Popowich ----------------------------------------------- http://home.comcast.net/~d.popowich/mpservlets/ Graham Dumpleton writes: > Have a strange patch here for consideration. > > In CherryPy, one can manually construct the page hierarchy by writing: > > cpg.root.onepage = OnePage() > cpg.root.otherpage = OtherPage() > > cpg.root.some = Page() > cpg.root.some.page = Page() > > The closest equivalent to this in mod_python is the publisher handler, > whereby a URL will be mapped to attributes and member functions of a > class. One generally though has to create an actual class to encapsulate > all the bits together. > > One can to a degree with publisher create a mapping without creating a > proper class by using: > > class _Mapping: > pass > > def _method1(): > return "_method1" > > def _method2(): > return "_method2" > > object = _Mapping() > object.onepage = _method1 > object.otherpage = _method2 > > What isn't possible though without creating a real class is have a > normal function which is called when the dummy mapping object itself > is the target. Ie., following does not work: > > object.__call__ = _method1 > > This is because util.apply_fs_data() assumes that __call__() is always > an object method. > > I know this is sort of an abuse of __call__(), but it does actually > work in Python itself, just not in mod_python when URLs are mapped to > object. > > >>> class A: > ... pass > ... > >>> def _method(): > ... return "method" > ... > >>> a=A() > >>> a.__call__ = _method > >>> > >>> a() > 'method' > > Anyway, I have attached a patch which would allow this sort of thing to > actually work within mod_python. > > I feel it could be a useful way of quickly constructing special object > hierarchies from other functions, objects and attributes without having > to actually create real classes. > > For example: > > def _method(): > return "method" > > class _Mapping: > pass > > _subdir1 = _Mapping() > _subdir1.__call__ = _method # .../root/subdir1 > _subdir1.page1 = _method # .../root/subdir1/page1 > _subdir1.page2 = _method # .../root/subdir1/page2 > > root = _Mapping() > root.__call__ = _method # .../root > root.page1 = _method # .../root/page1 > root.subdir1 = _subdir1 > > Comments? > > Index: lib/python/mod_python/util.py > =================================================================== > --- lib/python/mod_python/util.py (revision 231212) > +++ lib/python/mod_python/util.py (working copy) > @@ -371,20 +371,6 @@ > then call the object, return the result. > """ > > - # add form data to args > - for field in fs.list: > - if field.filename: > - val = field > - else: > - val = field.value > - args.setdefault(field.name, []).append(val) > - > - # replace lists with single values > - for arg in args: > - if ((type(args[arg]) is ListType) and > - (len(args[arg]) == 1)): > - args[arg] = args[arg][0] > - > # we need to weed out unexpected keyword arguments > # and for that we need to get a list of them. There > # are a few options for callable objects here: > @@ -409,9 +395,27 @@ > expected = [] > elif hasattr(object, '__call__'): > # callable object > - fc = object.__call__.im_func.func_code > - expected = fc.co_varnames[1:fc.co_argcount] > + if type(object.__call__) is MethodType: > + fc = object.__call__.im_func.func_code > + expected = fc.co_varnames[1:fc.co_argcount] > + else: > + # abuse of objects to create hierarchy > + return apply_fs_data(object.__call__, fs, **args) > > + # add form data to args > + for field in fs.list: > + if field.filename: > + val = field > + else: > + val = field.value > + args.setdefault(field.name, []).append(val) > + > + # replace lists with single values > + for arg in args: > + if ((type(args[arg]) is ListType) and > + (len(args[arg]) == 1)): > + args[arg] = args[arg][0] > + > # remove unexpected args unless co_flags & 0x08, > # meaning function accepts **kw syntax > if fc is None: > > > Graham