[z3-checkins] r31671 - in z3/sqlos/branch/kobold-sqlos/src/sqlos: . ftests interfaces testing
kobold at codespeak.net
kobold at codespeak.net
Sat Aug 26 11:39:22 CEST 2006
Author: kobold
Date: Sat Aug 26 11:39:20 2006
New Revision: 31671
Added:
z3/sqlos/branch/kobold-sqlos/src/sqlos/browser.py (contents, props changed)
z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/joins.txt
z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/joins_browser.txt
z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/mono_containers.txt
Modified:
z3/sqlos/branch/kobold-sqlos/src/sqlos/configure.zcml
z3/sqlos/branch/kobold-sqlos/src/sqlos/container.py
z3/sqlos/branch/kobold-sqlos/src/sqlos/ftesting.zcml
z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/containers.txt
z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/localutilities.txt
z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/test_doctest.py
z3/sqlos/branch/kobold-sqlos/src/sqlos/interfaces/__init__.py
z3/sqlos/branch/kobold-sqlos/src/sqlos/interfaces/container.py
z3/sqlos/branch/kobold-sqlos/src/sqlos/testing/sampleperson.py
z3/sqlos/branch/kobold-sqlos/src/sqlos/zsqlobject.py
Log:
Implemented SQLObjectMonoContainer and SQLOSContainer for joined SQLOS objects, as well as test and ftests.
Added: z3/sqlos/branch/kobold-sqlos/src/sqlos/browser.py
==============================================================================
--- (empty file)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/browser.py Sat Aug 26 11:39:20 2006
@@ -0,0 +1,48 @@
+##############################################################################
+#
+# Copyright (c) 2004 Enfold Systems LLC. All rights reserved.
+# Copyright (c) 2005-2006 Brian Sutherland. All rights reserved.
+# Copyright (c) 2006 Fabio Tranchitella. All rights reserved.
+#
+# This software is distributed under the terms of the Zope Public
+# License (ZPL) v2.1. See COPYING.txt for more information.
+#
+##############################################################################
+"""Browser package for sqlos
+
+$Id$
+"""
+
+from zope.interface import implements
+from zope.app.form.browser.add import AddView
+from zope.app.traversing.interfaces import ITraversable, TraversalError
+
+from sqlos.interfaces.container import ISQLObjectJoinContainer
+
+
+class SQLOSAddView(AddView):
+ """Custom AddView for SQLOS objects"""
+
+ def create(self, *args, **kw):
+ for container in (self.context, self.context.__parent__):
+ if hasattr(container, '_filters'):
+ kw.update(container._filters)
+ return self._factory(*args, **kw)
+
+
+class SQLOSContainerTraversable(object):
+ """Traverses containers via `__getitem__`."""
+
+ implements(ITraversable)
+ __used_for__ = ISQLObjectJoinContainer
+
+ def __init__(self, container):
+ self._container = container
+
+ def traverse(self, name, furtherPath):
+ container = self._container
+ try:
+ v = container[name]
+ except KeyError:
+ raise TraversalError(name)
+ return v
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/configure.zcml
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/configure.zcml (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/configure.zcml Sat Aug 26 11:39:20 2006
@@ -38,6 +38,33 @@
factory=".container.SQLObjectNameChooser"
/>
+ <!-- ISQLObjectJoinContainer Views -->
+
+ <content class=".container.SQLOSContainer">
+ <implements interface="zope.app.container.interfaces.IContentContainer" />
+ <factory
+ id="sqlos.container.SQLOSContainer"
+ title="SQLOS join container"
+ description="A container for SQLOS joined instances" />
+ <require
+ permission="zope.View"
+ interface="zope.app.container.interfaces.IReadContainer"
+ />
+ </content>
+
+ <adapter
+ provides="zope.app.container.interfaces.INameChooser"
+ for="sqlos.interfaces.container.ISQLObjectMonoContainer"
+ permission="zope.Public"
+ factory=".container.SQLObjectMonoNameChooser"
+ />
+
+ <adapter
+ factory=".browser.SQLOSContainerTraversable"
+ provides="zope.app.traversing.interfaces.ITraversable"
+ for=".interfaces.container.ISQLObjectJoinContainer"
+ />
+
<!-- Default view for containers. Should we really be specifying this??-->
<browser:defaultView
@@ -45,6 +72,11 @@
name="contents.html"
/>
+ <browser:defaultView
+ for="sqlos.interfaces.container.ISQLObjectJoinContainer"
+ name="contents.html"
+ />
+
<browser:page
name="contents.html"
menu="zmi_views" title="Contents"
@@ -54,6 +86,15 @@
attribute="contents"
/>
+ <browser:page
+ name="contents.html"
+ menu="zmi_views" title="Contents"
+ for=".interfaces.container.ISQLObjectJoinContainer"
+ permission="zope.ManageContent"
+ class="zope.app.container.browser.contents.Contents"
+ attribute="contents"
+ />
+
<class class=".adapter.MySQLAdapter">
<require
permission="zope.Public"
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/container.py
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/container.py (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/container.py Sat Aug 26 11:39:20 2006
@@ -14,6 +14,8 @@
import random
from sqlobject import *
+from sqlos.zsqlobject import SQLOS
+
from persistent import Persistent
from zope.interface import implements
from zope.component import IFactory
@@ -28,8 +30,7 @@
from zope.app.exception.interfaces import UserError
from sqlos.interfaces import ISQLObject, ISQLObjectIsolated, IISQLObject
-from sqlos.interfaces.container import ISQLObjectContainer
-from sqlos.interfaces.container import IIsolatedSQLContainer
+from sqlos.interfaces.container import ISQLObjectContainer, IIsolatedSQLContainer, ISQLObjectMonoContainer, ISQLObjectJoinContainer
def contained(obj, parent=None, name=None):
"""An implementation of zope.app.container.contained.contained
@@ -78,10 +79,20 @@
raise UserError("Cannot find a name") # XXX better message, i18n?
+class SQLObjectMonoNameChooser(NameChooser):
+ """Name chooser for SQLObjectMonoContainer and SQLOSContainer objects"""
+
+ def chooseName(self, name, obj):
+ return str(obj.id)
+
+
class SQLObjectContainer(Persistent, Contained):
implements(ISQLObjectContainer)
+ _monocontainer = False
+ _filters = None
+
def __init__(self):
pass
@@ -95,6 +106,7 @@
# ignore it
if utility is not None:
yield name, utility
+ if self._monocontainer: break
def keys(self):
""" Return a sequence-like object containing the names
@@ -116,8 +128,10 @@
(name, object) for the objects that appear in the folder.
"""
for utility_name, utility in self._getAllowedIISQLObjectUtilities():
- for obj in utility.select():
- name = '%s.%s' % (utility_name, obj.id)
+ for obj in (self._filters and utility.selectBy(**self._filters) or utility.select()):
+ if self._monocontainer:
+ name = isinstance(obj.id, basestring) and obj.id or str(obj.id)
+ else: name = '%s.%s' % (utility_name, obj.id)
yield (name, contained(obj, parent=self, name=name))
def __getitem__(self, name):
@@ -140,20 +154,25 @@
...
KeyError: ...
"""
- if not isinstance(name, basestring):
- raise KeyError, "%s is not a string" % name
- try:
- parts = name.split('.')
- id = parts[-1]
- factoryName = '.'.join(parts[:-1])
- except ValueError:
- raise KeyError, name
+ if not self._monocontainer:
+ if not isinstance(name, basestring):
+ raise KeyError, "%s is not a string" % name
+ try:
+ parts = name.split('.')
+ id = parts[-1]
+ factoryName = '.'.join(parts[:-1])
+ except ValueError:
+ raise KeyError, name
+ else: factoryName, id = None, name
for utility_name, utility in self._getAllowedIISQLObjectUtilities():
- if factoryName != utility_name:
- continue
+ if factoryName and factoryName != utility_name: continue
try:
- obj = utility.get(id)
+ obj = utility.get(utility.sqlmeta.idType(id))
+ if self._filters:
+ for key in self._filters:
+ if getattr(obj, key) != self._filters[key]:
+ raise KeyError, name
return contained(obj, parent=self, name=name)
except (SQLObjectNotFound, ValueError):
# SQlObject raises ValueError if the key is not correct
@@ -179,7 +198,7 @@
"""Return the number of objects in the folder."""
i = 0
for utility_name, utility in self._getAllowedIISQLObjectUtilities():
- i += utility.select().count() # optimal, does not get all objects
+ i += (self._filters and utility.selectBy(**self._filters) or utility.select()).count()
return i
def __delitem__(self, name):
@@ -254,3 +273,85 @@
if self.container_id in obj.domains:
return obj
raise KeyError, name
+
+
+class SQLObjectMonoContainer(SQLObjectContainer):
+ """Mount point for ZSQLObject objects, with multiple item type support
+
+ Test the interface:
+
+ >>> from zope.interface.verify import verifyObject, verifyClass
+ >>> verifyClass(ISQLObjectContainer, SQLObjectMonoContainer)
+ True
+ >>> verifyClass(ISQLObjectMonoContainer, SQLObjectMonoContainer)
+ True
+ >>> c = SQLObjectMonoContainer()
+ >>> verifyObject(ISQLObjectContainer, c)
+ True
+ >>> verifyObject(ISQLObjectMonoContainer, c)
+ True
+ """
+ implements(ISQLObjectMonoContainer)
+
+ _monocontainer = True
+
+
+class SQLOSContainer(SQLOS):
+ """SQLOS subclass for use in Zope 3 as both content and container
+
+ First, make a test data base:
+
+ >>> from sqlos import testing
+ >>> testdb = testing.TestDB([SQLOSContainer])
+
+ Test the interface:
+
+ >>> from zope.interface.verify import verifyObject, verifyClass
+ >>> verifyClass(ISQLObject, SQLOSContainer)
+ True
+ >>> s = SQLOSContainer()
+ >>> verifyObject(ISQLObject, s)
+ True
+ >>> verifyClass(ISQLObjectJoinContainer, SQLOSContainer)
+ True
+ >>> s = SQLOSContainer()
+ >>> verifyObject(ISQLObjectJoinContainer, s)
+ True
+
+ And finally call tearDown and cleanup:
+
+ >>> testdb.tearDown()
+ """
+
+ implements(ISQLObjectJoinContainer)
+
+ def __getitem__(self, name):
+ for j in self.sqlmeta.joins:
+ if name != j.joinDef.name: continue
+ for i, container in self._allowed_joins:
+ if not i.implementedBy(j.otherClass): continue
+ c = container()
+ c._filters = {j.joinColumn[:-3] + 'ID': self.id}
+ return contained(c, parent=self, name=name)
+ raise KeyError, name
+
+ def keys(self):
+ for j in self.sqlmeta.joins:
+ yield j.joinDef.name
+
+ def items(self):
+ for key in self.keys():
+ yield (key, self[key])
+
+ def values(self):
+ for key, obj in self.items():
+ yield obj
+
+ def __contains__(self, name):
+ return name in self.keys()
+
+ def __iter__(self):
+ return iter(self.keys())
+
+ def __len__(self):
+ return len(self.sqlmeta.joins)
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/ftesting.zcml
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/ftesting.zcml (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/ftesting.zcml Sat Aug 26 11:39:20 2006
@@ -48,7 +48,7 @@
low level testing -->
<sqlos:factory
- id="Dog"
+ id="sqlos.somename.Dog"
component=".testing.sampleperson.Dog"
description="A Sample Dog"
/>
@@ -82,11 +82,14 @@
interface="sqlos.testing.sampleperson.IPerson"
set_schema="sqlos.testing.sampleperson.IPerson"
/>
-
<require
permission="zope.View"
interface="sqlos.interfaces.ISQLObject"
/>
+ <require
+ permission="zope.View"
+ interface="zope.app.container.interfaces.IReadContainer"
+ />
</content>
<browser:addform
@@ -118,6 +121,50 @@
view="AddPerson.html"
/>
+ <!-- Define a Sample Dog with some views so we can test through the ZMI -->
+
+ <content class=".testing.sampleperson.Dog">
+ <require
+ permission="zope.ManageContent"
+ interface="sqlos.testing.sampleperson.IDog"
+ set_schema="sqlos.testing.sampleperson.IDog"
+ />
+ <require
+ permission="zope.View"
+ interface="sqlos.interfaces.ISQLObject"
+ />
+ </content>
+
+ <browser:addform
+ schema="sqlos.testing.sampleperson.IDog"
+ content_factory="sqlos.testing.sampleperson.Dog"
+ class=".browser.SQLOSAddView"
+ keyword_arguments="fullname"
+ label="New Sample Dog"
+ name="AddDog.html"
+ permission="zope.ManageContent"
+ />
+
+ <browser:editform
+ schema="sqlos.testing.sampleperson.IDog"
+ name="edit.html"
+ menu="zmi_views"
+ label="Edit a Sample Dog"
+ permission="zope.ManageContent"
+ />
+
+ <browser:defaultView
+ for="sqlos.testing.sampleperson.IDog"
+ name="edit.html"
+ />
+
+ <browser:addMenuItem
+ title="SampleDog"
+ factory="sqlos.somename.Dog"
+ permission="zope.ManageContent"
+ view="AddDog.html"
+ />
+
<!-- Set up a MultiContainer which can contain the Sample People-->
<!--we have to register an adding view for the container, we just use the
@@ -160,4 +207,45 @@
permission="zope.ManageContent"
/>
+ <!-- Dog Container -->
+
+ <browser:view
+ name="+"
+ menu="zmi_actions" title="Add SQLObjects"
+ for="sqlos.testing.sampleperson.IDogContainer"
+ permission="zope.ManageContent"
+ class="zope.app.container.browser.adding.Adding"
+ >
+ <browser:page name="index.html" attribute="index"/>
+ <browser:page name="action.html" attribute="action"/>
+ </browser:view>
+
+ <content class="sqlos.testing.sampleperson.SampleDogContainer">
+ <factory
+ id="sqlos.testing.sampleperson.SampleDogContainer"
+ title="SQLObject Dog Container"
+ description="A persistent container for SQL-backed Dog Objects"
+ />
+ <allow attributes="_filters" />
+ <require
+ permission="zope.View"
+ interface="zope.app.container.interfaces.IReadContainer"
+ />
+ <require
+ permission="zope.ManageContent"
+ interface="zope.app.container.interfaces.IWriteContainer"
+ />
+ <require
+ permission="zope.View"
+ attributes="select"
+ />
+ </content>
+
+ <browser:addMenuItem
+ class="sqlos.testing.sampleperson.SampleDogContainer"
+ title="SQLObject Dog Container"
+ description="A persistent container for SQL-backed Dog Objects"
+ permission="zope.ManageContent"
+ />
+
</configure>
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/containers.txt
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/containers.txt (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/containers.txt Sat Aug 26 11:39:20 2006
@@ -124,7 +124,7 @@
Now we add sally's dog:
- >>> fido = sampleperson.Dog(fullname='Fido', owner='sally')
+ >>> fido = sampleperson.Dog(fullname='Fido', owner=sally)
>>> len(multicontainer)
2
>>> fido in [i for i in multicontainer.values()]
Added: z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/joins.txt
==============================================================================
--- (empty file)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/joins.txt Sat Aug 26 11:39:20 2006
@@ -0,0 +1,67 @@
+Using joins between SQLOS objects
+=================================
+
+First let's set up some tables in the database:
+
+ >>> from sqlos.testing.sampleperson import createTestingTables
+ >>> from sqlos.testing.sampleperson import SamplePerson, Dog, SamplePersonMonoContainer
+ >>> createTestingTables()
+
+Create a new container, and add a SamplePerson object to it:
+
+ >>> container = SamplePersonMonoContainer()
+ >>> len(container)
+ 0
+ >>> from zope.app import zapi
+ >>> from sqlos.interfaces import IISQLObject
+ >>> SamplePerson = zapi.getUtility(IISQLObject,
+ ... u'sqlos.somename.SamplePerson',
+ ... context=container)
+ >>> john = SamplePerson(username='john', fullname='John Black', password='johnpass')
+ >>> len(container)
+ 1
+
+Create an external person with his dog:
+
+ >>> mark = SamplePerson(username='mark', fullname='Mark Brown', password='markpass')
+ >>> lessie = Dog(fullname='lessie', owner=mark)
+
+We have a dog in the system, but it is not owned by John:
+
+ >>> len(john.dogs)
+ 0
+ >>> len(john['dogs'])
+ 0
+
+Now, create a new dog owned by John:
+
+ >>> Dog = zapi.getUtility(IISQLObject,
+ ... u'sqlos.somename.Dog',
+ ... context=container)
+ >>> fido = Dog(fullname='fido', owner=john)
+
+Check if the dog is really owned by John:
+
+ >>> fido.owner == john
+ True
+ >>> [i for i in john.dogs] == [fido]
+ True
+
+Get the container for the join and test it:
+
+ >>> dogs = john['dogs']
+ >>> from zope.interface.verify import verifyObject
+ >>> from sqlos.interfaces.container import ISQLObjectContainer
+ >>> verifyObject(ISQLObjectContainer, dogs)
+ True
+ >>> len(dogs)
+ 1
+ >>> fido.id in dogs
+ True
+ >>> lessie.id in dogs
+ False
+
+CleanUp:
+
+ >>> from sqlos.testing.sampleperson import dropTestingTables
+ >>> dropTestingTables()
Added: z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/joins_browser.txt
==============================================================================
--- (empty file)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/joins_browser.txt Sat Aug 26 11:39:20 2006
@@ -0,0 +1,72 @@
+===============================
+Adding SQLOS objects with joins
+===============================
+
+First let's set up some tables in the database:
+
+ >>> from sqlos.testing.sampleperson import createTestingTables
+ >>> from sqlos.testing.sampleperson import SamplePerson, Dog, SamplePersonContainer
+ >>> createTestingTables()
+
+Then get a browser:
+
+ >>> from zope.testbrowser import Browser
+ >>> browser = Browser()
+ >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw')
+ >>> browser.handleErrors = False
+
+Go to the main interface and add a SQLObject MultiContainer
+
+ >>> browser.open('http://localhost/manage')
+ >>> 'New Sample Person' not in str(browser.contents)
+ True
+ >>> browser.getLink('SQLObject Multi Container').click()
+ >>> browser.getControl(name='new_value').value = 'multicontainer1'
+ >>> browser.getControl('Apply').click()
+
+Now add a Sample Person to the container:
+
+ >>> browser.getLink('multicontainer1').click()
+ >>> browser.getLink('SamplePerson').click()
+ >>> browser.getControl(name='field.fullname').value = 'Bob'
+ >>> browser.getControl(name='field.username').value = 'bob'
+ >>> browser.getControl(name='field.password').value = 'obo'
+ >>> browser.getControl('Add').click()
+
+Lets try to add a dog inside the person:
+
+ >>> browser.getLink('sqlos.somename.SamplePerson.1').click()
+ >>> print browser.contents
+ <BLANKLINE>
+ <!DOC...
+ ...
+ ...Full Name...
+ ...
+ ...Bob...
+ ...
+ ...Username...
+ ...
+ ...bob...
+ ...
+ ...Password...
+ ...
+ ...obo...
+ ...
+ >>> browser.open('http://localhost/multicontainer1/sqlos.somename.SamplePerson.1/dogs')
+ >>> browser.getLink('SampleDog').click()
+ >>> browser.getControl(name='field.fullname').value = 'Fido'
+ >>> browser.getControl('Add').click()
+ >>> browser.open('http://localhost/multicontainer1/sqlos.somename.SamplePerson.1/dogs/1')
+ >>> print browser.contents
+ <BLANKLINE>
+ <!DOC...
+ ...
+ ...Name...
+ ...
+ ...Fido...
+ ...
+
+CleanUp:
+
+ >>> from sqlos.testing.sampleperson import dropTestingTables
+ >>> dropTestingTables()
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/localutilities.txt
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/localutilities.txt (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/localutilities.txt Sat Aug 26 11:39:20 2006
@@ -67,7 +67,7 @@
... '''create table dog (
... id integer primary key,
... fullname varchar(50) not null,
- ... owner varchar(20) not null)''')
+ ... owner_id integer not null)''')
>>> c = cursor.execute(
... '''create table sample_isolated_person (
... id integer primary key,
Added: z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/mono_containers.txt
==============================================================================
--- (empty file)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/mono_containers.txt Sat Aug 26 11:39:20 2006
@@ -0,0 +1,106 @@
+Functional test for SQLOSContainer objects
+==========================================
+
+First, prepare the testing environment:
+
+ >>> from sqlos.testing.sampleperson import SamplePerson, SamplePersonMonoContainer
+ >>> from sqlos.interfaces import ISQLObject
+ >>> from sqlos.interfaces.container import ISQLObjectMonoContainer
+ >>> from zope.interface.verify import verifyObject
+ >>> container = SamplePersonMonoContainer()
+ >>> verifyObject(ISQLObjectMonoContainer, container)
+ True
+
+We are not in the business of letting errors pass silently, so looking inside if
+we get a database error (it must be of the type DatabaseException):
+
+ >>> [i for i in container.items()]
+ Traceback (most recent call last):
+ ...
+ DatabaseException: ...
+
+So let's create some database tables if not already there:
+
+ >>> from sqlos.testing.sampleperson import createTestingTables
+ >>> createTestingTables()
+
+We should now be able to look inside an empty container:
+
+ >>> [i for i in container.keys()]
+ []
+ >>> [i for i in container.items()]
+ []
+ >>> [i for i in container]
+ []
+ >>> [i for i in container.values()]
+ []
+ >>> len(container)
+ 0
+
+Lets create some objects:
+
+ >>> people = [{'username': 'harry',
+ ... 'fullname': 'Harry the Hack',
+ ... 'password': 'harrypass'},
+ ... {'username': 'sally',
+ ... 'fullname': 'Sally the Wack',
+ ... 'password': 'sallypass'}]
+ >>> from zope.app import zapi
+ >>> from sqlos.interfaces import IISQLObject
+ >>> SamplePerson = zapi.getUtility(IISQLObject,
+ ... u'sqlos.somename.SamplePerson',
+ ... context=container)
+ >>> harry = SamplePerson(**people[0])
+ >>> len(container)
+ 1
+ >>> sally = SamplePerson(**people[1])
+ >>> len(container)
+ 2
+
+Lets see whats inside:
+
+ >>> [i[0] for i in container.items()]
+ ['1', '2']
+ >>> [i[1] for i in container.items()] == [harry, sally]
+ True
+ >>> [i for i in container.values()] == [harry, sally]
+ True
+ >>> [i for i in container.keys()]
+ ['1', '2']
+ >>> [i for i in container]
+ ['1', '2']
+
+Let's test to see what the container does with bad id's (must raise KeyError):
+
+ >>> container[3]
+ Traceback (most recent call last):
+ ...
+ KeyError: ...
+
+You can get() as well:
+
+ >>> container.get(1) == harry
+ True
+ >>> container.get('sss', 'default')
+ 'default'
+
+Setitem passes but is really a no-op:
+
+ >>> container['sss'] = 'yyy'
+ >>> len(container)
+ 2
+
+Finally let's delete harry:
+
+ >>> del container[1]
+ >>> len(container)
+ 1
+ >>> container[1]
+ Traceback (most recent call last):
+ ...
+ KeyError: 1
+
+CleanUp:
+
+ >>> from sqlos.testing.sampleperson import dropTestingTables
+ >>> dropTestingTables()
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/test_doctest.py
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/test_doctest.py (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/ftests/test_doctest.py Sat Aug 26 11:39:20 2006
@@ -20,9 +20,13 @@
def test_suite():
filelist = [readme,
+ 'joins_browser.txt',
'adding.txt',
'connection.txt',
'containers.txt',
'localutilities.txt',
- 'isolated_containers.txt']
+ 'isolated_containers.txt',
+ 'mono_containers.txt',
+ 'joins.txt',
+ ]
return FunctionalDocFileSuite(*filelist)
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/interfaces/__init__.py
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/interfaces/__init__.py (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/interfaces/__init__.py Sat Aug 26 11:39:20 2006
@@ -17,6 +17,7 @@
from zope.schema.vocabulary import SimpleVocabulary
from zope.schema import Choice, List
from zope.app.annotation.interfaces import IAttributeAnnotatable
+from zope.app.container.interfaces import IContained
from sqlobject import NoDefault
from sqlobject.dbconnection import DBConnection, DBAPI
from sqlobject import _mysql, _postgres, _sybase
@@ -268,7 +269,7 @@
similar to select()
"""
-class ISQLObject(Interface):
+class ISQLObject(IContained):
# XXX - _idName moved to sqlmeta
#_idName = Attribute('Primary Key')
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/interfaces/container.py
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/interfaces/container.py (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/interfaces/container.py Sat Aug 26 11:39:20 2006
@@ -15,9 +15,13 @@
from zope.app.container.interfaces import IContainerNamesContainer
from zope.app.container.interfaces import IReadContainer, IContainer
+from sqlos.interfaces import ISQLObject
+
+
class ISQLObjectReadContainer(IReadContainer, IAttributeAnnotatable):
""" An SQLObject Container """
+
class ISQLObjectContainer(IContainer, IContainerNamesContainer,
IAttributeAnnotatable):
""" An SQLObject Container """
@@ -27,7 +31,16 @@
__setitem__.precondition = ItemTypePrecondition()
+
class IIsolatedSQLContainer(ISQLObjectContainer):
# TODO Attribute -> zope.schema.* - jinty
container_id = Attribute("The id of the containers, this is a filter on the"
"database table.")
+
+
+class ISQLObjectMonoContainer(IContainer, IContainerNamesContainer, IAttributeAnnotatable):
+ """A single-factory SQLObject container"""
+
+
+class ISQLObjectJoinContainer(ISQLObject, IReadContainer):
+ """Interface for SQLOS objects which expose joins"""
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/testing/sampleperson.py
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/testing/sampleperson.py (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/testing/sampleperson.py Sat Aug 26 11:39:20 2006
@@ -1,13 +1,13 @@
from sqlobject import *
import transaction
-from zope.interface import implements, classProvides, Interface
+from zope.interface import implements, classProvides, Interface, Attribute
from zope.schema import TextLine, Text, Datetime
from zope.app.container import constraints
from sqlos.zsqlobject import SQLOS
from sqlos.interfaces import ISQLSchema, IISQLObjectIsolated, ISQLObjectIsolated
-from sqlos.interfaces.container import ISQLObjectContainer
-from sqlos.container import SQLObjectContainer, SQLIsolatedContainer
+from sqlos.interfaces.container import ISQLObjectContainer, ISQLObjectJoinContainer
+from sqlos.container import SQLObjectContainer, SQLIsolatedContainer, SQLObjectMonoContainer, SQLOSContainer
def createTestingTablesSubscriber(obj):
# An event subscriber that can be used to create the testing tables
@@ -38,6 +38,7 @@
description=u"The user's login")
password = TextLine(title=u'Password',
description=u"The user's password")
+ dogs = Attribute('Dogs')
class IPersonContainer(ISQLObjectContainer):
@@ -50,19 +51,46 @@
constraints.containers(IPersonContainer)
+class IDog(ISQLSchema):
+
+ fullname = TextLine(title=u'Full Name',
+ description=u'The full name of the dog')
+ owner = Attribute(u'Owner')
+
+
+class IDogContainer(ISQLObjectContainer):
+
+ constraints.contains(IDog)
+
+
+class IDogContained(Interface):
+
+ constraints.containers(IDogContainer)
+
+
class SamplePersonContainer(SQLObjectContainer):
implements(IPersonContainer)
-class SamplePerson(SQLOS):
+class SampleDogContainer(SQLObjectMonoContainer):
+ """Sample container for Dog objects"""
+
+ implements(IDogContainer)
+
+
+class SamplePerson(SQLOSContainer):
implements(IPerson, IPersonContained)
+ _allowed_joins = [(IDog, SampleDogContainer)]
+
fullname = StringCol(length=50, notNull=1)
username = StringCol(length=20, notNull=1)
password = StringCol(length=20, notNull=1)
+ dogs = MultipleJoin('Dog', joinColumn='owner_id')
+
class SampleIsolatedPerson(SQLOS):
@@ -112,23 +140,15 @@
implements(IPersonContainer)
-class IDog(ISQLSchema):
-
- fullname = TextLine(title=u'Full Name',
- description=u'The full name of the dog')
- owner = TextLine(title=u'Owner username',
- description=u'The username of the dog\'s owner')
-
-
class Dog(SQLOS):
- implements(IDog)
+ implements(IDog, IDogContained)
fullname = StringCol(length=50, notNull=1)
- owner = StringCol(length=20, notNull=1)
+ owner = ForeignKey('SamplePerson')
-class IMultiContainer(IPersonContainer):
+class IMultiContainer(IPersonContainer, IDogContainer):
constraints.contains(IDog, IPerson)
@@ -136,3 +156,8 @@
class MultiContainer(SQLObjectContainer):
implements(IMultiContainer)
+
+
+class SamplePersonMonoContainer(SQLObjectMonoContainer):
+
+ implements(IPersonContainer)
Modified: z3/sqlos/branch/kobold-sqlos/src/sqlos/zsqlobject.py
==============================================================================
--- z3/sqlos/branch/kobold-sqlos/src/sqlos/zsqlobject.py (original)
+++ z3/sqlos/branch/kobold-sqlos/src/sqlos/zsqlobject.py Sat Aug 26 11:39:20 2006
@@ -13,9 +13,11 @@
from zope.interface import implements
from sqlobject.main import SQLObject
from sqlobject import StringCol
+from zope.app.container.contained import Contained
from sqlos.connection import ConnectionDescriptor
from sqlos.interfaces import ISQLObject
+from sqlos.interfaces.container import ISQLObjectJoinContainer
from sqlos import _transaction
def syncUpdateAll():
@@ -26,7 +28,7 @@
_transaction.dirty_object_registry.syncUpdateAll()
-class SQLOS(SQLObject):
+class SQLOS(SQLObject, Contained):
"""Subclass SQLObject to enable ``lazy updates`` by default,
as well as adding knowledge to register ``dirty`` objects
with SQLObjectTransactionManager so they get sync'd on transaction
@@ -49,7 +51,9 @@
>>> testdb.tearDown()
"""
implements(ISQLObject)
+
_connection = ConnectionDescriptor()
+ _allowed_joins = []
class sqlmeta:
lazyUpdate = True
More information about the z3-checkins
mailing list