Skip to main content

A minimalist MCQ quiz web application

Project description

SnekQuiz ๐Ÿ

Python 3.13 Ruff ty pre-commit Coverage

A minimalist multiple-choice quiz web application built with FastAPI, HTMX, and Jinja2 templates.

[!NOTE] This project was vibe-coded with Claude Opus 4.6 ๐Ÿค–โœจ

Features

  • Simple auth โ€“ HTTP Basic. Admins can do admin things, users can take quizzes
  • Quiz list โ€“ See what's available, what you've finished, what's left to do
  • One question at a time โ€“ HTMX gives you instant feedback without page reloads
  • Results โ€“ Your score, what you got wrong, what the right answers were
  • Admin stuff โ€“ Upload quizzes (JSON), see how everyone's doing, delete quizzes when needed
  • API โ€“ POST new quizzes, GET quiz lists, DELETE when you messed up
  • SQLite โ€“ Because sometimes simple is better. No database server required
  • YAML config โ€“ Tweak settings without touching code

Quick Start

# Install dependencies (requires Python 3.13+ and uv)
uv sync

# Run the app (default: http://0.0.0.0:8001)
uv run snekquiz

# or run via the CLI entry-point
snekquiz

# or via python -m
python -m snekquiz

# Run with custom host/port, SSL, auto-reload for development
snekquiz --host localhost --port 8000 --ssl_keyfile key.pem --ssl_certfile cert.pem --reload

# Run with custom config files
snekquiz --config /path/to/app.yaml --log-config /path/to/logging.yaml

# or via uvicorn directly. NB this will expect `uvicorn` CLI args only
uvicorn snekquiz:create_app --factory --host 0.0.0.0 --port 8001

The server starts at http://0.0.0.0:8001 by default. Log in with one of the default accounts configured in src/snekquiz/config/app.yaml:

Admins can also take quizzes. The admin portal is at http://0.0.0.0:8001/admin.

Adding Quizzes

Via the admin portal at /admin/upload, or via the API:

curl -u admin:admin \
  -H "Content-Type: application/json" \
  -d @quiz.json \
  http://localhost:8001/api/quizzes

Quiz format is pretty straightforward:

Example quiz.json
{
  "quiz_name": "Cities quiz",
  "questions": [
    {
      "id": 1,
      "question_type": "single_answer",
      "question_text": "What is the capital of France?",
      "options": [
        {"id": "A", "text": "Paris"},
        {"id": "B", "text": "London"},
        {"id": "C", "text": "Berlin"},
        {"id": "D", "text": "Madrid"}
      ],
      "correct_answers": ["A"],
      "explanation": "Paris is the capital and largest city of France."
    },
    {
      "id": 2,
      "question_type": "multiple_answer",
      "question_text": "Which of the following are cities in Europe?",
      "options": [
        {"id": "A", "text": "Paris"},
        {"id": "B", "text": "London"},
        {"id": "C", "text": "Singapore"},
        {"id": "D", "text": "Perth"}
      ],
      "correct_answers": ["A", "B", "D"],
      "explanation": "Paris (France), London (England), Perth (Scotland)."
    }
  ]
}

Project Structure

src/snekquiz/
โ”œโ”€โ”€ __init__.py          # App factory & CLI entry-point
โ”œโ”€โ”€ auth.py              # Authentication including LDAP layer
โ”œโ”€โ”€ database.py          # SQLite database layer (aiosqlite)
โ”œโ”€โ”€ models.py            # Pydantic models (config + quiz data)
โ”œโ”€โ”€ routes.py            # Web & API routes
โ”œโ”€โ”€ config/
โ”‚   โ”œโ”€โ”€ app.yaml         # Application settings
โ”‚   โ””โ”€โ”€ logging.yaml     # Python logging dictConfig
โ”œโ”€โ”€ templates/
โ”‚   โ”œโ”€โ”€ base.html        # Base layout
โ”‚   โ”œโ”€โ”€ home.html        # Quiz catalogue
โ”‚   โ”œโ”€โ”€ complete.html    # Quiz completion interstitial
โ”‚   โ”œโ”€โ”€ question.html    # Question page
โ”‚   โ”œโ”€โ”€ results.html     # Results / score page
โ”‚   โ”œโ”€โ”€ admin/
โ”‚   โ”‚   โ”œโ”€โ”€ dashboard.html    # Admin overview with aggregated stats
โ”‚   โ”‚   โ”œโ”€โ”€ quiz_detail.html  # Per-quiz attempt drilldown
โ”‚   โ”‚   โ””โ”€โ”€ upload.html       # Quiz upload form
โ”‚   โ””โ”€โ”€ partials/
โ”‚       โ””โ”€โ”€ answer_feedback.html   # HTMX fragment for answer feedback
โ””โ”€โ”€ static/
    โ””โ”€โ”€ style.css        # Minimalist CSS theme

Configuration

App config (src/snekquiz/config/app.yaml) provides default config if no path is provided.

A user specified config file can be supplied with:

  • The APP_CONFIG environment variable: export APP_CONFIG=/path/to/config.yaml
  • The --config (or -c) CLI argument: snekquiz --config /path/to/config.yaml

Logging config (src/snekquiz/config/logging.yaml) provides default logging config.

A user specified config file can be supplied with:

  • The LOG_CONFIG environment variable: export LOG_CONFIG=/path/to/logging.yaml
  • The --log-config (or -l) CLI argument: snekquiz --log-config /path/to/logging.yaml

When running with uvicorn directly, you must use the environment variable approach.

CLI Arguments

snekquiz --help

Available options:

  • --config, -c: Path to app config YAML (default: bundled config/app.yaml)
  • --log-config, -l: Path to logging config YAML (default: bundled config/logging.yaml)
  • --host: Host to bind to (default: 0.0.0.0)
  • --port: Port to bind to (default: 8001)
  • --reload: Enable auto-reload for development
  • --ssl_keyfile: Path to SSL key file
  • --ssl_certfile: Path to SSL certificate file

Development

# Lint & format
uv run ruff check --fix .
uv run ruff format .

# Type check
uv run ty check

# Pre-commit hooks (using prek)
prek install
prek run --all-files

Theme

Colours: #ffffff ยท #000000 ยท #002554 ยท #099d91 ยท #00cc99

White, black, navy, teal, and more teal: #ffffff ยท #000000 ยท #002554 ยท #099d91 ยท #00cc99

License

See LICENSE.


Made with questionable judgment and Claude Opus 4.6.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

snekquiz-0.2.1.tar.gz (21.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

snekquiz-0.2.1-py3-none-any.whl (28.6 kB view details)

Uploaded Python 3

File details

Details for the file snekquiz-0.2.1.tar.gz.

File metadata

  • Download URL: snekquiz-0.2.1.tar.gz
  • Upload date:
  • Size: 21.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for snekquiz-0.2.1.tar.gz
Algorithm Hash digest
SHA256 55639807b848da21c5b1882cc73eb04cbf6e94e9a168430a2f3affa8b1a84e30
MD5 10ef136c07653afdfab5e308b26e8865
BLAKE2b-256 d7620fe258b49fd5b519cdc1c13c535279554f7d163e3c91f25af066d4c20660

See more details on using hashes here.

Provenance

The following attestation bundles were made for snekquiz-0.2.1.tar.gz:

Publisher: python-publish.yaml on ac3673/SnekQuiz

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file snekquiz-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: snekquiz-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 28.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for snekquiz-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 dd87ad9c87b8b85cedbf2dfadc87a5d1951b9796eb98de21bfd5386348a1c084
MD5 dda256b3c64f6303d6f19c53bbd13a7c
BLAKE2b-256 5e783747219a8dd7c2dc925168946684e38576c9f455f81bac2ecdbc39ca96c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for snekquiz-0.2.1-py3-none-any.whl:

Publisher: python-publish.yaml on ac3673/SnekQuiz

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page