From be8eee6aa0d68510901a4ea971f5535a41160e1d Mon Sep 17 00:00:00 2001 From: Jens Bergmann <1742418+1cu@users.noreply.github.com> Date: Mon, 3 Feb 2025 10:20:35 +0100 Subject: [PATCH] fix: Handle None values in calculate_content_hash - Add test case to reproduce TypeError with None values - Fix handling of None values in special_attributes, shipping_options and images - Ensure consistent empty value handling (empty string instead of 'None') - Fixes #395 --- src/kleinanzeigen_bot/utils.py | 8 ++++---- tests/test_utils.py | 23 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/kleinanzeigen_bot/utils.py b/src/kleinanzeigen_bot/utils.py index e177ef6..7703d3f 100644 --- a/src/kleinanzeigen_bot/utils.py +++ b/src/kleinanzeigen_bot/utils.py @@ -347,15 +347,15 @@ def calculate_content_hash(ad_cfg: dict[str, Any]) -> str: "category": str(ad_cfg.get("category", "")), "price": str(ad_cfg.get("price", "")), # Price always as string "price_type": str(ad_cfg.get("price_type", "")), - "special_attributes": dict(ad_cfg.get("special_attributes", {})), # Copy the dict + "special_attributes": dict(ad_cfg.get("special_attributes") or {}), # Handle None case "shipping_type": str(ad_cfg.get("shipping_type", "")), "shipping_costs": str(ad_cfg.get("shipping_costs", "")), - "shipping_options": sorted([str(x) for x in (ad_cfg.get("shipping_options") or [])]), # Convert to list and sort + "shipping_options": sorted([str(x) for x in (ad_cfg.get("shipping_options") or [])]), # Handle None case "sell_directly": bool(ad_cfg.get("sell_directly", False)), # Explicitly convert to bool - "images": sorted([os.path.basename(img) if isinstance(img, str) else str(img) for img in ad_cfg.get("images", [])]), # Only filenames + "images": sorted([os.path.basename(str(img)) if img is not None else "" for img in (ad_cfg.get("images") or [])]), # Handle None values in images "contact": { "name": str(ad_cfg.get("contact", {}).get("name", "")), - "street": str(ad_cfg.get("contact", {}).get("street", "None")), # Explicitly "None" as string for None values + "street": str(ad_cfg.get("contact", {}).get("street", "")), # Changed from "None" to empty string for consistency "zipcode": str(ad_cfg.get("contact", {}).get("zipcode", "")), "phone": str(ad_cfg.get("contact", {}).get("phone", "")) } diff --git a/tests/test_utils.py b/tests/test_utils.py index 0931b3c..bd5ab2b 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -28,3 +28,26 @@ def test_ensure() -> None: with pytest.raises(AssertionError): utils.ensure(lambda: False, "FALSE", timeout = 2) + + +def test_calculate_content_hash_with_none_values() -> None: + """Test calculate_content_hash with None values in the ad configuration.""" + ad_cfg = { + # Minimale Konfiguration mit None-Werten wie im Bug-Report beschrieben + "id": "123456789", + "created_on": "2022-07-19T07:30:20.489289", + "updated_on": "2025-01-22T19:46:46.735896", + "title": "Test Anzeige", + "description": "Test Beschreibung", + "images": [None, "/path/to/image.jpg", None], # None-Werte in der images Liste + "shipping_options": None, # None statt Liste + "special_attributes": None, # None statt Dictionary + "contact": { + "street": None # None-Wert in contact + } + } + + # Sollte keinen TypeError werfen + hash_value = utils.calculate_content_hash(ad_cfg) + assert isinstance(hash_value, str) + assert len(hash_value) == 64 # SHA-256 Hash ist 64 Zeichen lang