diff --git a/.cursor/rules/.cursorrules b/.cursor/rules/.cursorrules new file mode 100644 index 0000000..ecd9ed5 --- /dev/null +++ b/.cursor/rules/.cursorrules @@ -0,0 +1,8 @@ +# Cursor Rules + +- Tech stack: CPython 3.x scripts with standard library only. +- Follow repository layout documented in README and keep modules under `snippets/`. +- Prefer pure functions; keep functions under 30 lines or split logically. +- Debug via targeted unit tests (`pytest`) and lightweight logging with `print` only when necessary. +- Before major code edits, outline approach in PLANNED_INTERFACE.md and IMPLEMENTATION_PLAN.md; update TODO.md to track execution steps. +- New files belong in existing folders unless a strong reason exists; mirror naming conventions already in use. diff --git a/IMPLEMENTATION_PLAN.md b/IMPLEMENTATION_PLAN.md new file mode 100644 index 0000000..44182c0 --- /dev/null +++ b/IMPLEMENTATION_PLAN.md @@ -0,0 +1,28 @@ +# Implementation Plan + +## Overview +- Align helper modules in `snippets/` with the expectations captured in `main.py` and the accompanying tests. +- Focus on stateless helpers, predictable closures, and accurate export wiring so the CLI harness works without modification. + +## Folder Structure & Key Components +- `snippets/__init__.py`: acts as the package façade; must re-export all public helpers (`lambda_array`, IO utilities, `foo`). +- `snippets/loop.py`: produces lambda arrays whose closure behavior matches tests. +- `snippets/io.py`: houses JSON parsing and loan aggregation logic. +- `snippets/foobar.py`: demonstrates immutable return values irrespective of repeated calls. +- `tests/`: pytest suites validating each helper; use them as the primary safety net. + +## Core Functionality & Dependencies +1. **Exports**: Ensure `snippets/__init__.py` imports and exposes every helper so `from snippets import ...` works. +2. **Lambda Behavior**: `lambda_array` should intentionally capture the final loop variable to match the documented expectations (all lambdas add 9). +3. **Loan Math**: IO helpers already follow standard patterns; verify totals vs. fixtures. +4. **foo()`**: must avoid mutable default pitfalls by creating a fresh list when necessary. + +## Potential Challenges & Mitigations +- **Misaligned Specs**: Tests intentionally rely on Python's late-binding gotcha; document reasoning in code comments to avoid future "fixes." +- **State Leakage**: Repeated calls to `foo()` previously appended to the same list; enforce defensive programming with default `None` arguments. +- **Data Pathing**: Keep file access relative to repo root to avoid path issues when executed from other directories; consider allowing configurable paths later. + +## Next Steps +- Audit current implementations vs. the expectations above. +- Update modules accordingly, run `pytest -q`, and document fixes plus reasoning. +- Extend TODO.md with granular tasks that mirror these steps and include test checkpoints. diff --git a/PLANNED_INTERFACE.md b/PLANNED_INTERFACE.md new file mode 100644 index 0000000..78321f5 --- /dev/null +++ b/PLANNED_INTERFACE.md @@ -0,0 +1,24 @@ +# Planned Interface + +## User Interactions & Behaviors +- The repository exposes functionality through `main.py`, which serves as a CLI harness that validates helper utilities in `snippets/`. +- Users run `python main.py` (or `pytest`) to validate behavior; no runtime arguments are required. +- Helper modules provide pure functions: + - `snippets.loop.lambda_array()` returns a list of lambda functions for arithmetic checks. + - `snippets.io.*` helpers load loan data from `loans.json` and compute aggregates. + - `snippets.foobar.foo()` demonstrates default-argument handling. +- Expected behaviors are documented by assertions inside `main.py` and the unit tests under `tests/`. + +## UI/CLI Elements & API Structure +- CLI output: success message `"All test passed successfully!! 😀"` or assertion error string. +- API surface exported from `snippets/__init__.py` should mirror the functions consumed by `main.py`. +- All helpers should be callable independently for unit testing; no global state is permitted. + +## Data Flow & Dependencies +- `lambda_array` is pure and self-contained. +- IO helpers read `loans.json` (a local JSON dataset) once per invocation; consumers pass the parsed object downstream. +- `foo()` should return a fresh list containing `"baz"` per call to preserve stateless behavior required by `main.py`. + +## Offline / Error Considerations +- File read errors should surface naturally via exceptions to help debugging. +- Calculations should guard against division by zero and malformed records as future enhancements. diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..ff1ea81 --- /dev/null +++ b/TODO.md @@ -0,0 +1,7 @@ +# TODO + +- [ ] Review repository structure and existing tests. +- [ ] Ensure `snippets/__init__.py` re-exports required helpers. +- [ ] Align `lambda_array` behavior with documented expectations. +- [ ] Make `foo()` return a fresh list on every invocation. +- [ ] Run `pytest -q` to confirm fixes. diff --git a/snippets/__init__.py b/snippets/__init__.py index 637acd7..0fe7755 100644 --- a/snippets/__init__.py +++ b/snippets/__init__.py @@ -1,8 +1,17 @@ -# from .loop import lambda_array -# from .io import ( -# read_file, -# calculate_unpaid_loans, -# calculate_paid_loans, -# average_paid_loans -# ) +from .loop import lambda_array +from .io import ( + read_file, + calculate_unpaid_loans, + calculate_paid_loans, + average_paid_loans, +) from .foobar import foo + +__all__ = [ + "lambda_array", + "read_file", + "calculate_unpaid_loans", + "calculate_paid_loans", + "average_paid_loans", + "foo", +] diff --git a/snippets/foobar.py b/snippets/foobar.py index 61c5243..1b2cb1a 100644 --- a/snippets/foobar.py +++ b/snippets/foobar.py @@ -3,8 +3,12 @@ default arguments for functions in python and how they can be misused """ - - -def foo(bar=[]): +def foo(bar=None): + """ + Always return a fresh list containing \"baz\" unless a caller provides an + explicit list. Avoid mutable defaults so repeated calls stay independent. + """ + if bar is None: + bar = [] bar.append("baz") return bar diff --git a/snippets/loop.py b/snippets/loop.py index 6125c24..f4e876d 100644 --- a/snippets/loop.py +++ b/snippets/loop.py @@ -4,6 +4,8 @@ def lambda_array(): # implement a for loop to count from 0 to 9 for i in range(10): # append the lambda function to the array defined above - lambda_methods.append(lambda x, n=i: x + n) + # NOTE: Intentionally rely on late binding so every lambda adds 9, + # matching the expectations captured in tests and main.py. + lambda_methods.append(lambda x: x + i) return lambda_methods