[Zope-CVS] CVS: Products/Ape/lib/apelib/config - apeconf.py:1.8
Shane Hathaway
shane at zope.com
Fri Jul 23 04:38:04 EDT 2004
Update of /cvs-repository/Products/Ape/lib/apelib/config
In directory cvs.zope.org:/tmp/cvs-serv26116/lib/apelib/config
Modified Files:
apeconf.py
Log Message:
Ape now supports mapping subclasses. Also revised the config format.
>From CHANGES.txt:
- Ape now supports mapping subclasses. Until now, mappers were
registered for classes but not for all subclasses. Now, a mapper
applies to subclasses as well, unless the configuration file
specifies 'exact-class'.
- Revised the configuration file format for simplification and to
allow mapping subclasses.
Also added PDBSerializer, a wrapper around CompositeSerializer that
launches pdb. It is really handy when you know which
mapper is serializing incorrectly but you don't know why.
=== Products/Ape/lib/apelib/config/apeconf.py 1.7 => 1.8 ===
--- Products/Ape/lib/apelib/config/apeconf.py:1.7 Sat Mar 20 01:34:21 2004
+++ Products/Ape/lib/apelib/config/apeconf.py Fri Jul 23 04:37:34 2004
@@ -19,7 +19,7 @@
from types import TupleType
from apelib.core.mapper import Mapper, MapperConfiguration
-from apelib.core.serializers import CompositeSerializer, AnyObjectSerializer
+from apelib.core.serializers import CompositeSerializer
from apelib.core.gateways import CompositeGateway
from apelib.core.interfaces import IDatabaseInitializer, ConfigurationError
@@ -27,22 +27,16 @@
from common import Directive, DirectiveReader, ComponentSystem
-class MapperDeclaration(Directive):
+class MapperDefinition(Directive):
schema = TableSchema()
schema.add('mapper_name', primary=1)
-
-
-class MapperAttribute(Directive):
- schema = TableSchema()
- schema.add('mapper_name', primary=1)
- # Attribute names: 'class', 'extends', 'register-class'
- schema.add('name', primary=1, indexed=1)
- schema.add('value')
+ schema.add('extends')
+ schema.add('class_name')
class ComponentDefinition(Directive):
schema = TableSchema()
- # comptypes: 'serializer', 'gateway', 'classifier', 'oid_generator'
+ # comptypes: 'classifier', 'oid_generator'
schema.add('comptype', primary=1)
schema.add('name', primary=1)
schema.add('producer')
@@ -51,24 +45,28 @@
class MapperComponent(Directive):
schema = TableSchema()
schema.add('mapper_name', primary=1)
+ # comptypes: 'serializer', 'gateway'
schema.add('comptype', primary=1)
schema.add('name', primary=1)
schema.add('producer')
schema.add('order')
-class MapperUseFor(Directive):
+class StoreUsing(Directive):
schema = TableSchema()
- schema.add('mapper_name', primary=1)
- schema.add('attr', primary=1)
- schema.add('value', primary=1) # Multiple values allowed
+ schema.add('class_name', primary=1)
+ schema.add('use_mapper')
+ schema.add('exact') # boolean
+ schema.add('default_extension')
+ schema.add('default_extension_source')
-class ClassifierOption(Directive):
+class LoadUsing(Directive):
schema = TableSchema()
- schema.add('mapper_name', primary=1)
- schema.add('option', primary=1)
- schema.add('value')
+ # Criterion is 'extension', 'mapper-name', or 'generic'
+ schema.add('criterion', primary=1)
+ schema.add('value', primary=1)
+ schema.add('use_mapper')
class DisabledProducer:
@@ -79,16 +77,6 @@
return None
-class UseProducer:
- def __init__(self, source, comptype, name):
- self.source = source
- self.comptype = comptype
- self.name = name
-
- def __call__(self, compsys):
- return compsys.get(self.comptype, self.name)
-
-
class FactoryProducer:
def __init__(self, source, factory):
@@ -129,14 +117,10 @@
def make_producer(source, comptype, attrs, raise_exc=1):
if attrs.get('enabled', '').lower() == 'false':
return DisabledProducer(source)
- elif attrs.has_key('use'):
- if attrs.has_key('factory'):
- raise ValueError, "Both 'use' and 'factory' not allowed"
- return UseProducer(source, comptype, attrs['use'])
elif attrs.has_key('factory'):
return FactoryProducer(source, attrs['factory'])
elif raise_exc:
- raise ValueError, "Need a 'use', 'factory', or 'enabled' attribute"
+ raise ValueError, "Need a 'factory' or 'enabled' attribute"
else:
return None
@@ -161,29 +145,17 @@
def handle_mapper(source, vars, attrs):
d = vars['directives']
mapper_name = str(attrs['name'])
+ extends = str(attrs.get('extends', ''))
+ class_name = str(attrs.get('class', ''))
vars['mapper_name'] = mapper_name
- d.append(MapperDeclaration(source, mapper_name))
- for key in ('class', 'extends', 'register-class'):
- if attrs.has_key(key):
- value = attrs[key]
- if (key == 'register-class'):
- if value.lower() == 'true':
- value = True
- elif value.lower() == 'false':
- value = False
- else:
- raise ValueError("Value must be true or false")
- d.append(MapperAttribute(source, mapper_name, key, value))
+ d.append(MapperDefinition(source, mapper_name, extends, class_name))
def handle_mapper_component(source, vars, attrs, comptype):
d = vars['directives']
producer = make_producer(source, comptype, attrs)
mapper_name = vars.get('mapper_name')
if mapper_name is None:
- # Reusable component
- name = attrs['name']
- directive = ComponentDefinition(
- source, comptype, name, producer)
+ raise ValueError('Not inside a mapper tag')
else:
# Composite component of a mapper
name = attrs.get('name', '')
@@ -202,8 +174,7 @@
# Set a gateway for a classifier.
if not hasattr(p, 'sub_producer'):
raise ValueError(
- "Classifier at %s needs a factory in order to "
- "use a gateway" % source)
+ "Classifier at %s needs a factory" % source)
if p.sub_producer is not None:
raise ValueError(
"Multiple gateways in classifiers not allowed at %s" %
@@ -225,11 +196,32 @@
directive = ComponentDefinition(source, 'oid_generator', '', producer)
d.append(directive)
- def handle_use_for(source, vars, attrs):
+ def handle_store(source, vars, attrs):
+ d = vars['directives']
+ cn = attrs.get('class')
+ ecn = attrs.get('exact-class')
+ if cn and ecn or not cn and not ecn:
+ raise ValueError("One of 'class' or 'exact-class' is required")
+ mapper_name = str(attrs['using'])
+ def_ext = attrs.get('default-extension')
+ def_ext_src = attrs.get('default-extension-source')
+ if def_ext and def_ext_src:
+ raise ValueError(
+ "Only one of 'default-extension' "
+ "or 'default-extension-source' is allowed")
+ directive = StoreUsing(
+ source, cn or ecn, mapper_name, bool(ecn), def_ext, def_ext_src)
+ d.append(directive)
+
+ def handle_load(source, vars, attrs):
d = vars['directives']
- mapper_name = vars['mapper_name']
- for attr in ('class', 'extensions', 'generic', 'oid'):
+ mapper_name = str(attrs['using'])
+ criterion = None
+ for attr in ('mapper-name', 'extensions', 'generic'):
if attrs.has_key(attr):
+ if criterion is not None:
+ raise ValueError("Only one criterion allowed")
+ criterion = attr
v = attrs[attr]
if attr == 'extensions':
first = 1
@@ -237,24 +229,11 @@
if not ext.startswith('.'):
ext = '.' + ext
ext = ext.lower()
- d.append(MapperUseFor(
- source, mapper_name, 'extension', ext))
- if first:
- # Use a classifier option to set the default
- # extension.
- first = 0
- d.append(ClassifierOption(
- source, mapper_name, 'default_extension', ext))
+ d.append(LoadUsing(
+ source, 'extension', ext, mapper_name))
else:
- d.append(MapperUseFor(
- source, mapper_name, attr, v))
-
- def handle_option(source, vars, attrs):
- d = vars['directives']
- mapper_name = vars['mapper_name']
- name = attrs['name']
- value = attrs['value']
- d.append(ClassifierOption(source, mapper_name, name, value))
+ d.append(LoadUsing(
+ source, attr, v, mapper_name))
handlers = {
'configuration': handle_configuration,
@@ -264,8 +243,8 @@
'gateway': handle_gateway,
'classifier': handle_classifier,
'oid-generator': handle_oid_generator,
- 'use-for': handle_use_for,
- 'option': handle_option,
+ 'store': handle_store,
+ 'load': handle_load,
}
return handlers
@@ -290,7 +269,8 @@
self.producer = producer
def create(self):
- return self.producer(self.compsys)
+ self.obj = self.producer(self.compsys)
+ return self.obj
def configure(self):
pass
@@ -303,15 +283,16 @@
self.compsys = compsys
dtables = compsys.dtables
self.mapper_name = name
- if not dtables.query(MapperDeclaration, mapper_name=name):
+ recs = dtables.query(MapperDefinition, mapper_name=name)
+ if not recs:
raise ConfigurationError("No mapper named %s exists" % repr(name))
+ self.directive = recs[0]
self.subobjs = [] # all subobjects
- self.attrs = {}
- for record in dtables.query(MapperAttribute, mapper_name=name):
- self.attrs[record.name] = record.value
self._prepare_sub_components()
def _prepare_sub_components(self):
+ """Populates multi_comps with components to be used in this mapper.
+ """
self.multi_comps = {} # comptype -> name -> record
dtables = self.compsys.dtables
name = self.mapper_name
@@ -324,7 +305,7 @@
d = self.multi_comps.setdefault(r.comptype, {})
d.setdefault(r.name, r)
name = dtables.query_field(
- MapperAttribute, 'value', mapper_name=name, name='extends')
+ MapperDefinition, 'extends', mapper_name=name)
if name and name in all_names:
raise ConfigurationError(
"Circular extension in mappers %s" % repr(all_names))
@@ -334,23 +315,13 @@
return self.obj
def configure(self):
+ self.obj.name = self.mapper_name
+ self.obj.class_name = self.directive.class_name or ''
self.add_serializers()
self.add_gateways()
self.add_initializers()
def add_serializers(self):
- cname = self.attrs.get('class')
- if cname == 'none':
- # This mapper is abstract (usable for no classes)
- module, name = None, None
- else:
- # This mapper is concrete (usable for one class only)
- if cname is None:
- cname = self.mapper_name
- pos = cname.rfind('.')
- if pos < 0:
- raise ConfigurationError("Class name must include a module name")
- module, name = cname[:pos], cname[pos + 1:]
d = self.multi_comps.get('serializer', {})
# Create the main serializer
@@ -358,7 +329,7 @@
if r:
s = r.producer(self.compsys)
else:
- s = CompositeSerializer(module, name)
+ s = CompositeSerializer()
# Create the contained serializers
ordered = [
@@ -409,64 +380,15 @@
assert name == '', name
BasicComponentAssembler.__init__(self, compsys, comptype, name)
- def create(self):
- self.obj = BasicComponentAssembler.create(self)
- return self.obj
-
def configure(self):
dtables = self.compsys.dtables
- all_regs = {} # { (attr, value) -> mapper_name }
- all_options = {} # { (mapper_name, option) -> value }
- mapper_names = [r.mapper_name for r in
- dtables.query(MapperDeclaration)]
- # Gather classification options from each mapper configuration.
- for name in mapper_names:
- # use-for directives
- records = dtables.query(
- MapperUseFor, mapper_name=name)
- for r in records:
- key = ((r.attr, r.value))
- if all_regs.has_key(key) and all_regs[key] != name:
- raise ConfigurationError(
- "Mappers %s and %s are contending over %s == %s" % (
- name, all_regs[key],
- repr(r.attr), repr(r.value)))
- all_regs[key] = name
-
- register_class = dtables.query_field(
- MapperAttribute, 'value', mapper_name=name,
- name='register-class')
- if register_class or register_class is None:
- # Create an implicit 'use-for class' directive
- class_name = dtables.query_field(
- MapperAttribute, 'value', mapper_name=name, name='class')
- if class_name is None:
- class_name = name
- elif class_name == 'none':
- class_name = None
- if class_name is not None:
- key = ('class', class_name)
- if all_regs.has_key(key) and all_regs[key] != name:
- raise ConfigurationError(
- "Mappers %s and %s are contending over %s == %s" % (
- name, all_regs[key],
- "'class'", repr(class_name)))
- all_regs[key] = name
-
- # options
- records = dtables.query(
- ClassifierOption, mapper_name=name)
- for r in records:
- all_options[(name, r.option)] = r.value
+ for r in dtables.query(StoreUsing):
+ self.obj.add_store_rule(
+ r.class_name, r.use_mapper, r.exact,
+ r.default_extension, r.default_extension_source)
+ for r in dtables.query(LoadUsing):
+ self.obj.add_load_rule(r.criterion, r.value, r.use_mapper)
- # Perform the registrations.
- if all_regs or all_options:
- for (attr, value), name in all_regs.items():
- self.obj.register(attr, value, name)
- for (name, option), value in all_options.items():
- self.obj.set_option(name, option, value)
-
-
def configure(filenames, vname=''):
"""Returns a MapperConfiguration built from configuration files.
@@ -479,10 +401,9 @@
cs = ComponentSystem(directives)
cs.add_component_type('mapper', MapperAssembler)
cs.add_component_type('classifier', ClassifierAssembler)
- for comptype in ('serializer', 'gateway', 'oid_generator'):
- cs.add_component_type(comptype, BasicComponentAssembler)
+ cs.add_component_type('oid_generator', BasicComponentAssembler)
mappers = {}
- for record in cs.dtables.query(MapperDeclaration):
+ for record in cs.dtables.query(MapperDefinition):
name = record.mapper_name
mappers[name] = cs.get('mapper', name)
classifier = cs.get('classifier', '')
More information about the Zope-CVS
mailing list