-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
52 lines (40 loc) · 1.73 KB
/
utils.py
File metadata and controls
52 lines (40 loc) · 1.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from typing import Dict, Optional
from config import PROPERTY_TYPE_MAP
def format_address(address_info: Optional[Dict]) -> str:
"""Build a full address string from Redfin addressInfo object."""
if not address_info:
return ""
street = address_info.get("formattedStreetLine", "")
city = address_info.get("city", "")
state = address_info.get("state", "")
zip_code = address_info.get("zip", "")
city_state_zip = ", ".join(
p for p in [city, f"{state} {zip_code}".strip()] if p
)
if street and city_state_zip:
return f"{street}, {city_state_zip}"
return street or city_state_zip
def get_property_type(code: Optional[int]) -> str:
"""Map Redfin numeric property type code to readable string."""
if code is None:
return ""
return PROPERTY_TYPE_MAP.get(code, f"Unknown ({code})")
def get_coordinates(address_info: Optional[Dict]) -> tuple:
"""Extract lat/lon from nested Redfin addressInfo centroid structure."""
if not address_info:
return None, None
centroid = address_info.get("centroid", {}).get("centroid", {})
return centroid.get("latitude"), centroid.get("longitude")
def truncate_description(description: Optional[str], max_length: int = 500) -> str:
"""Truncate description to max_length for CSV readability."""
if not description:
return ""
if len(description) <= max_length:
return description
return description[:max_length] + "..."
def build_polygon_string(coords: list) -> str:
"""Build a polygon coordinate string from a list of [lon, lat] pairs.
Redfin expects: lon1 lat1,lon2 lat2,...,lon1 lat1 (closed polygon).
"""
parts = [f"{lon} {lat}" for lon, lat in coords]
return ",".join(parts)