Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
## 2026-03-30 - [Demo Scale vs. Terminal Readability]
**Learning:** For demo scripts, larger data sets can degrade the UX by flooding the terminal with logs, making it harder for users to see the structure of the output.
**Action:** Limit the default number of items in demo loops (e.g., 5 items) to maintain a high signal-to-noise ratio while still demonstrating the functionality.

## 2026-03-31 - [Visual Polish for CLI Summaries]
**Learning:** In CLI-based workflow scaffolds, replacing raw success messages with structured `rich.table.Table` summaries significantly improves the professional feel and readability of the output. Additionally, zero-padding generated IDs (e.g., 'customer-01') ensures natural sorting and vertical alignment, which reduces cognitive load when scanning lists. Finally, adding minimal artificial delays (e.g., `time.sleep(0.1)`) in demo scripts makes the "work" visible by giving terminal spinners and status indicators enough time to register with the user.
**Action:** Use structured tables for final execution summaries, ensure all generated IDs are zero-padded for alignment, and include brief pacing pauses in demo tasks to make the execution flow more perceptible.
33 changes: 28 additions & 5 deletions 01_getting_started.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,64 @@
from prefect import flow, task
import random
import time
from rich.console import Console
from rich.panel import Panel
from rich.rule import Rule
from rich.table import Table

console = Console()


@task
def get_customer_ids() -> list[str]:
# Fetch customer IDs from a database or API
return [f"customer{n}" for n in random.choices(range(100), k=5)]
"""Fetch customer IDs from a database or API."""
# Use sorted and zero-padded IDs for better terminal alignment
ids = [f"customer-{n:02d}" for n in random.choices(range(100), k=5)]
return sorted(ids)


@task
def process_customer(customer_id: str) -> str:
# Process a single customer
"""Process a single customer."""
# Add a brief pause to make the processing state visible in the UI
time.sleep(0.1)
return f"Processed {customer_id}"


@flow(log_prints=True)
def main():
"""
### 🚀 Getting Started with Prefect

This flow demonstrates how to map a task over a list of inputs.
It fetches a list of customer IDs and processes each one individually.
"""
with console.status("[bold green]Fetching customer data..."):
customer_ids = get_customer_ids()

# Map the process_customer task across all customer IDs
console.print(f"[bold blue]📦 Fetched {len(customer_ids)} customer IDs[/bold blue]")

with console.status("[bold green]Processing customers..."):
results = process_customer.map(customer_ids)
futures = process_customer.map(customer_ids)
# Explicitly wait for results to avoid AttributeErrors on futures
results = [f.result() for f in futures]

# Display results in a clean table for better readability
table = Table(
title="Processing Summary", show_header=True, header_style="bold blue"
)
table.add_column("Customer ID", style="cyan")
table.add_column("Status", style="green")

for res in results:
# Extract the customer ID from the result string (e.g., "Processed customer-01")
customer_id = res.split()[-1]
table.add_row(customer_id, "✅ Success")

console.print()
console.print(table)
console.print()

console.print(
Panel.fit(
f"[bold green]✅ Successfully processed {len(results)} customers![/bold green]",
Expand Down
32 changes: 27 additions & 5 deletions 02_logging.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
from prefect import flow, task
from prefect.logging import get_run_logger
import random
import time
from rich.console import Console
from rich.panel import Panel
from rich.rule import Rule
from rich.table import Table

console = Console()


@task
def get_customer_ids() -> list[str]:
# Fetch customer IDs from a database or API
return [f"customer{n}" for n in random.choices(range(100), k=5)]
"""Fetch customer IDs from a database or API."""
# Use sorted and zero-padded IDs for better terminal alignment
ids = [f"customer-{n:02d}" for n in random.choices(range(100), k=5)]
return sorted(ids)


@task
def process_customer(customer_id: str) -> str:
# Process a single customer
"""Process a single customer."""
logger = get_run_logger()
for _ in range(3):
# Add a brief pause to make the logging visible and realistic
time.sleep(0.05)
logger.info(f"Processing customer {customer_id}")
return f"Processed {customer_id}"

Expand All @@ -39,13 +45,29 @@ def main():
with console.status("[bold green]Fetching customer data..."):
customer_ids = get_customer_ids()

# Map the process_customer task across all customer IDs
console.print(f"[bold blue]📦 Fetched {len(customer_ids)} customer IDs[/bold blue]")

with console.status("[bold green]Processing customers with logging..."):
results = process_customer.map(customer_ids)
futures = process_customer.map(customer_ids)
# Explicitly wait for results to avoid AttributeErrors on futures
results = [f.result() for f in futures]

# Display results in a clean table for better readability
table = Table(
title="Processing Summary", show_header=True, header_style="bold blue"
)
table.add_column("Customer ID", style="cyan")
table.add_column("Status", style="green")

for res in results:
# Extract the customer ID from the result string (e.g., "Processed customer-01")
customer_id = res.split()[-1]
table.add_row(customer_id, "✅ Success")

console.print()
console.print(table)
console.print()

console.print(
Panel.fit(
f"[bold green]✅ Successfully processed {len(results)} customers with detailed logging![/bold green]",
Expand Down
Loading