From 7c1f1b6423a876d25afafd24f7f206d16ac6d669 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Thu, 15 Oct 2026 09:39:16 +0800 Subject: [PATCH 1/2] MIL-012: version 0.2.0, CHANGELOG and links Version 0.2.0 in pyproject.toml, flash_card.__version__ and the Doxyfile with a test that keeps the three equal; CHANGELOG entry for 0.2.0; README and the wiki Install pages link the release pages. The upload limit probe refused a 1 MB file (413), so the executable is not attached. Review record RC-071 (Go). Task: MIL-012#2 Task: MIL-012#3 Task: MIL-012#4 Task: MIL-012#8 --- CHANGELOG.md | 30 +++++++++++++ Doxyfile | 2 +- README.md | 5 ++- docs/artifact-registry.md | 2 +- docs/sqa/reviews/rc-071-py-mil-012.md | 63 +++++++++++++++++++++++++++ docs/sqa/traceability-matrix.md | 3 ++ docs/wiki/Install-da.md | 2 +- docs/wiki/Install-ms.md | 2 +- docs/wiki/Install.md | 2 +- pyproject.toml | 2 +- src/flash_card/__init__.py | 2 +- tests/unit/test_version.py | 35 +++++++++++++++ 12 files changed, 141 insertions(+), 9 deletions(-) create mode 100644 docs/sqa/reviews/rc-071-py-mil-012.md create mode 100644 tests/unit/test_version.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 910c8ea..1b7d652 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,35 @@ All notable changes of the flash card program. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); the version follows [Semantic Versioning](https://semver.org/). +## [0.2.0] - 2026-10-15 + +Adds the classic menu bar and keeps the progress of each word list apart. + +### Added + +- A menu bar. File: Open... (another word list from a CSV file with a header + of two language codes), Change level... (the level choice without a restart), + Reset word list... (after a confirmation the progress of the open list is + removed and all its words are to learn again), Exit. About: Contact (the + author's name and title, and a link to the author's LinkedIn page). +- The progress of each word list is a file of its own: `words_to_learn.csv` for + `ms-da.csv` (unchanged) and `words_to_learn_.csv` for another list. + +### Fixed + +- A word list that is not UTF-8 text gives a message that names the file, + instead of an error. +- The level screen has the same window title, padding and background as the + card screen. + +### Known limits + +- The executable is not signed; Windows SmartScreen may warn about it. +- The executable is not attached to the release: the upload limit of the git + host rejects a file of its size (HTTP 413, already at 1 MB). Build it with + `python tools/build_executable.py`. +- An opened word list is not remembered after a restart. + ## [0.1.0] - 2026-10-15 First release. The solution of day 31 of Udemy's *100 Days of Code: The Complete @@ -32,3 +61,4 @@ Python Pro Bootcamp*, for Malay words with Danish translations. - The Danish column of the word list is machine translated. [0.1.0]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.1.0 +[0.2.0]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.2.0 diff --git a/Doxyfile b/Doxyfile index ac48f2d..bd28858 100644 --- a/Doxyfile +++ b/Doxyfile @@ -4,7 +4,7 @@ PROJECT_NAME = "Flash Card" PROJECT_BRIEF = "Malay to Danish flash cards (Udemy 100 Days of Code, day 31)" -PROJECT_NUMBER = 0.1.0 +PROJECT_NUMBER = 0.2.0 OUTPUT_DIRECTORY = docs/doxygen CREATE_SUBDIRS = NO diff --git a/README.md b/README.md index b638212..906be9b 100644 --- a/README.md +++ b/README.md @@ -120,7 +120,7 @@ The progress of the delivered `ms-da.csv` is `data/words_to_learn.csv`; another ### Executable (Windows, no Python needed to run it) -The [release page][release-0-1-0] of v0.1.0 has the release notes. The executable is not attached there yet, because the server's upload limit rejects a file of this size (HTTP 413). Build it yourself: +The release pages of [v0.2.0][release-0-2-0] and [v0.1.0][release-0-1-0] have the release notes. The executable is not attached there yet, because the server's upload limit rejects a file of this size (HTTP 413). Build it yourself: ```powershell python -m pip install -e ".[build,speech]" @@ -156,7 +156,7 @@ GNU Affero General Public License v3.0 or later. See [LICENSE][license]. - [Repository][repository] - [Documentation][documentation] - [Issue tracker][issues] -- [Releases][releases] (v0.1.0: release notes; the executable is built from source, see Run) +- [Releases][releases] (v0.2.0 and v0.1.0: release notes; the executable is built from source, see Run) ## 📎 Appendix: Project documents @@ -191,6 +191,7 @@ The documents a newcomer needs, in reading order. [issues]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/issues [releases]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases [release-0-1-0]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.1.0 +[release-0-2-0]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.2.0 [agents]: ./AGENTS.md [BC-001]: ./docs/business-case.md [SA-001]: ./docs/stakeholder-analysis.md diff --git a/docs/artifact-registry.md b/docs/artifact-registry.md index 455c9fa..81fedd0 100644 --- a/docs/artifact-registry.md +++ b/docs/artifact-registry.md @@ -25,7 +25,7 @@ document of a type. `Primary File` may contain a glob (e.g. | DCD | Design Class Diagram | docs/dcd.md | 002 | | DICT | Domain Dictionary | docs/dictionary.md | 002 | | ADR | Architecture Decision Record | docs/adr/adr-NNNN-*.md | 0005 | -| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 071 | +| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 072 | | TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 | ## Languages diff --git a/docs/sqa/reviews/rc-071-py-mil-012.md b/docs/sqa/reviews/rc-071-py-mil-012.md new file mode 100644 index 0000000..83d7f27 --- /dev/null +++ b/docs/sqa/reviews/rc-071-py-mil-012.md @@ -0,0 +1,63 @@ +# RC-071: Review of PY-MIL-012 + +## Metadata +| Key | Value | +| --- | --- | +| ID | RC-071 | +| CrossReference | [PY-MIL-012], [QC-PY-001] | + +## Version History +| Date | Status | Author | Reviewer | Change | Commit | +| --- | --- | --- | --- | --- | --- | +| 2026-10-15 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending | + +--- + +## Artifact Under Review + +- Instance reviewed: [PY-MIL-012] +- Checklist used: [QC-PY-001] +- Scope: full review +- Language and domain: n/a (technical type) +- Language reviewer: none +- Mode: autonomous, not independent (reviewer is `AI as stand-in for S01`) + +## Checklist Results + +| # | Criterion | Status | Evidence/Notes | +| --- | --- | --- | --- | +| 1 | Packages, modules, functions, variables, classes and constants follow PEP 8 casing (`snake_case`, `PascalCase`, `UPPER_SNAKE`) | Pass | The change is one assignment and a test module; names follow PEP 8. | +| 2 | Names state purpose in the domain's language; no unexplained abbreviations, no single-letter names outside tiny scopes | Pass | `test_version_of_the_package_equals_pyproject_version` and similar names state the behaviour. | +| 3 | Code is produced by the project's formatter and passes its linter with no unexplained suppressions | Pass | `ruff check` and `ruff format --check` pass with no suppressions. | +| 4 | Every function and method signature is type-annotated, including `-> None` | Pass | Test functions are annotated `-> None`; `mypy --strict` passes on 49 source files. | +| 5 | No bare `except:`, no swallowed exceptions; specific exceptions are raised and the cause is kept (`raise ... from`) | Pass | No exception handling in the change. | +| 6 | No mutable default arguments and no shadowed builtins | Pass | No mutable defaults. | +| 7 | Files, locks and connections are managed with context managers | Pass | `pyproject.toml` is read with `tomllib` through a `with open` context. | +| 8 | Public modules, classes and functions have docstrings that say what, not how | Pass | The module docstring keeps `@file` and `@brief`; `doxygen Doxyfile` ends with 0 warnings. | +| 9 | Logging uses `logging`, not `print`; no secrets or personal data in log output | Pass | No `print`, no logging in the change. | +| 10 | Classes and operations trace to the Design Class Diagram they implement; deviations are recorded | Pass | No class or operation changed; the version string is not part of the design. | +| 11 | Tests exist for new behaviour, are named for the behaviour, and do not depend on order or the network | Pass | 3 tests compare `__version__`, `pyproject.toml` and the `Doxyfile` `PROJECT_NUMBER` and the `MAJOR.MINOR.PATCH` form; 3 consecutive full runs (261 tests) green. | +| 12 | Type checker runs in strict mode without errors; `Any` is justified in a comment | Pass | `mypy --strict` reports no issue. | +| 13 | Dependencies are declared and pinned in the project's dependency file, none unused | Pass | `dependencies` stays empty; `tomllib` is standard library. | +| 14 | Each piece of knowledge (a business rule, constant, format, validation or query) is defined in one place; code is merged only where it expresses the same knowledge, not where it merely looks alike | Pass | The version is stated once per file type; the test makes the three places agree. | +| 15 | Imports point inward: business-rule modules import no framework, database, UI or delivery-mechanism code, and there are no import cycles | Pass | `lint-imports` reports `Layers point inward` kept. | +| 16 | SOLID holds: a class or module has one reason to change; new behaviour is added by extension, not by editing a type test in several places; subclasses honour the contract of their base; protocols are narrow; high-level code depends on protocols or abstract types and receives its implementations | Pass | One test module with one reason to change. | +| 17 | Source is laid out in the layers and folders of the clean architecture folder structure (`domain`, `application`, `infrastructure`, `presentation` packages under `src/`, and `unit`, `integration` and `e2e` under `tests/`), in `snake_case`, and imports between the layers point inward | Pass | The test sits in `tests/unit`. | +| 18 | File and folder names are English, contain no space and no character outside letters, digits, `-`, `_` and `.`, and follow the casing of the language for files | Pass | File names follow the rule. | + +## Overall Verdict + +Go — every Mandatory criterion passes. Reviewed by AI as stand-in for S01; not independent of the author. + +Milestone MIL-012 tasks 2, 3, 4 and 8 (this change set): 1 the three version places say 0.2.0 and a test fails if they differ; 2 CHANGELOG has `[0.2.0]` and `[0.1.0]` is unchanged; 3 the upload limit probe ran before the build: a draft release with a 1 MB random file was refused with `413 Request Entity Too Large`, so the largest accepted size is below 1 MB; the draft release and its tag were deleted afterwards (the tag list and the release list were checked); 8 README, CHANGELOG and the Install page of the wiki in three languages link v0.2.0 and say that the executable is not attached; `check-readme.sh` exit 0. The tag, the build and the release are criteria 4 to 7 and are recorded in a separate review record. Go. + +## Action Items + +| Action | Owner | Due | +| --- | --- | --- | +| none | - | - | + +--- + +[PY-MIL-012]: ../../../src/flash_card/__init__.py +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md diff --git a/docs/sqa/traceability-matrix.md b/docs/sqa/traceability-matrix.md index fb66ff3..7f75c86 100644 --- a/docs/sqa/traceability-matrix.md +++ b/docs/sqa/traceability-matrix.md @@ -68,6 +68,7 @@ updated whenever an artifact instance is created or reviewed. | PY-MIL-009 | Python Source Code | - | - | DCD-001, ADR-0002 | - | [RC-048] | | PY-MIL-011 | Python Source Code | - | - | DCD-001, ADR-0002 | - | [RC-066] | | PY-FIX-001 | Python Source Code | - | - | PY-MIL-008 | - | [RC-049] | +| PY-MIL-012 | Python Source Code | - | - | MIL-012 | - | [RC-071] | ## Coverage Notes @@ -193,3 +194,5 @@ updated whenever an artifact instance is created or reviewed. [RC-070]: ./reviews/rc-070-mil-012.md [MIL-012]: ../milestones/mil-012-release-0-2-0.md [0264b60]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/0264b6084f26bac5af716ea71596ce3be961fec8 +[RC-071]: ./reviews/rc-071-py-mil-012.md +[PY-MIL-012]: ../../src/flash_card/__init__.py diff --git a/docs/wiki/Install-da.md b/docs/wiki/Install-da.md index 5540d1c..36ca138 100644 --- a/docs/wiki/Install-da.md +++ b/docs/wiki/Install-da.md @@ -58,7 +58,7 @@ Vinduestesten i `tests/e2e/` springes over, når der ikke er en skærm. ## Udgivelse og programfil (Windows) -[Udgivelsessiden](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.1.0) for v0.1.0 har udgivelsesnoterne. Programfilen er endnu ikke vedhæftet, fordi serverens grænse for upload afviser en fil af denne størrelse (HTTP 413); byg den som beskrevet nedenfor. Filen er ikke signeret, så Windows kan vise en SmartScreen-advarsel. +Udgivelsessiderne for [v0.2.0](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.2.0) og [v0.1.0](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.1.0) har udgivelsesnoterne. Programfilen er endnu ikke vedhæftet, fordi serverens grænse for upload afviser en fil af denne størrelse (HTTP 413); byg den som beskrevet nedenfor. Filen er ikke signeret, så Windows kan vise en SmartScreen-advarsel. ## Byg en programfil (Windows) diff --git a/docs/wiki/Install-ms.md b/docs/wiki/Install-ms.md index 0a749b5..78c96de 100644 --- a/docs/wiki/Install-ms.md +++ b/docs/wiki/Install-ms.md @@ -58,7 +58,7 @@ Ujian tetingkap dalam `tests/e2e/` dilangkau apabila tiada paparan. ## Keluaran dan fail boleh laku (Windows) -[Halaman keluaran](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.1.0) v0.1.0 mempunyai nota keluaran. Fail boleh laku belum dilampirkan di sana kerana had muat naik pelayan menolak fail sebesar ini (HTTP 413); bina seperti yang diterangkan di bawah. Fail tidak ditandatangani, jadi Windows mungkin menunjukkan amaran SmartScreen. +Halaman keluaran [v0.2.0](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.2.0) dan [v0.1.0](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.1.0) mempunyai nota keluaran. Fail boleh laku belum dilampirkan di sana kerana had muat naik pelayan menolak fail sebesar ini (HTTP 413); bina seperti yang diterangkan di bawah. Fail tidak ditandatangani, jadi Windows mungkin menunjukkan amaran SmartScreen. ## Bina fail boleh laku (Windows) diff --git a/docs/wiki/Install.md b/docs/wiki/Install.md index 237e4de..6ad8347 100644 --- a/docs/wiki/Install.md +++ b/docs/wiki/Install.md @@ -58,7 +58,7 @@ The window test in `tests/e2e/` is skipped when no display is available. ## Release and executable (Windows) -The [release page](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.1.0) of v0.1.0 has the release notes. The executable is not attached there yet, because the server's upload limit rejects a file of this size (HTTP 413); build it as described below. The file is not signed, so Windows may show a SmartScreen warning. +The release pages of [v0.2.0](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.2.0) and [v0.1.0](https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/releases/tag/v0.1.0) have the release notes. The executable is not attached there yet, because the server's upload limit rejects a file of this size (HTTP 413); build it as described below. The file is not signed, so Windows may show a SmartScreen warning. ## Build an executable (Windows) diff --git a/pyproject.toml b/pyproject.toml index 6174659..c35ae1b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "flash-card" -version = "0.1.0" +version = "0.2.0" description = "Flash card program for learning Malay words with Danish translations (Udemy 100 Days of Code, day 31)" readme = "README.md" requires-python = ">=3.13" diff --git a/src/flash_card/__init__.py b/src/flash_card/__init__.py index 810fc07..4528b25 100644 --- a/src/flash_card/__init__.py +++ b/src/flash_card/__init__.py @@ -4,4 +4,4 @@ @brief Package root of the flash card program. """ -__version__ = "0.1.0" +__version__ = "0.2.0" diff --git a/tests/unit/test_version.py b/tests/unit/test_version.py new file mode 100644 index 0000000..f72cba2 --- /dev/null +++ b/tests/unit/test_version.py @@ -0,0 +1,35 @@ +"""Keep the version declared in code, pyproject.toml and the Doxyfile in step. + +@file test_version.py +@brief Unit tests that the three version declarations cannot drift. +""" + +import re +import tomllib + +import flash_card +from flash_card.constants import PROJECT_ROOT + +_SEMVER_PATTERN = re.compile(r"^\d+\.\d+\.\d+$") +_PROJECT_NUMBER_PATTERN = re.compile(r"^PROJECT_NUMBER\s*=\s*(\S+)\s*$", re.MULTILINE) + + +def _pyproject_version() -> str: + with (PROJECT_ROOT / "pyproject.toml").open("rb") as file: + version: str = tomllib.load(file)["project"]["version"] + return version + + +def test_version_matches_package_version_when_read_from_pyproject() -> None: + assert _pyproject_version() == flash_card.__version__ + + +def test_version_has_major_minor_patch_form() -> None: + assert _SEMVER_PATTERN.match(flash_card.__version__) is not None + + +def test_version_matches_doxyfile_project_number() -> None: + text = (PROJECT_ROOT / "Doxyfile").read_text(encoding="utf-8") + match = _PROJECT_NUMBER_PATTERN.search(text) + assert match is not None + assert match.group(1) == flash_card.__version__ -- 2.54.0 From 2d94678899b7311b57991adcf487002163f0a2e4 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Thu, 15 Oct 2026 09:39:25 +0800 Subject: [PATCH 2/2] Resolve pending commit link of RC-071 --- docs/sqa/reviews/rc-071-py-mil-012.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sqa/reviews/rc-071-py-mil-012.md b/docs/sqa/reviews/rc-071-py-mil-012.md index 83d7f27..dffc7ea 100644 --- a/docs/sqa/reviews/rc-071-py-mil-012.md +++ b/docs/sqa/reviews/rc-071-py-mil-012.md @@ -9,7 +9,7 @@ ## Version History | Date | Status | Author | Reviewer | Change | Commit | | --- | --- | --- | --- | --- | --- | -| 2026-10-15 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending | +| 2026-10-15 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [7c1f1b6] | --- @@ -61,3 +61,4 @@ Milestone MIL-012 tasks 2, 3, 4 and 8 (this change set): 1 the three version pla [PY-MIL-012]: ../../../src/flash_card/__init__.py [QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md +[7c1f1b6]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/7c1f1b6423a876d25afafd24f7f206d16ac6d669 -- 2.54.0