| from __future__ import annotations | |
| from typing import Any, Dict | |
| import pandas as pd | |
| TASK1_DIRTY = [ | |
| {"name": "Alice Johnson", "email": "alice@email.com", "country": "USA", "age": 28.0}, | |
| {"name": "Bob Smith", "email": "bob@email.com", "country": "United States", "age": None}, | |
| {"name": "Carol White", "email": "carol@email.com", "country": "UK", "age": 35.0}, | |
| {"name": "Alice Johnson", "email": "alice@email.com", "country": "USA", "age": 28.0}, | |
| {"name": "Dave Brown", "email": None, "country": "US", "age": 42.0}, | |
| {"name": "Eve Davis", "email": "eve@email.com", "country": "United Kingdom", "age": 31.0}, | |
| {"name": "Frank Miller", "email": "frank@email.com", "country": "Canada", "age": None}, | |
| {"name": "Grace Wilson", "email": "grace@email.com", "country": "CAN", "age": 25.0}, | |
| {"name": "Henry Moore", "email": "henry@email.com", "country": "australia", "age": 38.0}, | |
| {"name": "Iris Taylor", "email": "iris@email.com", "country": "AUS", "age": 29.0}, | |
| ] | |
| TASK1_DESCRIPTION = ( | |
| "Clean a customer dataset. Issues to fix:\n" | |
| "1) Remove exact duplicate rows\n" | |
| "2) Fill missing emails using constant 'unknown@email.com'\n" | |
| "3) Fill missing ages using median\n" | |
| "4) Standardize country names to United States, United Kingdom, Canada, Australia" | |
| ) | |
| TASK2_DIRTY = [ | |
| { | |
| "order_id": 1, | |
| "date": "2023-01-15", | |
| "product": "Laptop", | |
| "category": "Electronics", | |
| "price": "$1200.00", | |
| "quantity": 2, | |
| }, | |
| { | |
| "order_id": 2, | |
| "date": "02/20/2023", | |
| "product": "Chair", | |
| "category": "Furniture", | |
| "price": "$250.50", | |
| "quantity": 1, | |
| }, | |
| { | |
| "order_id": 3, | |
| "date": "Mar 10, 2023", | |
| "product": "Headphones", | |
| "category": "Electronics", | |
| "price": "$89.99", | |
| "quantity": 3, | |
| }, | |
| { | |
| "order_id": 4, | |
| "date": "2023-04-05", | |
| "product": "Desk", | |
| "category": "Furnitre", | |
| "price": "$450.00", | |
| "quantity": 1, | |
| }, | |
| { | |
| "order_id": 5, | |
| "date": "05/12/2023", | |
| "product": "Monitor", | |
| "category": "Electronics", | |
| "price": "320.00", | |
| "quantity": 2, | |
| }, | |
| { | |
| "order_id": 6, | |
| "date": "2023-06-18", | |
| "product": "Keyboard", | |
| "category": None, | |
| "price": "$75.00", | |
| "quantity": 5, | |
| }, | |
| { | |
| "order_id": 7, | |
| "date": "July 22 2023", | |
| "product": "Mouse", | |
| "category": "Electronics", | |
| "price": "$35.00", | |
| "quantity": 4, | |
| }, | |
| { | |
| "order_id": 8, | |
| "date": "2023-08-30", | |
| "product": "Bookshelf", | |
| "category": "Furniture", | |
| "price": None, | |
| "quantity": 1, | |
| }, | |
| { | |
| "order_id": 9, | |
| "date": "09-14-2023", | |
| "product": "Webcam", | |
| "category": "ELECTRONICS", | |
| "price": "$65.00", | |
| "quantity": 2, | |
| }, | |
| { | |
| "order_id": 10, | |
| "date": "2023-10-01", | |
| "product": "Lamp", | |
| "category": "Furniture", | |
| "price": "$45.00", | |
| "quantity": 3, | |
| }, | |
| { | |
| "order_id": 11, | |
| "date": "11/15/2023", | |
| "product": "Tablet", | |
| "category": "Electronix", | |
| "price": "$599.00", | |
| "quantity": 1, | |
| }, | |
| { | |
| "order_id": 12, | |
| "date": "2023-12-20", | |
| "product": "Sofa", | |
| "category": "Furniture", | |
| "price": "$1100.00", | |
| "quantity": 1, | |
| }, | |
| ] | |
| TASK2_DESCRIPTION = ( | |
| "Clean an e-commerce orders dataset. Issues to fix:\n" | |
| "1) Normalise all dates to YYYY-MM-DD format using convert_type(date, datetime)\n" | |
| "2) Convert price column to float (strips $ signs automatically)\n" | |
| "3) Standardise category typos: Furnitre to Furniture, ELECTRONICS to Electronics, Electronix to Electronics\n" | |
| "4) Fill missing price with median; fill or remove missing category rows" | |
| ) | |
| TASK3_DIRTY = [ | |
| {"user_id": "U001", "name": "Alice Johnson", "page_views": 45, "session_duration": 320, "bounce_rate": 0.25}, | |
| {"user_id": "U001", "name": "Alice J.", "page_views": 45, "session_duration": 315, "bounce_rate": 0.25}, | |
| {"user_id": "U002", "name": "Bob Smith", "page_views": 12, "session_duration": 85000, "bounce_rate": 0.80}, | |
| {"user_id": "U003", "name": "Carol White", "page_views": 67, "session_duration": 450, "bounce_rate": 0.15}, | |
| {"user_id": "U004", "name": "Dave Brown", "page_views": 23, "session_duration": 190, "bounce_rate": 0.55}, | |
| {"user_id": "U005", "name": "Eve Davis", "page_views": 89, "session_duration": 95000, "bounce_rate": 0.10}, | |
| {"user_id": "U003", "name": "Carol White", "page_views": 67, "session_duration": 450, "bounce_rate": 0.15}, | |
| {"user_id": "U006", "name": "Frank Miller", "page_views": None, "session_duration": 280, "bounce_rate": 0.45}, | |
| {"user_id": "U007", "name": "Grace Wilson", "page_views": 34, "session_duration": 360, "bounce_rate": 1.50}, | |
| {"user_id": "U008", "name": "Henry Moore", "page_views": 56, "session_duration": 420, "bounce_rate": 0.35}, | |
| {"user_id": "U009", "name": "Iris Taylor", "page_views": 78, "session_duration": 78000, "bounce_rate": 0.20}, | |
| {"user_id": "U010", "name": "Jack Wilson", "page_views": 19, "session_duration": 150, "bounce_rate": 0.70}, | |
| ] | |
| TASK3_DESCRIPTION = ( | |
| "Clean a web analytics dataset. Issues to fix:\n" | |
| "1) Remove duplicate user_ids (exact + near-duplicates, keep first occurrence)\n" | |
| "2) Clip session_duration outliers to max 1000 seconds\n" | |
| "3) Clip bounce_rate to valid range [0.0, 1.0]\n" | |
| "4) Fill missing page_views with median" | |
| ) | |
| TASK4_DESCRIPTION = ( | |
| "Alternative medium data-cleaning scenario based on e-commerce orders.\n" | |
| "Use the same cleaning operations as task2_medium and submit a clean table." | |
| ) | |
| TASK5_DESCRIPTION = ( | |
| "Alternative hard data-cleaning scenario based on analytics logs.\n" | |
| "Use the same cleaning operations as task3_hard and submit a clean table." | |
| ) | |
| TASK_GRADER_ENTRYPOINTS_COLON = { | |
| "task1_easy": "env.graders:grade_task1_easy", | |
| "task2_medium": "env.graders:grade_task2_medium", | |
| "task3_hard": "env.graders:grade_task3_hard", | |
| "task4_medium_alt": "env.graders:grade_task4_medium_alt", | |
| "task5_hard_alt": "env.graders:grade_task5_hard_alt", | |
| } | |
| TASK_GRADER_ENTRYPOINTS_DOTTED = { | |
| "task1_easy": "env.graders.grade_task1_easy", | |
| "task2_medium": "env.graders.grade_task2_medium", | |
| "task3_hard": "env.graders.grade_task3_hard", | |
| "task4_medium_alt": "env.graders.grade_task4_medium_alt", | |
| "task5_hard_alt": "env.graders.grade_task5_hard_alt", | |
| } | |
| def get_task(task_id: str) -> Dict[str, Any]: | |
| registry = { | |
| "task1_easy": { | |
| "description": TASK1_DESCRIPTION, | |
| "dirty_df": pd.DataFrame(TASK1_DIRTY), | |
| "task_id": "task1_easy", | |
| "difficulty": "easy", | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task1_easy"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task1_easy"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task1_easy"], | |
| }, | |
| "task2_medium": { | |
| "description": TASK2_DESCRIPTION, | |
| "dirty_df": pd.DataFrame(TASK2_DIRTY), | |
| "task_id": "task2_medium", | |
| "difficulty": "medium", | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task2_medium"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task2_medium"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task2_medium"], | |
| }, | |
| "task3_hard": { | |
| "description": TASK3_DESCRIPTION, | |
| "dirty_df": pd.DataFrame(TASK3_DIRTY), | |
| "task_id": "task3_hard", | |
| "difficulty": "hard", | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task3_hard"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task3_hard"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task3_hard"], | |
| }, | |
| "task4_medium_alt": { | |
| "description": TASK4_DESCRIPTION, | |
| "dirty_df": pd.DataFrame(TASK2_DIRTY), | |
| "task_id": "task4_medium_alt", | |
| "difficulty": "medium", | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task4_medium_alt"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task4_medium_alt"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task4_medium_alt"], | |
| }, | |
| "task5_hard_alt": { | |
| "description": TASK5_DESCRIPTION, | |
| "dirty_df": pd.DataFrame(TASK3_DIRTY), | |
| "task_id": "task5_hard_alt", | |
| "difficulty": "hard", | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task5_hard_alt"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task5_hard_alt"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task5_hard_alt"], | |
| }, | |
| } | |
| if task_id not in registry: | |
| raise ValueError(f"Unknown task_id '{task_id}'. Choose from: {list(registry)}") | |
| cfg = registry[task_id] | |
| cfg["dirty_df"] = cfg["dirty_df"].copy() | |
| return cfg | |
| TASK_IDS = ["task1_easy", "task2_medium", "task3_hard", "task4_medium_alt", "task5_hard_alt"] | |
| def list_tasks() -> list[dict[str, Any]]: | |
| return [ | |
| { | |
| "id": "task1_easy", | |
| "task_id": "task1_easy", | |
| "difficulty": "easy", | |
| "max_steps": 20, | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task1_easy"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task1_easy"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task1_easy"], | |
| }, | |
| { | |
| "id": "task2_medium", | |
| "task_id": "task2_medium", | |
| "difficulty": "medium", | |
| "max_steps": 20, | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task2_medium"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task2_medium"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task2_medium"], | |
| }, | |
| { | |
| "id": "task3_hard", | |
| "task_id": "task3_hard", | |
| "difficulty": "hard", | |
| "max_steps": 20, | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task3_hard"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task3_hard"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task3_hard"], | |
| }, | |
| { | |
| "id": "task4_medium_alt", | |
| "task_id": "task4_medium_alt", | |
| "difficulty": "medium", | |
| "max_steps": 20, | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task4_medium_alt"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task4_medium_alt"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task4_medium_alt"], | |
| }, | |
| { | |
| "id": "task5_hard_alt", | |
| "task_id": "task5_hard_alt", | |
| "difficulty": "hard", | |
| "max_steps": 20, | |
| "grader": TASK_GRADER_ENTRYPOINTS_COLON["task5_hard_alt"], | |
| "grader_fn": TASK_GRADER_ENTRYPOINTS_COLON["task5_hard_alt"], | |
| "grader_path": TASK_GRADER_ENTRYPOINTS_COLON["task5_hard_alt"], | |
| }, | |
| ] | |