Testing
uv2nix
uses the pyproject.nix
build infrastructure.
Unlike the nixpkgs, runtime & test dependencies are not available at build time. Tests should instead be implemented as separate derivations.
This usage pattern shows how to:
- Overriding a package adding tests to
passthru.tests
- Using
passthru.tests
in Flake checks
flake.nix
{
description = "Pytest flake using uv2nix";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
pyproject-nix = {
url = "github:pyproject-nix/pyproject.nix";
inputs.nixpkgs.follows = "nixpkgs";
};
uv2nix = {
url = "github:pyproject-nix/uv2nix";
inputs.pyproject-nix.follows = "pyproject-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
pyproject-build-systems = {
url = "github:pyproject-nix/build-system-pkgs";
inputs.pyproject-nix.follows = "pyproject-nix";
inputs.uv2nix.follows = "uv2nix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
# This example shows testing with pytest using uv2nix.
# You should first read and understand the hello-world example before this one.
outputs =
{
nixpkgs,
uv2nix,
pyproject-nix,
pyproject-build-systems,
...
}:
let
inherit (nixpkgs) lib;
forAllSystems = lib.genAttrs lib.systems.flakeExposed;
workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; };
overlay = workspace.mkPyprojectOverlay {
sourcePreference = "wheel";
};
# Python sets grouped per system
pythonSets = forAllSystems (
system:
let
pkgs = nixpkgs.legacyPackages.${system};
inherit (pkgs) stdenv;
baseSet = pkgs.callPackage pyproject-nix.build.packages {
python = pkgs.python312;
};
# An overlay of build fixups & test additions.
pyprojectOverrides = final: prev: {
# testing is the name of our example package
testing = prev.testing.overrideAttrs (old: {
passthru = old.passthru // {
# Put all tests in the passthru.tests attribute set.
# Nixpkgs also uses the passthru.tests mechanism for ofborg test discovery.
#
# For usage with Flakes we will refer to the passthru.tests attributes to construct the flake checks attribute set.
tests =
let
# Construct a virtual environment with only the test dependency-group enabled for testing.
virtualenv = final.mkVirtualEnv "testing-pytest-env" {
testing = [ "test" ];
};
in
(old.tests or { })
// {
pytest = stdenv.mkDerivation {
name = "${final.testing.name}-pytest";
inherit (final.testing) src;
nativeBuildInputs = [
virtualenv
];
dontConfigure = true;
# Because this package is running tests, and not actually building the main package
# the build phase is running the tests.
#
# In this particular example we also output a HTML coverage report, which is used as the build output.
buildPhase = ''
runHook preBuild
pytest --cov tests --cov-report html
runHook postBuild
'';
# Install the HTML coverage report into the build output.
#
# If you wanted to install multiple test output formats such as TAP outputs
# you could make this derivation a multiple-output derivation.
#
# See https://nixos.org/manual/nixpkgs/stable/#chap-multiple-output for more information on multiple outputs.
installPhase = ''
runHook preInstall
mv htmlcov $out
runHook postInstall
'';
};
};
};
});
};
in
baseSet.overrideScope (
lib.composeManyExtensions [
pyproject-build-systems.overlays.default
overlay
pyprojectOverrides
]
)
);
in
{
# Construct flake checks from Python set
checks = forAllSystems (
system:
let
pythonSet = pythonSets.${system};
in
{
inherit (pythonSet.testing.passthru.tests) pytest;
}
);
};
}
pyproject.toml
[project]
name = "testing"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
[project.scripts]
hello = "testing:hello"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[dependency-groups]
dev = [
"ruff>=0.7.2",
{include-group = "test"}
]
test = [
"pytest-cov>=6.0.0",
"pytest>=8.3.3",
]