--- a/appobject.py Fri Feb 05 17:57:51 2010 +0100
+++ b/appobject.py Mon Feb 08 10:07:52 2010 +0100
@@ -295,7 +295,6 @@
cls.vreg = registry.vreg
cls.schema = registry.schema
cls.config = registry.config
- cls.register_properties()
return cls
@classmethod
--- a/cwvreg.py Fri Feb 05 17:57:51 2010 +0100
+++ b/cwvreg.py Mon Feb 08 10:07:52 2010 +0100
@@ -63,6 +63,7 @@
# registry content
for appobjects in self.itervalues():
for appobject in appobjects:
+ # XXX kill vreg_initialization_completed
appobject.vreg_initialization_completed()
def render(self, __oid, req, __fallback_oid=None, rset=None, initargs=None,
@@ -376,9 +377,12 @@
check=self.config.cleanup_interface_sobjects)
def initialization_completed(self):
- for regname, reg in self.items():
+ for regname, reg in self.iteritems():
self.debug('available in registry %s: %s', regname, sorted(reg))
reg.initialization_completed()
+ for appobjects in reg.itervalues():
+ for appobjectcls in appobjects:
+ appobjectcls.register_properties()
# we may want to keep interface dependent objects (e.g.for i18n
# catalog generation)
if self.config.cleanup_interface_sobjects:
--- a/server/hooks.py Fri Feb 05 17:57:51 2010 +0100
+++ b/server/hooks.py Mon Feb 08 10:07:52 2010 +0100
@@ -8,6 +8,7 @@
"""
__docformat__ = "restructuredtext en"
+from threading import Lock
from datetime import datetime
from cubicweb import UnknownProperty, ValidationError, BadConnectionId
@@ -25,6 +26,41 @@
DONT_CHECK_RTYPES_ON_DEL = set(('is', 'is_instance_of',
'wf_info_for', 'from_state', 'to_state'))
+_UNIQUE_CONSTRAINTS_LOCK = Lock()
+_UNIQUE_CONSTRAINTS_HOLDER = None
+
+class _ReleaseUniqueConstraintsHook(Operation):
+ def commit_event(self):
+ pass
+ def postcommit_event(self):
+ _release_unique_cstr_lock(self.session)
+ def rollback_event(self):
+ _release_unique_cstr_lock(self.session)
+
+def _acquire_unique_cstr_lock(session):
+ """acquire the _UNIQUE_CONSTRAINTS_LOCK for the session.
+
+ This lock used to avoid potential integrity pb when checking
+ RQLUniqueConstraint in two different transactions, as explained in
+ http://intranet.logilab.fr/jpl/ticket/36564
+ """
+ global _UNIQUE_CONSTRAINTS_HOLDER
+ asession = session.actual_session()
+ if _UNIQUE_CONSTRAINTS_HOLDER is asession:
+ return
+ _UNIQUE_CONSTRAINTS_LOCK.acquire()
+ _UNIQUE_CONSTRAINTS_HOLDER = asession
+ # register operation responsible to release the lock on commit/rollback
+ _ReleaseUniqueConstraintsHook(asession)
+
+def _release_unique_cstr_lock(session):
+ global _UNIQUE_CONSTRAINTS_HOLDER
+ if _UNIQUE_CONSTRAINTS_HOLDER is session:
+ _UNIQUE_CONSTRAINTS_HOLDER = None
+ _UNIQUE_CONSTRAINTS_LOCK.release()
+ else:
+ assert _UNIQUE_CONSTRAINTS_HOLDER is None
+
def relation_deleted(session, eidfrom, rtype, eidto):
session.transaction_data.setdefault('pendingrelations', []).append(
@@ -216,6 +252,12 @@
if eidto in pending:
return
for constraint in self.constraints:
+ # XXX
+ # * lock RQLConstraint as well?
+ # * use a constraint id to use per constraint lock and avoid
+ # unnecessary commit serialization ?
+ if isinstance(constraint, RQLUniqueConstraint):
+ _acquire_unique_cstr_lock(self.session)
try:
constraint.repo_check(self.session, eidfrom, rtype, eidto)
except NotImplementedError:
--- a/server/session.py Fri Feb 05 17:57:51 2010 +0100
+++ b/server/session.py Mon Feb 08 10:07:52 2010 +0100
@@ -474,7 +474,8 @@
try:
operation.handle_event('%s_event' % trstate)
except:
- self.exception('error while %sing', trstate)
+ self.critical('error while %sing', trstate,
+ exc_info=sys.exc_info())
self.debug('%s session %s done', trstate, self.id)
finally:
self._touch()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/data/views.py Mon Feb 08 10:07:52 2010 +0100
@@ -0,0 +1,2 @@
+from cubicweb.web.views import xmlrss
+xmlrss.RSSIconBox.visible = True
--- a/test/unittest_vregistry.py Fri Feb 05 17:57:51 2010 +0100
+++ b/test/unittest_vregistry.py Mon Feb 08 10:07:52 2010 +0100
@@ -13,6 +13,7 @@
from cubicweb.appobject import AppObject
from cubicweb.cwvreg import CubicWebVRegistry, UnknownProperty
from cubicweb.devtools import TestServerConfiguration
+from cubicweb.devtools.apptest import EnvBasedTC
from cubicweb.interfaces import IMileStone
from cubes.card.entities import Card
@@ -31,6 +32,14 @@
config.bootstrap_cubes()
self.vreg.schema = config.load_schema()
+ def test___selectors__compat(self):
+ myselector1 = lambda *args: 1
+ myselector2 = lambda *args: 1
+ class AnAppObject(AppObject):
+ __selectors__ = (myselector1, myselector2)
+ AnAppObject.build___select__()
+ self.assertEquals(AnAppObject.__select__(AnAppObject), 2)
+
def test_load_interface_based_vojects(self):
self.vreg.init_registration([WEBVIEWSDIR])
self.vreg.load_file(join(BASE, 'entities', '__init__.py'), 'cubicweb.entities.__init__')
@@ -40,19 +49,6 @@
self.vreg.initialization_completed()
self.assertEquals(len(self.vreg['views']['primary']), 1)
- def test___selectors__compat(self):
- myselector1 = lambda *args: 1
- myselector2 = lambda *args: 1
- class AnAppObject(AppObject):
- __selectors__ = (myselector1, myselector2)
- AnAppObject.build___select__()
- self.assertEquals(AnAppObject.__select__(AnAppObject), 2)
-
- def test_properties(self):
- self.failIf('system.version.cubicweb' in self.vreg['propertydefs'])
- self.failUnless(self.vreg.property_info('system.version.cubicweb'))
- self.assertRaises(UnknownProperty, self.vreg.property_info, 'a.non.existent.key')
-
def test_load_subinterface_based_appobjects(self):
self.vreg.reset()
self.vreg.register_objects([join(BASE, 'web', 'views', 'iprogress.py')])
@@ -68,6 +64,17 @@
# check progressbar isn't kicked
self.assertEquals(len(self.vreg['views']['progressbar']), 1)
+ def test_properties(self):
+ self.failIf('system.version.cubicweb' in self.vreg['propertydefs'])
+ self.failUnless(self.vreg.property_info('system.version.cubicweb'))
+ self.assertRaises(UnknownProperty, self.vreg.property_info, 'a.non.existent.key')
+
+class CWVregTC(EnvBasedTC):
+
+ def test_property_default_overriding(self):
+ # see data/views.py
+ from cubicweb.web.views.xmlrss import RSSIconBox
+ self.assertEquals(self.vreg.property_info(RSSIconBox.propkey('visible'))['default'], True)
if __name__ == '__main__':
unittest_main()
--- a/web/application.py Fri Feb 05 17:57:51 2010 +0100
+++ b/web/application.py Mon Feb 08 10:07:52 2010 +0100
@@ -226,17 +226,23 @@
def __init__(self, config, debug=None,
session_handler_fact=CookieSessionHandler,
vreg=None):
- super(CubicWebPublisher, self).__init__()
- # connect to the repository and get instance's schema
+ self.info('starting web instance from %s', config.apphome)
if vreg is None:
vreg = cwvreg.CubicWebVRegistry(config, debug=debug)
+ need_set_schema = True
+ else:
+ # vreg is specified during test and the vreg is already properly
+ # initialized. Even, reinitializing it may cause some unwanted
+ # side effect due to unproper reloading of appobjects modules
+ need_set_schema = False
self.vreg = vreg
- self.info('starting web instance from %s', config.apphome)
+ # connect to the repository and get instance's schema
self.repo = config.repository(vreg)
if not vreg.initialized:
self.config.init_cubes(self.repo.get_cubes())
vreg.init_properties(self.repo.properties())
- vreg.set_schema(self.repo.get_schema())
+ if need_set_schema:
+ vreg.set_schema(self.repo.get_schema())
# set the correct publish method
if config['query-log-file']:
from threading import Lock