created the cybertools.typology package; + some related extensions and improvements on other packages
git-svn-id: svn://svn.cy55.de/Zope3/src/cybertools/trunk@1116 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
b43d1475c2
commit
1b0652a555
13 changed files with 336 additions and 8 deletions
|
@ -18,20 +18,59 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
A set of simple application classes for contact management to be used
|
A set of simple application classes for contact management to be used
|
||||||
as an example for the cybertools.reporter package.
|
as an example for some of the cybertools packages.
|
||||||
|
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
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 datetime import date
|
||||||
|
|
||||||
|
|
||||||
class Person(object):
|
class Person(object):
|
||||||
|
|
||||||
|
implements(IPerson)
|
||||||
|
|
||||||
def __init__(self, firstName, lastName, birthDate):
|
def __init__(self, firstName, lastName, birthDate):
|
||||||
self.firstName = firstName
|
self.firstName = firstName
|
||||||
self.lastName = lastName
|
self.lastName = lastName
|
||||||
self.birthDate = birthDate
|
self.birthDate = birthDate
|
||||||
|
self.moreFirstNames = []
|
||||||
|
self.personalAddress = 'mrs' # or 'mr', 'ms', None (unknown)
|
||||||
|
self.academicTitle = None
|
||||||
|
self.communicationInfos = []
|
||||||
|
self.addresses = {} # keys: 'standard', ...?
|
||||||
|
self.affiliations = {} # keys: 'employed', ...?
|
||||||
|
|
||||||
|
@property
|
||||||
|
def age(self):
|
||||||
|
return (date.today() - self.birthDate).days/365.25
|
||||||
|
|
||||||
|
|
||||||
|
class Address(object):
|
||||||
|
|
||||||
|
def __init__(self, title, lines, street, zipcode, city, country):
|
||||||
|
self.title = title
|
||||||
|
self.lines = lines # a sequence of address lines
|
||||||
|
self.street = street
|
||||||
|
self.zipcode = zipcode
|
||||||
|
self.city = city
|
||||||
|
self.country = country # 'de', 'at', 'us', ...
|
||||||
|
|
||||||
|
|
||||||
|
class Institution(object):
|
||||||
|
|
||||||
|
def __init__(self, title):
|
||||||
|
self.title = title
|
||||||
|
self.addresses = {}
|
||||||
|
|
||||||
|
|
||||||
|
class CommunicationInfo(object):
|
||||||
|
|
||||||
|
def __init__(self, commType, qualifier, address):
|
||||||
|
self.commType = commType # e.g. 'email', 'phone', ...
|
||||||
|
self.qualifier = qualifier # e.g. 'private', or institution
|
||||||
|
self.address = address # the real address or number
|
||||||
|
|
||||||
|
|
|
@ -23,4 +23,10 @@ as an example for some of the cybertools packages.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope.interface import Interface
|
from zope.interface import Interface, Attribute
|
||||||
|
|
||||||
|
class IPerson(Interface):
|
||||||
|
""" Just a person...
|
||||||
|
"""
|
||||||
|
|
||||||
|
age = Attribute('A float representing the age in years. Read-only.')
|
||||||
|
|
|
@ -20,18 +20,20 @@ then provide a listing of persons...
|
||||||
>>> from cybertools.reporter.example.interfaces import IContactsDataSource
|
>>> from cybertools.reporter.example.interfaces import IContactsDataSource
|
||||||
>>> from cybertools.reporter.example.contact import Contacts
|
>>> from cybertools.reporter.example.contact import Contacts
|
||||||
|
|
||||||
>>> import time
|
>>> from datetime import date
|
||||||
>>> format = '%Y-%m-%d'
|
|
||||||
>>> pdata = ((u'John', u'Smith', '1956-08-01'),
|
>>> pdata = ((u'John', u'Smith', '1956-08-01'),
|
||||||
... (u'David', u'Waters', '1972-12-24'),
|
... (u'David', u'Waters', '1972-12-24'),
|
||||||
... (u'Carla', u'Myers', '1981-10-11'))
|
... (u'Carla', u'Myers', '1981-10-11'))
|
||||||
>>> persons = DataSource([Person(f, s, time.strptime(b, format))
|
>>> persons = DataSource([Person(f, s, date(*[int(d) for d in b.split('-')]))
|
||||||
... for f, s, b in pdata])
|
... for f, s, b in pdata])
|
||||||
>>> directlyProvides(persons, IContactsDataSource)
|
>>> directlyProvides(persons, IContactsDataSource)
|
||||||
|
|
||||||
>>> ztapi.provideAdapter(IContactsDataSource, IResultSet, Contacts)
|
>>> ztapi.provideAdapter(IContactsDataSource, IResultSet, Contacts)
|
||||||
>>> rset = IResultSet(persons)
|
>>> rset = IResultSet(persons)
|
||||||
|
|
||||||
|
>>> len(rset)
|
||||||
|
3
|
||||||
|
|
||||||
For the browser presentation we can also use a browser view providing
|
For the browser presentation we can also use a browser view providing
|
||||||
the result set with extended attributes:
|
the result set with extended attributes:
|
||||||
|
|
||||||
|
|
|
@ -23,12 +23,52 @@ cybertools.contact package
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# TODO: move the generic stuff to cybertools.reporter.result
|
||||||
|
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.interface import implements
|
from zope.interface import implements
|
||||||
from cybertools.reporter.interfaces import IResultSet
|
from cybertools.reporter.interfaces import IResultSet, IRow, ICell
|
||||||
from cybertools.reporter.example.interfaces import IContactsDataSource
|
from cybertools.reporter.example.interfaces import IContactsDataSource
|
||||||
|
|
||||||
|
|
||||||
|
class Cell(object):
|
||||||
|
|
||||||
|
implements(ICell)
|
||||||
|
|
||||||
|
def __init__(self, field, value, row):
|
||||||
|
self.field = field
|
||||||
|
self.value = value
|
||||||
|
self.row = row
|
||||||
|
|
||||||
|
@property
|
||||||
|
def text(self):
|
||||||
|
return value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def token(self):
|
||||||
|
return value
|
||||||
|
|
||||||
|
def sortKey(self):
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class Row(object):
|
||||||
|
|
||||||
|
implements(IRow)
|
||||||
|
|
||||||
|
def __init__(self, context, resultSet):
|
||||||
|
self.context = context # a single object (in this case)
|
||||||
|
self.resultSet = resultSet
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cells(self):
|
||||||
|
schema = self.resultSet.schema
|
||||||
|
if schema is None:
|
||||||
|
return {}
|
||||||
|
return dict([(f.__name__, getattr(self.context, f.__name__))
|
||||||
|
for f in schema.fields])
|
||||||
|
|
||||||
|
|
||||||
class Contacts(object):
|
class Contacts(object):
|
||||||
|
|
||||||
implements(IResultSet)
|
implements(IResultSet)
|
||||||
|
@ -37,4 +77,14 @@ class Contacts(object):
|
||||||
def __init__(self, context):
|
def __init__(self, context):
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
|
_schema = None
|
||||||
|
def setSchema(self, schema): self._schema = schema
|
||||||
|
def getSchema(self): return self._schema
|
||||||
|
schema = property(getSchema, setSchema)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def rows(self):
|
||||||
|
return [Row(o, self) for o in iter(self.context)]
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.rows)
|
||||||
|
|
57
typology/README.txt
Normal file
57
typology/README.txt
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
Quickstart Instructions
|
||||||
|
=======================
|
||||||
|
|
||||||
|
($Id$)
|
||||||
|
|
||||||
|
>>> 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
|
||||||
|
|
||||||
|
Let's start with the Person class from the cybertools.contact package -
|
||||||
|
we will then apply dynamic typing to Person objects:
|
||||||
|
|
||||||
|
>>> from cybertools.contact.interfaces import IPerson
|
||||||
|
>>> from cybertools.contact import Person
|
||||||
|
|
||||||
|
>>> from datetime import date
|
||||||
|
>>> pdata = ((u'John', u'Smith', '1956-08-01'),
|
||||||
|
... (u'David', u'Waters', '1972-12-24'),
|
||||||
|
... (u'Carla', u'Myers', '1999-10-11'))
|
||||||
|
>>> persons = [Person(f, s, date(*[int(d) for d in b.split('-')]))
|
||||||
|
... for f, s, b in pdata]
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
|
>>> 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])
|
||||||
|
|
||||||
|
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'
|
||||||
|
>>> david_type.token
|
||||||
|
'contact.person.agetype.adult'
|
||||||
|
>>> carla_type.token
|
||||||
|
'contact.person.agetype.child'
|
||||||
|
|
||||||
|
Usually types are equal if they have the same token:
|
||||||
|
|
||||||
|
>>> john_type == david_type
|
||||||
|
True
|
||||||
|
>>> john_type == carla_type
|
||||||
|
False
|
4
typology/__init__.py
Normal file
4
typology/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
4
typology/browser/__init__.py
Normal file
4
typology/browser/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
8
typology/configure.zcml
Normal file
8
typology/configure.zcml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<!-- $Id$ -->
|
||||||
|
|
||||||
|
<configure
|
||||||
|
xmlns="http://namespaces.zope.org/zope"
|
||||||
|
xmlns:browser="http://namespaces.zope.org/browser"
|
||||||
|
i18n_domain="zope">
|
||||||
|
|
||||||
|
</configure>
|
1
typology/cybertools.typology-configure.zcml
Normal file
1
typology/cybertools.typology-configure.zcml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<include package="cybertools.typology" />
|
4
typology/example/__init__.py
Normal file
4
typology/example/__init__.py
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
60
typology/example/person.py
Normal file
60
typology/example/person.py
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Example classes for the cybertools.reporter package. These use the
|
||||||
|
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
|
||||||
|
|
||||||
|
class BasicAgeGroup(object):
|
||||||
|
|
||||||
|
implements(IType)
|
||||||
|
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'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def token(self): return 'contact.person.agetype.' + str(self.title.lower())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tokenForSearch(self): return self.token
|
||||||
|
|
||||||
|
# helper methods
|
||||||
|
|
||||||
|
def isChild(self):
|
||||||
|
return self.context.age < 18.0
|
||||||
|
|
66
typology/interfaces.py
Normal file
66
typology/interfaces.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
interface definitions for the typology package.
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.app.container.interfaces import IContainer
|
||||||
|
from zope import schema
|
||||||
|
from zope.configuration.fields import GlobalObject
|
||||||
|
from zope.interface import Interface, Attribute
|
||||||
|
|
||||||
|
|
||||||
|
class IType(Interface):
|
||||||
|
""" Associated with an object (typically as an adapter) giving
|
||||||
|
information about the object's type.
|
||||||
|
"""
|
||||||
|
|
||||||
|
title = schema.TextLine(title=u'Title',
|
||||||
|
description=u'A readable representation',
|
||||||
|
required=True)
|
||||||
|
token = schema.ASCIILine(title=u'Token',
|
||||||
|
description=u'A representation used for identifying a type '
|
||||||
|
'temporarily, e.g. on forms',
|
||||||
|
required=True)
|
||||||
|
tokenForSearch = schema.ASCIILine(title=u'Token for Search',
|
||||||
|
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')
|
||||||
|
factory = GlobalObject(title=u'Factory',
|
||||||
|
description=u'A factory (or class) that may be used for '
|
||||||
|
'creating an object of this type')
|
||||||
|
defaultContainer = schema.Object(IContainer,
|
||||||
|
title=u'Default Container',
|
||||||
|
description=u'Where objects of this type will be created in '
|
||||||
|
'when no explicit container is given')
|
||||||
|
typeProvider = schema.Object(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')
|
||||||
|
|
||||||
|
|
||||||
|
class ITypeManager(Interface):
|
||||||
|
""" A utility or utility-like object (e.g. a container) that may
|
||||||
|
manage (store, retrieve, assign) types.
|
||||||
|
"""
|
27
typology/tests.py
Executable file
27
typology/tests.py
Executable file
|
@ -0,0 +1,27 @@
|
||||||
|
# $Id$
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
from zope.testing.doctestunit import DocFileSuite
|
||||||
|
from zope.app.testing import ztapi
|
||||||
|
from zope.interface.verify import verifyClass
|
||||||
|
from zope.interface import implements
|
||||||
|
from zope.app import zapi
|
||||||
|
|
||||||
|
from cybertools.typology.interfaces import IType, ITypeManager
|
||||||
|
|
||||||
|
|
||||||
|
class TestTypology(unittest.TestCase):
|
||||||
|
"Basic tests for the typology package."
|
||||||
|
|
||||||
|
def testInterfaces(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def test_suite():
|
||||||
|
return unittest.TestSuite((
|
||||||
|
unittest.makeSuite(TestTypology),
|
||||||
|
DocFileSuite('README.txt'),
|
||||||
|
))
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(defaultTest='test_suite')
|
Loading…
Add table
Reference in a new issue