From 6e38305ccb414143fe15a7f0eee46310cf46b559 Mon Sep 17 00:00:00 2001 From: sujata-m Date: Wed, 2 Jul 2025 16:27:51 +0530 Subject: [PATCH] Fixed BUG-2065 - Fixed [BUG-2065](https://dev.azure.com/TDEI-UW/TDEI/_workitems/edit/2065/) - Added functionality to catch serialization errors - Added unit test cases for that - Added test file `test_serialization_error.zip` to test the serialization error --- CHANGELOG.md | 7 +++++++ src/python_osw_validation/__init__.py | 22 ++++++++++++++++++++-- src/python_osw_validation/version.py | 2 +- tests/assets/test_serialization_error.zip | Bin 0 -> 2580 bytes tests/unit_tests/test_osw_validation.py | 8 ++++++++ 5 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/assets/test_serialization_error.zip diff --git a/CHANGELOG.md b/CHANGELOG.md index e9d8c5a..7072305 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change log +### 0.2.11 + +- Fixed [BUG-2065](https://dev.azure.com/TDEI-UW/TDEI/_workitems/edit/2065/) +- Added functionality to catch serialization errors +- Added unit test cases for that +- Added test file `test_serialization_error.zip` to test the serialization error + ### 0.2.10 - Added limit the message error when u_id and v_id are missing diff --git a/src/python_osw_validation/__init__.py b/src/python_osw_validation/__init__.py index 46527e4..a88d156 100644 --- a/src/python_osw_validation/__init__.py +++ b/src/python_osw_validation/__init__.py @@ -161,12 +161,30 @@ def validate(self, max_errors=20) -> ValidationResult: # Validate OSW external extensions for file in validator.externalExtensions: file_path = os.path.join(file) + file_name = os.path.basename(file) extensionFile = gpd.read_file(file_path) invalid_geojson = extensionFile[extensionFile.is_valid == False] is_valid = len(invalid_geojson) == 0 if not is_valid: - self.errors.append( - f"Invalid geometries found in extension file {file}, list of invalid geometries: {invalid_geojson.to_json()}") + try: + # Safely extract invalid _id or fallback to index if _id is missing + invalid_ids = list(set(invalid_geojson.get('_id', invalid_geojson.index))) + num_invalid = len(invalid_ids) + limit = min(num_invalid, 20) + displayed_invalid = ', '.join(map(str, invalid_ids[:limit])) + self.errors.append( + f"Invalid geometries found in extension file `{file_name}`. Showing {limit if num_invalid > 20 else 'all'} of {num_invalid} invalid geometry IDs: {displayed_invalid}" + ) + except Exception as e: + self.errors.append(f"Invalid features found in `{file_name}`, but failed to extract IDs: {e}") + + # Optional: Test serializability of extension file + try: + for idx, row in extensionFile.drop(columns='geometry').iterrows(): + json.dumps(row.to_dict()) + except Exception as e: + self.errors.append(f"Extension file `{file_name}` has non-serializable properties: {e}") + break if self.errors: return ValidationResult(False, self.errors) diff --git a/src/python_osw_validation/version.py b/src/python_osw_validation/version.py index f0ca935..2418de5 100644 --- a/src/python_osw_validation/version.py +++ b/src/python_osw_validation/version.py @@ -1 +1 @@ -__version__ = '0.2.10' \ No newline at end of file +__version__ = '0.2.11' \ No newline at end of file diff --git a/tests/assets/test_serialization_error.zip b/tests/assets/test_serialization_error.zip new file mode 100644 index 0000000000000000000000000000000000000000..20f7a2730c771c1213e81b887dd895ba38129fdb GIT binary patch literal 2580 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 literal 0 HcmV?d00001 diff --git a/tests/unit_tests/test_osw_validation.py b/tests/unit_tests/test_osw_validation.py index 1095fe0..53be383 100644 --- a/tests/unit_tests/test_osw_validation.py +++ b/tests/unit_tests/test_osw_validation.py @@ -30,6 +30,7 @@ def setUp(self): self.invalid_zones_file = os.path.join(ASSETS_PATH, 'UW.zones.invalid.zip') self.valid_osw_file = os.path.join(ASSETS_PATH, 'wa.bellevue.zip') self.invalid_v_id_file = os.path.join(ASSETS_PATH, '4151.zip') + self.serialization_file = os.path.join(ASSETS_PATH, 'test_serialization_error.zip') self.schema_file_path = SCHEMA_FILE_PATH self.invalid_schema_file_path = INVALID_SCHEMA_FILE_PATH @@ -227,6 +228,13 @@ def test_invalid_zones_file(self): self.assertFalse(result.is_valid) self.assertIsNotNone(result.errors) + def test_invalid_serialization_file(self): + validation = OSWValidation(zipfile_path=self.serialization_file) + result = validation.validate() + self.assertFalse(result.is_valid) + self.assertIsNotNone(result.errors) + error_message = next((err for err in result.errors if 'non-serializable' in err.lower()), None) + def test_unmatched_ids_limited_to_20(self): validation = OSWValidation(zipfile_path=self.invalid_v_id_file) result = validation.validate()