Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python: indicate whether a derivation provides a Python module #30606

Closed
wants to merge 8 commits into from

Conversation

FRidh
Copy link
Member

@FRidh FRidh commented Oct 20, 2017

Motivation for this change

The python-packages.nix file contains derivations that provide Python modules. Sometimes, one needs to determine whether packages provide Python modules. Currently, a hook is used for this, but the hook does not check whether the site-packages correspond to the right Python derivation.

Derivations providing Python modules should be marked with isPythonModule = python; where python is the interpreter that was used to build the module.

Most of the derivations in python-packages.nix are produced with buildPythonPackage but not all of them. Therefore, a helper function toPythonModule is provided that sets this attribute, and corrects the name as well.

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option build-use-sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Fits CONTRIBUTING.md.

@FRidh FRidh changed the title Python: pythonModule Python: indicate whether a derivation provides a Python module Oct 20, 2017
hasPythonModule = drv: (hasAttr "pythonModule" drv) && ( (getAttr "pythonModule" drv) == python);

# Recurse into a list of Python modules, returning all Python modules that are required.
requiredModules = drvs: filter hasPythonModule (closePropagation drvs);
Copy link
Member

@veprbl veprbl Oct 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe name it requiredPythonModules or even recursiveFilterPythonModules. The meaning of requiredModules is hard to understand if you don't think in the context of Python modules.

@veprbl
Copy link
Member

veprbl commented Oct 20, 2017

When I first tried python package using mkDerivation I was really surprised that

stdenv.mkDerivation {
  #...
  buildInputs = with pythonPackages; [ foo ];
}

is not automatically transformed into

stdenv.mkDerivation rec {
  #...
  buildInputs = with pythonPackages; [ foo ];
  pythonPath = requiredModules buildInputs;
}

Or perhaps even do this in bash. Say, we could call buildPythonPath() on $buildInputs instead of $pythonPath. I guess there must be a good reason to not do that. Is it because it can be too slow?

@FRidh
Copy link
Member Author

FRidh commented Oct 20, 2017

@veprbl certain inputs are only needed at build or test time. Also, non-python dependencies should not be added to PYTHONPATH.

Certain things can be done in sh but I'm actually trying to get rid of that because its brittle and because you cannot guarantee that your module belongs to the interpreter for which you seek the modules.

@FRidh FRidh force-pushed the pythonmodule branch 2 times, most recently from e2b3956 to e2fc437 Compare October 20, 2017 18:51
@veprbl
Copy link
Member

veprbl commented Oct 20, 2017

@FRidh Things that are only needed at build and test time go to nativeBuildInputs and checkInputs. My point was that it would be nice if things would work automagically with what is put in buildInputs like it already does for many different places in nixpkgs. As far as I understand, it usually is implemented via shell hooks, which is why I brought up shell. It can be also implemented fully in nix, like you did here, except that nix doesn't have information whether a dependence will produce "${drv}/lib/pythonXX/" path or not, so you need to introduce toPythonModule to explicitly mark each and every derivation manually (which is not necessarily a bad thing).

Also, yoda and rivet could use toPythonModule too.

@teto
Copy link
Member

teto commented Oct 21, 2017

I had to clean up some space and disable some packages that were too long to recompile but finally ended up ok. It fixed the problem for me (1st version of the PR, you 've pushed a new version since then but I can't recompile on every push sry xD).
Also, non-python dependencies should not be added to PYTHONPATH.
couldn't buildInputs identify python packages via checking for isPython in the atttSet ?
Not sure what to do but ditching (i.e., automate the generation) pythonPath for buildInputs would make packaging easier.

@FRidh
Copy link
Member Author

FRidh commented Oct 21, 2017

It fixed the problem for me

Good to hear.

couldn't buildInputs identify python packages via checking for isPython in the atttSet ?

Yes and no. Currently the Python interpreter comes with a setup hook which adds the site-packages folders to PYTHONPATH. The issue is that it does not distinguish between interpreter versions.

I would prefer to do most of this in Nix instead of through a setup hook. In case of our buildPythonPackage function and python.buildEnv we can do that easily. But in case of stdenv.mkDerivation we cannot.

Python libraries or modules now have an attribute `pythonModule = interpreter;` to indicate
they provide Python modules for the specified `interpreter`.

The package set provides the following helper functions:

- hasPythonModule: Check whether a derivation provides a Python module.
- requiredPythonModules: Recurse into a list of Python modules, returning all Python modules that are required.
- makePythonPath: Create a PYTHONPATH from a list of Python modules.

Also included in this commit is:
- disabledIf: Helper function for disabling non-buildPythonPackage functions.
pythonPath is used to create the eventual wrappers. It does not recurse
into the Python dependencies, which means e.g. requests doesn't haven
its dependencies.
@FRidh
Copy link
Member Author

FRidh commented Nov 25, 2017

I've pushed this to staging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants