Merge pull request 'MIL-007: Documentation and publication' (#44) from mil-007-documentation-and-publication into main
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 8s
TirSystem/github-action: Sync GitHub mirror metadata / sync-metadata (push) Successful in 8s
This commit was merged in pull request #44.
This commit is contained in:
@@ -22,11 +22,34 @@ The program shows a Malay word on a card. After three seconds the card turns ove
|
||||
| `src/flash_card/` | The program, in four layers: `domain`, `application`, `infrastructure`, `presentation` |
|
||||
| `tests/` | `pytest` tests: `unit`, `integration`, `e2e` |
|
||||
| `data/` | The word list `ms-da.csv` and, after the first known word, your own `words_to_learn.csv` |
|
||||
| `docs/` | Project documents (business case, plan, design, review records) |
|
||||
| `docs/` | Project documents (business case, plan, design, review records), `docs/wiki/` and `docs/images/` |
|
||||
| `tools/` | Helper scripts: `generate_images.py` and `capture_screenshots.py` |
|
||||
| `Doxyfile` | Doxygen configuration for the source code documentation |
|
||||
|
||||
The core program uses only the Python standard library. Spoken Malay words are an optional extra.
|
||||
|
||||
### Screenshots
|
||||
|
||||
| Front: the Malay word | Back: the Danish translation after 3 seconds |
|
||||
| --- | --- |
|
||||
| ![The front of a card][screenshot-front] | ![The back of a card][screenshot-back] |
|
||||
|
||||
### Where is each assignment step?
|
||||
|
||||
| Assignment step | Code |
|
||||
| --- | --- |
|
||||
| 1. User interface | `FlashCardView.__init__` in `src/flash_card/presentation/features/flash_card/flash_card_view.py`; images made by `tools/generate_images.py` |
|
||||
| 2. New flash cards | `CsvVocabularyRepository` (the standard library `csv` instead of `pandas`), `Deck.draw`, `StudySession.next_card`, `FlashCardView.next_card` |
|
||||
| 3. Flip the cards | `FlashCardView.flip_card` and `FlashCardView.flip_timer` (`after`, `after_cancel`), `FlashCardViewModel.flip_card` |
|
||||
| 4. Save your progress | `FlashCardView.is_known`, `StudySession.mark_known`, `CsvProgressRepository` |
|
||||
| Extra: spoken word | `GttsSpeech`, `NullSpeech`, `build_speech` in `presentation/app.py` |
|
||||
|
||||
The wiki ([English][wiki-en], [Dansk][wiki-da], [Bahasa Malaysia][wiki-ms]) explains the same in three languages.
|
||||
|
||||
### Data
|
||||
|
||||
`data/ms-da.csv` holds 1000 frequent Malay words with a Danish machine translation; see [data/README.md][data-readme] for the format and origin.
|
||||
|
||||
## 📋 Requirements
|
||||
|
||||
| Need | Why |
|
||||
@@ -69,7 +92,14 @@ python -m pip install -e ".[dev]"
|
||||
python -m flash_card
|
||||
```
|
||||
|
||||
The program is run from the activated `.venv`. The window opens with the first card; the program is built step by step and the pull requests and milestones show each step.
|
||||
The program is run from the activated `.venv`. The window opens with a card. Press the green tick for a word you know and the red cross for a word you do not. Options:
|
||||
|
||||
| Option | Meaning |
|
||||
| --- | --- |
|
||||
| `--data-dir <folder>` | Folder with `ms-da.csv` and `words_to_learn.csv` |
|
||||
| `--no-speech` | Do not speak the Malay word |
|
||||
|
||||
To start again, delete `data/words_to_learn.csv`.
|
||||
|
||||
## 🧪 Tests
|
||||
|
||||
@@ -87,6 +117,8 @@ lint-imports
|
||||
|
||||
The window test in `tests/e2e/` is skipped when no display is available.
|
||||
|
||||
Build the source code documentation (Doxygen comments) with `doxygen Doxyfile`; the HTML is written to `docs/doxygen/html/`. The screenshots are made with `python tools/capture_screenshots.py` after `python -m pip install -e ".[tools]"` (Pillow, tool only).
|
||||
|
||||
## 📄 License
|
||||
|
||||
GNU Affero General Public License v3.0 or later. See [LICENSE][license].
|
||||
@@ -117,6 +149,12 @@ The documents a newcomer needs, in reading order.
|
||||
---
|
||||
|
||||
[license]: ./LICENSE
|
||||
[screenshot-front]: ./docs/images/screenshot-front.png
|
||||
[screenshot-back]: ./docs/images/screenshot-back.png
|
||||
[wiki-en]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/wiki/Home
|
||||
[wiki-da]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/wiki/Home-da
|
||||
[wiki-ms]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/wiki/Home-ms
|
||||
[data-readme]: ./data/README.md
|
||||
[repository]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card
|
||||
[documentation]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/wiki
|
||||
[issues]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/issues
|
||||
|
||||
@@ -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 | 0004 |
|
||||
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 029 |
|
||||
| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 030 |
|
||||
| TM | Traceability Matrix | docs/sqa/traceability-matrix.md | 002 |
|
||||
|
||||
## Languages
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
+115
-108
@@ -1,108 +1,115 @@
|
||||
# Project Plan: Flash Card
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | PP-001 |
|
||||
| CrossReference | [BC-001], [SA-001], [US-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [MIL-007] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
This plan schedules the seven phases (gateways) that deliver the flash card program inside the delivery window of one week that the Business Case sets as a constraint (2026-10-14 to 2026-10-21). Each phase is one milestone and is delivered by one pull request, so the Product Owner (S01) can follow the work step by step.
|
||||
|
||||
## Planning Assumptions
|
||||
|
||||
- Week 1 starts 2026-10-14; the plan ends by 2026-10-21, per the Business Case constraint.
|
||||
- One phase takes one day; the last phase (documentation and publication) has three days because the wiki exists in three languages and the screenshots need the finished program.
|
||||
- The baseline documents (Business Case, Stakeholder Analysis, Project Plan, use case documents, ADRs) are accepted before MIL-001 starts, in a pull request of their own.
|
||||
- Phases 2 to 5 follow the four steps of the course assignment in order; phase 6 is the Product Owner's extra.
|
||||
- S01 is owner and approving reviewer of every phase; in autonomous mode the AI acts as stand-in and the review records say so.
|
||||
|
||||
## Gateway Schedule
|
||||
|
||||
| Gateway | Document | Window | Decision date | Owner | Stories | Main deliverable | Milestone |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| Project foundation | [MIL-001] | 2026-10-14 | 2026-10-14 | S01 | none | pyproject, gitignore, skeleton, Doxyfile, first README, word list | |
|
||||
| Step 1 - User interface | [MIL-002] | 2026-10-15 | 2026-10-15 | S01 | US-001.01 | The window with card and buttons | |
|
||||
| Step 2 - New flash cards | [MIL-003] | 2026-10-16 | 2026-10-16 | S01 | US-001.02 | Random cards from the word list | |
|
||||
| Step 3 - Flip the cards | [MIL-004] | 2026-10-17 | 2026-10-17 | S01 | US-001.03 | Flip after 3000 ms | |
|
||||
| Step 4 - Save progress | [MIL-005] | 2026-10-18 | 2026-10-18 | S01 | US-001.04 | words_to_learn.csv | |
|
||||
| Spoken Malay word | [MIL-006] | 2026-10-19 | 2026-10-19 | S01 | US-001.05 | Text to speech as optional extra | |
|
||||
| Documentation and publication | [MIL-007] | 2026-10-19 to 2026-10-21 | 2026-10-21 | S01 | none | README, screenshots, wiki in 3 languages, description and topics | |
|
||||
|
||||
```plantuml
|
||||
@startgantt
|
||||
Project starts 2026-10-14
|
||||
[Foundation] starts 2026-10-14 and ends 2026-10-14
|
||||
[Step 1 UI] starts 2026-10-15 and ends 2026-10-15
|
||||
[Step 2 Cards] starts 2026-10-16 and ends 2026-10-16
|
||||
[Step 3 Flip] starts 2026-10-17 and ends 2026-10-17
|
||||
[Step 4 Progress] starts 2026-10-18 and ends 2026-10-18
|
||||
[Speech] starts 2026-10-19 and ends 2026-10-19
|
||||
[Documentation] starts 2026-10-19 and ends 2026-10-21
|
||||
[Foundation Go/No-Go] happens 2026-10-14
|
||||
[Step 1 Go/No-Go] happens 2026-10-15
|
||||
[Step 2 Go/No-Go] happens 2026-10-16
|
||||
[Step 3 Go/No-Go] happens 2026-10-17
|
||||
[Step 4 Go/No-Go] happens 2026-10-18
|
||||
[Speech Go/No-Go] happens 2026-10-19
|
||||
[Documentation Go/No-Go] happens 2026-10-21
|
||||
@endgantt
|
||||
```
|
||||
|
||||
## Scope Coverage
|
||||
|
||||
| Business Case scope item | Gateway |
|
||||
| --- | --- |
|
||||
| Tkinter program with the assignment's function names | MIL-002, MIL-003, MIL-004, MIL-005 |
|
||||
| Reading `data/ms-da.csv` | MIL-003 |
|
||||
| Saving and using `words_to_learn.csv` | MIL-005 |
|
||||
| Optional spoken Malay word | MIL-006 |
|
||||
| `pyproject.toml`, `.gitignore`, `Doxyfile`, `.venv` instructions, `pytest`, `constants.py` | MIL-001 |
|
||||
| README, screenshots, wiki in three languages | MIL-007 |
|
||||
| Repository description and topics | MIL-007 |
|
||||
| Framework documents of the baseline | Baseline pull request before MIL-001 |
|
||||
|
||||
## Dependencies
|
||||
|
||||
```
|
||||
Baseline → MIL-001 → MIL-002 → MIL-003 → MIL-004 → MIL-005 → MIL-006 → MIL-007
|
||||
```
|
||||
|
||||
A No-Go on a phase moves every later date by the days the rework takes; the buffer is the 2026-10-20 working day, which has no phase of its own.
|
||||
|
||||
## Plan Risks
|
||||
|
||||
| Risk | Impact | Mitigation |
|
||||
| --- | --- | --- |
|
||||
| No display on the machine that runs the review, so the e2e tests skip | Window behaviour is checked by the view model tests only | The review record states whether the e2e tests ran; the screenshots in MIL-007 prove the window on a machine with a display |
|
||||
| The git host's CI is not available | The publish workflows cannot run | Milestones are published with `sync-project.sh` and the wiki by SSH push (MIL-007) |
|
||||
| The speech extra cannot be installed on the build machine | MIL-006 cannot be demonstrated end to end | The adapter is tested with fakes; the manual check is recorded as not done |
|
||||
|
||||
## Open Issues
|
||||
|
||||
- No Governance document (GOV): see ADR-0003. S01 is the only approver.
|
||||
- The git host's `sync-milestones` workflow is not installed; whether to install it is S01's decision.
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ./business-case.md
|
||||
[SA-001]: ./stakeholder-analysis.md
|
||||
[US-001]: ./user-stories.md
|
||||
[MIL-001]: ./milestones/mil-001-foundation.md
|
||||
[MIL-002]: ./milestones/mil-002-step1-user-interface.md
|
||||
[MIL-003]: ./milestones/mil-003-step2-new-flash-cards.md
|
||||
[MIL-004]: ./milestones/mil-004-step3-flip-cards.md
|
||||
[MIL-005]: ./milestones/mil-005-step4-save-progress.md
|
||||
[MIL-006]: ./milestones/mil-006-malay-speech.md
|
||||
[MIL-007]: ./milestones/mil-007-documentation-and-publication.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
# Project Plan: Flash Card
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | PP-001 |
|
||||
| CrossReference | [BC-001], [SA-001], [US-001], [MIL-001], [MIL-002], [MIL-003], [MIL-004], [MIL-005], [MIL-006], [MIL-007] |
|
||||
| Language | en |
|
||||
| Domain | it |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
This plan schedules the seven phases (gateways) that deliver the flash card program inside the delivery window of one week that the Business Case sets as a constraint (2026-10-14 to 2026-10-21). Each phase is one milestone and is delivered by one pull request, so the Product Owner (S01) can follow the work step by step.
|
||||
|
||||
## Planning Assumptions
|
||||
|
||||
- Week 1 starts 2026-10-14; the plan ends by 2026-10-21, per the Business Case constraint.
|
||||
- One phase takes one day; the last phase (documentation and publication) has three days because the wiki exists in three languages and the screenshots need the finished program.
|
||||
- The baseline documents (Business Case, Stakeholder Analysis, Project Plan, use case documents, ADRs) are accepted before MIL-001 starts, in a pull request of their own.
|
||||
- Phases 2 to 5 follow the four steps of the course assignment in order; phase 6 is the Product Owner's extra.
|
||||
- S01 is owner and approving reviewer of every phase; in autonomous mode the AI acts as stand-in and the review records say so.
|
||||
|
||||
## Gateway Schedule
|
||||
|
||||
| Gateway | Document | Window | Decision date | Owner | Stories | Main deliverable | Milestone |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| Project foundation | [MIL-001] | 2026-10-14 | 2026-10-14 | S01 | none | pyproject, gitignore, skeleton, Doxyfile, first README, word list | [Milestone MIL-001][MS-001] |
|
||||
| Step 1 - User interface | [MIL-002] | 2026-10-15 | 2026-10-15 | S01 | US-001.01 | The window with card and buttons | [Milestone MIL-002][MS-002] |
|
||||
| Step 2 - New flash cards | [MIL-003] | 2026-10-16 | 2026-10-16 | S01 | US-001.02 | Random cards from the word list | [Milestone MIL-003][MS-003] |
|
||||
| Step 3 - Flip the cards | [MIL-004] | 2026-10-17 | 2026-10-17 | S01 | US-001.03 | Flip after 3000 ms | [Milestone MIL-004][MS-004] |
|
||||
| Step 4 - Save progress | [MIL-005] | 2026-10-18 | 2026-10-18 | S01 | US-001.04 | words_to_learn.csv | [Milestone MIL-005][MS-005] |
|
||||
| Spoken Malay word | [MIL-006] | 2026-10-19 | 2026-10-19 | S01 | US-001.05 | Text to speech as optional extra | [Milestone MIL-006][MS-006] |
|
||||
| Documentation and publication | [MIL-007] | 2026-10-19 to 2026-10-21 | 2026-10-21 | S01 | none | README, screenshots, wiki in 3 languages, description and topics | [Milestone MIL-007][MS-007] |
|
||||
|
||||
```plantuml
|
||||
@startgantt
|
||||
Project starts 2026-10-14
|
||||
[Foundation] starts 2026-10-14 and ends 2026-10-14
|
||||
[Step 1 UI] starts 2026-10-15 and ends 2026-10-15
|
||||
[Step 2 Cards] starts 2026-10-16 and ends 2026-10-16
|
||||
[Step 3 Flip] starts 2026-10-17 and ends 2026-10-17
|
||||
[Step 4 Progress] starts 2026-10-18 and ends 2026-10-18
|
||||
[Speech] starts 2026-10-19 and ends 2026-10-19
|
||||
[Documentation] starts 2026-10-19 and ends 2026-10-21
|
||||
[Foundation Go/No-Go] happens 2026-10-14
|
||||
[Step 1 Go/No-Go] happens 2026-10-15
|
||||
[Step 2 Go/No-Go] happens 2026-10-16
|
||||
[Step 3 Go/No-Go] happens 2026-10-17
|
||||
[Step 4 Go/No-Go] happens 2026-10-18
|
||||
[Speech Go/No-Go] happens 2026-10-19
|
||||
[Documentation Go/No-Go] happens 2026-10-21
|
||||
@endgantt
|
||||
```
|
||||
|
||||
## Scope Coverage
|
||||
|
||||
| Business Case scope item | Gateway |
|
||||
| --- | --- |
|
||||
| Tkinter program with the assignment's function names | MIL-002, MIL-003, MIL-004, MIL-005 |
|
||||
| Reading `data/ms-da.csv` | MIL-003 |
|
||||
| Saving and using `words_to_learn.csv` | MIL-005 |
|
||||
| Optional spoken Malay word | MIL-006 |
|
||||
| `pyproject.toml`, `.gitignore`, `Doxyfile`, `.venv` instructions, `pytest`, `constants.py` | MIL-001 |
|
||||
| README, screenshots, wiki in three languages | MIL-007 |
|
||||
| Repository description and topics | MIL-007 |
|
||||
| Framework documents of the baseline | Baseline pull request before MIL-001 |
|
||||
|
||||
## Dependencies
|
||||
|
||||
```
|
||||
Baseline → MIL-001 → MIL-002 → MIL-003 → MIL-004 → MIL-005 → MIL-006 → MIL-007
|
||||
```
|
||||
|
||||
A No-Go on a phase moves every later date by the days the rework takes; the buffer is the 2026-10-20 working day, which has no phase of its own.
|
||||
|
||||
## Plan Risks
|
||||
|
||||
| Risk | Impact | Mitigation |
|
||||
| --- | --- | --- |
|
||||
| No display on the machine that runs the review, so the e2e tests skip | Window behaviour is checked by the view model tests only | The review record states whether the e2e tests ran; the screenshots in MIL-007 prove the window on a machine with a display |
|
||||
| The git host's CI is not available | The publish workflows cannot run | Milestones are published with `sync-project.sh` and the wiki by SSH push (MIL-007) |
|
||||
| The speech extra cannot be installed on the build machine | MIL-006 cannot be demonstrated end to end | The adapter is tested with fakes; the manual check is recorded as not done |
|
||||
|
||||
## Open Issues
|
||||
|
||||
- No Governance document (GOV): see ADR-0003. S01 is the only approver.
|
||||
- The git host's `sync-milestones` workflow is not installed; whether to install it is S01's decision.
|
||||
|
||||
---
|
||||
|
||||
[BC-001]: ./business-case.md
|
||||
[SA-001]: ./stakeholder-analysis.md
|
||||
[US-001]: ./user-stories.md
|
||||
[MIL-001]: ./milestones/mil-001-foundation.md
|
||||
[MIL-002]: ./milestones/mil-002-step1-user-interface.md
|
||||
[MIL-003]: ./milestones/mil-003-step2-new-flash-cards.md
|
||||
[MIL-004]: ./milestones/mil-004-step3-flip-cards.md
|
||||
[MIL-005]: ./milestones/mil-005-step4-save-progress.md
|
||||
[MIL-006]: ./milestones/mil-006-malay-speech.md
|
||||
[MIL-007]: ./milestones/mil-007-documentation-and-publication.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
[MS-001]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/milestone/165
|
||||
[MS-002]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/milestone/166
|
||||
[MS-003]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/milestone/167
|
||||
[MS-004]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/milestone/168
|
||||
[MS-005]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/milestone/169
|
||||
[MS-006]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/milestone/170
|
||||
[MS-007]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/milestone/171
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# RC-029: Review of PY-MIL-007
|
||||
|
||||
## Metadata
|
||||
| Key | Value |
|
||||
| --- | --- |
|
||||
| ID | RC-029 |
|
||||
| CrossReference | [PY-MIL-007], [QC-PY-001] |
|
||||
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [9289426] |
|
||||
|
||||
---
|
||||
|
||||
## Artifact Under Review
|
||||
|
||||
- Instance reviewed: [PY-MIL-007]
|
||||
- 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 | PEP 8 casing holds in `tools/capture_screenshots.py` and the changed view; ruff rule set N passes. |
|
||||
| 2 | Names state purpose in the domain's language; no unexplained abbreviations, no single-letter names outside tiny scopes | Pass | Names state purpose (`capture`, `_make_dpi_aware`, `SCREENSHOT_SEED`). |
|
||||
| 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 on 56 files; the one `type: ignore` is for a Windows-only attribute and says which error it silences. |
|
||||
| 4 | Every function and method signature is type-annotated, including `-> None` | Pass | Every signature is annotated; `mypy --strict` passes on `src` (38 files) and on both tool scripts. |
|
||||
| 5 | No bare `except:`, no swallowed exceptions; specific exceptions are raised and the cause is kept (`raise ... from`) | Pass | No exception handling was added. |
|
||||
| 6 | No mutable default arguments and no shadowed builtins | Pass | No mutable defaults, no builtin shadowed. |
|
||||
| 7 | Files, locks and connections are managed with context managers | Pass | The data copy uses `tempfile.TemporaryDirectory` as a context manager; the Tk root is destroyed. |
|
||||
| 8 | Public modules, classes and functions have docstrings that say what, not how | Pass | Module, functions and constants have Doxygen comments; `doxygen Doxyfile` ends with 0 warnings. |
|
||||
| 9 | Logging uses `logging`, not `print`; no secrets or personal data in log output | Pass | The tool writes the two output paths with `sys.stdout.write`; no `print`, no secret. |
|
||||
| 10 | Classes and operations trace to the Design Class Diagram they implement; deviations are recorded | Pass | The only source change is the button background in `FlashCardView`, which follows `wireframe.md`; the tool is outside the design classes and is not part of the program. |
|
||||
| 11 | Tests exist for new behaviour, are named for the behaviour, and do not depend on order or the network | Pass | 125 tests, 2 consecutive full runs green; one e2e assertion was added for the button background; the tool is checked by running it and reading both images. |
|
||||
| 12 | Type checker runs in strict mode without errors; `Any` is justified in a comment | Pass | `mypy --strict` reports no issue on the touched files; no `Any`. |
|
||||
| 13 | Dependencies are declared and pinned in the project's dependency file, none unused | Pass | `dependencies` stays empty; Pillow is the optional extra `tools` and is imported only by the tool. |
|
||||
| 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 seed, output folder and delay come from one definition each; the delay is `FLIP_DELAY_MS`. |
|
||||
| 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; the tool imports the composition root only. |
|
||||
| 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 | The tool has one purpose (capture); the view change adds no rule. |
|
||||
| 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 | `tools/` holds helper scripts outside `src/`; the layers are unchanged. |
|
||||
| 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 and folder names follow the rule (`docs/images`, `docs/wiki` pages are exceptions for wiki names). |
|
||||
|
||||
## Overall Verdict
|
||||
|
||||
Go — every Mandatory criterion passes. Reviewed by AI as stand-in for S01; not independent of the author.
|
||||
|
||||
Milestone MIL-007 Go criteria: 1 `check-readme.sh` exit 0 and both screenshots linked from the README; 2 `docs/wiki/` holds Home, Install, Usage and Architecture as `<Page>.md`, `<Page>-da.md`, `<Page>-ms.md` (12 pages) and `_Sidebar.md` listing the three languages; 3 the screenshots are captured from the running program by `tools/capture_screenshots.py` and were inspected; 4 the README Setup and Run need 5 commands (create `.venv`, activate, upgrade pip, install, run); 5 the repository has a description and 10 topics (read back from the API); 6 `doxygen Doxyfile` 0 warnings; 7 `docs/sqa/traceability-matrix.md` has a row for every created artifact with its latest `RC-*`, and the plan links each milestone; 8 `check-languages.sh` exit 0 (`check-plan.sh` is a commit-message hook and was not run). The wiki is pushed to the host's wiki after this merge. The Danish and Malay wiki pages were written by the AI and have not been read by a native speaker; this is stated in the end-of-run summary. All Go.
|
||||
|
||||
## Action Items
|
||||
|
||||
| Action | Owner | Due |
|
||||
| --- | --- | --- |
|
||||
| none | - | - |
|
||||
|
||||
---
|
||||
|
||||
[PY-MIL-007]: ../../../tools
|
||||
[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md
|
||||
[9289426]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/92894268c51ec77d56cff48d968566e6265795a2
|
||||
@@ -51,6 +51,7 @@ updated whenever an artifact instance is created or reviewed.
|
||||
| PY-MIL-004 | Python Source Code | - | - | DCD-001, ADR-0002 | - | [RC-026] |
|
||||
| PY-MIL-005 | Python Source Code | - | - | DCD-001, ADR-0002 | - | [RC-027] |
|
||||
| PY-MIL-006 | Python Source Code | - | - | DCD-001, ADR-0002 | - | [RC-028] |
|
||||
| PY-MIL-007 | Python Source Code | - | - | DCD-001, ADR-0002 | - | [RC-029] |
|
||||
|
||||
## Coverage Notes
|
||||
|
||||
@@ -117,3 +118,5 @@ updated whenever an artifact instance is created or reviewed.
|
||||
[PY-MIL-005]: ../../src/flash_card
|
||||
[RC-028]: ./reviews/rc-028-py-mil-006.md
|
||||
[PY-MIL-006]: ../../src/flash_card
|
||||
[RC-029]: ./reviews/rc-029-py-mil-007.md
|
||||
[PY-MIL-007]: ../../src/flash_card
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# Arkitektur
|
||||
|
||||
🌐 [English](Architecture) · **Dansk** · [Bahasa Malaysia](Architecture-ms)
|
||||
|
||||
Programmet er bygget i fire lag under `src/flash_card/`. Importer peger indad; `lint-imports` kontrollerer det.
|
||||
|
||||
| Lag | Indeholder | Må importere |
|
||||
| --- | --- | --- |
|
||||
| `domain` | `Card`, `LanguagePair`, `Vocabulary`, `Deck`, fejlene og repository-grænsefladerne | ingenting |
|
||||
| `application` | `StudySession`, `open_study_session`, `CardDto` og `SpeechPort` | `domain` |
|
||||
| `infrastructure` | CSV-repositories og tale-adaptere | `application`, `domain` |
|
||||
| `presentation` | `FlashCardView`, `FlashCardViewModel` (MVVM) og kompositionsroden `app.py` | alle lag |
|
||||
|
||||
Alle konstanter står i `src/flash_card/constants.py`.
|
||||
|
||||
## Hvor er hvert opgavetrin?
|
||||
|
||||
| Opgave | Kode |
|
||||
| --- | --- |
|
||||
| Trin 1: vindue, lærred, billede, tekster, knapper | `FlashCardView.__init__` i `presentation/features/flash_card/flash_card_view.py`; billederne laves af `tools/generate_images.py` |
|
||||
| Trin 2: læs CSV, tilfældigt ord ved hvert tryk | `CsvVocabularyRepository` og `read_word_list` (erstatter `pandas`), `Deck.draw`, `StudySession.next_card`, `FlashCardView.next_card` |
|
||||
| Trin 3: vend efter 3 sekunder | `FlashCardView.flip_card`, `FlashCardView.flip_timer` (`after`, `after_cancel`), `FlashCardViewModel.flip_card` |
|
||||
| Trin 4: kendte ord, `words_to_learn.csv` | `FlashCardView.is_known`, `StudySession.mark_known`, `CsvProgressRepository`, `open_study_session` |
|
||||
| Ekstra: tale | `SpeechPort`, `GttsSpeech`, `NullSpeech`, `build_speech` i `presentation/app.py` |
|
||||
|
||||
## Hvorfor en lagdelt løsning til en lille opgave?
|
||||
|
||||
Reglerne (hvilket kort der kommer næste gang, hvad et kendt ord gør) testes uden vindue og uden filsystem. Vinduet, CSV-filerne og taletjenesten kan udskiftes uden at røre reglerne. Se ADR-0001 og ADR-0002 i `docs/adr/`.
|
||||
|
||||
## Test
|
||||
|
||||
| Mappe | Hvad den tester |
|
||||
| --- | --- |
|
||||
| `tests/unit/` | Hvert lag for sig, med falske objekter til portene |
|
||||
| `tests/integration/` | Den rigtige ordliste og fremgangsfilen i en midlertidig mappe |
|
||||
| `tests/e2e/` | Det rigtige Tkinter-vindue (springes over uden skærm) |
|
||||
|
||||
## Projektdokumenter
|
||||
|
||||
Business case, plan, design og gennemgangsrapporter ligger i `docs/`. Arbejdet blev udført i syv milepæle, én pull request hver: se `docs/milestones/`.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Seni bina
|
||||
|
||||
🌐 [English](Architecture) · [Dansk](Architecture-da) · **Bahasa Malaysia**
|
||||
|
||||
Program dibina dalam empat lapisan di bawah `src/flash_card/`. Import menuju ke dalam; `lint-imports` memeriksanya.
|
||||
|
||||
| Lapisan | Mengandungi | Boleh mengimport |
|
||||
| --- | --- | --- |
|
||||
| `domain` | `Card`, `LanguagePair`, `Vocabulary`, `Deck`, ralat dan antara muka repositori | tiada |
|
||||
| `application` | `StudySession`, `open_study_session`, `CardDto` dan `SpeechPort` | `domain` |
|
||||
| `infrastructure` | Repositori CSV dan penyesuai suara | `application`, `domain` |
|
||||
| `presentation` | `FlashCardView`, `FlashCardViewModel` (MVVM) dan akar komposisi `app.py` | semua lapisan |
|
||||
|
||||
Semua pemalar terdapat dalam `src/flash_card/constants.py`.
|
||||
|
||||
## Di manakah setiap langkah tugasan?
|
||||
|
||||
| Tugasan | Kod |
|
||||
| --- | --- |
|
||||
| Langkah 1: tetingkap, kanvas, imej, teks, butang | `FlashCardView.__init__` dalam `presentation/features/flash_card/flash_card_view.py`; imej dibuat oleh `tools/generate_images.py` |
|
||||
| Langkah 2: baca CSV, perkataan rawak setiap tekanan | `CsvVocabularyRepository` dan `read_word_list` (menggantikan `pandas`), `Deck.draw`, `StudySession.next_card`, `FlashCardView.next_card` |
|
||||
| Langkah 3: terbalik selepas 3 saat | `FlashCardView.flip_card`, `FlashCardView.flip_timer` (`after`, `after_cancel`), `FlashCardViewModel.flip_card` |
|
||||
| Langkah 4: perkataan diketahui, `words_to_learn.csv` | `FlashCardView.is_known`, `StudySession.mark_known`, `CsvProgressRepository`, `open_study_session` |
|
||||
| Tambahan: suara | `SpeechPort`, `GttsSpeech`, `NullSpeech`, `build_speech` dalam `presentation/app.py` |
|
||||
|
||||
## Mengapa program berlapis untuk tugasan kecil?
|
||||
|
||||
Peraturan (kad mana yang seterusnya, apa yang berlaku apabila perkataan diketahui) diuji tanpa tetingkap atau sistem fail. Tetingkap, fail CSV dan perkhidmatan suara boleh diganti tanpa menyentuh peraturan. Lihat ADR-0001 dan ADR-0002 dalam `docs/adr/`.
|
||||
|
||||
## Ujian
|
||||
|
||||
| Folder | Apa yang diuji |
|
||||
| --- | --- |
|
||||
| `tests/unit/` | Setiap lapisan sendiri, dengan objek palsu untuk port |
|
||||
| `tests/integration/` | Senarai perkataan sebenar dan fail kemajuan dalam folder sementara |
|
||||
| `tests/e2e/` | Tetingkap Tkinter sebenar (dilangkau tanpa paparan) |
|
||||
|
||||
## Dokumen projek
|
||||
|
||||
Kes perniagaan, pelan, reka bentuk dan rekod semakan terdapat dalam `docs/`. Kerja dilakukan dalam tujuh pencapaian, satu pull request setiap satu: lihat `docs/milestones/`.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Architecture
|
||||
|
||||
🌐 **English** · [Dansk](Architecture-da) · [Bahasa Malaysia](Architecture-ms)
|
||||
|
||||
The program is built in four layers under `src/flash_card/`. Imports point inward; `lint-imports` checks this.
|
||||
|
||||
| Layer | Holds | May import |
|
||||
| --- | --- | --- |
|
||||
| `domain` | `Card`, `LanguagePair`, `Vocabulary`, `Deck`, the errors and the repository interfaces | nothing |
|
||||
| `application` | `StudySession`, `open_study_session`, `CardDto` and `SpeechPort` | `domain` |
|
||||
| `infrastructure` | The CSV repositories and the speech adapters | `application`, `domain` |
|
||||
| `presentation` | `FlashCardView`, `FlashCardViewModel` (MVVM) and the composition root `app.py` | all layers |
|
||||
|
||||
All constants are in `src/flash_card/constants.py`.
|
||||
|
||||
## Where is each assignment step?
|
||||
|
||||
| Assignment | Code |
|
||||
| --- | --- |
|
||||
| Step 1: window, canvas, image, texts, buttons | `FlashCardView.__init__` in `presentation/features/flash_card/flash_card_view.py`; images made by `tools/generate_images.py` |
|
||||
| Step 2: read the CSV, random word on each press | `CsvVocabularyRepository` and `read_word_list` (replace `pandas`), `Deck.draw`, `StudySession.next_card`, `FlashCardView.next_card` |
|
||||
| Step 3: flip after 3 seconds | `FlashCardView.flip_card`, `FlashCardView.flip_timer` (`after`, `after_cancel`), `FlashCardViewModel.flip_card` |
|
||||
| Step 4: known words, `words_to_learn.csv` | `FlashCardView.is_known`, `StudySession.mark_known`, `CsvProgressRepository`, `open_study_session` |
|
||||
| Extra: speech | `SpeechPort`, `GttsSpeech`, `NullSpeech`, `build_speech` in `presentation/app.py` |
|
||||
|
||||
## Why a layered program for a small assignment?
|
||||
|
||||
The rules (which card comes next, what a known word does) are tested without a window or a file system. The window, the CSV files and the speech service can be replaced without touching the rules. See ADR-0001 and ADR-0002 in `docs/adr/`.
|
||||
|
||||
## Tests
|
||||
|
||||
| Folder | What it tests |
|
||||
| --- | --- |
|
||||
| `tests/unit/` | Each layer alone, with fakes for the ports |
|
||||
| `tests/integration/` | The real word list and the progress file in a temporary folder |
|
||||
| `tests/e2e/` | The real Tkinter window (skipped when no display exists) |
|
||||
|
||||
## Project documents
|
||||
|
||||
The business case, plan, design and review records are in `docs/`. The work was done in seven milestones, one pull request each: see `docs/milestones/`.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Flash Card
|
||||
|
||||
🌐 [English](Home) · **Dansk** · [Bahasa Malaysia](Home-ms)
|
||||
|
||||
Et flashkortprogram til at lære de mest almindelige malajiske ord med danske oversættelser. Det er løsningen på dag 31 i Udemys kursus *100 Days of Code: The Complete Python Pro Bootcamp*.
|
||||
|
||||

|
||||

|
||||
|
||||
| Side | Læs den, når du vil |
|
||||
| --- | --- |
|
||||
| [Installation](Install-da) | Oprette `.venv`, installere programmet og køre testene |
|
||||
| [Brug](Usage-da) | Øve kortene, forstå fremgangsfilen og bruge indstillingerne |
|
||||
| [Arkitektur](Architecture-da) | Se lagene og finde koden til hvert opgavetrin |
|
||||
|
||||
## De fire opgavetrin
|
||||
|
||||
| Trin | Hvad programmet gør | Milepæl |
|
||||
| --- | --- | --- |
|
||||
| 1. Brugerflade | Et vindue med et kort og to knapper | MIL-002 |
|
||||
| 2. Nye flashkort | Et tilfældigt ord fra ordlisten ved hvert tryk på en knap | MIL-003 |
|
||||
| 3. Vend kortene | Efter 3 sekunder viser kortet den danske oversættelse | MIL-004 |
|
||||
| 4. Gem din fremgang | Kendte ord fjernes, og resten gemmes i `words_to_learn.csv` | MIL-005 |
|
||||
| Ekstra | Det malajiske ord bliver udtalt (valgfrit) | MIL-006 |
|
||||
|
||||
## Til kursister
|
||||
|
||||
Opgavens funktionsnavne er bevaret: `next_card`, `flip_card`, `is_known` og attributterne `flip_timer` og `current_card`. Data læses med standardbibliotekets `csv`-modul i stedet for `pandas`, så kerneprogrammet ikke har nogen afhængigheder ved kørsel.
|
||||
|
||||
Repository: <https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card>
|
||||
@@ -0,0 +1,30 @@
|
||||
# Flash Card
|
||||
|
||||
🌐 [English](Home) · [Dansk](Home-da) · **Bahasa Malaysia**
|
||||
|
||||
Program kad imbas untuk mempelajari perkataan Melayu yang paling kerap digunakan beserta terjemahan Denmark. Ia ialah penyelesaian hari ke-31 kursus Udemy *100 Days of Code: The Complete Python Pro Bootcamp*.
|
||||
|
||||

|
||||

|
||||
|
||||
| Halaman | Baca apabila anda mahu |
|
||||
| --- | --- |
|
||||
| [Pemasangan](Install-ms) | Mencipta `.venv`, memasang program dan menjalankan ujian |
|
||||
| [Penggunaan](Usage-ms) | Berlatih dengan kad, memahami fail kemajuan dan menggunakan pilihan |
|
||||
| [Seni bina](Architecture-ms) | Melihat lapisan dan mencari kod bagi setiap langkah tugasan |
|
||||
|
||||
## Empat langkah tugasan
|
||||
|
||||
| Langkah | Apa yang program lakukan | Pencapaian |
|
||||
| --- | --- | --- |
|
||||
| 1. Antara muka pengguna | Tetingkap dengan satu kad dan dua butang | MIL-002 |
|
||||
| 2. Kad imbas baharu | Satu perkataan rawak daripada senarai perkataan setiap kali butang ditekan | MIL-003 |
|
||||
| 3. Terbalikkan kad | Selepas 3 saat kad menunjukkan terjemahan Denmark | MIL-004 |
|
||||
| 4. Simpan kemajuan anda | Perkataan yang diketahui dibuang dan selebihnya disimpan dalam `words_to_learn.csv` | MIL-005 |
|
||||
| Tambahan | Perkataan Melayu disebut (pilihan) | MIL-006 |
|
||||
|
||||
## Untuk peserta kursus
|
||||
|
||||
Nama fungsi tugasan dikekalkan: `next_card`, `flip_card`, `is_known`, serta atribut `flip_timer` dan `current_card`. Data dibaca dengan modul `csv` pustaka standard dan bukan `pandas`, jadi program teras tidak mempunyai kebergantungan semasa larian.
|
||||
|
||||
Repositori: <https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card>
|
||||
@@ -0,0 +1,30 @@
|
||||
# Flash Card
|
||||
|
||||
🌐 **English** · [Dansk](Home-da) · [Bahasa Malaysia](Home-ms)
|
||||
|
||||
A flash card program for learning the most frequent Malay words with their Danish translations. It is the solution of day 31 of Udemy's *100 Days of Code: The Complete Python Pro Bootcamp*.
|
||||
|
||||

|
||||

|
||||
|
||||
| Page | Read it when you want to |
|
||||
| --- | --- |
|
||||
| [Install](Install) | Create the `.venv`, install the program and run the tests |
|
||||
| [Usage](Usage) | Study the cards, understand the progress file, use the options |
|
||||
| [Architecture](Architecture) | See the layers and find the code of each assignment step |
|
||||
|
||||
## The four assignment steps
|
||||
|
||||
| Step | What the program does | Milestone |
|
||||
| --- | --- | --- |
|
||||
| 1. User interface | A window with a card and two buttons | MIL-002 |
|
||||
| 2. New flash cards | A random word from the word list on every button press | MIL-003 |
|
||||
| 3. Flip the cards | After 3 seconds the card shows the Danish translation | MIL-004 |
|
||||
| 4. Save your progress | Known words are removed and the rest is saved in `words_to_learn.csv` | MIL-005 |
|
||||
| Extra | The Malay word is spoken (optional) | MIL-006 |
|
||||
|
||||
## For course participants
|
||||
|
||||
The function names of the assignment are kept: `next_card`, `flip_card`, `is_known`, and the attributes `flip_timer` and `current_card`. The data is read with the standard library `csv` module instead of `pandas`, so the core program has no runtime dependency.
|
||||
|
||||
Repository: <https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card>
|
||||
@@ -0,0 +1,65 @@
|
||||
# Installation
|
||||
|
||||
🌐 [English](Install) · **Dansk** · [Bahasa Malaysia](Install-ms)
|
||||
|
||||
## Krav
|
||||
|
||||
- Python 3.13 eller nyere med Tkinter (på Debian eller Ubuntu: `sudo apt install python3-tk`).
|
||||
- `git`.
|
||||
- Valgfrit: en internetforbindelse og tilvalget `speech`, hvis du vil høre det malajiske ord.
|
||||
|
||||
## Hent koden
|
||||
|
||||
```bash
|
||||
git clone https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card.git
|
||||
cd 031-flash-card
|
||||
```
|
||||
|
||||
## Opret og brug et lokalt virtuelt miljø
|
||||
|
||||
Windows (PowerShell):
|
||||
|
||||
```powershell
|
||||
python -m venv .venv
|
||||
.\.venv\Scripts\Activate.ps1
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
Linux og macOS:
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
- `.[dev]` tilføjer `pytest`, `ruff`, `mypy` og `import-linter`. Brug `.`, hvis du kun vil køre programmet.
|
||||
- Hvis PowerShell nægter at køre `Activate.ps1`, så kør `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` én gang.
|
||||
- Forlad miljøet med `deactivate`; slet mappen `.venv` for at starte forfra.
|
||||
|
||||
## Udtalt malajisk ord (valgfrit)
|
||||
|
||||
```bash
|
||||
python -m pip install -e ".[speech]"
|
||||
```
|
||||
|
||||
Det installerer `gTTS` og `playsound==1.2.2`. Uden tilvalget virker programmet uden lyd.
|
||||
|
||||
## Kør og test
|
||||
|
||||
```bash
|
||||
python -m flash_card
|
||||
python -m pytest
|
||||
```
|
||||
|
||||
Vinduestesten i `tests/e2e/` springes over, når der ikke er en skærm.
|
||||
|
||||
## Dokumentation af kildekoden
|
||||
|
||||
```bash
|
||||
doxygen Doxyfile
|
||||
```
|
||||
|
||||
HTML-filerne skrives til `docs/doxygen/html/index.html`.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Pemasangan
|
||||
|
||||
🌐 [English](Install) · [Dansk](Install-da) · **Bahasa Malaysia**
|
||||
|
||||
## Keperluan
|
||||
|
||||
- Python 3.13 atau lebih baharu dengan Tkinter (pada Debian atau Ubuntu: `sudo apt install python3-tk`).
|
||||
- `git`.
|
||||
- Pilihan: sambungan internet dan tambahan `speech` jika anda mahu mendengar perkataan Melayu.
|
||||
|
||||
## Dapatkan kod
|
||||
|
||||
```bash
|
||||
git clone https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card.git
|
||||
cd 031-flash-card
|
||||
```
|
||||
|
||||
## Cipta dan gunakan persekitaran maya setempat
|
||||
|
||||
Windows (PowerShell):
|
||||
|
||||
```powershell
|
||||
python -m venv .venv
|
||||
.\.venv\Scripts\Activate.ps1
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
Linux dan macOS:
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
- `.[dev]` menambah `pytest`, `ruff`, `mypy` dan `import-linter`. Gunakan `.` jika anda hanya mahu menjalankan program.
|
||||
- Jika PowerShell enggan menjalankan `Activate.ps1`, jalankan `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` sekali.
|
||||
- Keluar daripada persekitaran dengan `deactivate`; padam folder `.venv` untuk bermula semula.
|
||||
|
||||
## Perkataan Melayu bersuara (pilihan)
|
||||
|
||||
```bash
|
||||
python -m pip install -e ".[speech]"
|
||||
```
|
||||
|
||||
Ini memasang `gTTS` dan `playsound==1.2.2`. Tanpa tambahan ini program berfungsi tanpa bunyi.
|
||||
|
||||
## Jalankan dan uji
|
||||
|
||||
```bash
|
||||
python -m flash_card
|
||||
python -m pytest
|
||||
```
|
||||
|
||||
Ujian tetingkap dalam `tests/e2e/` dilangkau apabila tiada paparan.
|
||||
|
||||
## Dokumentasi kod sumber
|
||||
|
||||
```bash
|
||||
doxygen Doxyfile
|
||||
```
|
||||
|
||||
HTML ditulis ke `docs/doxygen/html/index.html`.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Install
|
||||
|
||||
🌐 **English** · [Dansk](Install-da) · [Bahasa Malaysia](Install-ms)
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.13 or later with Tkinter (on Debian or Ubuntu: `sudo apt install python3-tk`).
|
||||
- `git`.
|
||||
- Optional: an internet connection and the `speech` extra to hear the Malay word.
|
||||
|
||||
## Get the code
|
||||
|
||||
```bash
|
||||
git clone https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card.git
|
||||
cd 031-flash-card
|
||||
```
|
||||
|
||||
## Create and use a local virtual environment
|
||||
|
||||
Windows (PowerShell):
|
||||
|
||||
```powershell
|
||||
python -m venv .venv
|
||||
.\.venv\Scripts\Activate.ps1
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
Linux and macOS:
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
- `.[dev]` adds `pytest`, `ruff`, `mypy` and `import-linter`. Use `.` if you only want to run the program.
|
||||
- If PowerShell refuses to run `Activate.ps1`, run `Set-ExecutionPolicy -Scope CurrentUser RemoteSigned` once.
|
||||
- Leave the environment with `deactivate`; delete the `.venv` folder to start over.
|
||||
|
||||
## Spoken Malay word (optional)
|
||||
|
||||
```bash
|
||||
python -m pip install -e ".[speech]"
|
||||
```
|
||||
|
||||
This installs `gTTS` and `playsound==1.2.2`. Without it the program works silently.
|
||||
|
||||
## Run and test
|
||||
|
||||
```bash
|
||||
python -m flash_card
|
||||
python -m pytest
|
||||
```
|
||||
|
||||
The window test in `tests/e2e/` is skipped when no display is available.
|
||||
|
||||
## Documentation of the source code
|
||||
|
||||
```bash
|
||||
doxygen Doxyfile
|
||||
```
|
||||
|
||||
The HTML is written to `docs/doxygen/html/index.html`.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Brug
|
||||
|
||||
🌐 [English](Usage) · **Dansk** · [Bahasa Malaysia](Usage-ms)
|
||||
|
||||
## Øv kortene
|
||||
|
||||
1. Start programmet med `python -m flash_card`.
|
||||
2. Et kort viser et malajisk ord. Prøv at huske den danske oversættelse.
|
||||
3. Efter tre sekunder vender kortet og viser oversættelsen.
|
||||
4. Tryk på det grønne flueben, hvis du kendte ordet, eller på det røde kryds, hvis du ikke gjorde.
|
||||
5. Et nyt tilfældigt ord vises. Gentag.
|
||||
|
||||
Et ord, du har markeret som kendt, fjernes og kommer ikke igen. Når der ikke er flere ord, står der "Nothing left to learn" på kortet.
|
||||
|
||||
## Din fremgang
|
||||
|
||||
- Første gang du trykker på det grønne flueben, skriver programmet `data/words_to_learn.csv` med de ord, du endnu ikke kan.
|
||||
- Næste start bruger den fil. Findes den ikke, bruger programmet hele ordlisten `data/ms-da.csv`.
|
||||
- For at starte forfra skal du slette `data/words_to_learn.csv`.
|
||||
- Det røde kryds ændrer aldrig filen.
|
||||
|
||||
## Filformat
|
||||
|
||||
Begge filer er UTF-8-tekst med ét kort pr. linje og cellerne adskilt af semikolon. Første linje har de to sprogkoder.
|
||||
|
||||
```text
|
||||
ms;da
|
||||
aku;mig
|
||||
yang;hvilke
|
||||
```
|
||||
|
||||
## Indstillinger
|
||||
|
||||
| Indstilling | Betydning |
|
||||
| --- | --- |
|
||||
| `--data-dir <mappe>` | Mappen med `ms-da.csv` og `words_to_learn.csv` (standard: `data/` i repositoryet) |
|
||||
| `--no-speech` | Udtal ikke det malajiske ord, selv om tilvalget til tale er installeret |
|
||||
|
||||
## Brug et andet sprogpar
|
||||
|
||||
Læg en fil med samme format i datamappen og kald den `ms-da.csv`, eller ret `VOCABULARY_FILE_NAME` og `LANGUAGE_NAMES` i `src/flash_card/constants.py`. Kodene i overskriften vises som sprognavne fra `LANGUAGE_NAMES`; ukendte koder vises med store bogstaver.
|
||||
|
||||
## Fejlfinding
|
||||
|
||||
| Problem | Hvad du skal gøre |
|
||||
| --- | --- |
|
||||
| `No module named tkinter` | Installer Tkinter (`python3-tk` på Debian og Ubuntu) |
|
||||
| Ingen lyd | Installer tilvalget `speech` og tjek netværket; programmet logger en advarsel, når udtalen mislykkes |
|
||||
| Programmet stopper med en meddelelse om filen | CSV-filen er forkert opbygget; meddelelsen nævner filen og linjen. Filen bliver ikke overskrevet |
|
||||
@@ -0,0 +1,49 @@
|
||||
# Penggunaan
|
||||
|
||||
🌐 [English](Usage) · [Dansk](Usage-da) · **Bahasa Malaysia**
|
||||
|
||||
## Berlatih dengan kad
|
||||
|
||||
1. Mulakan program dengan `python -m flash_card`.
|
||||
2. Kad menunjukkan satu perkataan Melayu. Cuba ingat terjemahan Denmarknya.
|
||||
3. Selepas tiga saat kad terbalik dan menunjukkan terjemahan.
|
||||
4. Tekan tanda semak hijau jika anda tahu perkataan itu, atau pangkah merah jika tidak.
|
||||
5. Satu perkataan rawak baharu muncul. Ulang.
|
||||
|
||||
Perkataan yang anda tandakan sebagai diketahui dibuang dan tidak muncul lagi. Apabila tiada perkataan lagi, kad menunjukkan "Nothing left to learn".
|
||||
|
||||
## Kemajuan anda
|
||||
|
||||
- Kali pertama anda menekan tanda semak hijau, program menulis `data/words_to_learn.csv` dengan perkataan yang anda belum tahu.
|
||||
- Permulaan seterusnya menggunakan fail itu. Jika ia tiada, program menggunakan senarai penuh `data/ms-da.csv`.
|
||||
- Untuk bermula semula, padam `data/words_to_learn.csv`.
|
||||
- Pangkah merah tidak pernah mengubah fail.
|
||||
|
||||
## Format fail
|
||||
|
||||
Kedua-dua fail ialah teks UTF-8 dengan satu kad setiap baris dan sel dipisahkan oleh koma bertitik. Baris pertama mengandungi dua kod bahasa.
|
||||
|
||||
```text
|
||||
ms;da
|
||||
aku;mig
|
||||
yang;hvilke
|
||||
```
|
||||
|
||||
## Pilihan
|
||||
|
||||
| Pilihan | Maksud |
|
||||
| --- | --- |
|
||||
| `--data-dir <folder>` | Folder yang mengandungi `ms-da.csv` dan `words_to_learn.csv` (lalai: `data/` dalam repositori) |
|
||||
| `--no-speech` | Jangan sebut perkataan Melayu, walaupun tambahan suara dipasang |
|
||||
|
||||
## Gunakan pasangan bahasa lain
|
||||
|
||||
Letakkan fail dengan format yang sama dalam folder data dan namakannya `ms-da.csv`, atau ubah `VOCABULARY_FILE_NAME` dan `LANGUAGE_NAMES` dalam `src/flash_card/constants.py`. Kod pada baris pertama dipaparkan sebagai nama bahasa daripada `LANGUAGE_NAMES`; kod yang tidak dikenali dipaparkan dengan huruf besar.
|
||||
|
||||
## Penyelesaian masalah
|
||||
|
||||
| Masalah | Apa yang perlu dilakukan |
|
||||
| --- | --- |
|
||||
| `No module named tkinter` | Pasang Tkinter (`python3-tk` pada Debian dan Ubuntu) |
|
||||
| Tiada bunyi | Pasang tambahan `speech` dan periksa rangkaian; program mencatat amaran apabila penyebutan gagal |
|
||||
| Program berhenti dengan mesej tentang fail | Fail CSV tidak betul; mesej menyebut fail dan barisnya. Fail tidak ditulis ganti |
|
||||
@@ -0,0 +1,49 @@
|
||||
# Usage
|
||||
|
||||
🌐 **English** · [Dansk](Usage-da) · [Bahasa Malaysia](Usage-ms)
|
||||
|
||||
## Study the cards
|
||||
|
||||
1. Start the program with `python -m flash_card`.
|
||||
2. A card shows a Malay word. Try to remember its Danish translation.
|
||||
3. After three seconds the card turns over and shows the translation.
|
||||
4. Press the green tick when you knew the word, or the red cross when you did not.
|
||||
5. A new random word appears. Repeat.
|
||||
|
||||
A word you marked as known is removed and does not come up again. When no word is left, the card says "Nothing left to learn".
|
||||
|
||||
## Your progress
|
||||
|
||||
- The first time you press the green tick, the program writes `data/words_to_learn.csv` with the words you do not know yet.
|
||||
- The next start uses that file. If it does not exist, the program uses the full word list `data/ms-da.csv`.
|
||||
- To start again, delete `data/words_to_learn.csv`.
|
||||
- The red cross never changes the file.
|
||||
|
||||
## File format
|
||||
|
||||
Both files are UTF-8 text with one card per line and the cells separated by a semicolon. The first line holds the two language codes.
|
||||
|
||||
```text
|
||||
ms;da
|
||||
aku;mig
|
||||
yang;hvilke
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Meaning |
|
||||
| --- | --- |
|
||||
| `--data-dir <folder>` | Folder that holds `ms-da.csv` and `words_to_learn.csv` (default: `data/` of the repository) |
|
||||
| `--no-speech` | Do not speak the Malay word, even when the speech extra is installed |
|
||||
|
||||
## Use another language pair
|
||||
|
||||
Put a file with the same format in the data folder and name it `ms-da.csv`, or change `VOCABULARY_FILE_NAME` and `LANGUAGE_NAMES` in `src/flash_card/constants.py`. The header codes are shown as language names from `LANGUAGE_NAMES`; unknown codes are shown in upper case.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Problem | What to do |
|
||||
| --- | --- |
|
||||
| `No module named tkinter` | Install Tkinter (`python3-tk` on Debian and Ubuntu) |
|
||||
| No sound | Install the `speech` extra and check the network; the program logs a warning when speaking fails |
|
||||
| The program stops with a message about the file | The CSV file is malformed; the message names the file and the line. The file is not overwritten |
|
||||
@@ -0,0 +1,12 @@
|
||||
**Flash Card**
|
||||
|
||||
- [Home](Home)
|
||||
- [Install](Install)
|
||||
- [Usage](Usage)
|
||||
- [Architecture](Architecture)
|
||||
|
||||
**Languages**
|
||||
|
||||
- English: [Home](Home) · [Install](Install) · [Usage](Usage) · [Architecture](Architecture)
|
||||
- Dansk: [Hjem](Home-da) · [Installation](Install-da) · [Brug](Usage-da) · [Arkitektur](Architecture-da)
|
||||
- Bahasa Malaysia: [Utama](Home-ms) · [Pemasangan](Install-ms) · [Penggunaan](Usage-ms) · [Seni bina](Architecture-ms)
|
||||
@@ -24,6 +24,8 @@ dependencies = []
|
||||
[project.optional-dependencies]
|
||||
# Spoken Malay word (text to speech). Optional; the program works without it.
|
||||
speech = ["gTTS>=2.5", "playsound==1.2.2"]
|
||||
# Only for tools/capture_screenshots.py; not needed to run the program.
|
||||
tools = ["pillow>=10"]
|
||||
dev = ["pytest>=8", "ruff>=0.6", "mypy>=1.11", "import-linter>=2.0"]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -107,6 +107,9 @@ class FlashCardView:
|
||||
self.wrong_button = tk.Button(
|
||||
root,
|
||||
image=self._wrong_image,
|
||||
bg=BACKGROUND_COLOR,
|
||||
activebackground=BACKGROUND_COLOR,
|
||||
relief="flat",
|
||||
highlightthickness=0,
|
||||
bd=0,
|
||||
command=self.next_card,
|
||||
@@ -116,6 +119,9 @@ class FlashCardView:
|
||||
self.right_button = tk.Button(
|
||||
root,
|
||||
image=self._right_image,
|
||||
bg=BACKGROUND_COLOR,
|
||||
activebackground=BACKGROUND_COLOR,
|
||||
relief="flat",
|
||||
highlightthickness=0,
|
||||
bd=0,
|
||||
command=self.is_known,
|
||||
|
||||
@@ -163,6 +163,14 @@ def test_buttons_sit_in_row_one_with_their_images(
|
||||
assert str(view.right_button.cget("command"))
|
||||
|
||||
|
||||
def test_buttons_sit_on_the_window_background(
|
||||
window: tuple[tk.Tk, FlashCardView],
|
||||
) -> None:
|
||||
_root, view = window
|
||||
assert view.wrong_button.cget("bg") == BACKGROUND_COLOR
|
||||
assert view.right_button.cget("bg") == BACKGROUND_COLOR
|
||||
|
||||
|
||||
def test_wrong_button_press_shows_next_card(
|
||||
window: tuple[tk.Tk, FlashCardView],
|
||||
) -> None:
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
"""Capture screenshots of the running flash card window.
|
||||
|
||||
@file capture_screenshots.py
|
||||
@brief Starts the program, grabs the front of a card and, three seconds later,
|
||||
the back, and saves both as PNG files.
|
||||
|
||||
The tool needs Pillow (`python -m pip install -e ".[tools]"`), which is a tool
|
||||
dependency only and not a dependency of the program. It grabs the screen area
|
||||
of the window, so it needs a visible desktop.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import ctypes
|
||||
import random
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
from collections.abc import Sequence
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import ImageGrab
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||||
|
||||
from flash_card.constants import ( # noqa: E402
|
||||
DEFAULT_DATA_DIR,
|
||||
FLIP_DELAY_MS,
|
||||
PROJECT_ROOT,
|
||||
VOCABULARY_FILE_NAME,
|
||||
)
|
||||
from flash_card.presentation.app import create_application # noqa: E402
|
||||
|
||||
## @brief Default folder of the screenshots.
|
||||
DEFAULT_OUTPUT_DIR = PROJECT_ROOT / "docs" / "images"
|
||||
## @brief Seed that makes the first card the same on every run.
|
||||
SCREENSHOT_SEED = 7
|
||||
## @brief Extra time in seconds to let the window settle before a grab.
|
||||
SETTLE_SECONDS = 0.5
|
||||
|
||||
|
||||
def _make_dpi_aware() -> None:
|
||||
"""Make Windows report real pixel coordinates (no effect elsewhere)."""
|
||||
if sys.platform == "win32":
|
||||
ctypes.windll.shcore.SetProcessDpiAwareness(2) # type: ignore[attr-defined,unused-ignore]
|
||||
|
||||
|
||||
def _pump(root: object, seconds: float) -> None:
|
||||
"""Run the Tk event loop for a while.
|
||||
|
||||
@param root The Tk root window.
|
||||
@param seconds How long to run.
|
||||
"""
|
||||
end = time.monotonic() + seconds
|
||||
while time.monotonic() < end:
|
||||
root.update() # type: ignore[attr-defined]
|
||||
time.sleep(0.01)
|
||||
|
||||
|
||||
def capture(output_dir: Path) -> list[Path]:
|
||||
"""Capture the front and the back of one card.
|
||||
|
||||
@param output_dir Folder to write `screenshot-front.png` and
|
||||
`screenshot-back.png` into.
|
||||
@return The two files written, front first.
|
||||
"""
|
||||
_make_dpi_aware()
|
||||
output_dir.mkdir(parents=True, exist_ok=True)
|
||||
random.seed(SCREENSHOT_SEED)
|
||||
with tempfile.TemporaryDirectory() as data_dir:
|
||||
shutil.copy(DEFAULT_DATA_DIR / VOCABULARY_FILE_NAME, data_dir)
|
||||
root, view = create_application(Path(data_dir), speech_enabled=False)
|
||||
root.lift()
|
||||
root.attributes("-topmost", True)
|
||||
_pump(root, SETTLE_SECONDS)
|
||||
box = (
|
||||
view.canvas.winfo_rootx() - 20,
|
||||
view.canvas.winfo_rooty() - 20,
|
||||
view.canvas.winfo_rootx() + view.canvas.winfo_width() + 20,
|
||||
view.canvas.winfo_rooty()
|
||||
+ view.canvas.winfo_height()
|
||||
+ view.right_button.winfo_height()
|
||||
+ 20,
|
||||
)
|
||||
front = output_dir / "screenshot-front.png"
|
||||
back = output_dir / "screenshot-back.png"
|
||||
ImageGrab.grab(bbox=box).save(front)
|
||||
_pump(root, FLIP_DELAY_MS / 1000 + SETTLE_SECONDS)
|
||||
ImageGrab.grab(bbox=box).save(back)
|
||||
root.destroy()
|
||||
return [front, back]
|
||||
|
||||
|
||||
def main(argv: Sequence[str] | None = None) -> int:
|
||||
"""Run the tool.
|
||||
|
||||
@param argv Command line arguments, or None for `sys.argv`.
|
||||
@return The exit code, 0 on success.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT_DIR)
|
||||
args = parser.parse_args(argv)
|
||||
for path in capture(args.output_dir):
|
||||
sys.stdout.write(f"{path}\n")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user