fix: Update import paths to use 'apps' prefix for models and services

This commit is contained in:
pacnpal
2025-09-28 10:50:57 -04:00
parent 1b246eeaa4
commit bf04e4d854
6 changed files with 395 additions and 363 deletions

View File

@@ -5,8 +5,8 @@ This script demonstrates real-world scenarios for using the OSM Road Trip Servic
in the ThrillWiki application. in the ThrillWiki application.
""" """
from parks.models import Park from apps.parks.models import Park
from parks.services import RoadTripService from apps.parks.services import RoadTripService
import os import os
import django import django
@@ -14,350 +14,378 @@ import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings")
django.setup() django.setup()
# New small helpers and constant to simplify functions and avoid repeated literals
MAGIC_KINGDOM = "Magic Kingdom"
def _format_coords(coords):
"""
Return (lat, lon) tuple or None for a coords object/sequence.
Accepts objects with .latitude/.longitude or indexable (lat, lon).
"""
if not coords:
return None
lat = getattr(coords, "latitude", None)
lon = getattr(coords, "longitude", None)
if lat is not None and lon is not None:
return (lat, lon)
# Fallback to indexable
try:
return (coords[0], coords[1])
except Exception:
return None
def _print_route_summary(route, indent=" "):
"""Safely print route summary fields if route is present."""
if not route:
return
# Use attributes with fallback to dict keys if needed
formatted_distance = getattr(route, "formatted_distance", None) or route.get(
"formatted_distance", "N/A"
) if isinstance(route, dict) else getattr(route, "formatted_distance", "N/A")
formatted_duration = getattr(route, "formatted_duration", None) or route.get(
"formatted_duration", "N/A"
) if isinstance(route, dict) else getattr(route, "formatted_duration", "N/A")
print(f"{indent}{formatted_distance}, {formatted_duration}")
def demo_florida_theme_park_trip(): def demo_florida_theme_park_trip():
""" """
Demonstrate planning a Florida theme park road trip. Demonstrate planning a Florida theme park road trip.
""" """
print("🏖️ Florida Theme Park Road Trip Planner") print("🏖️ Florida Theme Park Road Trip Planner")
print("=" * 50) print("=" * 50)
service = RoadTripService() service = RoadTripService()
# Define Florida theme parks with addresses # Define Florida theme parks with addresses
florida_parks = [ florida_parks = [
("Magic Kingdom", "Magic Kingdom Dr, Orlando, FL 32830"), (MAGIC_KINGDOM, "Magic Kingdom Dr, Orlando, FL 32830"),
( ("Universal Studios Florida", "6000 Universal Blvd, Orlando, FL 32819"),
"Universal Studios Florida", ("SeaWorld Orlando", "7007 Sea World Dr, Orlando, FL 32821"),
"6000 Universal Blvd, Orlando, FL 32819", ("Busch Gardens Tampa", "10165 McKinley Dr, Tampa, FL 33612"),
), ]
("SeaWorld Orlando", "7007 Sea World Dr, Orlando, FL 32821"),
("Busch Gardens Tampa", "10165 McKinley Dr, Tampa, FL 33612"),
]
print("Planning trip for these Florida parks:") print("Planning trip for these Florida parks:")
park_coords = {} park_coords = {}
for name, address in florida_parks: # small helper to geocode and store
print(f"\n📍 Geocoding {name}...") def _geocode_and_store(name, address):
coords = service.geocode_address(address) print(f"\n📍 Geocoding {name}...")
if coords: coords = service.geocode_address(address)
park_coords[name] = coords if coords:
print( latlon = _format_coords(coords)
f" ✅ Located at { if latlon:
coords.latitude:.4f}, { park_coords[name] = coords
coords.longitude:.4f}" print(f" ✅ Located at {latlon[0]:.4f}, {latlon[1]:.4f}")
) return True
else: print(f" ❌ Could not geocode {address}")
print(f" ❌ Could not geocode {address}") return False
if len(park_coords) < 2: for name, address in florida_parks:
print("❌ Need at least 2 parks to plan a trip") _geocode_and_store(name, address)
return
# Calculate distances between all parks if len(park_coords) < 2:
print("\n🗺️ Distance Matrix:") print("❌ Need at least 2 parks to plan a trip")
park_names = list(park_coords.keys()) return
for i, park1 in enumerate(park_names): # Calculate distances between all parks
for j, park2 in enumerate(park_names): print("\n🗺️ Distance Matrix:")
if i < j: # Only calculate each pair once park_names = list(park_coords.keys())
route = service.calculate_route(park_coords[park1], park_coords[park2])
if route:
print(f" {park1}{park2}")
print(
f" {
route.formatted_distance}, {
route.formatted_duration}"
)
# Find central park for radiating searches for i, park1 in enumerate(park_names):
print("\n🎢 Parks within 100km of Magic Kingdom:") for j, park2 in enumerate(park_names):
magic_kingdom_coords = park_coords.get("Magic Kingdom") if i < j: # Only calculate each pair once
if magic_kingdom_coords: route = service.calculate_route(park_coords[park1], park_coords[park2])
for name, coords in park_coords.items(): if route:
if name != "Magic Kingdom": print(f" {park1}{park2}")
route = service.calculate_route(magic_kingdom_coords, coords) _print_route_summary(route, indent=" ")
if route:
print( # Find central park for radiating searches
f" {name}: { print(f"\n🎢 Parks within 100km of {MAGIC_KINGDOM}:")
route.formatted_distance} ({ magic_kingdom_coords = park_coords.get(MAGIC_KINGDOM)
route.formatted_duration})" if magic_kingdom_coords:
) for name, coords in park_coords.items():
if name != MAGIC_KINGDOM:
route = service.calculate_route(magic_kingdom_coords, coords)
if route:
_print_route_summary(route, indent=f" {name}: ")
def demo_cross_country_road_trip(): def demo_cross_country_road_trip():
""" """
Demonstrate planning a cross-country theme park road trip. Demonstrate planning a cross-country theme park road trip.
""" """
print("\n\n🇺🇸 Cross-Country Theme Park Road Trip") print("\n\n🇺🇸 Cross-Country Theme Park Road Trip")
print("=" * 50) print("=" * 50)
service = RoadTripService() service = RoadTripService()
# Major theme parks across the US # Major theme parks across the US
major_parks = [ major_parks = [
("Disneyland", "1313 Disneyland Dr, Anaheim, CA 92802"), ("Disneyland", "1313 Disneyland Dr, Anaheim, CA 92802"),
("Cedar Point", "1 Cedar Point Dr, Sandusky, OH 44870"), ("Cedar Point", "1 Cedar Point Dr, Sandusky, OH 44870"),
( ("Six Flags Magic Mountain", "26101 Magic Mountain Pkwy, Valencia, CA 91355"),
"Six Flags Magic Mountain", ("Walt Disney World", "Walt Disney World Resort, Orlando, FL 32830"),
"26101 Magic Mountain Pkwy, Valencia, CA 91355", ]
),
("Walt Disney World", "Walt Disney World Resort, Orlando, FL 32830"),
]
print("Geocoding major US theme parks:") print("Geocoding major US theme parks:")
park_coords = {} park_coords = {}
for name, address in major_parks: for name, address in major_parks:
print(f"\n📍 {name}...") print(f"\n📍 {name}...")
coords = service.geocode_address(address) coords = service.geocode_address(address)
if coords: if coords:
park_coords[name] = coords park_coords[name] = coords
print(f"{coords.latitude:.4f}, {coords.longitude:.4f}") latlon = _format_coords(coords)
if latlon:
print(f"{latlon[0]:.4f}, {latlon[1]:.4f}")
if len(park_coords) >= 3: if len(park_coords) >= 3:
# Calculate an optimized route if we have DB parks # Calculate an optimized route if we have DB parks
print("\n🛣️ Optimized Route Planning:") print("\n🛣️ Optimized Route Planning:")
print("Note: This would work with actual Park objects from the database") print("Note: This would work with actual Park objects from the database")
# Show distances for a potential route # Show distances for a potential route
route_order = [ route_order = [
"Disneyland", "Disneyland",
"Six Flags Magic Mountain", "Six Flags Magic Mountain",
"Cedar Point", "Cedar Point",
"Walt Disney World", "Walt Disney World",
] ]
total_distance = 0 total_distance = 0
total_time = 0 total_time = 0
for i in range(len(route_order) - 1): for i in range(len(route_order) - 1):
from_park = route_order[i] from_park = route_order[i]
to_park = route_order[i + 1] to_park = route_order[i + 1]
if from_park in park_coords and to_park in park_coords: if from_park in park_coords and to_park in park_coords:
route = service.calculate_route( route = service.calculate_route(park_coords[from_park], park_coords[to_park])
park_coords[from_park], park_coords[to_park] if route:
) total_distance += getattr(route, "distance_km", 0) or route.get("distance_km", 0) if isinstance(route, dict) else getattr(route, "distance_km", 0)
if route: total_time += getattr(route, "duration_minutes", 0) or route.get("duration_minutes", 0) if isinstance(route, dict) else getattr(route, "duration_minutes", 0)
total_distance += route.distance_km print(f" {i + 1}. {from_park}{to_park}")
total_time += route.duration_minutes _print_route_summary(route, indent=" ")
print(f" {i + 1}. {from_park}{to_park}")
print(
f" {
route.formatted_distance}, {
route.formatted_duration}"
)
print("\n📊 Trip Summary:") print("\n📊 Trip Summary:")
print(f" Total Distance: {total_distance:.1f}km") print(f" Total Distance: {total_distance:.1f}km")
print( hours = total_time // 60
f" Total Driving Time: { mins = total_time % 60
total_time // print(f" Total Driving Time: {hours}h {mins}min")
60}h { # avoid division by zero
total_time % legs = max(1, len(route_order) - 1)
60}min" print(f" Average Distance per Leg: {total_distance / legs:.1f}km")
)
print(f" Average Distance per Leg: {total_distance / 3:.1f}km")
def demo_database_integration(): def demo_database_integration():
""" """
Demonstrate working with actual parks from the database. Demonstrate working with actual parks from the database.
""" """
print("\n\n🗄️ Database Integration Demo") print("\n\n🗄️ Database Integration Demo")
print("=" * 50) print("=" * 50)
service = RoadTripService() service = RoadTripService()
# Get parks that have location data # Get parks that have location data
parks_with_location = Park.objects.filter( parks_with_location = Park.objects.filter(location__point__isnull=False).select_related("location")[:5]
location__point__isnull=False
).select_related("location")[:5]
if not parks_with_location: if not parks_with_location:
print("❌ No parks with location data found in database") print("❌ No parks with location data found in database")
return return
print(f"Found {len(parks_with_location)} parks with location data:") print(f"Found {len(parks_with_location)} parks with location data:")
for park in parks_with_location: for park in parks_with_location:
coords = park.coordinates coords = getattr(park, "coordinates", None)
if coords: latlon = _format_coords(coords)
print(f" 🎢 {park.name}: {coords[0]:.4f}, {coords[1]:.4f}") if latlon:
print(f" 🎢 {park.name}: {latlon[0]:.4f}, {latlon[1]:.4f}")
# Demonstrate nearby park search # Demonstrate nearby park search
if len(parks_with_location) >= 1: if len(parks_with_location) >= 1:
center_park = parks_with_location[0] center_park = parks_with_location[0]
print(f"\n🔍 Finding parks within 500km of {center_park.name}:") print(f"\n🔍 Finding parks within 500km of {center_park.name}:")
nearby_parks = service.get_park_distances(center_park, radius_km=500) nearby_parks = service.get_park_distances(center_park, radius_km=500)
if nearby_parks: if nearby_parks:
print(f" Found {len(nearby_parks)} nearby parks:") print(f" Found {len(nearby_parks)} nearby parks:")
for result in nearby_parks[:3]: # Show top 3 for result in nearby_parks[:3]: # Show top 3
park = result["park"] park = result.get("park") if isinstance(result, dict) else getattr(result, "park", None)
print( # use safe formatted strings
f" 📍 { formatted_distance = result.get("formatted_distance", "N/A") if isinstance(result, dict) else getattr(result, "formatted_distance", "N/A")
park.name}: { formatted_duration = result.get("formatted_duration", "N/A") if isinstance(result, dict) else getattr(result, "formatted_duration", "N/A")
result['formatted_distance']} ({ if park:
result['formatted_duration']})" print(f" 📍 {park.name}: {formatted_distance} ({formatted_duration})")
) else:
else: print(" No nearby parks found (may need larger radius)")
print(" No nearby parks found (may need larger radius)")
# Demonstrate multi-park trip planning # Demonstrate multi-park trip planning
if len(parks_with_location) >= 3: if len(parks_with_location) >= 3:
selected_parks = list(parks_with_location)[:3] selected_parks = list(parks_with_location)[:3]
print("\n🗺️ Planning optimized trip for 3 parks:") print("\n🗺️ Planning optimized trip for 3 parks:")
for park in selected_parks: for park in selected_parks:
print(f" - {park.name}") print(f" - {park.name}")
trip = service.create_multi_park_trip(selected_parks) trip = service.create_multi_park_trip(selected_parks)
if trip: if trip:
print("\n✅ Optimized Route:") print("\n✅ Optimized Route:")
print(f" Total Distance: {trip.formatted_total_distance}") print(f" Total Distance: {getattr(trip, 'formatted_total_distance', 'N/A')}")
print(f" Total Duration: {trip.formatted_total_duration}") print(f" Total Duration: {getattr(trip, 'formatted_total_duration', 'N/A')}")
print(" Route:") print(" Route:")
for i, leg in enumerate(trip.legs, 1): for i, leg in enumerate(getattr(trip, "legs", []) or [], 1):
print(f" {i}. {leg.from_park.name}{leg.to_park.name}") from_park = getattr(leg, "from_park", None)
print( to_park = getattr(leg, "to_park", None)
f" { route = getattr(leg, "route", None)
leg.route.formatted_distance}, { if from_park and to_park:
leg.route.formatted_duration}" print(f" {i}. {from_park.name}{to_park.name}")
) _print_route_summary(route, indent=" ")
else: else:
print(" ❌ Could not optimize trip route") print(" ❌ Could not optimize trip route")
def demo_geocoding_fallback(): def demo_geocoding_fallback():
""" """
Demonstrate geocoding parks that don't have coordinates. Demonstrate geocoding parks that don't have coordinates.
""" """
print("\n\n🌍 Geocoding Demo") print("\n\n🌍 Geocoding Demo")
print("=" * 50) print("=" * 50)
service = RoadTripService() service = RoadTripService()
# Get parks without location data # Get parks without location data
parks_without_coords = Park.objects.filter( parks_without_coords = Park.objects.filter(location__point__isnull=True).select_related("location")[:3]
location__point__isnull=True
).select_related("location")[:3]
if not parks_without_coords: if not parks_without_coords:
print("✅ All parks already have coordinates") print("✅ All parks already have coordinates")
return return
print(f"Found {len(parks_without_coords)} parks without coordinates:") print(f"Found {len(parks_without_coords)} parks without coordinates:")
for park in parks_without_coords: for park in parks_without_coords:
print(f"\n🎢 {park.name}") print(f"\n🎢 {park.name}")
if hasattr(park, "location") and park.location: location = getattr(park, "location", None)
location = park.location if location:
address_parts = [ # use getattr to avoid attribute errors
park.name, address_parts = [
location.street_address, getattr(park, "name", None),
location.city, getattr(location, "street_address", None),
location.state, getattr(location, "city", None),
location.country, getattr(location, "state", None),
] getattr(location, "country", None),
address = ", ".join(part for part in address_parts if part) ]
print(f" Address: {address}") address = ", ".join(part for part in address_parts if part)
print(f" Address: {address}")
# Try to geocode # Try to geocode
success = service.geocode_park_if_needed(park) success = service.geocode_park_if_needed(park)
if success: if success:
coords = park.coordinates coords = getattr(park, "coordinates", None)
print(f" ✅ Geocoded to: {coords[0]:.4f}, {coords[1]:.4f}") latlon = _format_coords(coords)
else: if latlon:
print(" Geocoding failed") print(f" Geocoded to: {latlon[0]:.4f}, {latlon[1]:.4f}")
else: else:
print(" ❌ No location data available") print(" ✅ Geocoded but coordinates unavailable")
else:
print(" ❌ Geocoding failed")
else:
print(" ❌ No location data available")
def demo_cache_performance(): def demo_cache_performance():
""" """
Demonstrate caching performance benefits. Demonstrate caching performance benefits.
""" """
print("\n\n⚡ Cache Performance Demo") print("\n\n⚡ Cache Performance Demo")
print("=" * 50) print("=" * 50)
service = RoadTripService() service = RoadTripService()
import time import time
# Test address for geocoding # Test address for geocoding
test_address = "Disneyland, Anaheim, CA" test_address = "Disneyland, Anaheim, CA"
print(f"Testing cache performance with: {test_address}") print(f"Testing cache performance with: {test_address}")
# First request (cache miss) # First request (cache miss)
print("\n1⃣ First request (cache miss):") print("\n1⃣ First request (cache miss):")
start_time = time.time() start_time = time.time()
coords1 = service.geocode_address(test_address) coords1 = service.geocode_address(test_address)
first_duration = time.time() - start_time first_duration = time.time() - start_time
if coords1: if coords1:
print(f" ✅ Result: {coords1.latitude:.4f}, {coords1.longitude:.4f}") latlon = _format_coords(coords1)
print(f" ⏱️ Duration: {first_duration:.2f} seconds") if latlon:
print(f" ✅ Result: {latlon[0]:.4f}, {latlon[1]:.4f}")
else:
print(" ✅ Result obtained")
print(f" ⏱️ Duration: {first_duration:.2f} seconds")
# Second request (cache hit) # Second request (cache hit)
print("\n2⃣ Second request (cache hit):") print("\n2⃣ Second request (cache hit):")
start_time = time.time() start_time = time.time()
coords2 = service.geocode_address(test_address) coords2 = service.geocode_address(test_address)
second_duration = time.time() - start_time second_duration = time.time() - start_time
if coords2: if coords2:
print(f" ✅ Result: {coords2.latitude:.4f}, {coords2.longitude:.4f}") latlon2 = _format_coords(coords2)
print(f" ⏱️ Duration: {second_duration:.2f} seconds") if latlon2:
print(f" ✅ Result: {latlon2[0]:.4f}, {latlon2[1]:.4f}")
else:
print(" ✅ Result obtained")
print(f" ⏱️ Duration: {second_duration:.2f} seconds")
if first_duration > second_duration: if first_duration > second_duration and second_duration > 0:
speedup = first_duration / second_duration speedup = first_duration / second_duration
print(f" 🚀 Cache speedup: {speedup:.1f}x faster") print(f" 🚀 Cache speedup: {speedup:.1f}x faster")
if ( # Compare coordinates if both present
coords1.latitude == coords2.latitude if coords1 and coords2:
and coords1.longitude == coords2.longitude latlon1 = _format_coords(coords1)
): latlon2 = _format_coords(coords2)
print(" ✅ Results identical (cache working)") if latlon1 and latlon2 and latlon1 == latlon2:
print(" ✅ Results identical (cache working)")
def main(): def main():
""" """
Run all demonstration scenarios. Run all demonstration scenarios.
""" """
print("🎢 ThrillWiki Road Trip Service Demo") print("🎢 ThrillWiki Road Trip Service Demo")
print("This demo shows practical usage scenarios for the OSM Road Trip Service") print("This demo shows practical usage scenarios for the OSM Road Trip Service")
try: try:
demo_florida_theme_park_trip() demo_florida_theme_park_trip()
demo_cross_country_road_trip() demo_cross_country_road_trip()
demo_database_integration() demo_database_integration()
demo_geocoding_fallback() demo_geocoding_fallback()
demo_cache_performance() demo_cache_performance()
print("\n" + "=" * 50) print("\n" + "=" * 50)
print("🎉 Demo completed successfully!") print("🎉 Demo completed successfully!")
print("\nThe Road Trip Service is ready for integration into ThrillWiki!") print("\nThe Road Trip Service is ready for integration into ThrillWiki!")
print("\nKey Features Demonstrated:") print("\nKey Features Demonstrated:")
print("✅ Geocoding theme park addresses") print("✅ Geocoding theme park addresses")
print("✅ Route calculation with distance/time") print("✅ Route calculation with distance/time")
print("✅ Multi-park trip optimization") print("✅ Multi-park trip optimization")
print("✅ Database integration with Park models") print("✅ Database integration with Park models")
print("✅ Caching for performance") print("✅ Caching for performance")
print("✅ Rate limiting for OSM compliance") print("✅ Rate limiting for OSM compliance")
print("✅ Error handling and fallbacks") print("✅ Error handling and fallbacks")
except Exception as e: except Exception as e:
print(f"\n❌ Demo failed with error: {e}") print(f"\n❌ Demo failed with error: {e}")
import traceback import traceback
traceback.print_exc() traceback.print_exc()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -2,8 +2,8 @@
""" """
Basic test script to verify RideLocation and CompanyHeadquarters models work correctly. Basic test script to verify RideLocation and CompanyHeadquarters models work correctly.
""" """
from rides.models import Ride, RideLocation from apps.rides.models import Ride, RideLocation
from parks.models import Company, CompanyHeadquarters from apps.parks.models import Company, CompanyHeadquarters
import os import os
import sys import sys
import django import django
@@ -23,11 +23,11 @@ def test_company_headquarters():
print("⚠️ No existing companies found, skipping CompanyHeadquarters test") print("⚠️ No existing companies found, skipping CompanyHeadquarters test")
return None, None return None, None
# Check if headquarters already exist # Check if headquarters already exist (use queryset lookup to avoid relying on a reverse attribute name)
try: headquarters = CompanyHeadquarters.objects.filter(company=existing_company).first()
headquarters = existing_company.headquarters if headquarters:
print(f"✓ Found existing headquarters: {headquarters}") print(f"✓ Found existing headquarters: {headquarters}")
except CompanyHeadquarters.DoesNotExist: else:
# Create headquarters for existing company # Create headquarters for existing company
headquarters = CompanyHeadquarters.objects.create( headquarters = CompanyHeadquarters.objects.create(
company=existing_company, company=existing_company,
@@ -53,7 +53,13 @@ def test_ride_location():
# First, we need a ride - let's check if any exist # First, we need a ride - let's check if any exist
if Ride.objects.exists(): if Ride.objects.exists():
ride = Ride.objects.first() ride = Ride.objects.first()
print(f"✓ Using existing ride: {ride.name}") # Safely access the ride's name in case static analysis or runtime sees None/no attribute.
ride_name = getattr(ride, "name", None) if ride is not None else None
if ride_name:
print(f"✓ Using existing ride: {ride_name}")
else:
# Fall back to repr of the ride object to avoid AttributeError
print(f"✓ Using existing ride: {ride!r}")
else: else:
print("! No rides found in database - skipping RideLocation test") print("! No rides found in database - skipping RideLocation test")
return None, None return None, None
@@ -93,9 +99,9 @@ def cleanup_test_data(company=None, headquarters=None, ride_location=None):
headquarters.delete() headquarters.delete()
print("✓ Deleted test headquarters") print("✓ Deleted test headquarters")
if company: # Do not delete an existing company record discovered in the database.
company.delete() # Tests should avoid removing production/existing data. If a test created a Company
print("✓ Deleted test company") # instance explicitly, add logic to delete it here (not implemented by default).
def main(): def main():

View File

@@ -46,7 +46,7 @@ def test_trigger_endpoint(token):
"Content-Type": "application/json" "Content-Type": "application/json"
} }
print(f"\n🚀 Testing manual trigger endpoint...") print("\n🚀 Testing manual trigger endpoint...")
print(f"URL: {trigger_url}") print(f"URL: {trigger_url}")
response = requests.post(trigger_url, headers=headers) response = requests.post(trigger_url, headers=headers)
@@ -72,7 +72,7 @@ def test_trigger_endpoint(token):
def test_trending_endpoints(): def test_trending_endpoints():
"""Test the trending content endpoints to see the results.""" """Test the trending content endpoints to see the results."""
print(f"\n📊 Testing trending content endpoints...") print("\n📊 Testing trending content endpoints...")
# Test trending content endpoint # Test trending content endpoint
trending_url = f"{BASE_URL}/api/v1/trending/content/" trending_url = f"{BASE_URL}/api/v1/trending/content/"
@@ -109,7 +109,7 @@ def test_trending_endpoints():
# Show the newly_opened structure to verify our changes # Show the newly_opened structure to verify our changes
if data.get('newly_opened'): if data.get('newly_opened'):
print(f"\n🎢 First newly opened item structure:") print("\n🎢 First newly opened item structure:")
first_item = data['newly_opened'][0] first_item = data['newly_opened'][0]
print(f" Name: {first_item.get('name')}") print(f" Name: {first_item.get('name')}")
# Should be park name, not location # Should be park name, not location
@@ -124,12 +124,12 @@ def test_trending_endpoints():
print( print(
f" ❌ ERROR: 'location' field still present: {first_item['location']}") f" ❌ ERROR: 'location' field still present: {first_item['location']}")
else: else:
print(f" ✅ SUCCESS: 'location' field removed as requested") print(" ✅ SUCCESS: 'location' field removed as requested")
def test_unauthorized_access(): def test_unauthorized_access():
"""Test that non-admin users cannot access the trigger endpoint.""" """Test that non-admin users cannot access the trigger endpoint."""
print(f"\n🔒 Testing unauthorized access...") print("\n🔒 Testing unauthorized access...")
trigger_url = f"{BASE_URL}/api/v1/trending/calculate/" trigger_url = f"{BASE_URL}/api/v1/trending/calculate/"
@@ -169,7 +169,7 @@ def main():
trigger_result = test_trigger_endpoint(token) trigger_result = test_trigger_endpoint(token)
if trigger_result: if trigger_result:
print(f"\n⏳ Waiting 10 seconds for tasks to process...") print("\n⏳ Waiting 10 seconds for tasks to process...")
time.sleep(10) time.sleep(10)
# Test the trending endpoints to see results # Test the trending endpoints to see results

View File

@@ -2,7 +2,7 @@
""" """
Test script for ParkLocation model functionality Test script for ParkLocation model functionality
""" """
from parks.models import Park, ParkLocation, Company from apps.parks.models import Park, ParkLocation, Company
import os import os
import django import django

View File

@@ -9,14 +9,21 @@ This script tests all functionality of the OSM Road Trip Service including:
- Integration with existing Park models - Integration with existing Park models
""" """
from typing import cast
from apps.parks.services import RoadTripService
from apps.parks.services.roadtrip import Coordinates
from apps.parks.models import Park
from django.core.cache import cache from django.core.cache import cache
from parks.models import Park
from parks.services.roadtrip import Coordinates
from parks.services import RoadTripService
import os import os
import sys
import django import django
# Setup Django # Ensure project root is on sys.path so imports like `parks.models` resolve.
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT)
# Setup Django before importing project modules that depend on settings.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings")
django.setup() django.setup()
@@ -40,16 +47,13 @@ def test_geocoding():
print(f"\nGeocoding: {address}") print(f"\nGeocoding: {address}")
coords = service.geocode_address(address) coords = service.geocode_address(address)
if coords: if coords:
print( # fixed: single-line f-string formatting
f" ✅ Success: { print(f" ✅ Success: {coords.latitude:.6f}, {coords.longitude:.6f}")
coords.latitude:.6f}, {
coords.longitude:.6f}"
)
else: else:
print(f" ❌ Failed") print(" ❌ Failed")
# Test cache functionality # Test cache functionality
print(f"\nTesting cache...") print("\nTesting cache...")
coords1 = service.geocode_address("Cedar Point, Sandusky, Ohio") coords1 = service.geocode_address("Cedar Point, Sandusky, Ohio")
coords2 = service.geocode_address("Cedar Point, Sandusky, Ohio") coords2 = service.geocode_address("Cedar Point, Sandusky, Ohio")
if coords1 and coords2: if coords1 and coords2:
@@ -66,30 +70,30 @@ def test_route_calculation():
cedar_point = Coordinates(41.4793, -82.6833) cedar_point = Coordinates(41.4793, -82.6833)
magic_kingdom = Coordinates(28.4177, -81.5812) magic_kingdom = Coordinates(28.4177, -81.5812)
print(f"Calculating route from Cedar Point to Magic Kingdom...") print("Calculating route from Cedar Point to Magic Kingdom...")
route = service.calculate_route(cedar_point, magic_kingdom) route = service.calculate_route(cedar_point, magic_kingdom)
if route: if route:
print(f" ✅ Success:") print(" ✅ Success:")
print(f" Distance: {route.formatted_distance}") print(f" Distance: {route.formatted_distance}")
print(f" Duration: {route.formatted_duration}") print(f" Duration: {route.formatted_duration}")
print(f" Geometry: {'Yes' if route.geometry else 'No'}") print(f" Geometry: {'Yes' if route.geometry else 'No'}")
else: else:
print(f" ❌ Failed") print(" ❌ Failed")
# Test short distance (should use OSRM) # Test short distance (should use OSRM)
disneyland = Coordinates(33.8121, -117.9190) disneyland = Coordinates(33.8121, -117.9190)
knotts = Coordinates(33.8442, -118.0000) knotts = Coordinates(33.8442, -118.0000)
print(f"\nCalculating route from Disneyland to Knott's Berry Farm...") print("\nCalculating route from Disneyland to Knott's Berry Farm...")
route = service.calculate_route(disneyland, knotts) route = service.calculate_route(disneyland, knotts)
if route: if route:
print(f" ✅ Success:") print(" ✅ Success:")
print(f" Distance: {route.formatted_distance}") print(f" Distance: {route.formatted_distance}")
print(f" Duration: {route.formatted_duration}") print(f" Duration: {route.formatted_duration}")
else: else:
print(f" ❌ Failed") print(" ❌ Failed")
def test_park_integration(): def test_park_integration():
@@ -108,24 +112,25 @@ def test_park_integration():
print(f"Found {len(parks)} parks to test with:") print(f"Found {len(parks)} parks to test with:")
for park in parks: for park in parks:
print(f" - {park.name}") print(f" - {park.name}")
if hasattr(park, "location") and park.location: # Use getattr to safely access the optional related attribute and avoid static type warnings.
coords = park.coordinates location = getattr(park, "location", None)
if location:
coords = getattr(park, "coordinates", None)
if coords: if coords:
print(f" 📍 {coords[0]:.4f}, {coords[1]:.4f}") print(f" 📍 {coords[0]:.4f}, {coords[1]:.4f}")
else: else:
print(f" 📍 No coordinates, will try to geocode...") print(" 📍 No coordinates, will try to geocode...")
success = service.geocode_park_if_needed(park) success = service.geocode_park_if_needed(park)
if success: if success:
coords = park.coordinates coords = getattr(park, "coordinates", None)
print( if coords:
f" ✅ Geocoded to: { print(f" ✅ Geocoded to: {coords[0]:.4f}, {coords[1]:.4f}")
coords[0]:.4f}, { else:
coords[1]:.4f}" print(" ❌ Geocoding succeeded but coordinates still missing")
)
else: else:
print(f" ❌ Geocoding failed") print(" ❌ Geocoding failed")
else: else:
print(f" ❌ No location data") print(" ❌ No location data")
def test_nearby_parks(): def test_nearby_parks():
@@ -153,13 +158,9 @@ def test_nearby_parks():
for result in nearby_parks[:5]: # Show first 5 for result in nearby_parks[:5]: # Show first 5
park = result["park"] park = result["park"]
print( print(
f" { f" {park.name}: {result['formatted_distance']}, {result['formatted_duration']}")
park.name}: {
result['formatted_distance']}, {
result['formatted_duration']}"
)
else: else:
print(f" ❌ No nearby parks found") print(" ❌ No nearby parks found")
def test_route_park_discovery(): def test_route_park_discovery():
@@ -180,11 +181,7 @@ def test_route_park_discovery():
start_park = parks_with_location[0] start_park = parks_with_location[0]
end_park = parks_with_location[1] end_park = parks_with_location[1]
print( print(f"Finding parks along route from {start_park.name} to {end_park.name}...")
f"Finding parks along route from {
start_park.name} to {
end_park.name}..."
)
parks_along_route = service.find_parks_along_route( parks_along_route = service.find_parks_along_route(
start_park, end_park, max_detour_km=100 start_park, end_park, max_detour_km=100
@@ -195,7 +192,7 @@ def test_route_park_discovery():
for park in parks_along_route[:3]: # Show first 3 for park in parks_along_route[:3]: # Show first 3
print(f" - {park.name}") print(f" - {park.name}")
else: else:
print(f" ❌ No parks found along route") print(" ❌ No parks found along route")
def test_multi_park_trip(): def test_multi_park_trip():
@@ -221,19 +218,16 @@ def test_multi_park_trip():
trip = service.create_multi_park_trip(parks_list) trip = service.create_multi_park_trip(parks_list)
if trip: if trip:
print(f" ✅ Trip planned successfully:") print(" ✅ Trip planned successfully:")
print(f" Total Distance: {trip.formatted_total_distance}") print(f" Total Distance: {trip.formatted_total_distance}")
print(f" Total Duration: {trip.formatted_total_duration}") print(f" Total Duration: {trip.formatted_total_duration}")
print(f" Route:") print(" Route:")
for i, leg in enumerate(trip.legs, 1): for i, leg in enumerate(trip.legs, 1):
print(f" {i}. {leg.from_park.name}{leg.to_park.name}") print(f" {i}. {leg.from_park.name}{leg.to_park.name}")
print( print(
f" { f" {leg.route.formatted_distance}, {leg.route.formatted_duration}")
leg.route.formatted_distance}, {
leg.route.formatted_duration}"
)
else: else:
print(f" ❌ Trip planning failed") print(" ❌ Trip planning failed")
def test_error_handling(): def test_error_handling():
@@ -249,28 +243,28 @@ def test_error_handling():
route = service.calculate_route(invalid_coords, valid_coords) route = service.calculate_route(invalid_coords, valid_coords)
if route: if route:
print( print(f" ⚠️ Got route with invalid coords: {route.formatted_distance}")
f" ⚠️ Got route with invalid coords: {
route.formatted_distance}"
)
else: else:
print(f" ✅ Correctly handled invalid coordinates") print(" ✅ Correctly handled invalid coordinates")
# Test with empty address # Test with empty address
print("Testing empty address geocoding...") print("Testing empty address geocoding...")
coords = service.geocode_address("") coords = service.geocode_address("")
if coords: if coords:
print(f" ⚠️ Got coordinates for empty address") print(" ⚠️ Got coordinates for empty address")
else: else:
print(f" ✅ Correctly handled empty address") print(" ✅ Correctly handled empty address")
# Test with None values # Test with None values
print("Testing None coordinates...") print("Testing None coordinates...")
route = service.calculate_route(None, valid_coords) # cast(None, Coordinates) is used only to satisfy static typing checks
# while keeping the runtime intent of passing None to the service.
route = service.calculate_route(cast(Coordinates, None), valid_coords)
if route: if route:
print(f" ⚠️ Got route with None coordinates") print(" ⚠️ Got route with None coordinates")
else: else:
print(f" ✅ Correctly handled None coordinates") print(" ✅ Correctly handled None coordinates")
def test_rate_limiting(): def test_rate_limiting():
@@ -294,19 +288,15 @@ def test_rate_limiting():
for address in addresses: for address in addresses:
coords = service.geocode_address(address) coords = service.geocode_address(address)
if coords: if coords:
print( print(f"{address}: {coords.latitude:.4f}, {coords.longitude:.4f}")
f"{address}: {
coords.latitude:.4f}, {
coords.longitude:.4f}"
)
elapsed = time.time() - start_time elapsed = time.time() - start_time
print(f" Total time for 3 requests: {elapsed:.2f} seconds") print(f" Total time for 3 requests: {elapsed:.2f} seconds")
if elapsed >= 2.0: # Should take at least 2 seconds with 1 req/sec limit if elapsed >= 2.0: # Should take at least 2 seconds with 1 req/sec limit
print(f" ✅ Rate limiting appears to be working") print(" ✅ Rate limiting appears to be working")
else: else:
print(f" ⚠️ Requests may have been cached or rate limiting not working") print(" ⚠️ Requests may have been cached or rate limiting not working")
def main(): def main():

View File

@@ -4,16 +4,24 @@ Test script for the unified map service.
This script tests the map service with real location data. This script tests the map service with real location data.
""" """
from core.services.data_structures import GeoBounds, MapFilters, LocationType
from core.services.map_service import unified_map_service
import os import os
import sys import sys
import django import django
# Setup Django environment # Ensure project root is on sys.path so imports like `core.services.*` resolve.
# This inserts the parent directory of the tests folder (project root).
PROJECT_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if PROJECT_ROOT not in sys.path:
sys.path.insert(0, PROJECT_ROOT)
# Setup Django environment before importing app modules that depend on settings.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings") os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings")
django.setup() django.setup()
# Now import project modules
from apps.core.services.data_structures import GeoBounds, MapFilters, LocationType # noqa: E402
from apps.core.services.map_service import unified_map_service # noqa: E402
def test_basic_map_service(): def test_basic_map_service():
"""Test basic map service functionality.""" """Test basic map service functionality."""
@@ -215,7 +223,7 @@ def test_performance():
print(f" Max time: {max(times):.2f}ms") print(f" Max time: {max(times):.2f}ms")
# Test cache performance # Test cache performance
print(f"\n Testing cache performance:") print("\n Testing cache performance:")
start = time.time() start = time.time()
response1 = unified_map_service.get_map_data(zoom_level=10, use_cache=True) response1 = unified_map_service.get_map_data(zoom_level=10, use_cache=True)
time1 = time.time() - start time1 = time.time() - start