From 0e73d7d0d00cd5993d30c87a5ae2f35c7fa60392 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Tue, 13 Oct 2026 15:40:16 +0800 Subject: [PATCH] Add README with set up, run, test, CI, documentation build and screenshots Closes #17 Closes #18 Closes #19 Closes #20 --- README.md | 141 +++++++++++++++++++++++++++++++++++++++++- docs/images/run.png | Bin 0 -> 12261 bytes docs/images/tests.png | Bin 0 -> 24834 bytes 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 docs/images/run.png create mode 100644 docs/images/tests.png diff --git a/README.md b/README.md index 549593b..8784814 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,141 @@ -# 025-squirrel +# Squirrel Census +Day 25 of Udemy's *100 Days of Code: The Complete Python Pro Bootcamp*: count the +squirrels of the 2018 Central Park Squirrel Census by primary fur colour (gray, +cinnamon, black) and export the counts to `squirrel_count.csv`. Python 3.13 or +later, no runtime dependencies, with tests and source documentation. + +![Program run][img-run] + +## Requirements + +- Python 3.13 or later (`python --version` on Windows, `python3 --version` on Linux and macOS). +- `venv`, which ships with Python (on Debian: the `python3-venv` package). +- The 2018 census file. It is already in the repository under `data/`. +- Optional: [Doxygen][doxygen] 1.9 or later, only to build the source documentation. + +There are no runtime dependencies: the program uses only the Python standard library +([ADR-0001][adr-0001]). `pytest` is needed only to run the tests. + +## Set up + +Create a local virtual environment named `.venv` in the project folder, upgrade `pip` +and install the project with its development tools (pytest, ruff, mypy). + +### 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 it for the current session: +`Set-ExecutionPolicy -Scope Process -ExecutionPolicy RemoteSigned`. + +### Linux debian + +```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 +python3 -m venv .venv +source .venv/bin/activate +python -m pip install --upgrade pip +python -m pip install -e ".[dev]" +``` + +On macOS, Python 3.13 can be installed with `brew install python@3.13`. + +## Run + +With the virtual environment active, run from the project folder: + +```bash +python -m squirrel +``` + +The program reads `data/2018_Central_Park_Squirrel_Census_-_Squirrel_Data.csv`, prints +the colour counts and writes `squirrel_count.csv`: + +```text +Gray: 2473 +Cinnamon: 392 +Black: 103 +``` + +Use other files by passing them as arguments, `python -m squirrel `. +If the census file does not exist the program prints a message and exits with status 2. + +## Run the tests + +```bash +python -m pytest +``` + +![Test run][img-tests] + +The tests use small fixture rows; one test also checks the real 2018 census file when +it is present. + +## Continuous integration + +The workflow [`.gitea/workflows/ci.yml`][ci] runs for every push to `main` and for every +pull request. It sets up Python 3.13, creates a `.venv`, upgrades `pip`, installs the +project with `.[dev]` and runs `python -m pytest`. It uses `github.*` contexts only, so +it also runs on GitHub Actions. + +## Build the source documentation + +The source is documented with Doxygen comments and configured by [`Doxyfile`][doxyfile]. + +```bash +doxygen Doxyfile +``` + +Open `docs/doxygen/html/index.html` in a browser. The output folder is ignored by git. + +## Project layout + +```text +.gitea/workflows/ci.yml continuous integration workflow +data/ the 2018 census file +docs/ business case, plan, milestones, models, reviews, ADRs +docs/images/ screenshots used by this README and the wiki +src/squirrel/ the package: census.py, cli.py, constants.py +tests/ pytest tests +Doxyfile Doxygen configuration +pyproject.toml project configuration (Python >=3.13, no runtime dependencies) +squirrel_count.csv the result of the assignment +``` + +The project documents, in reading order: [Business Case][bc], [Stakeholder +Analysis][sa], [Project Plan][pp], [Use Case][uc], [Domain Model][dm], [ADR-0001][adr-0001]. +The repository also has a wiki in English, Danish and Bahasa Malaysia. + +## License + +GNU Affero General Public License v3.0 or later. See [LICENSE][license]. + +--- + +[img-run]: docs/images/run.png +[img-tests]: docs/images/tests.png +[doxygen]: https://www.doxygen.nl/ +[adr-0001]: docs/adr/adr-0001-standard-library-instead-of-pandas.md +[ci]: .gitea/workflows/ci.yml +[doxyfile]: Doxyfile +[bc]: docs/business-case.md +[sa]: docs/stakeholder-analysis.md +[pp]: docs/project-plan.md +[uc]: docs/uc-001/uc.md +[dm]: docs/domain-model.md +[license]: LICENSE diff --git a/docs/images/run.png b/docs/images/run.png new file mode 100644 index 0000000000000000000000000000000000000000..142e827d32ece7c8de28d561af55dfc3105cc008 GIT binary patch literal 12261 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

e#6T#5iIGC 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 literal 0 HcmV?d00001 diff --git a/docs/images/tests.png b/docs/images/tests.png new file mode 100644 index 0000000000000000000000000000000000000000..b4243ef16992289e91f86ce8e627bd44f375badb GIT binary patch literal 24834 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

7V#L*DKKe*xby1Fu^`rCfTEPa8M1AZCo$ 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 literal 0 HcmV?d00001 -- 2.54.0