Skip to content

Commit a206910

Browse files
authored
version 2.2.0 (#60)
# 2.2.0 (09 Aug 2020) Improved success rate, MacOS support, bugfixes, optimizations ### Features - Improved selection of wheel releases. MacOS is now supported and architectures besides x86_64 should be handled correctly. - Whenever mach-nix resolves dependencies, a visualization of the resulting dependency tree is printed on the terminal. - The dependency DB is now accessed through a caching layer which reduces the resolver's CPU time significantly for larger environments. - The python platform context is now generated from the nix build environment variable `system`. This should decrease the chance of impurities during dependency resolution. ### Fixes - The requires_python attribute of wheels was not respected. This lead to failing builds especially for older python versions. Now `requires_python` is part of the dependency graph and affects resolution. - Detecting the correct package name for python packages in nixpkgs often failed since the attribute names don't follow a fixed schema. This lead to a handful of different errors in different situations. Now the package names are extracted from the pypi `url` inside the `src` attribute which is much more reliable. For packages which are not fetched from pypi, the `pname` attribute is used as fallback. - Fixed bug which lead to the error `attribute 'sdist' missing` if a package from the nixpkgs provider was used which doesn't publish it's source on pypi. (For example `tensorflow`) ### Other Changes - Mach-nix now uses a revision of the nixpkgs-unstable branch instead of nixos-20.03 as base fo the tool and the nixpkgs provider. - Updated revision of the dependency DB
1 parent cb47e6f commit a206910

18 files changed

+117
-62
lines changed

Changelog.md

+18
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1+
# 2.2.0 (09 Aug 2020)
2+
Improved success rate, MacOS support, bugfixes, optimizations
3+
4+
### Features
5+
- Improved selection of wheel releases. MacOS is now supported and architectures besides x86_64 should be handled correctly.
6+
- Whenever mach-nix resolves dependencies, a visualization of the resulting dependency tree is printed on the terminal.
7+
- The dependency DB is now accessed through a caching layer which reduces the resolver's CPU time significantly for larger environments.
8+
- The python platform context is now generated from the nix build environment variable `system`. This should decrease the chance of impurities during dependency resolution.
9+
10+
### Fixes
11+
- The requires_python attribute of wheels was not respected. This lead to failing builds especially for older python versions. Now `requires_python` is part of the dependency graph and affects resolution.
12+
- Detecting the correct package name for python packages in nixpkgs often failed since the attribute names don't follow a fixed schema. This lead to a handful of different errors in different situations. Now the package names are extracted from the pypi `url` inside the `src` attribute which is much more reliable. For packages which are not fetched from pypi, the `pname` attribute is used as fallback.
13+
- Fixed bug which lead to the error `attribute 'sdist' missing` if a package from the nixpkgs provider was used which doesn't publish it's source on pypi. (For example `tensorflow`)
14+
15+
### Other Changes
16+
- Mach-nix now uses a revision of the nixpkgs-unstable branch instead of nixos-20.03 as base fo the tool and the nixpkgs provider.
17+
- Updated revision of the dependency DB
18+
119
# 2.1.1 (30 Jul 2020)
220
Fix broken wheel packages
321
### Fixes:

Readme.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ Table of Contents
5555
You can either install mach-nix via pip or by using nix in case you already have the nix package manager installed.
5656
#### Installing via pip
5757
```shell
58-
pip install git+git://github.com/DavHau/mach-nix@2.1.1
58+
pip install git+git://github.com/DavHau/mach-nix@2.2.0
5959
```
6060
#### Installing via nix
6161
```shell
62-
nix-env -if https://github.com/DavHau/mach-nix/tarball/2.1.1 -A mach-nix
62+
nix-env -if https://github.com/DavHau/mach-nix/tarball/2.2.0 -A mach-nix
6363
```
6464

6565
---
@@ -91,7 +91,7 @@ You can call mach-nix directly from a nix expression
9191
let
9292
mach-nix = import (builtins.fetchGit {
9393
url = "https://github.com/DavHau/mach-nix/";
94-
ref = "2.1.1";
94+
ref = "2.2.0";
9595
});
9696
in
9797
mach-nix.mkPython {

debug/nixpkgs-json.nix

+5-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,8 @@ let
1010
python = (import target_nixpkgs_src { config = {}; }).python37;
1111
in
1212
with import target_nixpkgs_src { config = {}; overlays = []; };
13-
import ../mach_nix/nix/nixpkgs-json.nix { inherit pkgs python; }
13+
import ../mach_nix/nix/nixpkgs-json.nix rec {
14+
inherit pkgs python;
15+
overrides = [(import ./overrides_pre.nix)];
16+
mergeOverrides = lib.foldr lib.composeExtensions (self: super: { });
17+
}

debug/overrides_pre.nix.example

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
pySelf: pySuper: {
2+
pulsar = pySuper.buildPythonPackage {
3+
src = fetchGit {
4+
url = "https://github.com/DavHau/pulsar";
5+
ref = "dev";
6+
rev = "4b01fa19cc28ac912a6ffb18ef64d46bae77f800";
7+
};
8+
pname = "pulsar";
9+
version = "2.0.2"; # not really
10+
doCheck = false;
11+
doInstallCheck = false;
12+
};
13+
asyncssh = pySuper.asyncssh.overridePythonAttrs (oldAttrs: {
14+
patches = [];
15+
});
16+
pytest-dependency = pySuper.pytest-dependency.overridePythonAttrs (oldAttrs: {
17+
patches = [];
18+
});
19+
}

default.nix

+15-18
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,7 @@ let
22
pkgs = import (import ./mach_nix/nix/nixpkgs-src.nix) { config = {}; overlays = []; };
33
python = import ./mach_nix/nix/python.nix { inherit pkgs; };
44
python_deps = (builtins.attrValues (import ./mach_nix/nix/python-deps.nix { inherit python; fetchurl = pkgs.fetchurl; }));
5-
mergeOverrides = with pkgs.lib; overrides:
6-
if length overrides == 0
7-
then a: b: {} # return dummy overrides
8-
else
9-
if length overrides == 1
10-
then elemAt overrides 0
11-
else
12-
let
13-
last = head ( reverseList overrides );
14-
rest = reverseList (tail ( reverseList overrides ));
15-
in
16-
composeExtensions (mergeOverrides rest) last;
5+
mergeOverrides = with pkgs.lib; foldr composeExtensions (self: super: { });
176
autoPatchelfHook = import ./mach_nix/nix/auto_patchelf_hook.nix {inherit (pkgs) fetchurl makeSetupHook writeText;};
187
in
198
rec {
@@ -37,9 +26,15 @@ rec {
3726

3827
# Returns `overrides` and `select_pkgs` which satisfy your requirements
3928
machNix = args:
40-
let result = import "${machNixFile args}/share/mach_nix_file.nix";
29+
let
30+
result = import "${machNixFile args}/share/mach_nix_file.nix";
31+
manylinux =
32+
if pkgs.stdenv.hostPlatform.system == "x86_64-darwin" then
33+
[]
34+
else
35+
pkgs.pythonManylinuxPackages.manylinux1;
4136
in {
42-
overrides = result.overrides pkgs.pythonManylinuxPackages.manylinux1 autoPatchelfHook;
37+
overrides = result.overrides manylinux autoPatchelfHook;
4338
select_pkgs = result.select_pkgs;
4439
};
4540

@@ -57,18 +52,19 @@ rec {
5752
disable_checks ? true, # Disable tests wherever possible to decrease build time.
5853
overrides_pre ? [], # list of pythonOverrides to apply before the machnix overrides
5954
overrides_post ? [], # list of pythonOverrides to apply after the machnix overrides
60-
pkgs ? nixpkgs, # pass custom nixpkgs. Only used for manylinux wheel dependencies
55+
pkgs ? nixpkgs, # pass custom nixpkgs.
6156
providers ? {}, # define provider preferences
6257
pypi_deps_db_commit ? builtins.readFile ./mach_nix/nix/PYPI_DEPS_DB_COMMIT, # python dependency DB version
6358
pypi_deps_db_sha256 ? builtins.readFile ./mach_nix/nix/PYPI_DEPS_DB_SHA256,
64-
python ? pkgs.python3, # select custom python to base overrides on. Should be from nixpkgs >= 20.03
59+
python ? pkgs.python3, # select custom python to base overrides onto. Should be from nixpkgs >= 20.03
6560
_provider_defaults ? with builtins; fromTOML (readFile ./mach_nix/provider_defaults.toml),
6661
...
6762
}:
6863
let
6964
py = python.override { packageOverrides = mergeOverrides overrides_pre; };
7065
result = machNix {
7166
inherit requirements disable_checks providers pypi_deps_db_commit pypi_deps_db_sha256 _provider_defaults;
67+
overrides = overrides_pre;
7268
python = py;
7369
};
7470
py_final = python.override { packageOverrides = mergeOverrides (
@@ -88,17 +84,18 @@ rec {
8884
disable_checks ? true, # Disable tests wherever possible to decrease build time.
8985
overrides_pre ? [], # list of pythonOverrides to apply before the machnix overrides
9086
overrides_post ? [], # list of pythonOverrides to apply after the machnix overrides
91-
pkgs ? nixpkgs, # pass custom nixpkgs. Only used for manylinux wheel dependencies
87+
pkgs ? nixpkgs, # pass custom nixpkgs.
9288
providers ? {}, # define provider preferences
9389
pypi_deps_db_commit ? builtins.readFile ./mach_nix/nix/PYPI_DEPS_DB_COMMIT, # python dependency DB version
9490
pypi_deps_db_sha256 ? builtins.readFile ./mach_nix/nix/PYPI_DEPS_DB_SHA256,
95-
python ? pkgs.python3, # select custom python to base overrides on. Should be from nixpkgs >= 20.03
91+
python ? pkgs.python3, # select custom python to base overrides onto. Should be from nixpkgs >= 20.03
9692
_provider_defaults ? with builtins; fromTOML (readFile ./mach_nix/provider_defaults.toml)
9793
}:
9894
let
9995
py = python.override { packageOverrides = mergeOverrides overrides_pre; };
10096
result = machNix {
10197
inherit requirements disable_checks providers pypi_deps_db_commit pypi_deps_db_sha256 _provider_defaults;
98+
overrides = overrides_pre;
10299
python = py;
103100
};
104101
py_final = python.override { packageOverrides = mergeOverrides (

examples.md

+7-7
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ build a python environment from a list of requirements
2424
let
2525
mach-nix = import (builtins.fetchGit {
2626
url = "https://github.com/DavHau/mach-nix/";
27-
ref = "2.1.1";
27+
ref = "2.2.0";
2828
});
2929
in mach-nix.mkPython {
3030
requirements = builtins.readFile ./requirements.txt;
@@ -37,7 +37,7 @@ Build a python package from its source code and a list of requirements
3737
let
3838
mach-nix = import (builtins.fetchGit {
3939
url = "https://github.com/DavHau/mach-nix/";
40-
ref = "2.1.1";
40+
ref = "2.2.0";
4141
});
4242
in mach-nix.buildPythonPackage {
4343
pname = "my-package";
@@ -53,7 +53,7 @@ Build a python package from its source code and a list of requirements
5353
let
5454
mach-nix = import (builtins.fetchGit {
5555
url = "https://github.com/DavHau/mach-nix/";
56-
ref = "2.1.1";
56+
ref = "2.2.0";
5757
});
5858
in mach-nix.buildPythonPackage rec {
5959
pname = "projectname";
@@ -77,7 +77,7 @@ I have a complex set of requirements including tensorflow. I'd like to have tens
7777
let
7878
mach-nix = import (builtins.fetchGit {
7979
url = "https://github.com/DavHau/mach-nix/";
80-
ref = "2.1.1";
80+
ref = "2.2.0";
8181
});
8282
in mach-nix.mkPython {
8383
@@ -100,7 +100,7 @@ I'd like to install a more recent version of tensorflow which is not available f
100100
let
101101
mach-nix = import (builtins.fetchGit {
102102
url = "https://github.com/DavHau/mach-nix/";
103-
ref = "2.1.1";
103+
ref = "2.2.0";
104104
});
105105
in mach-nix.mkPython {
106106
@@ -129,7 +129,7 @@ I'd like to use a recent version of Pytorch from wheel, but I'd like to build th
129129
let
130130
mach-nix = import (builtins.fetchGit {
131131
url = "https://github.com/DavHau/mach-nix/";
132-
ref = "2.1.1";
132+
ref = "2.2.0";
133133
});
134134
overlays = []; # some very useful overlays
135135
in mach-nix.mkPython rec {
@@ -164,7 +164,7 @@ I have a complex requirements.txt which includes `imagecodecs`. It is available
164164
let
165165
mach-nix = import (builtins.fetchGit {
166166
url = "https://github.com/DavHau/mach-nix/";
167-
ref = "2.1.1";
167+
ref = "2.2.0";
168168
});
169169
in mach-nix.mkPython rec {
170170

mach_nix/VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.1.0
1+
2.2.0

mach_nix/data/nixpkgs.py

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
from packaging.version import Version, parse
77

8+
from mach_nix.cache import cached
9+
810

911
@dataclass
1012
class NixpkgsPyPkg:
@@ -48,6 +50,7 @@ def is_same_ver(ver1, ver2, ver_idx):
4850
return False
4951
return ver1.release[ver_idx] == ver2.release[ver_idx]
5052

53+
@cached(lambda args: (args[1], args[2]))
5154
def find_best_nixpkgs_candidate(self, name, ver):
5255
"""
5356
In case a python package has more than one candidate in nixpkgs

mach_nix/data/providers.py

+22-19
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import distlib.markers
1010
from packaging.version import Version, parse
11+
from pkg_resources import RequirementParseError
1112

1213
from .nixpkgs import NixpkgsIndex
1314
from mach_nix.requirements import filter_reqs_by_eval_marker, Requirement, parse_reqs, context
@@ -65,7 +66,7 @@ def __init__(self, pkg_name, pkg_ver, provider_name, *args, **kwargs):
6566

6667
class DependencyProviderBase(ABC):
6768
def __init__(self, py_ver: PyVer, platform, system, *args, **kwargs):
68-
self.context = context(py_ver)
69+
self.context = context(py_ver, platform, system)
6970
self.context_wheel = self.context.copy()
7071
self.context_wheel['extra'] = None
7172
self.py_ver_digits = py_ver.digits()
@@ -202,11 +203,6 @@ def _available_versions(self, pkg_name: str) -> Iterable[Version]:
202203

203204
class NixpkgsDependencyProvider(DependencyProviderBase):
204205
name = 'nixpkgs'
205-
# mapping from pypi name to nix key
206-
# _aliases = dict(
207-
# torch='pytorch',
208-
# tensorboard='tensorflow-tensorboard'
209-
# )
210206

211207
# TODO: implement extras by looking them up via the equivalent wheel
212208
def __init__(
@@ -261,22 +257,24 @@ class WheelDependencyProvider(DependencyProviderBase):
261257
def __init__(self, data_dir: str, *args, **kwargs):
262258
super(WheelDependencyProvider, self).__init__(*args, **kwargs)
263259
self.data = LazyBucketDict(data_dir)
264-
m = self.py_ver_digits[-1]
260+
maj = self.py_ver_digits[0] # major version
261+
min = self.py_ver_digits[1] # minor version
265262
if self.system == "linux":
263+
cp_abi = f"cp{maj}{min}mu" if int(maj) == 2 else f"cp{maj}{min}m"
266264
self.preferred_wheels = (
267-
re.compile(rf"(py3|cp3){m}?-(cp3{m}m|abi3|none)-manylinux2014_{self.platform}"),
268-
re.compile(rf"(py3|cp3){m}?-(cp3{m}m|abi3|none)-manylinux2010_{self.platform}"),
269-
re.compile(rf"(py3|cp3){m}?-(cp3{m}m|abi3|none)-manylinux1_{self.platform}"),
270-
re.compile(rf"(py3|cp3){m}?-(cp3{m}m|abi3|none)-linux_{self.platform}"),
271-
re.compile(rf"(py3|cp3){m}?-(cp3{m}m|abi3|none)-any"),
265+
re.compile(rf"(py{maj}|cp{maj}){min}?-({cp_abi}|abi3|none)-manylinux2014_{self.platform}"),
266+
re.compile(rf"(py{maj}|cp{maj}){min}?-({cp_abi}|abi3|none)-manylinux2010_{self.platform}"),
267+
re.compile(rf"(py{maj}|cp{maj}){min}?-({cp_abi}|abi3|none)-manylinux1_{self.platform}"),
268+
re.compile(rf"(py{maj}|cp{maj}){min}?-({cp_abi}|abi3|none)-linux_{self.platform}"),
269+
re.compile(rf"(py{maj}|cp{maj}){min}?-({cp_abi}|abi3|none)-any"),
272270
)
273271
elif self.system == "darwin":
274272
self.preferred_wheels = (
275-
re.compile(rf"(py3|cp3){m}?-(cp3{m}|abi3|none)-macosx_\d*_\d*_universal"),
276-
re.compile(rf"(py3|cp3){m}?-(cp3{m}|abi3|none)-macosx_\d*_\d*_x86_64"),
277-
re.compile(rf"(py3|cp3){m}?-(cp3{m}|abi3|none)-macosx_\d*_\d*_intel"),
278-
re.compile(rf"(py3|cp3){m}?-(cp3{m}|abi3|none)-macosx_\d*_\d*_(fat64|fat32)"),
279-
re.compile(rf"(py3|cp3){m}?-(cp3{m}|abi3|none)-any"),)
273+
re.compile(rf"(py{maj}|cp{maj}){min}?-(cp{maj}{min}|abi3|none)-macosx_\d*_\d*_universal"),
274+
re.compile(rf"(py{maj}|cp{maj}){min}?-(cp{maj}{min}|abi3|none)-macosx_\d*_\d*_x86_64"),
275+
re.compile(rf"(py{maj}|cp{maj}){min}?-(cp{maj}{min}|abi3|none)-macosx_\d*_\d*_intel"),
276+
re.compile(rf"(py{maj}|cp{maj}){min}?-(cp{maj}{min}|abi3|none)-macosx_\d*_\d*_(fat64|fat32)"),
277+
re.compile(rf"(py{maj}|cp{maj}){min}?-(cp{maj}{min}|abi3|none)-any"),)
280278
else:
281279
raise Exception(f"Unsupported Platform {platform.system()}")
282280

@@ -317,7 +315,7 @@ def _all_releases(self, pkg_name):
317315
fn,
318316
deps['requires_dist'] if 'requires_dist' in deps else None,
319317
deps['requires_extras'] if 'requires_extras' in deps else None,
320-
deps['requires_python'] if 'requires_python' in deps else None,
318+
deps['requires_python'].strip(',') if 'requires_python' in deps else None,
321319
)
322320

323321
def _apply_filters(self, filters: List[callable], objects: Iterable):
@@ -362,7 +360,12 @@ def _python_requires_ok(self, wheel: WheelRelease):
362360
if not wheel.requires_python:
363361
return True
364362
ver = parse('.'.join(self.py_ver_digits))
365-
return bool(filter_versions([ver], list(parse_reqs(f"python{wheel.requires_python}"))[0].specs))
363+
try:
364+
parsed_py_requires = list(parse_reqs(f"python{wheel.requires_python}"))
365+
return bool(filter_versions([ver], parsed_py_requires[0].specs))
366+
except RequirementParseError:
367+
print(f"WARNING: `requires_python` attribute of wheel {wheel.name}:{wheel.ver} could not be parsed")
368+
return False
366369

367370

368371
class SdistDependencyProvider(DependencyProviderBase):

mach_nix/generate.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def main():
4848
disable_checks,
4949
ResolvelibResolver(nixpkgs, deps_provider),
5050
)
51-
reqs = filter_reqs_by_eval_marker(parse_reqs(requirements), context(py_ver))
51+
reqs = filter_reqs_by_eval_marker(parse_reqs(requirements), context(py_ver, platform, system))
5252
expr = generator.generate(reqs)
5353
with open(out_file, 'w') as f:
5454
f.write(expr)

mach_nix/generators/overides_generator.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,13 @@ def _gen_prop_build_inputs(self, prop_build_inputs_local, prop_build_inputs_nixp
6868
f"{b}" for b in sorted(prop_build_inputs_local | prop_build_inputs_nixpkgs))
6969
return prop_build_inputs_str
7070

71-
def _gen_overrideAttrs(self, name, ver, nix_name, build_inputs_str, prop_build_inputs_str):
71+
def _gen_overrideAttrs(self, name, ver, nix_name, build_inputs_str, prop_build_inputs_str, keep_src=False):
7272
out = f"""
7373
{nix_name} = python-super.{nix_name}.overridePythonAttrs ( oldAttrs: {{
7474
pname = "{name}";
75-
version = "{ver}";
75+
version = "{ver}";"""
76+
if not keep_src:
77+
out += f"""
7678
src = fetchPypi "{name}" "{ver}";"""
7779
if build_inputs_str:
7880
out += f"""
@@ -183,7 +185,9 @@ def _gen_overrides(self, pkgs: Dict[str, ResolvedPkg], overlay_keys, pkgs_names:
183185
out += self._unify_nixpkgs_keys(pkg.name)
184186
elif pkg.provider_info.provider == NixpkgsDependencyProvider.name:
185187
nix_name = self.nixpkgs.find_best_nixpkgs_candidate(pkg.name, pkg.ver)
186-
out += self._gen_overrideAttrs(pkg.name, pkg.ver, nix_name, build_inputs_str, prop_build_inputs_str)
188+
out += self._gen_overrideAttrs(
189+
pkg.name, pkg.ver, nix_name, build_inputs_str, prop_build_inputs_str,
190+
keep_src=True)
187191
out += self._unify_nixpkgs_keys(pkg.name, main_key=nix_name)
188192
end_overlay_section = f"""
189193
}};

mach_nix/nix/NIXPKGS_COMMIT

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
f8248ab6d9e69ea9c07950d73d48807ec595e923
1+
1365b9ac700aabe8dc959e9897bc1376e416c553

mach_nix/nix/NIXPKGS_SHA256

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
009i9j6mbq6i481088jllblgdnci105b2q4mscprdawg3knlyahk
1+
180bq107z7qc2h4dxs3fxmrag3l8p9lvgjf3530qknp2h3ji8vqh

mach_nix/nix/PYPI_DEPS_DB_COMMIT

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2a2501aab1fe4eb50763652c4f74c5327f976f85
1+
521ca251792514f1a8170dd89b11edd158d7bfbe

mach_nix/nix/PYPI_DEPS_DB_SHA256

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
03c64w1x4q2li57cn6zsb2shjk2fc4f5ksmsz3695dmvckp0lj14
1+
01hi8r7pzvpimw282zsnk1giysznarx8a067dnh8m9h7wz506lgc

0 commit comments

Comments
 (0)