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
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,20 @@
All notable changes to this project are documented here. Pythonlings follows
Semantic Versioning.

## [0.3.1] - 2026-06-20

### Fixed

- `pythonlings --version` now reports the installed package version instead of
a separate hardcoded string in `cli.py` (which had drifted to `0.3.0`). The
version is read from package metadata, so it can no longer fall out of sync
with `pyproject.toml`.
- Corrected stale `pylings` references in the contributor guide (`CLAUDE.md`):
the smoke-test command, manual-testing flows, package paths, stylesheet, and
entry point now consistently use the `pythonlings` name the project adopted
in 0.3.0. (The unrelated `pylings` PyPI package belongs to a different
project; `pythonlings` is the only command this project ships.)

## [0.3.0] - 2026-06-10

### Added
Expand Down
14 changes: 7 additions & 7 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ python -m pytest -q # full suite
python -m pytest tests/unit/test_runner.py -q # one file
python -m pytest tests/unit/test_state.py::test_name -q # one test

pylings --root tests/fixtures/passing_curriculum verify # smoke-test: all solutions pass their checks
pythonlings --root tests/fixtures/passing_curriculum verify # smoke-test: all solutions pass their checks

python -m build # sdist + wheel
```

Manual testing of flows: `pylings init --path ./learn-python` (create a learner workspace), `pylings` (TUI), `pylings run variables1`, `pylings dry-run variables1`, `pylings solution variables1`, `pylings hint`, `pylings list`, `pylings topics`, `pylings reset`. `--root` points any command at an arbitrary workspace (used heavily by tests against `tests/fixtures/`).
Manual testing of flows: `pythonlings init --path ./learn-python` (create a learner workspace), `pythonlings` (TUI), `pythonlings run variables1`, `pythonlings dry-run variables1`, `pythonlings solution variables1`, `pythonlings hint`, `pythonlings list`, `pythonlings topics`, `pythonlings reset`. `--root` points any command at an arbitrary workspace (used heavily by tests against `tests/fixtures/`).

## Architecture

Two distinct trees in this repo:

1. **The application** — `pylings/` (installable package)
1. **The application** — `pythonlings/` (installable package)
2. **The curriculum** — repo-root `exercises/`, `checks/`, `solutions/`, and `info.toml`

At build time, hatch `force-include` maps the curriculum into the wheel as `pylings/curriculum/` (see `pyproject.toml`). `pylings init` copies that bundled curriculum into a self-contained learner workspace; progress lives in `<workspace>/.pylings/state.json` (written atomically, with `.bak` recovery on corruption).
At build time, hatch `force-include` maps the curriculum into the wheel as `pythonlings/curriculum/` (see `pyproject.toml`). `pythonlings init` copies that bundled curriculum into a self-contained learner workspace; progress lives in `<workspace>/.pythonlings/state.json` (written atomically, with `.bak` recovery on corruption).

### Curriculum model

Expand All @@ -38,7 +38,7 @@ Each exercise is a triple that must stay in sync, plus a manifest entry:
- `solutions/<name>.py` — reference answer
- `info.toml` — ordered `[[exercises]]` entries with `name`, `path`, `hint`, `docs` URL; this file is the source of truth for exercise order and topics

When changing curriculum, update all four, then run the relevant tests plus `pylings --root tests/fixtures/passing_curriculum verify`. Exercise names are topic + ordinal (`variables1`, `collections10`).
When changing curriculum, update all four, then run the relevant tests plus `pythonlings --root tests/fixtures/passing_curriculum verify`. Exercise names are topic + ordinal (`variables1`, `collections10`).

### How checks run (`core/runner.py`)

Expand All @@ -47,8 +47,8 @@ An exercise passes when a generated runner script `exec()`s the exercise source
### Layering

- `pythonlings/core/` — all filesystem, manifest, state, reset, solutions, and runner logic. No UI imports. (Checks rerun on a debounce in the TUI editor, not a filesystem watcher.)
- `pylings/screens/` and `pylings/widgets/` — Textual UI only; `pylings/app.py` wires them up; `pylings.tcss` holds styles.
- `pylings/cli.py` — argparse subcommands; entry point `pylings = "pylings.cli:main"`.
- `pythonlings/screens/` and `pythonlings/widgets/` — Textual UI only; `pythonlings/app.py` wires them up; `pythonlings.tcss` holds styles.
- `pythonlings/cli.py` — argparse subcommands; entry point `pythonlings = "pythonlings.cli:main"`.

Keep UI behavior in screens/widgets and behavior logic in core — tests depend on this split (`tests/unit/` for core, `tests/integration/` for CLI/workspace flows, `tests/tui/` for Textual pilot tests, fixtures in `tests/fixtures/`).

Expand Down
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ cd learn-python && uvx pythonlings
How it works: **edit** the broken exercise in the built-in editor → checks
rerun as you type and advance you to the next one. That's the whole loop.

Status: `v0.3.0`, alpha — published on PyPI as `pythonlings`.
Status: `v0.3.1`, alpha — published on PyPI as `pythonlings`.

![Coding screen](docs/assets/screenshots/coding-screen.png)

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "pythonlings"
version = "0.3.0"
version = "0.3.1"
description = "Python learnings, Rustlings-style, in a terminal TUI."
readme = "Readme.md"
requires-python = ">=3.9"
Expand Down
6 changes: 5 additions & 1 deletion pythonlings/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@

import argparse
import sys
from importlib.metadata import PackageNotFoundError, version as _package_version
from pathlib import Path

__version__ = "0.3.0"
try:
__version__ = _package_version("pythonlings")
except PackageNotFoundError: # running from a source checkout without an install
__version__ = "0.0.0+unknown"


def _build_parser() -> argparse.ArgumentParser:
Expand Down
Loading