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:
parent
1b0652a555
commit
8e9d392030
4 changed files with 193 additions and 39 deletions
|
@ -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'
|
||||
|
|
|
@ -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)])
|
||||
|
||||
|
|
|
@ -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
69
typology/type.py
Normal 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)
|
||||
|
Loading…
Add table
Reference in a new issue