[Zope-CVS] CVS: Products/AdaptableStorage/mapper - AspectEvent.py:1.1 DeserializationEvent.py:1.1 FieldSchema.py:1.1 MapperEvent.py:1.1 ObjectGateway.py:1.1 ObjectMapper.py:1.1 ObjectSerializer.py:1.1 SerializationEvent.py:1.1 __init__.py:1.1 exceptions.py:1.1 public.py:1.1
Shane Hathaway
shane@zope.com
Tue, 31 Dec 2002 16:47:47 -0500
Update of /cvs-repository/Products/AdaptableStorage/mapper
In directory cvs.zope.org:/tmp/cvs-serv18282/mapper
Added Files:
AspectEvent.py DeserializationEvent.py FieldSchema.py
MapperEvent.py ObjectGateway.py ObjectMapper.py
ObjectSerializer.py SerializationEvent.py __init__.py
exceptions.py public.py
Log Message:
Changed the name of the "serial" package to "mapper". It's a more
appropriate name, since mappers are the focus of this software.
Sorry about the flood of checkins.
=== Added File Products/AdaptableStorage/mapper/AspectEvent.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Aspect-related event base.
$Id: AspectEvent.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
from interfaces.public import IAspectEvent
from MapperEvent import MapperEvent
class AspectEvent (MapperEvent):
__implements__ = IAspectEvent
_aspect_name = ''
def __init__(self, keyed_ob_sys, object_mapper, keychain, object):
MapperEvent.__init__(self, object_mapper, keychain)
self._keyed_ob_sys = keyed_ob_sys
self._object = object
self._unmanaged = []
def getKeyedObjectSystem(self):
"""Returns the IKeyedObjectSystem that generated this event.
It is needed for loading and identifying other objects.
"""
return self._keyed_ob_sys
def setAspectName(self, name):
"""Sets the name of the aspect being (de)serialized."""
assert ':' not in name
self._aspect_name = name
def getAspectName(self):
"""Returns the name of the aspect being (de)serialized."""
return self._aspect_name
def getObject(self):
"""Returns the object being serialized."""
return self._object
def addUnmanagedPersistentObjects(self, obs):
"""Notifies that there are unmanaged persistent objects in the object.
"""
self._unmanaged.extend(obs)
def getUnmanagedPersistentObjects(self):
"""Returns the list of unmanaged persistent objects."""
return self._unmanaged
=== Added File Products/AdaptableStorage/mapper/DeserializationEvent.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Standard deserialization event class
$Id: DeserializationEvent.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
from interfaces.public import IFullDeserializationEvent
from AspectEvent import AspectEvent
class DeserializationEvent (AspectEvent):
__implements__ = IFullDeserializationEvent
def __init__(self, keyed_ob_sys, object_mapper, keychain, object):
AspectEvent.__init__(
self, keyed_ob_sys, object_mapper, keychain, object)
self._loaded_refs = {} # { (aspect_name, name) -> object }
# IDeserializationEvent interface methods:
def notifyDeserialized(self, name, value):
"""See the IDeserializationEvent interface."""
assert self._aspect_name is not None
self._loaded_refs['%s:%s' % (self._aspect_name, name)] = value
def dereference(self, name, keychain, hints=None):
"""Retrieves a referenced subobject (usually ghosted initially).
"""
kos = self.getKeyedObjectSystem()
ob = kos.loadStub(keychain, hints)
self.notifyDeserialized(name, ob)
return ob
# IFullDeserializationEvent interface methods:
def loadInternalRef(self, ref):
"""Returns an object for a reference of the form (aspect_name, name).
"""
return self._loaded_refs[ref]
=== Added File Products/AdaptableStorage/mapper/FieldSchema.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Row-oriented schema definitions
$Id: FieldSchema.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
from interfaces.public import ISchema
# ok_types just constrains the possible types until we figure out
# what we really want to do here.
ok_types = ('unicode', 'string', 'int', 'float', 'bool', 'object',
'classification', 'keychain')
class FieldSchema:
"""Defines the schema of one field."""
__implements__ = ISchema
def __init__(self, name, type='string', unique=0):
assert type in ok_types, type
self.name = name
self.type = type
self.unique = not not unique
def __eq__(self, other):
if isinstance(other, self.__class__):
if (other.name == self.name) and (other.type == self.type) and (
other.unique == self.unique):
return 1 # Same
return 0 # Different
def __repr__(self):
return 'FieldSchema(name=%s, type=%s, unique=%s)' % (
repr(self.name), repr(self.type), repr(self.unique))
class RowSchema:
"""Defines an ordered set of fields for exactly one row.
"""
__implements__ = ISchema
def __init__(self, fields=()):
self.fields = []
self.field_names = {}
for c in fields:
self._add(c)
def _add(self, c):
if self.field_names.has_key(c.name):
raise KeyError, 'Duplicate field name: %s' % c.name
self.field_names[c.name] = 1
self.fields.append(c)
def addField(self, name, type='string', unique=0):
self._add(FieldSchema(name, type, unique))
def __eq__(self, other):
if isinstance(other, self.__class__):
if (self.fields == other.fields):
return 1 # Same
return 0 # Different
def __repr__(self):
return 'RowSchema(%s)' % repr(self.fields)
class RowSequenceSchema (RowSchema):
"""Defines a schema for a sequence of rows, including row count limits.
"""
__implements__ = ISchema
def __init__(self, fields=(), min_rows=0, max_rows=0):
# max_rows == 0 means unlimited.
assert (max_rows == 0 or max_rows >= min_rows)
RowSchema.__init__(self, fields)
self.min_rows = min_rows
self.max_rows = max_rows
def __eq__(self, other):
if isinstance(other, self.__class__):
if (self.fields == other.fields) and (
self.min_rows == other.min_rows) and (
self.max_rows == other.max_rows):
return 1 # Same
return 0 # Different
def __repr__(self):
return 'RowSequenceSchema(%s, min_rows=%s, max_rows=%s)' % (
repr(self.fields), repr(self.min_rows), repr(self.max_rows))
=== Added File Products/AdaptableStorage/mapper/MapperEvent.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Mapper event base.
$Id: MapperEvent.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
from interfaces.public import IMapperEvent
class MapperEvent:
__implements__ = IMapperEvent
_aspect_name = ''
def __init__(self, object_mapper, keychain):
self._object_mapper = object_mapper
self._keychain = keychain
def getObjectMapper(self):
"""Returns the object mapper for the object being (de)serialized."""
return self._object_mapper
def getKeychain(self):
"""Returns the keychain of the object being (de)serialized."""
return self._keychain
def makeKeychain(self, name, stored):
kcg = self.getObjectMapper().getKeychainGenerator()
return kcg.makeKeychain(self, name, stored)
=== Added File Products/AdaptableStorage/mapper/ObjectGateway.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Basic data gateway based on smaller gateways.
$Id: ObjectGateway.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
from interfaces.public import IGateway
class ObjectGateway:
__implements__ = IGateway
def __init__(self):
self._gws = {}
def addGateway(self, name, gw):
self._gws[name] = gw
def getSchema(self):
"""Returns the ISchema of data stored by this gateway.
See interfaces.ISchema.
"""
res = {}
for name, gw in self._gws.items():
s = gw.getSchema()
if s is not None:
res[name] = s
return res
def load(self, event):
"""Loads data.
Returns a pair containing the data and an object
that acts as a serial number or a hash of the data.
The serial number is either a time stamp or some other object
that can be consistently compared to detect conflicts.
"""
full_state = {}
serials = {}
for name, gw in self._gws.items():
state, serial = gw.load(event)
if state is not None:
full_state[name] = state
if serial is not None:
serials[name] = serial
serials = serials.items()
serials.sort()
return full_state, tuple(serials)
def store(self, event, full_state):
"""Stores data.
Returns a new serial.
"""
serials = {}
for name, gw in self._gws.items():
state = full_state.get(name)
# print 'gateway storing', keychain, name, state
serial = gw.store(event, state)
if serial is not None:
serials[name] = serial
serials = serials.items()
serials.sort()
return tuple(serials)
=== Added File Products/AdaptableStorage/mapper/ObjectMapper.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Default object mapper.
$Id: ObjectMapper.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
from interfaces.public \
import IConfigurableObjectMapper, IObjectMapper, IObjectSerializer, \
IGateway, IClassifier, IKeychainGenerator
class ObjectMapper:
__implements__ = IConfigurableObjectMapper
def __init__(self,
parent=None,
serializer=None,
gateway=None,
classifier=None,
kgen=None,
volatile=None):
self._sub_mappers = {}
self._parent = parent
self._serializer = serializer
self._gateway = gateway
self._classifier = classifier
self._kgen = kgen
self._volatile = volatile
# IConfigurableObjectMapper implementation
def setSerializer(self, s):
self._serializer = s
def setGateway(self, g):
self._gateway = g
def setClassifier(self, c):
self._classifier = c
def setKeychainGenerator(self, k):
self._kgen = k
def setVolatile(self, v):
self._volatile = v
def addSubMapper(self, name, m=None, replace=0):
if not replace and self._sub_mappers.has_key(name):
raise KeyError('mapper name %s already in use' % name)
if m is None:
m = ObjectMapper(self)
self._sub_mappers[name] = m
return m
def checkConfiguration(self, names=(), recursive=1):
s = self._serializer
if s is None:
raise RuntimeError(
'No serializer configured for mapper %s' % repr(names))
if not IObjectSerializer.isImplementedBy(s):
raise RuntimeError(
'Not an IObjectSerializer: %s' % repr(s))
g = self._gateway
if g is None:
raise RuntimeError(
'No gateway configured for mapper %s' % repr(names))
if not IGateway.isImplementedBy(g):
raise RuntimeError(
'Not an IGateway: %s' % repr(g))
if s.getSchema() != g.getSchema():
raise RuntimeError('Mismatched schemas in mapper %s: %s != %s' % (
repr(names), s.getSchema(), g.getSchema()))
if self._parent is None:
if self._classifier is None:
raise RuntimeError('No root classifier configured')
if not IClassifier.isImplementedBy(self._classifier):
raise RuntimeError(
'Not an IClassifier: %s' % repr(self._classifier))
if self._kgen is None:
raise RuntimeError('No root keychain generator configured')
if not IKeychainGenerator.isImplementedBy(self._kgen):
raise RuntimeError(
'Not an IKeychainGenerator: %s' % repr(self._kgen))
else:
if not IObjectMapper.isImplementedBy(self._parent):
raise RuntimeError(
'Not an IObjectMapper: %s' % repr(self._parent))
if recursive:
for name, m in self._sub_mappers.items():
m.checkConfiguration((names + (name,)), recursive)
# IObjectMapper implementation
def getSerializer(self):
return self._serializer
def getGateway(self):
return self._gateway
def getSubMapper(self, name):
return self._sub_mappers[name]
def getClassifier(self):
if self._classifier is not None:
return self._classifier
if self._parent is not None:
return self._parent.getClassifier()
return None
def getKeychainGenerator(self):
if self._kgen is not None:
return self._kgen
if self._parent is not None:
return self._parent.getKeychainGenerator()
return None
def isVolatile(self):
if self._volatile is not None:
return self._volatile
if self._parent is not None:
return self._parent.isVolatile()
return None
=== Added File Products/AdaptableStorage/mapper/ObjectSerializer.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Basic object serializer based on aspects.
$Id: ObjectSerializer.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
from interfaces.public import IObjectSerializer
from SerializationEvent import SerializationEvent
from DeserializationEvent import DeserializationEvent
class ObjectSerializer:
__implements__ = IObjectSerializer
def __init__(self, module, name):
self._module = module
self._name = name
self._aspects = [] # [(name, aspect)] -- Order matters.
def addAspect(self, name, aspect):
self._aspects.append((name, aspect))
def getSchema(self):
res = {}
for name, aspect in self._aspects:
s = aspect.getSchema()
if s is not None:
res[name] = s
return res
def canSerialize(self, object):
if not hasattr(object, '__class__'):
return 0
c = object.__class__
return (c.__module__ == self._module and c.__name__ == self._name)
def serialize(self, object, event):
full_state = {}
for name, aspect in self._aspects:
event.setAspectName(name)
state = aspect.serialize(object, event)
if state is not None:
full_state[name] = state
return full_state
def deserialize(self, object, event, full_state):
for name, aspect in self._aspects:
state = full_state.get(name)
event.setAspectName(name)
aspect.deserialize(object, event, state)
def createEmptyInstance(self, classification=None):
m = __import__(self._module, {}, {}, ('__doc__',))
c = getattr(m, self._name)
return c.__basicnew__()
=== Added File Products/AdaptableStorage/mapper/SerializationEvent.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Standard serialization event class
$Id: SerializationEvent.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
from interfaces.public import IFullSerializationEvent
from AspectEvent import AspectEvent
SIMPLE_IMMUTABLE_OBJECTS = (None, (), 0, 1, '', u'')
try:
True
except NameError:
pass
else:
SIMPLE_IMMUTABLE_OBJECTS += (False, True)
class SerializationEvent (AspectEvent):
__implements__ = IFullSerializationEvent
def __init__(self, keyed_ob_sys, object_mapper, keychain, object):
AspectEvent.__init__(
self, keyed_ob_sys, object_mapper, keychain, object)
self._attrs = {}
# _refs is the list of externally referenced objects.
# It has the form [(keychain, value)]
self._refs = []
# _internal_refs:
# id(ob) -> (aspect_name, name)
self._internal_refs = {}
# _internal_ref_list contains all objects that may be referenced
# internally. This only ensures that id(ob) stays consistent.
self._internal_ref_list = []
# ISerializationEvent interface methods:
def notifySerialized(self, name, value, is_attribute):
"""See the ISerializationEvent interface."""
assert self._aspect_name is not None
if value not in SIMPLE_IMMUTABLE_OBJECTS:
# Make internal references only for mutable or complex objects.
idx = id(value)
if not self._internal_refs.has_key(idx):
self._internal_ref_list.append(value)
if name is not None:
self._internal_refs[idx] = (
'%s:%s' % (self._aspect_name, name))
else:
self._internal_refs[idx] = None
if is_attribute and name is not None:
self._attrs[name] = 1
def identifyObject(self, value):
kos = self.getKeyedObjectSystem()
return kos.identifyObject(value)
def notifySerializedRef(self, name, value, is_attribute, keychain):
assert keychain is not None
self._refs.append((keychain, value))
self.notifySerialized(name, value, is_attribute)
def ignoreAttribute(self, name):
"""See the ISerializationEvent interface."""
self._attrs[name] = 1
def getExternalRefs(self):
"""Returns the list of external references"""
return self._refs
# IFullSerializationEvent interface methods:
def getSerializedAttributeNames(self):
"""Returns the name of all attributes serialized."""
return self._attrs.keys()
def getInternalRef(self, ob):
"""Returns (aspect_name, name) or None."""
return self._internal_refs.get(id(ob))
=== Added File Products/AdaptableStorage/mapper/__init__.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""General object mapping framework.
The names are influenced by Martin Fowler's O/R mapping patterns.
"""
=== Added File Products/AdaptableStorage/mapper/exceptions.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Serializer exception types.
$Id: exceptions.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
class SerializationError(Exception):
"""Error during serialization"""
class DeserializationError(Exception):
"""Error during deserialization"""
=== Added File Products/AdaptableStorage/mapper/public.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Public serialization interfaces and default implementations
$Id: public.py,v 1.1 2002/12/31 21:47:46 shane Exp $
"""
from interfaces.public import *
from exceptions import *
from DeserializationEvent import DeserializationEvent
from MapperEvent import MapperEvent
from ObjectGateway import ObjectGateway
from ObjectMapper import ObjectMapper
from ObjectSerializer import ObjectSerializer
from FieldSchema import FieldSchema, RowSchema, RowSequenceSchema
from SerializationEvent import SerializationEvent