diff --git a/homeharvest/utils.py b/homeharvest/utils.py index 5c2b142..ee57475 100644 --- a/homeharvest/utils.py +++ b/homeharvest/utils.py @@ -171,27 +171,31 @@ def validate_input(listing_type: str | list[str] | None) -> None: def validate_dates(date_from: str | None, date_to: str | None) -> None: - if isinstance(date_from, str) != isinstance(date_to, str): - raise InvalidDate("Both date_from and date_to must be provided together.") - - if date_from and date_to: - try: - # Use fromisoformat to accept both date and datetime strings + # Allow either date_from or date_to individually, or both together + try: + # Validate and parse date_from if provided + date_from_obj = None + if date_from: date_from_str = date_from.replace('Z', '+00:00') if date_from.endswith('Z') else date_from - date_to_str = date_to.replace('Z', '+00:00') if date_to.endswith('Z') else date_to - date_from_obj = datetime.fromisoformat(date_from_str) + + # Validate and parse date_to if provided + date_to_obj = None + if date_to: + date_to_str = date_to.replace('Z', '+00:00') if date_to.endswith('Z') else date_to date_to_obj = datetime.fromisoformat(date_to_str) - if date_to_obj < date_from_obj: - raise InvalidDate(f"date_to ('{date_to}') must be after date_from ('{date_from}').") - except ValueError as e: - # Provide specific guidance on the expected format - raise InvalidDate( - f"Invalid date format. Expected ISO 8601 format. " - f"Examples: '2025-01-20' (date only) or '2025-01-20T14:30:00' (with time). " - f"Got: date_from='{date_from}', date_to='{date_to}'. Error: {e}" - ) + # If both provided, ensure date_to is after date_from + if date_from_obj and date_to_obj and date_to_obj < date_from_obj: + raise InvalidDate(f"date_to ('{date_to}') must be after date_from ('{date_from}').") + + except ValueError as e: + # Provide specific guidance on the expected format + raise InvalidDate( + f"Invalid date format. Expected ISO 8601 format. " + f"Examples: '2025-01-20' (date only) or '2025-01-20T14:30:00' (with time). " + f"Got: date_from='{date_from}', date_to='{date_to}'. Error: {e}" + ) def validate_limit(limit: int) -> None: diff --git a/tests/test_realtor.py b/tests/test_realtor.py index c5fd493..bf334bc 100644 --- a/tests/test_realtor.py +++ b/tests/test_realtor.py @@ -169,7 +169,13 @@ def test_realtor_without_extra_details(): ), ] - assert not results[0].equals(results[1]) + # When extra_property_data=False, these fields should be None + extra_fields = ["nearby_schools", "assessed_value", "tax", "tax_history"] + + # Check that all extra fields are None when extra_property_data=False + for field in extra_fields: + if field in results[0].columns: + assert results[0][field].isna().all(), f"Field '{field}' should be None when extra_property_data=False" def test_pr_zip_code(): @@ -286,7 +292,7 @@ def test_return_type(): "pydantic": [scrape_property(location="Surprise, AZ", listing_type="for_rent", limit=100, return_type="pydantic")], "raw": [ scrape_property(location="Surprise, AZ", listing_type="for_rent", limit=100, return_type="raw"), - scrape_property(location="66642", listing_type="for_rent", limit=100, return_type="raw"), + scrape_property(location="85281", listing_type="for_rent", limit=100, return_type="raw"), ], } @@ -607,7 +613,7 @@ def test_past_hours_all_listing_types(): def test_datetime_filtering(): - """Test datetime_from and datetime_to parameters with hour precision""" + """Test date_from and date_to parameters with hour precision""" from datetime import datetime, timedelta # Get a recent date range (e.g., yesterday) @@ -618,28 +624,28 @@ def test_datetime_filtering(): result = scrape_property( location="Dallas, TX", listing_type="for_sale", - datetime_from=f"{date_str}T09:00:00", - datetime_to=f"{date_str}T17:00:00", + date_from=f"{date_str}T09:00:00", + date_to=f"{date_str}T17:00:00", limit=30 ) assert result is not None - # Test with only datetime_from + # Test with only date_from result_from_only = scrape_property( location="Houston, TX", listing_type="for_sale", - datetime_from=f"{date_str}T00:00:00", + date_from=f"{date_str}T00:00:00", limit=30 ) assert result_from_only is not None - # Test with only datetime_to + # Test with only date_to result_to_only = scrape_property( location="Austin, TX", listing_type="for_sale", - datetime_to=f"{date_str}T23:59:59", + date_to=f"{date_str}T23:59:59", limit=30 ) @@ -1106,8 +1112,10 @@ def test_last_status_change_date_field(): ) assert result_pending is not None - assert "last_status_change_date" in result_pending.columns, \ - "last_status_change_date column should be present in PENDING results" + # Only check columns if we have results (empty DataFrame has no columns) + if len(result_pending) > 0: + assert "last_status_change_date" in result_pending.columns, \ + "last_status_change_date column should be present in PENDING results" # Test 3: Field is present in FOR_SALE listings result_for_sale = scrape_property(