Phase 0: Repository Setup

Phase 0: Repository Setup

Objective

Create the project skeleton using uv — the Rust-based Python package manager that replaces pip, venv, and poetry in a single binary. By the end of this phase you have a working directory structure, an isolated environment, and two empty files ready for code.

Python Concepts

Concept Plain English

uv

A package manager for Python. Think of it as pacman for your project — it installs dependencies, creates virtual environments, and runs your code, all without polluting the system Python.

pyproject.toml

The manifest file. It declares your project’s name, version, dependencies, and scripts. The same role as package.json in Node or Cargo.toml in Rust.

__init__.py

A marker file that tells Python "this directory is a package — you can import from it." An empty __init__.py is perfectly valid. Without it, Python treats the directory as a plain folder and import statements fail.

.venv/

A virtual environment — an isolated copy of Python plus any libraries you install. Like node_modules/ but sandboxed: nothing leaks into your system Python. uv creates and manages this automatically.

src/ layout

The modern Python convention puts your package inside src/<package_name>/. This prevents accidental imports from the working directory and forces Python to use the installed version.

tests/ directory

Convention: test files live in a top-level tests/ directory, mirroring the src/ structure. pytest discovers anything prefixed test_.

Steps

1. Initialize the project

uv init association-engine
cd association-engine

This creates:

association-engine/
├── pyproject.toml      (1)
├── README.md
└── src/
    └── association_engine/
        └── __init__.py (2)
1 The manifest. Open it — you will see [project] with name, version, and an empty dependencies list.
2 The package marker. It exists so Python recognizes association_engine as importable.
uv init names the package with underscores (association_engine) even though the directory uses hyphens (association-engine). Python identifiers cannot contain hyphens — this is not a mistake.

2. Examine pyproject.toml

awk '/^\[/' pyproject.toml

You will see section headers like [project], [build-system]. This is TOML — the same format Rust uses, and structurally similar to INI files you have seen in network device configs.

3. Add development dependencies

uv add --dev pytest ruff

This does three things:

  1. Adds pytest and ruff to [dependency-groups] in pyproject.toml

  2. Creates .venv/ if it does not exist

  3. Installs the packages into .venv/

pytest is the test runner. ruff is the linter and formatter — think shellcheck for Python but faster.

4. Create the core module and test file

touch src/association_engine/graph.py
mkdir -p tests
touch tests/__init__.py
touch tests/test_graph.py

The tests/__init__.py makes the test directory a package too — pytest needs this to resolve imports correctly in the src/ layout.

Your tree now looks like:

association-engine/
├── pyproject.toml
├── src/
│   └── association_engine/
│       ├── __init__.py
│       └── graph.py        # your code goes here
└── tests/
    ├── __init__.py
    └── test_graph.py       # your tests go here

5. Write a smoke test

Open tests/test_graph.py and add:

def test_smoke():
    """Verify pytest itself works."""
    assert 1 + 1 == 2

This test does nothing useful yet — it just proves your toolchain is wired correctly.

6. Run tests

uv run pytest tests/ -v

uv run activates the virtual environment transparently and executes the command. You never need to type source .venv/bin/activate.

Expected output:

tests/test_graph.py::test_smoke PASSED

7. Run the linter

uv run ruff check src/

On an empty graph.py this will produce no output — no errors. As you write code, ruff catches style violations, unused imports, and common bugs.

Checklist

  • uv init association-engine completed

  • pyproject.toml exists with [project] section

  • src/association_engine/__init__.py exists

  • src/association_engine/graph.py exists (empty for now)

  • tests/test_graph.py exists with smoke test

  • uv add --dev pytest ruff completed

  • .venv/ directory exists

  • uv run pytest tests/ -v shows PASSED

  • uv run ruff check src/ shows no errors

Verification

# All three must succeed with zero exit code
uv run pytest tests/ -v && echo "tests: ok"
uv run ruff check src/ && echo "lint: ok"
ls src/association_engine/graph.py tests/test_graph.py && echo "files: ok"

If any of these fail, fix the issue before moving to Phase 1. The foundation has to be solid — every phase after this assumes a clean test run.