From 47103d7f3d8fb2b45e7a178ec90acb60763f9d75 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Fri, 3 Nov 2023 15:43:57 +0100 Subject: [PATCH] Refactor Excel / wachete import, extend tests (#1931) --- changedetectionio/importer.py | 194 ++++++++++-------- .../tests/import/spreadsheet.xlsx | Bin 29444 -> 29544 bytes changedetectionio/tests/test_import.py | 18 +- 3 files changed, 122 insertions(+), 90 deletions(-) diff --git a/changedetectionio/importer.py b/changedetectionio/importer.py index 963482de..60e494e0 100644 --- a/changedetectionio/importer.py +++ b/changedetectionio/importer.py @@ -137,6 +137,7 @@ class import_distill_io_json(Importer): flash("{} Imported from Distill.io in {:.2f}s, {} Skipped.".format(len(self.new_uuids), time.time() - now, len(self.remaining_data))) + class import_xlsx_wachete(Importer): def run(self, @@ -144,6 +145,7 @@ class import_xlsx_wachete(Importer): flash, datastore, ): + good = 0 now = time.time() self.new_uuids = [] @@ -153,62 +155,67 @@ class import_xlsx_wachete(Importer): try: wb = load_workbook(data) except Exception as e: - #@todo correct except + # @todo correct except flash("Unable to read export XLSX file, something wrong with the file?", 'error') return - sheet_obj = wb.active + row_id = 2 + for row in wb.active.iter_rows(min_row=row_id): + try: + extras = {} + data = {} + for cell in row: + if not cell.value: + continue + column_title = wb.active.cell(row=1, column=cell.column).value.strip().lower() + data[column_title] = cell.value - i = 1 - row = 2 - while sheet_obj.cell(row=row, column=1).value: - data = {} - while sheet_obj.cell(row=row, column=i).value: - column_title = sheet_obj.cell(row=1, column=i).value.strip().lower() - column_row_value = sheet_obj.cell(row=row, column=i).value - data[column_title] = column_row_value + # Forced switch to webdriver/playwright/etc + dynamic_wachet = str(data.get('dynamic wachet')).strip().lower() # Convert bool to str to cover all cases + # libreoffice and others can have it as =FALSE() =TRUE(), or bool(true) + if 'true' in dynamic_wachet or dynamic_wachet == '1': + extras['fetch_backend'] = 'html_webdriver' - i += 1 + if data.get('xpath'): + # @todo split by || ? + extras['include_filters'] = [data.get('xpath')] + if data.get('name'): + extras['title'] = data.get('name').strip() + if data.get('interval (min)'): + minutes = int(data.get('interval (min)')) + hours, minutes = divmod(minutes, 60) + days, hours = divmod(hours, 24) + weeks, days = divmod(days, 7) + extras['time_between_check'] = {'weeks': weeks, 'days': days, 'hours': hours, 'minutes': minutes, 'seconds': 0} - extras = {} - if data.get('xpath'): - #@todo split by || ? - extras['include_filters'] = [data.get('xpath')] - if data.get('name'): - extras['title'] = [data.get('name').strip()] - if data.get('interval (min)'): - minutes = int(data.get('interval (min)')) - hours, minutes = divmod(minutes, 60) - days, hours = divmod(hours, 24) - weeks, days = divmod(days, 7) - extras['time_between_check'] = {'weeks': weeks, 'days': days, 'hours': hours, 'minutes': minutes, 'seconds': 0} - - - # At minimum a URL is required. - if data.get('url'): - try: - validate_url(data.get('url')) - except ValidationError as e: - print(">> import URL error", data.get('url'), str(e)) - # Don't bother processing anything else on this row - continue - - new_uuid = datastore.add_watch(url=data['url'].strip(), - extras=extras, - tag=data.get('folder'), - write_to_disk_now=False) - if new_uuid: - # Straight into the queue. - self.new_uuids.append(new_uuid) - good += 1 - - row += 1 - i = 1 + # At minimum a URL is required. + if data.get('url'): + try: + validate_url(data.get('url')) + except ValidationError as e: + print(">> import URL error", data.get('url'), str(e)) + flash(f"Error processing row number {row_id}, URL value was incorrect, row was skipped.", 'error') + # Don't bother processing anything else on this row + continue + new_uuid = datastore.add_watch(url=data['url'].strip(), + extras=extras, + tag=data.get('folder'), + write_to_disk_now=False) + if new_uuid: + # Straight into the queue. + self.new_uuids.append(new_uuid) + good += 1 + except Exception as e: + print(e) + flash(f"Error processing row number {row_id}, check all cell data types are correct, row was skipped.", 'error') + else: + row_id += 1 flash( "{} imported from Wachete .xlsx in {:.2f}s".format(len(self.new_uuids), time.time() - now)) + class import_xlsx_custom(Importer): def run(self, @@ -216,6 +223,7 @@ class import_xlsx_custom(Importer): flash, datastore, ): + good = 0 now = time.time() self.new_uuids = [] @@ -225,56 +233,68 @@ class import_xlsx_custom(Importer): try: wb = load_workbook(data) except Exception as e: - #@todo correct except + # @todo correct except flash("Unable to read export XLSX file, something wrong with the file?", 'error') return # @todo cehck atleast 2 rows, same in other method - - sheet_obj = wb.active from .forms import validate_url - row = 2 - while sheet_obj.cell(row=row, column=1).value: - url = None - tags = None - extras = {} - for col_i, cell_map in self.import_profile.items(): - cell_val = sheet_obj.cell(row=row, column=col_i).value - if cell_map == 'url': - url = cell_val.strip() - try: - validate_url(url) - except ValidationError as e: - print (">> Import URL error",url, str(e)) - # Don't bother processing anything else on this row - url = None - break + row_i = 1 - elif cell_map == 'tag': - tags = cell_val.strip() - elif cell_map == 'include_filters': - # @todo validate? - extras['include_filters'] = [cell_val.strip()] - elif cell_map == 'interval_minutes': - hours, minutes = divmod(int(cell_val), 60) - days, hours = divmod(hours, 24) - weeks, days = divmod(days, 7) - extras['time_between_check'] = {'weeks': weeks, 'days': days, 'hours': hours, 'minutes': minutes, 'seconds': 0} - else: - extras[cell_map] = cell_val.strip() + try: + for row in wb.active.iter_rows(): + url = None + tags = None + extras = {} - # At minimum a URL is required. - if url: - new_uuid = datastore.add_watch(url=url, - extras=extras, - tag=tags, - write_to_disk_now=False) - if new_uuid: - # Straight into the queue. - self.new_uuids.append(new_uuid) - good += 1 + for cell in row: + if not self.import_profile.get(cell.col_idx): + continue + if not cell.value: + continue - row += 1 + cell_map = self.import_profile.get(cell.col_idx) + + cell_val = str(cell.value).strip() # could be bool + + if cell_map == 'url': + url = cell.value.strip() + try: + validate_url(url) + except ValidationError as e: + print(">> Import URL error", url, str(e)) + flash(f"Error processing row number {row_i}, URL value was incorrect, row was skipped.", 'error') + # Don't bother processing anything else on this row + url = None + break + elif cell_map == 'tag': + tags = cell.value.strip() + elif cell_map == 'include_filters': + # @todo validate? + extras['include_filters'] = [cell.value.strip()] + elif cell_map == 'interval_minutes': + hours, minutes = divmod(int(cell_val), 60) + days, hours = divmod(hours, 24) + weeks, days = divmod(days, 7) + extras['time_between_check'] = {'weeks': weeks, 'days': days, 'hours': hours, 'minutes': minutes, 'seconds': 0} + else: + extras[cell_map] = cell_val + + # At minimum a URL is required. + if url: + new_uuid = datastore.add_watch(url=url, + extras=extras, + tag=tags, + write_to_disk_now=False) + if new_uuid: + # Straight into the queue. + self.new_uuids.append(new_uuid) + good += 1 + except Exception as e: + print(e) + flash(f"Error processing row number {row_i}, check all cell data types are correct, row was skipped.", 'error') + else: + row_i += 1 flash( "{} imported from custom .xlsx in {:.2f}s".format(len(self.new_uuids), time.time() - now)) diff --git a/changedetectionio/tests/import/spreadsheet.xlsx b/changedetectionio/tests/import/spreadsheet.xlsx index 600847b897dd564c4af1b59632e492b6bc697d5c..b7f33db26f2addeaa92bc81d6aa9070e7bd09555 100644 GIT binary patch delta 8563 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 Kn}_~>^?v{X`R9ND diff --git a/changedetectionio/tests/test_import.py b/changedetectionio/tests/test_import.py index 4772226c..e8c66726 100644 --- a/changedetectionio/tests/test_import.py +++ b/changedetectionio/tests/test_import.py @@ -127,6 +127,7 @@ def test_import_custom_xlsx(client, live_server): """Test can upload a excel spreadsheet and the watches are created correctly""" #live_server_setup(live_server) + dirname = os.path.dirname(__file__) filename = os.path.join(dirname, 'import/spreadsheet.xlsx') with open(filename, 'rb') as f: @@ -150,13 +151,14 @@ def test_import_custom_xlsx(client, live_server): follow_redirects=True, ) - assert b'2 imported from custom .xlsx' in res.data + assert b'3 imported from custom .xlsx' in res.data + # Because this row was actually just a header with no usable URL, we should get an error + assert b'Error processing row number 1' in res.data res = client.get( url_for("index") ) - assert b'Somesite results ABC' in res.data assert b'City news results' in res.data @@ -167,6 +169,9 @@ def test_import_custom_xlsx(client, live_server): assert filters[0] == '/html[1]/body[1]/div[4]/div[1]/div[1]/div[1]||//*[@id=\'content\']/div[3]/div[1]/div[1]||//*[@id=\'content\']/div[1]' assert watch.get('time_between_check') == {'weeks': 0, 'days': 1, 'hours': 6, 'minutes': 24, 'seconds': 0} + res = client.get(url_for("form_delete", uuid="all"), follow_redirects=True) + assert b'Deleted' in res.data + def test_import_watchete_xlsx(client, live_server): """Test can upload a excel spreadsheet and the watches are created correctly""" @@ -186,7 +191,7 @@ def test_import_watchete_xlsx(client, live_server): follow_redirects=True, ) - assert b'2 imported from Wachete .xlsx' in res.data + assert b'3 imported from Wachete .xlsx' in res.data res = client.get( url_for("index") @@ -201,3 +206,10 @@ def test_import_watchete_xlsx(client, live_server): filters = watch.get('include_filters') assert filters[0] == '/html[1]/body[1]/div[4]/div[1]/div[1]/div[1]||//*[@id=\'content\']/div[3]/div[1]/div[1]||//*[@id=\'content\']/div[1]' assert watch.get('time_between_check') == {'weeks': 0, 'days': 1, 'hours': 6, 'minutes': 24, 'seconds': 0} + assert watch.get('fetch_backend') == 'system' # always uses default + + if watch.get('title') == 'JS website': + assert watch.get('fetch_backend') == 'html_webdriver' # Has active 'dynamic wachet' + + res = client.get(url_for("form_delete", uuid="all"), follow_redirects=True) + assert b'Deleted' in res.data