[Zope-CMF] CMFDefault.utils is not monkey-patchable

Paul Winkler pw_lists@slinkp.com
Wed, 13 Nov 2002 09:16:07 -0800


On Wed, Nov 13, 2002 at 01:44:32PM +0000, Chris Withers wrote:
> Paul Winkler wrote:
> ><rant>
> >I like doing "monkey patches" to change default behavior
> >of downloaded Zope products without having to build
> >wrapper products or patch the actual source.
> 
> Ah, many other people see them as 'bad' ;-)

I see it as one of the chief advantages of a highly
dynamic language. But i'm interested to hear
why people see monkeypatches as bad. References?

> >>>>import Products.CMFDefault.utils
> >>>>hasattr(Products.CMFDefault.utils, 'scrubHTML')
> >>>
> >0
> 
> Why does that matter?

It's normal to expect the following two idioms to 
have an equivalent effect:

import A.B.C;  D = A.B.C.D
from A.B.C import D

This is not the case with CMFDefault.utils.

With CMFDefault.utils, the former idiom
will always raise an AttributeError unless D
exists in CMFCore.utils, because "import Products.CMFDefault.utils" 
is sneakily giving you Products.CMFCore.utils instead.
So NOTHING that you find in CMFDefault/utils.py can be
used with the former idiom, because the two utils.py
do not define any of the same names.

This is sufficiently confusing that I stand by
my assertion that it is Bad and Wrong. :-)

Don't believe me? Ask the interpreter.

>>> from Products.CMFDefault import utils
>>> scrubHTML = utils.scrubHTML
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'Products.CMFCore.utils' module has no attribute 'scrubHTML'
>>> utils.__name__
'Products.CMFCore.utils'
>>> from Products.CMFDefault.utils import scrubHTML
>>>


Look at that and tell me there's nothing wrong with it.


As for the "from foo import bar" idiom...

> No its not. It's generally the recommended way of bringing in oftne used 
> names from other modules and packages.

OK, I went too far. "from foo import bar" is common; what IS generally
frowned on in most cases is "from foo import *".

I do think that "generally the recommended way" is not accurate either:

>From the python FAQ, q 4.17: 
"""...  Guido van Rossum recommends to avoid all uses of 
from <module> import ..." (so everything from an imported module 
is referenced as <module>.<name> """


Let's say it's nearly always a matter of taste, and leave it
at that.  In the Python Tutorial, section 6.4.1, I found this
illuminating passage:


""" there is nothing wrong with using from Package import specific_submodule! 
In fact, this is the recommended notation unless the importing module 
                                          ^^^^^^
needs to use submodules with the same name from different packages.
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"""

CMFCore/utils.py hides CMFDefault/utils.py.
This is my real problem.  Either they should not have the same
name, or CMFDefault/__init__.py should not do:
from Products.CMFCore import utils

A quick recursive grep for "utils" in CMFDefault
suggests that it *might* be that this line in __init__.py
is merely a convenience and does not affect
any other modules.  So all the lines in __init__.py
of the form utils.initializeBasesPhase2(...)
could be safely replaced with
CMFCore.utils.initializeBasesPhase2(...)

I will change this locally and see if it hurts anything,
and report back.

> I still fail to see what your problem actually.
> 
> Does:
> 
> Products.CMFDefault.utils.scrubHTML = xxx
> 
> not work?

It does not work.
That assignment creates Products.CMFCore.utils.scrubHTML,
and anything that does "from Products.CMFDefaults.utils import scrubHTML"
still gets the old one. If you don't believe me, ask the interpreter.


--

Paul Winkler
http://www.slinkp.com
"Welcome to Muppet Labs, where the future is made - today!"