|
|
@@ -3,124 +3,82 @@
|
|
|
import DirectNotifyGlobal
|
|
|
import types
|
|
|
import AttribDesc
|
|
|
-import EntityTypes
|
|
|
+import EntityTypeDesc
|
|
|
from PythonUtil import mostDerivedLast
|
|
|
|
|
|
class EntityTypeRegistry:
|
|
|
notify = DirectNotifyGlobal.directNotify.newCategory('EntityTypeRegistry')
|
|
|
|
|
|
- def __init__(self, entityTypeModule=EntityTypes):
|
|
|
- """pass in a module that contains EntityType classes"""
|
|
|
- # get a list of the entity type classes in the type module
|
|
|
+ def __init__(self, entityTypeModule):
|
|
|
+ """pass in a module that contains EntityTypeDesc classes"""
|
|
|
+ # get a list of the EntityTypeDesc classes in the type module
|
|
|
classes = []
|
|
|
for key, value in entityTypeModule.__dict__.items():
|
|
|
if type(value) is types.ClassType:
|
|
|
- if issubclass(value, EntityTypes.Entity):
|
|
|
+ if issubclass(value, EntityTypeDesc.EntityTypeDesc):
|
|
|
classes.append(value)
|
|
|
|
|
|
- # put derived classes after their bases
|
|
|
- mostDerivedLast(classes)
|
|
|
+ self.entTypeName2typeDesc = {}
|
|
|
|
|
|
- # scrub through the class heirarchy and compile complete
|
|
|
- # attribute descriptor lists for each concrete Entity type class
|
|
|
- typeName2class = {}
|
|
|
+ # create an instance of each EntityType class with a typename
|
|
|
+ # make sure that derived classes come after bases
|
|
|
+ mostDerivedLast(classes)
|
|
|
for c in classes:
|
|
|
- # if this is a concrete Entity type, add it to the dict
|
|
|
if c.__dict__.has_key('type'):
|
|
|
- if typeName2class.has_key(c.type):
|
|
|
- EntityTypeRegistry.notify.debug(
|
|
|
- "replacing %s with %s for type '%s'" %
|
|
|
- (typeName2class[c.type], c, c.type))
|
|
|
- typeName2class[c.type] = c
|
|
|
-
|
|
|
- self.privCompileAttribDescs(c)
|
|
|
-
|
|
|
- # maps entity typename to ordered list of attrib names
|
|
|
- self.typeName2attribNames = {}
|
|
|
- # maps entity typename to dict of attrib name -> attrib descriptor
|
|
|
- self.typeName2attribDescDict = {}
|
|
|
-
|
|
|
- for typeName, c in typeName2class.items():
|
|
|
- self.typeName2attribNames[typeName] = []
|
|
|
- self.typeName2attribDescDict[typeName] = {}
|
|
|
-
|
|
|
- # ordered list of attrib descriptors
|
|
|
- attribDescs = c._attribDescs
|
|
|
-
|
|
|
- for desc in attribDescs:
|
|
|
- attribName = desc.getName()
|
|
|
- self.typeName2attribNames[typeName].append(attribName)
|
|
|
- self.typeName2attribDescDict[typeName][attribName] = desc
|
|
|
-
|
|
|
- def getAttribNames(self, entityTypeName):
|
|
|
- """ returns ordered list of attribute names for entity type """
|
|
|
- assert entityTypeName in self.typeName2attribNames
|
|
|
- return self.typeName2attribNames[entityTypeName]
|
|
|
-
|
|
|
- def getAttribDescDict(self, entityTypeName):
|
|
|
- """ returns dict of attribName -> attribDescriptor """
|
|
|
- assert entityTypeName in self.typeName2attribDescDict
|
|
|
- return self.typeName2attribDescDict[entityTypeName]
|
|
|
+ if self.entTypeName2typeDesc.has_key(c.type):
|
|
|
+ # a more-derived class is replacing a less-derived class
|
|
|
+ # to implement a particular entity type
|
|
|
+ EntityTypeRegistry.notify.info(
|
|
|
+ "replacing %s with %s for entity type '%s'" %
|
|
|
+ (self.entTypeName2typeDesc[c.type].__class__,
|
|
|
+ c, c.type))
|
|
|
+ self.entTypeName2typeDesc[c.type] = c()
|
|
|
+
|
|
|
+ # create mapping of entity output types to list of concrete entity
|
|
|
+ # typenames with that output type
|
|
|
+ self.output2typeNames = {}
|
|
|
+ for typename, typeDesc in self.entTypeName2typeDesc.items():
|
|
|
+ if typeDesc.isConcrete():
|
|
|
+ if hasattr(typeDesc, 'output'):
|
|
|
+ outputType = typeDesc.output
|
|
|
+ self.output2typeNames.setdefault(outputType, [])
|
|
|
+ self.output2typeNames[outputType].append(typename)
|
|
|
+
|
|
|
+ # create mapping of entity typename (abstract or concrete) to list
|
|
|
+ # of entity typenames are concrete and are of that type or derive
|
|
|
+ # from that type
|
|
|
+ self.typeName2derivedTypeNames = {}
|
|
|
+ for typename, typeDesc in self.entTypeName2typeDesc.items():
|
|
|
+ typenames = []
|
|
|
+ for tn, td in self.entTypeName2typeDesc.items():
|
|
|
+ if td.isConcrete():
|
|
|
+ if issubclass(td.__class__, typeDesc.__class__):
|
|
|
+ typenames.append(tn)
|
|
|
+ self.typeName2derivedTypeNames[typename] = typenames
|
|
|
+
|
|
|
+ def getTypeDesc(self, entTypeName):
|
|
|
+ """returns EntityTypeDesc instance for concrete Entity type"""
|
|
|
+ assert entTypeName in self.entTypeName2typeDesc,\
|
|
|
+ "unknown entity type '%s'" % entTypeName
|
|
|
+ # the table has descriptors for abstract entity types, but I don't
|
|
|
+ # think there's any need for anyone outside this class to access them
|
|
|
+ assert self.entTypeName2typeDesc[entTypeName].isConcrete(),\
|
|
|
+ "entity type '%s' is abstract" % entTypeName
|
|
|
+ return self.entTypeName2typeDesc[entTypeName]
|
|
|
+
|
|
|
+ def getTypeNamesFromOutputType(self, outputType):
|
|
|
+ """return Entity typenames for Entity types with particular output"""
|
|
|
+ return self.output2typeNames.get(outputType, [])
|
|
|
+
|
|
|
+ def getDerivedTypeNames(self, entTypeName):
|
|
|
+ """return Entity typenames that are of or derive from an entity type,
|
|
|
+ which may be concrete or abstract"""
|
|
|
+ assert entTypeName in self.typeName2derivedTypeNames,\
|
|
|
+ "unknown entity type '%s'" % entTypeName
|
|
|
+ return self.typeName2derivedTypeNames[entTypeName]
|
|
|
|
|
|
def __hash__(self):
|
|
|
- return hash(str(self))
|
|
|
- def __str__(self):
|
|
|
- return str(self.typeName2attribNames)+str(self.typeName2attribDescDict)
|
|
|
-
|
|
|
- def privCompileAttribDescs(self, entTypeClass):
|
|
|
- # has someone already compiled the info?
|
|
|
- if entTypeClass.__dict__.has_key('_attribDescs'):
|
|
|
- return
|
|
|
-
|
|
|
- c = entTypeClass
|
|
|
- EntityTypeRegistry.notify.debug('compiling attrib descriptors for %s' %
|
|
|
- c.__name__)
|
|
|
-
|
|
|
- # make sure all of our base classes have their complete list of
|
|
|
- # attribDescs
|
|
|
- for base in c.__bases__:
|
|
|
- self.privCompileAttribDescs(base)
|
|
|
-
|
|
|
- # aggregate the attribute descriptors from our direct base classes
|
|
|
- delAttribs = c.__dict__.get('delAttribs', [])
|
|
|
- baseADs = []
|
|
|
-
|
|
|
- bases = list(c.__bases__)
|
|
|
- # make sure that Entity comes first
|
|
|
- if EntityTypes.Entity in bases:
|
|
|
- bases.remove(EntityTypes.Entity)
|
|
|
- bases = [EntityTypes.Entity] + bases
|
|
|
-
|
|
|
- for base in bases:
|
|
|
- for desc in base._attribDescs:
|
|
|
- # are we blocking this attribute?
|
|
|
- if desc.getName() in delAttribs:
|
|
|
- continue
|
|
|
-
|
|
|
- # make sure we haven't already picked up this attribute
|
|
|
- # from an earlier base class
|
|
|
- for d in baseADs:
|
|
|
- if desc.getName() == d.getName():
|
|
|
- break
|
|
|
- else:
|
|
|
- baseADs.append(desc)
|
|
|
-
|
|
|
- # now that we have all of the descriptors from our base classes,
|
|
|
- # add the descriptors from this class
|
|
|
- attribDescs = []
|
|
|
- if c.__dict__.has_key('attribs'):
|
|
|
- for attrib in c.attribs:
|
|
|
- desc = AttribDesc.AttribDesc(*attrib)
|
|
|
-
|
|
|
- # if we picked up an attribute with the same name from a base
|
|
|
- # class, this overrides it
|
|
|
- for ad in baseADs:
|
|
|
- if ad.getName() == desc.getName():
|
|
|
- baseADs.remove(ad)
|
|
|
- # there ought to be no more than one desc with
|
|
|
- # this name from the base classes
|
|
|
- break
|
|
|
-
|
|
|
- attribDescs.append(desc)
|
|
|
-
|
|
|
- c._attribDescs = baseADs + attribDescs
|
|
|
+ return hash(repr(self))
|
|
|
+ def __repr__(self):
|
|
|
+ # this is used to produce a hash value
|
|
|
+ return str(self.entTypeName2typeDesc)
|