DataComparerLibrary 0.845__tar.gz → 0.847__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/PKG-INFO +3 -3
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/setup.py +0 -1
- datacomparerlibrary-0.847/src/DataComparerLibrary/datacomparer.py +162 -0
- datacomparerlibrary-0.847/src/DataComparerLibrary/field.py +174 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/fileconverter.py +36 -4
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/report.py +16 -10
- datacomparerlibrary-0.847/src/DataComparerLibrary/row.py +32 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/tools.py +2 -1
- datacomparerlibrary-0.847/src/DataComparerLibrary/twodarray.py +36 -0
- datacomparerlibrary-0.847/src/DataComparerLibrary/version.py +3 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary.egg-info/PKG-INFO +3 -3
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary.egg-info/SOURCES.txt +4 -3
- datacomparerlibrary-0.845/src/DataComparerLibrary/arraycomparer.py +0 -206
- datacomparerlibrary-0.845/src/DataComparerLibrary/datacomparer.py +0 -135
- datacomparerlibrary-0.845/src/DataComparerLibrary/version.py +0 -3
- datacomparerlibrary-0.845/test/test1.py +0 -21
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/LICENSE.txt +0 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/README.rst +0 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/pyproject.toml +0 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/setup.cfg +0 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/__init__.py +0 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/datasorter.py +0 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/datetimehandler.py +0 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/delimitertranslator.py +0 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary.egg-info/dependency_links.txt +0 -0
- {datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: DataComparerLibrary
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.847
|
|
4
4
|
Summary: For comparing csv-files, 2d-array with a csv-file or 2d-arrays. For comparing text-files, text variable with a text-file or text variables. Including a sorting module.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author: René Philip Zuijderduijn
|
|
@@ -10,7 +10,6 @@ Keywords: robotframework testing test-automation datacompare
|
|
|
10
10
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
11
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
12
12
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 11
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.8
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -26,6 +25,7 @@ Dynamic: description
|
|
|
26
25
|
Dynamic: description-content-type
|
|
27
26
|
Dynamic: keywords
|
|
28
27
|
Dynamic: license
|
|
28
|
+
Dynamic: license-file
|
|
29
29
|
Dynamic: summary
|
|
30
30
|
|
|
31
31
|
===================
|
|
@@ -33,7 +33,6 @@ def main():
|
|
|
33
33
|
"License :: OSI Approved :: Apache Software License",
|
|
34
34
|
"Operating System :: Microsoft :: Windows :: Windows 10",
|
|
35
35
|
"Operating System :: Microsoft :: Windows :: Windows 11",
|
|
36
|
-
"Programming Language :: Python :: 3.7",
|
|
37
36
|
"Programming Language :: Python :: 3.8",
|
|
38
37
|
"Programming Language :: Python :: 3.9",
|
|
39
38
|
"Programming Language :: Python :: 3.10",
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Script for comparing csv-files, 2d-array with a csv-file or 2d-arrays and for comparing text-files, text variable with a text-file or text variables.
|
|
2
|
+
#
|
|
3
|
+
import csv
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
from DataComparerLibrary.twodarray import TwoDArray
|
|
7
|
+
from DataComparerLibrary.report import Report
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DataComparer:
|
|
11
|
+
def compare_data_2d_array_with_file(self, actual_data, expected_file, delimiter_expected_data=",", quotechar_expected_data='"', template_literals_dict=None):
|
|
12
|
+
self.__check_if_actual_data_is_present(actual_data)
|
|
13
|
+
self.__check_if_expected_file_is_present(expected_file)
|
|
14
|
+
#
|
|
15
|
+
expected_data = self.__get_data_from_csv_input_file(expected_file, delimiter_expected_data, quotechar_expected_data)
|
|
16
|
+
#
|
|
17
|
+
DataComparer.compare_data(actual_data, expected_data, template_literals_dict)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def compare_data_file_with_2d_array(self, actual_file, expected_data, delimiter_actual_data=",", quotechar_actual_data='"', template_literals_dict=None):
|
|
21
|
+
self.__check_if_actual_file_is_present(actual_file)
|
|
22
|
+
self.__check_if_expected_data_is_present(expected_data)
|
|
23
|
+
#
|
|
24
|
+
actual_data = self.__get_data_from_csv_input_file(actual_file, delimiter_actual_data, quotechar_actual_data)
|
|
25
|
+
#
|
|
26
|
+
DataComparer.compare_data(actual_data, expected_data, template_literals_dict)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def compare_data_2d_arrays(self, actual_data, expected_data, template_literals_dict=None):
|
|
30
|
+
self.__check_if_actual_data_is_present(actual_data)
|
|
31
|
+
self.__check_if_expected_data_is_present(expected_data)
|
|
32
|
+
#
|
|
33
|
+
DataComparer.compare_data(actual_data, expected_data, template_literals_dict)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def compare_data_files(self, actual_file, expected_file, delimiter_actual_data=",", delimiter_expected_data=",", quotechar_actual_data='"', quotechar_expected_data='"', template_literals_dict=None):
|
|
37
|
+
self.__check_if_actual_file_is_present(actual_file)
|
|
38
|
+
self.__check_if_expected_file_is_present(expected_file)
|
|
39
|
+
#
|
|
40
|
+
actual_data = self.__get_data_from_csv_input_file(actual_file, delimiter_actual_data, quotechar_actual_data)
|
|
41
|
+
expected_data = self.__get_data_from_csv_input_file(expected_file, delimiter_expected_data, quotechar_expected_data)
|
|
42
|
+
#
|
|
43
|
+
DataComparer.compare_data(actual_data, expected_data, template_literals_dict)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def compare_text_variable_with_text_file(self, actual_text, expected_file, template_literals_dict=None):
|
|
48
|
+
self.__check_if_actual_data_is_present(actual_text)
|
|
49
|
+
self.__check_if_expected_file_is_present(expected_file)
|
|
50
|
+
#
|
|
51
|
+
actual_data = self.__split_text_into_textline_array(actual_text)
|
|
52
|
+
expected_data = self.__split_textfile_into_textline_array(expected_file)
|
|
53
|
+
#
|
|
54
|
+
DataComparer.compare_data(actual_data, expected_data, template_literals_dict)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def compare_text_file_with_text_variable(self, actual_file, expected_text, template_literals_dict=None):
|
|
58
|
+
self.__check_if_actual_file_is_present(actual_file)
|
|
59
|
+
self.__check_if_expected_data_is_present(expected_text)
|
|
60
|
+
#
|
|
61
|
+
actual_data = self.__split_textfile_into_textline_array(actual_file)
|
|
62
|
+
expected_data = self.__split_text_into_textline_array(expected_text)
|
|
63
|
+
#
|
|
64
|
+
DataComparer.compare_data(actual_data, expected_data, template_literals_dict)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def compare_text_variables(self, actual_text, expected_text, template_literals_dict=None):
|
|
68
|
+
self.__check_if_actual_data_is_present(actual_text)
|
|
69
|
+
self.__check_if_expected_data_is_present(expected_text)
|
|
70
|
+
#
|
|
71
|
+
actual_data = self.__split_text_into_textline_array(actual_text)
|
|
72
|
+
expected_data = self.__split_text_into_textline_array(expected_text)
|
|
73
|
+
#
|
|
74
|
+
DataComparer.compare_data(actual_data, expected_data, template_literals_dict)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def compare_text_files(self, actual_file, expected_file, template_literals_dict=None):
|
|
78
|
+
self.__check_if_actual_file_is_present(actual_file)
|
|
79
|
+
self.__check_if_expected_file_is_present(expected_file)
|
|
80
|
+
#
|
|
81
|
+
actual_data = self.__split_textfile_into_textline_array(actual_file)
|
|
82
|
+
expected_data = self.__split_textfile_into_textline_array(expected_file)
|
|
83
|
+
#
|
|
84
|
+
DataComparer.compare_data(actual_data, expected_data, template_literals_dict)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def compare_data(actual_data, expected_data, template_literals_dict=None):
|
|
90
|
+
actual_data = DataComparer.__make_data_2d_compliant(actual_data)
|
|
91
|
+
expected_data = DataComparer.__make_data_2d_compliant(expected_data)
|
|
92
|
+
#
|
|
93
|
+
Report.show_header_and_data("Actual data", actual_data)
|
|
94
|
+
Report.show_header_and_data("Expected data", expected_data)
|
|
95
|
+
Report.show_header_differences_actual_and_expected_data()
|
|
96
|
+
#
|
|
97
|
+
Report().show_footer_comparation_result(TwoDArray(actual_data).equals(TwoDArray(expected_data), template_literals_dict))
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@staticmethod
|
|
101
|
+
def __check_if_actual_data_is_present(data):
|
|
102
|
+
if data == None:
|
|
103
|
+
raise Exception("Actual Input data unknown.")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def __check_if_expected_data_is_present(data):
|
|
108
|
+
if data == None:
|
|
109
|
+
raise Exception("Expected Input data unknown.")
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def __check_if_actual_file_is_present(file):
|
|
114
|
+
if os.path.exists(file):
|
|
115
|
+
print("actual_file: ", file)
|
|
116
|
+
else:
|
|
117
|
+
raise Exception("Actual Input file doesn't exists: ", file)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
@staticmethod
|
|
121
|
+
def __check_if_expected_file_is_present(file):
|
|
122
|
+
if os.path.exists(file):
|
|
123
|
+
print("expected_file: ", file)
|
|
124
|
+
else:
|
|
125
|
+
raise Exception("Expected Input file doesn't exists: ", file)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@staticmethod
|
|
129
|
+
def __get_data_from_csv_input_file(input_file, delimiter_data=",", quotechar_data='"'):
|
|
130
|
+
with open(input_file, mode='rt', encoding='utf-8') as input_file:
|
|
131
|
+
if len(delimiter_data) == 1:
|
|
132
|
+
data = list(csv.reader(input_file, delimiter=delimiter_data, quotechar=quotechar_data))
|
|
133
|
+
else:
|
|
134
|
+
data = list(csv.reader((line.replace(delimiter_data, chr(255)) for line in input_file), delimiter=chr(255), quotechar=quotechar_data))
|
|
135
|
+
#
|
|
136
|
+
return data
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
def __split_text_into_textline_array(text):
|
|
141
|
+
data = []
|
|
142
|
+
for line in text.split('\n'):
|
|
143
|
+
data.append(line.strip('\n').split(chr(255)))
|
|
144
|
+
#
|
|
145
|
+
return data
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@staticmethod
|
|
149
|
+
def __split_textfile_into_textline_array(input_file):
|
|
150
|
+
with open(input_file, mode='rt', encoding='utf-8') as input_file:
|
|
151
|
+
data = []
|
|
152
|
+
for line in input_file.readlines():
|
|
153
|
+
data.append(line.strip('\n').split(chr(255)))
|
|
154
|
+
#
|
|
155
|
+
return data
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def __make_data_2d_compliant(data):
|
|
160
|
+
if data and type(data[0]) is not list: # only a single row
|
|
161
|
+
data = [data,] # add row to tuple of lenght 1
|
|
162
|
+
return data
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import fnmatch
|
|
2
|
+
import re
|
|
3
|
+
|
|
4
|
+
from DataComparerLibrary.datetimehandler import DatetimeHandler
|
|
5
|
+
from DataComparerLibrary.report import Report
|
|
6
|
+
from DataComparerLibrary.tools import Tools
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Field:
|
|
10
|
+
def __init__(self, field_data, row_nr, column_nr):
|
|
11
|
+
self.field_data = field_data
|
|
12
|
+
self.row_nr = row_nr
|
|
13
|
+
self.column_nr = column_nr
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def equals(self, other_field_including_templates_and_literals, template_literals_dict):
|
|
17
|
+
equal = True
|
|
18
|
+
|
|
19
|
+
expected_data_including_date_template = None
|
|
20
|
+
expected_data_with_wildcard = None
|
|
21
|
+
skip_exception_rule_used = False
|
|
22
|
+
|
|
23
|
+
if self.field_data == other_field_including_templates_and_literals.field_data:
|
|
24
|
+
return True
|
|
25
|
+
|
|
26
|
+
# Replace literal templates with fixed external strings.
|
|
27
|
+
other_field_data_including_templates = self.__replace_template_literals_dict(other_field_including_templates_and_literals.field_data, template_literals_dict)
|
|
28
|
+
|
|
29
|
+
if self.field_data == other_field_data_including_templates:
|
|
30
|
+
return True
|
|
31
|
+
|
|
32
|
+
# Verify if difference is a matter of string versus integer representation.
|
|
33
|
+
if Field.__is_same_value_but_different_types(self, other_field_data_including_templates):
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
if isinstance(other_field_data_including_templates, int):
|
|
37
|
+
# A real integer.
|
|
38
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "There is a difference between actual and expected data. No match with literals or templates.")
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
# If data in actual and expected field doesn't match, check if a template has been used in expected data.
|
|
42
|
+
match other_field_data_including_templates.upper():
|
|
43
|
+
case "{PRESENT}":
|
|
44
|
+
if not self.field_data:
|
|
45
|
+
# No data is present in actual data field.
|
|
46
|
+
equal = False
|
|
47
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "Actual data field is not PRESENT")
|
|
48
|
+
#
|
|
49
|
+
case "{EMPTY}":
|
|
50
|
+
if self.field_data:
|
|
51
|
+
# Actual data field is not empty.
|
|
52
|
+
equal = False
|
|
53
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "Actual data field is not EMPTY")
|
|
54
|
+
#
|
|
55
|
+
case "{INTEGER}":
|
|
56
|
+
if isinstance(self.field_data, int):
|
|
57
|
+
# A real integer.
|
|
58
|
+
return True
|
|
59
|
+
#
|
|
60
|
+
# Verify if string is integer.
|
|
61
|
+
if not self.field_data.isdigit():
|
|
62
|
+
# Not positive integer field.
|
|
63
|
+
equal = False
|
|
64
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "Actual data field is not INTEGER.")
|
|
65
|
+
#
|
|
66
|
+
case "{SKIP}":
|
|
67
|
+
pass
|
|
68
|
+
case _:
|
|
69
|
+
if "{SKIP}" in other_field_data_including_templates.upper() or "{DATETIME_FORMAT():YYYYMMDDHHMMSSFF6}" in other_field_data_including_templates.upper():
|
|
70
|
+
if other_field_data_including_templates.upper() == "{SKIP}":
|
|
71
|
+
# Complete actual data field will be skipped for verification.
|
|
72
|
+
pass
|
|
73
|
+
else:
|
|
74
|
+
# Part(s) of the actual data field will be skipped for verification.
|
|
75
|
+
# Replace {SKIP}, ignoring cases, by wildcard *.
|
|
76
|
+
# compiled = re.compile(re.escape("{SKIP}"), re.IGNORECASE)
|
|
77
|
+
# expected_data_with_wildcard = compiled.sub("*", other_field_data_including_templates)
|
|
78
|
+
compiled = re.compile(re.escape("{SKIP}"), re.IGNORECASE)
|
|
79
|
+
compiled2 = re.compile(re.escape("{DATETIME_FORMAT():YYYYMMDDHHMMSSFF6}"), re.IGNORECASE)
|
|
80
|
+
expected_data_with_wildcard = compiled2.sub("*", compiled.sub("*", other_field_data_including_templates))
|
|
81
|
+
#
|
|
82
|
+
if fnmatch.fnmatch(self.field_data, expected_data_with_wildcard):
|
|
83
|
+
skip_exception_rule_used = True
|
|
84
|
+
# continue
|
|
85
|
+
#
|
|
86
|
+
if expected_data_with_wildcard == None:
|
|
87
|
+
# Wildcards not used.
|
|
88
|
+
expected_data_including_date_template = other_field_data_including_templates
|
|
89
|
+
else:
|
|
90
|
+
expected_data_including_date_template = expected_data_with_wildcard
|
|
91
|
+
#
|
|
92
|
+
if "{NOW()" in other_field_data_including_templates.upper():
|
|
93
|
+
matches = ["{NOW():", "{NOW()+", "{NOW()-"]
|
|
94
|
+
if all([x not in other_field_data_including_templates.upper() for x in matches]):
|
|
95
|
+
equal = False
|
|
96
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "NOW() has been found in expected data field, but format is incorrect.")
|
|
97
|
+
#continue
|
|
98
|
+
#
|
|
99
|
+
expected_data = DatetimeHandler.replace_date_template_in_expected_data(self, expected_data_including_date_template)
|
|
100
|
+
#
|
|
101
|
+
if expected_data == -1:
|
|
102
|
+
equal = False
|
|
103
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "NOW() has been found in expected data field, but format is incorrect.")
|
|
104
|
+
else:
|
|
105
|
+
if not fnmatch.fnmatch(self.field_data, expected_data):
|
|
106
|
+
# No match despite using of wildcard(s).
|
|
107
|
+
equal = False
|
|
108
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "Date template format displayed. See also next message line.")
|
|
109
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, expected_data, "There is a difference between actual and expected data.")
|
|
110
|
+
# continue
|
|
111
|
+
#
|
|
112
|
+
elif "{NOT(" in other_field_data_including_templates.upper():
|
|
113
|
+
try:
|
|
114
|
+
unwanted_expected_data = Field.__get_unwanted_expected_data(expected_data_including_date_template)
|
|
115
|
+
#
|
|
116
|
+
if self.field_data == unwanted_expected_data:
|
|
117
|
+
# Unwanted match.
|
|
118
|
+
equal = False
|
|
119
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "NOT() template format displayed. See also next message line.")
|
|
120
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, unwanted_expected_data, "Actual and expected data are equal. However actual data should NOT be equal to the expected data!!!")
|
|
121
|
+
except Exception as exception_message:
|
|
122
|
+
# print(f"An exception occurred: {exception_message}")
|
|
123
|
+
equal = False
|
|
124
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "NOT() has been found in expected data field, but format is incorrect.")
|
|
125
|
+
#
|
|
126
|
+
else:
|
|
127
|
+
if not skip_exception_rule_used:
|
|
128
|
+
# No exceptions.
|
|
129
|
+
equal = False
|
|
130
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data_including_templates, "There is a difference between actual and expected data. No exception rule has been used.")
|
|
131
|
+
#
|
|
132
|
+
return equal
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@staticmethod
|
|
136
|
+
def __replace_template_literals_dict(data, template_literals_dict):
|
|
137
|
+
if template_literals_dict:
|
|
138
|
+
for i in range(0, len(template_literals_dict)):
|
|
139
|
+
data = data.replace(list(template_literals_dict.keys())[i], list(template_literals_dict.values())[i])
|
|
140
|
+
return data
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def __is_same_value_but_different_types(self, other_field_data):
|
|
144
|
+
# Verify if difference is a matter of string versus integer representation.
|
|
145
|
+
if str(self.field_data) == str(other_field_data):
|
|
146
|
+
if isinstance(self.field_data, int) and isinstance(other_field_data, str):
|
|
147
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data, "There is a difference between actual and expected data. Actual data is an integer while expected data is a string.")
|
|
148
|
+
return True
|
|
149
|
+
elif isinstance(self.field_data, str) and isinstance(other_field_data, int):
|
|
150
|
+
Report.show_differences_comparation_result(self.row_nr, self.column_nr, self.field_data, other_field_data, "There is a difference between actual and expected data. Actual data is a string while expected data is an integer.")
|
|
151
|
+
return True
|
|
152
|
+
return False
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
@staticmethod
|
|
156
|
+
def __get_unwanted_expected_data(expected_data_field_including_date_template):
|
|
157
|
+
position_open_brace = expected_data_field_including_date_template.find("{NOT(")
|
|
158
|
+
position_close_brace = expected_data_field_including_date_template.find(")}", position_open_brace)
|
|
159
|
+
#
|
|
160
|
+
if position_open_brace == -1:
|
|
161
|
+
#print("position_open_brace:", position_open_brace)
|
|
162
|
+
raise Exception()
|
|
163
|
+
#
|
|
164
|
+
if position_close_brace == -1:
|
|
165
|
+
#print("position_close_brace:", position_close_brace)
|
|
166
|
+
raise Exception()
|
|
167
|
+
#
|
|
168
|
+
unwanted_expected_data = expected_data_field_including_date_template[position_open_brace+5:position_close_brace]
|
|
169
|
+
#
|
|
170
|
+
if Tools.is_integer(unwanted_expected_data):
|
|
171
|
+
unwanted_expected_data = int(unwanted_expected_data)
|
|
172
|
+
return unwanted_expected_data
|
|
173
|
+
|
|
174
|
+
|
{datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/fileconverter.py
RENAMED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
# The files are open in binary mode.
|
|
3
3
|
# Currently, methods are implemented to remove or replace a separate linefeed within a record. Records are ended by carriage return linefeed.
|
|
4
4
|
#
|
|
5
|
+
import csv
|
|
6
|
+
import openpyxl
|
|
5
7
|
import os
|
|
6
8
|
import re
|
|
9
|
+
import warnings
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
class FileConverter:
|
|
10
|
-
|
|
13
|
+
@staticmethod
|
|
14
|
+
def remove_separate_lf(input_file, output_file):
|
|
11
15
|
# Remove separate linefeed (LF), so carriage return linefeed (CRLF) remains.
|
|
12
16
|
try:
|
|
13
17
|
if not os.path.exists(input_file):
|
|
@@ -24,7 +28,8 @@ class FileConverter:
|
|
|
24
28
|
raise Exception("Error message: ", type(error).__name__, "–", error)
|
|
25
29
|
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
@staticmethod
|
|
32
|
+
def replace_separate_lf(input_file, output_file, replacement_string, encoding_replacement_string='utf-8'):
|
|
28
33
|
# Replace separate linefeed (LF), so carriage return linefeed (CRLF) remains.
|
|
29
34
|
try:
|
|
30
35
|
if not os.path.exists(input_file):
|
|
@@ -43,7 +48,8 @@ class FileConverter:
|
|
|
43
48
|
raise Exception("Error message: ", type(error).__name__, "–", error)
|
|
44
49
|
|
|
45
50
|
|
|
46
|
-
|
|
51
|
+
@staticmethod
|
|
52
|
+
def remove_cr_and_lf(input):
|
|
47
53
|
# Remove carriage return (CR) and linefeed (LF) from input string.
|
|
48
54
|
print("input: ", input)
|
|
49
55
|
output = str(input).replace("\r", "").replace("\n", "")
|
|
@@ -52,10 +58,36 @@ class FileConverter:
|
|
|
52
58
|
return output
|
|
53
59
|
|
|
54
60
|
|
|
55
|
-
|
|
61
|
+
@staticmethod
|
|
62
|
+
def replace_cr_and_lf(input, replacement_string):
|
|
56
63
|
# Replace carriage return (CR) and linefeed (LF) from input string.
|
|
57
64
|
print("input: ", input)
|
|
58
65
|
output = str(input).replace("\r", replacement_string).replace("\n", replacement_string)
|
|
59
66
|
print("output: ", output)
|
|
60
67
|
#
|
|
61
68
|
return output
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@staticmethod
|
|
72
|
+
def convert_excel_file_to_csv_file(excel_file, csv_file):
|
|
73
|
+
if not os.path.exists(excel_file):
|
|
74
|
+
raise Exception("Input file doesn't exists: ", excel_file)
|
|
75
|
+
|
|
76
|
+
if not excel_file.endswith('.xslx') and not excel_file.endswith('.xslm') and not excel_file.endswith('.xls') and not excel_file.endswith('.xlm'):
|
|
77
|
+
raise Exception("Input file is not a Excel-file: ", excel_file)
|
|
78
|
+
|
|
79
|
+
if not excel_file.endswith('.csv'):
|
|
80
|
+
raise Exception("Input file is not a csv-file: ", csv_file)
|
|
81
|
+
|
|
82
|
+
with warnings.catch_warnings():
|
|
83
|
+
warnings.filterwarnings("ignore", message="Workbook contains no defaultstyle", category=UserWarning)
|
|
84
|
+
#
|
|
85
|
+
excel = openpyxl.load_workbook(excel_file)
|
|
86
|
+
# select the active sheet
|
|
87
|
+
sheet = excel.active
|
|
88
|
+
#
|
|
89
|
+
# write the data in a csv-file
|
|
90
|
+
col = csv.writer(open(csv_file, 'w', newline=""))
|
|
91
|
+
#
|
|
92
|
+
for row in sheet.rows:
|
|
93
|
+
col.writerow([cell.value for cell in row])
|
|
@@ -1,30 +1,36 @@
|
|
|
1
1
|
class Report:
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
@staticmethod
|
|
3
|
+
def show_header_and_data(header, data):
|
|
4
|
+
Report.show_2d_array(header, data, 20)
|
|
4
5
|
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
@staticmethod
|
|
8
|
+
def show_header_differences_actual_and_expected_data():
|
|
7
9
|
print()
|
|
8
10
|
print("=== Overview differences between actual and expected data")
|
|
9
11
|
print()
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
#show_difference_between_actual_and_expected_data
|
|
13
|
-
|
|
15
|
+
@staticmethod
|
|
16
|
+
def show_differences_comparation_result(row_number, column_number, actual_data, expected_data, error_message):
|
|
14
17
|
print("Row: ", row_number + 1, " Column: ", column_number + 1, " => Actual data: ", actual_data, " Expected data: ", expected_data, " Remark / Error message: ", error_message)
|
|
15
18
|
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
def show_footer_comparation_result(
|
|
19
|
-
if
|
|
20
|
+
@staticmethod
|
|
21
|
+
def show_footer_comparation_result(equal):
|
|
22
|
+
if equal:
|
|
20
23
|
print("\n\n\n")
|
|
21
|
-
raise Exception("There is a difference between actual and expected data. See detail information.")
|
|
22
|
-
else:
|
|
23
24
|
print("There are no differences between actual and expected data found.")
|
|
24
25
|
print("\n\n\n")
|
|
26
|
+
else:
|
|
27
|
+
print("\n\n\n")
|
|
28
|
+
raise Exception("There is a difference between actual and expected data. See detail information.")
|
|
29
|
+
|
|
25
30
|
|
|
26
31
|
|
|
27
|
-
|
|
32
|
+
@staticmethod
|
|
33
|
+
def show_2d_array(title, reader_file_list, column_width):
|
|
28
34
|
max_length_title = 30
|
|
29
35
|
title = title[0:(max_length_title - 1)]
|
|
30
36
|
length_title = len(title)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from DataComparerLibrary.field import Field
|
|
2
|
+
from DataComparerLibrary.report import Report
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class Row:
|
|
6
|
+
def __init__(self, row_data, row_nr):
|
|
7
|
+
self.row_data = row_data
|
|
8
|
+
self.row_nr = row_nr
|
|
9
|
+
#
|
|
10
|
+
self.number_of_columns = len(row_data)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def equals(self, other_row, template_literals_dict):
|
|
14
|
+
equal = True
|
|
15
|
+
#
|
|
16
|
+
max_number_of_columns = max(self.number_of_columns, other_row.number_of_columns)
|
|
17
|
+
#
|
|
18
|
+
for column_nr in range(max_number_of_columns):
|
|
19
|
+
if column_nr >= self.number_of_columns:
|
|
20
|
+
equal = False
|
|
21
|
+
Report.show_differences_comparation_result(self.row_nr, column_nr, "", other_row.row_data[column_nr], "Column actual data is not PRESENT.")
|
|
22
|
+
continue
|
|
23
|
+
#
|
|
24
|
+
if column_nr >= other_row.number_of_columns:
|
|
25
|
+
equal = False
|
|
26
|
+
Report.show_differences_comparation_result(self.row_nr, column_nr, self.row_data[column_nr], "", "Column expected data is not PRESENT.")
|
|
27
|
+
continue
|
|
28
|
+
#
|
|
29
|
+
if not Field(self.row_data[column_nr], self.row_nr, column_nr).equals(Field(other_row.row_data[column_nr], self.row_nr, column_nr), template_literals_dict):
|
|
30
|
+
equal = False
|
|
31
|
+
#
|
|
32
|
+
return equal
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from DataComparerLibrary.row import Row
|
|
2
|
+
from DataComparerLibrary.report import Report
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TwoDArray:
|
|
6
|
+
def __init__(self, two_d_array_data):
|
|
7
|
+
self.two_d_array_data = two_d_array_data
|
|
8
|
+
self.number_of_rows = len(two_d_array_data)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def equals(self, other_two_d_array, template_literals_dict):
|
|
12
|
+
equal = True
|
|
13
|
+
#
|
|
14
|
+
max_number_of_rows = max(self.number_of_rows, other_two_d_array.number_of_rows)
|
|
15
|
+
#
|
|
16
|
+
for row_nr in range(max_number_of_rows):
|
|
17
|
+
if row_nr >= self.number_of_rows:
|
|
18
|
+
equal = False
|
|
19
|
+
if len(other_two_d_array.two_d_array_data[row_nr]) == 0:
|
|
20
|
+
Report.show_differences_comparation_result(row_nr, 0, "", "", "Row actual data is not PRESENT. Row expected data is EMPTY.")
|
|
21
|
+
else:
|
|
22
|
+
Report.show_differences_comparation_result(row_nr, 0, "", other_two_d_array.two_d_array_data[row_nr][0], "Row actual data is not PRESENT.")
|
|
23
|
+
continue
|
|
24
|
+
#
|
|
25
|
+
if row_nr >= other_two_d_array.number_of_rows:
|
|
26
|
+
equal = False
|
|
27
|
+
if len(self.two_d_array_data[row_nr]) == 0:
|
|
28
|
+
Report.show_differences_comparation_result(row_nr, 0, "", "", "Row actual data is EMPTY. Row expected data is not PRESENT.")
|
|
29
|
+
else:
|
|
30
|
+
Report.show_differences_comparation_result(row_nr, 0, self.two_d_array_data[row_nr][0], "", "Row expected data is not PRESENT.")
|
|
31
|
+
continue
|
|
32
|
+
#
|
|
33
|
+
if not Row(self.two_d_array_data[row_nr], row_nr).equals(Row(other_two_d_array.two_d_array_data[row_nr], row_nr), template_literals_dict):
|
|
34
|
+
equal = False
|
|
35
|
+
#
|
|
36
|
+
return equal
|
{datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: DataComparerLibrary
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.847
|
|
4
4
|
Summary: For comparing csv-files, 2d-array with a csv-file or 2d-arrays. For comparing text-files, text variable with a text-file or text variables. Including a sorting module.
|
|
5
5
|
Home-page:
|
|
6
6
|
Author: René Philip Zuijderduijn
|
|
@@ -10,7 +10,6 @@ Keywords: robotframework testing test-automation datacompare
|
|
|
10
10
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
11
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 10
|
|
12
12
|
Classifier: Operating System :: Microsoft :: Windows :: Windows 11
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
14
13
|
Classifier: Programming Language :: Python :: 3.8
|
|
15
14
|
Classifier: Programming Language :: Python :: 3.9
|
|
16
15
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -26,6 +25,7 @@ Dynamic: description
|
|
|
26
25
|
Dynamic: description-content-type
|
|
27
26
|
Dynamic: keywords
|
|
28
27
|
Dynamic: license
|
|
28
|
+
Dynamic: license-file
|
|
29
29
|
Dynamic: summary
|
|
30
30
|
|
|
31
31
|
===================
|
{datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary.egg-info/SOURCES.txt
RENAMED
|
@@ -3,17 +3,18 @@ README.rst
|
|
|
3
3
|
pyproject.toml
|
|
4
4
|
setup.py
|
|
5
5
|
src/DataComparerLibrary/__init__.py
|
|
6
|
-
src/DataComparerLibrary/arraycomparer.py
|
|
7
6
|
src/DataComparerLibrary/datacomparer.py
|
|
8
7
|
src/DataComparerLibrary/datasorter.py
|
|
9
8
|
src/DataComparerLibrary/datetimehandler.py
|
|
10
9
|
src/DataComparerLibrary/delimitertranslator.py
|
|
10
|
+
src/DataComparerLibrary/field.py
|
|
11
11
|
src/DataComparerLibrary/fileconverter.py
|
|
12
12
|
src/DataComparerLibrary/report.py
|
|
13
|
+
src/DataComparerLibrary/row.py
|
|
13
14
|
src/DataComparerLibrary/tools.py
|
|
15
|
+
src/DataComparerLibrary/twodarray.py
|
|
14
16
|
src/DataComparerLibrary/version.py
|
|
15
17
|
src/DataComparerLibrary.egg-info/PKG-INFO
|
|
16
18
|
src/DataComparerLibrary.egg-info/SOURCES.txt
|
|
17
19
|
src/DataComparerLibrary.egg-info/dependency_links.txt
|
|
18
|
-
src/DataComparerLibrary.egg-info/top_level.txt
|
|
19
|
-
test/test1.py
|
|
20
|
+
src/DataComparerLibrary.egg-info/top_level.txt
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import fnmatch
|
|
2
|
-
import re
|
|
3
|
-
|
|
4
|
-
from DataComparerLibrary.datetimehandler import DatetimeHandler
|
|
5
|
-
from DataComparerLibrary.report import Report
|
|
6
|
-
from DataComparerLibrary.tools import Tools
|
|
7
|
-
|
|
8
|
-
class ArrayComparer:
|
|
9
|
-
def compare_data(self, actual_data, expected_data_including_templates, template_literals_dict):
|
|
10
|
-
difference_found = False
|
|
11
|
-
#
|
|
12
|
-
if actual_data and type(actual_data[0]) is not list: # only a single row
|
|
13
|
-
actual_data = [actual_data,] # add row to tuple of lenght 1
|
|
14
|
-
#
|
|
15
|
-
if expected_data_including_templates and type(expected_data_including_templates[0]) is not list: # only a single row
|
|
16
|
-
expected_data_including_templates = [expected_data_including_templates,] # add row to tuple of lenght 1
|
|
17
|
-
|
|
18
|
-
number_of_rows_actual_data = len(actual_data)
|
|
19
|
-
number_of_rows_expected_data = len(expected_data_including_templates)
|
|
20
|
-
|
|
21
|
-
number_of_rows = max(number_of_rows_actual_data, number_of_rows_expected_data)
|
|
22
|
-
|
|
23
|
-
Report.show_2d_array(self, "Actual data", actual_data, 20)
|
|
24
|
-
Report.show_2d_array(self, "Expected data", expected_data_including_templates, 20)
|
|
25
|
-
|
|
26
|
-
Report().show_header_differences_actual_and_expected_data()
|
|
27
|
-
|
|
28
|
-
for row_nr in range(number_of_rows):
|
|
29
|
-
if row_nr >= number_of_rows_actual_data:
|
|
30
|
-
difference_found = True
|
|
31
|
-
if len(expected_data_including_templates[row_nr]) == 0:
|
|
32
|
-
Report.show_differences_comparation_result(self, row_nr, 0, "", "", "Row actual data is not PRESENT. Row expected data is EMPTY.")
|
|
33
|
-
else:
|
|
34
|
-
Report.show_differences_comparation_result(self, row_nr, 0, "", expected_data_including_templates[row_nr][0], "Row actual data is not PRESENT.")
|
|
35
|
-
continue
|
|
36
|
-
#
|
|
37
|
-
if row_nr >= number_of_rows_expected_data:
|
|
38
|
-
difference_found = True
|
|
39
|
-
if len(actual_data[row_nr]) == 0:
|
|
40
|
-
Report.show_differences_comparation_result(self, row_nr, 0, "", "", "Row actual data is EMPTY. Row expected data is not PRESENT.")
|
|
41
|
-
else:
|
|
42
|
-
Report.show_differences_comparation_result(self, row_nr, 0, actual_data[row_nr][0], "", "Row expected data is not PRESENT.")
|
|
43
|
-
continue
|
|
44
|
-
#
|
|
45
|
-
number_of_columns_actual_data = len(actual_data[row_nr])
|
|
46
|
-
number_of_columns_expected_data = len(expected_data_including_templates[row_nr])
|
|
47
|
-
|
|
48
|
-
number_of_columns = max(number_of_columns_actual_data, number_of_columns_expected_data)
|
|
49
|
-
|
|
50
|
-
for column_nr in range(number_of_columns):
|
|
51
|
-
expected_data_including_date_template = None
|
|
52
|
-
expected_data_with_wildcard = None
|
|
53
|
-
skip_exception_rule_used = False
|
|
54
|
-
#
|
|
55
|
-
if column_nr >= number_of_columns_actual_data:
|
|
56
|
-
difference_found = True
|
|
57
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, "", expected_data_including_templates[row_nr][column_nr], "Column actual data is not PRESENT.")
|
|
58
|
-
continue
|
|
59
|
-
#
|
|
60
|
-
if column_nr >= number_of_columns_expected_data:
|
|
61
|
-
difference_found = True
|
|
62
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], "", "Column expected data is not PRESENT.")
|
|
63
|
-
continue
|
|
64
|
-
#
|
|
65
|
-
if actual_data[row_nr][column_nr] != expected_data_including_templates[row_nr][column_nr]:
|
|
66
|
-
# Replace literal templates with fixed external strings.
|
|
67
|
-
if template_literals_dict:
|
|
68
|
-
for i in range(0, len(template_literals_dict)):
|
|
69
|
-
# key = list(template_literals_dict.keys())[i]
|
|
70
|
-
# value = list(template_literals_dict.values())[i]
|
|
71
|
-
# print("key: ", key)
|
|
72
|
-
# print("value: ", value)
|
|
73
|
-
expected_data_including_templates[row_nr][column_nr] = expected_data_including_templates[row_nr][column_nr].replace(list(template_literals_dict.keys())[i], list(template_literals_dict.values())[i])
|
|
74
|
-
# print("actual_data[row_nr][column_nr]: \n", actual_data[row_nr][column_nr])
|
|
75
|
-
# print("expected_data_including_templates[row_nr][column_nr]: \n", expected_data_including_templates[row_nr][column_nr])
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# Verify if difference is a matter of string versus integer representation.
|
|
79
|
-
if str(actual_data[row_nr][column_nr]) == str(expected_data_including_templates[row_nr][column_nr]):
|
|
80
|
-
if isinstance(actual_data[row_nr][column_nr], int) and isinstance(expected_data_including_templates[row_nr][column_nr], str):
|
|
81
|
-
difference_found = True
|
|
82
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "There is a difference between actual and expected data. Actual data is an integer while expected data is a string.")
|
|
83
|
-
elif isinstance(actual_data[row_nr][column_nr], str) and isinstance(expected_data_including_templates[row_nr][column_nr], int):
|
|
84
|
-
difference_found = True
|
|
85
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "There is a difference between actual and expected data. Actual data is a string while expected data is an integer.")
|
|
86
|
-
continue
|
|
87
|
-
#
|
|
88
|
-
# If data in actual and expected field doesn't match, check if a template has been used in expected data.
|
|
89
|
-
match expected_data_including_templates[row_nr][column_nr].upper():
|
|
90
|
-
case "{PRESENT}":
|
|
91
|
-
if not actual_data[row_nr][column_nr]:
|
|
92
|
-
# No data is present in actual data field.
|
|
93
|
-
difference_found = True
|
|
94
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "Actual data field is not PRESENT")
|
|
95
|
-
#
|
|
96
|
-
case "{EMPTY}":
|
|
97
|
-
if actual_data[row_nr][column_nr]:
|
|
98
|
-
# Actual data field is not empty.
|
|
99
|
-
difference_found = True
|
|
100
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "Actual data field is not EMPTY")
|
|
101
|
-
#
|
|
102
|
-
case "{INTEGER}":
|
|
103
|
-
if isinstance(actual_data[row_nr][column_nr], int):
|
|
104
|
-
# A real integer.
|
|
105
|
-
continue
|
|
106
|
-
#
|
|
107
|
-
# Verify if string is integer.
|
|
108
|
-
if not actual_data[row_nr][column_nr].isdigit():
|
|
109
|
-
# Not positive integer field.
|
|
110
|
-
difference_found = True
|
|
111
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "Actual data field is not INTEGER.")
|
|
112
|
-
#
|
|
113
|
-
case "{SKIP}":
|
|
114
|
-
pass
|
|
115
|
-
case _:
|
|
116
|
-
if "{SKIP}" in expected_data_including_templates[row_nr][column_nr].upper() or "{DATETIME_FORMAT():YYYYMMDDHHMMSSFF6}" in expected_data_including_templates[row_nr][column_nr].upper():
|
|
117
|
-
if expected_data_including_templates[row_nr][column_nr].upper() == "{SKIP}":
|
|
118
|
-
# Complete actual data field will be skipped for verification.
|
|
119
|
-
pass
|
|
120
|
-
else:
|
|
121
|
-
# Part(s) of the actual data field will be skipped for verification.
|
|
122
|
-
# Replace {SKIP}, ignoring cases, by wildcard *.
|
|
123
|
-
# compiled = re.compile(re.escape("{SKIP}"), re.IGNORECASE)
|
|
124
|
-
# expected_data_with_wildcard = compiled.sub("*", expected_data_including_templates[row_nr][column_nr])
|
|
125
|
-
compiled = re.compile(re.escape("{SKIP}"), re.IGNORECASE)
|
|
126
|
-
compiled2 = re.compile(re.escape("{DATETIME_FORMAT():YYYYMMDDHHMMSSFF6}"), re.IGNORECASE)
|
|
127
|
-
expected_data_with_wildcard = compiled2.sub("*", compiled.sub("*", expected_data_including_templates[row_nr][column_nr]))
|
|
128
|
-
#
|
|
129
|
-
if fnmatch.fnmatch(actual_data[row_nr][column_nr], expected_data_with_wildcard):
|
|
130
|
-
skip_exception_rule_used = True
|
|
131
|
-
continue
|
|
132
|
-
#
|
|
133
|
-
if expected_data_with_wildcard is None:
|
|
134
|
-
# Wildcards not used.
|
|
135
|
-
expected_data_including_date_template = expected_data_including_templates[row_nr][column_nr]
|
|
136
|
-
else:
|
|
137
|
-
expected_data_including_date_template = expected_data_with_wildcard
|
|
138
|
-
#
|
|
139
|
-
if "{NOW()" in expected_data_including_templates[row_nr][column_nr].upper():
|
|
140
|
-
matches = ["{NOW():", "{NOW()+", "{NOW()-"]
|
|
141
|
-
if all([x not in expected_data_including_templates[row_nr][column_nr].upper() for x in matches]):
|
|
142
|
-
difference_found = True
|
|
143
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "NOW() has been found in expected data field, but format is incorrect.")
|
|
144
|
-
continue
|
|
145
|
-
#
|
|
146
|
-
expected_data = DatetimeHandler.replace_date_template_in_expected_data(self, expected_data_including_date_template)
|
|
147
|
-
#
|
|
148
|
-
if expected_data == -1:
|
|
149
|
-
difference_found = True
|
|
150
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "NOW() has been found in expected data field, but format is incorrect.")
|
|
151
|
-
else:
|
|
152
|
-
if not fnmatch.fnmatch(actual_data[row_nr][column_nr], expected_data):
|
|
153
|
-
# No match despite using of wildcard(s).
|
|
154
|
-
difference_found = True
|
|
155
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "Date template format displayed. See also next message line.")
|
|
156
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data, "There is a difference between actual and expected data.")
|
|
157
|
-
continue
|
|
158
|
-
#
|
|
159
|
-
elif "{NOT(" in expected_data_including_templates[row_nr][column_nr].upper():
|
|
160
|
-
try:
|
|
161
|
-
unwanted_expected_data = ArrayComparer.__get_unwanted_expected_data(self, expected_data_including_date_template)
|
|
162
|
-
#
|
|
163
|
-
if actual_data[row_nr][column_nr] == unwanted_expected_data:
|
|
164
|
-
# Unwanted match.
|
|
165
|
-
difference_found = True
|
|
166
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "NOT() template format displayed. See also next message line.")
|
|
167
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], unwanted_expected_data, "Actual and expected data are equal. However actual data should NOT be equal to the expected data!!!")
|
|
168
|
-
except Exception as exception_message:
|
|
169
|
-
# print(f"An exception occurred: {exception_message}")
|
|
170
|
-
difference_found = True
|
|
171
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "NOT() has been found in expected data field, but format is incorrect.")
|
|
172
|
-
#
|
|
173
|
-
else:
|
|
174
|
-
if not skip_exception_rule_used:
|
|
175
|
-
# No exceptions.
|
|
176
|
-
difference_found = True
|
|
177
|
-
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data_including_templates[row_nr][column_nr], "There is a difference between actual and expected data. No exception rule has been used.")
|
|
178
|
-
#
|
|
179
|
-
if difference_found:
|
|
180
|
-
print("\n\n\n")
|
|
181
|
-
raise Exception("There is a difference between actual and expected data. See detail information.")
|
|
182
|
-
else:
|
|
183
|
-
print("There are no differences between actual and expected data found.")
|
|
184
|
-
print("\n\n\n")
|
|
185
|
-
|
|
186
|
-
#Report().show_footer_comparation_result()
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
def __get_unwanted_expected_data(self, expected_data_field_including_date_template):
|
|
190
|
-
position_open_brace = expected_data_field_including_date_template.find("{NOT(")
|
|
191
|
-
position_close_brace = expected_data_field_including_date_template.find(")}", position_open_brace)
|
|
192
|
-
#
|
|
193
|
-
if position_open_brace == -1:
|
|
194
|
-
#print("position_open_brace:", position_open_brace)
|
|
195
|
-
raise Exception()
|
|
196
|
-
#
|
|
197
|
-
if position_close_brace == -1:
|
|
198
|
-
#print("position_close_brace:", position_close_brace)
|
|
199
|
-
raise Exception()
|
|
200
|
-
#
|
|
201
|
-
unwanted_expected_data = expected_data_field_including_date_template[position_open_brace+5:position_close_brace]
|
|
202
|
-
#
|
|
203
|
-
if Tools.is_integer(self, unwanted_expected_data):
|
|
204
|
-
unwanted_expected_data = int(unwanted_expected_data)
|
|
205
|
-
return unwanted_expected_data
|
|
206
|
-
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# Script for comparing csv-files, 2d-array with a csv-file or 2d-arrays and for comparing text-files, text variable with a text-file or text variables.
|
|
2
|
-
#
|
|
3
|
-
import csv
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
from DataComparerLibrary.arraycomparer import ArrayComparer
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
class DataComparer:
|
|
10
|
-
def compare_data_2d_array_with_file(self, actual_data, expected_file, delimiter_expected_data=",", quotechar_expected_data='"', template_literals_dict=None):
|
|
11
|
-
self.__check_if_actual_data_is_present(actual_data)
|
|
12
|
-
self.__check_if_expected_file_is_present(expected_file)
|
|
13
|
-
#
|
|
14
|
-
expected_data = self.__open_csv_input_file(expected_file, delimiter_expected_data, quotechar_expected_data)
|
|
15
|
-
#
|
|
16
|
-
ArrayComparer.compare_data(self, actual_data, expected_data, template_literals_dict)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def compare_data_file_with_2d_array(self, actual_file, expected_data, delimiter_actual_data=",", quotechar_actual_data='"', template_literals_dict=None):
|
|
20
|
-
self.__check_if_actual_file_is_present(actual_file)
|
|
21
|
-
self.__check_if_expected_data_is_present(expected_data)
|
|
22
|
-
#
|
|
23
|
-
actual_data = self.__open_csv_input_file(actual_file, delimiter_actual_data, quotechar_actual_data)
|
|
24
|
-
#
|
|
25
|
-
ArrayComparer.compare_data(self, actual_data, expected_data, template_literals_dict)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def compare_data_2d_arrays(self, actual_data, expected_data, template_literals_dict=None):
|
|
29
|
-
self.__check_if_actual_data_is_present(actual_data)
|
|
30
|
-
self.__check_if_expected_data_is_present(expected_data)
|
|
31
|
-
#
|
|
32
|
-
ArrayComparer.compare_data(self, actual_data, expected_data, template_literals_dict)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def compare_data_files(self, actual_file, expected_file, delimiter_actual_data=",", delimiter_expected_data=",", quotechar_actual_data='"', quotechar_expected_data='"', template_literals_dict=None):
|
|
36
|
-
self.__check_if_actual_file_is_present(actual_file)
|
|
37
|
-
self.__check_if_expected_file_is_present(expected_file)
|
|
38
|
-
#
|
|
39
|
-
actual_data = self.__open_csv_input_file(actual_file, delimiter_actual_data, quotechar_actual_data)
|
|
40
|
-
expected_data = self.__open_csv_input_file(expected_file, delimiter_expected_data, quotechar_expected_data)
|
|
41
|
-
#
|
|
42
|
-
ArrayComparer.compare_data(self, actual_data, expected_data, template_literals_dict)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def compare_text_variable_with_text_file(self, actual_text, expected_file, template_literals_dict=None):
|
|
46
|
-
self.__check_if_actual_data_is_present(actual_text)
|
|
47
|
-
self.__check_if_expected_file_is_present(expected_file)
|
|
48
|
-
#
|
|
49
|
-
actual_data = self.__split_text_into_textline_array(actual_text)
|
|
50
|
-
expected_data = self.__split_textfile_into_textline_array(expected_file)
|
|
51
|
-
#
|
|
52
|
-
ArrayComparer.compare_data(self, actual_data, expected_data, template_literals_dict)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def compare_text_file_with_text_variable(self, actual_file, expected_text, template_literals_dict=None):
|
|
56
|
-
self.__check_if_actual_file_is_present(actual_file)
|
|
57
|
-
self.__check_if_expected_data_is_present(expected_text)
|
|
58
|
-
#
|
|
59
|
-
actual_data = self.__split_textfile_into_textline_array(actual_file)
|
|
60
|
-
expected_data = self.__split_text_into_textline_array(expected_text)
|
|
61
|
-
#
|
|
62
|
-
ArrayComparer.compare_data(self, actual_data, expected_data, template_literals_dict)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
def compare_text_variables(self, actual_text, expected_text, template_literals_dict=None):
|
|
66
|
-
self.__check_if_actual_data_is_present(actual_text)
|
|
67
|
-
self.__check_if_expected_data_is_present(expected_text)
|
|
68
|
-
#
|
|
69
|
-
actual_data = self.__split_text_into_textline_array(actual_text)
|
|
70
|
-
expected_data = self.__split_text_into_textline_array(expected_text)
|
|
71
|
-
#
|
|
72
|
-
ArrayComparer.compare_data(self, actual_data, expected_data, template_literals_dict)
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def compare_text_files(self, actual_file, expected_file, template_literals_dict=None):
|
|
76
|
-
self.__check_if_actual_file_is_present(actual_file)
|
|
77
|
-
self.__check_if_expected_file_is_present(expected_file)
|
|
78
|
-
#
|
|
79
|
-
actual_data = self.__split_textfile_into_textline_array(actual_file)
|
|
80
|
-
expected_data = self.__split_textfile_into_textline_array(expected_file)
|
|
81
|
-
#
|
|
82
|
-
ArrayComparer.compare_data(self, actual_data, expected_data, template_literals_dict)
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def __check_if_actual_data_is_present(self, data):
|
|
87
|
-
if data == None:
|
|
88
|
-
raise Exception("Actual Input data unknown.")
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
def __check_if_expected_data_is_present(self, data):
|
|
92
|
-
if data == None:
|
|
93
|
-
raise Exception("Expected Input data unknown.")
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def __check_if_actual_file_is_present(self, file):
|
|
97
|
-
if os.path.exists(file):
|
|
98
|
-
print("actual_file: ", file)
|
|
99
|
-
else:
|
|
100
|
-
raise Exception("Actual Input file doesn't exists: ", file)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def __check_if_expected_file_is_present(self, file):
|
|
104
|
-
if os.path.exists(file):
|
|
105
|
-
print("expected_file: ", file)
|
|
106
|
-
else:
|
|
107
|
-
raise Exception("Expected Input file doesn't exists: ", file)
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
def __open_csv_input_file(self, input_file, delimiter_data=",", quotechar_data='"'):
|
|
111
|
-
with open(input_file, mode='rt', encoding='utf-8') as input_file:
|
|
112
|
-
if len(delimiter_data) == 1:
|
|
113
|
-
data = list(csv.reader(input_file, delimiter=delimiter_data, quotechar=quotechar_data))
|
|
114
|
-
else:
|
|
115
|
-
data = list(csv.reader((line.replace(delimiter_data, chr(255)) for line in input_file), delimiter=chr(255), quotechar=quotechar_data))
|
|
116
|
-
#
|
|
117
|
-
return data
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
def __split_text_into_textline_array(self, text):
|
|
121
|
-
data = []
|
|
122
|
-
for line in text.split('\n'):
|
|
123
|
-
data.append(line.strip('\n').split(chr(255)))
|
|
124
|
-
#
|
|
125
|
-
return data
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def __split_textfile_into_textline_array(self, input_file):
|
|
129
|
-
with open(input_file, mode='rt', encoding='utf-8') as input_file:
|
|
130
|
-
data = []
|
|
131
|
-
for line in input_file.readlines():
|
|
132
|
-
data.append(line.strip('\n').split(chr(255)))
|
|
133
|
-
#
|
|
134
|
-
return data
|
|
135
|
-
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from DataComparerLibrary import DataComparer
|
|
2
|
-
|
|
3
|
-
# Input files
|
|
4
|
-
actual_file = "C:\\Users\\USER\\Documents\\Tool projecten\\Robot Framework Verzamelmap\\RobotDemo-master-Probeersel\\data_vergelijker\\actueel_resultaat\\actual.csv"
|
|
5
|
-
expected_file = "C:\\Users\\USER\\Documents\\Tool projecten\\Robot Framework Verzamelmap\\RobotDemo-master-Probeersel\\data_vergelijker\\verwacht_resultaat\\expected_equal.csv"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
a = DataComparer()
|
|
9
|
-
a.compare_data_files(actual_file, expected_file, delimiter_actual_data=';', delimiter_expected_data=';')
|
|
10
|
-
a.compare_data_files(actual_file, expected_file, delimiter_actual_data=';', delimiter_expected_data=';', quotechar_actual_data=None, quotechar_expected_data=None)
|
|
11
|
-
a.compare_data_files(actual_file, expected_file)
|
|
12
|
-
actual_data_input = [['3', '1.1', '4', '7', '2023-05-27 12:00'],
|
|
13
|
-
['1', '0', '2', '9', '2023-05-29 12:00'],
|
|
14
|
-
['', '2', '0', '1', '5'],
|
|
15
|
-
['5.1', '8', '1', '0', '3'],
|
|
16
|
-
['3', '', '2023-06-19', '3', '2023-06-08']]
|
|
17
|
-
|
|
18
|
-
a.compare_data_files(actual_data_input, expected_file)
|
|
19
|
-
|
|
20
|
-
a.compare_data_files(actual_file, expected_file)
|
|
21
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/datasorter.py
RENAMED
|
File without changes
|
{datacomparerlibrary-0.845 → datacomparerlibrary-0.847}/src/DataComparerLibrary/datetimehandler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|