when adding/removing cubes, we should add/remove entity types in correct order if one inherits from another
--- 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):
--- 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
--- 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)