ProtocolSubsets |
UserPreferences |
The PEAK Developers' Center | FrontPage | RecentChanges | TitleIndex | WordIndex | SiteNavigation | HelpContents |
I originally posted this here but figured it would be good netiquette to re-post the details of it on this wiki :-) Comments/corrections greatly appreciated.
If you have code similar to the following, which produces a "?TypeError" with an "Ambiguous adapter choice" error message, you are missing an adapter that makes the choice unambiguous:
1 #!/usr/bin/env python 2 3 import protocols 4 5 class IBase(protocols.Interface): 6 pass 7 class IWhy(IBase): 8 pass 9 class IZee(IBase): 10 pass 11 12 class X(object): 13 value = 'foo' 14 class Y(object): 15 protocols.advise(instancesProvide=[IWhy]) 16 def __init__(self, ob): 17 self.value = ob.value + 'bar' 18 class Z(object): 19 protocols.advise(instancesProvide=[IZee]) 20 def __init__(self, ob): 21 self.value = ob.value + 'baz' 22 23 protocols.declareAdapter(factory=Y, provides=[IWhy], forTypes=[X]) 24 protocols.declareAdapter(factory=Z, provides=[IZee], forTypes=[X]) 25 26 x = X(); print 'x', x.value 27 y = IWhy(x); print 'y', y.value 28 z = IZee(x); print 'z', z.value
By adding this adapter *above* the other two adapters, you make the adapter choices unambiguous: (In this case, we do not want to allow adapting type X to interface IBase)
protocols.declareAdapter( factory=protocols.DOES_NOT_SUPPORT, provides=[IBase], forTypes[X], )
What you DO NOT WANT TO DO is to make subsets of the base interface. Even though this makes adapter choices unambiguous, it still has the opposite effect of what you might have intended. Do not use the following pattern to fix the problem described above. See Phillip Eby's comments on the original post linked to above for a more thorough explanation.
1 #!/usr/bin/env python 2 3 import protocols 4 5 class IBase(protocols.Interface): 6 pass 7 class IWhy(protocols.Interface): 8 protocols.advise(protocolIsSubsetOf=[IBase]) 9 class IZee(protocols.Interface): 10 protocols.advise(protocolIsSubsetOf=[IBase]) 11 12 class X(object): 13 value = 'foo' 14 class Y(object): 15 protocols.advise(instancesProvide=[IWhy]) 16 def __init__(self, ob): 17 self.value = ob.value + 'bar' 18 class Z(object): 19 protocols.advise(instancesProvide=[IZee]) 20 def __init__(self, ob): 21 self.value = ob.value + 'baz' 22 23 protocols.declareAdapter(factory=Y, provides=[IWhy], forTypes=[X]) 24 protocols.declareAdapter(factory=Z, provides=[IZee], forTypes=[X]) 25 26 x = X(); print 'x', x.value 27 y = IWhy(x); print 'y', y.value 28 z = IZee(x); print 'z', z.value