| #!/usr/bin/env python3 | |
| # Licensed to the Apache Software Foundation (ASF) under one | |
| # or more contributor license agreements. See the NOTICE file | |
| # distributed with this work for additional information | |
| # regarding copyright ownership. The ASF licenses this file | |
| # to you under the Apache License, Version 2.0 (the | |
| # "License"); you may not use this file except in compliance | |
| # with the License. You may obtain a copy of the License at | |
| # | |
| # http://www.apache.org/licenses/LICENSE-2.0 | |
| # | |
| # Unless required by applicable law or agreed to in writing, | |
| # software distributed under the License is distributed on an | |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| # KIND, either express or implied. See the License for the | |
| # specific language governing permissions and limitations | |
| # under the License. | |
| """ | |
| Simple test script to validate Hamilton UI tracking. | |
| This script will: | |
| 1. Check if the Hamilton UI is running | |
| 2. Guide you through creating a project if needed | |
| 3. Run a simple DAG with tracking enabled | |
| 4. Display the results and links to view in the UI | |
| Usage: | |
| # Make sure the UI server is running: | |
| hamilton ui | |
| # Then run this script (optionally with a user name for API calls): | |
| python ui/test_tracking_simple.py | |
| python ui/test_tracking_simple.py --user my-username | |
| python ui/test_tracking_simple.py --dag dataframe # DataFrame-based DAG | |
| """ | |
| import argparse | |
| import sys | |
| import pandas as pd | |
| import requests | |
| from hamilton import driver | |
| def _parse_args(): | |
| parser = argparse.ArgumentParser(description="Hamilton UI Tracking Test") | |
| parser.add_argument( | |
| "--user", | |
| default="test-user", | |
| help="User name to use for API calls (x-api-user and tracker username)", | |
| ) | |
| parser.add_argument( | |
| "--dag", | |
| choices=["simple", "dataframe"], | |
| default="simple", | |
| help="DAG to run: 'simple' (default) or 'dataframe' (DataFrame-based)", | |
| ) | |
| return parser.parse_args() | |
| args = _parse_args() | |
| USER_NAME = args.user | |
| print("=" * 70) | |
| print("Hamilton UI Tracking Test") | |
| print("=" * 70) | |
| print(f"User: {USER_NAME}") | |
| print() | |
| # Step 1: Check if UI is running | |
| print("🔍 Checking Hamilton UI connection...") | |
| try: | |
| response = requests.get("http://localhost:8241/", timeout=5) | |
| if response.status_code == 200: | |
| print("✅ Hamilton UI is running at http://localhost:8241") | |
| else: | |
| print(f"⚠️ Unexpected response: {response.status_code}") | |
| except requests.exceptions.RequestException as e: | |
| print("❌ Cannot connect to Hamilton UI at http://localhost:8241") | |
| print(f" Error: {e}") | |
| print() | |
| print("Please start the Hamilton UI server first:") | |
| print(" hamilton ui") | |
| sys.exit(1) | |
| print() | |
| # Step 2: Check for projects | |
| print("📋 Checking for existing projects...") | |
| try: | |
| response = requests.get( | |
| "http://localhost:8241/api/v1/projects", | |
| headers={"x-api-user": USER_NAME, "x-api-key": "test-key"}, | |
| timeout=5, | |
| ) | |
| projects = response.json() | |
| if not projects: | |
| print("⚠️ No projects found.") | |
| print() | |
| print(" The user name must match the one used in the UI; otherwise no") | |
| print(" projects are returned for this user. (Current user: --user " + USER_NAME + ")") | |
| print() | |
| print("📝 Please create a project in the UI first:") | |
| print() | |
| print(" 1. Open: http://localhost:8241/dashboard/projects") | |
| print(" 2. Click 'Create Project'") | |
| print(" 3. Fill in:") | |
| print(" - Name: Test Project") | |
| print(" - Description: Testing Hamilton tracking") | |
| print(" - Visibility: Public") | |
| print(" 4. Note the Project ID (should be 1)") | |
| print() | |
| print("Then run this script again (with the same user name if needed).") | |
| print() | |
| # Try to open browser | |
| try: | |
| import webbrowser | |
| webbrowser.open("http://localhost:8241/dashboard/projects") | |
| print("✅ Opened browser to create project") | |
| except Exception: | |
| pass | |
| sys.exit(0) | |
| else: | |
| print(f"✅ Found {len(projects)} project(s):") | |
| for proj in projects[:3]: # Show first 3 | |
| print(f" - Project {proj['id']}: {proj['name']}") | |
| project_id = projects[0]["id"] | |
| print() | |
| print(f"📦 Using Project ID: {project_id}") | |
| except Exception as e: | |
| print(f"❌ Error checking projects: {e}") | |
| sys.exit(1) | |
| print() | |
| # Step 3: Create and run a Hamilton DAG | |
| if args.dag == "dataframe": | |
| DAG_OUTPUTS = ["average", "sum_all", "x_squared", "y_doubled"] | |
| DAG_NAME = "test_tracking_dag" | |
| else: | |
| DAG_OUTPUTS = ["average_squared", "sum_squared"] | |
| DAG_NAME = "simple_test_dag" | |
| print("🚀 Creating Hamilton DAG (" + args.dag + ")...") | |
| # Define simple Hamilton functions inline | |
| def input_numbers() -> pd.Series: | |
| """Generate input numbers.""" | |
| return pd.Series([1, 2, 3, 4, 5]) | |
| def squared(input_numbers: pd.Series) -> pd.Series: | |
| """Square the numbers.""" | |
| return input_numbers**2 | |
| def sum_squared(squared: pd.Series) -> float: | |
| """Sum of squared numbers.""" | |
| return squared.sum() | |
| def average_squared(sum_squared: float, input_numbers: pd.Series) -> float: | |
| """Average of squared numbers.""" | |
| return sum_squared / len(input_numbers) | |
| # DataFrame-based DAG (--dag dataframe) | |
| def input_data() -> pd.DataFrame: | |
| """Create sample input data.""" | |
| return pd.DataFrame({"x": [1, 2, 3, 4, 5], "y": [2, 4, 6, 8, 10]}) | |
| def x_squared(input_data: pd.DataFrame) -> pd.Series: | |
| """Square the x column.""" | |
| return input_data["x"] ** 2 | |
| def y_doubled(input_data: pd.DataFrame) -> pd.Series: | |
| """Double the y column.""" | |
| return input_data["y"] * 2 | |
| def sum_all(x_squared: pd.Series, y_doubled: pd.Series) -> float: | |
| """Sum all values.""" | |
| return x_squared.sum() + y_doubled.sum() | |
| def average(sum_all: float, input_data: pd.DataFrame) -> float: | |
| """Calculate average.""" | |
| total_elements = len(input_data) * 2 # x and y columns | |
| return sum_all / total_elements | |
| # Build driver WITHOUT tracking first (to test basic functionality) | |
| print(" Building DAG...") | |
| dr = driver.Builder().with_modules(sys.modules[__name__]).build() | |
| print(" DAG created successfully!") | |
| if args.dag == "dataframe": | |
| print() | |
| print("📈 DAG structure:") | |
| dr.display_all_functions() | |
| print() | |
| # Step 4: Execute without tracking | |
| print("▶️ Executing DAG (without tracking)...") | |
| result = dr.execute(DAG_OUTPUTS) | |
| print() | |
| print("Results:") | |
| if args.dag == "dataframe": | |
| for key, value in result.items(): | |
| if isinstance(value, pd.Series): | |
| print(f" {key}:") | |
| print(value.to_string()) | |
| else: | |
| print(f" {key}: {value}") | |
| else: | |
| print(f" - sum_squared: {result['sum_squared']}") | |
| print(f" - average_squared: {result['average_squared']}") | |
| print() | |
| # Step 5: Now execute WITH tracking | |
| print("🔄 Executing with Hamilton UI tracking...") | |
| try: | |
| from hamilton_sdk import adapters | |
| tracker = adapters.HamiltonTracker( | |
| project_id=project_id, | |
| username=USER_NAME, | |
| dag_name=DAG_NAME, | |
| tags={"test": "true", "environment": "local"}, | |
| hamilton_api_url="http://localhost:8241", | |
| hamilton_ui_url="http://localhost:8241", | |
| api_key="test-key", | |
| ) | |
| # Rebuild driver with tracker | |
| dr_tracked = driver.Builder().with_modules(sys.modules[__name__]).with_adapters(tracker).build() | |
| # Execute | |
| result_tracked = dr_tracked.execute(DAG_OUTPUTS) | |
| print("✅ Execution tracked successfully!") | |
| print() | |
| print("=" * 70) | |
| print("🎉 Success! View your results:") | |
| print("=" * 70) | |
| print() | |
| print(f"📊 Dashboard: http://localhost:8241/dashboard/projects/{project_id}") | |
| print(f"📈 Project: http://localhost:8241/dashboard/project/{project_id}") | |
| print() | |
| print("You should see:") | |
| print(" - Your DAG execution in the project dashboard") | |
| print(" - Execution details including node values") | |
| print(" - DAG visualization") | |
| print() | |
| except ImportError: | |
| print("❌ hamilton-sdk not installed") | |
| print(" Install with: pip install apache-hamilton-sdk") | |
| except Exception as e: | |
| print(f"❌ Error during tracked execution: {e}") | |
| import traceback | |
| traceback.print_exc() |