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 |
|---|---|
|
A package manager for Python.
Think of it as |
|
The manifest file.
It declares your project’s name, version, dependencies, and scripts.
The same role as |
|
A marker file that tells Python "this directory is a package — you can import from it."
An empty |
|
A virtual environment — an isolated copy of Python plus any libraries you install.
Like |
|
The modern Python convention puts your package inside |
|
Convention: test files live in a top-level |
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:
-
Adds
pytestandruffto[dependency-groups]inpyproject.toml -
Creates
.venv/if it does not exist -
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-enginecompleted -
pyproject.tomlexists with[project]section -
src/association_engine/__init__.pyexists -
src/association_engine/graph.pyexists (empty for now) -
tests/test_graph.pyexists with smoke test -
uv add --dev pytest ruffcompleted -
.venv/directory exists -
uv run pytest tests/ -vshows 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.