[Zope3-Users] Re: sqlos, sites and local utilities

Andreas Elvers andreas at work.de
Wed Nov 16 10:13:23 EST 2005

Stephan Richter wrote:
> On Tuesday 08 November 2005 05:38, Andreas Elvers wrote:
>>Has anyone yet tried sqlos with database connections created as local
>>utilities ? At one point sqlos tries to get the utility in connection.py
>>Line 88.
>>  newconn = zapi.queryUtility(IZopeDatabaseAdapter, name,
>>                                                     default=None,
>>                                                     context=context)
>>The context points to a sqlobject instance. The problem is that these
>>instances seem to have no parent and thus will fail the lookup my local
>>utility and will raise an 'NoneType' object is not callable error later
>>in the code when trying to adapt.
>>When you try the sqlos example everything is fine, since the database
>>connection is defined in configure.zcml as a global utility.
>>My current idea is to expose the enclosing folder as a context to query
>>utility. But I don't know if setting references in sqlobject instances
>>is such a great idea.
> If the sqlobject instance does not have a parent, then that's bad. It probably 
> does not have a parent, because it is usually wrapped using a location proxy, 
> which is lost inside a method. I think the smart thing to do here would be 
> what you suggested or to write a subclass of sqlobject that implements 
> ILocation.


While digging a bit depper into my problem I found out, that 
implementing ILocation
will not do the trick, since the mentioned exception is caused by a 
factory call, and
a factory will never have a __parent__ or am I totally wrong here ?

Anyway I have created a functional unit test to demonstrate the problem. 
In fact
the unit test shows that sqlos will always lookup global utilities and 
never local utilities.

Here is the test. It will fail in the last block on 
"testsite['personcontainer'] = personcontainer".

- Andreas

-------------- next part --------------
First we need to set up some folder structure to set up a site.

    >>> from zope.app import zapi
    >>> from zope.app.folder import Folder
    >>> from zope.app.container.contained import Contained
    >>> from sqlos.testing.sampleperson import SamplePersonContainer, createTestingTables
    >>> from zope.app.component import interfaces as componentInterfaces
    >>> from zope.app.component.site import LocalSiteManager,SiteManagerContainer
    >>> from sqlos.container import SQLObjectContainer

    >>> class LocalSitePersonContainer(SamplePersonContainer, SiteManagerContainer, Contained):
    ...    pass

    >>> root = getRootFolder()
    >>> testsite = Folder()
    >>> root['testsite'] = testsite
    >>> componentInterfaces.ISite.providedBy(testsite)

    >>> sm = LocalSiteManager(testsite)
    >>> testsite.setSiteManager(sm)
    >>> componentInterfaces.ISite.providedBy(testsite)

Now we set up a local database utility

    >>> from zope.app.rdb.interfaces import IZopeDatabaseAdapter
    >>> from zope.app.component.interfaces.registration import ActiveStatus,InactiveStatus
    >>> from sqlos.testing.testdb import SQLiteda
    >>> from zope.app.utility import UtilityRegistration

    >>> dbAdapter = SQLiteda(u'dbi://:memory:') 
    >>> reg = UtilityRegistration('sqlite',IZopeDatabaseAdapter,dbAdapter)
    >>> default = sm['default']
    >>> key = default.registrationManager.addRegistration(reg)
    >>> zapi.traverse(default.registrationManager, key).status = ActiveStatus

    >>> localUtility = sm.queryUtility(IZopeDatabaseAdapter,'sqlite')
    >>> localUtility
    <sqlos.testing.testdb.SQLiteda object at ...>

    >>> localUtility is dbAdapter

Ok. Now we have a site in root/testsite with a registered sqlite adapter.
We make sure that our localUtility is not identical to the global sqlite utility
that has been registered through ftesting.zcml.

    >>> gsm = zapi.getGlobalSiteManager()
    >>> globalUtility = gsm.queryUtility(IZopeDatabaseAdapter,'sqlite')
    >>> globalUtility is not localUtility

Now we populate testsite with data. We do this by using direct SQL, because there is currently
no support for local sites in testcode.

    >>> from zope.component.interfaces import ISiteManager

    >>> cursor = localUtility().cursor()

    >>> cursor.execute(
    ...         '''create table dog (
    ...                   id integer primary key,
    ...                   fullname varchar(50) not null,
    ...                   owner varchar(20) not null)''')
    >>> cursor.execute(
    ...         '''create table sample_isolated_person (
    ...                   id integer primary key,
    ...                   domains text,
    ...                   fullname varchar(50) not null,
    ...                   username varchar(20) not null,
    ...                   password varchar(20) not null)''')
    >>> cursor.execute(
    ...         '''create table sample_person (
    ...                       id integer primary key,
    ...                   fullname varchar(50),
    ...                   username varchar(20),
    ...                   password varchar(20))''')

Now that we have setup database tables we should be able to create the personcontainer without errors.

    >>> personcontainer = LocalSitePersonContainer()
    >>> testsite['personcontainer'] = personcontainer
    >>> localUtility2 = ISiteManager(personcontainer).queryUtility(IZopeDatabaseAdapter,'sqlite')
    >>> localUtility2 is localUtility


More information about the Zope3-users mailing list