Basic functionality for type management

git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1117 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2006-03-08 10:54:33 +00:00
parent 1b0652a555
commit 8e9d392030
4 changed files with 193 additions and 39 deletions

View file

@ -1,14 +1,15 @@
Quickstart Instructions
=======================
A Basic API for Dynamic Typing
==============================
($Id$)
The typology package offers a basic standard API for associating
arbitrary objects with types that may then be used for controlling
execution of code, helping with search interfaces or editing of
object data.
>>> from zope.app import zapi
>>> from zope.app.testing import ztapi
>>> from zope.interface import directlyProvides
A Basic API for Dynamic Typing
==============================
>>> from cybertools.typology.interfaces import IType, ITypeManager
@ -29,29 +30,59 @@ Now we want to express that any person younger than 18 years is a
child, and from 18 years on a person is an adult. (Note that this test
will only work until November 2017 ;-))
The example package gives us a class for this type that we use as an
adapter to IPerson:
The example package gives us a class (AgeGroup) for this type
that we use as an adapter to IPerson. The type itself we specify as a
subclass (IAgeGroup) of IType; thus we can associate different types
to one object by providing adapters to different type interfaces.
>>> from cybertools.typology.example.person import BasicAgeGroup
>>> ztapi.provideAdapter(IPerson, IType, BasicAgeGroup)
>>> john_type = IType(persons[0])
>>> david_type = IType(persons[1])
>>> carla_type = IType(persons[2])
In addition, the AgeGroup adapter makes use of an AgeGroupManager,
a global utility that does the real work.
>>> from cybertools.typology.example.person import IAgeGroup, AgeGroup
>>> ztapi.provideAdapter(IPerson, IAgeGroup, AgeGroup)
>>> from cybertools.typology.example.person import IAgeGroupManager
>>> from cybertools.typology.example.person import AgeGroupManager
>>> ztapi.provideUtility(IAgeGroupManager, AgeGroupManager())
>>> john_type = IAgeGroup(persons[0])
>>> david_type = IAgeGroup(persons[1])
>>> carla_type = IAgeGroup(persons[2])
We can now look what the type is telling us about the persons:
>>> john_type.title
u'Adult'
>>> john_type.token
'contact.person.agetype.adult'
'contact.person.agegroup.adult'
>>> david_type.token
'contact.person.agetype.adult'
'contact.person.agegroup.adult'
>>> carla_type.token
'contact.person.agetype.child'
'contact.person.agegroup.child'
Usually types are equal if they have the same token:
In this case (and probably a lot of others) types are considered equal
if they have the same token:
>>> john_type == david_type
True
>>> john_type == carla_type
False
If we want to use this type information on a search form for retrieving
only persons of a certain age group we need a list of available types
(in fact that is an iterable source and, based on it, a vocabulary).
This is where type managers come in. A type manager is a utility or
another (possibly persistent) object knowing about the available types.
>>> typeManager = zapi.getUtility(IAgeGroupManager)
>>> types = typeManager.types
>>> [t.title for t in types]
[u'Child', u'Adult']
>>> types[0] == carla_type
True
>>> types[1] == john_type == david_type
True
>>> t = typeManager.getType(carla_type.token)
>>> t.title
u'Child'

View file

@ -23,38 +23,63 @@ cybertools.contact package
$Id$
"""
# TODO: move generic stuff to type.Type class
from zope.component import adapts
from zope.interface import implements
from cybertools.contact.interfaces import IPerson
from cybertools.typology.interfaces import IType
from cybertools.typology.interfaces import IType, ITypeManager
from cybertools.typology.type import BaseType, TypeManager
class BasicAgeGroup(object):
implements(IType)
# interfaces
class IAgeGroup(IType):
""" A type interface for discerning childs and adults.
"""
class IAgeGroupManager(ITypeManager):
""" A type manager managing age groups.
"""
# implementations
class AgeGroup(BaseType):
implements(IAgeGroup)
adapts(IPerson)
def __init__(self, context):
self.context = context
def __eq__(self, other):
return self.token == other.token
# IType attributes
@property
def title(self):
return self.isChild() and u'Child' or u'Adult'
return self.isChild and u'Child' or u'Adult'
@property
def token(self): return 'contact.person.agetype.' + str(self.title.lower())
def token(self): return 'contact.person.agegroup.' + str(self.title.lower())
# helpers
@property
def tokenForSearch(self): return self.token
# helper methods
def isChild(self):
return self.context.age < 18.0
class AgeGroupTypeInfo(AgeGroup):
""" Age group type info object with fixed (not computed) isChild property.
"""
isChild = None
def __init__(self, isChild):
self.isChild = isChild
class AgeGroupManager(TypeManager):
implements(IAgeGroupManager)
@property
def types(self):
return tuple([AgeGroupTypeInfo(flag) for flag in (True, False)])

View file

@ -29,8 +29,9 @@ from zope.interface import Interface, Attribute
class IType(Interface):
""" Associated with an object (typically as an adapter) giving
information about the object's type.
""" A collection of informations about a type; may be associated
with an object (typically as an adapter) specifying the object's
type.
"""
title = schema.TextLine(title=u'Title',
@ -44,8 +45,8 @@ class IType(Interface):
description=u'A fairly unique token that may be used '
'e.g. for identifying types via a catalog index')
interfaceToProvide = GlobalObject(title=u'Interface to Provide',
description=u'An (optional) interface that objects of this '
'type will provide')
description=u'An (optional) interface (or schema) that '
'objects of this type will provide')
factory = GlobalObject(title=u'Factory',
description=u'A factory (or class) that may be used for '
'creating an object of this type')
@ -57,10 +58,38 @@ class IType(Interface):
title=u'Type Provider',
description=u'A usually long-living object that corresponds '
'to the type. Note that this object need not '
'provide the IType interface itself')
'provide the IType interface itself but it '
'should be adaptable to ITypeProvider')
# possible extensions:
# subTypes
# parentTypes
class ITypeManager(Interface):
""" A utility or utility-like object (e.g. a container) that may
manage (store, retrieve, assign) types.
"""
types = schema.Tuple(schema.Object(IType), unique=True,
title=u'Types',
description=u'A sequence of type objects managed by '
'this type manager')
def listTypes(**criteria):
""" Return a sequence of type objects probably restricted via
a set of query criteria.
"""
def getType(token):
""" Return a type object belonging to the token given.
"""
class ITypeProvider(Interface):
""" An object (probably used as an adapter) that may provide a
certain type object.
"""
def getType():
""" Return the type object this type provider provides.
"""

69
typology/type.py Normal file
View file

@ -0,0 +1,69 @@
#
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""
Abstract base classes for type management.
$Id$
"""
from zope.interface import implements
from cybertools.typology.interfaces import IType, ITypeManager
class BaseType(object):
implements(IType)
def __init__(self, context):
self.context = context
def __eq__(self, other):
return self.token == other.token
title = 'BaseType'
@property
def token(self): return self.title.lower()
@property
def tokenForSearch(self): return self.token
interfaceToProvide = None
factory = None
defaultContainer = None
typeProvider = None
class TypeManager(object):
implements(ITypeManager)
@property
def types(self):
return (BaseType(None),)
def listTypes(self, **criteria):
return self.types
def getType(self, token):
for t in self.types:
if t.token == token:
return t
raise ValueError('Unrecognized token: ' + token)