DataComparerLibrary 0.844__tar.gz → 0.845__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.844 → datacomparerlibrary-0.845}/PKG-INFO +10 -2
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/arraycomparer.py +27 -135
- datacomparerlibrary-0.845/src/DataComparerLibrary/datetimehandler.py +100 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/report.py +26 -5
- datacomparerlibrary-0.845/src/DataComparerLibrary/version.py +3 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/PKG-INFO +10 -2
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/SOURCES.txt +1 -0
- datacomparerlibrary-0.844/src/DataComparerLibrary/version.py +0 -3
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/LICENSE.txt +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/README.rst +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/pyproject.toml +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/setup.cfg +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/setup.py +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/__init__.py +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/datacomparer.py +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/datasorter.py +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/delimitertranslator.py +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/fileconverter.py +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/tools.py +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/dependency_links.txt +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/top_level.txt +0 -0
- {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/test/test1.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: DataComparerLibrary
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.845
|
|
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
|
|
@@ -19,6 +19,14 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
20
|
Description-Content-Type: text/x-rst
|
|
21
21
|
License-File: LICENSE.txt
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: author-email
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: description
|
|
26
|
+
Dynamic: description-content-type
|
|
27
|
+
Dynamic: keywords
|
|
28
|
+
Dynamic: license
|
|
29
|
+
Dynamic: summary
|
|
22
30
|
|
|
23
31
|
===================
|
|
24
32
|
DataComparerLibrary
|
{datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/arraycomparer.py
RENAMED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import datetime
|
|
2
1
|
import fnmatch
|
|
3
2
|
import re
|
|
4
|
-
import dateutil.relativedelta
|
|
5
3
|
|
|
4
|
+
from DataComparerLibrary.datetimehandler import DatetimeHandler
|
|
6
5
|
from DataComparerLibrary.report import Report
|
|
6
|
+
from DataComparerLibrary.tools import Tools
|
|
7
7
|
|
|
8
8
|
class ArrayComparer:
|
|
9
9
|
def compare_data(self, actual_data, expected_data_including_templates, template_literals_dict):
|
|
@@ -18,36 +18,34 @@ class ArrayComparer:
|
|
|
18
18
|
number_of_rows_actual_data = len(actual_data)
|
|
19
19
|
number_of_rows_expected_data = len(expected_data_including_templates)
|
|
20
20
|
|
|
21
|
-
number_of_rows =
|
|
21
|
+
number_of_rows = max(number_of_rows_actual_data, number_of_rows_expected_data)
|
|
22
22
|
|
|
23
23
|
Report.show_2d_array(self, "Actual data", actual_data, 20)
|
|
24
24
|
Report.show_2d_array(self, "Expected data", expected_data_including_templates, 20)
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
print("=== Overview differences between actual and expected data")
|
|
28
|
-
print()
|
|
26
|
+
Report().show_header_differences_actual_and_expected_data()
|
|
29
27
|
|
|
30
28
|
for row_nr in range(number_of_rows):
|
|
31
29
|
if row_nr >= number_of_rows_actual_data:
|
|
32
30
|
difference_found = True
|
|
33
31
|
if len(expected_data_including_templates[row_nr]) == 0:
|
|
34
|
-
Report.
|
|
32
|
+
Report.show_differences_comparation_result(self, row_nr, 0, "", "", "Row actual data is not PRESENT. Row expected data is EMPTY.")
|
|
35
33
|
else:
|
|
36
|
-
Report.
|
|
34
|
+
Report.show_differences_comparation_result(self, row_nr, 0, "", expected_data_including_templates[row_nr][0], "Row actual data is not PRESENT.")
|
|
37
35
|
continue
|
|
38
36
|
#
|
|
39
37
|
if row_nr >= number_of_rows_expected_data:
|
|
40
38
|
difference_found = True
|
|
41
39
|
if len(actual_data[row_nr]) == 0:
|
|
42
|
-
Report.
|
|
40
|
+
Report.show_differences_comparation_result(self, row_nr, 0, "", "", "Row actual data is EMPTY. Row expected data is not PRESENT.")
|
|
43
41
|
else:
|
|
44
|
-
Report.
|
|
42
|
+
Report.show_differences_comparation_result(self, row_nr, 0, actual_data[row_nr][0], "", "Row expected data is not PRESENT.")
|
|
45
43
|
continue
|
|
46
44
|
#
|
|
47
45
|
number_of_columns_actual_data = len(actual_data[row_nr])
|
|
48
46
|
number_of_columns_expected_data = len(expected_data_including_templates[row_nr])
|
|
49
47
|
|
|
50
|
-
number_of_columns =
|
|
48
|
+
number_of_columns = max(number_of_columns_actual_data, number_of_columns_expected_data)
|
|
51
49
|
|
|
52
50
|
for column_nr in range(number_of_columns):
|
|
53
51
|
expected_data_including_date_template = None
|
|
@@ -56,12 +54,12 @@ class ArrayComparer:
|
|
|
56
54
|
#
|
|
57
55
|
if column_nr >= number_of_columns_actual_data:
|
|
58
56
|
difference_found = True
|
|
59
|
-
Report.
|
|
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.")
|
|
60
58
|
continue
|
|
61
59
|
#
|
|
62
60
|
if column_nr >= number_of_columns_expected_data:
|
|
63
61
|
difference_found = True
|
|
64
|
-
Report.
|
|
62
|
+
Report.show_differences_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], "", "Column expected data is not PRESENT.")
|
|
65
63
|
continue
|
|
66
64
|
#
|
|
67
65
|
if actual_data[row_nr][column_nr] != expected_data_including_templates[row_nr][column_nr]:
|
|
@@ -81,10 +79,10 @@ class ArrayComparer:
|
|
|
81
79
|
if str(actual_data[row_nr][column_nr]) == str(expected_data_including_templates[row_nr][column_nr]):
|
|
82
80
|
if isinstance(actual_data[row_nr][column_nr], int) and isinstance(expected_data_including_templates[row_nr][column_nr], str):
|
|
83
81
|
difference_found = True
|
|
84
|
-
Report.
|
|
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.")
|
|
85
83
|
elif isinstance(actual_data[row_nr][column_nr], str) and isinstance(expected_data_including_templates[row_nr][column_nr], int):
|
|
86
84
|
difference_found = True
|
|
87
|
-
Report.
|
|
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.")
|
|
88
86
|
continue
|
|
89
87
|
#
|
|
90
88
|
# If data in actual and expected field doesn't match, check if a template has been used in expected data.
|
|
@@ -93,13 +91,13 @@ class ArrayComparer:
|
|
|
93
91
|
if not actual_data[row_nr][column_nr]:
|
|
94
92
|
# No data is present in actual data field.
|
|
95
93
|
difference_found = True
|
|
96
|
-
Report.
|
|
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")
|
|
97
95
|
#
|
|
98
96
|
case "{EMPTY}":
|
|
99
97
|
if actual_data[row_nr][column_nr]:
|
|
100
98
|
# Actual data field is not empty.
|
|
101
99
|
difference_found = True
|
|
102
|
-
Report.
|
|
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")
|
|
103
101
|
#
|
|
104
102
|
case "{INTEGER}":
|
|
105
103
|
if isinstance(actual_data[row_nr][column_nr], int):
|
|
@@ -110,7 +108,7 @@ class ArrayComparer:
|
|
|
110
108
|
if not actual_data[row_nr][column_nr].isdigit():
|
|
111
109
|
# Not positive integer field.
|
|
112
110
|
difference_found = True
|
|
113
|
-
Report.
|
|
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.")
|
|
114
112
|
#
|
|
115
113
|
case "{SKIP}":
|
|
116
114
|
pass
|
|
@@ -142,20 +140,20 @@ class ArrayComparer:
|
|
|
142
140
|
matches = ["{NOW():", "{NOW()+", "{NOW()-"]
|
|
143
141
|
if all([x not in expected_data_including_templates[row_nr][column_nr].upper() for x in matches]):
|
|
144
142
|
difference_found = True
|
|
145
|
-
Report.
|
|
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.")
|
|
146
144
|
continue
|
|
147
145
|
#
|
|
148
|
-
expected_data =
|
|
146
|
+
expected_data = DatetimeHandler.replace_date_template_in_expected_data(self, expected_data_including_date_template)
|
|
149
147
|
#
|
|
150
148
|
if expected_data == -1:
|
|
151
149
|
difference_found = True
|
|
152
|
-
Report.
|
|
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.")
|
|
153
151
|
else:
|
|
154
152
|
if not fnmatch.fnmatch(actual_data[row_nr][column_nr], expected_data):
|
|
155
153
|
# No match despite using of wildcard(s).
|
|
156
154
|
difference_found = True
|
|
157
|
-
Report.
|
|
158
|
-
Report.
|
|
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.")
|
|
159
157
|
continue
|
|
160
158
|
#
|
|
161
159
|
elif "{NOT(" in expected_data_including_templates[row_nr][column_nr].upper():
|
|
@@ -165,18 +163,18 @@ class ArrayComparer:
|
|
|
165
163
|
if actual_data[row_nr][column_nr] == unwanted_expected_data:
|
|
166
164
|
# Unwanted match.
|
|
167
165
|
difference_found = True
|
|
168
|
-
Report.
|
|
169
|
-
Report.
|
|
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!!!")
|
|
170
168
|
except Exception as exception_message:
|
|
171
169
|
# print(f"An exception occurred: {exception_message}")
|
|
172
170
|
difference_found = True
|
|
173
|
-
Report.
|
|
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.")
|
|
174
172
|
#
|
|
175
173
|
else:
|
|
176
174
|
if not skip_exception_rule_used:
|
|
177
175
|
# No exceptions.
|
|
178
176
|
difference_found = True
|
|
179
|
-
Report.
|
|
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.")
|
|
180
178
|
#
|
|
181
179
|
if difference_found:
|
|
182
180
|
print("\n\n\n")
|
|
@@ -185,103 +183,7 @@ class ArrayComparer:
|
|
|
185
183
|
print("There are no differences between actual and expected data found.")
|
|
186
184
|
print("\n\n\n")
|
|
187
185
|
|
|
188
|
-
|
|
189
|
-
def __replace_date_template_in_expected_data(self, expected_data_field_including_date_template):
|
|
190
|
-
# Replace date_template in expected data.
|
|
191
|
-
# For example: This is text {NOW()-5Y2M1D:YYYY-MM-DD} and also text. => This is text 2018-05-03 and also text.
|
|
192
|
-
position_open_brace_today_text = expected_data_field_including_date_template.find("{NOW()")
|
|
193
|
-
position_close_brace_today_text = expected_data_field_including_date_template.find("}", position_open_brace_today_text)
|
|
194
|
-
#
|
|
195
|
-
if position_close_brace_today_text == -1:
|
|
196
|
-
return -1
|
|
197
|
-
# Close brace of TODAY has been found.
|
|
198
|
-
#
|
|
199
|
-
expected_datetime_template_string = expected_data_field_including_date_template[position_open_brace_today_text:position_close_brace_today_text + 1]
|
|
200
|
-
expected_datetime_string = ArrayComparer.__convert_datetime_template_to_datetime(self, expected_datetime_template_string)
|
|
201
|
-
#
|
|
202
|
-
if expected_datetime_string == -1:
|
|
203
|
-
return -1
|
|
204
|
-
# Datetime_template_string has been converted to datetime.
|
|
205
|
-
#
|
|
206
|
-
# Replace expected_datetime_template_string by expected_datetime_string in expected_data_field_including_template.
|
|
207
|
-
compiled = re.compile(re.escape(expected_datetime_template_string), re.IGNORECASE)
|
|
208
|
-
expected_data_with_calculated_date = compiled.sub(expected_datetime_string, expected_data_field_including_date_template)
|
|
209
|
-
#
|
|
210
|
-
return expected_data_with_calculated_date
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
def __convert_datetime_template_to_datetime(self, expected_datetime_format):
|
|
214
|
-
# Convert expected datetime template into datetime.
|
|
215
|
-
# For example: {NOW():YYYY-MM-DD} => 2023-07-04
|
|
216
|
-
# {NOW():MMDDYY} => 070423
|
|
217
|
-
# {NOW()-5Y3M1D:D-MMMM-YY} => 3-April-18
|
|
218
|
-
# {NOW()-5Y2M1D:YYYY-MMM-DD} => 2018-Apr-03
|
|
219
|
-
# {NOW()-5Y2M1D:YYYYMMDD} => 20180503
|
|
220
|
-
# {NOW()-5Y2M1D:YYYY-M-D} => 2018-5-3
|
|
221
|
-
# {NOW()+2D:DDMMYYYY => 06072023
|
|
222
|
-
# {NOW()-5Y2M1D:YYYY-MM-DD} => 2018-05-03
|
|
223
|
-
template_datetime_string_splitted = expected_datetime_format.split(":")
|
|
224
|
-
#
|
|
225
|
-
match len(template_datetime_string_splitted):
|
|
226
|
-
case 2:
|
|
227
|
-
if template_datetime_string_splitted[0] == "{NOW()":
|
|
228
|
-
# Current date time.
|
|
229
|
-
expected_datetime = datetime.datetime.now()
|
|
230
|
-
else:
|
|
231
|
-
# Adjust date time based on current date time.
|
|
232
|
-
relative_datetime_template_string = template_datetime_string_splitted[0].replace('{NOW()', '')
|
|
233
|
-
relative_datetime = ArrayComparer.__convert_relative_datetime_template_to_relative_datetime(self, relative_datetime_template_string[1:len(relative_datetime_template_string)])
|
|
234
|
-
if relative_datetime == -1:
|
|
235
|
-
return -1
|
|
236
|
-
else:
|
|
237
|
-
match relative_datetime_template_string[0]:
|
|
238
|
-
case "+":
|
|
239
|
-
expected_datetime = datetime.datetime.now() + relative_datetime
|
|
240
|
-
case "-":
|
|
241
|
-
expected_datetime = datetime.datetime.now() - relative_datetime
|
|
242
|
-
case _:
|
|
243
|
-
return -1
|
|
244
|
-
case _:
|
|
245
|
-
return -1
|
|
246
|
-
#
|
|
247
|
-
year = expected_datetime.strftime("%Y")
|
|
248
|
-
year_2_digits = expected_datetime.strftime("%y")
|
|
249
|
-
month = expected_datetime.strftime("%m")
|
|
250
|
-
month_abbreviated = expected_datetime.strftime("%b")
|
|
251
|
-
month_full = expected_datetime.strftime("%B")
|
|
252
|
-
day = expected_datetime.strftime("%d")
|
|
253
|
-
#
|
|
254
|
-
expected_date = template_datetime_string_splitted[1][0:len(template_datetime_string_splitted[1]) - 1].replace("YYYY", year).replace("YY", year_2_digits).replace("MMMM", month_full).replace("MMM", month_abbreviated).replace("MM", month).replace("M", month.lstrip("0")).replace("DD", day).replace("D", day.lstrip("0"))
|
|
255
|
-
return expected_date
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
def __convert_relative_datetime_template_to_relative_datetime(self, relative_datetime_str):
|
|
259
|
-
# Convert relative datetime template to relative datetime.
|
|
260
|
-
# For example: 2Y5M1D => 2 years, 5 months, 1 day (used to add to or subtract from current moment / date)
|
|
261
|
-
# \d+ means 1 of more digits; search on character - for example Y;
|
|
262
|
-
regex = re.compile(r'((?P<years>\d+?)Y)?((?P<months>\d+?)M)?((?P<days>\d+?)D)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
|
|
263
|
-
period = regex.match(relative_datetime_str)
|
|
264
|
-
|
|
265
|
-
if not period:
|
|
266
|
-
return -1
|
|
267
|
-
|
|
268
|
-
period = period.groupdict()
|
|
269
|
-
kwargs = {}
|
|
270
|
-
period_names = ["years", "months", "days"]
|
|
271
|
-
#
|
|
272
|
-
for name, param in period.items():
|
|
273
|
-
if param:
|
|
274
|
-
period_name = name
|
|
275
|
-
period_count = param
|
|
276
|
-
#
|
|
277
|
-
if period_name in period_names:
|
|
278
|
-
kwargs[period_name] = int(period_count)
|
|
279
|
-
#
|
|
280
|
-
if kwargs:
|
|
281
|
-
return dateutil.relativedelta.relativedelta(**kwargs)
|
|
282
|
-
else:
|
|
283
|
-
return -1
|
|
284
|
-
|
|
186
|
+
#Report().show_footer_comparation_result()
|
|
285
187
|
|
|
286
188
|
|
|
287
189
|
def __get_unwanted_expected_data(self, expected_data_field_including_date_template):
|
|
@@ -298,17 +200,7 @@ class ArrayComparer:
|
|
|
298
200
|
#
|
|
299
201
|
unwanted_expected_data = expected_data_field_including_date_template[position_open_brace+5:position_close_brace]
|
|
300
202
|
#
|
|
301
|
-
if
|
|
203
|
+
if Tools.is_integer(self, unwanted_expected_data):
|
|
302
204
|
unwanted_expected_data = int(unwanted_expected_data)
|
|
303
205
|
return unwanted_expected_data
|
|
304
206
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
def is_integer(self, string):
|
|
308
|
-
if string[0] == '-':
|
|
309
|
-
# if a negative number
|
|
310
|
-
return string[1:].isdigit()
|
|
311
|
-
else:
|
|
312
|
-
return string.isdigit()
|
|
313
|
-
|
|
314
|
-
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import dateutil.relativedelta
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
class DatetimeHandler:
|
|
6
|
+
def replace_date_template_in_expected_data(self, expected_data_field_including_date_template):
|
|
7
|
+
# Replace date_template in expected data.
|
|
8
|
+
# For example: This is text {NOW()-5Y2M1D:YYYY-MM-DD} and also text. => This is text 2018-05-03 and also text.
|
|
9
|
+
position_open_brace_today_text = expected_data_field_including_date_template.find("{NOW()")
|
|
10
|
+
position_close_brace_today_text = expected_data_field_including_date_template.find("}", position_open_brace_today_text)
|
|
11
|
+
#
|
|
12
|
+
if position_close_brace_today_text == -1:
|
|
13
|
+
return -1
|
|
14
|
+
# Close brace of TODAY has been found.
|
|
15
|
+
#
|
|
16
|
+
expected_datetime_template_string = expected_data_field_including_date_template[position_open_brace_today_text:position_close_brace_today_text + 1]
|
|
17
|
+
expected_datetime_string = DatetimeHandler.__convert_datetime_template_to_datetime(self, expected_datetime_template_string)
|
|
18
|
+
#
|
|
19
|
+
if expected_datetime_string == -1:
|
|
20
|
+
return -1
|
|
21
|
+
# Datetime_template_string has been converted to datetime.
|
|
22
|
+
#
|
|
23
|
+
# Replace expected_datetime_template_string by expected_datetime_string in expected_data_field_including_template.
|
|
24
|
+
compiled = re.compile(re.escape(expected_datetime_template_string), re.IGNORECASE)
|
|
25
|
+
expected_data_with_calculated_date = compiled.sub(expected_datetime_string, expected_data_field_including_date_template)
|
|
26
|
+
#
|
|
27
|
+
return expected_data_with_calculated_date
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def __convert_datetime_template_to_datetime(self, expected_datetime_format):
|
|
31
|
+
# Convert expected datetime template into datetime.
|
|
32
|
+
# For example: {NOW():YYYY-MM-DD} => 2023-07-04
|
|
33
|
+
# {NOW():MMDDYY} => 070423
|
|
34
|
+
# {NOW()-5Y3M1D:D-MMMM-YY} => 3-April-18
|
|
35
|
+
# {NOW()-5Y2M1D:YYYY-MMM-DD} => 2018-Apr-03
|
|
36
|
+
# {NOW()-5Y2M1D:YYYYMMDD} => 20180503
|
|
37
|
+
# {NOW()-5Y2M1D:YYYY-M-D} => 2018-5-3
|
|
38
|
+
# {NOW()+2D:DDMMYYYY => 06072023
|
|
39
|
+
# {NOW()-5Y2M1D:YYYY-MM-DD} => 2018-05-03
|
|
40
|
+
template_datetime_string_splitted = expected_datetime_format.split(":")
|
|
41
|
+
#
|
|
42
|
+
match len(template_datetime_string_splitted):
|
|
43
|
+
case 2:
|
|
44
|
+
if template_datetime_string_splitted[0] == "{NOW()":
|
|
45
|
+
# Current date time.
|
|
46
|
+
expected_datetime = datetime.datetime.now()
|
|
47
|
+
else:
|
|
48
|
+
# Adjust date time based on current date time.
|
|
49
|
+
relative_datetime_template_string = template_datetime_string_splitted[0].replace('{NOW()', '')
|
|
50
|
+
relative_datetime = DatetimeHandler.__convert_relative_datetime_template_to_relative_datetime(self, relative_datetime_template_string[1:len(relative_datetime_template_string)])
|
|
51
|
+
if relative_datetime == -1:
|
|
52
|
+
return -1
|
|
53
|
+
else:
|
|
54
|
+
match relative_datetime_template_string[0]:
|
|
55
|
+
case "+":
|
|
56
|
+
expected_datetime = datetime.datetime.now() + relative_datetime
|
|
57
|
+
case "-":
|
|
58
|
+
expected_datetime = datetime.datetime.now() - relative_datetime
|
|
59
|
+
case _:
|
|
60
|
+
return -1
|
|
61
|
+
case _:
|
|
62
|
+
return -1
|
|
63
|
+
#
|
|
64
|
+
year = expected_datetime.strftime("%Y")
|
|
65
|
+
year_2_digits = expected_datetime.strftime("%y")
|
|
66
|
+
month = expected_datetime.strftime("%m")
|
|
67
|
+
month_abbreviated = expected_datetime.strftime("%b")
|
|
68
|
+
month_full = expected_datetime.strftime("%B")
|
|
69
|
+
day = expected_datetime.strftime("%d")
|
|
70
|
+
#
|
|
71
|
+
expected_date = template_datetime_string_splitted[1][0:len(template_datetime_string_splitted[1]) - 1].replace("YYYY", year).replace("YY", year_2_digits).replace("MMMM", month_full).replace("MMM", month_abbreviated).replace("MM", month).replace("M", month.lstrip("0")).replace("DD", day).replace("D", day.lstrip("0"))
|
|
72
|
+
return expected_date
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def __convert_relative_datetime_template_to_relative_datetime(self, relative_datetime_str):
|
|
76
|
+
# Convert relative datetime template to relative datetime.
|
|
77
|
+
# For example: 2Y5M1D => 2 years, 5 months, 1 day (used to add to or subtract from current moment / date)
|
|
78
|
+
# \d+ means 1 of more digits; search on character - for example Y;
|
|
79
|
+
regex = re.compile(r'((?P<years>\d+?)Y)?((?P<months>\d+?)M)?((?P<days>\d+?)D)?((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?')
|
|
80
|
+
period = regex.match(relative_datetime_str)
|
|
81
|
+
|
|
82
|
+
if not period:
|
|
83
|
+
return -1
|
|
84
|
+
|
|
85
|
+
period = period.groupdict()
|
|
86
|
+
kwargs = {}
|
|
87
|
+
period_names = ["years", "months", "days"]
|
|
88
|
+
#
|
|
89
|
+
for name, param in period.items():
|
|
90
|
+
if param:
|
|
91
|
+
period_name = name
|
|
92
|
+
period_count = param
|
|
93
|
+
#
|
|
94
|
+
if period_name in period_names:
|
|
95
|
+
kwargs[period_name] = int(period_count)
|
|
96
|
+
#
|
|
97
|
+
if kwargs:
|
|
98
|
+
return dateutil.relativedelta.relativedelta(**kwargs)
|
|
99
|
+
else:
|
|
100
|
+
return -1
|
|
@@ -1,4 +1,29 @@
|
|
|
1
1
|
class Report:
|
|
2
|
+
def show_header_and_data(self, header, data):
|
|
3
|
+
Report.show_2d_array(self, header, data, 20)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def show_header_differences_actual_and_expected_data(self):
|
|
7
|
+
print()
|
|
8
|
+
print("=== Overview differences between actual and expected data")
|
|
9
|
+
print()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
#show_difference_between_actual_and_expected_data
|
|
13
|
+
def show_differences_comparation_result(self, row_number, column_number, actual_data, expected_data, error_message):
|
|
14
|
+
print("Row: ", row_number + 1, " Column: ", column_number + 1, " => Actual data: ", actual_data, " Expected data: ", expected_data, " Remark / Error message: ", error_message)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
#def show_footer(self, StatusMessage().difference):
|
|
18
|
+
def show_footer_comparation_result(self):
|
|
19
|
+
if StatusMessage().difference:
|
|
20
|
+
print("\n\n\n")
|
|
21
|
+
raise Exception("There is a difference between actual and expected data. See detail information.")
|
|
22
|
+
else:
|
|
23
|
+
print("There are no differences between actual and expected data found.")
|
|
24
|
+
print("\n\n\n")
|
|
25
|
+
|
|
26
|
+
|
|
2
27
|
def show_2d_array(self, title, reader_file_list, column_width):
|
|
3
28
|
max_length_title = 30
|
|
4
29
|
title = title[0:(max_length_title - 1)]
|
|
@@ -16,8 +41,4 @@ class Report:
|
|
|
16
41
|
|
|
17
42
|
print()
|
|
18
43
|
print()
|
|
19
|
-
print()
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def show_comparation_result(self, row_number, column_number, actual_data, expected_data, error_message):
|
|
23
|
-
print("Row: ", row_number + 1, " Column: ", column_number + 1, " => Actual data: ", actual_data, " Expected data: ", expected_data, " Remark / Error message: ", error_message)
|
|
44
|
+
print()
|
{datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: DataComparerLibrary
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.845
|
|
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
|
|
@@ -19,6 +19,14 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
19
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
20
|
Description-Content-Type: text/x-rst
|
|
21
21
|
License-File: LICENSE.txt
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: author-email
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: description
|
|
26
|
+
Dynamic: description-content-type
|
|
27
|
+
Dynamic: keywords
|
|
28
|
+
Dynamic: license
|
|
29
|
+
Dynamic: summary
|
|
22
30
|
|
|
23
31
|
===================
|
|
24
32
|
DataComparerLibrary
|
{datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/SOURCES.txt
RENAMED
|
@@ -6,6 +6,7 @@ src/DataComparerLibrary/__init__.py
|
|
|
6
6
|
src/DataComparerLibrary/arraycomparer.py
|
|
7
7
|
src/DataComparerLibrary/datacomparer.py
|
|
8
8
|
src/DataComparerLibrary/datasorter.py
|
|
9
|
+
src/DataComparerLibrary/datetimehandler.py
|
|
9
10
|
src/DataComparerLibrary/delimitertranslator.py
|
|
10
11
|
src/DataComparerLibrary/fileconverter.py
|
|
11
12
|
src/DataComparerLibrary/report.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/datacomparer.py
RENAMED
|
File without changes
|
{datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/datasorter.py
RENAMED
|
File without changes
|
|
File without changes
|
{datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/fileconverter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|