[Grok-dev] getUtility(ICatalog) fails with ComponentLookupError

Àlex Magaz Graça rivaldi8 at gmail.com
Fri Nov 11 23:44:59 UTC 2011


El 11/11/11 13:28, Uli Fouquet escribió:
> Hi there,
>
> Am Freitag, den 11.11.2011, 09:14 +0100 schrieb Christian Klinger:
>
>> what kind of testsetup do you use in your unittest?
>> Do you use the default setup?
>  From the snippets sent by Alex I get the impression that the test setup
> is rather plain: no layer, no 'FunctionalTestCase' of any kind, just
> pure unittest.TestCase.
>
> In case of catalogs that quickly means trouble. While Sylvains hint to
> use setSite() is correct, there are still some caveats to consider:
>
> Catalogs are created automatically when you add a grok.Application
> instance (like a HelpDesk instance) to the ZODB. The catalog creation is
> triggered by an event handler for IObjectAddedEvent.
>
> So, there should be no need to create the catalog in tests manually.
>
> To have a ZODB available during testing, you certainly want some kind of
> 'functional' test setup. What you need then, is some real 'root' meaning
> the root object of the ZODB activated during tests. This is normally the
> main thing created by functional test setups (beside registrations and
> all that).
>
> If you have this root, you should be able to follow the examples from
> docs as stated:
>
>    >>>  root['app'] = HelpDesk()
>    >>>  from zope.component.hooks import setSite
>    >>>  setSite(root['app'])
>
> and also the catalog lookup should work.
>
> By the way: if you use `bin/interactive_debugger` instead of
> `bin/python_console` you should get a functional environment around your
> Python shell where you can do things like above as you like. One main
> difference is: you get a 'root' of ZODB and all components defined in
> your code (like the indexes etc.) are registered on startup of this
> 'high-level' console. The interactive debugger has access to the local
> ZODB (but be aware that you work on the real ZODB data there).
>
> A nice side-effect if you do 'functional' testing is that new objects
> added to the ZODB (yes, they won't be catalogued before put in the ZODB,
> because catalogs also rely on IObjectAddedEvents which are triggered by
> ZODB additions) will be searchable afterwards.
>
> Otherwise - after enourmous efforts to make your catalog findable in a
> pure unittest.TestCase environment - you might hit the next big problem:
> your objects won't be catalogued as expected.
>
> I admit that setting up catalogs and their persistence is really
> difficult or even nasty to manage sometimes (just think of the problems
> when trying to add/remove indexes from existing catalogs), but for now I
> don't know of something better.
>
> Best regards,

Hi Christian and Uli,

You were right, the problem was I had a plain unit test. Now it founds 
ICatalog, but another error appears:

File 
"/home/alex/uni/projecte/repo/list-active-tickets/HelpDesk/src/helpdesk/tests/app.txt", 
line 15, in app.txt
Failed example:
     t1 = catalog.openNewTicket("0", "summary1", "description1")
Exception raised:
     Traceback (most recent call last):
       File "/usr/lib/python2.7/doctest.py", line 1254, in __run
         compileflags, 1) in test.globs
       File "<doctest app.txt[6]>", line 1, in <module>
         t1 = catalog.openNewTicket("0", "summary1", "description1")
       File 
"/home/alex/uni/projecte/repo/list-active-tickets/HelpDesk/src/helpdesk/app.py", 
line 22, in openNewTicket
         self[ str(ticketNumber) ] = Ticket(ticketNumber, uid, summary, 
description)
       File 
"/home/alex/.buildout/eggs/zope.container-3.12.0-py2.7-linux-x86_64.egg/zope/container/btree.py", 
line 112, in __setitem__
         setitem(self, self._setitemf, key, value)
       File 
"/home/alex/.buildout/eggs/zope.container-3.12.0-py2.7-linux-x86_64.egg/zope/container/contained.py", 
line 559, in setitem
         notify(event)
       File 
"/home/alex/.buildout/eggs/zope.event-3.5.0_1-py2.7.egg/zope/event/__init__.py", 
line 23, in notify
         subscriber(event)
       File 
"/home/alex/.buildout/eggs/zope.component-3.10.0-py2.7.egg/zope/component/event.py", 
line 24, in dispatch
         zope.component.subscribers(event, None)
       File 
"/home/alex/.buildout/eggs/zope.component-3.10.0-py2.7.egg/zope/component/_api.py", 
line 136, in subscribers
         return sitemanager.subscribers(objects, interface)
       File 
"/home/alex/.buildout/eggs/zope.component-3.10.0-py2.7.egg/zope/component/registry.py", 
line 321, in subscribers
         return self.adapters.subscribers(objects, provided)
       File 
"/home/alex/.buildout/eggs/zope.interface-3.6.3-py2.7-linux-x86_64.egg/zope/interface/adapter.py", 
line 583, in subscribers
         subscription(*objects)
       File 
"/home/alex/.buildout/eggs/zope.component-3.10.0-py2.7.egg/zope/component/event.py", 
line 32, in objectEventNotify
         zope.component.subscribers((event.object, event), None)
       File 
"/home/alex/.buildout/eggs/zope.component-3.10.0-py2.7.egg/zope/component/_api.py", 
line 136, in subscribers
         return sitemanager.subscribers(objects, interface)
       File 
"/home/alex/.buildout/eggs/zope.component-3.10.0-py2.7.egg/zope/component/registry.py", 
line 321, in subscribers
         return self.adapters.subscribers(objects, provided)
       File 
"/home/alex/.buildout/eggs/zope.interface-3.6.3-py2.7-linux-x86_64.egg/zope/interface/adapter.py", 
line 583, in subscribers
         subscription(*objects)
       File 
"/home/alex/.buildout/eggs/zope.intid-3.7.2-py2.7.egg/zope/intid/__init__.py", 
line 166, in addIntIdSubscriber
         key = IKeyReference(ob, None)
       File 
"/home/alex/.buildout/eggs/zope.component-3.10.0-py2.7.egg/zope/component/hookable.py", 
line 33, in __call__
         return self.__implementation(*args, **kw)
       File 
"/home/alex/.buildout/eggs/zope.component-3.10.0-py2.7.egg/zope/component/hooks.py", 
line 104, in adapter_hook
         return siteinfo.adapter_hook(interface, object, name, default)
       File 
"/home/alex/.buildout/eggs/zope.security-3.8.2-py2.7-linux-x86_64.egg/zope/security/adapter.py", 
line 86, in __call__
         adapter = self.factory(*args)
       File 
"/home/alex/.buildout/eggs/zope.keyreference-3.6.2-py2.7.egg/zope/keyreference/persistent.py", 
line 40, in __init__
         raise zope.keyreference.interfaces.NotYet(object)
     NotYet: <helpdesk.app.Ticket object at 0x3d62938>

I found the following thread, but I think it doesn't apply in my case as 
I'm not adding anything from __init__()

http://osdir.com/ml/web.zope.grok.devel/2007-07/msg00143.html

My code is something like this:

class Helpdesk(grok.Application, grok.Container):
     def __init__(self):
         super(Helpdesk, self).__init__()
         self.ticketCatalog = TicketCatalog()

class TicketCatalog(grok.Container):
     def __init__(self):
         super(TicketCatalog, self).__init__()

     def openNewTicket(self, uid, summary, description):
         ticketNumber = self.nextTicketNumber()
         self[ str(ticketNumber) ] = Ticket(ticketNumber, uid, summary, 
description)

class Ticket(grok.Model):
     ...

and my functional test:

 >>> from helpdesk.app import Helpdesk
 >>> from zope.component.hooks import setSite
 >>> root = getRootFolder()
 >>> root['app'] = Helpdesk()
 >>> setSite(root['app'])
 >>> catalog = root['app'].ticketCatalog
 >>> t1 = catalog.openNewTicket("0", "summary1", "description1")
 >>> activeTickets = catalog.getActiveTickets()
 >>> len(activeTickets)
     1


Am I doing something wrong?

Thanks,
Àlex


More information about the Grok-dev mailing list