Merge pull request #9 from headnet/master

Default value provided by subtype field
This commit is contained in:
Malthe Borch 2012-10-26 06:07:20 -07:00
commit fd32e11102
4 changed files with 28 additions and 20 deletions

View File

@ -4,6 +4,10 @@ Changelog
2.0.1 (unreleased)
------------------
- The default attribute accessor now also looks through subtypes
(behaviors) to find a field default.
[malthe]
- Added support in the FTI to look up behaviors by utility name when
getting additional schemata (i.e. fields provided by behaviors).

View File

@ -53,7 +53,6 @@ class FTIAwareSpecification(ObjectSpecificationDescriptor):
"""
def __get__(self, inst, cls=None):
# We're looking at a class - fall back on default
if inst is None:
return getObjectSpecification(cls)
@ -186,7 +185,13 @@ class DexterityContent(DAVResourceMixin, PortalContent, DefaultDublinCoreImpl, C
field = schema.get(name, None)
if field is not None:
return deepcopy(field.default)
# do the same for each subtype
for schema in SCHEMA_CACHE.subtypes(self.portal_type):
field = schema.get(name, None)
if field is not None:
return deepcopy(field.default)
raise AttributeError(name)
# Let __name__ and id be identical. Note that id must be ASCII in Zope 2,
@ -316,16 +321,11 @@ class Container(DAVCollectionMixin, BrowserDefaultMixin, CMFCatalogAware, CMFOrd
setattr(self, k, v)
def __getattr__(self, name):
# attribute was not found; try to look it up in the schema and return
# a default
schema = SCHEMA_CACHE.get(self.portal_type)
if schema is not None:
field = schema.get(name, None)
if field is not None:
return deepcopy(field.default)
try:
return DexterityContent.__getattr__(self, name)
except AttributeError:
pass
# Be specific about the implementation we use
return CMFOrderedBTreeFolderBase.__getattr__(self, name)

View File

@ -77,12 +77,13 @@ class SchemaCache(object):
if cached is None:
subtypes = []
fti = queryUtility(IDexterityFTI, name=portal_type)
if fti is not None:
for behavior_name in fti.behaviors:
behavior = queryUtility(IBehavior, name=behavior_name)
if behavior is not None and behavior.marker is not None:
subtypes.append(behavior.marker)
cached = self.subtypes_cache[portal_type] = tuple(subtypes)
if fti is None:
return ()
for behavior_name in fti.behaviors:
behavior = queryUtility(IBehavior, name=behavior_name)
if behavior is not None and behavior.marker is not None:
subtypes.append(behavior.marker)
cached = self.subtypes_cache[portal_type] = tuple(subtypes)
return cached
@synchronized(lock)

View File

@ -231,7 +231,7 @@ class TestContent(MockTestCase):
pass
class ISubtype(Interface):
pass
baz = zope.schema.TextLine(title=u"baz", default=u"baz")
behavior1 = BehaviorRegistration(u"Behavior1", "", IBehavior1, None, None)
behavior2 = BehaviorRegistration(u"Behavior2", "", IBehavior2, ISubtype, None)
@ -258,7 +258,10 @@ class TestContent(MockTestCase):
# the cache. This is not the case, as evidenced by .count(1) above.
self.assertEquals(True, ISubtype.providedBy(item))
self.assertEquals(True, ISchema.providedBy(item))
# Subtypes provide field defaults.
self.assertEquals(u"baz", getattr(item, "baz", None))
# We also need to ensure that the _v_ attribute doesn't hide any
# interface set directly on the instance with alsoProvides() or
# directlyProvides(). This is done by clearing the cache when these