merge 3.5
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Mon, 14 Sep 2009 12:50:27 +0200
branch3.5
changeset 3208 11b84e3b9458
parent 3207 2516324401dd (diff)
parent 3203 1366cacd5387 (current diff)
child 3210 44fa8d4a25d5
merge
--- a/cwvreg.py	Mon Sep 14 11:38:30 2009 +0200
+++ b/cwvreg.py	Mon Sep 14 12:50:27 2009 +0200
@@ -140,9 +140,12 @@
                 try:
                     objects = self[btype]
                     assert len(objects) == 1, objects
-                    cls = objects[0]
+                    if btype == etype:
+                        cls = objects[0]
+                    else:
+                        cls = self.etype_class(btype)
                 except ObjectNotFound:
-                    pass
+                    continue
             else:
                 # ensure parent classes are built first
                 self.etype_class(btype)
--- a/entities/lib.py	Mon Sep 14 11:38:30 2009 +0200
+++ b/entities/lib.py	Mon Sep 14 12:50:27 2009 +0200
@@ -11,6 +11,7 @@
 from datetime import datetime
 
 from logilab.common.decorators import cached
+from logilab.common.deprecation import deprecated
 
 from cubicweb import UnknownProperty
 from cubicweb.entity import _marker
@@ -25,7 +26,7 @@
 
 class EmailAddress(AnyEntity):
     id = 'EmailAddress'
-    fetch_attrs, fetch_order = fetch_config(['address', 'alias', 'canonical'])
+    fetch_attrs, fetch_order = fetch_config(['address', 'alias'])
 
     def dc_title(self):
         if self.alias:
@@ -36,15 +37,13 @@
     def email_of(self):
         return self.reverse_use_email and self.reverse_use_email[0]
 
-    @cached
+    @property
+    def prefered(self):
+        return self.prefered_form and self.prefered_form[0] or self
+
+    @deprecated('use .prefered')
     def canonical_form(self):
-        if self.canonical:
-            return self
-        rql = 'EmailAddress X WHERE X identical_to Y, X canonical TRUE, Y eid %(y)s'
-        cnrset = self.req.execute(rql, {'y': self.eid}, 'y')
-        if cnrset:
-            return cnrset.get_entity(0, 0)
-        return None
+        return self.prefered_form and self.prefered_form[0] or self
 
     def related_emails(self, skipeids=None):
         # XXX move to eemail
--- a/entities/test/unittest_base.py	Mon Sep 14 11:38:30 2009 +0200
+++ b/entities/test/unittest_base.py	Mon Sep 14 12:50:27 2009 +0200
@@ -16,7 +16,6 @@
 from cubicweb import ValidationError
 from cubicweb.interfaces import IMileStone, IWorkflowable
 from cubicweb.entities import AnyEntity
-from cubicweb.entities.authobjs import CWUser
 from cubicweb.web.widgets import AutoCompletionWidget
 
 
@@ -60,16 +59,13 @@
 
 class EmailAddressTC(BaseEntityTC):
     def test_canonical_form(self):
-        eid1 = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"')[0][0]
-        eid2 = self.execute('INSERT EmailAddress X: X address "maarten@philips.com", X canonical TRUE')[0][0]
-        self.execute('SET X identical_to Y WHERE X eid %s, Y eid %s' % (eid1, eid2))
-        email1 = self.entity('Any X WHERE X eid %(x)s', {'x':eid1}, 'x')
-        email2 = self.entity('Any X WHERE X eid %(x)s', {'x':eid2}, 'x')
-        self.assertEquals(email1.canonical_form().eid, eid2)
-        self.assertEquals(email2.canonical_form(), email2)
-        eid3 = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr"')[0][0]
-        email3 = self.entity('Any X WHERE X eid %s'%eid3)
-        self.assertEquals(email3.canonical_form(), None)
+        email1 = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"').get_entity(0, 0)
+        email2 = self.execute('INSERT EmailAddress X: X address "maarten@philips.com"').get_entity(0, 0)
+        email3 = self.execute('INSERT EmailAddress X: X address "toto@logilab.fr"').get_entity(0, 0)
+        self.execute('SET X prefered_form Y WHERE X eid %s, Y eid %s' % (email1.eid, email2.eid))
+        self.assertEquals(email1.prefered.eid, email2.eid)
+        self.assertEquals(email2.prefered.eid, email2.eid)
+        self.assertEquals(email3.prefered.eid, email3.eid)
 
     def test_mangling(self):
         eid = self.execute('INSERT EmailAddress X: X address "maarten.ter.huurne@philips.com"')[0][0]
@@ -102,6 +98,7 @@
 class InterfaceTC(EnvBasedTC):
 
     def test_nonregr_subclasses_and_mixins_interfaces(self):
+        CWUser = self.vreg['etypes'].etype_class('CWUser')
         self.failUnless(implements(CWUser, IWorkflowable))
         class MyUser(CWUser):
             __implements__ = (IMileStone,)
@@ -109,9 +106,13 @@
         self.vreg.register_appobject_class(MyUser)
         self.vreg['etypes'].initialization_completed()
         MyUser_ = self.vreg['etypes'].etype_class('CWUser')
-        self.failUnless(MyUser is MyUser_)
+        # a copy is done systematically
+        self.failUnless(issubclass(MyUser_, MyUser))
         self.failUnless(implements(MyUser_, IMileStone))
         self.failUnless(implements(MyUser_, IWorkflowable))
+        # original class should not have beed modified, only the copy
+        self.failUnless(implements(MyUser, IMileStone))
+        self.failIf(implements(MyUser, IWorkflowable))
 
 
 class SpecializedEntityClassesTC(EnvBasedTC):
@@ -134,11 +135,11 @@
                 id = etype
             self.vreg.register_appobject_class(Foo)
             eclass = self.select_eclass('SubDivision')
+            self.failUnless(eclass.__autogenerated__)
             if etype == 'SubDivision':
-                self.failUnless(eclass is Foo)
+                self.assertEquals(eclass.__bases__, (Foo,))
             else:
-                self.failUnless(eclass.__autogenerated__)
-                self.assertEquals(eclass.__bases__, (Foo,))
+                self.assertEquals(eclass.__bases__[0].__bases__, (Foo,))
         # check Division eclass is still selected for plain Division entities
         eclass = self.select_eclass('Division')
         self.assertEquals(eclass.id, 'Division')
--- a/entities/test/unittest_wfobjs.py	Mon Sep 14 11:38:30 2009 +0200
+++ b/entities/test/unittest_wfobjs.py	Mon Sep 14 12:50:27 2009 +0200
@@ -335,12 +335,12 @@
         self.assertEquals(self.member.state, 'asleep')# no change before commit
         self.commit()
         self.member.clear_all_caches()
-        self.assertEquals(self.member.current_workflow.name, "CWUser workflow")
+        self.assertEquals(self.member.current_workflow.name, "default user workflow")
         self.assertEquals(self.member.state, 'activated')
         self.assertEquals(parse_hist(self.member.workflow_history),
                           [('activated', 'deactivated', 'deactivate', None),
                            ('deactivated', 'asleep', None, 'workflow changed to "CWUser"'),
-                           ('asleep', 'activated', None, 'workflow changed to "CWUser workflow"'),])
+                           ('asleep', 'activated', None, 'workflow changed to "default user workflow"'),])
 
 
 from cubicweb.devtools.apptest import RepositoryBasedTC
--- a/schemas/base.py	Mon Sep 14 11:38:30 2009 +0200
+++ b/schemas/base.py	Mon Sep 14 12:50:27 2009 +0200
@@ -52,11 +52,10 @@
     alias   = String(fulltextindexed=True, maxsize=56)
     address = String(required=True, fulltextindexed=True,
                      indexed=True, unique=True, maxsize=128)
-    canonical = Boolean(default=False,
-                        description=_('when multiple addresses are equivalent \
+    prefered_form = SubjectRelation('EmailAddress', cardinality='?*',
+                                    description=_('when multiple addresses are equivalent \
 (such as python-projects@logilab.org and python-projects@lists.logilab.org), set this \
-to true on one of them which is the preferred form.'))
-    identical_to = SubjectRelation('EmailAddress')
+to indicate which is the preferred form.'))
 
 class use_email(RelationType):
     """ """
@@ -71,9 +70,7 @@
     """the prefered email"""
     permissions = use_email.permissions
 
-class identical_to(RelationType):
-    """identical_to"""
-    symetric = True
+class prefered_form(RelationType):
     permissions = {
         'read':   ('managers', 'users', 'guests',),
         # XXX should have update permissions on both subject and object,
@@ -207,10 +204,6 @@
         }
 
 
-class see_also(RelationType):
-    """generic relation to link one entity to another"""
-    symetric = True
-
 class ExternalUri(EntityType):
     """a URI representing an object in external data store"""
     uri = String(required=True, unique=True, maxsize=256,
@@ -254,3 +247,25 @@
     name = String(required=True, unique=True, indexed=True,  maxsize=128,
                   description=_('name of the cache'))
     timestamp = Datetime(default='NOW')
+
+
+# "abtract" relation types, not used in cubicweb itself
+
+class identical_to(RelationType):
+    """identical to"""
+    symetric = True
+    permissions = {
+        'read':   ('managers', 'users', 'guests',),
+        # XXX should have update permissions on both subject and object,
+        #     though by doing this we will probably have no way to add
+        #     this relation in the web ui. The easiest way to acheive this
+        #     is probably to be able to have "U has_update_permission O" as
+        #     RQLConstraint of the relation definition, though this is not yet
+        #     possible
+        'add':    ('managers', RRQLExpression('U has_update_permission S'),),
+        'delete': ('managers', RRQLExpression('U has_update_permission S'),),
+        }
+
+class see_also(RelationType):
+    """generic relation to link one entity to another"""
+    symetric = True
--- a/test/unittest_schema.py	Mon Sep 14 11:38:30 2009 +0200
+++ b/test/unittest_schema.py	Mon Sep 14 12:50:27 2009 +0200
@@ -162,7 +162,7 @@
         expected_relations = ['add_permission', 'address', 'alias', 'allowed_transition',
                               'bookmarked_by', 'by_transition',
 
-                              'canonical', 'cardinality', 'comment', 'comment_format',
+                              'cardinality', 'comment', 'comment_format',
                               'composite', 'condition', 'connait', 'constrained_by', 'content',
                               'content_format', 'created_by', 'creation_date', 'cstrtype', 'custom_workflow', 'cwuri',
 
@@ -175,7 +175,7 @@
                               'from_entity', 'from_state', 'fulltext_container', 'fulltextindexed',
 
                               'has_text',
-                              'identical_to', 'identity', 'in_group', 'in_state', 'indexed',
+                              'identity', 'in_group', 'in_state', 'indexed',
                               'initial_state', 'inlined', 'internationalizable', 'is', 'is_instance_of',
 
                               'label', 'last_login_time', 'login',
@@ -186,7 +186,7 @@
 
                               'ordernum', 'owned_by',
 
-                              'path', 'pkey', 'prenom', 'primary_email',
+                              'path', 'pkey', 'prefered_form', 'prenom', 'primary_email',
 
                               'read_permission', 'relation_type', 'require_group',
 
--- a/web/views/emailaddress.py	Mon Sep 14 11:38:30 2009 +0200
+++ b/web/views/emailaddress.py	Mon Sep 14 12:50:27 2009 +0200
@@ -24,17 +24,9 @@
     def render_entity_attributes(self, entity):
         self.w(u'<h3>')
         entity.view('oneline', w=self.w)
-        if not entity.canonical:
-            canonemailaddr = entity.canonical_form()
-            if canonemailaddr:
-                self.w(u'&#160;(<i>%s</i>)' % canonemailaddr.view('oneline'))
-            self.w(u'</h3>')
-        elif entity.identical_to:
-            self.w(u'</h3>')
-            identicaladdr = [e.view('oneline') for e in entity.identical_to]
-            self.field('identical_to', ', '.join(identicaladdr))
-        else:
-            self.w(u'</h3>')
+        if entity.prefered:
+            self.w(u'&#160;(<i>%s</i>)' % entity.prefered.view('oneline'))
+        self.w(u'</h3>')
         try:
             persons = entity.reverse_primary_email
         except Unauthorized: