From 2450b4a6e26fc961a3c5de0c546b675998d93190 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 15:26:18 +0800 Subject: [PATCH 1/8] Add pyproject.toml for the Day 25 weather repository Task: MIL-001#1 --- pyproject.toml | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..eabbf97 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,61 @@ +[build-system] +requires = ["setuptools>=77"] +build-backend = "setuptools.build_meta" + +[project] +name = "weather" +version = "0.1.0" +description = "Reading CSV weather data with the csv library and pandas, from Udemy's 100 Days of Code (day 25): DataFrame and Series, average, maximum, row selection, create and export." +readme = "README.md" +requires-python = ">=3.13" +license = "AGPL-3.0-only" +license-files = ["LICENSE"] +authors = [{ name = "Jens Tirsvad Nielsen" }] +keywords = ["csv", "pandas", "weather", "udemy", "100-days-of-code", "dataframe"] +classifiers = [ + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.13", + "Topic :: Education", +] +# The csv part runs on the standard library only; pandas is an optional extra. +dependencies = [] + +[project.optional-dependencies] +pandas = [ + "pandas>=2.2", +] +dev = [ + "pandas>=2.2", + "pandas-stubs>=2.2", + "pytest>=8", + "ruff>=0.6", + "mypy>=1.11", +] + +[project.urls] +Repository = "https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-weather" + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.setuptools.package-data] +weather = ["weather_data.csv"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +pythonpath = ["src", "tests"] + +[tool.ruff] +line-length = 88 +target-version = "py313" +src = ["src", "tests"] +extend-exclude = ["framework", "build"] + +[tool.ruff.lint] +select = ["E", "F", "W", "I", "N", "UP", "B", "SIM"] + +[tool.mypy] +python_version = "3.13" +strict = true +files = ["src", "tests"] +mypy_path = ["src", "tests"] -- 2.54.0 From 3db6634b15069ceb38122e4aa1cecace5dceb24c Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 15:26:19 +0800 Subject: [PATCH 2/8] Add the Python .gitignore for the Day 25 weather repository Task: MIL-001#2 --- .gitignore | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4535440 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +# Personal tokens: never commit or import this file +.env + +# Virtual environment +.venv +venv + +# Byte-compiled and cached files +__pycache__ +*.py[cod] +*$py.class + +# Packaging and build output (build/ also holds the Doxygen HTML) +build/ +dist/ +*.egg-info/ +*.egg +.eggs/ +pip-wheel-metadata/ + +# Test, lint and type-check caches +.pytest_cache/ +.ruff_cache/ +.mypy_cache/ +.coverage +.coverage.* +htmlcov/ + +# Editors and operating systems +.idea/ +.vscode/ +*.swp +.DS_Store +Thumbs.db +.codex/agents/ + +# Local output of the program: the exported table of the lecture +new_data.csv -- 2.54.0 From a44339927c23d235d7d3dc14ca7d5f945f0d6495 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 15:26:20 +0800 Subject: [PATCH 3/8] Add constants.py and its test Task: MIL-001#3 --- src/weather/__init__.py | 14 ++++++++++++ src/weather/constants.py | 48 ++++++++++++++++++++++++++++++++++++++++ tests/conftest.py | 16 ++++++++++++++ tests/test_constants.py | 36 ++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 src/weather/__init__.py create mode 100644 src/weather/constants.py create mode 100644 tests/conftest.py create mode 100644 tests/test_constants.py diff --git a/src/weather/__init__.py b/src/weather/__init__.py new file mode 100644 index 0000000..425bd54 --- /dev/null +++ b/src/weather/__init__.py @@ -0,0 +1,14 @@ +## @package weather +# @brief Reading CSV weather data, from Udemy's 100 Days of Code (day 25). +# +# @mainpage Weather Data +# +# The day-25 lectures read the weather data of one week from the file +# weather_data.csv: first with Python's built-in csv library, then with the +# pandas library, which makes the same work a one-liner. The package keeps the +# two ways side by side: csv_reader.py uses the standard library only, and +# analysis.py and export.py need the optional pandas extra. +# +# The constants of the package are in constants.py. + +"""Reading CSV weather data, from Udemy's 100 Days of Code (day 25).""" diff --git a/src/weather/constants.py b/src/weather/constants.py new file mode 100644 index 0000000..f28690a --- /dev/null +++ b/src/weather/constants.py @@ -0,0 +1,48 @@ +## @file constants.py +# @brief Constants of the weather data project. +# +# Every value that the day-25 lectures fix lives here, so that no other module +# contains a magic string or number: the name of the data file, the names of +# its columns, the factors of the Fahrenheit conversion and the name of the +# exported file. + +"""Constants of the weather data project, as fixed by the day-25 lectures.""" + +from pathlib import Path +from typing import Final + +## @brief Folder of this package; the data file lies next to the modules. +PACKAGE_DIR: Final[Path] = Path(__file__).resolve().parent + +## @brief Name of the weather data file of the lecture. +DATA_FILE_NAME: Final[str] = "weather_data.csv" + +## @brief Full path of the weather data file, independent of the working folder. +DATA_FILE: Final[Path] = PACKAGE_DIR / DATA_FILE_NAME + +## @brief Name of the file that the exported table is written to by default. +EXPORT_FILE_NAME: Final[str] = "new_data.csv" + +## @brief Encoding of the CSV files that are read and written. +FILE_ENCODING: Final[str] = "utf-8" + +## @brief Name of the column that holds the day of the week. +COLUMN_DAY: Final[str] = "day" + +## @brief Name of the column that holds the temperature in degrees Celsius. +COLUMN_TEMP: Final[str] = "temp" + +## @brief Name of the column that holds the weather condition, such as `Sunny`. +COLUMN_CONDITION: Final[str] = "condition" + +## @brief Position of the temperature in a row that `csv.reader` returns. +TEMP_COLUMN_INDEX: Final[int] = 1 + +## @brief Numerator of the Celsius to Fahrenheit factor: `temp * 9 / 5 + 32`. +FAHRENHEIT_NUMERATOR: Final[int] = 9 + +## @brief Denominator of the Celsius to Fahrenheit factor: `temp * 9 / 5 + 32`. +FAHRENHEIT_DENOMINATOR: Final[int] = 5 + +## @brief Offset of the Celsius to Fahrenheit conversion: `temp * 9 / 5 + 32`. +FAHRENHEIT_OFFSET: Final[int] = 32 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..ff287b5 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,16 @@ +"""Shared pytest configuration for the weather data tests.""" + +from pathlib import Path + +import pytest + + +@pytest.fixture(autouse=True) +def isolated_working_directory(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: + """Run every test in an empty temporary working directory. + + The export has a default file name relative to the working directory. Without + this fixture, a test that uses the default would write into the folder pytest + was started from. + """ + monkeypatch.chdir(tmp_path) diff --git a/tests/test_constants.py b/tests/test_constants.py new file mode 100644 index 0000000..c9872de --- /dev/null +++ b/tests/test_constants.py @@ -0,0 +1,36 @@ +"""Tests of the constants that the day-25 lectures fix.""" + +from weather import constants + + +def test_data_file_is_the_one_of_the_lecture() -> None: + assert constants.DATA_FILE_NAME == "weather_data.csv" + + +def test_data_file_lies_next_to_the_modules_not_in_the_working_folder() -> None: + assert constants.DATA_FILE.is_absolute() + assert constants.DATA_FILE.parent == constants.PACKAGE_DIR + assert constants.DATA_FILE.name == constants.DATA_FILE_NAME + + +def test_column_names_match_the_header_of_the_lecture() -> None: + assert constants.COLUMN_DAY == "day" + assert constants.COLUMN_TEMP == "temp" + assert constants.COLUMN_CONDITION == "condition" + + +def test_temperature_is_the_second_value_of_a_row() -> None: + assert constants.TEMP_COLUMN_INDEX == 1 + + +def test_fahrenheit_factors_give_the_lecture_formula() -> None: + celsius = 100 + fahrenheit = ( + celsius * constants.FAHRENHEIT_NUMERATOR / constants.FAHRENHEIT_DENOMINATOR + + constants.FAHRENHEIT_OFFSET + ) + assert fahrenheit == 212 + + +def test_exported_file_has_the_name_of_the_lecture() -> None: + assert constants.EXPORT_FILE_NAME == "new_data.csv" -- 2.54.0 From 0bc441e6298c3afd0912a7d706a0b720f830c162 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 15:26:21 +0800 Subject: [PATCH 4/8] Add the README for the Day 25 weather repository Task: MIL-001#4 --- README.md | 151 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 150 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c9f2c67..5a7dbdd 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,151 @@ -# 025-weather +# Weather Data (Day 25) +Reading CSV weather data in Python, first with the built-in `csv` library and then +with `pandas`. It is the day-25 assignment of Udemy's *100 Days of Code: The +Complete Python Pro Bootcamp*. The lectures read the weather of one week from +`weather_data.csv`, collect the temperatures as whole numbers, and then show how +`pandas` does the same in one line: a table is a `DataFrame` and a column of it is +a `Series`. They convert both to a dictionary and a list, compute the average and +the maximum temperature, select rows by a condition (the row of Monday, the row of +the hottest day, Monday's temperature in Fahrenheit), create a `DataFrame` from a +dictionary, and export it to a CSV file. + +The `csv` part has no runtime dependencies; `pandas` is an optional extra. The code +keeps the names of the lectures (`data`, `temperatures`, `temp_list`, `data_dict`, +`average_temp`, `monday`, `to_dict`, `to_list`, `mean`, `max`, `to_csv`) so that you +can compare it with your own solution. + +> **Status:** in progress. The project foundation (configuration, constants, +> documentation settings and continuous integration) is in place; the readers and +> the analysis follow in the next milestones, see `docs/project-plan.md`. + +## Requirements + +- Python 3.13 or newer. +- `git`, to clone the repository. +- Optional: [Doxygen](https://www.doxygen.nl/) to build the source documentation. +- No runtime dependencies. `pandas` (the optional extra `pandas`) is needed for the + second half of the lectures and is installed by the `dev` extra, together with + the development tools (`pytest`, `ruff`, `mypy`). + +## Set up + +Clone the repository, then create a local virtual environment `.venv` in its +root, upgrade `pip` and install the project with its development tools. The +`.venv` folder is ignored by git. + +```bash +git clone https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-weather.git +cd 025-weather +``` + +### Windows powershell + +```powershell +python -m venv .venv +.\.venv\Scripts\Activate.ps1 +python -m pip install --upgrade pip +python -m pip install -e ".[dev]" +``` + +If PowerShell refuses to run the activation script, allow scripts for this +window only with `Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned` +and activate again. + +### Linux debian + +Debian 13 or newer ships Python 3.13. On older releases install Python 3.13 +separately. + +```bash +sudo apt install python3 python3-venv +python3 -m venv .venv +source .venv/bin/activate +python -m pip install --upgrade pip +python -m pip install -e ".[dev]" +``` + +### MacOS + +```bash +brew install python@3.13 +python3.13 -m venv .venv +source .venv/bin/activate +python -m pip install --upgrade pip +python -m pip install -e ".[dev]" +``` + +To install only what the `csv` part needs, leave out the extras: +`python -m pip install -e .`. To add `pandas` without the development tools use +`python -m pip install -e ".[pandas]"`. + +## Run + +With the virtual environment active, the program that prints the results of the +lectures is added in a later milestone (`python -m weather`); until then the +package can be imported: + +```bash +python -c "from weather import constants; print(constants.DATA_FILE)" +``` + +## Run the tests + +The tests write only into temporary folders. + +```bash +pytest +``` + +The same checks that continuous integration runs: + +```bash +python -m pytest +python -m ruff check src tests +python -m ruff format --check src tests +python -m mypy +``` + +## Continuous integration + +`.gitea/workflows/ci.yml` runs on Gitea Actions on every push and on every pull +request. It sets up Python 3.13, upgrades `pip`, installs `.[dev]`, then runs +`pytest`, `ruff` (lint and format check) and `mypy`. It does not build the source +documentation: run `doxygen Doxyfile` yourself, as the next section shows. + +The workflow lives in `.gitea/workflows` and not in `.github/workflows`, so +GitHub does not run it and pushing to a GitHub mirror needs no workflow +permission. + +## Build the source documentation + +The source is documented with Doxygen comments and the `Doxyfile` in the root. +Install Doxygen (`winget install DimitriVanHeesch.Doxygen` on Windows, +`sudo apt install doxygen` on Debian, `brew install doxygen` on macOS), then: + +```bash +doxygen Doxyfile +``` + +The HTML is written to `build/doxygen/index.html`. A warning fails the build. + +## Project layout + +```text +. +├── .gitea/workflows/ci.yml continuous integration (Gitea Actions) +├── docs/ business case, plan, milestones, reviews +├── src/weather/ the package +│ ├── __init__.py +│ └── constants.py every constant of the lectures +├── tests/ pytest tests (conftest.py runs every test in a +│ temporary folder) +├── Doxyfile source documentation settings +├── LICENSE +├── pyproject.toml project configuration +└── README.md +``` + +## License + +GNU Affero General Public License v3.0 only. See [LICENSE](LICENSE). -- 2.54.0 From 4d2a7a2bd935157eb23282d1325708863437134e Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 15:26:22 +0800 Subject: [PATCH 5/8] Add the Doxyfile for the Day 25 weather repository Task: MIL-001#5 --- Doxyfile | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 Doxyfile diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..118053b --- /dev/null +++ b/Doxyfile @@ -0,0 +1,37 @@ +# Doxygen configuration for the weather data project (Python sources in src/). +# +# Build: doxygen Doxyfile +# Output: build/doxygen/index.html +# +# Only the settings that differ from the Doxygen defaults are listed. A warning +# (for example an undocumented public item) fails the build. + +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Weather Data" +PROJECT_BRIEF = "Reading CSV weather data with csv and pandas, Udemy's 100 Days of Code (day 25)" +OUTPUT_DIRECTORY = build +HTML_OUTPUT = doxygen + +# Python sources are documented with Doxygen commands in docstrings and in +# "##" comments. +OPTIMIZE_OUTPUT_JAVA = YES +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO + +INPUT = src +FILE_PATTERNS = *.py +RECURSIVE = YES +SOURCE_BROWSER = YES + +GENERATE_HTML = YES +GENERATE_LATEX = NO +HAVE_DOT = NO + +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_IF_INCOMPLETE_DOC = YES +# NO: with YES, Doxygen also asks for an @return on every "-> None" function. +WARN_NO_PARAMDOC = NO +WARN_AS_ERROR = FAIL_ON_WARNINGS -- 2.54.0 From fb1da368e1531891c27a9143eec589b3c9d6277b Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 15:26:23 +0800 Subject: [PATCH 6/8] Add the continuous integration workflow Task: MIL-001#6 --- .gitea/workflows/ci.yml | 45 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 .gitea/workflows/ci.yml diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..69f1a30 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,45 @@ +# Continuous integration for the Weather Data project (day 25). +# +# Run by Gitea Actions. The file lives in .gitea/workflows, not in +# .github/workflows: GitHub refuses a push that touches .github/workflows from a +# token without the workflow scope, and that blocks the push mirror to GitHub. +# Runs the same checks as the README, "Run the tests". +# +# The tests need no display and write only into pytest's temporary folders. +name: CI + +on: + push: + pull_request: + +permissions: + contents: read + +jobs: + checks: + runs-on: ubuntu-latest + steps: + - name: Check out the repository + uses: actions/checkout@v4 + + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: "3.13" + + - name: Install + run: | + python -m pip install --upgrade pip + python -m pip install -e ".[dev]" + + - name: Tests + run: python -m pytest + + - name: Lint + run: python -m ruff check src tests + + - name: Format check + run: python -m ruff format --check src tests + + - name: Types + run: python -m mypy -- 2.54.0 From 38867cccd1f04cba39283b1300bcbdcff68d9724 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 15:26:24 +0800 Subject: [PATCH 7/8] Record the review of the MIL-001 code (RC-009) --- docs/artifact-registry.md | 118 ++++++++++++------------ docs/sqa/reviews/rc-009-mil-001-code.md | 60 ++++++++++++ 2 files changed, 119 insertions(+), 59 deletions(-) create mode 100644 docs/sqa/reviews/rc-009-mil-001-code.md diff --git a/docs/artifact-registry.md b/docs/artifact-registry.md index a2b17af..5e9452e 100644 --- a/docs/artifact-registry.md +++ b/docs/artifact-registry.md @@ -1,59 +1,59 @@ -# Artifact Registry - -This project's artifact state. Types, short names and `CrossReference -Candidates` come from the framework catalog -(`framework/registry/artifact-catalog.md`); this file only records where -each document lives in *this* project and the next version to use. - -Delete rows for types you don't use. Add a row the first time you create a -document of a type. `Primary File` may contain a glob (e.g. -`docs/uc-*/uc.md`); `framework/scripts/find-crossreferences.sh` reads it. - -| Short Name | Artifact Type | Primary File | Next Available Version | -| --- | --- | --- | --- | -| BC | Business Case | docs/business-case.md | 002 | -| SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 | -| PP | Project Plan | docs/project-plan.md | 002 | -| MIL | Milestone / Gateway | docs/milestones/*.md | 006 | -| DICT | Domain Dictionary | docs/dictionary.md | 002 | -| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 009 | - -## Languages - -Set the PO language when the project starts; `project-planning` asks for it -if it is missing. An artifact of a type marked "Written in the PO language" -exists once, in that language, under its normal name (`business-case.md`); the -`artifact` skill ("One file per artifact") has the rule. - -| Setting | Value | -| --- | --- | -| PO language | en | -| PO domain | it | -| High-level register | IT Executive English | -| Technical register | IT Professional English | - -Every artifact of a type marked "Yes" below states its language and domain in -its `Language` and `Domain` Metadata rows; `new-artifact.sh` fills them from -`PO language` and `PO domain`. `Language` is a BCP 47 code (`da`, `en`). -`Domain` is a value from this list; add a row to introduce a domain, so a -reviewer can see at once which professional vocabulary a document uses. - -| Domain | Meaning | -| --- | --- | -| it | Software and IT | -| medical | Healthcare and medical devices | -| construction | Construction and civil engineering | - -| Artifact types | Register | Written in the PO language | -| --- | --- | --- | -| BC, KPI, PP, MIL | IT Executive English | Yes | -| SA, BMC, BPMN, UCD, US, UC, SSD, DM, RA, GOV, DICT | IT Professional English | Yes | -| OC, SD, DCD, ERD, ADR, TM, RC, QC, source code | IT Professional English | No | - -## Notes - -- "Next Available Version" is the zero-padded (3-digit) version to use the - *next* time a new document of that type is created. Increment it only when - a brand-new document is created, not when an existing document's - `## Version History` gets a row. -- `ADR` uses 4 digits (`0001`); `RC` is sequential across all artifact types. +# Artifact Registry + +This project's artifact state. Types, short names and `CrossReference +Candidates` come from the framework catalog +(`framework/registry/artifact-catalog.md`); this file only records where +each document lives in *this* project and the next version to use. + +Delete rows for types you don't use. Add a row the first time you create a +document of a type. `Primary File` may contain a glob (e.g. +`docs/uc-*/uc.md`); `framework/scripts/find-crossreferences.sh` reads it. + +| Short Name | Artifact Type | Primary File | Next Available Version | +| --- | --- | --- | --- | +| BC | Business Case | docs/business-case.md | 002 | +| SA | Stakeholder Analysis | docs/stakeholder-analysis.md | 002 | +| PP | Project Plan | docs/project-plan.md | 002 | +| MIL | Milestone / Gateway | docs/milestones/*.md | 006 | +| DICT | Domain Dictionary | docs/dictionary.md | 002 | +| RC | SQA Review Record | docs/sqa/reviews/rc-*.md | 010 | + +## Languages + +Set the PO language when the project starts; `project-planning` asks for it +if it is missing. An artifact of a type marked "Written in the PO language" +exists once, in that language, under its normal name (`business-case.md`); the +`artifact` skill ("One file per artifact") has the rule. + +| Setting | Value | +| --- | --- | +| PO language | en | +| PO domain | it | +| High-level register | IT Executive English | +| Technical register | IT Professional English | + +Every artifact of a type marked "Yes" below states its language and domain in +its `Language` and `Domain` Metadata rows; `new-artifact.sh` fills them from +`PO language` and `PO domain`. `Language` is a BCP 47 code (`da`, `en`). +`Domain` is a value from this list; add a row to introduce a domain, so a +reviewer can see at once which professional vocabulary a document uses. + +| Domain | Meaning | +| --- | --- | +| it | Software and IT | +| medical | Healthcare and medical devices | +| construction | Construction and civil engineering | + +| Artifact types | Register | Written in the PO language | +| --- | --- | --- | +| BC, KPI, PP, MIL | IT Executive English | Yes | +| SA, BMC, BPMN, UCD, US, UC, SSD, DM, RA, GOV, DICT | IT Professional English | Yes | +| OC, SD, DCD, ERD, ADR, TM, RC, QC, source code | IT Professional English | No | + +## Notes + +- "Next Available Version" is the zero-padded (3-digit) version to use the + *next* time a new document of that type is created. Increment it only when + a brand-new document is created, not when an existing document's + `## Version History` gets a row. +- `ADR` uses 4 digits (`0001`); `RC` is sequential across all artifact types. diff --git a/docs/sqa/reviews/rc-009-mil-001-code.md b/docs/sqa/reviews/rc-009-mil-001-code.md new file mode 100644 index 0000000..16fffdb --- /dev/null +++ b/docs/sqa/reviews/rc-009-mil-001-code.md @@ -0,0 +1,60 @@ +# RC-009: Code review of MIL-001 (project foundation: constants, package, tests) + +## Metadata +| Key | Value | +| --- | --- | +| ID | RC-009 | +| CrossReference | [MIL-001], [QC-PY-001] | + +## Version History +| Date | Status | Author | Reviewer | Change | Commit | +| --- | --- | --- | --- | --- | --- | +| 2026-10-13 | Proposed | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending | + +--- + +## Artifact Under Review + +- Instance reviewed: the source and tests that [MIL-001] delivers (project foundation: constants, package, tests) +- Checklist used: [QC-PY-001] +- Scope: full review of the files changed on the branch of the milestone +- Language and domain: n/a +- Language reviewer: none +- Mode: autonomous, not independent (the reviewer is `AI as stand-in for S01`; the assistant also wrote the code; the review of the files was done by the `python-developer` agent of the session) + +## Checklist Results + +| # | Criterion | Status | Evidence/Notes | +| --- | --- | --- | --- | +| 1 | Packages, modules, functions, variables, classes and constants follow PEP 8 casing (`snake_case`, `PascalCase`, `UPPER_SNAKE`) | Pass | `PACKAGE_DIR`, `DATA_FILE_NAME` and the other constants are `UPPER_SNAKE`; test functions and the fixture are `snake_case`; the package is `weather`. | +| 2 | Names state purpose in the domain's language; no unexplained abbreviations, no single-letter names outside tiny scopes | Pass | Names state purpose (`FAHRENHEIT_NUMERATOR`, `TEMP_COLUMN_INDEX`, `DATA_FILE`); `temp` is the column name of the lecture's file. | +| 3 | Code is produced by the project's formatter and passes its linter with no unexplained suppressions | Pass | `python -m ruff check src tests` and `python -m ruff format --check src tests` exit 0 with the selection E, F, W, I, N, UP, B, SIM; no `noqa` or ignore. | +| 4 | Every function and method signature is type-annotated, including `-> None` | Pass | Every test function and the fixture are annotated `-> None`; the constants are `Final[...]` annotated. | +| 5 | No bare `except:`, no swallowed exceptions; specific exceptions are raised and the cause is kept (`raise ... from`) | N-A | The changed files contain no exception handling. | +| 6 | No mutable default arguments and no shadowed builtins | Pass | No function has a mutable default and no builtin is shadowed. | +| 7 | Files, locks and connections are managed with context managers | N-A | The changed files open no file. | +| 8 | Public modules, classes and functions have docstrings that say what, not how | Pass | Every constant has a Doxygen `##` comment; the package, `constants.py` and the test and fixture modules have docstrings; `doxygen Doxyfile` ends with 0 warnings. | +| 9 | Logging uses `logging`, not `print`; no secrets or personal data in log output | N-A | The changed files neither log nor print. | +| 10 | Classes and operations trace to the Design Class Diagram they implement; deviations are recorded | Pass | No class exists in these files; the project has no Design Class Diagram (a learning project of this size, recorded in the open issues of [PP-001]). | +| 11 | Tests exist for new behaviour, are named for the behaviour, and do not depend on order or the network | Pass | `tests/test_constants.py` has tests named for the value they fix; none depends on order or the network; the autouse fixture runs each test in a temporary folder. | +| 12 | Type checker runs in strict mode without errors; `Any` is justified in a comment | Pass | `python -m mypy` runs with `strict = true` and reports no issues; no `Any`. | +| 13 | Dependencies are declared and pinned in the project's dependency file, none unused | Pass | `dependencies = []`; the `pandas` extra and the `dev` extra declare `pandas`, `pandas-stubs`, pytest, ruff and mypy with lower bounds; pandas is used by the later milestones. | +| 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 | Every value of the lectures is defined once in `constants.py`; `DATA_FILE` is derived from `PACKAGE_DIR` and `DATA_FILE_NAME`; the Fahrenheit factors are separate constants. | +| 15 | Imports point inward: business-rule modules import no framework, database, UI or delivery-mechanism code, and there are no import cycles | Pass | `constants.py` imports only `pathlib.Path` and `typing.Final`; no import cycle. | +| 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 | A module of constants has one reason to change; there is no class to extend. | + +## Overall Verdict + +Go — all Mandatory criteria pass or are not applicable. Assessed on 2026-10-13 by the assistant that wrote the code, as stand-in for S01 in autonomous mode. Mode: autonomous, not independent. The pull request is the second look. + +## Action Items + +| Action | Owner | Due | +| --- | --- | --- | +| Challenge this `Go` in the run summary or on the pull request if the stand-in decision is not wanted | S01 | 2026-10-23 | + +--- + +[MIL-001]: ../../milestones/mil-001-project-foundation.md +[QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md +[PP-001]: ../../project-plan.md -- 2.54.0 From 6a012f01369dd729d3f16ccc109ca67cfea38286 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 15:26:35 +0800 Subject: [PATCH 8/8] Resolve pending commit links --- docs/sqa/reviews/rc-009-mil-001-code.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sqa/reviews/rc-009-mil-001-code.md b/docs/sqa/reviews/rc-009-mil-001-code.md index 16fffdb..be231af 100644 --- a/docs/sqa/reviews/rc-009-mil-001-code.md +++ b/docs/sqa/reviews/rc-009-mil-001-code.md @@ -9,7 +9,7 @@ ## Version History | Date | Status | Author | Reviewer | Change | Commit | | --- | --- | --- | --- | --- | --- | -| 2026-10-13 | Proposed | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | pending | +| 2026-10-13 | Proposed | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [38867cc] | --- @@ -58,3 +58,4 @@ Go — all Mandatory criteria pass or are not applicable. Assessed on 2026-10-13 [MIL-001]: ../../milestones/mil-001-project-foundation.md [QC-PY-001]: ../../../framework/qc/code/qc-programming-python.md [PP-001]: ../../project-plan.md +[38867cc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/025-weather/commit/38867cccd1f04cba39283b1300bcbdcff68d9724 -- 2.54.0