# HG changeset patch # User Vincent Michel # Date 1366991216 -7200 # Node ID ba9e3fbfa5a5248bdf0e945eb9fd5d182e643ea2 # Parent b167f039b6cbfbbae0cb2fd055478816e655d937 [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 diff -r b167f039b6cb -r ba9e3fbfa5a5 misc/migration/3.17.0_Any.py --- /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') diff -r b167f039b6cb -r ba9e3fbfa5a5 schema.py --- 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""" diff -r b167f039b6cb -r ba9e3fbfa5a5 schemas/bootstrap.py --- 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')) diff -r b167f039b6cb -r ba9e3fbfa5a5 server/schemaserial.py --- 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 diff -r b167f039b6cb -r ba9e3fbfa5a5 server/test/data-schemaserial/bootstrap_cubes --- /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 diff -r b167f039b6cb -r ba9e3fbfa5a5 server/test/data-schemaserial/schema.py --- /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 . + +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 = '?*' diff -r b167f039b6cb -r ba9e3fbfa5a5 server/test/data-schemaserial/site_cubicweb.py --- /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 . + +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) + diff -r b167f039b6cb -r ba9e3fbfa5a5 server/test/unittest_repository.py --- 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): diff -r b167f039b6cb -r ba9e3fbfa5a5 server/test/unittest_schemaserial.py --- 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)), [ diff -r b167f039b6cb -r ba9e3fbfa5a5 test/unittest_schema.py --- 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',