-
Sources:
-
Generally, if you use
uv, you shouldnβt activate .venv- always use
uv run uv runonly works with or looks atuv.lock, so any change to the venv will not be reflected
- always use
Setting up an application
- We want:
- clear structure
- predictable imports
- CLI commands
- uv sync as the go-to command for installation
Structure
- The basic structure relies on a
srcfolder, and then the package. Why?- source: https://hynek.me/articles/testing-packaging/
- If you use the ad hoc layout without an
srcdirectory, your tests do not run against the package as it will be installed by its users. They run against whatever the situation in your project directory is. - But this is not just about tests: the same is true for your application. The behavior can change completely once you package and install it somewhere else.
βββ pyproject.toml
βββ src
βββ hello_svc ## package name
βββ __init__.py ## indicate the folder is a package
βββ views.py ## main logic
βββ tests
βββ test_e2e.py
py-project.toml
[project]
name = "hello-svc" ## dashes and underscore are normalized to dashes
version = "0"
requires-python = "==3.13.*"
dependencies = ["fastapi", "granian", "stamina"]
[dependency-groups] ## allows to separate local development and production
dev = ["fastapi[standard]", "pytest"] # dev is a dependency group automatically installed by uv
[build-system] ## specifying uv build, no need for setup.py
requires = ["uv_build"]
build-backend = "uv_build"
Entrypoints
- Entrypoints are clean places for your app to interface with the real world, theyβre the bridge.
- They should contain code that will only run once e.g. setup a config, run logic, and cleanup
- You donβt want outside code to need to know what file to import within your package
It may look like this
βββ src
βΒ Β βββ hello_svc
βΒ Β βββ entrypoints
βΒ Β βΒ Β βββ asgi.py
βΒ Β βΒ Β βββ cli.py
βΒ Β βΒ Β βββ __init__.py
βΒ Β βΒ Β βββ queue_worker.py
βΒ Β βββ __init__.py
βΒ Β βββ views.py
βββ tests
βββ test_e2e.py
Lifecycle or updating
uv lock --upgrade
Local workflows
- Adding a new dependency to your local dev env
uv add --dev <package>
- Ephemeral dependencies
uv run --with <package>not add to the .lock file
- Using just & justfile
- For testing, linting, typing
test *args:
uv run -m pytest {{ args }}
_pre-commit *args:
uvx --with pre-commit-uv pre-commit {{ args }}
lint:
- uv run -m ruff check --fix --unsafe-fixes .
- uv run -m ruff format .
@just _pre-commit run --all-files #run _every hook_ in your `.pre-commit-config.yaml` on every file in the repository,
typing:
uv run -m mypy src
check-all: lint typing