Skip to content

Practice Workspace

Status: Canonical Reference
Scope: src/practice_workspace/ - Practice file history management
Related: Package README

Practice Workspace provides stateful management of practice file history and restore operations, enabling users to track their practice attempts over time.


Table of Contents

  1. Overview
  2. Scope
  3. Interfaces
  4. How It Fits in the System
  5. Typical Workflows
  6. Key Design Decisions
  7. File Naming Convention
  8. Failure Modes and Constraints
  9. Related Documentation

Overview

Practice Workspace is the state management layer for practice files. Unlike codegen (stateless generation), this module:

  • Tracks practice file versions over time
  • Provides history listing with relative timestamps
  • Enables restore to any previous version

Goals

Goal Description
Version Tracking Save practice files to _history/ directory
History Browsing List versions with timestamps and relative time
Easy Restore Restore specific or latest version
Minimal Footprint Filesystem-only, no external dependencies

Non-Goals

Non-Goal Reason
❌ Generate file content Handled by codegen
❌ Execute tests Handled by runner/
❌ Complex version control Simple timestamp-based backup
❌ Diff/merge functionality Out of scope

Scope

What this module handles

  • βœ… Saving practice files to _history/ directory
  • βœ… Listing historical versions with timestamps
  • βœ… Formatting relative time display ("2 hours ago")
  • βœ… Restoring specific or latest version
  • βœ… Path utilities for practice files

What this module explicitly avoids

  • ❌ File content generation (handled by codegen)
  • ❌ Test execution (handled by runner/)
  • ❌ Network operations (filesystem-only)
  • ❌ Problem data fetching (handled by leetcode_datasource)

Interfaces

High-level summary of public APIs. For complete API reference, see Package README.

Interface Purpose
save_to_history() Save current practice to history
list_history() List all history versions (formatted output)
get_history_entries() Get history entries as objects
restore_from_history() Restore specific version
restore_latest() Restore most recent version
HistoryEntry History entry data class

How It Fits in the System

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Workflow                               β”‚
β”‚                                                             β”‚
β”‚   codegen practice <id>                                     β”‚
β”‚         β”‚                                                   β”‚
β”‚         β–Ό                                                   β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚  1. Check if practices/<id>.py exists               β”‚  β”‚
β”‚   β”‚     └── If yes, call practice_workspace.save_to_history β”‚
β”‚   β”‚                                                      β”‚  β”‚
β”‚   β”‚  2. Generate new skeleton                           β”‚  β”‚
β”‚   β”‚                                                      β”‚  β”‚
β”‚   β”‚  3. Write to practices/<id>.py                      β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                             β”‚
β”‚   User commands: practice history / practice restore        β”‚
β”‚         β”‚                                                   β”‚
β”‚         β–Ό                                                   β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚   β”‚  practice_workspace handles listing/restore         β”‚  β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Directory Structure

practices/
β”œβ”€β”€ 0001_two_sum.py                    # Active practice file
β”œβ”€β”€ 0003_longest_substring.py          # Active practice file
β”‚
└── _history/                          # Version history
    β”œβ”€β”€ 0001_two_sum.py.20251225_200000.bak
    β”œβ”€β”€ 0001_two_sum.py.20251230_091500.bak
    β”œβ”€β”€ 0001_two_sum.py.20251231_143022.bak
    └── 0003_longest_substring.py.20251231_100000.bak

Module Relationships

Module Relationship
codegen Used by - Calls save_to_history() before regenerating
leetcode_datasource No direct dependency
runner No direct dependency
Package Relationship
codegen Generates practice skeletons, calls save_to_history()
leetcode_datasource No direct dependency

Dependency Direction

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                                                          β”‚
β”‚   βœ… codegen β†’ practice_workspace                        β”‚
β”‚   ❌ practice_workspace β†’ codegen (FORBIDDEN)            β”‚
β”‚   ❌ practice_workspace β†’ runner  (FORBIDDEN)            β”‚
β”‚                                                          β”‚
β”‚   practice_workspace is filesystem-only                  β”‚
β”‚   (stdlib dependencies only)                             β”‚
β”‚                                                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Typical Workflows

Workflow: Save to History

When codegen practice <id> finds an existing practice file:

save_to_history(Path("practices/0001_two_sum.py"))
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  1. Read current practice file content                  β”‚
β”‚  2. Generate timestamp: 20251231_143022                 β”‚
β”‚  3. Create backup filename: 0001_two_sum.py.20251231_143022.bak β”‚
β”‚  4. Write to practices/_history/                        β”‚
β”‚  5. Return backup path                                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Workflow: List History

list_history(problem_id=1)
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  1. Find all .bak files for problem 1 in _history/      β”‚
β”‚  2. Parse timestamps from filenames                     β”‚
β”‚  3. Sort by timestamp (oldest first)                    β”‚
β”‚  4. Format relative times ("2 hours ago")               β”‚
β”‚  5. Print formatted list with index numbers             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Output Example:

Practice history for 0001_two_sum:

  [1] 20251225_200000  (6 days ago)
  [2] 20251230_091500  (1 day ago)
  [3] 20251231_143022  (2 hours ago)   ← latest

Total: 3 versions

Workflow: Restore Version

restore_from_history(problem_id=1, timestamp="20251230_091500")
         β”‚
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  1. Find backup file matching timestamp                 β”‚
β”‚  2. Read backup content                                 β”‚
β”‚  3. Write to practices/0001_two_sum.py                  β”‚
β”‚  4. Return success message                              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Design Decisions

Decision Rationale
Stateful design History requires persistent state by nature
Filesystem-only No database needed; simple backup files
Timestamp-based naming Simple, sortable, unique identifiers
Oldest-first display Natural chronological order; latest at bottom
No automatic cleanup User controls when to delete old versions
Separate from codegen Clear responsibility separation

Design Philosophy

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  codegen = stateless                                     β”‚
β”‚  practice_workspace = stateful                           β”‚
β”‚                                                          β”‚
β”‚  This separation allows:                                 β”‚
β”‚  - codegen to focus purely on generation                β”‚
β”‚  - workspace to manage state independently              β”‚
β”‚  - Clear boundaries and testability                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

File Naming Convention

Backup Filename Format

<original_filename>.<timestamp>.bak

Timestamp Format

YYYYMMDD_HHMMSS

Examples:

Original Timestamp Backup
0001_two_sum.py 20251231_143022 0001_two_sum.py.20251231_143022.bak
0003_longest_substring.py 20251225_200000 0003_longest_substring.py.20251225_200000.bak

Failure Modes and Constraints

Constraint Behavior
Practice file not found Returns error message
No history exists Returns "No history found"
Invalid timestamp Returns "Version not found"
_history/ doesn't exist Creates directory automatically
File permission error Raises standard Python exception

Document Content
Package README Quick reference, API details
CodeGen Spec How codegen integrates with workspace
Solution Contract File format requirements

Appendix: CLI Commands

practice history

List practice history versions:

practice history <problem_id>

Output:

Practice history for 0001_two_sum:

  [1] 20251225_200000  (6 days ago)
  [2] 20251230_091500  (1 day ago)
  [3] 20251231_143022  (2 hours ago)   ← latest

Total: 3 versions

practice restore

Restore a specific version:

# Interactive mode (default)
practice restore <problem_id>

# Restore latest
practice restore <problem_id> --latest

# Restore specific timestamp
practice restore <problem_id> --at 20251230_091500

Interactive Example:

Available versions for 0001_two_sum:

  [1] 20251225_200000  (6 days ago)
  [2] 20251230_091500  (1 day ago)
  [3] 20251231_143022  (2 hours ago)   ← latest

Select version to restore [3]: 2

βœ… Restored: practices/0001_two_sum.py
   (from: 20251230_091500)