# HG changeset patch # User Sylvain Thénault # Date 1250783708 -7200 # Node ID 4484387ed0122ca2363ceb2ac78d15c3f382c812 # Parent 53bf6a2bfdfcbe08db815d6e29348b4f7dda3b2f when adding/removing cubes, we should add/remove entity types in correct order if one inherits from another diff -r 53bf6a2bfdfc -r 4484387ed012 schema.py --- a/schema.py Wed Aug 19 19:08:59 2009 +0200 +++ b/schema.py Thu Aug 20 17:55:08 2009 +0200 @@ -16,6 +16,7 @@ from logilab.common.decorators import cached, clear_cache, monkeypatch from logilab.common.logging_ext import set_log_methods from logilab.common.deprecation import deprecated +from logilab.common.graph import get_cycles from logilab.common.compat import any from yams import BadSchemaDefinition, buildobjs as ybo @@ -59,6 +60,38 @@ ybo.RTYPE_PROPERTIES += ('eid',) ybo.RDEF_PROPERTIES += ('eid',) + +# XXX same algorithm as in reorder_cubes and probably other place, +# may probably extract a generic function +def order_eschemas(eschemas): + """return entity schemas ordered such that entity types which specializes an + other one appears after that one + """ + graph = {} + for eschema in eschemas: + if eschema.specializes(): + graph[eschema] = set((eschema.specializes(),)) + else: + graph[eschema] = set() + cycles = get_cycles(graph) + if cycles: + cycles = '\n'.join(' -> '.join(cycle) for cycle in cycles) + raise Exception('cycles in entity schema specialization: %s' + % cycles) + eschemas = [] + while graph: + # sorted to get predictable results + for eschema, deps in sorted(graph.items()): + if not deps: + eschemas.append(eschema) + del graph[eschema] + for deps in graph.itervalues(): + try: + deps.remove(eschema) + except KeyError: + continue + return eschemas + def bw_normalize_etype(etype): if etype in ETYPE_NAME_MAP: msg = '%s has been renamed to %s, please update your code' % ( @@ -804,6 +837,7 @@ PyFileReader.context['RRQLExpression'] = yobsolete(RRQLExpression) # workflow extensions ######################################################### + from yams.buildobjs import _add_relation as yams_add_relation class workflowable_definition(ybo.metadefinition): diff -r 53bf6a2bfdfc -r 4484387ed012 server/migractions.py --- a/server/migractions.py Wed Aug 19 19:08:59 2009 +0200 +++ b/server/migractions.py Thu Aug 20 17:55:08 2009 +0200 @@ -33,7 +33,8 @@ from yams.schema2sql import eschema2sql, rschema2sql from cubicweb import AuthenticationError, ETYPE_NAME_MAP -from cubicweb.schema import META_RTYPES, VIRTUAL_RTYPES, CubicWebRelationSchema +from cubicweb.schema import (META_RTYPES, VIRTUAL_RTYPES, + CubicWebRelationSchema, order_eschemas) from cubicweb.dbapi import get_repository, repo_connect from cubicweb.common.migration import MigrationHelper, yes @@ -518,10 +519,11 @@ if not rschema in self.repo.schema: self.cmd_add_relation_type(rschema.type) new.add(rschema.type) - for eschema in newcubes_schema.entities(): - if not eschema in self.repo.schema: - self.cmd_add_entity_type(eschema.type) - new.add(eschema.type) + toadd = [eschema for eschema in newcubes_schema.entities() + if not eschema in self.repo.schema] + for eschema in order_eschemas(toadd): + self.cmd_add_entity_type(eschema.type) + new.add(eschema.type) # check if attributes has been added to existing entities for rschema in newcubes_schema.relations(): existingschema = self.repo.schema.rschema(rschema.type) @@ -553,9 +555,11 @@ for rschema in fsschema.relations(): if not rschema in removedcubes_schema and rschema in reposchema: self.cmd_drop_relation_type(rschema.type) - for eschema in fsschema.entities(): - if not eschema in removedcubes_schema and eschema in reposchema: - self.cmd_drop_entity_type(eschema.type) + toremove = [eschema for eschema in fsschema.entities() + if not eschema in removedcubes_schema + and eschema in reposchema] + for eschema in reversed(order_eschemas(toremove)): + self.cmd_drop_entity_type(eschema.type) for rschema in fsschema.relations(): if rschema in removedcubes_schema and rschema in reposchema: # check if attributes/relations has been added to entities from diff -r 53bf6a2bfdfc -r 4484387ed012 test/unittest_schema.py --- a/test/unittest_schema.py Wed Aug 19 19:08:59 2009 +0200 +++ b/test/unittest_schema.py Thu Aug 20 17:55:08 2009 +0200 @@ -20,7 +20,7 @@ from cubicweb.schema import CubicWebSchema, CubicWebEntitySchema, \ RQLConstraint, CubicWebSchemaLoader, ERQLExpression, RRQLExpression, \ - normalize_expression + normalize_expression, order_eschemas from cubicweb.devtools import TestServerConfiguration as TestConfiguration DATADIR = join(dirname(__file__), 'data') @@ -126,12 +126,18 @@ expr = RRQLExpression('U has_update_permission O') self.assertEquals(str(expr), 'Any O WHERE U has_update_permission O, O eid %(o)s, U eid %(u)s') - loader = CubicWebSchemaLoader() config = TestConfiguration('data') config.bootstrap_cubes() -class SQLSchemaReaderClassTest(TestCase): +class SchemaReaderClassTest(TestCase): + + def test_order_eschemas(self): + schema = loader.load(config) + self.assertEquals(order_eschemas([schema['Note'], schema['SubNote']]), + [schema['Note'], schema['SubNote']]) + self.assertEquals(order_eschemas([schema['SubNote'], schema['Note']]), + [schema['Note'], schema['SubNote']]) def test_knownValues_load_schema(self): schema = loader.load(config)