Skip to content

Commit

Permalink
Fix nix develop
Browse files Browse the repository at this point in the history
  • Loading branch information
charmoniumQ committed Mar 11, 2022
1 parent 50dbf75 commit fa62b59
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 65 deletions.
3 changes: 3 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
use flake .
# https://github.com/nix-community/nix-direnv/issues/109
eval "$shellHook"
25 changes: 9 additions & 16 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
on: [push, pull_request]
jobs:
ci:
all-tests:
runs-on: ubuntu-latest
steps:

- uses: actions/setup-python@v2
with:
python-version: '3.9'
steps:

- uses: snok/install-poetry@v1
- uses: cachix/install-nix-action@v15
with:
version: 1.1.10
virtualenvs-create: true
virtualenvs-in-project: true
nix_path: nixpkgs=channel:nixos-unstable

- uses: actions/checkout@v2

- id: cached-poetry-dependencies
uses: actions/cache@v2
- uses: actions/cache@v2
with:
path: |
.venv
.tox
build/
.tox/
$HOME/.cache/pypoetry/
key: venv-${{ hashFiles('poetry.lock') }}-${{ hashFiles('pyproject.toml') }}

- run: poetry install

- run: poetry run ./script.py all-tests --no-interactive
- run: nix develop --command ./script.py all-tests --no-interactive
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/build/
__pycache__/
.tox/
/.tox/
/.direnv/

/.cache/
44 changes: 14 additions & 30 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,53 +1,37 @@
# How to setup the development environment

This project manages dependencies through [Poetry][poetry] or through [Nix][nix]. These are package managers that create a "project-local" development environment with minimal system-wide changes.
## With Nix

- Poetry is a wrapper around virtualenv/pip, so it can only manage packages in PyPI. Use it like so:
[Nix][nix] is a language-agnostic package manager that installs packages locally. [Nix Flakes][nix flakes] are a way of specifying dependencies to Nix declaraively. Currently, they are [installed separately][install nix flakes]. Use `nix develop` to get a shell or `nix develop --command ipython` to run commands in the project-specific environment.

```
# install Python
# Version should match that in `pyproject.toml` > `tool.poetry.dependencies` > `python`
$ python -m pip --user install poetry
# This is the only "system-wide" command.
$ poetry install
# This creates a virtualenv and installs the dev dependencies.
[nix]: https://nixos.org/
[nix flakes]: https://nixos.wiki/wiki/Flakes
[install nix flakes]: https://nixos.wiki/wiki/Flakes#Installing_flakes

$ poetry run ipython
# This runs just one command, "ipython" in this case, in the project environment.
## With Nix and direnv

$ poetry shell
# This gives you a shell in the project environment.
```
In addition to Nix, I suggest also installing [direnv][direnv] and [nix-direnv][nix-direnv]. Then simply `cd`ing to the project will activate the project-specific environment.

- Nix is a language-agnostic UNIX-agnostic package manager that can create project-local environments. Nix uses Poetry's config file thanks to [poetry2nix][poetry2nix], but it can install binary dependencies that are not in PyPI. However, not all Python packages work in Nix (see [poetry2nix issue #413][issue-413]). Use it like so:
Consider adding this line in your shell's initfile so you can see when `direnv` is activated. `PS1="\$PREPEND_TO_PS1$PS1"` Note that the sigil (dollar sign) in `$PREPEND_TO_PS1` is quoted but the one in `$PS1` is not, so `PS1` is evaluated when the shell initializes, but `PREPEND_TO_PS1` is evaluated before every prompt.

```
# Install nix
# This is the only "system-wide" command.
[direnv]: https://direnv.net/
[nix-direnv]: https://github.com/nix-community/nix-direnv

$ nix develop --command ipython
# This runs just one command in the project environment.
## With Poetry

$ nix develop --command zsh
# This runs a shell in the project environment.
```
Nix can be trouble to set up, so here is how to use the project without Nix. [Poetry][poetry] is a wrapper around `pip`/`virtualenv`, and it will manage dependencies from PyPI, but *you* have to manage external dependencies, e.g. installing the right version of Python, C libraries, etc. Poetry can be installed globally with `python -m pip install poetry. `Use `poetry shell` to get a shell and `poetry run ipython` to run a command in the project-specific environment.

[poetry]: https://python-poetry.org/
[nix]: https://nixos.org/
[poetry2nix]: https://github.com/nix-community/poetry2nix
[issue-413]: https://github.com/nix-community/poetry2nix/issues/413

# How to use development tools

Once in the development environment, use `./script.py` to run black, isort, mypy, etc.
Once in the development environment, use `./script.py` to run development tools. In the order of usefulness,

- `./script.py fmt` runs code formatters (autoimport, isort, black).

- `./script.py test` runs tests and code complexity analysis (mypy, pylint, pytest, coverage, radon in parallel).

- `./script.py all-tests` runs the usual tests and more (proselint, rstcheck, twine, pytest, tox). It runs them in multiple Python versions. This is mostly for CI.
- `./script.py all-tests` runs the usual tests and more (proselint, rstcheck, twine, tox (which runs mypy and pytest)). This is intended for CI.

- `./script.py docs` builds the documentation locally (sphinx, proselint).

Expand Down
55 changes: 37 additions & 18 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -8,46 +8,65 @@
let
pkgs = nixpkgs.legacyPackages.${system};
name = "ACSL.net-scraper";
name-pure-shell = "${name}-pure-shell";
name-shell = "${name}-shell";
name-test = "${name}-test";
default-python = pkgs.python39;
# Alternative Pythons for Tox
alternative-pythons = [
];
poetry2nix-crypto-override = pkgs.poetry2nix.overrides.withDefaults (self: super: {
cryptography = super.cryptography.overridePythonAttrs(old: {
cargoDeps = pkgs.rustPlatform.fetchCargoTarball {
inherit (old) src;
name = "${old.pname}-${old.version}";
sourceRoot = "${old.pname}-${old.version}/src/rust/";
sha256 = "sha256-kozYXkqt1Wpqyo9GYCwN08J+zV92ZWFJY/f+rulxmeQ=";
};
cargoRoot = "src/rust";
nativeBuildInputs = old.nativeBuildInputs ++ (with pkgs.rustPlatform; [
rust.rustc
rust.cargo
cargoSetupHook
]);
});
});
in {
packages.${name} = pkgs.poetry2nix.mkPoetryApplication {
projectDir = ./.;
python = default-python;
};
packages.${name-shell} = pkgs.mkShell {

# There are two approaches to make a poetry project work in Nix:
# 1. Use Nix to install dependencies in poetry.lock.
# 2. Use Nix to install Poetry and use Poetry to install dependencies in poetry.lock.
# Option 2 is less elegant, because it uses a package manager to install a package manager.
# For example, to effectively cache the environment in CI, I have to cache the Nix state and the Poetry venv.
# But at the time of writing poetry2nix DOES NOT WORK with Python's cryptography.
# Cryptography is a core dependency, so it won't work at all.
# ${name-pure-shell} is option 1, ${name-shell} is option 2.
packages.${name-pure-shell} = pkgs.mkShell {
buildInputs = alternative-pythons ++ [
pkgs.poetry
(pkgs.poetry2nix.mkPoetryEnv {
projectDir = ./.;
# default Python for shell
python = default-python;
overrides = poetry2nix-crypto-override;
})
];
# TODO: write a check expression (`nix flake check`)
};

packages.${name-shell} = pkgs.mkShell {
buildInputs = alternative-pythons ++ [
pkgs.poetry
pkgs.libseccomp.lib
pkgs.gcc-unwrapped.lib
];
shellHook = ''
env_hash=$(sha1sum poetry.lock | cut -f1 -d' ')
if [ ! -f build/$env_hash ]; then
poetry install --remove-untracked
if [ ! -d build ]; then
mkdir build
fi
touch build/$env_hash
fi
export PREPEND_TO_PS1="(${name}) "
export PYTHONNOUSERSITE=true
export VIRTUAL_ENV=$(poetry env info -p)
export PATH=$VIRTUAL_ENV/bin:$PATH
export LD_LIBRARY_PATH=LD_LIBRARY_PATH=$(nix eval --raw nixpkgs#libseccomp.lib)/lib:$(nix eval --raw nixpkgs#gcc-unwrapped.lib)/lib:$LD_LIBRARY_PATH
'';
# TODO: write a check expression (`nix flake check`)
};

devShell = self.packages.${system}.${name-shell};

defaultPackage = self.packages.${system}.${name};
});
}

0 comments on commit fa62b59

Please sign in to comment.