Completed
Pull Request — master (#127)
by Jasper
01:07
created

Diff.getDifferenceString()   B

Complexity

Conditions 6

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 6
dl 0
loc 31
rs 7.5384

1 Method

Rating   Name   Duplication   Size   Complexity  
A Diff.row() 0 4 3
1
from os.path import basename
2
3
class Diff(object):
4
    """Difference between two files.
5
6
    This represents differences in provenance between two files.
7
8
    See :py:mod:`niprov.comparing`
9
10
    Args:
11
        file1 (:class:`.BaseFile`): One of two niprov BaseFile objects to 
12
            compare.
13
        file2 (:class:`.BaseFile`): As file1
14
    """
15
16
    NCHARSCOL = 20              # width of columns
17
    defaultIgnore = ['_id']     # these fields are always ignored
18
19
    def __init__(self, file1, file2):
20
        self.file1 = file1
21
        self.file2 = file2
22
23
    def getDifferences(self, ignore=None, select=None):
24
        """Get dictionary with fields that differ and how they differ.
25
26
        Args:
27
            ignore (list): Optional. List of fields not to evaluate when 
28
                determining differences.
29
            select (list): Optional. List of fields that should be specifically
30
                evaluated. All other fields will be ignored.
31
32
        Returns:
33
            dict: A dictionary with provenance fields as keys and strings
34
                indicating how they differ.
35
        """
36
        assert isinstance(ignore, list) or ignore is None
37
        if ignore is None:
38
            ignore = []
39
        ignore += self.defaultIgnore
40
        prov1 = self.file1.getProvenance()
41
        prov2 = self.file2.getProvenance()
42
        if select:
43
            allkeys = set(prov1.keys()+prov2.keys())
44
            ignore = [k for k in allkeys if k not in select]
45
        diffDict = {}
46
        for k in set(prov1.keys()).difference(prov2.keys()):
47
            if k not in ignore:
48
                diffDict[k] = 'missingIn2'
49
        for k in set(prov2.keys()).difference(prov1.keys()):
50
            if k not in ignore:
51
                diffDict[k] = 'missingIn1'
52
        for k in set(prov1.keys()).intersection(prov2.keys()):
53
            if k not in ignore:
54
                if prov1[k] != prov2[k]:
55
                    diffDict[k] = 'value'
56
        return diffDict
57
58
    def getDifferenceString(self, ignore=None, select=None):
59
        """Get table of differences as string.
60
61
        Args:
62
            ignore (list): Optional. List of fields not to evaluate when 
63
                determining differences.
64
            select (list): Optional. List of fields that should be specifically
65
                evaluated. All other fields will be ignored.
66
67
        Returns:
68
            str: A three-columns table listing provenance fields and their
69
                respective values for the two files.
70
        """
71
        differences = self.getDifferences(ignore, select)
72
        if not differences:
73
            return ''
74
        name1 = basename(str(self.file1.location))
75
        name2 = basename(str(self.file2.location))
76
        prov1 = self.file1.getProvenance()
77
        prov2 = self.file2.getProvenance()
78
        def row(*vals):
79
            cells = [c[:self.NCHARSCOL] for c in vals]
80
            cells = [c.ljust(self.NCHARSCOL) for c in cells]
81
            return ' '.join(cells)+'\n'
82
        diffStr = 'Differences:\n'
83
        diffStr += row('', name1, name2)
84
        for field, status in differences.items():
85
            val1 = prov1.get(field, 'n/a')
86
            val2 = prov2.get(field, 'n/a')
87
            diffStr += row(field, str(val1), str(val2))
88
        return diffStr
89
90
    def areEqual(self, ignore=None, select=None):
91
        """Whether there are any differences between the files.
92
93
        Args:
94
            ignore (list): Optional. List of fields not to evaluate when 
95
                determining differences.
96
            select (list): Optional. List of fields that should be specifically
97
                evaluated. All other fields will be ignored.
98
99
        Returns:
100
            bool: True if no differences, False otherwise.
101
        """
102
        differences = self.getDifferences(ignore, select)
103
        return len(differences) == 0
104
105
    def areEqualProtocol(self):
106
        """Whether there are any differences for protocol fields.
107
108
        Each :class:`.BaseFile` subtype has a getProtocolFields() method
109
        that is used here to selectively see if any of these are different.
110
111
        Returns:
112
            bool: True if no differences, False otherwise.
113
        """
114
        protocol = self.file1.getProtocolFields()
115
        differences = self.getDifferences(select=protocol)
116
        return len(differences) == 0
117
118
    def assertEqual(self, ignore=None, select=None):
119
        """Raises exception if there are differences.
120
121
        Args:
122
            ignore (list): Optional. List of fields not to evaluate when 
123
                determining differences.
124
            select (list): Optional. List of fields that should be specifically
125
                evaluated. All other fields will be ignored.
126
127
        Raises:
128
            AssertionError: Message with differences in a table.
129
        """
130
        differences = self.getDifferenceString(ignore, select)
131
        if differences:
132
            raise AssertionError(differences)
133
134
    def assertEqualProtocol(self):
135
        """Raises exception if there are differences in protocol fields.
136
137
        Each :class:`.BaseFile` subtype has a getProtocolFields() method
138
        that is used here to selectively see if any of these are different.
139
140
        Raises:
141
            AssertionError: Message with protocol differences in a table.
142
        """
143
        protocol = self.file1.getProtocolFields()
144
        differences = self.getDifferenceString(select=protocol)
145
        if differences:
146
            raise AssertionError(differences)
147
148
    def __str__(self):
149
        return self.getDifferenceString()
150