Last active
January 29, 2025 14:53
-
-
Save hnaderi/fb488030ce072487e1442c863774a33a to your computer and use it in GitHub Desktop.
NixOS flake for django and mssql using uv2nix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
description = "Environment for the miserables who need to work with mssql on NixOS!"; | |
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"; | |
}; | |
}; | |
outputs = | |
{ self, nixpkgs, uv2nix, pyproject-nix, pyproject-build-systems, ... }: | |
let | |
inherit (nixpkgs) lib; | |
# Load a uv workspace from a workspace root. | |
# Uv2nix treats all uv projects as workspace projects. | |
workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; | |
# Create package overlay from workspace. | |
overlay = workspace.mkPyprojectOverlay { | |
# Prefer prebuilt binary wheels as a package source. | |
# Sdists are less likely to "just work" because of the metadata missing from uv.lock. | |
# Binary wheels are more likely to, but may still require overrides for library dependencies. | |
sourcePreference = "wheel"; # or sourcePreference = "sdist"; | |
# Optionally customise PEP 508 environment | |
# environ = { | |
# platform_release = "5.10.65"; | |
# }; | |
}; | |
# Extend generated overlay with build fixups | |
# | |
# Uv2nix can only work with what it has, and uv.lock is missing essential metadata to perform some builds. | |
# This is an additional overlay implementing build fixups. | |
# See: | |
# - https://pyproject-nix.github.io/uv2nix/FAQ.html | |
pyprojectOverrides = _final: _prev: | |
let inherit (_final) resolveBuildSystem; | |
in { | |
pyodbc = _prev.pyodbc.overrideAttrs (old: { | |
nativeBuildInputs = old.nativeBuildInputs ++ [ pkgs.unixODBC ]; | |
}); | |
cssbeautifier = _prev.cssbeautifier.overrideAttrs (old: { | |
nativeBuildInputs = old.nativeBuildInputs | |
++ resolveBuildSystem { setuptools = [ ]; }; | |
}); | |
jsbeautifier = _prev.jsbeautifier.overrideAttrs (old: { | |
nativeBuildInputs = old.nativeBuildInputs | |
++ resolveBuildSystem { setuptools = [ ]; }; | |
}); | |
}; | |
pkgs = import nixpkgs { | |
system = "x86_64-linux"; | |
config = { | |
allowUnfree = true; | |
permittedInsecurePackages = [ "openssl-1.1.1w" ]; | |
}; | |
}; | |
# Use Python 3.12 from nixpkgs | |
python = pkgs.python312; | |
# Construct package set | |
pythonSet = | |
# Use base package set from pyproject.nix builders | |
(pkgs.callPackage pyproject-nix.build.packages { | |
inherit python; | |
}).overrideScope (lib.composeManyExtensions [ | |
pyproject-build-systems.overlays.default | |
overlay | |
pyprojectOverrides | |
]); | |
in { | |
# Package a virtual environment as our main application. | |
# | |
# Enable no optional dependencies for production build. | |
packages.x86_64-linux.default = | |
pythonSet.mkVirtualEnv "hello-world-env" workspace.deps.default; | |
# Make hello runnable with `nix run` | |
apps.x86_64-linux = { | |
default = { | |
type = "app"; | |
program = "${self.packages.x86_64-linux.default}/bin/hello-world"; | |
}; | |
}; | |
# This example provides two different modes of development: | |
# - Impurely using uv to manage virtual environments | |
# - Pure development using uv2nix to manage virtual environments | |
devShells.x86_64-linux = { | |
# It is of course perfectly OK to keep using an impure virtualenv workflow and only use uv2nix to build packages. | |
# This devShell simply adds Python and undoes the dependency leakage done by Nixpkgs Python infrastructure. | |
impure = pkgs.mkShell { | |
packages = [ python pkgs.uv ]; | |
env = { | |
# Prevent uv from managing Python downloads | |
UV_PYTHON_DOWNLOADS = "never"; | |
# Force uv to use nixpkgs Python interpreter | |
UV_PYTHON = python.interpreter; | |
} // lib.optionalAttrs pkgs.stdenv.isLinux { | |
# Python libraries often load native shared objects using dlopen(3). | |
# Setting LD_LIBRARY_PATH makes the dynamic library loader aware of libraries without using RPATH for lookup. | |
LD_LIBRARY_PATH = | |
lib.makeLibraryPath pkgs.pythonManylinuxPackages.manylinux1; | |
}; | |
shellHook = '' | |
unset PYTHONPATH | |
''; | |
}; | |
# This devShell uses uv2nix to construct a virtual environment purely from Nix, using the same dependency specification as the application. | |
# The notable difference is that we also apply another overlay here enabling editable mode ( https://setuptools.pypa.io/en/latest/userguide/development_mode.html ). | |
# | |
# This means that any changes done to your local files do not require a rebuild. | |
# | |
# Note: Editable package support is still unstable and subject to change. | |
default = let | |
# Create an overlay enabling editable mode for all local dependencies. | |
editableOverlay = workspace.mkEditablePyprojectOverlay { | |
# Use environment variable | |
root = "$REPO_ROOT"; | |
# Optional: Only enable editable for these packages | |
# members = [ "hello-world" ]; | |
}; | |
# Override previous set with our overrideable overlay. | |
editablePythonSet = pythonSet.overrideScope | |
(lib.composeManyExtensions [ | |
editableOverlay | |
# Apply fixups for building an editable package of your workspace packages | |
(final: prev: { | |
hello-world = prev.hello-world.overrideAttrs (old: { | |
# It's a good idea to filter the sources going into an editable build | |
# so the editable package doesn't have to be rebuilt on every change. | |
src = lib.fileset.toSource { | |
root = old.src; | |
fileset = lib.fileset.unions [ | |
(old.src + "/pyproject.toml") | |
(old.src + "/README.md") | |
(old.src + "/hello-world/__init__.py") | |
]; | |
}; | |
# Hatchling (our build system) has a dependency on the `editables` package when building editables. | |
# | |
# In normal Python flows this dependency is dynamically handled, and doesn't need to be explicitly declared. | |
# This behaviour is documented in PEP-660. | |
# | |
# With Nix the dependency needs to be explicitly declared. | |
nativeBuildInputs = old.nativeBuildInputs | |
++ final.resolveBuildSystem { editables = [ ]; }; | |
}); | |
}) | |
]); | |
# Build virtual environment, with local packages being editable. | |
# | |
# Enable all optional dependencies for development. | |
virtualenv = | |
editablePythonSet.mkVirtualEnv "hello-world-dev-env" workspace.deps.all; | |
in pkgs.mkShell { | |
packages = [ virtualenv pkgs.uv pkgs.python3Packages.pylsp-mypy ]; | |
env = { | |
# Don't create venv using uv | |
UV_NO_SYNC = "1"; | |
# Force uv to use Python interpreter from venv | |
UV_PYTHON = "${virtualenv}/bin/python"; | |
# Prevent uv from downloading managed Python's | |
UV_PYTHON_DOWNLOADS = "never"; | |
}; | |
shellHook = '' | |
# Setup ODBC for mysql17 | |
# https://github.com/NixOS/nixpkgs/issues/235407 | |
# https://stackoverflow.com/a/51266453 | |
export ODBCSYSINI=$(pwd)/.odbc | |
export LD_LIBRARY_PATH=${ | |
pkgs.lib.makeLibraryPath | |
(with pkgs; [ openssl_1_1 stdenv.cc.cc.lib unixODBC ]) | |
} | |
mkdir -p .odbc | |
# driver config | |
echo " | |
[ODBC Driver 17 for SQL Server] | |
Description=Microsoft ODBC Driver 17 for SQL Server | |
Driver=$(ls -1 ${pkgs.unixODBCDrivers.msodbcsql17}/lib/*.so*) | |
" > .odbc/odbcinst.ini | |
# Undo dependency propagation by nixpkgs. | |
unset PYTHONPATH | |
# Get repository root using git. This is expanded at runtime by the editable `.pth` machinery. | |
export REPO_ROOT=$(git rev-parse --show-toplevel) | |
''; | |
}; | |
}; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment