ComponentLookupError when querying the registry at startup

I am creating an application that queries some data in an external relational database using collect.lead (trunk). The user can change the database connection settings in a custom tool of the Plone panel (I followed the example in the Aspeli Professional Plone Development development book). Thus, the database parameters are set in this way.

My configure.zcml product database installs a utility for the database:

<include package="plone.app.registry" /> <include package="collective.lead" /> <i18n:registerTranslations directory="locales" /> <utility provides="collective.lead.interfaces.IDatabase" factory=".dbsettings.CalculatorDatabase" name="test.calc.db" /> 

dbsettings.py has:

 from zope.component import getUtility from plone.registry.interfaces import IRegistry class CalculatorDatabase(Database): @property def _url(self): registry = getUtility(IRegistry) settings = registry.forInterface(IDatabaseSettings) return URL( drivername=settings.drivername, username=settings.username, password=settings.password, host=settings.hostname, port=settings.port, database=settings.database, ) 

This raises a ComponentLookupError exception at runtime:

 File "/home/zope/envs/test-web/src/test.calc/test/calc/dbsettings.py", line 38, in _url registry = getUtility(IRegistry) File "/home/zope/envs/test-web/eggs/zope.component-3.7.1-py2.6.egg/zope/component/_api.py", line 171, in getUtility raise ComponentLookupError(interface, name) zope.configuration.config.ConfigurationExecutionError: <class 'zope.component.interfaces.ComponentLookupError'>: (<InterfaceClass plone.registry.interfaces.IRegistry>, '') in: File "/home/zope/envs/test-web/src/test.calc/test/calc/configure.zcml", line 26.2-30.6 <utility provides="collective.lead.interfaces.IDatabase" factory=".dbsettings.CalculatorDatabase" name="test.calc.db" /> 

Why is the registry not found at runtime? What am I doing wrong?

Thanks.

+6
source share
3 answers

What Steve mentions is the root of the problem, so I will only add a workaround for cases where you cannot handle exception handling. In a similar scenario, I needed to register a utility, depending on the settings stored in the registry. The utility cannot be registered without these settings, so I absolutely wanted everything to be in order.

The workaround was not to register the utility in zcml, but instead to do it inside the following subscriber:

 <subscriber for="Products.CMFPlone.interfaces.IPloneSiteRoot zope.app.publication.interfaces.IBeforeTraverseEvent" handler=".component.setupStuff" /> 

This ensures that setupStuff will have access to all local utilities. Also note that setupStuff also return quickly after a request if the utility already exists, since the subscriber will be launched for each request.

+5
source

The .lead collective has been replaced by http://pypi.python.org/pypi/z3c.saconfig , which allows you to define database connections in zcml. It can be used with http://pypi.python.org/pypi/collective.saconnect if you need a control panel to configure the connection.

+6
source

The registry is a local component. Each Plone site (and there may be many in the database) has its own. Thus, it depends on the context.

Zope defines this context during the crawl (connecting the URL to the object). This (to a large extent) means that you can only search the registry in the context of a query. Therefore, you cannot find the registry in the startup code.

This can lead to writing code with chicken eggs. One solution is to embed the search in try / except, which handles the search exception gracefully if you don't already have a crawl context.

+5
source

Source: https://habr.com/ru/post/890516/


All Articles