zope.testbrowser is swallowing imports that confuse you with: TypeError: Error when calling the metaclass bases

Bug #149517 reported by kumar303
2
Affects Status Importance Assigned to Milestone
Zope 3
Status tracked in 3.4
3.4
Fix Released
Undecided
Christian Theune

Bug Description

[Hi benji]

in zope.testbrowser.interfaces, this import statement is swallowed if *either* module does not exist:

try:
    from zope import interface, schema
except ImportError:
    from dummymodule import interface, schema

This creates a very confusing situation if one has zope.interface installed but not zope.schema. In this case, zope.interface is set to dummymodule.interface but only in interfaces.py. So when the class IBrowser is created, it does not inherit from interface.Interface like it should. Now, fast forward to the module zope.testbrowser.browser. Here, zope.interface loads just fine. When class Browser(SetattrErrorsMixin) is instantiated, it says interface.implements(interfaces.IBrowser) but IBrowser is not an interface! The result is a very very confusing traceback that took me an hour to figure out :

Traceback (most recent call last):
...
  File "/Users/kumar/Sites/wsgi_intercept/wsgi_intercept/zope_testbrowser/wsgi_testbrowser.py", line 7, in ?
    from zope.testbrowser.browser import Browser as ZopeTestbrowser
  File "/Library/Frameworks/Python.framework/Versions/2.4/lib/python2.4/site-packages/zope.testbrowser-3.4.1-py2.4.egg/zope/testbrowser/browser.py", line 149, in ?
    class Browser(SetattrErrorsMixin):
  File "/opt/local/lib/python2.4/site-packages/zope/interface/advice.py", line 132, in advise
    return callback(newClass)
  File "/opt/local/lib/python2.4/site-packages/zope/interface/declarations.py", line 488, in _implements_advice
    classImplements(cls, *interfaces)
  File "/opt/local/lib/python2.4/site-packages/zope/interface/declarations.py", line 465, in classImplements
    spec.declared += tuple(_normalizeargs(interfaces))
  File "/opt/local/lib/python2.4/site-packages/zope/interface/declarations.py", line 1372, in _normalizeargs
    _normalizeargs(v, output)
  File "/opt/local/lib/python2.4/site-packages/zope/interface/declarations.py", line 1371, in _normalizeargs
    for v in sequence:
TypeError: Error when calling the metaclass bases
    iteration over non-sequence

The cause is simply that IBrowser is not a descendent of Interface. Doh! That could be explained a little nicer in zope.interface IMHO although there is some recursion that needs to be preserved and it makes my head hurt.

_

In zope.testbrowser I think the best fix for this is to make both of these modules (zope.interface and zope.schema) requirements. I took a stab at simply breaking up the "from zope import interface, schema" so that it imports the dummy interface only for schema but this creates another exception "invalid interface" since the schema calls used to build IBrowser are dummy objects. I suggest biting the bullet and requiring installation of both. Or you could use pkg_resources in the setup file to raise an error if one is installed but not the other.

The change for making them required is the easier route, here is a patch:

Index: src/zope/testbrowser/browser.py
===================================================================
--- src/zope/testbrowser/browser.py (revision 80664)
+++ src/zope/testbrowser/browser.py (working copy)
@@ -26,10 +26,7 @@
 import time
 import urllib2

-try:
- from zope import interface
-except ImportError:
- from dummymodules import interface
+from zope import interface

 RegexType = type(re.compile(''))
 _compress_re = re.compile(r"\s+")
Index: src/zope/testbrowser/interfaces.py
===================================================================
--- src/zope/testbrowser/interfaces.py (revision 80664)
+++ src/zope/testbrowser/interfaces.py (working copy)
@@ -17,11 +17,7 @@
 """
 __docformat__ = "reStructuredText"

-try:
- # zope.interface and zope.schema aren't included in the stand-alone version
- from zope import interface, schema
-except ImportError:
- from dummymodules import interface, schema
+from zope import interface, schema

 class IBrowser(interface.Interface):
Index: setup.py
===================================================================
--- setup.py (revision 80664)
+++ setup.py (working copy)
@@ -48,11 +48,11 @@
     tests_require = ['zope.testing'],
     install_requires = ['setuptools',
                         'mechanize',
- 'ClientForm'],
+ 'ClientForm',
+ 'zope.interface',
+ 'zope.schema'],
     extras_require = dict(
- test = ['zope.interface',
- 'zope.schema',
- 'zope.app.component',
+ test = ['zope.app.component',
                 'zope.app.folder',
                 'zope.app.testing',
                 'zope.app.zcmlfiles',

Revision history for this message
kumar303 (kumar-mcmillan) wrote :

somehow I also felt compelled to submit a patch to address this in zope.interface : https://bugs.launchpad.net/zope3/+bug/149544

...hey, it's Friday and I don't feel like doing any real work :)

Revision history for this message
kumar303 (kumar-mcmillan) wrote :

Hello, has anyone been able to look at this? Is this "Undecided" because making zope.interface and zope.schema requirements would be too big a change? I'm still seeing the confusing error in 3.4.1 (I was confused all over again when I switched to a new system just now).

Revision history for this message
Benji York (benji) wrote : Re: [Bug 149517] Re: zope.testbrowser is swallowing imports that confuse you with: TypeError: Error when calling the metaclass bases

kumar303 wrote:
> Hello, has anyone been able to look at this?

I just tried to apply your patch. I couldn't get it to apply cleanly
against the head or revision 80664. Can you create a branch with the
fix applied instead? That'd be easier to work with. (If you don't have
commit privileges, we can grant them to you.)

> Is this "Undecided"
> because making zope.interface and zope.schema requirements would be too
> big a change?

Nope, just hasn't been decided.

> I'm still seeing the confusing error in 3.4.1 (I was
> confused all over again when I switched to a new system just now).

Generally, I like your solution. I suspect that once we get a working
patch/branch we'll do something very similar (if not identical) to what
you propose.

Revision history for this message
kumar303 (kumar-mcmillan) wrote :

oh, right, the patch was a little out of date. Here is one with the conflicts resolved, applied to trunk r 82096. I couldn't get the tests to run but the changes are minimal so hopefully I didn't break anything ;) I suppose this also invalidates the dummymodules.py module but I didn't delete that in this patch.

Revision history for this message
Benji York (benji) wrote :

kumar303 wrote:
> oh, right, the patch was a little out of date.

It applied cleanly. I just committed revision 82106 should fix this bug.

> I couldn't get the tests
> to run but the changes are minimal so hopefully I didn't break anything
> ;)

There was another problem, I fixed that as well.

> I suppose this also invalidates the dummymodules.py module but I
> didn't delete that in this patch.

It did, so I removed it.

Thanks for working on this!
--
Benji York
Senior Software Engineer
Zope Corporation

Benji York (benji)
Changed in zope3:
assignee: nobody → benji-york
status: New → Fix Committed
Revision history for this message
Claus Conrad (cconrad) wrote :

Thanks to the original poster, this helped me solve the problem.

Revision history for this message
Christian Theune (ctheune) wrote :

We'll backport this.

Revision history for this message
Christian Theune (ctheune) wrote :

Darn. Darn. This is tracked under the Zope 3 project, not its own. Well. We'll create a backported 3.4.3 anyways.

Revision history for this message
Wolfgang Schnerring (wosc) wrote :

released as zope.testbrowser-3.5.0

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.