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

Reply via email to