blob: 5735fa0a83f3ec211e3aa463a13c557e912ec826 [file]
#!/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()