[schema building] Fix key in context.defined for RelationDefinition

Ensures that subjects and objects stored in key are strings not tuples.
This allows to check RelationDefinition existence using for instance:

nosy_list_subjects = ('Forum', 'ForumThread')
if ('Comment', 'nosy_list', 'CWUser') not in context.defined:
nosy_list_subjects += ('Comment', )


This may trigger some hidden bugs of duplicated RelationDefinition.

Closes #149660.

authorDenis Laxalde <denis.laxalde@logilab.fr>
changeset3d27ad290904
branchdefault
phasedraft
hiddenyes
parent revision#25d0bff4eb9d [pkg] update changelog
child revision<not specified>
files modified by this revision
buildobjs.py
reader.py
# HG changeset patch
# User Denis Laxalde <denis.laxalde@logilab.fr>
# Date 1372325385 -7200
# Thu Jun 27 11:29:45 2013 +0200
# Node ID 3d27ad290904bcf9e027836aad66da55c2783715
# Parent 25d0bff4eb9d851da4b814677b58f81e2bfc5391
[schema building] Fix key in context.defined for RelationDefinition

Ensures that subjects and objects stored in key are strings not tuples.
This allows to check RelationDefinition existence using for instance:

nosy_list_subjects = ('Forum', 'ForumThread')
if ('Comment', 'nosy_list', 'CWUser') not in context.defined:
nosy_list_subjects += ('Comment', )


This may trigger some hidden bugs of duplicated RelationDefinition.

Closes #149660.

diff --git a/buildobjs.py b/buildobjs.py
@@ -535,15 +535,31 @@
1          _copy_attributes(cls, rtype, RTYPE_PROPERTIES)
2          if name in defined:
3              _copy_attributes(rtype, defined[name], RTYPE_PROPERTIES)
4          else:
5              defined[name] = rtype
6 -        key = (cls.subject, name, cls.object)
7 -        if key in defined:
8 -            raise BadSchemaDefinition('duplicated relation definition %s (%s.%s)'
9 -                                      % (key, cls.__module__, cls.__name__))
10 -        defined[key] = cls
11 +
12 +        # subject and object in defined's keys are only strings not tuples
13 +        if isinstance(cls.subject, tuple):
14 +            subjects = cls.subject
15 +        else:
16 +            subjects = (cls.subject, )
17 +        if isinstance(cls.object, tuple):
18 +            objects = cls.object
19 +        else:
20 +            objects = (cls.object, )
21 +        for sub in subjects:
22 +            for obj in objects:
23 +                key = (sub, name, obj)
24 +                if key in defined:
25 +                    raise BadSchemaDefinition(
26 +                        'duplicated relation definition (%s) %s (%s.%s)'
27 +                        % (defined[key], key, cls.__module__, cls.__name__))
28 +                defined[key] = cls
29 +
30 +        # XXX keep this for bw compat
31 +        defined[(cls.subject, name, cls.object)] = cls
32 
33      @classmethod
34      def expand_relation_definitions(cls, defined, schema):
35          """schema building step 2:
36 
diff --git a/reader.py b/reader.py
@@ -71,20 +71,22 @@
37 
38  def fill_schema(schema, erdefs, register_base_types=True,
39                  remove_unused_rtypes=False, post_build_callbacks=[]):
40      if register_base_types:
41          buildobjs.register_base_types(schema)
42 +    # relation definitions may appear multiple times
43 +    erdefs_vals = set(erdefs.itervalues())
44      # register relation types and non final entity types
45 -    for definition in erdefs.itervalues():
46 +    for definition in erdefs_vals:
47          if isinstance(definition, type):
48              definition = definition()
49          if isinstance(definition, buildobjs.RelationType):
50              schema.add_relation_type(definition)
51          elif isinstance(definition, buildobjs.EntityType):
52              schema.add_entity_type(definition)
53      # register relation definitions
54 -    for definition in erdefs.itervalues():
55 +    for definition in erdefs_vals:
56          if isinstance(definition, type):
57              definition = definition()
58          definition.expand_relation_definitions(erdefs, schema)
59      # call 'post_build_callback' functions found in schema modules
60      for cb in post_build_callbacks: