Lab 09: Final Project Setup — Instructions
In this lab you will build the skeleton of your final project repository from scratch, following professional software engineering practices. You will create the repository on GitHub and evolve it commit by commit on main — no branches — so you can watch a real project take shape: package layout, tests, linting, documentation, and CI/CD pipelines.
By the end of the session your repository will already have most of the scaffolding required for the final grade. Your remaining work over the coming weeks is to fill it with meteorological data and analysis.
Additional Resources
- Tips & Reference Guide —
pyproject.tomltemplates, GitHub Actions syntax, MkDocs configuration, git cheatsheet, and badge reference.
Pre-flight Checklist
- Git installed:
git --version(should print2.xor higher). - Python 3.10+:
python --version. - uv installed:
pip install uv(or follow docs.astral.sh/uv). - GitHub account: if you don't have one, create it at github.com — choose a professional username.
- GitHub CLI (optional but recommended):
gh --version. Install from cli.github.com.
Step 0 — Create the GitHub Repository
- Go to github.com → + → New repository.
- Name it
proyecto-meteorologia(or something similar). - Set visibility to Public (required for free GitHub Pages hosting).
- Do not initialise with README,
.gitignore, or licence — we create everything from scratch. - Click Create repository.
Then initialise your local copy:
mkdir -p ~/repos/proyecto-meteorologia
cd ~/repos/proyecto-meteorologia
git init -b main
git remote add origin https://github.com/YOUR_USERNAME/proyecto-meteorologia.git
Configure your identity if you have not done so globally:
Commit 1 — Skeleton and .gitignore
Objective
Create the full directory structure and a .gitignore that prevents data files, virtual environments, and generated artefacts from ever reaching version control.
1.1 — Create the directory tree
mkdir -p .github/workflows data docs notebooks src/weather tests
touch data/.gitkeep # keeps the data/ folder tracked even though its contents are ignored
1.2 — Create .gitignore
Create a file .gitignore at the root of the project with the following content (see the full template in the guide):
- Python bytecode:
__pycache__/,*.pyc,*.egg-info/ - Virtual environments:
.venv/,.uv/ - Jupyter checkpoints:
.ipynb_checkpoints/ - Data files — the most important section:
data/*with!data/.gitkeep - Secrets:
.env,credentials.json - Build output:
site/,dist/,build/ - Coverage:
.coverage,coverage.xml,htmlcov/
1.3 — Add a README stub
Create README.md with just a title and your name — you will complete it in Commit 7.
1.4 — Commit
git add .gitignore README.md data/.gitkeep
git commit -m "Initial commit: project skeleton and .gitignore"
Commit 2 — pyproject.toml and Python Package
Objective
Set up pyproject.toml as the single source of truth for project metadata, dependencies, and tool configuration. Create the src/weather/ package with a couple of utility functions.
2.1 — pyproject.toml
Create pyproject.toml at the root. The key sections are:
[project]— name, version (0.0.1), description,requires-python = ">=3.10", runtimedependencies. We will follow SemVer.[dependency-groups] dev—pytest,pytest-cov,ruff,mkdocs,mkdocs-material.[tool.pytest.ini_options]—testpaths = ["tests"]andpythonpath = ["src"](so tests canimport weather).[tool.ruff]—line-length = 88,target-version = "py310".[tool.ruff.lint]—select = ["E", "F", "W", "I", "UP"].[build-system]—setuptools.
See the complete template in the guide.
2.2 — src/weather/__init__.py
2.3 — src/weather/utils.py
Add at least one utility function relevant to your chosen line of work. As a starting point, include:
celsius_to_fahrenheit(temp_c)— trivial conversion, useful to verify the test pipeline works.
def celsius_to_fahrenheit(temp_c: float) -> float:
"""Convert a temperature from Celsius to Fahrenheit.
Args:
temp_c: The temperature in degrees Celsius.
Returns:
The temperature in degrees Fahrenheit.
"""
return (temp_c * 9 / 5) + 32
Each function must have a docstring with Args: and Returns: sections, and type hints. Following Google style.
2.4 — Install the dependencies
2.5 — Commit
Commit 3 — Tests with pytest and Coverage
Objective
Write a first test suite with enough coverage to validate that the CI pipeline will pass. Aim for ≥70% coverage from the start — it is much easier than retrofitting tests later.
3.1 — tests/__init__.py
Empty file — marks the directory as a Python package so pytest can discover tests.
3.2 — tests/test_utils.py
Write tests for every function in src/weather/utils.py. Organise them in classes (TestCelsiusToFahrenheit, etc.). For each function test:
- The normal (happy path) case.
- At least one edge case or boundary value.
- Any exception it is supposed to raise (
pytest.raises).
Example structure:
import pytest
import pandas as pd
from weather.utils import celsius_to_fahrenheit
class TestCelsiusToFahrenheit:
def test_freezing_point(self):
assert celsius_to_fahrenheit(0) == 32.0
def test_boiling_point(self):
assert celsius_to_fahrenheit(100) == 212.0
def test_negative_forty_is_equal_in_both_scales(self):
assert celsius_to_fahrenheit(-40) == -40.0
3.3 — Run tests and check coverage
You should see a coverage table. Fix any gaps before committing.
3.4 — Commit
Commit 4 — Code Quality with ruff
Objective
Lint and auto-format every Python file in the project. From this point forward, all new code must pass ruff check and ruff format --check before being committed.
4.1 — Lint
Fix any reported issues. Most are auto-fixable:
4.2 — Format
4.3 — Verify CI will pass
uv run ruff check src/ tests/ # must exit with code 0
uv run ruff format --check src/ tests/ # must exit with code 0
4.4 — Commit
If ruff made no changes (your code was already clean), use:
4.5 — VS Code Integration (Optional)
To run Ruff automatically every time you save a Python file in Visual Studio Code:
- Install the Ruff extension from the VS Code Marketplace (publisher:
charliermarsh). - Create a folder named
.vscodein the root of your project. - Inside that folder, create a file named
settings.jsonand add the following configuration:
{
"[python]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "explicit"
}
}
}
Commit 5 — MkDocs Documentation with Material Theme
Objective
Create a documentation site with MkDocs and the Material theme. Verify it builds without errors locally before it goes into CI.
5.1 — mkdocs.yml
Create mkdocs.yml at the root. Key settings:
site_name,site_author,repo_url— fill in your details.theme.name: material,theme.language: es.- Light/dark palette toggle.
- Features:
content.code.copy,navigation.indexes,navigation.top. - Minimal nav:
Home: index.md+Analysis: analysis.md.
See the complete template in the guide.
5.2 — docs/index.md
Include: project title, brief description of your chosen line of work, data source, installation instructions, and your name.
5.3 — docs/analysis.md
A placeholder page with section headings for: Data Loading & Cleaning, Exploratory Analysis, Results, Conclusions. You will fill these in as you develop your project.
5.4 — Build locally
--strict turns warnings into errors — the same flag used in CI. Fix any warnings before committing.
To preview in the browser:
5.5 — Commit
Commit 6 — GitHub Actions CI/CD
Objective
Add three automated workflows: CI (lint + test on every push), documentation deployment to GitHub Pages, and automatic versioned releases.
Before creating the files — enable GitHub Pages
- Go to your repository on GitHub → Settings → Pages.
- Under Build and deployment → Source: Deploy from a branch.
- Set Branch to
gh-pagesand folder to/ (root). - Save. The
gh-pagesbranch will be created automatically after your first push.
6.1 — .github/workflows/ci.yml
Runs on every push and PR to main. Steps:
- Checkout (with
fetch-depth: 0) - Check version bump
- Set up Python (via project file) +
uv uv sync --group devruff check .ruff format --check .pytest --cov=src --cov-report=xml --cov-report=term-missing- Upload
coverage.xmlto Codecov (optional —continue-on-error: true)
See the complete YAML in the guide.
6.2 — .github/workflows/docs.yml
Runs on push to main (and PRs for the build step only). Two jobs:
- build:
mkdocs build --strict - deploy (main only,
permissions: contents: write):mkdocs gh-deploy --force
See the complete YAML in the guide.
6.3 — .github/workflows/release.yml
Runs on push to main. Reads the version from pyproject.toml and creates a GitHub Release + tag if the tag does not already exist.
See the complete YAML in the guide.
6.4 — Commit and push
git add .github/
git commit -m "Add GitHub Actions: CI, docs deploy, and auto-release"
git push -u origin main
Watch the Actions tab on GitHub. All three workflows should turn green within a few minutes. If any workflow fails, read the error log, fix the issue, and push again.
Commit 7 — Complete README with Badges
Objective
Replace the README stub with a complete project README that includes live status badges, installation instructions, and a project structure overview.
7.1 — Badge URLs
Add these badges below the title (replace YOUR_USERNAME with your GitHub username):
| Badge | URL pattern |
|---|---|
| CI status | https://github.com/YOUR_USERNAME/proyecto-meteorologia/actions/workflows/ci.yml/badge.svg |
| Docs status | https://github.com/YOUR_USERNAME/proyecto-meteorologia/actions/workflows/docs.yml/badge.svg |
| Coverage | https://codecov.io/gh/YOUR_USERNAME/proyecto-meteorologia/graph/badge.svg |
| Version | https://img.shields.io/github/v/release/YOUR_USERNAME/proyecto-meteorologia |
| Python version | https://img.shields.io/badge/python-3.10%2B-blue |
| Ruff | https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json |
Embed badges as Markdown image links:
7.2 — README sections
Include at minimum:
- Title and badges
- Description — your line of work, data source, main objective
- Documentation link — link to your GitHub Pages site
- Installation —
git clone,uv sync --group dev - Data download — how to get the data (script or instructions)
- Usage — how to run tests, serve docs, lint
- Project structure — directory tree
- Author
See the full README template in the guide.
7.3 — Commit and push
Final Verification
After all seven commits are pushed, confirm the following:
You should see exactly seven commits on main, with descriptive messages.
Then check on GitHub:
- [ ] Actions tab — all three workflows show ✅ on the latest commit.
- [ ] GitHub Pages —
https://YOUR_USERNAME.github.io/proyecto-meteorologia/loads your docs site. - [ ] Releases — a release
v0.0.1has been created automatically. - [ ] Repository root — the README renders with live green badges.
Note: Probably the coverage badge will display "unknown". I let you guys figure out how to fix it. Probably you will need to login into codecov.io and follow the instructions.
What to Submit
Submit the URL of your GitHub repository through the course platform:
https://github.com/YOUR_USERNAME/proyecto-meteorologia
Before submitting verify:
- [ ] The repository is public.
- [ ] The CI workflow shows ✅ on the last commit.
- [ ] The coverage badge shows the correct percentage.
- [ ] The docs site is deployed and accessible.
- [ ] GitHub Release
v0.0.1exists. - [ ] All seven commits are on
mainwith descriptive messages.
This repository is your final project
Keep committing to it regularly as you develop your analysis. The professor will evaluate the GitHub repository as it stands at the time of the oral presentation on 28 April 2026.
Questions? Check the Tips & Reference Guide or ask your instructor.