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.
Files changed (22) hide show
  1. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/PKG-INFO +10 -2
  2. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/arraycomparer.py +27 -135
  3. datacomparerlibrary-0.845/src/DataComparerLibrary/datetimehandler.py +100 -0
  4. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/report.py +26 -5
  5. datacomparerlibrary-0.845/src/DataComparerLibrary/version.py +3 -0
  6. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/PKG-INFO +10 -2
  7. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/SOURCES.txt +1 -0
  8. datacomparerlibrary-0.844/src/DataComparerLibrary/version.py +0 -3
  9. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/LICENSE.txt +0 -0
  10. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/README.rst +0 -0
  11. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/pyproject.toml +0 -0
  12. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/setup.cfg +0 -0
  13. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/setup.py +0 -0
  14. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/__init__.py +0 -0
  15. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/datacomparer.py +0 -0
  16. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/datasorter.py +0 -0
  17. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/delimitertranslator.py +0 -0
  18. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/fileconverter.py +0 -0
  19. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary/tools.py +0 -0
  20. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/dependency_links.txt +0 -0
  21. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/src/DataComparerLibrary.egg-info/top_level.txt +0 -0
  22. {datacomparerlibrary-0.844 → datacomparerlibrary-0.845}/test/test1.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: DataComparerLibrary
3
- Version: 0.844
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
@@ -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 = number_of_rows_actual_data if (number_of_rows_actual_data >= number_of_rows_expected_data) else number_of_rows_expected_data
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
- print()
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.show_comparation_result(self, row_nr, 0, "", "", "Row actual data is not PRESENT. Row expected data is EMPTY.")
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.show_comparation_result(self, row_nr, 0, "", expected_data_including_templates[row_nr][0], "Row actual data is not PRESENT.")
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.show_comparation_result(self, row_nr, 0, "", "", "Row actual data is EMPTY. Row expected data is not PRESENT.")
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.show_comparation_result(self, row_nr, 0, actual_data[row_nr][0], "", "Row expected data is not PRESENT.")
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 = number_of_columns_actual_data if (number_of_columns_actual_data >= number_of_columns_expected_data) else number_of_columns_expected_data
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.show_comparation_result(self, row_nr, column_nr, "", expected_data_including_templates[row_nr][column_nr], "Column actual data is not PRESENT.")
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.show_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], "", "Column expected data is not PRESENT.")
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.show_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.")
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.show_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.")
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.show_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")
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.show_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")
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.show_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.")
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.show_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.")
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 = ArrayComparer.__replace_date_template_in_expected_data(self, expected_data_including_date_template)
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.show_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.")
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.show_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.")
158
- Report.show_comparation_result(self, row_nr, column_nr, actual_data[row_nr][column_nr], expected_data, "There is a difference between actual and expected data.")
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.show_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.")
169
- Report.show_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!!!")
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.show_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.")
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.show_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.")
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 ArrayComparer.is_integer(self, unwanted_expected_data):
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()
@@ -0,0 +1,3 @@
1
+ # encoding=utf-8
2
+
3
+ VERSION = '0.845'
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: DataComparerLibrary
3
- Version: 0.844
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
@@ -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
@@ -1,3 +0,0 @@
1
- # encoding=utf-8
2
-
3
- VERSION = '0.844'