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$)
|
($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 import zapi
|
||||||
>>> from zope.app.testing import ztapi
|
>>> from zope.app.testing import ztapi
|
||||||
>>> from zope.interface import directlyProvides
|
|
||||||
|
|
||||||
A Basic API for Dynamic Typing
|
|
||||||
==============================
|
|
||||||
|
|
||||||
>>> from cybertools.typology.interfaces import IType, ITypeManager
|
>>> 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
|
child, and from 18 years on a person is an adult. (Note that this test
|
||||||
will only work until November 2017 ;-))
|
will only work until November 2017 ;-))
|
||||||
|
|
||||||
The example package gives us a class for this type that we use as an
|
The example package gives us a class (AgeGroup) for this type
|
||||||
adapter to IPerson:
|
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
|
In addition, the AgeGroup adapter makes use of an AgeGroupManager,
|
||||||
>>> ztapi.provideAdapter(IPerson, IType, BasicAgeGroup)
|
a global utility that does the real work.
|
||||||
>>> john_type = IType(persons[0])
|
|
||||||
>>> david_type = IType(persons[1])
|
>>> from cybertools.typology.example.person import IAgeGroup, AgeGroup
|
||||||
>>> carla_type = IType(persons[2])
|
>>> 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:
|
We can now look what the type is telling us about the persons:
|
||||||
|
|
||||||
>>> john_type.title
|
>>> john_type.title
|
||||||
u'Adult'
|
u'Adult'
|
||||||
>>> john_type.token
|
>>> john_type.token
|
||||||
'contact.person.agetype.adult'
|
'contact.person.agegroup.adult'
|
||||||
>>> david_type.token
|
>>> david_type.token
|
||||||
'contact.person.agetype.adult'
|
'contact.person.agegroup.adult'
|
||||||
>>> carla_type.token
|
>>> 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
|
>>> john_type == david_type
|
||||||
True
|
True
|
||||||
>>> john_type == carla_type
|
>>> john_type == carla_type
|
||||||
False
|
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$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: move generic stuff to type.Type class
|
|
||||||
|
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from cybertools.contact.interfaces import IPerson
|
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)
|
adapts(IPerson)
|
||||||
|
|
||||||
def __init__(self, context):
|
|
||||||
self.context = context
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return self.token == other.token
|
|
||||||
|
|
||||||
# IType attributes
|
# IType attributes
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def title(self):
|
def title(self):
|
||||||
return self.isChild() and u'Child' or u'Adult'
|
return self.isChild and u'Child' or u'Adult'
|
||||||
|
|
||||||
@property
|
@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
|
@property
|
||||||
def tokenForSearch(self): return self.token
|
|
||||||
|
|
||||||
# helper methods
|
|
||||||
|
|
||||||
def isChild(self):
|
def isChild(self):
|
||||||
return self.context.age < 18.0
|
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):
|
class IType(Interface):
|
||||||
""" Associated with an object (typically as an adapter) giving
|
""" A collection of informations about a type; may be associated
|
||||||
information about the object's type.
|
with an object (typically as an adapter) specifying the object's
|
||||||
|
type.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
title = schema.TextLine(title=u'Title',
|
title = schema.TextLine(title=u'Title',
|
||||||
|
@ -44,8 +45,8 @@ class IType(Interface):
|
||||||
description=u'A fairly unique token that may be used '
|
description=u'A fairly unique token that may be used '
|
||||||
'e.g. for identifying types via a catalog index')
|
'e.g. for identifying types via a catalog index')
|
||||||
interfaceToProvide = GlobalObject(title=u'Interface to Provide',
|
interfaceToProvide = GlobalObject(title=u'Interface to Provide',
|
||||||
description=u'An (optional) interface that objects of this '
|
description=u'An (optional) interface (or schema) that '
|
||||||
'type will provide')
|
'objects of this type will provide')
|
||||||
factory = GlobalObject(title=u'Factory',
|
factory = GlobalObject(title=u'Factory',
|
||||||
description=u'A factory (or class) that may be used for '
|
description=u'A factory (or class) that may be used for '
|
||||||
'creating an object of this type')
|
'creating an object of this type')
|
||||||
|
@ -57,10 +58,38 @@ class IType(Interface):
|
||||||
title=u'Type Provider',
|
title=u'Type Provider',
|
||||||
description=u'A usually long-living object that corresponds '
|
description=u'A usually long-living object that corresponds '
|
||||||
'to the type. Note that this object need not '
|
'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):
|
class ITypeManager(Interface):
|
||||||
""" A utility or utility-like object (e.g. a container) that may
|
""" A utility or utility-like object (e.g. a container) that may
|
||||||
manage (store, retrieve, assign) types.
|
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