[Checkins] SVN: z3c.form/trunk/ Fix deep and unpleasant bug relating to getSpecification. Maybe a little less magic next time? ; -)
Martin Aspeli
optilude at gmx.net
Tue Mar 9 09:31:11 EST 2010
Log message for revision 109870:
Fix deep and unpleasant bug relating to getSpecification. Maybe a little less magic next time? ;-)
Changed:
U z3c.form/trunk/CHANGES.txt
U z3c.form/trunk/src/z3c/form/util.py
U z3c.form/trunk/src/z3c/form/util.txt
-=-
Modified: z3c.form/trunk/CHANGES.txt
===================================================================
--- z3c.form/trunk/CHANGES.txt 2010-03-09 10:32:36 UTC (rev 109869)
+++ z3c.form/trunk/CHANGES.txt 2010-03-09 14:31:11 UTC (rev 109870)
@@ -5,6 +5,15 @@
2.3.3 (unreleased)
------------------
+- Don't let util.getSpecification() generate an interface more than once.
+ This causes strange effects when used in value adapters: if two adapters
+ use e.g. ISchema['some_field'] as a "discriminator" for 'field', with one
+ adapter being more specific on a discriminator that comes later in the
+ discriminator list (e.g. 'form' for an ErrorViewMessage), then depending on
+ the order in which these two were set up, the adapter specialisation may
+ differ, giving unexpected results that make it look like the adapter
+ registry is picking the wrong adapter.
+
- Fix trivial test failures on Python 2.4 stemming from differences in
pprint's sorting of dicts.
Modified: z3c.form/trunk/src/z3c/form/util.py
===================================================================
--- z3c.form/trunk/src/z3c/form/util.py 2010-03-09 10:32:36 UTC (rev 109869)
+++ z3c.form/trunk/src/z3c/form/util.py 2010-03-09 14:31:11 UTC (rev 109870)
@@ -56,13 +56,24 @@
(spec is not None and
not zope.interface.interfaces.ISpecification.providedBy(spec)
and not isinstance(spec, classTypes)) ):
- # Step 1: Create an interface
- iface = zope.interface.interface.InterfaceClass(
- 'IGeneratedForObject_%i' %hash(spec))
- # Step 2: Directly-provide the interface on the specification
- zope.interface.alsoProvides(spec, iface)
- # Step 3: Make the new interface the specification for this instance
- spec = iface
+
+ # Step 1: Calculate an interface name
+ ifaceName = 'IGeneratedForObject_%i' %hash(spec)
+
+ # Step 2: Find out if we already have such an interface
+ existingInterfaces = [
+ i for i in zope.interface.directlyProvidedBy(spec)
+ if i.__name__ == ifaceName
+ ]
+
+ # Step 3a: Return an existing interface if there is one
+ if len(existingInterfaces) > 0:
+ spec = existingInterfaces[0]
+ # Step 3b: Create a new interface if not
+ else:
+ iface = zope.interface.interface.InterfaceClass(ifaceName)
+ zope.interface.alsoProvides(spec, iface)
+ spec = iface
return spec
Modified: z3c.form/trunk/src/z3c/form/util.txt
===================================================================
--- z3c.form/trunk/src/z3c/form/util.txt 2010-03-09 10:32:36 UTC (rev 109869)
+++ z3c.form/trunk/src/z3c/form/util.txt 2010-03-09 14:31:11 UTC (rev 109870)
@@ -396,3 +396,50 @@
True
That's all.
+
+`getSpecification()` function
+-----------------------------
+
+This function is capable of returning an `ISpecification` for any object,
+including instances.
+
+For an interface, it simply returns the interface:
+
+ >>> import zope.interface
+ >>> class IFoo(zope.interface.Interface):
+ ... pass
+
+ >>> util.getSpecification(IFoo) == IFoo
+ True
+
+Ditto for a class:
+
+ >>> class Bar(object):
+ ... pass
+
+ >>> util.getSpecification(Bar) == Bar
+ True
+
+For an instance, it will create a marker interface on the fly if necessary:
+
+ >>> bar = Bar()
+ >>> util.getSpecification(bar) # doctest: +ELLIPSIS
+ <InterfaceClass z3c.form.util.IGeneratedForObject_...>
+
+The ellipsis represents a hash of the object.
+
+If the function is called twice on the same object, it will not create a new
+marker each time:
+
+ >>> baz = Bar()
+ >>> barMarker = util.getSpecification(bar)
+ >>> bazMarker1 = util.getSpecification(baz)
+ >>> bazMarker2 = util.getSpecification(baz)
+
+ >>> barMarker is bazMarker1
+ False
+
+ >>> bazMarker1 == bazMarker2
+ True
+ >>> bazMarker1 is bazMarker2
+ True
More information about the checkins
mailing list