[schemaserial] serialize additional yams parameter for customs type
Yams have a new custom type feature. We add support for extra parameter on
CWAttribute in schema serialization handling.
Closes #2847151
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/misc/migration/3.17.0_Any.py Fri Apr 26 17:46:56 2013 +0200
@@ -0,0 +1,1 @@
+add_attribute('CWAttribute', 'extra_props')
--- a/schema.py Tue Apr 23 14:13:58 2013 +0200
+++ b/schema.py Fri Apr 26 17:46:56 2013 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -90,11 +90,9 @@
_LOGGER = getLogger('cubicweb.schemaloader')
-# schema entities created from serialized schema have an eid rproperty
+# entity and relation schema created from serialized schema have an eid
ybo.ETYPE_PROPERTIES += ('eid',)
ybo.RTYPE_PROPERTIES += ('eid',)
-ybo.RDEF_PROPERTIES += ('eid',)
-
PUB_SYSTEM_ENTITY_PERMS = {
'read': ('managers', 'users', 'guests',),
@@ -296,6 +294,9 @@
RelationDefinitionSchema._RPROPERTIES['eid'] = None
+# remember rproperties defined at this point. Others will have to be serialized in
+# CWAttribute.extra_props
+KNOWN_RPROPERTIES = RelationDefinitionSchema.ALL_PROPERTIES()
def rql_expression(self, expression, mainvars=None, eid=None):
"""rql expression factory"""
--- a/schemas/bootstrap.py Tue Apr 23 14:13:58 2013 +0200
+++ b/schemas/bootstrap.py Fri Apr 26 17:46:56 2013 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -21,7 +21,7 @@
__docformat__ = "restructuredtext en"
_ = unicode
-from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
+from yams.buildobjs import (EntityType, RelationType, RelationDefinition, Bytes,
SubjectRelation, RichString, String, Boolean, Int)
from cubicweb.schema import (
RQLConstraint,
@@ -84,6 +84,7 @@
fulltextindexed = Boolean(description=_('index this attribute\'s value in the plain text index'))
internationalizable = Boolean(description=_('is this attribute\'s value translatable'))
defaultval = String(maxsize=256)
+ extra_props = Bytes(description=_('additional type specific properties'))
description = RichString(internationalizable=True,
description=_('semantic description of this attribute'))
--- a/server/schemaserial.py Tue Apr 23 14:13:58 2013 +0200
+++ b/server/schemaserial.py Fri Apr 26 17:46:56 2013 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -21,16 +21,18 @@
import os
from itertools import chain
+import json
from logilab.common.shellutils import ProgressBar
from yams import BadSchemaDefinition, schema as schemamod, buildobjs as ybo
-from cubicweb import CW_SOFTWARE_ROOT
-from cubicweb.schema import (CONSTRAINTS, ETYPE_NAME_MAP,
+from cubicweb import CW_SOFTWARE_ROOT, Binary
+from cubicweb.schema import (KNOWN_RPROPERTIES, CONSTRAINTS, ETYPE_NAME_MAP,
VIRTUAL_RTYPES, PURE_VIRTUAL_RTYPES)
from cubicweb.server import sqlutils
+
def group_mapping(cursor, interactive=True):
"""create a group mapping from an rql cursor
@@ -195,7 +197,12 @@
if rdefs is not None:
ertidx[rdefeid] = rdefs
set_perms(rdefs, permsidx)
-
+ # Get the type parameters for additional base types.
+ try:
+ extra_props = dict(session.execute('Any X, XTP WHERE X is CWAttribute, '
+ 'X extra_props XTP'))
+ except Exception:
+ extra_props = {} # not yet in the schema (introduced by 3.17 migration)
for values in session.execute(
'Any X,SE,RT,OE,CARD,ORD,DESC,IDX,FTIDX,I18N,DFLT WHERE X is CWAttribute,'
'X relation_type RT, X cardinality CARD, X ordernum ORD, X indexed IDX,'
@@ -203,10 +210,12 @@
'X fulltextindexed FTIDX, X from_entity SE, X to_entity OE',
build_descr=False):
rdefeid, seid, reid, oeid, card, ord, desc, idx, ftidx, i18n, default = values
+ typeparams = extra_props.get(rdefeid)
+ typeparams = json.load(typeparams) if typeparams else {}
_add_rdef(rdefeid, seid, reid, oeid,
cardinality=card, description=desc, order=ord,
indexed=idx, fulltextindexed=ftidx, internationalizable=i18n,
- default=default)
+ default=default, **typeparams)
for values in session.execute(
'Any X,SE,RT,OE,CARD,ORD,DESC,C WHERE X is CWRelation, X relation_type RT,'
'X cardinality CARD, X ordernum ORD, X description DESC, '
@@ -509,10 +518,14 @@
def _rdef_values(rdef):
amap = {'order': 'ordernum', 'default': 'defaultval'}
values = {}
- for prop, default in rdef.rproperty_defs(rdef.object).iteritems():
+ extra = {}
+ for prop in rdef.rproperty_defs(rdef.object):
if prop in ('eid', 'constraints', 'uid', 'infered', 'permissions'):
continue
value = getattr(rdef, prop)
+ if prop not in KNOWN_RPROPERTIES:
+ extra[prop] = value
+ continue
# XXX type cast really necessary?
if prop in ('indexed', 'fulltextindexed', 'internationalizable'):
value = bool(value)
@@ -526,6 +539,8 @@
if not isinstance(value, unicode):
value = unicode(value)
values[amap.get(prop, prop)] = value
+ if extra:
+ values['extra_props'] = Binary(json.dumps(extra))
relations = ['X %s %%(%s)s' % (attr, attr) for attr in sorted(values)]
return relations, values
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/data-schemaserial/bootstrap_cubes Fri Apr 26 17:46:56 2013 +0200
@@ -0,0 +1,1 @@
+card,comment,folder,tag,basket,email,file,localperms
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/data-schemaserial/schema.py Fri Apr 26 17:46:56 2013 +0200
@@ -0,0 +1,256 @@
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+
+from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
+ SubjectRelation, RichString, String, Int, Float,
+ Boolean, Datetime, TZDatetime, Bytes)
+from yams.constraints import SizeConstraint
+from cubicweb.schema import (WorkflowableEntityType,
+ RQLConstraint, RQLUniqueConstraint,
+ ERQLExpression, RRQLExpression)
+
+from yams.buildobjs import make_type
+BabarTestType = make_type('BabarTestType')
+
+
+class Affaire(WorkflowableEntityType):
+ __permissions__ = {
+ 'read': ('managers',
+ ERQLExpression('X owned_by U'), ERQLExpression('X concerne S?, S owned_by U')),
+ 'add': ('managers', ERQLExpression('X concerne S, S owned_by U')),
+ 'update': ('managers', 'owners', ERQLExpression('X in_state S, S name in ("pitetre", "en cours")')),
+ 'delete': ('managers', 'owners', ERQLExpression('X concerne S, S owned_by U')),
+ }
+
+ ref = String(fulltextindexed=True, indexed=True,
+ constraints=[SizeConstraint(16)])
+ sujet = String(fulltextindexed=True,
+ constraints=[SizeConstraint(256)])
+ descr = RichString(fulltextindexed=True,
+ description=_('more detailed description'))
+
+ duration = Int()
+ invoiced = Float()
+ opt_attr = Bytes()
+
+ depends_on = SubjectRelation('Affaire')
+ require_permission = SubjectRelation('CWPermission')
+ concerne = SubjectRelation(('Societe', 'Note'))
+ todo_by = SubjectRelation('Personne', cardinality='?*')
+ documented_by = SubjectRelation('Card')
+
+
+class Societe(EntityType):
+ __unique_together__ = [('nom', 'type', 'cp')]
+ __permissions__ = {
+ 'read': ('managers', 'users', 'guests'),
+ 'update': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
+ 'delete': ('managers', 'owners', ERQLExpression('U login L, X nom L')),
+ 'add': ('managers', 'users',)
+ }
+
+ nom = String(maxsize=64, fulltextindexed=True)
+ web = String(maxsize=128)
+ type = String(maxsize=128) # attribute in common with Note
+ tel = Int()
+ fax = Int()
+ rncs = String(maxsize=128)
+ ad1 = String(maxsize=128)
+ ad2 = String(maxsize=128)
+ ad3 = String(maxsize=128)
+ cp = String(maxsize=12)
+ ville= String(maxsize=32)
+
+
+class Division(Societe):
+ __specializes_schema__ = True
+
+class SubDivision(Division):
+ __specializes_schema__ = True
+
+class travaille_subdivision(RelationDefinition):
+ subject = 'Personne'
+ object = 'SubDivision'
+
+from cubicweb.schemas.base import CWUser
+CWUser.get_relations('login').next().fulltextindexed = True
+
+class Note(WorkflowableEntityType):
+ date = String(maxsize=10)
+ type = String(maxsize=6)
+ para = String(maxsize=512,
+ __permissions__ = {
+ 'read': ('managers', 'users', 'guests'),
+ 'update': ('managers', ERQLExpression('X in_state S, S name "todo"')),
+ })
+
+ migrated_from = SubjectRelation('Note')
+ attachment = SubjectRelation('File')
+ inline1 = SubjectRelation('Affaire', inlined=True, cardinality='?*',
+ constraints=[RQLUniqueConstraint('S type T, S inline1 A1, A1 todo_by C, '
+ 'Y type T, Y inline1 A2, A2 todo_by C',
+ 'S,Y')])
+ todo_by = SubjectRelation('CWUser')
+
+class Personne(EntityType):
+ __unique_together__ = [('nom', 'prenom', 'inline2')]
+ nom = String(fulltextindexed=True, required=True, maxsize=64)
+ prenom = String(fulltextindexed=True, maxsize=64)
+ sexe = String(maxsize=1, default='M', fulltextindexed=True)
+ promo = String(vocabulary=('bon','pasbon'))
+ titre = String(fulltextindexed=True, maxsize=128)
+ adel = String(maxsize=128)
+ ass = String(maxsize=128)
+ web = String(maxsize=128)
+ tel = Int()
+ fax = Int()
+ datenaiss = Datetime()
+ tzdatenaiss = TZDatetime()
+ test = Boolean(__permissions__={
+ 'read': ('managers', 'users', 'guests'),
+ 'update': ('managers',),
+ })
+ description = String()
+ firstname = String(fulltextindexed=True, maxsize=64)
+
+ concerne = SubjectRelation('Affaire')
+ connait = SubjectRelation('Personne')
+ inline2 = SubjectRelation('Affaire', inlined=True, cardinality='?*')
+
+ custom_field_of_jungle = BabarTestType(jungle_speed=42)
+
+
+class Old(EntityType):
+ name = String()
+
+
+class connait(RelationType):
+ symmetric = True
+
+class concerne(RelationType):
+ __permissions__ = {
+ 'read': ('managers', 'users', 'guests'),
+ 'add': ('managers', RRQLExpression('U has_update_permission S')),
+ 'delete': ('managers', RRQLExpression('O owned_by U')),
+ }
+
+class travaille(RelationDefinition):
+ __permissions__ = {
+ 'read': ('managers', 'users', 'guests'),
+ 'add': ('managers', RRQLExpression('U has_update_permission S')),
+ 'delete': ('managers', RRQLExpression('O owned_by U')),
+ }
+ subject = 'Personne'
+ object = 'Societe'
+
+class comments(RelationDefinition):
+ subject = 'Comment'
+ object = 'Personne'
+
+class fiche(RelationDefinition):
+ inlined = True
+ subject = 'Personne'
+ object = 'Card'
+ cardinality = '??'
+
+class multisource_inlined_rel(RelationDefinition):
+ inlined = True
+ cardinality = '?*'
+ subject = ('Card', 'Note')
+ object = ('Affaire', 'Note')
+
+class multisource_rel(RelationDefinition):
+ subject = ('Card', 'Note')
+ object = 'Note'
+
+class multisource_crossed_rel(RelationDefinition):
+ subject = ('Card', 'Note')
+ object = 'Note'
+
+
+class see_also_1(RelationDefinition):
+ name = 'see_also'
+ subject = object = 'Folder'
+
+class see_also_2(RelationDefinition):
+ name = 'see_also'
+ subject = ('Bookmark', 'Note')
+ object = ('Bookmark', 'Note')
+
+class evaluee(RelationDefinition):
+ subject = ('Personne', 'CWUser', 'Societe')
+ object = ('Note')
+
+class ecrit_par(RelationType):
+ inlined = True
+
+class ecrit_par_1(RelationDefinition):
+ name = 'ecrit_par'
+ subject = 'Note'
+ object ='Personne'
+ constraints = [RQLConstraint('E concerns P, S version_of P')]
+ cardinality = '?*'
+
+class ecrit_par_2(RelationDefinition):
+ name = 'ecrit_par'
+ subject = 'Note'
+ object ='CWUser'
+ cardinality='?*'
+
+
+class copain(RelationDefinition):
+ subject = object = 'CWUser'
+
+class tags(RelationDefinition):
+ subject = 'Tag'
+ object = ('CWUser', 'CWGroup', 'State', 'Note', 'Card', 'Affaire')
+
+class filed_under(RelationDefinition):
+ subject = ('Note', 'Affaire')
+ object = 'Folder'
+
+class require_permission(RelationDefinition):
+ subject = ('Card', 'Note', 'Personne')
+ object = 'CWPermission'
+
+class require_state(RelationDefinition):
+ subject = 'CWPermission'
+ object = 'State'
+
+class personne_composite(RelationDefinition):
+ subject='Personne'
+ object='Personne'
+ composite='subject'
+
+class personne_inlined(RelationDefinition):
+ subject='Personne'
+ object='Personne'
+ cardinality='?*'
+ inlined=True
+
+
+class login_user(RelationDefinition):
+ subject = 'Personne'
+ object = 'CWUser'
+ cardinality = '??'
+
+class ambiguous_inlined(RelationDefinition):
+ subject = ('Affaire', 'Note')
+ object = 'CWUser'
+ inlined = True
+ cardinality = '?*'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/server/test/data-schemaserial/site_cubicweb.py Fri Apr 26 17:46:56 2013 +0200
@@ -0,0 +1,30 @@
+# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# CubicWeb is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
+
+from logilab.database import FunctionDescr
+from logilab.database.sqlite import register_sqlite_pyfunc
+from rql.utils import register_function
+
+class DUMB_SORT(FunctionDescr):
+ pass
+
+register_function(DUMB_SORT)
+def dumb_sort(something):
+ return something
+register_sqlite_pyfunc(dumb_sort)
+
--- a/server/test/unittest_repository.py Tue Apr 23 14:13:58 2013 +0200
+++ b/server/test/unittest_repository.py Fri Apr 26 17:46:56 2013 +0200
@@ -1,5 +1,5 @@
# -*- coding: iso-8859-1 -*-
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -29,6 +29,9 @@
from logilab.common.testlib import TestCase, unittest_main
from yams.constraints import UniqueConstraint
+from yams import register_base_type, unregister_base_type
+
+from logilab.database import get_db_helper
from cubicweb import (BadConnectionId, RepositoryError, ValidationError,
UnknownEid, AuthenticationError, Unauthorized, QueryError)
@@ -57,44 +60,6 @@
'type': u'violates unique_together constraints (cp, nom, type)'},
wraperr.exception.args[1])
- def test_fill_schema(self):
- origshema = self.repo.schema
- try:
- self.repo.schema = CubicWebSchema(self.repo.config.appid)
- self.repo.config._cubes = None # avoid assertion error
- self.repo.config.repairing = True # avoid versions checking
- self.repo.fill_schema()
- table = SQL_PREFIX + 'CWEType'
- namecol = SQL_PREFIX + 'name'
- finalcol = SQL_PREFIX + 'final'
- self.session.set_cnxset()
- cu = self.session.system_sql('SELECT %s FROM %s WHERE %s is NULL' % (
- namecol, table, finalcol))
- self.assertEqual(cu.fetchall(), [])
- cu = self.session.system_sql('SELECT %s FROM %s WHERE %s=%%(final)s ORDER BY %s'
- % (namecol, table, finalcol, namecol), {'final': True})
- self.assertEqual(cu.fetchall(), [(u'BigInt',), (u'Boolean',), (u'Bytes',),
- (u'Date',), (u'Datetime',),
- (u'Decimal',),(u'Float',),
- (u'Int',),
- (u'Interval',), (u'Password',),
- (u'String',),
- (u'TZDatetime',), (u'TZTime',), (u'Time',)])
- sql = ("SELECT etype.cw_eid, etype.cw_name, cstr.cw_eid, rel.eid_to "
- "FROM cw_CWUniqueTogetherConstraint as cstr, "
- " relations_relation as rel, "
- " cw_CWEType as etype "
- "WHERE cstr.cw_eid = rel.eid_from "
- " AND cstr.cw_constraint_of = etype.cw_eid "
- " AND etype.cw_name = 'Personne' "
- ";")
- cu = self.session.system_sql(sql)
- rows = cu.fetchall()
- self.assertEqual(len(rows), 3)
- self.test_unique_together()
- finally:
- self.repo.set_schema(origshema)
-
def test_unique_together(self):
person = self.repo.schema.eschema('Personne')
self.assertEqual(len(person._unique_together), 1)
@@ -317,7 +282,8 @@
'constrained_by',
'cardinality', 'ordernum',
'indexed', 'fulltextindexed', 'internationalizable',
- 'defaultval', 'description', 'description_format'])
+ 'defaultval', 'extra_props',
+ 'description', 'description_format'])
self.assertEqual(schema.eschema('CWEType').main_attribute(), 'name')
self.assertEqual(schema.eschema('State').main_attribute(), 'name')
@@ -584,6 +550,85 @@
req.create_entity('Affaire', ref=u'AFF02')
req.execute('SET A duration 10 WHERE A is Affaire')
+class SchemaDeserialTC(CubicWebTC):
+
+ appid = 'data-schemaserial'
+
+ @classmethod
+ def setUpClass(cls):
+ register_base_type('BabarTestType', ('jungle_speed',))
+ helper = get_db_helper('sqlite')
+ helper.TYPE_MAPPING['BabarTestType'] = 'TEXT'
+ helper.TYPE_CONVERTERS['BabarTestType'] = lambda x: '"%s"' % x
+ super(SchemaDeserialTC, cls).setUpClass()
+
+
+ @classmethod
+ def tearDownClass(cls):
+ unregister_base_type('BabarTestType')
+ helper = get_db_helper('sqlite')
+ helper.TYPE_MAPPING.pop('BabarTestType', None)
+ helper.TYPE_CONVERTERS.pop('BabarTestType', None)
+ super(SchemaDeserialTC, cls).tearDownClass()
+
+ def test_fill_schema(self):
+ origshema = self.repo.schema
+ try:
+ self.repo.schema = CubicWebSchema(self.repo.config.appid)
+ self.repo.config._cubes = None # avoid assertion error
+ self.repo.config.repairing = True # avoid versions checking
+ self.repo.fill_schema()
+ table = SQL_PREFIX + 'CWEType'
+ namecol = SQL_PREFIX + 'name'
+ finalcol = SQL_PREFIX + 'final'
+ self.session.set_cnxset()
+ cu = self.session.system_sql('SELECT %s FROM %s WHERE %s is NULL' % (
+ namecol, table, finalcol))
+ self.assertEqual(cu.fetchall(), [])
+ cu = self.session.system_sql('SELECT %s FROM %s WHERE %s=%%(final)s ORDER BY %s'
+ % (namecol, table, finalcol, namecol), {'final': True})
+ self.assertEqual(cu.fetchall(), [(u'BabarTestType',),
+ (u'BigInt',), (u'Boolean',), (u'Bytes',),
+ (u'Date',), (u'Datetime',),
+ (u'Decimal',),(u'Float',),
+ (u'Int',),
+ (u'Interval',), (u'Password',),
+ (u'String',),
+ (u'TZDatetime',), (u'TZTime',), (u'Time',)])
+ sql = ("SELECT etype.cw_eid, etype.cw_name, cstr.cw_eid, rel.eid_to "
+ "FROM cw_CWUniqueTogetherConstraint as cstr, "
+ " relations_relation as rel, "
+ " cw_CWEType as etype "
+ "WHERE cstr.cw_eid = rel.eid_from "
+ " AND cstr.cw_constraint_of = etype.cw_eid "
+ " AND etype.cw_name = 'Personne' "
+ ";")
+ cu = self.session.system_sql(sql)
+ rows = cu.fetchall()
+ self.assertEqual(len(rows), 3)
+ person = self.repo.schema.eschema('Personne')
+ self.assertEqual(len(person._unique_together), 1)
+ self.assertItemsEqual(person._unique_together[0],
+ ('nom', 'prenom', 'inline2'))
+
+ finally:
+ self.repo.set_schema(origshema)
+
+ def test_custom_attribute_param(self):
+ origshema = self.repo.schema
+ try:
+ self.repo.schema = CubicWebSchema(self.repo.config.appid)
+ self.repo.config._cubes = None # avoid assertion error
+ self.repo.config.repairing = True # avoid versions checking
+ self.repo.fill_schema()
+ pes = self.repo.schema['Personne']
+ attr = pes.rdef('custom_field_of_jungle')
+ self.assertIn('jungle_speed', vars(attr))
+ self.assertEqual(42, attr.jungle_speed)
+ finally:
+ self.repo.set_schema(origshema)
+
+
class DataHelpersTC(CubicWebTC):
--- a/server/test/unittest_schemaserial.py Tue Apr 23 14:13:58 2013 +0200
+++ b/server/test/unittest_schemaserial.py Fri Apr 26 17:46:56 2013 +0200
@@ -25,17 +25,32 @@
from cubicweb.schema import CubicWebSchemaLoader
from cubicweb.devtools import TestServerConfiguration
+from logilab.database import get_db_helper
+from yams import register_base_type, unregister_base_type
+
def setUpModule(*args):
+ register_base_type('BabarTestType', ('jungle_speed',))
+ helper = get_db_helper('sqlite')
+ helper.TYPE_MAPPING['BabarTestType'] = 'TEXT'
+ helper.TYPE_CONVERTERS['BabarTestType'] = lambda x: '"%s"' % x
+
global schema, config
loader = CubicWebSchemaLoader()
- config = TestServerConfiguration('data', apphome=Schema2RQLTC.datadir)
+ apphome = Schema2RQLTC.datadir + '-schemaserial'
+ config = TestServerConfiguration('data', apphome=apphome)
config.bootstrap_cubes()
schema = loader.load(config)
+
def tearDownModule(*args):
global schema, config
del schema, config
+ unregister_base_type('BabarTestType')
+ helper = get_db_helper('sqlite')
+ helper.TYPE_MAPPING.pop('BabarTestType', None)
+ helper.TYPE_CONVERTERS.pop('BabarTestType', None)
+
from cubicweb.server.schemaserial import *
from cubicweb.server.schemaserial import _erperms2rql as erperms2rql
@@ -72,6 +87,13 @@
('SET X specializes ET WHERE X eid %(x)s, ET eid %(et)s',
{'et': None, 'x': None})])
+ def test_esche2rql_custom_type(self):
+ expected = [('INSERT CWEType X: X description %(description)s,X final %(final)s,X name %(name)s',
+ {'description': u'',
+ 'name': u'BabarTestType', 'final': True},)]
+ got = list(eschema2rql(schema.eschema('BabarTestType')))
+ self.assertListEqual(expected, got)
+
def test_rschema2rql1(self):
self.assertListEqual(list(rschema2rql(schema.rschema('relation_type'), cstrtypemap)),
[
@@ -136,6 +158,42 @@
{'x': None, 'ct': u'StaticVocabularyConstraint_eid', 'value': u"u'?*', u'1*', u'+*', u'**', u'?+', u'1+', u'++', u'*+', u'?1', u'11', u'+1', u'*1', u'??', u'1?', u'+?', u'*?'"}),
])
+ def test_rschema2rql_custom_type(self):
+ expected = [('INSERT CWRType X: X description %(description)s,X final %(final)s,'
+ 'X fulltext_container %(fulltext_container)s,X inlined %(inlined)s,'
+ 'X name %(name)s,X symmetric %(symmetric)s',
+ {'description': u'',
+ 'final': True,
+ 'fulltext_container': None,
+ 'inlined': False,
+ 'name': u'custom_field_of_jungle',
+ 'symmetric': False}),
+ ('INSERT CWAttribute X: X cardinality %(cardinality)s,'
+ 'X defaultval %(defaultval)s,X description %(description)s,'
+ 'X extra_props %(extra_props)s,X indexed %(indexed)s,'
+ 'X ordernum %(ordernum)s,X relation_type ER,X from_entity SE,'
+ 'X to_entity OE WHERE SE eid %(se)s,ER eid %(rt)s,OE eid %(oe)s',
+ {'cardinality': u'?1',
+ 'defaultval': None,
+ 'description': u'',
+ 'extra_props': '{"jungle_speed": 42}',
+ 'indexed': False,
+ 'oe': None,
+ 'ordernum': 19,
+ 'rt': None,
+ 'se': None})]
+
+ got = list(rschema2rql(schema.rschema('custom_field_of_jungle'), cstrtypemap))
+ self.assertEqual(2, len(got))
+ # this is a custom type attribute with an extra parameter
+ self.assertIn('extra_props', got[1][1])
+ # this extr
+ extra_props = got[1][1]['extra_props']
+ from cubicweb import Binary
+ self.assertIsInstance(extra_props, Binary)
+ got[1][1]['extra_props'] = got[1][1]['extra_props'].getvalue()
+ self.assertListEqual(expected, got)
+
def test_rdef2rql(self):
self.assertListEqual(list(rdef2rql(schema['description_format'].rdefs[('CWRType', 'String')], cstrtypemap)),
[
--- a/test/unittest_schema.py Tue Apr 23 14:13:58 2013 +0200
+++ b/test/unittest_schema.py Fri Apr 26 17:46:56 2013 +0200
@@ -1,4 +1,4 @@
-# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of CubicWeb.
@@ -186,7 +186,7 @@
'data', 'data_encoding', 'data_format', 'data_name', 'default_workflow', 'defaultval', 'delete_permission',
'description', 'description_format', 'destination_state', 'dirige',
- 'ecrit_par', 'eid', 'end_timestamp', 'evaluee', 'expression', 'exprtype',
+ 'ecrit_par', 'eid', 'end_timestamp', 'evaluee', 'expression', 'exprtype', 'extra_props',
'fabrique_par', 'final', 'firstname', 'for_user', 'fournit',
'from_entity', 'from_state', 'fulltext_container', 'fulltextindexed',