I know a little about nix
.
Not a lot.
I know some things about Python virtual environments, asdf
and a few things about package managers.
I’ve heard the combo of direnv
and nix
is fantastic from a number of engineers I trust, but I haven’t had the chance to figure out what these tools can really do.
I could totally ask someone what their setup is, but I decided to ask ChatGPT (gpt-4
) to see what would happen.
The following is the summary of what I did that worked, as instructed and summarized by the LM, with a bit of editing and commentary by me.
Creating a Python environment with Nix#
In this example, we will create a Python environment with specific packages (requests
and beautifulsoup4
) using Nix. We will then use this environment to run a Python script that fetches a web page and prints its title.
Python Script#
Create a Python script named web_title.py
with the following content:
import requests
from bs4 import BeautifulSoup
def get_web_title(url):
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
return soup.title.string
if __name__ == "__main__":
url = "https://nixos.org/"
title = get_web_title(url)
print(f"The title of the web page at {url} is: {title}")
Nix environment#
Create a Nix expression named python-environment.nix
with the following content:
{ pkgs ? import <nixpkgs> { } }:
let
pythonEnv = pkgs.python3.withPackages(ps: with ps; [
ps.beautifulsoup4
ps.requests
]);
in
pkgs.mkShell {
packages = [
pythonEnv
];
}
This Nix expression creates a shell environment with the required Python packages.
The withPackages
function is used to create a custom Python interpreter that includes the specified packages.
Running the script#
To enter the Nix shell environment, run the following command in your terminal:
nix-shell python-environment.nix
Inside the nix-shell
environment, you can run the web_title.py
script with:
python web_title.py
This will fetch the web page at https://nixos.org and print its title.
The title of the web page at https://nixos.org/ is: Nix & NixOS | Reproducible builds and deployments
By using Nix, we ensure that the Python environment and its dependencies are managed in an isolated and reproducible manner, without affecting the rest of the system or other projects.
Adding direnv to the environment#
If you don’t have it already, install direnv
from here.
Create an .envrc
file in the same directory as your python-environment.nix
file with the following content:
use_nix
export MY_SECRET_KEY="your-secret-key-here"
Replace "your-secret-key-here"
with the actual secret you want to use.
Create a symbolic link named shell.nix
pointing to the python-environment.nix
file:
ln -s python-environment.nix shell.nix
Allow direnv
to load the .envrc
file in the current directory:
direnv allow
Now, direnv
will automatically load the Nix environment when you enter the directory, and unload it when you leave. Additionally, the MY_SECRET_KEY
environment variable will be set with the specified value.
You just have everything there, loaded and isolated when you cd
into the project directory.
Inside your Python scripts, you can access the environment variable using the os.environ
dictionary:
import os
secret_key = os.environ["MY_SECRET_KEY"]
IMPORTANT: To avoid sharing sensitive information, do not commit your .envrc
file to version control
Wrapping it up#
To tie it all together, run the example above, but with direnv
you no longer need to run nix-shell python-environment.nix
.
Let’s modify the code a little to print the environment variable.
import os
import requests
from bs4 import BeautifulSoup
def get_web_title(url):
response = requests.get(url)
soup = BeautifulSoup(response.text, 'html.parser')
return soup.title.string
if __name__ == "__main__":
url = "https://nixos.org/"
title = get_web_title(url)
print(f"The title of the web page at {url} is: {title}")
print(os.environ.get("MY_SECRET_KEY"))
Now run it with just:
python web_title.py
Output:
The title of the web page at https://nixos.org/ is: Nix & NixOS | Reproducible builds and deployments
your-secret-key-here
๐