Ruff fixes
This commit is contained in:
@@ -5,6 +5,7 @@ Comprehensive tests for filter_deals_by_criteria function.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from nadlan_mcp.govmap.filters import filter_deals_by_criteria
|
||||
from nadlan_mcp.govmap.models import Deal, DealFilters
|
||||
|
||||
@@ -80,83 +81,79 @@ class TestFilterDealsByCriteria:
|
||||
result = filter_deals_by_criteria(sample_deals, property_type="דירה")
|
||||
# Should match "דירה" and "דירת גג" via substring match.
|
||||
assert len(result) == 3
|
||||
assert set(d.objectid for d in result) == {1, 2, 4}
|
||||
assert {d.objectid for d in result} == {1, 2, 4}
|
||||
|
||||
def test_filter_by_min_rooms(self, sample_deals):
|
||||
"""Test filtering by minimum rooms."""
|
||||
result = filter_deals_by_criteria(sample_deals, min_rooms=4.0)
|
||||
assert len(result) == 3
|
||||
assert set(d.objectid for d in result) == {2, 3, 5}
|
||||
assert {d.objectid for d in result} == {2, 3, 5}
|
||||
|
||||
def test_filter_by_max_rooms(self, sample_deals):
|
||||
"""Test filtering by maximum rooms."""
|
||||
result = filter_deals_by_criteria(sample_deals, max_rooms=3.0)
|
||||
assert len(result) == 2
|
||||
assert set(d.objectid for d in result) == {1, 4}
|
||||
assert {d.objectid for d in result} == {1, 4}
|
||||
|
||||
def test_filter_by_room_range(self, sample_deals):
|
||||
"""Test filtering by room range."""
|
||||
result = filter_deals_by_criteria(sample_deals, min_rooms=3.0, max_rooms=4.0)
|
||||
assert len(result) == 2
|
||||
assert set(d.objectid for d in result) == {1, 2}
|
||||
assert {d.objectid for d in result} == {1, 2}
|
||||
|
||||
def test_filter_by_min_price(self, sample_deals):
|
||||
"""Test filtering by minimum price."""
|
||||
result = filter_deals_by_criteria(sample_deals, min_price=1200000.0)
|
||||
assert len(result) == 3
|
||||
assert set(d.objectid for d in result) == {2, 3, 5}
|
||||
assert {d.objectid for d in result} == {2, 3, 5}
|
||||
|
||||
def test_filter_by_max_price(self, sample_deals):
|
||||
"""Test filtering by maximum price."""
|
||||
result = filter_deals_by_criteria(sample_deals, max_price=1000000.0)
|
||||
assert len(result) == 2
|
||||
assert set(d.objectid for d in result) == {1, 4}
|
||||
assert {d.objectid for d in result} == {1, 4}
|
||||
|
||||
def test_filter_by_price_range(self, sample_deals):
|
||||
"""Test filtering by price range."""
|
||||
result = filter_deals_by_criteria(
|
||||
sample_deals, min_price=1000000.0, max_price=1500000.0
|
||||
)
|
||||
result = filter_deals_by_criteria(sample_deals, min_price=1000000.0, max_price=1500000.0)
|
||||
assert len(result) == 3
|
||||
assert set(d.objectid for d in result) == {1, 2, 5}
|
||||
assert {d.objectid for d in result} == {1, 2, 5}
|
||||
|
||||
def test_filter_by_min_area(self, sample_deals):
|
||||
"""Test filtering by minimum area."""
|
||||
result = filter_deals_by_criteria(sample_deals, min_area=100.0)
|
||||
assert len(result) == 3
|
||||
assert set(d.objectid for d in result) == {2, 3, 5}
|
||||
assert {d.objectid for d in result} == {2, 3, 5}
|
||||
|
||||
def test_filter_by_max_area(self, sample_deals):
|
||||
"""Test filtering by maximum area."""
|
||||
result = filter_deals_by_criteria(sample_deals, max_area=80.0)
|
||||
assert len(result) == 2
|
||||
assert set(d.objectid for d in result) == {1, 4}
|
||||
assert {d.objectid for d in result} == {1, 4}
|
||||
|
||||
def test_filter_by_area_range(self, sample_deals):
|
||||
"""Test filtering by area range."""
|
||||
result = filter_deals_by_criteria(
|
||||
sample_deals, min_area=80.0, max_area=120.0
|
||||
)
|
||||
result = filter_deals_by_criteria(sample_deals, min_area=80.0, max_area=120.0)
|
||||
assert len(result) == 3
|
||||
assert set(d.objectid for d in result) == {1, 2, 5}
|
||||
assert {d.objectid for d in result} == {1, 2, 5}
|
||||
|
||||
def test_filter_by_min_floor(self, sample_deals):
|
||||
"""Test filtering by minimum floor."""
|
||||
result = filter_deals_by_criteria(sample_deals, min_floor=2)
|
||||
assert len(result) == 3
|
||||
assert set(d.objectid for d in result) == {1, 2, 5}
|
||||
assert {d.objectid for d in result} == {1, 2, 5}
|
||||
|
||||
def test_filter_by_max_floor(self, sample_deals):
|
||||
"""Test filtering by maximum floor."""
|
||||
result = filter_deals_by_criteria(sample_deals, max_floor=2)
|
||||
assert len(result) == 3
|
||||
assert set(d.objectid for d in result) == {1, 3, 4}
|
||||
assert {d.objectid for d in result} == {1, 3, 4}
|
||||
|
||||
def test_filter_by_floor_range(self, sample_deals):
|
||||
"""Test filtering by floor range."""
|
||||
result = filter_deals_by_criteria(sample_deals, min_floor=1, max_floor=5)
|
||||
assert len(result) == 3
|
||||
assert set(d.objectid for d in result) == {1, 2, 4}
|
||||
assert {d.objectid for d in result} == {1, 2, 4}
|
||||
|
||||
def test_combined_filters(self, sample_deals):
|
||||
"""Test combining multiple filters."""
|
||||
@@ -171,19 +168,17 @@ class TestFilterDealsByCriteria:
|
||||
# objectid=1: "דירה", 3 rooms, 1M price ✓
|
||||
# objectid=2: "דירת גג" (matches "דירה" variant), 4 rooms, 1.5M price ✓
|
||||
assert len(result) == 2
|
||||
assert set(d.objectid for d in result) == {1, 2}
|
||||
assert {d.objectid for d in result} == {1, 2}
|
||||
|
||||
def test_filter_using_dealfilters_model(self, sample_deals):
|
||||
"""Test filtering using DealFilters model."""
|
||||
filters = DealFilters(
|
||||
property_type="דירה", min_rooms=3.0, max_rooms=4.0
|
||||
)
|
||||
filters = DealFilters(property_type="דירה", min_rooms=3.0, max_rooms=4.0)
|
||||
result = filter_deals_by_criteria(sample_deals, filters=filters)
|
||||
# Should match objectid=1 and objectid=2
|
||||
# objectid=1: "דירה", 3 rooms ✓
|
||||
# objectid=2: "דירת גג" (matches "דירה" variant), 4 rooms ✓
|
||||
assert len(result) == 2
|
||||
assert set(d.objectid for d in result) == {1, 2}
|
||||
assert {d.objectid for d in result} == {1, 2}
|
||||
|
||||
def test_filter_using_dict(self, sample_deals):
|
||||
"""Test filtering using dict (converted to DealFilters)."""
|
||||
@@ -197,23 +192,35 @@ class TestFilterDealsByCriteria:
|
||||
# objectid=1: "דירה", 3 rooms ✓
|
||||
# objectid=2: "דירת גג" (matches "דירה" variant), 4 rooms ✓
|
||||
assert len(result) == 2
|
||||
assert set(d.objectid for d in result) == {1, 2}
|
||||
assert {d.objectid for d in result} == {1, 2}
|
||||
|
||||
def test_individual_params_override_filters_model(self, sample_deals):
|
||||
"""Test that individual parameters override filters model."""
|
||||
filters = DealFilters(min_rooms=5.0) # Would match only objectid=3
|
||||
result = filter_deals_by_criteria(
|
||||
sample_deals, filters=filters, min_rooms=3.0 # Override to 3.0
|
||||
sample_deals,
|
||||
filters=filters,
|
||||
min_rooms=3.0, # Override to 3.0
|
||||
)
|
||||
# Should use min_rooms=3.0, not 5.0
|
||||
assert len(result) == 4
|
||||
assert set(d.objectid for d in result) == {1, 2, 3, 5}
|
||||
assert {d.objectid for d in result} == {1, 2, 3, 5}
|
||||
|
||||
def test_filters_exclude_deals_with_missing_property_type(self):
|
||||
"""Test that deals with missing property_type are excluded when filter active."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000, deal_date="2024-01-01", property_type_description="דירה"),
|
||||
Deal(objectid=2, deal_amount=1000000, deal_date="2024-01-01", property_type_description=None),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000,
|
||||
deal_date="2024-01-01",
|
||||
property_type_description="דירה",
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1000000,
|
||||
deal_date="2024-01-01",
|
||||
property_type_description=None,
|
||||
),
|
||||
Deal(objectid=3, deal_amount=1000000, deal_date="2024-01-01"), # No property_type
|
||||
]
|
||||
result = filter_deals_by_criteria(deals, property_type="דירה")
|
||||
@@ -281,13 +288,17 @@ class TestFilterDealsByCriteria:
|
||||
"""Test floor filtering with Hebrew floor descriptions."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000, deal_date="2024-01-01", floor="קרקע"), # Ground=0
|
||||
Deal(objectid=2, deal_amount=1000000, deal_date="2024-01-01", floor="קומה 3"), # Floor 3
|
||||
Deal(objectid=3, deal_amount=1000000, deal_date="2024-01-01", floor="מרתף"), # Basement=-1
|
||||
Deal(
|
||||
objectid=2, deal_amount=1000000, deal_date="2024-01-01", floor="קומה 3"
|
||||
), # Floor 3
|
||||
Deal(
|
||||
objectid=3, deal_amount=1000000, deal_date="2024-01-01", floor="מרתף"
|
||||
), # Basement=-1
|
||||
]
|
||||
result = filter_deals_by_criteria(deals, min_floor=0)
|
||||
# Should match ground (0) and floor 3, but not basement (-1)
|
||||
assert len(result) == 2
|
||||
assert set(d.objectid for d in result) == {1, 2}
|
||||
assert {d.objectid for d in result} == {1, 2}
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"min_val,max_val,expected_count",
|
||||
|
||||
@@ -4,15 +4,17 @@ Tests for nadlan_mcp.govmap.market_analysis module.
|
||||
Comprehensive tests for market analysis functions.
|
||||
"""
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
from datetime import date, datetime, timedelta
|
||||
|
||||
from nadlan_mcp.govmap.market_analysis import (
|
||||
parse_deal_dates,
|
||||
calculate_market_activity_score,
|
||||
analyze_investment_potential,
|
||||
calculate_market_activity_score,
|
||||
get_market_liquidity,
|
||||
parse_deal_dates,
|
||||
)
|
||||
from nadlan_mcp.govmap.models import Deal, MarketActivityScore, InvestmentAnalysis, LiquidityMetrics
|
||||
from nadlan_mcp.govmap.models import Deal, InvestmentAnalysis, LiquidityMetrics, MarketActivityScore
|
||||
|
||||
|
||||
def get_recent_date(months_ago=0, days_ago=0):
|
||||
@@ -27,11 +29,36 @@ class TestParseDealDates:
|
||||
def sample_deals(self):
|
||||
"""Create sample deals spanning multiple months (recent dates)."""
|
||||
return [
|
||||
Deal(objectid=1, deal_amount=1000000, deal_date=get_recent_date(months_ago=4, days_ago=15), asset_area=80),
|
||||
Deal(objectid=2, deal_amount=1100000, deal_date=get_recent_date(months_ago=4, days_ago=10), asset_area=85),
|
||||
Deal(objectid=3, deal_amount=1200000, deal_date=get_recent_date(months_ago=3, days_ago=20), asset_area=90),
|
||||
Deal(objectid=4, deal_amount=1300000, deal_date=get_recent_date(months_ago=2, days_ago=25), asset_area=95),
|
||||
Deal(objectid=5, deal_amount=1400000, deal_date=get_recent_date(months_ago=1, days_ago=18), asset_area=100),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=4, days_ago=15),
|
||||
asset_area=80,
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1100000,
|
||||
deal_date=get_recent_date(months_ago=4, days_ago=10),
|
||||
asset_area=85,
|
||||
),
|
||||
Deal(
|
||||
objectid=3,
|
||||
deal_amount=1200000,
|
||||
deal_date=get_recent_date(months_ago=3, days_ago=20),
|
||||
asset_area=90,
|
||||
),
|
||||
Deal(
|
||||
objectid=4,
|
||||
deal_amount=1300000,
|
||||
deal_date=get_recent_date(months_ago=2, days_ago=25),
|
||||
asset_area=95,
|
||||
),
|
||||
Deal(
|
||||
objectid=5,
|
||||
deal_amount=1400000,
|
||||
deal_date=get_recent_date(months_ago=1, days_ago=18),
|
||||
asset_area=100,
|
||||
),
|
||||
]
|
||||
|
||||
def test_parse_deal_dates_basic(self, sample_deals):
|
||||
@@ -60,8 +87,18 @@ class TestParseDealDates:
|
||||
"""Test parsing with date objects instead of strings."""
|
||||
recent = datetime.now().date()
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000, deal_date=recent - timedelta(days=30), asset_area=80),
|
||||
Deal(objectid=2, deal_amount=1100000, deal_date=recent - timedelta(days=60), asset_area=85),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000,
|
||||
deal_date=recent - timedelta(days=30),
|
||||
asset_area=80,
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1100000,
|
||||
deal_date=recent - timedelta(days=60),
|
||||
asset_area=85,
|
||||
),
|
||||
]
|
||||
deal_dates, monthly, _ = parse_deal_dates(deals)
|
||||
|
||||
@@ -71,8 +108,18 @@ class TestParseDealDates:
|
||||
def test_parse_deal_dates_all_valid(self):
|
||||
"""Test that all valid dates are parsed."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000, deal_date=get_recent_date(months_ago=1), asset_area=80),
|
||||
Deal(objectid=2, deal_amount=1100000, deal_date=get_recent_date(months_ago=2), asset_area=85),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=1),
|
||||
asset_area=80,
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1100000,
|
||||
deal_date=get_recent_date(months_ago=2),
|
||||
asset_area=85,
|
||||
),
|
||||
]
|
||||
deal_dates, _, _ = parse_deal_dates(deals)
|
||||
assert len(deal_dates) == 2
|
||||
@@ -90,7 +137,12 @@ class TestCalculateMarketActivityScore:
|
||||
"""Test basic market activity calculation."""
|
||||
# Create 12 deals spread across last 12 months
|
||||
deals = [
|
||||
Deal(objectid=i, deal_amount=1000000, deal_date=get_recent_date(months_ago=i), asset_area=80)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=i),
|
||||
asset_area=80,
|
||||
)
|
||||
for i in range(12)
|
||||
]
|
||||
score = calculate_market_activity_score(deals, time_period_months=12)
|
||||
@@ -106,10 +158,15 @@ class TestCalculateMarketActivityScore:
|
||||
# Create 120 deals spread across last 10 months = ~12 deals/month (very high)
|
||||
deals = []
|
||||
for i in range(120):
|
||||
month_ago = (i % 10)
|
||||
month_ago = i % 10
|
||||
day = (i % 28) + 1
|
||||
deals.append(
|
||||
Deal(objectid=i, deal_amount=1000000, deal_date=get_recent_date(months_ago=month_ago, days_ago=day), asset_area=80)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=month_ago, days_ago=day),
|
||||
asset_area=80,
|
||||
)
|
||||
)
|
||||
score = calculate_market_activity_score(deals, time_period_months=12)
|
||||
|
||||
@@ -118,8 +175,18 @@ class TestCalculateMarketActivityScore:
|
||||
def test_market_activity_low_volume(self):
|
||||
"""Test activity score with low volume."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000, deal_date=get_recent_date(months_ago=1), asset_area=80),
|
||||
Deal(objectid=2, deal_amount=1100000, deal_date=get_recent_date(months_ago=6), asset_area=85),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=1),
|
||||
asset_area=80,
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1100000,
|
||||
deal_date=get_recent_date(months_ago=6),
|
||||
asset_area=85,
|
||||
),
|
||||
]
|
||||
score = calculate_market_activity_score(deals, time_period_months=12)
|
||||
|
||||
@@ -135,7 +202,12 @@ class TestCalculateMarketActivityScore:
|
||||
num_deals = i + 1 # Increasing: 1 deal earliest, 12 deals most recent
|
||||
for j in range(num_deals):
|
||||
deals.append(
|
||||
Deal(objectid=len(deals), deal_amount=1000000, deal_date=get_recent_date(months_ago=months_ago, days_ago=j), asset_area=80)
|
||||
Deal(
|
||||
objectid=len(deals),
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=months_ago, days_ago=j),
|
||||
asset_area=80,
|
||||
)
|
||||
)
|
||||
|
||||
score = calculate_market_activity_score(deals, time_period_months=12)
|
||||
@@ -150,7 +222,12 @@ class TestCalculateMarketActivityScore:
|
||||
num_deals = 12 - i # Decreasing: 12 deals earliest, 1 deal most recent
|
||||
for j in range(num_deals):
|
||||
deals.append(
|
||||
Deal(objectid=len(deals), deal_amount=1000000, deal_date=get_recent_date(months_ago=months_ago, days_ago=j), asset_area=80)
|
||||
Deal(
|
||||
objectid=len(deals),
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=months_ago, days_ago=j),
|
||||
asset_area=80,
|
||||
)
|
||||
)
|
||||
|
||||
score = calculate_market_activity_score(deals, time_period_months=12)
|
||||
@@ -160,7 +237,12 @@ class TestCalculateMarketActivityScore:
|
||||
"""Test trend detection - stable activity."""
|
||||
# Same number of deals each month
|
||||
deals = [
|
||||
Deal(objectid=i, deal_amount=1000000, deal_date=get_recent_date(months_ago=i), asset_area=80)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=i),
|
||||
asset_area=80,
|
||||
)
|
||||
for i in range(12)
|
||||
]
|
||||
score = calculate_market_activity_score(deals, time_period_months=12)
|
||||
@@ -171,8 +253,18 @@ class TestCalculateMarketActivityScore:
|
||||
def test_market_activity_insufficient_data_for_trend(self):
|
||||
"""Test trend with insufficient data."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000, deal_date=get_recent_date(months_ago=1), asset_area=80),
|
||||
Deal(objectid=2, deal_amount=1100000, deal_date=get_recent_date(months_ago=2), asset_area=85),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=1),
|
||||
asset_area=80,
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1100000,
|
||||
deal_date=get_recent_date(months_ago=2),
|
||||
asset_area=85,
|
||||
),
|
||||
]
|
||||
score = calculate_market_activity_score(deals, time_period_months=12)
|
||||
|
||||
@@ -198,7 +290,12 @@ class TestCalculateMarketActivityScore:
|
||||
month_ago = i % months
|
||||
day = (i // months) % 28
|
||||
deals.append(
|
||||
Deal(objectid=i, deal_amount=1000000, deal_date=get_recent_date(months_ago=month_ago, days_ago=day), asset_area=80)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=month_ago, days_ago=day),
|
||||
asset_area=80,
|
||||
)
|
||||
)
|
||||
score = calculate_market_activity_score(deals, time_period_months=12)
|
||||
|
||||
@@ -212,9 +309,15 @@ class TestAnalyzeInvestmentPotential:
|
||||
"""Test basic investment analysis."""
|
||||
# Create deals with increasing prices
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000, deal_date="2024-01-01", asset_area=100), # 10000/sqm
|
||||
Deal(objectid=2, deal_amount=1100000, deal_date="2024-02-01", asset_area=100), # 11000/sqm
|
||||
Deal(objectid=3, deal_amount=1200000, deal_date="2024-03-01", asset_area=100), # 12000/sqm
|
||||
Deal(
|
||||
objectid=1, deal_amount=1000000, deal_date="2024-01-01", asset_area=100
|
||||
), # 10000/sqm
|
||||
Deal(
|
||||
objectid=2, deal_amount=1100000, deal_date="2024-02-01", asset_area=100
|
||||
), # 11000/sqm
|
||||
Deal(
|
||||
objectid=3, deal_amount=1200000, deal_date="2024-03-01", asset_area=100
|
||||
), # 12000/sqm
|
||||
]
|
||||
analysis = analyze_investment_potential(deals)
|
||||
|
||||
@@ -253,7 +356,12 @@ class TestAnalyzeInvestmentPotential:
|
||||
"""Test volatility calculation with low volatility."""
|
||||
# Prices very similar
|
||||
deals = [
|
||||
Deal(objectid=i, deal_amount=1000000 + i*1000, deal_date=f"2024-{i+1:02d}-01", asset_area=100)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000 + i * 1000,
|
||||
deal_date=f"2024-{i + 1:02d}-01",
|
||||
asset_area=100,
|
||||
)
|
||||
for i in range(5)
|
||||
]
|
||||
analysis = analyze_investment_potential(deals)
|
||||
@@ -278,7 +386,12 @@ class TestAnalyzeInvestmentPotential:
|
||||
def test_investment_analysis_data_quality_excellent(self):
|
||||
"""Test data quality assessment with excellent data."""
|
||||
deals = [
|
||||
Deal(objectid=i, deal_amount=1000000, deal_date=f"2024-{(i%12)+1:02d}-01", asset_area=100)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000,
|
||||
deal_date=f"2024-{(i % 12) + 1:02d}-01",
|
||||
asset_area=100,
|
||||
)
|
||||
for i in range(25)
|
||||
]
|
||||
analysis = analyze_investment_potential(deals)
|
||||
@@ -334,7 +447,7 @@ class TestAnalyzeInvestmentPotential:
|
||||
def test_investment_analysis_price_trends(self, price_changes, expected_trend):
|
||||
"""Parametrized test for price trend detection."""
|
||||
deals = [
|
||||
Deal(objectid=i, deal_amount=price, deal_date=f"2024-{i+1:02d}-01", asset_area=100)
|
||||
Deal(objectid=i, deal_amount=price, deal_date=f"2024-{i + 1:02d}-01", asset_area=100)
|
||||
for i, price in enumerate(price_changes)
|
||||
]
|
||||
analysis = analyze_investment_potential(deals)
|
||||
@@ -348,7 +461,12 @@ class TestGetMarketLiquidity:
|
||||
def test_market_liquidity_basic(self):
|
||||
"""Test basic liquidity calculation."""
|
||||
deals = [
|
||||
Deal(objectid=i, deal_amount=1000000, deal_date=get_recent_date(months_ago=i), asset_area=80)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=i),
|
||||
asset_area=80,
|
||||
)
|
||||
for i in range(12)
|
||||
]
|
||||
liquidity = get_market_liquidity(deals, time_period_months=12)
|
||||
@@ -367,7 +485,12 @@ class TestGetMarketLiquidity:
|
||||
month_ago = i % 10
|
||||
day = (i % 28) + 1
|
||||
deals.append(
|
||||
Deal(objectid=i, deal_amount=1000000, deal_date=get_recent_date(months_ago=month_ago, days_ago=day), asset_area=80)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=month_ago, days_ago=day),
|
||||
asset_area=80,
|
||||
)
|
||||
)
|
||||
liquidity = get_market_liquidity(deals, time_period_months=12)
|
||||
|
||||
@@ -377,8 +500,18 @@ class TestGetMarketLiquidity:
|
||||
def test_market_liquidity_low(self):
|
||||
"""Test low liquidity."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000, deal_date=get_recent_date(months_ago=1), asset_area=80),
|
||||
Deal(objectid=2, deal_amount=1100000, deal_date=get_recent_date(months_ago=6), asset_area=85),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=1),
|
||||
asset_area=80,
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1100000,
|
||||
deal_date=get_recent_date(months_ago=6),
|
||||
asset_area=85,
|
||||
),
|
||||
]
|
||||
liquidity = get_market_liquidity(deals, time_period_months=12)
|
||||
|
||||
@@ -389,7 +522,12 @@ class TestGetMarketLiquidity:
|
||||
"""Test deal velocity calculation."""
|
||||
# 12 deals spread evenly across 12 months
|
||||
deals = [
|
||||
Deal(objectid=i, deal_amount=1000000, deal_date=get_recent_date(months_ago=i), asset_area=80)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=i),
|
||||
asset_area=80,
|
||||
)
|
||||
for i in range(12)
|
||||
]
|
||||
liquidity = get_market_liquidity(deals, time_period_months=12)
|
||||
@@ -420,7 +558,12 @@ class TestGetMarketLiquidity:
|
||||
month_ago = i % months
|
||||
day = (i // months) % 28
|
||||
deals.append(
|
||||
Deal(objectid=i, deal_amount=1000000, deal_date=get_recent_date(months_ago=month_ago, days_ago=day), asset_area=80)
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000,
|
||||
deal_date=get_recent_date(months_ago=month_ago, days_ago=day),
|
||||
asset_area=80,
|
||||
)
|
||||
)
|
||||
liquidity = get_market_liquidity(deals, time_period_months=12)
|
||||
|
||||
|
||||
+73
-126
@@ -5,21 +5,20 @@ This module tests all Pydantic model validation, serialization,
|
||||
and computed fields to ensure type safety and correctness.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from datetime import datetime
|
||||
from pydantic import ValidationError
|
||||
import pytest
|
||||
|
||||
from nadlan_mcp.govmap.models import (
|
||||
CoordinatePoint,
|
||||
Address,
|
||||
AutocompleteResult,
|
||||
AutocompleteResponse,
|
||||
AutocompleteResult,
|
||||
CoordinatePoint,
|
||||
Deal,
|
||||
DealFilters,
|
||||
DealStatistics,
|
||||
MarketActivityScore,
|
||||
InvestmentAnalysis,
|
||||
LiquidityMetrics,
|
||||
DealFilters,
|
||||
MarketActivityScore,
|
||||
)
|
||||
|
||||
|
||||
@@ -51,11 +50,7 @@ class TestAddress:
|
||||
"""Test creating valid address."""
|
||||
coord = CoordinatePoint(longitude=180000.0, latitude=650000.0)
|
||||
address = Address(
|
||||
text="סוקולוב 38 חולון",
|
||||
id="addr123",
|
||||
type="address",
|
||||
score=95.5,
|
||||
coordinates=coord
|
||||
text="סוקולוב 38 חולון", id="addr123", type="address", score=95.5, coordinates=coord
|
||||
)
|
||||
assert address.text == "סוקולוב 38 חולון"
|
||||
assert address.score == 95.5
|
||||
@@ -63,11 +58,7 @@ class TestAddress:
|
||||
|
||||
def test_address_without_coordinates(self):
|
||||
"""Test creating address without coordinates."""
|
||||
address = Address(
|
||||
text="סוקולוב 38 חולון",
|
||||
id="addr123",
|
||||
type="address"
|
||||
)
|
||||
address = Address(text="סוקולוב 38 חולון", id="addr123", type="address")
|
||||
assert address.coordinates is None
|
||||
assert address.score == 0 # Default value
|
||||
|
||||
@@ -84,7 +75,7 @@ class TestAutocompleteResult:
|
||||
type="city",
|
||||
score=100.0,
|
||||
coordinates=coord,
|
||||
shape="POINT(180000.0 650000.0)"
|
||||
shape="POINT(180000.0 650000.0)",
|
||||
)
|
||||
assert result.text == "חולון"
|
||||
assert result.coordinates.longitude == 180000.0
|
||||
@@ -92,11 +83,7 @@ class TestAutocompleteResult:
|
||||
|
||||
def test_result_without_shape(self):
|
||||
"""Test result without shape data."""
|
||||
result = AutocompleteResult(
|
||||
text="חולון",
|
||||
id="city123",
|
||||
type="city"
|
||||
)
|
||||
result = AutocompleteResult(text="חולון", id="city123", type="city")
|
||||
assert result.shape is None
|
||||
assert result.coordinates is None
|
||||
|
||||
@@ -108,7 +95,7 @@ class TestAutocompleteResponse:
|
||||
"""Test creating valid autocomplete response."""
|
||||
results = [
|
||||
AutocompleteResult(text="חולון", id="city1", type="city"),
|
||||
AutocompleteResult(text="חולון סוקולוב", id="street1", type="street")
|
||||
AutocompleteResult(text="חולון סוקולוב", id="street1", type="street"),
|
||||
]
|
||||
response = AutocompleteResponse(resultsCount=2, results=results)
|
||||
assert response.results_count == 2
|
||||
@@ -116,10 +103,7 @@ class TestAutocompleteResponse:
|
||||
|
||||
def test_response_with_alias(self):
|
||||
"""Test that camelCase alias works."""
|
||||
response = AutocompleteResponse.model_validate({
|
||||
"resultsCount": 5,
|
||||
"results": []
|
||||
})
|
||||
response = AutocompleteResponse.model_validate({"resultsCount": 5, "results": []})
|
||||
assert response.results_count == 5
|
||||
|
||||
def test_empty_response(self):
|
||||
@@ -143,7 +127,7 @@ class TestDeal:
|
||||
property_type_description="דירה",
|
||||
street_name="סוקולוב",
|
||||
house_number="38",
|
||||
rooms=3.5
|
||||
rooms=3.5,
|
||||
)
|
||||
assert deal.objectid == 12345
|
||||
assert deal.deal_amount == 1500000.0
|
||||
@@ -151,43 +135,31 @@ class TestDeal:
|
||||
|
||||
def test_deal_with_aliases(self):
|
||||
"""Test creating deal using API camelCase field names."""
|
||||
deal = Deal.model_validate({
|
||||
"objectid": 12345,
|
||||
"dealAmount": 1500000.0,
|
||||
"dealDate": "2024-01-15",
|
||||
"assetArea": 85.0,
|
||||
"propertyTypeDescription": "דירה"
|
||||
})
|
||||
deal = Deal.model_validate(
|
||||
{
|
||||
"objectid": 12345,
|
||||
"dealAmount": 1500000.0,
|
||||
"dealDate": "2024-01-15",
|
||||
"assetArea": 85.0,
|
||||
"propertyTypeDescription": "דירה",
|
||||
}
|
||||
)
|
||||
assert deal.deal_amount == 1500000.0
|
||||
assert deal.property_type_description == "דירה"
|
||||
|
||||
def test_deal_price_per_sqm_computed(self):
|
||||
"""Test price_per_sqm computed field."""
|
||||
deal = Deal(
|
||||
objectid=12345,
|
||||
deal_amount=1500000.0,
|
||||
deal_date="2024-01-15",
|
||||
asset_area=85.0
|
||||
)
|
||||
deal = Deal(objectid=12345, deal_amount=1500000.0, deal_date="2024-01-15", asset_area=85.0)
|
||||
assert deal.price_per_sqm == round(1500000.0 / 85.0, 2)
|
||||
|
||||
def test_deal_price_per_sqm_no_area(self):
|
||||
"""Test price_per_sqm returns None when area is missing."""
|
||||
deal = Deal(
|
||||
objectid=12345,
|
||||
deal_amount=1500000.0,
|
||||
deal_date="2024-01-15"
|
||||
)
|
||||
deal = Deal(objectid=12345, deal_amount=1500000.0, deal_date="2024-01-15")
|
||||
assert deal.price_per_sqm is None
|
||||
|
||||
def test_deal_price_per_sqm_zero_area(self):
|
||||
"""Test price_per_sqm returns None when area is zero."""
|
||||
deal = Deal(
|
||||
objectid=12345,
|
||||
deal_amount=1500000.0,
|
||||
deal_date="2024-01-15",
|
||||
asset_area=0.0
|
||||
)
|
||||
deal = Deal(objectid=12345, deal_amount=1500000.0, deal_date="2024-01-15", asset_area=0.0)
|
||||
assert deal.price_per_sqm is None
|
||||
|
||||
def test_deal_extra_fields_allowed(self):
|
||||
@@ -197,7 +169,7 @@ class TestDeal:
|
||||
"dealAmount": 1500000.0,
|
||||
"dealDate": "2024-01-15",
|
||||
"extra_field": "extra_value",
|
||||
"another_field": 123
|
||||
"another_field": 123,
|
||||
}
|
||||
deal = Deal.model_validate(deal_data)
|
||||
# Extra fields should be stored
|
||||
@@ -205,12 +177,7 @@ class TestDeal:
|
||||
|
||||
def test_deal_serialization(self):
|
||||
"""Test deal serialization to dict."""
|
||||
deal = Deal(
|
||||
objectid=12345,
|
||||
deal_amount=1500000.0,
|
||||
deal_date="2024-01-15",
|
||||
asset_area=85.0
|
||||
)
|
||||
deal = Deal(objectid=12345, deal_amount=1500000.0, deal_date="2024-01-15", asset_area=85.0)
|
||||
deal_dict = deal.model_dump()
|
||||
assert deal_dict["objectid"] == 12345
|
||||
assert deal_dict["deal_amount"] == 1500000.0
|
||||
@@ -218,11 +185,7 @@ class TestDeal:
|
||||
|
||||
def test_deal_serialization_exclude_none(self):
|
||||
"""Test deal serialization excluding None values."""
|
||||
deal = Deal(
|
||||
objectid=12345,
|
||||
deal_amount=1500000.0,
|
||||
deal_date="2024-01-15"
|
||||
)
|
||||
deal = Deal(objectid=12345, deal_amount=1500000.0, deal_date="2024-01-15")
|
||||
deal_dict = deal.model_dump(exclude_none=True)
|
||||
assert "asset_area" not in deal_dict
|
||||
assert "rooms" not in deal_dict
|
||||
@@ -240,28 +203,11 @@ class TestDealStatistics:
|
||||
"""Test creating valid deal statistics."""
|
||||
stats = DealStatistics(
|
||||
total_deals=100,
|
||||
price_statistics={
|
||||
"mean": 1500000.0,
|
||||
"median": 1400000.0,
|
||||
"std_dev": 200000.0
|
||||
},
|
||||
area_statistics={
|
||||
"mean": 85.5,
|
||||
"median": 82.0
|
||||
},
|
||||
price_per_sqm_statistics={
|
||||
"mean": 17500.0,
|
||||
"median": 17200.0
|
||||
},
|
||||
property_type_distribution={
|
||||
"דירה": 80,
|
||||
"דירת גן": 15,
|
||||
"פנטהאוז": 5
|
||||
},
|
||||
date_range={
|
||||
"earliest": "2022-01-01",
|
||||
"latest": "2024-12-31"
|
||||
}
|
||||
price_statistics={"mean": 1500000.0, "median": 1400000.0, "std_dev": 200000.0},
|
||||
area_statistics={"mean": 85.5, "median": 82.0},
|
||||
price_per_sqm_statistics={"mean": 17500.0, "median": 17200.0},
|
||||
property_type_distribution={"דירה": 80, "דירת גן": 15, "פנטהאוז": 5},
|
||||
date_range={"earliest": "2022-01-01", "latest": "2024-12-31"},
|
||||
)
|
||||
assert stats.total_deals == 100
|
||||
assert stats.price_statistics["mean"] == 1500000.0
|
||||
@@ -286,7 +232,7 @@ class TestMarketActivityScore:
|
||||
deals_per_month=10.0,
|
||||
trend="increasing",
|
||||
time_period_months=12,
|
||||
monthly_distribution={"2024-01": 8, "2024-02": 12}
|
||||
monthly_distribution={"2024-01": 8, "2024-02": 12},
|
||||
)
|
||||
assert score.activity_score == 75.5
|
||||
assert score.trend == "increasing"
|
||||
@@ -300,7 +246,7 @@ class TestMarketActivityScore:
|
||||
total_deals=100,
|
||||
deals_per_month=8.0,
|
||||
trend="stable",
|
||||
time_period_months=12
|
||||
time_period_months=12,
|
||||
)
|
||||
|
||||
with pytest.raises(ValidationError):
|
||||
@@ -309,7 +255,7 @@ class TestMarketActivityScore:
|
||||
total_deals=100,
|
||||
deals_per_month=8.0,
|
||||
trend="stable",
|
||||
time_period_months=12
|
||||
time_period_months=12,
|
||||
)
|
||||
|
||||
|
||||
@@ -327,7 +273,7 @@ class TestInvestmentAnalysis:
|
||||
avg_price_per_sqm=17500.0,
|
||||
price_change_pct=12.5,
|
||||
total_deals=85,
|
||||
data_quality="good"
|
||||
data_quality="good",
|
||||
)
|
||||
assert analysis.investment_score == 68.5
|
||||
assert analysis.price_trend == "increasing"
|
||||
@@ -345,7 +291,7 @@ class TestInvestmentAnalysis:
|
||||
avg_price_per_sqm=17000.0,
|
||||
price_change_pct=5.0,
|
||||
total_deals=100,
|
||||
data_quality="excellent"
|
||||
data_quality="excellent",
|
||||
)
|
||||
|
||||
|
||||
@@ -360,7 +306,7 @@ class TestLiquidityMetrics:
|
||||
time_period_months=12,
|
||||
avg_deals_per_month=12.5,
|
||||
deal_velocity=12.5,
|
||||
market_activity_level="high"
|
||||
market_activity_level="high",
|
||||
)
|
||||
assert metrics.liquidity_score == 82.3
|
||||
assert metrics.market_activity_level == "high"
|
||||
@@ -381,7 +327,7 @@ class TestDealFilters:
|
||||
min_area=60.0,
|
||||
max_area=100.0,
|
||||
min_floor=1,
|
||||
max_floor=5
|
||||
max_floor=5,
|
||||
)
|
||||
assert filters.property_type == "דירה"
|
||||
assert filters.min_rooms == 2.0
|
||||
@@ -425,45 +371,42 @@ class TestDealFilters:
|
||||
class TestModelIntegration:
|
||||
"""Integration tests for models working together."""
|
||||
|
||||
def test_deal_to_statistics_workflow(self):
|
||||
"""Test creating deals and calculating statistics."""
|
||||
# Import the function to test integration
|
||||
from nadlan_mcp.govmap.statistics import calculate_deal_statistics
|
||||
def test_deal_to_statistics_workflow(self):
|
||||
"""Test creating deals and calculating statistics."""
|
||||
# Import the function to test integration
|
||||
from nadlan_mcp.govmap.statistics import calculate_deal_statistics
|
||||
|
||||
deals = [
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000.0,
|
||||
deal_date="2024-01-01",
|
||||
asset_area=100.0,
|
||||
property_type_description="דירה"
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=2000000.0,
|
||||
deal_date="2024-01-02",
|
||||
asset_area=100.0,
|
||||
property_type_description="דירה"
|
||||
),
|
||||
]
|
||||
deals = [
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000.0,
|
||||
deal_date="2024-01-01",
|
||||
asset_area=100.0,
|
||||
property_type_description="דירה",
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=2000000.0,
|
||||
deal_date="2024-01-02",
|
||||
asset_area=100.0,
|
||||
property_type_description="דירה",
|
||||
),
|
||||
]
|
||||
|
||||
stats = calculate_deal_statistics(deals)
|
||||
stats = calculate_deal_statistics(deals)
|
||||
|
||||
assert isinstance(stats, DealStatistics)
|
||||
assert stats.total_deals == 2
|
||||
assert stats.price_statistics["mean"] == 1500000.0
|
||||
assert stats.price_per_sqm_statistics["mean"] == 15000.0
|
||||
assert stats.property_type_distribution["דירה"] == 2
|
||||
assert isinstance(stats, DealStatistics)
|
||||
assert stats.total_deals == 2
|
||||
assert stats.price_statistics["mean"] == 1500000.0
|
||||
assert stats.price_per_sqm_statistics["mean"] == 15000.0
|
||||
assert stats.property_type_distribution["דירה"] == 2
|
||||
|
||||
def test_autocomplete_to_deals_workflow(self):
|
||||
"""Test autocomplete response leading to deal search."""
|
||||
# Simulate autocomplete response
|
||||
coord = CoordinatePoint(longitude=180000.0, latitude=650000.0)
|
||||
result = AutocompleteResult(
|
||||
text="סוקולוב 38 חולון",
|
||||
id="addr123",
|
||||
type="address",
|
||||
coordinates=coord
|
||||
text="סוקולוב 38 חולון", id="addr123", type="address", coordinates=coord
|
||||
)
|
||||
response = AutocompleteResponse(resultsCount=1, results=[result])
|
||||
|
||||
@@ -478,14 +421,18 @@ class TestModelIntegration:
|
||||
min_rooms=3.0,
|
||||
max_rooms=4.0,
|
||||
min_price=1000000.0,
|
||||
max_price=2000000.0
|
||||
max_price=2000000.0,
|
||||
)
|
||||
|
||||
# Create test deals
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1200000.0, deal_date="2024-01-01", rooms=3.0),
|
||||
Deal(objectid=2, deal_amount=2500000.0, deal_date="2024-01-02", rooms=4.0), # Price too high
|
||||
Deal(objectid=3, deal_amount=1500000.0, deal_date="2024-01-03", rooms=2.0), # Too few rooms
|
||||
Deal(
|
||||
objectid=2, deal_amount=2500000.0, deal_date="2024-01-02", rooms=4.0
|
||||
), # Price too high
|
||||
Deal(
|
||||
objectid=3, deal_amount=1500000.0, deal_date="2024-01-03", rooms=2.0
|
||||
), # Too few rooms
|
||||
]
|
||||
|
||||
# Manually check which deals would pass
|
||||
|
||||
@@ -4,10 +4,12 @@ Tests for nadlan_mcp.govmap.statistics module.
|
||||
Comprehensive tests for statistical calculation functions.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from datetime import date
|
||||
from nadlan_mcp.govmap.statistics import calculate_deal_statistics, calculate_std_dev
|
||||
|
||||
import pytest
|
||||
|
||||
from nadlan_mcp.govmap.models import Deal, DealStatistics
|
||||
from nadlan_mcp.govmap.statistics import calculate_deal_statistics, calculate_std_dev
|
||||
|
||||
|
||||
class TestCalculateDealStatistics:
|
||||
@@ -135,8 +137,12 @@ class TestCalculateDealStatistics:
|
||||
"""Test statistics when some deals have zero prices."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000.0, deal_date="2024-01-01", asset_area=80.0),
|
||||
Deal(objectid=2, deal_amount=0.0, deal_date="2024-01-02", asset_area=100.0), # Zero price excluded
|
||||
Deal(objectid=3, deal_amount=-1.0, deal_date="2024-01-03", asset_area=120.0), # Negative excluded
|
||||
Deal(
|
||||
objectid=2, deal_amount=0.0, deal_date="2024-01-02", asset_area=100.0
|
||||
), # Zero price excluded
|
||||
Deal(
|
||||
objectid=3, deal_amount=-1.0, deal_date="2024-01-03", asset_area=120.0
|
||||
), # Negative excluded
|
||||
]
|
||||
stats = calculate_deal_statistics(deals)
|
||||
|
||||
@@ -161,8 +167,18 @@ class TestCalculateDealStatistics:
|
||||
def test_deals_with_missing_property_types(self):
|
||||
"""Test statistics when some deals have missing property types."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000.0, deal_date="2024-01-01", property_type_description="דירה"),
|
||||
Deal(objectid=2, deal_amount=1500000.0, deal_date="2024-01-02", property_type_description=None),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000.0,
|
||||
deal_date="2024-01-01",
|
||||
property_type_description="דירה",
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1500000.0,
|
||||
deal_date="2024-01-02",
|
||||
property_type_description=None,
|
||||
),
|
||||
Deal(objectid=3, deal_amount=2000000.0, deal_date="2024-01-03"), # No property_type
|
||||
]
|
||||
stats = calculate_deal_statistics(deals)
|
||||
@@ -196,7 +212,13 @@ class TestCalculateDealStatistics:
|
||||
def test_single_deal(self):
|
||||
"""Test statistics with single deal."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000.0, deal_date="2024-01-01", asset_area=80.0, property_type_description="דירה")
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000.0,
|
||||
deal_date="2024-01-01",
|
||||
asset_area=80.0,
|
||||
property_type_description="דירה",
|
||||
)
|
||||
]
|
||||
stats = calculate_deal_statistics(deals)
|
||||
|
||||
@@ -238,8 +260,18 @@ class TestCalculateDealStatistics:
|
||||
def test_date_handling_with_iso_strings(self):
|
||||
"""Test date range calculation with ISO format strings."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000.0, deal_date="2024-01-15T00:00:00.000Z", asset_area=80.0),
|
||||
Deal(objectid=2, deal_amount=1500000.0, deal_date="2024-02-01T12:30:45.123Z", asset_area=100.0),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000.0,
|
||||
deal_date="2024-01-15T00:00:00.000Z",
|
||||
asset_area=80.0,
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1500000.0,
|
||||
deal_date="2024-02-01T12:30:45.123Z",
|
||||
asset_area=100.0,
|
||||
),
|
||||
]
|
||||
stats = calculate_deal_statistics(deals)
|
||||
|
||||
@@ -250,9 +282,24 @@ class TestCalculateDealStatistics:
|
||||
def test_multiple_same_property_types(self):
|
||||
"""Test property type distribution with duplicates."""
|
||||
deals = [
|
||||
Deal(objectid=1, deal_amount=1000000.0, deal_date="2024-01-01", property_type_description="דירה"),
|
||||
Deal(objectid=2, deal_amount=1500000.0, deal_date="2024-01-02", property_type_description="דירה"),
|
||||
Deal(objectid=3, deal_amount=2000000.0, deal_date="2024-01-03", property_type_description="דירה"),
|
||||
Deal(
|
||||
objectid=1,
|
||||
deal_amount=1000000.0,
|
||||
deal_date="2024-01-01",
|
||||
property_type_description="דירה",
|
||||
),
|
||||
Deal(
|
||||
objectid=2,
|
||||
deal_amount=1500000.0,
|
||||
deal_date="2024-01-02",
|
||||
property_type_description="דירה",
|
||||
),
|
||||
Deal(
|
||||
objectid=3,
|
||||
deal_amount=2000000.0,
|
||||
deal_date="2024-01-03",
|
||||
property_type_description="דירה",
|
||||
),
|
||||
]
|
||||
stats = calculate_deal_statistics(deals)
|
||||
|
||||
@@ -289,7 +336,7 @@ class TestCalculateDealStatistics:
|
||||
Deal(
|
||||
objectid=i,
|
||||
deal_amount=1000000.0 if has_price else 0.0, # Use 0.0 instead of None
|
||||
deal_date=f"2024-01-{i+1:02d}",
|
||||
deal_date=f"2024-01-{i + 1:02d}",
|
||||
asset_area=80.0 if has_area else None,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -4,11 +4,10 @@ Unit tests for utils module.
|
||||
Tests helper utilities including distance calculation, address matching, and floor parsing.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from nadlan_mcp.govmap.utils import (
|
||||
calculate_distance,
|
||||
is_same_building,
|
||||
extract_floor_number,
|
||||
is_same_building,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@ Tests input validation functions for addresses, coordinates, integers, and deal
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from nadlan_mcp.govmap.validators import (
|
||||
validate_address,
|
||||
validate_coordinates,
|
||||
validate_positive_int,
|
||||
validate_deal_type,
|
||||
validate_positive_int,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user