From bf04e4d85422c5ba394a5f7a95da8db96c0bd921 Mon Sep 17 00:00:00 2001 From: pacnpal <183241239+pacnpal@users.noreply.github.com> Date: Sun, 28 Sep 2025 10:50:57 -0400 Subject: [PATCH] fix: Update import paths to use 'apps' prefix for models and services --- demo_roadtrip_usage.py | 584 ++++++++++++++++-------------- tests/test_location_models.py | 26 +- tests/test_manual_trigger.py | 12 +- tests/test_park_location.py | 2 +- tests/test_roadtrip_service.py | 118 +++--- tests/test_unified_map_service.py | 16 +- 6 files changed, 395 insertions(+), 363 deletions(-) diff --git a/demo_roadtrip_usage.py b/demo_roadtrip_usage.py index f40745c9..bb71073a 100644 --- a/demo_roadtrip_usage.py +++ b/demo_roadtrip_usage.py @@ -5,8 +5,8 @@ This script demonstrates real-world scenarios for using the OSM Road Trip Servic in the ThrillWiki application. """ -from parks.models import Park -from parks.services import RoadTripService +from apps.parks.models import Park +from apps.parks.services import RoadTripService import os import django @@ -14,350 +14,378 @@ import django os.environ.setdefault("DJANGO_SETTINGS_MODULE", "thrillwiki.settings") 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(): - """ - Demonstrate planning a Florida theme park road trip. - """ - print("πŸ–οΈ Florida Theme Park Road Trip Planner") - print("=" * 50) + """ + Demonstrate planning a Florida theme park road trip. + """ + print("πŸ–οΈ Florida Theme Park Road Trip Planner") + print("=" * 50) - service = RoadTripService() + service = RoadTripService() - # Define Florida theme parks with addresses - florida_parks = [ - ("Magic Kingdom", "Magic Kingdom Dr, Orlando, FL 32830"), - ( - "Universal Studios Florida", - "6000 Universal Blvd, Orlando, FL 32819", - ), - ("SeaWorld Orlando", "7007 Sea World Dr, Orlando, FL 32821"), - ("Busch Gardens Tampa", "10165 McKinley Dr, Tampa, FL 33612"), - ] + # Define Florida theme parks with addresses + florida_parks = [ + (MAGIC_KINGDOM, "Magic Kingdom Dr, Orlando, FL 32830"), + ("Universal Studios Florida", "6000 Universal Blvd, Orlando, FL 32819"), + ("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:") - park_coords = {} + print("Planning trip for these Florida parks:") + park_coords = {} - for name, address in florida_parks: - print(f"\nπŸ“ Geocoding {name}...") - coords = service.geocode_address(address) - if coords: - park_coords[name] = coords - print( - f" βœ… Located at { - coords.latitude:.4f}, { - coords.longitude:.4f}" - ) - else: - print(f" ❌ Could not geocode {address}") + # small helper to geocode and store + def _geocode_and_store(name, address): + print(f"\nπŸ“ Geocoding {name}...") + coords = service.geocode_address(address) + if coords: + latlon = _format_coords(coords) + if latlon: + park_coords[name] = coords + print(f" βœ… Located at {latlon[0]:.4f}, {latlon[1]:.4f}") + return True + print(f" ❌ Could not geocode {address}") + return False - if len(park_coords) < 2: - print("❌ Need at least 2 parks to plan a trip") - return + for name, address in florida_parks: + _geocode_and_store(name, address) - # Calculate distances between all parks - print("\nπŸ—ΊοΈ Distance Matrix:") - park_names = list(park_coords.keys()) + if len(park_coords) < 2: + print("❌ Need at least 2 parks to plan a trip") + return - for i, park1 in enumerate(park_names): - for j, park2 in enumerate(park_names): - if i < j: # Only calculate each pair once - route = service.calculate_route(park_coords[park1], park_coords[park2]) - if route: - print(f" {park1} ↔ {park2}") - print( - f" { - route.formatted_distance}, { - route.formatted_duration}" - ) + # Calculate distances between all parks + print("\nπŸ—ΊοΈ Distance Matrix:") + park_names = list(park_coords.keys()) - # Find central park for radiating searches - print("\n🎒 Parks within 100km of Magic Kingdom:") - magic_kingdom_coords = park_coords.get("Magic Kingdom") - 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( - f" {name}: { - route.formatted_distance} ({ - route.formatted_duration})" - ) + for i, park1 in enumerate(park_names): + for j, park2 in enumerate(park_names): + if i < j: # Only calculate each pair once + route = service.calculate_route(park_coords[park1], park_coords[park2]) + if route: + print(f" {park1} ↔ {park2}") + _print_route_summary(route, indent=" ") + + # Find central park for radiating searches + print(f"\n🎒 Parks within 100km of {MAGIC_KINGDOM}:") + magic_kingdom_coords = park_coords.get(MAGIC_KINGDOM) + 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(): - """ - Demonstrate planning a cross-country theme park road trip. - """ - print("\n\nπŸ‡ΊπŸ‡Έ Cross-Country Theme Park Road Trip") - print("=" * 50) + """ + Demonstrate planning a cross-country theme park road trip. + """ + print("\n\nπŸ‡ΊπŸ‡Έ Cross-Country Theme Park Road Trip") + print("=" * 50) - service = RoadTripService() + service = RoadTripService() - # Major theme parks across the US - major_parks = [ - ("Disneyland", "1313 Disneyland Dr, Anaheim, CA 92802"), - ("Cedar Point", "1 Cedar Point Dr, Sandusky, OH 44870"), - ( - "Six Flags Magic Mountain", - "26101 Magic Mountain Pkwy, Valencia, CA 91355", - ), - ("Walt Disney World", "Walt Disney World Resort, Orlando, FL 32830"), - ] + # Major theme parks across the US + major_parks = [ + ("Disneyland", "1313 Disneyland Dr, Anaheim, CA 92802"), + ("Cedar Point", "1 Cedar Point Dr, Sandusky, OH 44870"), + ("Six Flags Magic Mountain", "26101 Magic Mountain Pkwy, Valencia, CA 91355"), + ("Walt Disney World", "Walt Disney World Resort, Orlando, FL 32830"), + ] - print("Geocoding major US theme parks:") - park_coords = {} + print("Geocoding major US theme parks:") + park_coords = {} - for name, address in major_parks: - print(f"\nπŸ“ {name}...") - coords = service.geocode_address(address) - if coords: - park_coords[name] = coords - print(f" βœ… {coords.latitude:.4f}, {coords.longitude:.4f}") + for name, address in major_parks: + print(f"\nπŸ“ {name}...") + coords = service.geocode_address(address) + if coords: + park_coords[name] = coords + latlon = _format_coords(coords) + if latlon: + print(f" βœ… {latlon[0]:.4f}, {latlon[1]:.4f}") - if len(park_coords) >= 3: - # Calculate an optimized route if we have DB parks - print("\nπŸ›£οΈ Optimized Route Planning:") - print("Note: This would work with actual Park objects from the database") + if len(park_coords) >= 3: + # Calculate an optimized route if we have DB parks + print("\nπŸ›£οΈ Optimized Route Planning:") + print("Note: This would work with actual Park objects from the database") - # Show distances for a potential route - route_order = [ - "Disneyland", - "Six Flags Magic Mountain", - "Cedar Point", - "Walt Disney World", - ] - total_distance = 0 - total_time = 0 + # Show distances for a potential route + route_order = [ + "Disneyland", + "Six Flags Magic Mountain", + "Cedar Point", + "Walt Disney World", + ] + total_distance = 0 + total_time = 0 - for i in range(len(route_order) - 1): - from_park = route_order[i] - to_park = route_order[i + 1] + for i in range(len(route_order) - 1): + from_park = route_order[i] + to_park = route_order[i + 1] - if from_park in park_coords and to_park in park_coords: - route = service.calculate_route( - park_coords[from_park], park_coords[to_park] - ) - if route: - total_distance += route.distance_km - total_time += route.duration_minutes - print(f" {i + 1}. {from_park} β†’ {to_park}") - print( - f" { - route.formatted_distance}, { - route.formatted_duration}" - ) + if from_park in park_coords and to_park in park_coords: + route = service.calculate_route(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) + total_time += getattr(route, "duration_minutes", 0) or route.get("duration_minutes", 0) if isinstance(route, dict) else getattr(route, "duration_minutes", 0) + print(f" {i + 1}. {from_park} β†’ {to_park}") + _print_route_summary(route, indent=" ") - print("\nπŸ“Š Trip Summary:") - print(f" Total Distance: {total_distance:.1f}km") - print( - f" Total Driving Time: { - total_time // - 60}h { - total_time % - 60}min" - ) - print(f" Average Distance per Leg: {total_distance / 3:.1f}km") + print("\nπŸ“Š Trip Summary:") + print(f" Total Distance: {total_distance:.1f}km") + hours = total_time // 60 + mins = total_time % 60 + print(f" Total Driving Time: {hours}h {mins}min") + # avoid division by zero + legs = max(1, len(route_order) - 1) + print(f" Average Distance per Leg: {total_distance / legs:.1f}km") def demo_database_integration(): - """ - Demonstrate working with actual parks from the database. - """ - print("\n\nπŸ—„οΈ Database Integration Demo") - print("=" * 50) + """ + Demonstrate working with actual parks from the database. + """ + print("\n\nπŸ—„οΈ Database Integration Demo") + print("=" * 50) - service = RoadTripService() + service = RoadTripService() - # Get parks that have location data - parks_with_location = Park.objects.filter( - location__point__isnull=False - ).select_related("location")[:5] + # Get parks that have location data + parks_with_location = Park.objects.filter(location__point__isnull=False).select_related("location")[:5] - if not parks_with_location: - print("❌ No parks with location data found in database") - return + if not parks_with_location: + print("❌ No parks with location data found in database") + 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: - coords = park.coordinates - if coords: - print(f" 🎒 {park.name}: {coords[0]:.4f}, {coords[1]:.4f}") + for park in parks_with_location: + coords = getattr(park, "coordinates", None) + latlon = _format_coords(coords) + if latlon: + print(f" 🎒 {park.name}: {latlon[0]:.4f}, {latlon[1]:.4f}") - # Demonstrate nearby park search - if len(parks_with_location) >= 1: - center_park = parks_with_location[0] - print(f"\nπŸ” Finding parks within 500km of {center_park.name}:") + # Demonstrate nearby park search + if len(parks_with_location) >= 1: + center_park = parks_with_location[0] + 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: - print(f" Found {len(nearby_parks)} nearby parks:") - for result in nearby_parks[:3]: # Show top 3 - park = result["park"] - print( - f" πŸ“ { - park.name}: { - result['formatted_distance']} ({ - result['formatted_duration']})" - ) - else: - print(" No nearby parks found (may need larger radius)") + if nearby_parks: + print(f" Found {len(nearby_parks)} nearby parks:") + for result in nearby_parks[:3]: # Show top 3 + park = result.get("park") if isinstance(result, dict) else getattr(result, "park", None) + # use safe formatted strings + formatted_distance = result.get("formatted_distance", "N/A") if isinstance(result, dict) else getattr(result, "formatted_distance", "N/A") + formatted_duration = result.get("formatted_duration", "N/A") if isinstance(result, dict) else getattr(result, "formatted_duration", "N/A") + if park: + print(f" πŸ“ {park.name}: {formatted_distance} ({formatted_duration})") + else: + print(" No nearby parks found (may need larger radius)") - # Demonstrate multi-park trip planning - if len(parks_with_location) >= 3: - selected_parks = list(parks_with_location)[:3] - print("\nπŸ—ΊοΈ Planning optimized trip for 3 parks:") + # Demonstrate multi-park trip planning + if len(parks_with_location) >= 3: + selected_parks = list(parks_with_location)[:3] + print("\nπŸ—ΊοΈ Planning optimized trip for 3 parks:") - for park in selected_parks: - print(f" - {park.name}") + for park in selected_parks: + print(f" - {park.name}") - trip = service.create_multi_park_trip(selected_parks) + trip = service.create_multi_park_trip(selected_parks) - if trip: - print("\nβœ… Optimized Route:") - print(f" Total Distance: {trip.formatted_total_distance}") - print(f" Total Duration: {trip.formatted_total_duration}") - print(" Route:") + if trip: + print("\nβœ… Optimized Route:") + print(f" Total Distance: {getattr(trip, 'formatted_total_distance', 'N/A')}") + print(f" Total Duration: {getattr(trip, 'formatted_total_duration', 'N/A')}") + print(" Route:") - for i, leg in enumerate(trip.legs, 1): - print(f" {i}. {leg.from_park.name} β†’ {leg.to_park.name}") - print( - f" { - leg.route.formatted_distance}, { - leg.route.formatted_duration}" - ) - else: - print(" ❌ Could not optimize trip route") + for i, leg in enumerate(getattr(trip, "legs", []) or [], 1): + from_park = getattr(leg, "from_park", None) + to_park = getattr(leg, "to_park", None) + route = getattr(leg, "route", None) + if from_park and to_park: + print(f" {i}. {from_park.name} β†’ {to_park.name}") + _print_route_summary(route, indent=" ") + else: + print(" ❌ Could not optimize trip route") def demo_geocoding_fallback(): - """ - Demonstrate geocoding parks that don't have coordinates. - """ - print("\n\n🌍 Geocoding Demo") - print("=" * 50) + """ + Demonstrate geocoding parks that don't have coordinates. + """ + print("\n\n🌍 Geocoding Demo") + print("=" * 50) - service = RoadTripService() + service = RoadTripService() - # Get parks without location data - parks_without_coords = Park.objects.filter( - location__point__isnull=True - ).select_related("location")[:3] + # Get parks without location data + parks_without_coords = Park.objects.filter(location__point__isnull=True).select_related("location")[:3] - if not parks_without_coords: - print("βœ… All parks already have coordinates") - return + if not parks_without_coords: + print("βœ… All parks already have coordinates") + 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: - print(f"\n🎒 {park.name}") + for park in parks_without_coords: + print(f"\n🎒 {park.name}") - if hasattr(park, "location") and park.location: - location = park.location - address_parts = [ - park.name, - location.street_address, - location.city, - location.state, - location.country, - ] - address = ", ".join(part for part in address_parts if part) - print(f" Address: {address}") + location = getattr(park, "location", None) + if location: + # use getattr to avoid attribute errors + address_parts = [ + getattr(park, "name", None), + getattr(location, "street_address", None), + getattr(location, "city", None), + getattr(location, "state", None), + getattr(location, "country", None), + ] + address = ", ".join(part for part in address_parts if part) + print(f" Address: {address}") - # Try to geocode - success = service.geocode_park_if_needed(park) - if success: - coords = park.coordinates - print(f" βœ… Geocoded to: {coords[0]:.4f}, {coords[1]:.4f}") - else: - print(" ❌ Geocoding failed") - else: - print(" ❌ No location data available") + # Try to geocode + success = service.geocode_park_if_needed(park) + if success: + coords = getattr(park, "coordinates", None) + latlon = _format_coords(coords) + if latlon: + print(f" βœ… Geocoded to: {latlon[0]:.4f}, {latlon[1]:.4f}") + else: + print(" βœ… Geocoded but coordinates unavailable") + else: + print(" ❌ Geocoding failed") + else: + print(" ❌ No location data available") def demo_cache_performance(): - """ - Demonstrate caching performance benefits. - """ - print("\n\n⚑ Cache Performance Demo") - print("=" * 50) + """ + Demonstrate caching performance benefits. + """ + print("\n\n⚑ Cache Performance Demo") + print("=" * 50) - service = RoadTripService() + service = RoadTripService() - import time + import time - # Test address for geocoding - test_address = "Disneyland, Anaheim, CA" + # Test address for geocoding + 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) - print("\n1️⃣ First request (cache miss):") - start_time = time.time() - coords1 = service.geocode_address(test_address) - first_duration = time.time() - start_time + # First request (cache miss) + print("\n1️⃣ First request (cache miss):") + start_time = time.time() + coords1 = service.geocode_address(test_address) + first_duration = time.time() - start_time - if coords1: - print(f" βœ… Result: {coords1.latitude:.4f}, {coords1.longitude:.4f}") - print(f" ⏱️ Duration: {first_duration:.2f} seconds") + if coords1: + latlon = _format_coords(coords1) + 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) - print("\n2️⃣ Second request (cache hit):") - start_time = time.time() - coords2 = service.geocode_address(test_address) - second_duration = time.time() - start_time + # Second request (cache hit) + print("\n2️⃣ Second request (cache hit):") + start_time = time.time() + coords2 = service.geocode_address(test_address) + second_duration = time.time() - start_time - if coords2: - print(f" βœ… Result: {coords2.latitude:.4f}, {coords2.longitude:.4f}") - print(f" ⏱️ Duration: {second_duration:.2f} seconds") + if coords2: + latlon2 = _format_coords(coords2) + 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: - speedup = first_duration / second_duration - print(f" πŸš€ Cache speedup: {speedup:.1f}x faster") + if first_duration > second_duration and second_duration > 0: + speedup = first_duration / second_duration + print(f" πŸš€ Cache speedup: {speedup:.1f}x faster") - if ( - coords1.latitude == coords2.latitude - and coords1.longitude == coords2.longitude - ): - print(" βœ… Results identical (cache working)") + # Compare coordinates if both present + if coords1 and coords2: + latlon1 = _format_coords(coords1) + latlon2 = _format_coords(coords2) + if latlon1 and latlon2 and latlon1 == latlon2: + print(" βœ… Results identical (cache working)") def main(): - """ - Run all demonstration scenarios. - """ - print("🎒 ThrillWiki Road Trip Service Demo") - print("This demo shows practical usage scenarios for the OSM Road Trip Service") + """ + Run all demonstration scenarios. + """ + print("🎒 ThrillWiki Road Trip Service Demo") + print("This demo shows practical usage scenarios for the OSM Road Trip Service") - try: - demo_florida_theme_park_trip() - demo_cross_country_road_trip() - demo_database_integration() - demo_geocoding_fallback() - demo_cache_performance() + try: + demo_florida_theme_park_trip() + demo_cross_country_road_trip() + demo_database_integration() + demo_geocoding_fallback() + demo_cache_performance() - print("\n" + "=" * 50) - print("πŸŽ‰ Demo completed successfully!") - print("\nThe Road Trip Service is ready for integration into ThrillWiki!") - print("\nKey Features Demonstrated:") - print("βœ… Geocoding theme park addresses") - print("βœ… Route calculation with distance/time") - print("βœ… Multi-park trip optimization") - print("βœ… Database integration with Park models") - print("βœ… Caching for performance") - print("βœ… Rate limiting for OSM compliance") - print("βœ… Error handling and fallbacks") + print("\n" + "=" * 50) + print("πŸŽ‰ Demo completed successfully!") + print("\nThe Road Trip Service is ready for integration into ThrillWiki!") + print("\nKey Features Demonstrated:") + print("βœ… Geocoding theme park addresses") + print("βœ… Route calculation with distance/time") + print("βœ… Multi-park trip optimization") + print("βœ… Database integration with Park models") + print("βœ… Caching for performance") + print("βœ… Rate limiting for OSM compliance") + print("βœ… Error handling and fallbacks") - except Exception as e: - print(f"\n❌ Demo failed with error: {e}") - import traceback + except Exception as e: + print(f"\n❌ Demo failed with error: {e}") + import traceback - traceback.print_exc() + traceback.print_exc() if __name__ == "__main__": - main() + main() diff --git a/tests/test_location_models.py b/tests/test_location_models.py index 83dfd36e..6d0d0de5 100644 --- a/tests/test_location_models.py +++ b/tests/test_location_models.py @@ -2,8 +2,8 @@ """ Basic test script to verify RideLocation and CompanyHeadquarters models work correctly. """ -from rides.models import Ride, RideLocation -from parks.models import Company, CompanyHeadquarters +from apps.rides.models import Ride, RideLocation +from apps.parks.models import Company, CompanyHeadquarters import os import sys import django @@ -23,11 +23,11 @@ def test_company_headquarters(): print("⚠️ No existing companies found, skipping CompanyHeadquarters test") return None, None - # Check if headquarters already exist - try: - headquarters = existing_company.headquarters + # Check if headquarters already exist (use queryset lookup to avoid relying on a reverse attribute name) + headquarters = CompanyHeadquarters.objects.filter(company=existing_company).first() + if headquarters: print(f"βœ“ Found existing headquarters: {headquarters}") - except CompanyHeadquarters.DoesNotExist: + else: # Create headquarters for existing company headquarters = CompanyHeadquarters.objects.create( company=existing_company, @@ -53,7 +53,13 @@ def test_ride_location(): # First, we need a ride - let's check if any exist if Ride.objects.exists(): 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: print("! No rides found in database - skipping RideLocation test") return None, None @@ -93,9 +99,9 @@ def cleanup_test_data(company=None, headquarters=None, ride_location=None): headquarters.delete() print("βœ“ Deleted test headquarters") - if company: - company.delete() - print("βœ“ Deleted test company") + # Do not delete an existing company record discovered in the database. + # Tests should avoid removing production/existing data. If a test created a Company + # instance explicitly, add logic to delete it here (not implemented by default). def main(): diff --git a/tests/test_manual_trigger.py b/tests/test_manual_trigger.py index 129f4c34..2bbe8ab0 100644 --- a/tests/test_manual_trigger.py +++ b/tests/test_manual_trigger.py @@ -46,7 +46,7 @@ def test_trigger_endpoint(token): "Content-Type": "application/json" } - print(f"\nπŸš€ Testing manual trigger endpoint...") + print("\nπŸš€ Testing manual trigger endpoint...") print(f"URL: {trigger_url}") response = requests.post(trigger_url, headers=headers) @@ -72,7 +72,7 @@ def test_trigger_endpoint(token): def test_trending_endpoints(): """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 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 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] print(f" Name: {first_item.get('name')}") # Should be park name, not location @@ -124,12 +124,12 @@ def test_trending_endpoints(): print( f" ❌ ERROR: 'location' field still present: {first_item['location']}") else: - print(f" βœ… SUCCESS: 'location' field removed as requested") + print(" βœ… SUCCESS: 'location' field removed as requested") def test_unauthorized_access(): """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/" @@ -169,7 +169,7 @@ def main(): trigger_result = test_trigger_endpoint(token) 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) # Test the trending endpoints to see results diff --git a/tests/test_park_location.py b/tests/test_park_location.py index fcc2fb5c..90bf53ef 100644 --- a/tests/test_park_location.py +++ b/tests/test_park_location.py @@ -2,7 +2,7 @@ """ Test script for ParkLocation model functionality """ -from parks.models import Park, ParkLocation, Company +from apps.parks.models import Park, ParkLocation, Company import os import django diff --git a/tests/test_roadtrip_service.py b/tests/test_roadtrip_service.py index 0917f334..cf8d2987 100644 --- a/tests/test_roadtrip_service.py +++ b/tests/test_roadtrip_service.py @@ -9,14 +9,21 @@ This script tests all functionality of the OSM Road Trip Service including: - 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 parks.models import Park -from parks.services.roadtrip import Coordinates -from parks.services import RoadTripService import os +import sys 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") django.setup() @@ -40,16 +47,13 @@ def test_geocoding(): print(f"\nGeocoding: {address}") coords = service.geocode_address(address) if coords: - print( - f" βœ… Success: { - coords.latitude:.6f}, { - coords.longitude:.6f}" - ) + # fixed: single-line f-string formatting + print(f" βœ… Success: {coords.latitude:.6f}, {coords.longitude:.6f}") else: - print(f" ❌ Failed") + print(" ❌ Failed") # Test cache functionality - print(f"\nTesting cache...") + print("\nTesting cache...") coords1 = service.geocode_address("Cedar Point, Sandusky, Ohio") coords2 = service.geocode_address("Cedar Point, Sandusky, Ohio") if coords1 and coords2: @@ -66,30 +70,30 @@ def test_route_calculation(): cedar_point = Coordinates(41.4793, -82.6833) 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) if route: - print(f" βœ… Success:") + print(" βœ… Success:") print(f" Distance: {route.formatted_distance}") print(f" Duration: {route.formatted_duration}") print(f" Geometry: {'Yes' if route.geometry else 'No'}") else: - print(f" ❌ Failed") + print(" ❌ Failed") # Test short distance (should use OSRM) disneyland = Coordinates(33.8121, -117.9190) 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) if route: - print(f" βœ… Success:") + print(" βœ… Success:") print(f" Distance: {route.formatted_distance}") print(f" Duration: {route.formatted_duration}") else: - print(f" ❌ Failed") + print(" ❌ Failed") def test_park_integration(): @@ -108,24 +112,25 @@ def test_park_integration(): print(f"Found {len(parks)} parks to test with:") for park in parks: print(f" - {park.name}") - if hasattr(park, "location") and park.location: - coords = park.coordinates + # Use getattr to safely access the optional related attribute and avoid static type warnings. + location = getattr(park, "location", None) + if location: + coords = getattr(park, "coordinates", None) if coords: print(f" πŸ“ {coords[0]:.4f}, {coords[1]:.4f}") else: - print(f" πŸ“ No coordinates, will try to geocode...") + print(" πŸ“ No coordinates, will try to geocode...") success = service.geocode_park_if_needed(park) if success: - coords = park.coordinates - print( - f" βœ… Geocoded to: { - coords[0]:.4f}, { - coords[1]:.4f}" - ) + coords = getattr(park, "coordinates", None) + if coords: + print(f" βœ… Geocoded to: {coords[0]:.4f}, {coords[1]:.4f}") + else: + print(" ❌ Geocoding succeeded but coordinates still missing") else: - print(f" ❌ Geocoding failed") + print(" ❌ Geocoding failed") else: - print(f" ❌ No location data") + print(" ❌ No location data") def test_nearby_parks(): @@ -153,13 +158,9 @@ def test_nearby_parks(): for result in nearby_parks[:5]: # Show first 5 park = result["park"] print( - f" { - park.name}: { - result['formatted_distance']}, { - result['formatted_duration']}" - ) + f" {park.name}: {result['formatted_distance']}, {result['formatted_duration']}") else: - print(f" ❌ No nearby parks found") + print(" ❌ No nearby parks found") def test_route_park_discovery(): @@ -180,11 +181,7 @@ def test_route_park_discovery(): start_park = parks_with_location[0] end_park = parks_with_location[1] - print( - f"Finding parks along route from { - start_park.name} to { - end_park.name}..." - ) + print(f"Finding parks along route from {start_park.name} to {end_park.name}...") parks_along_route = service.find_parks_along_route( 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 print(f" - {park.name}") else: - print(f" ❌ No parks found along route") + print(" ❌ No parks found along route") def test_multi_park_trip(): @@ -221,19 +218,16 @@ def test_multi_park_trip(): trip = service.create_multi_park_trip(parks_list) if trip: - print(f" βœ… Trip planned successfully:") + print(" βœ… Trip planned successfully:") print(f" Total Distance: {trip.formatted_total_distance}") print(f" Total Duration: {trip.formatted_total_duration}") - print(f" Route:") + print(" Route:") for i, leg in enumerate(trip.legs, 1): print(f" {i}. {leg.from_park.name} β†’ {leg.to_park.name}") print( - f" { - leg.route.formatted_distance}, { - leg.route.formatted_duration}" - ) + f" {leg.route.formatted_distance}, {leg.route.formatted_duration}") else: - print(f" ❌ Trip planning failed") + print(" ❌ Trip planning failed") def test_error_handling(): @@ -249,28 +243,28 @@ def test_error_handling(): route = service.calculate_route(invalid_coords, valid_coords) if route: - print( - f" ⚠️ Got route with invalid coords: { - route.formatted_distance}" - ) + print(f" ⚠️ Got route with invalid coords: {route.formatted_distance}") else: - print(f" βœ… Correctly handled invalid coordinates") + print(" βœ… Correctly handled invalid coordinates") # Test with empty address print("Testing empty address geocoding...") coords = service.geocode_address("") if coords: - print(f" ⚠️ Got coordinates for empty address") + print(" ⚠️ Got coordinates for empty address") else: - print(f" βœ… Correctly handled empty address") + print(" βœ… Correctly handled empty address") # Test with None values 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: - print(f" ⚠️ Got route with None coordinates") + print(" ⚠️ Got route with None coordinates") else: - print(f" βœ… Correctly handled None coordinates") + print(" βœ… Correctly handled None coordinates") def test_rate_limiting(): @@ -294,19 +288,15 @@ def test_rate_limiting(): for address in addresses: coords = service.geocode_address(address) if coords: - print( - f" βœ… {address}: { - coords.latitude:.4f}, { - coords.longitude:.4f}" - ) + print(f" βœ… {address}: {coords.latitude:.4f}, {coords.longitude:.4f}") elapsed = time.time() - start_time 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 - print(f" βœ… Rate limiting appears to be working") + print(" βœ… Rate limiting appears to be working") 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(): diff --git a/tests/test_unified_map_service.py b/tests/test_unified_map_service.py index cb3adb27..c8620a78 100644 --- a/tests/test_unified_map_service.py +++ b/tests/test_unified_map_service.py @@ -4,16 +4,24 @@ Test script for the unified map service. 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 sys 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") 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(): """Test basic map service functionality.""" @@ -215,7 +223,7 @@ def test_performance(): print(f" Max time: {max(times):.2f}ms") # Test cache performance - print(f"\n Testing cache performance:") + print("\n Testing cache performance:") start = time.time() response1 = unified_map_service.get_map_data(zoom_level=10, use_cache=True) time1 = time.time() - start