File: Differ.py

package info (click to toggle)
python-pyvmomi 9.0.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 21,372 kB
  • sloc: python: 18,622; xml: 77; makefile: 3
file content (225 lines) | stat: -rw-r--r-- 9,179 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# Copyright (c) 2008-2025 Broadcom. All Rights Reserved.
# The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.

# Diff any two objects

import logging

from .five import PY3
if not PY3:
    from .five import zip

from .VmomiSupport import F_LINK, F_OPTIONAL, GetWsdlName, Type, types

__Log__ = logging.getLogger('ObjDiffer')


def LogIf(condition, message):
    """Log a message if the condition is met"""
    if condition:
        __Log__.debug(message)

_primitive_types = (types.bool, types.byte, types.short, types.double, types.float,
                    types.PropertyPath, types.ManagedMethod,
                    types.datetime, types.URI, types.binary, type)

_primitive_types += (int, str) if PY3 else (int, long, basestring)

def IsPrimitiveType(obj):
    """See if the passed in type is a Primitive Type"""
    return isinstance(obj, _primitive_types)

class Differ:
    """Class for comparing two Objects"""
    def __init__(self, looseMatch=False, ignoreArrayOrder=True):
        self._looseMatch = looseMatch
        self._ignoreArrayOrder = ignoreArrayOrder

    def DiffAnyObjects(self, oldObj, newObj, isObjLink=False):
        """Diff any two Objects"""
        if oldObj == newObj:
            return True
        if not oldObj or not newObj:
            __Log__.debug('DiffAnyObjects: One of the objects is unset.')
            return self._looseMatch
        oldObjInstance = oldObj
        newObjInstance = newObj
        if isinstance(oldObj, list):
            oldObjInstance = oldObj[0]
        if isinstance(newObj, list):
            newObjInstance = newObj[0]
        # Need to see if it is a primitive type first since type information
        #   will not be available for them.
        if (IsPrimitiveType(oldObj) and IsPrimitiveType(newObj)
                and oldObj.__class__.__name__ == newObj.__class__.__name__):
            if oldObj == newObj:
                return True
            elif oldObj is None or newObj is None:
                __Log__.debug('DiffAnyObjects: One of the objects in None')
            return False
        oldType = Type(oldObjInstance)
        newType = Type(newObjInstance)
        if oldType != newType:
            __Log__.debug('DiffAnyObjects: Types do not match %s != %s',
                          repr(GetWsdlName(oldObjInstance.__class__)),
                          repr(GetWsdlName(newObjInstance.__class__)))
            return False
        elif isinstance(oldObj, list):
            return self.DiffArrayObjects(oldObj, newObj, isObjLink)
        elif isinstance(oldObjInstance, types.ManagedObject):
            return (not oldObj
                    and not newObj) or (oldObj and newObj
                                        and oldObj._moId == newObj._moId)
        elif isinstance(oldObjInstance, types.DataObject):
            if isObjLink:
                bMatch = oldObj.GetKey() == newObj.GetKey()
                LogIf(
                    not bMatch, 'DiffAnyObjects: Keys do not match %s != %s' %
                    (oldObj.GetKey(), newObj.GetKey()))
                return bMatch
            return self.DiffDataObjects(oldObj, newObj)

        else:
            raise TypeError("Unknown type: " +
                            repr(GetWsdlName(oldObj.__class__)))

    def DiffDoArrays(self, oldObj, newObj, isElementLinks):
        """Diff two DataObject arrays"""
        if len(oldObj) != len(newObj):
            __Log__.debug('DiffDoArrays: Array lengths do not match %d != %d',
                          len(oldObj), len(newObj))
            return False
        for i, j in zip(oldObj, newObj):
            if isElementLinks:
                if i.GetKey() != j.GetKey():
                    __Log__.debug('DiffDoArrays: Keys do not match %s != %s',
                                  i.GetKey(), j.GetKey())
                    return False
            else:
                if not self.DiffDataObjects(i, j):
                    __Log__.debug(
                        'DiffDoArrays: one of the elements do not match')
                    return False
        return True

    def DiffAnyArrays(self, oldObj, newObj, isElementLinks):
        """Diff two arrays which contain Any objects"""
        if len(oldObj) != len(newObj):
            __Log__.debug(
                'DiffAnyArrays: Array lengths do not match. %d != %d',
                len(oldObj), len(newObj))
            return False
        for i, j in zip(oldObj, newObj):
            if not self.DiffAnyObjects(i, j, isElementLinks):
                __Log__.debug(
                    'DiffAnyArrays: One of the elements do not match.')
                return False
        return True

    def DiffPrimitiveArrays(self, oldObj, newObj):
        """Diff two primitive arrays"""
        if len(oldObj) != len(newObj):
            __Log__.debug('DiffDoArrays: Array lengths do not match %d != %d',
                          len(oldObj), len(newObj))
            return False
        match = True
        if self._ignoreArrayOrder:
            oldSet = oldObj and frozenset(oldObj) or frozenset()
            newSet = newObj and frozenset(newObj) or frozenset()
            match = (oldSet == newSet)
        else:
            for i, j in zip(oldObj, newObj):
                if i != j:
                    match = False
                    break
        if not match:
            __Log__.debug(
                'DiffPrimitiveArrays: One of the elements do not match.')
            return False
        return True

    def DiffArrayObjects(self, oldObj, newObj, isElementLinks=False):
        """Method which deligates the diffing of arrays based on the type"""
        if oldObj == newObj:
            return True
        if not oldObj or not newObj:
            return False
        if len(oldObj) != len(newObj):
            __Log__.debug(
                'DiffArrayObjects: Array lengths do not match %d != %d',
                len(oldObj), len(newObj))
            return False
        firstObj = oldObj[0]
        if IsPrimitiveType(firstObj):
            return self.DiffPrimitiveArrays(oldObj, newObj)
        elif isinstance(firstObj, types.ManagedObject):
            return self.DiffAnyArrays(oldObj, newObj, isElementLinks)
        elif isinstance(firstObj, types.DataObject):
            return self.DiffDoArrays(oldObj, newObj, isElementLinks)
        else:
            raise TypeError("Unknown type: {0}".format(oldObj.__class__))

    def DiffDataObjects(self, oldObj, newObj):
        """Diff Data Objects"""
        if oldObj == newObj:
            return True
        if not oldObj or not newObj:
            __Log__.debug('DiffDataObjects: One of the objects in None')
            return False
        oldType = Type(oldObj)
        newType = Type(newObj)
        if oldType != newType:
            __Log__.debug(
                'DiffDataObjects: Types do not match for dataobjects. '
                '%s != %s', oldObj._wsdlName, newObj._wsdlName)
            return False
        for prop in oldObj._GetPropertyList():
            oldProp = getattr(oldObj, prop.name)
            newProp = getattr(newObj, prop.name)
            propType = oldObj._GetPropertyInfo(prop.name).type
            if not oldProp and not newProp:
                continue
            elif ((prop.flags & F_OPTIONAL) and self._looseMatch
                  and (not newProp or not oldProp)):
                continue
            elif not oldProp or not newProp:
                __Log__.debug(
                    'DiffDataObjects: One of the objects has '
                    'the property %s unset', prop.name)
                return False

            bMatch = True
            if IsPrimitiveType(oldProp):
                bMatch = oldProp == newProp
            elif isinstance(oldProp, types.ManagedObject):
                bMatch = self.DiffAnyObjects(oldProp, newProp, prop.flags
                                             & F_LINK)
            elif isinstance(oldProp, types.DataObject):
                if prop.flags & F_LINK:
                    bMatch = oldObj.GetKey() == newObj.GetKey()
                    LogIf(
                        not bMatch,
                        'DiffDataObjects: Key match failed %s != %s' %
                        (oldObj.GetKey(), newObj.GetKey()))
                else:
                    bMatch = self.DiffAnyObjects(oldProp, newProp, prop.flags
                                                 & F_LINK)
            elif isinstance(oldProp, list):
                bMatch = self.DiffArrayObjects(oldProp, newProp,
                                               prop.flags & F_LINK)
            else:
                raise TypeError("Unknown type: " + repr(propType))

            if not bMatch:
                __Log__.debug('DiffDataObjects: Objects differ in property %s',
                              prop.name)
                return False
        return True


def DiffAnys(obj1, obj2, looseMatch=False, ignoreArrayOrder=True):
    """Diff any two objects. Objects can either be primitive type
    or DataObjects
    """
    differ = Differ(looseMatch=looseMatch, ignoreArrayOrder=ignoreArrayOrder)
    return differ.DiffAnyObjects(obj1, obj2)