Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 13 additions & 26 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,38 @@ on:

jobs:
audit:
name: Full CI Audit Workflow
name: Full CI Audit Workflow
runs-on: ubuntu-latest

steps:
- name: 🧾 Checkout code
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive

- name: 🐍 Set up Python
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: 📜 Install Poetry
uses: snok/install-poetry@v1
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: latest
virtualenvs-create: true
virtualenvs-in-project: true
enable-cache: true

- name: 💾 Cache dependencies
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-${{ hashFiles('**/poetry.lock') }}
restore-keys: |
venv-${{ runner.os }}-
- name: Install dependencies
run: uv sync

- name: 📦 Install dependencies
run: poetry install --all-groups
- name: Check formatting
run: make fmt

- name: 🔍 Run checks
- name: Run checks
run: make check

- name: 🧪 Run tests
- name: Run tests
run: make test

- name: 🧼 Check formatting
run: make fmt

- name: 📈 Write coverage report
run: poetry run coverage lcov -o coverage/lcov.info

- name: Coverage
- name: Upload coverage to Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.github_token }}
71 changes: 71 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# CLAUDE.md

This file provides guidance for Claude Code when working with this repository.

## Project Overview

OTIS-WEB is a Django-based course management system for OTIS (Online Training for International Students), a math olympiad training program. The production server is hosted on PythonAnywhere.

## Tech Stack

- **Framework**: Django 5.2+
- **Python**: 3.13+
- **Package Manager**: uv
- **Database**: SQLite (dev), MySQL (prod)
- **Type Checking**: pyright
- **Linting/Formatting**: ruff, djlint
- **Testing**: pytest with pytest-django, pytest-xdist, coverage

## Common Commands

```bash
make install # Install dependencies with uv
make runserver # Run Django development server
make migrate # Apply database migrations
make migrations # Create new migrations
make check # Run Django checks and pyright type checking
make test # Run tests with coverage
make fmt # Run code formatters (prek)
```

## Project Structure

Key Django apps:
- `core/` - Core models and utilities
- `dashboard/` - Student dashboard
- `roster/` - Student roster management
- `exams/` - Exam management
- `arch/` - Problem archive
- `payments/` - Stripe payment integration
- `rpg/` - Achievement/gamification system
- `wiki/` - Wiki integration
- `otisweb/` - Main project settings

## Development Guidelines

### Code Style
- Follow Google's Python style guide
- Use type annotations for function parameters and return types
- Run `make fmt` before committing to auto-format code
- Run `make check` to verify type checking passes

### Testing
- Write tests for any new functionality in `*/tests.py` files
- Run `make test` to execute tests with coverage
- Tests use pytest with the `--reuse-db` flag for speed

### Database
- Use `make migrations` to create new migrations
- Use `make migrate` to apply migrations
- Fixtures are in `fixtures/` directory; load with `./fixtures/load-all.sh`

### Environment Variables
- Copy `env` to `.env` and configure as needed
- Required for Stripe integration and other optional features

## Type Checking Notes

The codebase is heavily type-checked with pyright. Key settings:
- `typeCheckingMode = "basic"`
- Migrations and test files are excluded from type checking
- Django stubs are installed for better type inference
45 changes: 17 additions & 28 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ It's not a bad idea to write the tests before the code.

## Checks

There's a script `./lint.sh` at the top directory which will run several
automated checks against the current commit.
Run `make fmt` to auto-format code and `make check` to run checks.
You need to make sure your code passes all these checks;
GitHub will run the same tests on any submitted code.

Expand All @@ -93,44 +92,38 @@ Here are some details about what is checked:
Your code should conform to the style of the rest of the OTIS,
which follows Google's standards.

- The codebase uses `isort` and `black`
for linting and formatting of Python files,
- The codebase uses `ruff` for linting and formatting of Python files,
to ensure the uniformity of style across the repository.
- In addition, `djlint` is used to format the HTML templates.

To preserve your sanity you may optionally configure
your editor to automatically apply `black` and `djlint` after each save:
your editor to automatically apply these formatters after each save:
if you're using a sufficiently sophisticated editor,
you can probably configure it to do so.

### Unit testing

Running `python manage.py test` in the top directory will run Django's unit
testing suite. This runs all the checks defined in `**/tests.py`.
Running `make test` will run the test suite with coverage.
This runs all the checks defined in `**/tests.py`.

The `./lint.sh` will actually run `coverage run manage.py test` so it can then
generate a [coverage report](https://coverage.readthedocs.io/en/6.4.4/) showing
which lines of code were actually checked at some point by at least one unit
test. The resulting percentage is a barometer on how far behind Evan is on
writing tests for some of the older code.
The coverage report shows which lines of code were actually
checked at some point by at least one unit test.

### Type checking

If you're new to development, skip this section.
I'll talk to you more about it later.

The OTIS-WEB repository is heavily type-checked.
We use `pyflakes` and `pyright` are to catch type errors and other
issues. This means type annotations are usually required for function
We use `pyright` to catch type errors and other issues.
This means type annotations are usually required for function
parameters or when initializing empty lists or dictionaries.

You should be able to use `pyflakes` in pure Python.
To use `pyright`, you'll need to do a separate installation process:
follow [the README](https://github.com/Microsoft/pyright#installation).
To use `pyright`, you can run `uv run pyright .` or just `make check`.

If your editor supports language server protocols,
you should be able to catch these errors inline.
If your editor doesn't, consider switching 😉
If your editor doesn't, consider switching.

## Submitting

Expand All @@ -150,26 +143,22 @@ Then:
When you submit a pull request,
GitHub will automatically run several checks on the code;
they are roughly the same checks described above,
and the exact specification can be read in `.github/workflows/main.yml`
and the exact specification can be read in `.github/workflows/ci.yml`.
If this is your first time doing this sort of thing
(and you didn't run `./lint.sh` successfully)
it's likely that at least one of these checks will fail.
Don't freak out; I'll help you through getting the tests to pass.

## For people with some software experience

### Pre-commit hooks

A mentioned above, the script `./lint.sh` will run all tests.
So you might like to do something like
You can use `prek` to run pre-commit hooks:

```bash
echo "./lint.sh" > .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
uv run prek install
```

which will prevent you from pushing a commit
that isn't going to pass the tests on GitHub.
This will install hooks that run the formatters and linters before each commit.

### Docker

Expand All @@ -187,8 +176,8 @@ docker run \
otis-web sh
```

Once in there, use `poetry run python ...` to run any python scripts. Also make sure
that you start the runserver with `poetry run python manage.py runserver 0.0.0.0:8000`,
Once in there, use `uv run python ...` to run any python scripts. Also make sure
that you start the runserver with `uv run python manage.py runserver 0.0.0.0:8000`,
as this will connect to the port you put in the `docker run` command. If you changed
it from port 8000 in the `docker run` command, **DO NOT** change it here - instead, just
go to `localhost:PORT`, where `PORT` is the specified port (not 8000 if you changed it).
12 changes: 6 additions & 6 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
# This is a development dockerfile, that's made in 5 minutes by Amol Rama
# If it seems bad, feel free to let him know :)
FROM python:buster

ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
RUN pip install poetry black toml
FROM python:3.13-bookworm

WORKDIR /app

COPY pyproject.toml .
# Install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

COPY pyproject.toml uv.lock ./

RUN poetry install
RUN uv sync --frozen

COPY . .

Expand Down
39 changes: 18 additions & 21 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,47 +1,44 @@
.PHONY: help install runserver migrate makemigrations createsuperuser check test fmt prek-install prek
.PHONY: help install runserver migrate migrations createsuperuser check test fmt prek

help:
@echo "Available commands:"
@echo " make install - Install dependencies with poetry"
@echo " make install - Install dependencies with uv"
@echo " make runserver - Run Django development server"
@echo " make migrate - Apply database migrations"
@echo " make makemigrations - Create new migrations"
@echo " make migrations - Create new migrations"
@echo " make createsuperuser - Create a Django superuser"
@echo " make check - Run Django checks and type checking"
@echo " make test - Run tests"
@echo " make test - Run tests with coverage"
@echo " make fmt - Run code formatter"
@echo " make prek-install - Install prek hooks"
@echo " make prek - Run prek on all files"

install:
poetry install --all-groups
poetry run prek install
uv sync
uv run prek install

runserver:
poetry run python manage.py runserver_plus
uv run python manage.py runserver_plus

migrate:
poetry run python manage.py migrate
uv run python manage.py migrate

makemigrations:
poetry run python manage.py makemigrations
migrations:
@files=$$(uv run python manage.py makemigrations | grep -oP 'migrations/\S+\.py' | tr '\n' ' '); \
if [ -n "$$files" ]; then uv run prek run --files $$files; fi

createsuperuser:
poetry run python manage.py createsuperuser
uv run python manage.py createsuperuser

check:
poetry run python manage.py check
poetry run python manage.py validate_templates
poetry run pyright .
uv run python manage.py check
uv run python manage.py validate_templates
uv run pyright .

test:
poetry run coverage run -m pytest -n auto
uv run pytest -n auto --cov --cov-report=term-missing --cov-report=lcov:coverage/lcov.info

fmt:
poetry run prek run --all-files

prek-install:
poetry run prek install
uv run prek run --all-files

prek:
poetry run prek run --all-files
uv run prek run --all-files
Loading
Loading