[schema] Add a fingerprint() method

Closes #292411

authorChristophe de Vienne <christophe@unlish.com>
changeset61f2cf11106d
branchdefault
phasedraft
hiddenyes
parent revision#037fed370cc1 [layout] Use a standard python package layout
child revision<not specified>
files modified by this revision
yams/schema.py
yams/test/unittest_schema.py
# HG changeset patch
# User Christophe de Vienne <christophe@unlish.com>
# Date 1434105235 -7200
# Fri Jun 12 12:33:55 2015 +0200
# Node ID 61f2cf11106dbe2751b9ba41ce4eb12123e82496
# Parent 037fed370cc12972ccb1a6ef78fc06e110396011
[schema] Add a fingerprint() method

Closes #292411

diff --git a/yams/schema.py b/yams/schema.py
@@ -17,10 +17,11 @@
1  # with yams. If not, see <http://www.gnu.org/licenses/>.
2  """Classes to define generic Entities/Relations schemas."""
3 
4  __docformat__ = "restructuredtext en"
5 
6 +import hashlib
7  import warnings
8  from copy import deepcopy
9  from decimal import Decimal
10  from itertools import chain
11 
@@ -1238,10 +1239,40 @@
12          Can be used to, e.g., infer relations from inheritance, computed
13          relations, etc.
14          """
15          self.infer_specialization_rules()
16 
17 +    def fingerprint(self):
18 +        h = hashlib.new('SHA1')
19 +
20 +        def stringify(o):
21 +            if isinstance(o, dict):
22 +                return ';'.join(
23 +                    ('%s=%s' % (key, stringify(o[key]))
24 +                     for key in sorted(o))
25 +                )
26 +            elif isinstance(o, (list, tuple)):
27 +                return ';'.join(stringify(item) for item in o)
28 +            else:
29 +                return str(o)
30 +
31 +        for entity in sorted(self._entities.values(), key=lambda x: x.type):
32 +            h.update(entity.type.encode('utf-8'))
33 +            h.update(entity.description.encode('utf-8'))
34 +            h.update(stringify(entity.__dict__).encode('utf-8'))
35 +
36 +        for relation in sorted(self._relations.values(), key=lambda x: x.type):
37 +            h.update(relation.type.encode('utf-8'))
38 +            h.update(relation.description.encode('utf-8'))
39 +            h.update(stringify(relation.__dict__).encode('utf-8'))
40 +            for rdef in sorted(relation.rdefs.values(),
41 +                               key=lambda rdef: (
42 +                                   rdef.subject, rdef.rtype, rdef.object)):
43 +                h.update(stringify(rdef.__dict__).encode('utf-8'))
44 +
45 +        return h.hexdigest()
46 +
47 
48  import logging
49  from logilab.common.logging_ext import set_log_methods
50  LOGGER = logging.getLogger('yams')
51  set_log_methods(Schema, LOGGER)
diff --git a/yams/test/unittest_schema.py b/yams/test/unittest_schema.py
@@ -532,10 +532,23 @@
52          class TE(Plan):
53              pass
54          self.assertListEqual(['custom_workflow'],
55                               [rel.name for rel in TE.__relations__])
56 
57 +    def test_fingerprint(self):
58 +        fp = schema.fingerprint()
59 +
60 +        schema.rename_entity_type('Affaire', 'Workcase')
61 +
62 +        self.assertNotEqual(schema.fingerprint(), fp)
63 +        fp = schema.fingerprint()
64 +
65 +        schema.add_relation_def(
66 +            RelationDefinition('Note', 'concerne', 'Societe'))
67 +        self.assertNotEqual(schema.fingerprint(), fp)
68 +        fp = schema.fingerprint()
69 +
70 
71  class SymetricTC(TestCase):
72      def setUp(self):
73          global schema
74          schema = Schema('Test Schema')