Commit 64f29aba authored by Wichert Akkerman's avatar Wichert Akkerman

Delay registration of python packages until a moment when a ZODB connection is...

Delay registration of python packages until a moment when a ZODB connection is available http://www.zope.org/Collectors/Zope/2293
parent c1f7b585
...@@ -633,6 +633,24 @@ def install_products(app): ...@@ -633,6 +633,24 @@ def install_products(app):
install_product(app, product_dir, product_name, meta_types, install_product(app, product_dir, product_name, meta_types,
folder_permissions, raise_exc=debug_mode) folder_permissions, raise_exc=debug_mode)
# Delayed install of products-as-packages
for module_, init_func in getattr(Products, '_packages_to_initialize', []):
try:
product = App.Product.initializeProduct(module_,
module_.__name__,
module_.__path__[0],
app)
product.package_name = module_.__name__
if init_func is not None:
newContext = ProductContext(product, app, module_)
init_func(newContext)
finally:
transaction.commit()
if hasattr(Products, '_packages_to_initialize'):
del Products._packages_to_initialize
Products.meta_types=Products.meta_types+tuple(meta_types) Products.meta_types=Products.meta_types+tuple(meta_types)
InitializeClass(Folder.Folder) InitializeClass(Folder.Folder)
......
...@@ -705,6 +705,7 @@ class ObjectManager( ...@@ -705,6 +705,7 @@ class ObjectManager(
out=out+((k,stat),) out=out+((k,stat),)
return marshal.dumps(out) return marshal.dumps(out)
security.declareProtected(access_contents_information, 'manage_hasId')
def manage_hasId(self, REQUEST): def manage_hasId(self, REQUEST):
""" check if the folder has an object with REQUEST['id'] """ """ check if the folder has an object with REQUEST['id'] """
......
...@@ -411,6 +411,16 @@ class ObjectManagerTests(PlacelessSetup, unittest.TestCase): ...@@ -411,6 +411,16 @@ class ObjectManagerTests(PlacelessSetup, unittest.TestCase):
self.failUnless(filename.endswith('.zexp') or self.failUnless(filename.endswith('.zexp') or
filename.endswith('.xml')) filename.endswith('.xml'))
def test_hasId(self):
om = self._makeOne()
request={'id' : 'test'}
self.assertRaises(KeyError, om.manage_hasId, request)
si = SimpleItem('test')
om._setObject('test', si)
om.manage_hasId(request)
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest( unittest.makeSuite( ObjectManagerTests ) ) suite.addTest( unittest.makeSuite( ObjectManagerTests ) )
......
...@@ -206,29 +206,19 @@ def _registerPackage(module_, init_func=None): ...@@ -206,29 +206,19 @@ def _registerPackage(module_, init_func=None):
raise ValueError("Must be a package and the " \ raise ValueError("Must be a package and the " \
"package must be filesystem based") "package must be filesystem based")
app = Zope2.app()
try:
product = initializeProduct(module_,
module_.__name__,
module_.__path__[0],
app)
product.package_name = module_.__name__
if init_func is not None:
newContext = ProductContext(product, app, module_)
init_func(newContext)
registered_packages = getattr(Products, '_registered_packages', None) registered_packages = getattr(Products, '_registered_packages', None)
if registered_packages is None: if registered_packages is None:
registered_packages = Products._registered_packages = [] registered_packages = Products._registered_packages = []
registered_packages.append(module_) registered_packages.append(module_)
finally:
try: # Delay the actual setup until the usual product loading time in
import transaction # OFS.Application. Otherwise, we may get database write errors in
transaction.commit() # ZEO, when there's no connection with which to write an entry to
finally: # Control_Panel. We would also get multiple calls to initialize().
app._p_jar.close() to_initialize = getattr(Products, '_packages_to_initialize', None)
if to_initialize is None:
to_initialize = Products._packages_to_initialize = []
to_initialize.append((module_, init_func,))
def registerPackage(_context, package, initialize=None): def registerPackage(_context, package, initialize=None):
"""ZCML directive function for registering a python package product """ZCML directive function for registering a python package product
......
...@@ -49,15 +49,21 @@ def test_registerPackage(): ...@@ -49,15 +49,21 @@ def test_registerPackage():
... /> ... />
... </configure>''' ... </configure>'''
>>> zcml.load_string(configure_zcml) >>> zcml.load_string(configure_zcml)
pythonproduct2 initialized
We need to load the product as well. This would normally happen during
Zope startup, but in the test, we're already too late.
>>> import Zope2
>>> from OFS.Application import install_products
>>> app = Zope2.app()
>>> install_products(app)
pythonproduct2 initialized
Test to see if the pythonproduct2 python package actually gets setup Test to see if the pythonproduct2 python package actually gets setup
as a zope2 product in the Control Panel. as a zope2 product in the Control Panel.
>>> product_listing = [] >>> product_listing = []
>>> import Zope2
>>> app = Zope2.app()
>>> try: >>> try:
... product_listing = app.Control_Panel.Products.objectIds() ... product_listing = app.Control_Panel.Products.objectIds()
... finally: ... finally:
......
...@@ -26,6 +26,7 @@ $Id$ ...@@ -26,6 +26,7 @@ $Id$
""" """
import os, sys, time import os, sys, time
import transaction
# Allow code to tell it is run by the test framework # Allow code to tell it is run by the test framework
os.environ['ZOPETESTCASE'] = '1' os.environ['ZOPETESTCASE'] = '1'
...@@ -143,11 +144,36 @@ def hasProduct(name): ...@@ -143,11 +144,36 @@ def hasProduct(name):
'''Checks if a product can be found along Products.__path__''' '''Checks if a product can be found along Products.__path__'''
return name in [n[1] for n in get_products()] return name in [n[1] for n in get_products()]
def installProduct(name, quiet=0): def installProduct(name, quiet=0, package=False):
'''Installs a Zope product.''' '''Installs a Zope product.'''
start = time.time() start = time.time()
meta_types = [] meta_types = []
if _patched and not _installedProducts.has_key(name): if _patched and not _installedProducts.has_key(name):
if package:
# Processing of products-as-packages can be simpler; also check
# whether this has been registered with <five:registerPackage />
# and has not been loaded.
for module_, init_func in getattr(Products, '_packages_to_initialize', []):
if module_.__name__ == name:
if not quiet: _print('Installing %s ... ' % name)
try:
product = App.Product.initializeProduct(module_,
module_.__name__,
module_.__path__[0],
_theApp)
product.package_name = module_.__name__
if init_func is not None:
newContext = App.ProductContext.ProductContext(product, app, module_)
init_func(newContext)
finally:
transaction.commit()
Globals.InitializeClass(Folder)
if not quiet: _print('done (%.3fs)\n' % (time.time() - start))
break
else:
for priority, product_name, index, product_dir in get_products(): for priority, product_name, index, product_dir in get_products():
if product_name == name: if product_name == name:
if not quiet: _print('Installing %s ... ' % product_name) if not quiet: _print('Installing %s ... ' % product_name)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment