[Zope3-checkins] SVN: Zope3/trunk/src/zope/interface/ Fixed a bug
in the inheritence of interface attribute definitions
Jim Fulton
jim at zope.com
Sat Sep 11 12:27:14 EDT 2004
Log message for revision 27496:
Fixed a bug in the inheritence of interface attribute definitions
Previously, attributes were looked up using a dpeth-first serach of
ancestor interfaces. This is inconsistent with the way that
components are looked up for interfaces (and with the way attributes
are looked up for new-style classes.)
Changed:
U Zope3/trunk/src/zope/interface/README.txt
U Zope3/trunk/src/zope/interface/declarations.py
U Zope3/trunk/src/zope/interface/interface.py
U Zope3/trunk/src/zope/interface/interfaces.py
U Zope3/trunk/src/zope/interface/tests/test_declarations.py
-=-
Modified: Zope3/trunk/src/zope/interface/README.txt
===================================================================
--- Zope3/trunk/src/zope/interface/README.txt 2004-09-10 17:08:49 UTC (rev 27495)
+++ Zope3/trunk/src/zope/interface/README.txt 2004-09-11 16:27:14 UTC (rev 27496)
@@ -90,6 +90,11 @@
>>> x.__doc__
'X blah blah'
+ >>> IFoo.get('x').__name__
+ 'x'
+
+ >>> IFoo.get('y')
+
You can use `in` to determine if an interface defines a name::
>>> 'x' in IFoo
@@ -116,7 +121,7 @@
>>> bar.getSignatureString()
'(q, r=None)'
-XXX
+TODO
Methods really should have a better API. This is something that
needs to be improved.
@@ -459,7 +464,46 @@
>>> list(IBaz.names())
['eek']
+Inheritance if attribute specifications
+---------------------------------------
+An interface may override attribute definitions frob base interfaces.
+If two base interfaces define the same attribute, the attribute is
+inherited from the most specific interface. For example, with:
+
+ >>> class IBase(zope.interface.Interface):
+ ...
+ ... def foo():
+ ... "base foo doc"
+
+ >>> class IBase1(IBase):
+ ... pass
+
+ >>> class IBase2(IBase):
+ ...
+ ... def foo():
+ ... "base2 foo doc"
+
+ >>> class ISub(IBase1, IBase2):
+ ... pass
+
+ISub's definition of foo is the one from IBase2, since IBase2 is more
+specific that IBase:
+
+ >>> ISub['foo'].__doc__
+ 'base2 foo doc'
+
+Note that this differs from a depth-first search.
+
+Sometimes, it's useful to ask whether an interface defines an
+attribute directly. You can use the direct method to get a directly
+defined definitions:
+
+ >>> IBase.direct('foo').__doc__
+ 'base foo doc'
+
+ >>> ISub.direct('foo')
+
Specifications
--------------
Modified: Zope3/trunk/src/zope/interface/declarations.py
===================================================================
--- Zope3/trunk/src/zope/interface/declarations.py 2004-09-10 17:08:49 UTC (rev 27495)
+++ Zope3/trunk/src/zope/interface/declarations.py 2004-09-11 16:27:14 UTC (rev 27496)
@@ -52,72 +52,6 @@
except AttributeError:
pass
- def get():
- marker1 = object()
- marker2 = object()
- def get(self, name, default=None):
- """Query for an attribute description
-
- >>> import zope.interface
- >>> class I1(zope.interface.Interface):
- ... a11 = zope.interface.Attribute('a11')
- ... a12 = zope.interface.Attribute('a12')
- >>> class I2(zope.interface.Interface):
- ... a21 = zope.interface.Attribute('a21')
- ... a22 = zope.interface.Attribute('a22')
- ... a12 = zope.interface.Attribute('a212')
- >>> class I11(I1):
- ... a11 = zope.interface.Attribute('a111')
-
- >>> decl = Declaration(I11, I2)
- >>> decl.get('a11') is I11.get('a11')
- True
- >>> decl.get('a12') is I1.get('a12')
- True
- >>> decl.get('a21') is I2.get('a21')
- True
- >>> decl.get('a22') is I2.get('a22')
- True
- >>> decl.get('a')
- >>> decl.get('a', 42)
- 42
-
- We get None even with no interfaces:
-
- >>> decl = Declaration()
- >>> decl.get('a11')
- >>> decl.get('a11', 42)
- 42
-
- We get new data if e change interface bases:
-
- >>> decl.__bases__ = I11, I2
- >>> decl.get('a11') is I11.get('a11')
- True
- """
- try:
- attrs = self._v_attrs
- except AttributeError:
- attrs = self._v_attrs = {}
- attr = attrs.get(name, marker1)
- if attr is marker1:
- for iface in self:
- attr = iface.get(name, marker2)
- if attr is not marker2:
- break
- else:
- attr = marker2
-
- attrs[name] = attr
-
- if attr is marker2:
- return default
- else:
- return attr
-
- return get
- get = get()
-
def __contains__(self, interface):
"""Test whether an interface is in the specification
Modified: Zope3/trunk/src/zope/interface/interface.py
===================================================================
--- Zope3/trunk/src/zope/interface/interface.py 2004-09-10 17:08:49 UTC (rev 27495)
+++ Zope3/trunk/src/zope/interface/interface.py 2004-09-11 16:27:14 UTC (rev 27496)
@@ -357,8 +357,28 @@
return weakref.ref(self)
else:
return weakref.ref(self, callback)
-
+
+ def get(self, name, default=None):
+ """Query for an attribute description
+ """
+ try:
+ attrs = self._v_attrs
+ except AttributeError:
+ attrs = self._v_attrs = {}
+ attr = attrs.get(name)
+ if attr is None:
+ for iface in self.__iro__:
+ attr = iface.direct(name)
+ if attr is not None:
+ attrs[name] = attr
+ break
+
+ if attr is None:
+ return default
+ else:
+ return attr
+
class InterfaceClass(Element, Specification):
"""Prototype (scarecrow) Interfaces Implementation."""
@@ -495,7 +515,7 @@
def getDescriptionFor(self, name):
"""Return the attribute description for the given name."""
- r = self.queryDescriptionFor(name)
+ r = self.get(name)
if r is not None:
return r
@@ -504,22 +524,14 @@
__getitem__ = getDescriptionFor
def __contains__(self, name):
- return self.queryDescriptionFor(name) is not None
+ return self.get(name) is not None
+ def direct(self, name):
+ return self.__attrs.get(name)
+
def queryDescriptionFor(self, name, default=None):
- """Return the attribute description for the given name."""
- r = self.__attrs.get(name, self)
- if r is not self:
- return r
- for base in self.__bases__:
- r = base.queryDescriptionFor(name, self)
- if r is not self:
- return r
+ return self.get(name, default)
- return default
-
- get = queryDescriptionFor
-
def deferred(self):
"""Return a defered class corresponding to the interface."""
if hasattr(self, "_deferred"): return self._deferred
Modified: Zope3/trunk/src/zope/interface/interfaces.py
===================================================================
--- Zope3/trunk/src/zope/interface/interfaces.py 2004-09-10 17:08:49 UTC (rev 27495)
+++ Zope3/trunk/src/zope/interface/interfaces.py 2004-09-11 16:27:14 UTC (rev 27496)
@@ -264,6 +264,12 @@
If the named attribute is not defined, a KeyError is raised.
"""
+
+ def direct(name):
+ """Get the description for the name if it was defined by the interface
+
+ If the interface doesn't define the name, returns None.
+ """
def validateInvariants(obj, errors=None):
"""Validate invariants
Modified: Zope3/trunk/src/zope/interface/tests/test_declarations.py
===================================================================
--- Zope3/trunk/src/zope/interface/tests/test_declarations.py 2004-09-10 17:08:49 UTC (rev 27495)
+++ Zope3/trunk/src/zope/interface/tests/test_declarations.py 2004-09-11 16:27:14 UTC (rev 27496)
@@ -311,6 +311,48 @@
"""
+def test_declaration_get():
+ """
+ We can get definitions from a declaration:
+
+ >>> import zope.interface
+ >>> class I1(zope.interface.Interface):
+ ... a11 = zope.interface.Attribute('a11')
+ ... a12 = zope.interface.Attribute('a12')
+ >>> class I2(zope.interface.Interface):
+ ... a21 = zope.interface.Attribute('a21')
+ ... a22 = zope.interface.Attribute('a22')
+ ... a12 = zope.interface.Attribute('a212')
+ >>> class I11(I1):
+ ... a11 = zope.interface.Attribute('a111')
+
+ >>> decl = Declaration(I11, I2)
+ >>> decl.get('a11') is I11.get('a11')
+ True
+ >>> decl.get('a12') is I1.get('a12')
+ True
+ >>> decl.get('a21') is I2.get('a21')
+ True
+ >>> decl.get('a22') is I2.get('a22')
+ True
+ >>> decl.get('a')
+ >>> decl.get('a', 42)
+ 42
+
+ We get None even with no interfaces:
+
+ >>> decl = Declaration()
+ >>> decl.get('a11')
+ >>> decl.get('a11', 42)
+ 42
+
+ We get new data if e change interface bases:
+
+ >>> decl.__bases__ = I11, I2
+ >>> decl.get('a11') is I11.get('a11')
+ True
+ """
+
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(Test))
More information about the Zope3-Checkins
mailing list