-
-
Notifications
You must be signed in to change notification settings - Fork 18.3k
Python: split buildPythonPackage into two functions #18143
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
Changes from all commits
b080748
725c37b
3e05cce
e9c4d00
4f6b6f1
9a85190
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| /* Generic builder for Python packages that come without a setup.py. */ | ||
|
|
||
| { lib | ||
| , python | ||
| , wrapPython | ||
| , setuptools | ||
| , unzip | ||
| , ensureNewerSourcesHook | ||
| }: | ||
|
|
||
| { name | ||
|
|
||
| # by default prefix `name` e.g. "python3.3-${name}" | ||
| , namePrefix ? python.libPrefix + "-" | ||
|
|
||
| # Dependencies for building the package | ||
| , buildInputs ? [] | ||
|
|
||
| # Dependencies needed for running the checkPhase. | ||
| # These are added to buildInputs when doCheck = true. | ||
| , checkInputs ? [] | ||
|
|
||
| # propagate build dependencies so in case we have A -> B -> C, | ||
| # C can import package A propagated by B | ||
| , propagatedBuildInputs ? [] | ||
|
|
||
| # DEPRECATED: use propagatedBuildInputs | ||
| , pythonPath ? [] | ||
|
|
||
| # used to disable derivation, useful for specific python versions | ||
| , disabled ? false | ||
|
|
||
| # Raise an error if two packages are installed with the same name | ||
| , catchConflicts ? true | ||
|
|
||
| # Additional arguments to pass to the makeWrapper function, which wraps | ||
| # generated binaries. | ||
| , makeWrapperArgs ? [] | ||
|
|
||
| , meta ? {} | ||
|
|
||
| , passthru ? {} | ||
|
|
||
| , ... } @ attrs: | ||
|
|
||
|
|
||
| # Keep extra attributes from `attrs`, e.g., `patchPhase', etc. | ||
| if disabled | ||
| then throw "${name} not supported for interpreter ${python.executable}" | ||
| else | ||
|
|
||
| python.stdenv.mkDerivation (builtins.removeAttrs attrs ["disabled"] // { | ||
|
|
||
| name = namePrefix + name; | ||
|
|
||
| inherit pythonPath; | ||
|
|
||
| buildInputs = [ wrapPython ] ++ buildInputs ++ pythonPath | ||
| ++ [ (ensureNewerSourcesHook { year = "1980"; }) ] | ||
| ++ (lib.optional (lib.hasSuffix "zip" attrs.src.name or "") unzip) | ||
| ++ lib.optionals attrs.doCheck checkInputs; | ||
|
|
||
| # propagate python/setuptools to active setup-hook in nix-shell | ||
| propagatedBuildInputs = propagatedBuildInputs ++ [ python setuptools ]; | ||
|
|
||
| # Python packages don't have a checkPhase, only an installCheckPhase | ||
| doCheck = false; | ||
| doInstallCheck = attrs.doCheck or false; | ||
|
|
||
| postFixup = attrs.postFixup or '' | ||
| wrapPythonPrograms | ||
| '' + lib.optionalString catchConflicts '' | ||
| # check if we have two packages with the same name in closure and fail | ||
| # this shouldn't happen, something went wrong with dependencies specs | ||
| ${python.interpreter} ${./catch_conflicts.py} | ||
| ''; | ||
|
|
||
| passthru = { | ||
| inherit python; # The python interpreter | ||
| } // passthru; | ||
|
|
||
| meta = with lib.maintainers; { | ||
| # default to python's platforms | ||
| platforms = python.meta.platforms; | ||
| } // meta // { | ||
| # add extra maintainer(s) to every package | ||
| maintainers = (meta.maintainers or []) ++ [ chaoflow domenkozar ]; | ||
| # a marker for release utilities to discover python packages | ||
| isBuildPythonPackage = python.meta.platforms; | ||
| }; | ||
| }) | ||
|
|
||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| { lib | ||
| , python | ||
| , makeSetupHook | ||
| , makeWrapper }: | ||
|
|
||
| with lib; | ||
|
|
||
| makeSetupHook { | ||
| deps = makeWrapper; | ||
|
||
| substitutions.libPrefix = python.libPrefix; | ||
| substitutions.executable = python.interpreter; | ||
| substitutions.python = python; | ||
| substitutions.magicalSedExpression = let | ||
|
||
| # Looks weird? Of course, it's between single quoted shell strings. | ||
| # NOTE: Order DOES matter here, so single character quotes need to be | ||
| # at the last position. | ||
| quoteVariants = [ "'\"'''\"'" "\"\"\"" "\"" "'\"'\"'" ]; # hey Vim: '' | ||
|
|
||
| mkStringSkipper = labelNum: quote: let | ||
| label = "q${toString labelNum}"; | ||
| isSingle = elem quote [ "\"" "'\"'\"'" ]; | ||
| endQuote = if isSingle then "[^\\\\]${quote}" else quote; | ||
| in '' | ||
| /^[a-z]?${quote}/ { | ||
| /${quote}${quote}|${quote}.*${endQuote}/{n;br} | ||
| :${label}; n; /^${quote}/{n;br}; /${endQuote}/{n;br}; b${label} | ||
| } | ||
| ''; | ||
|
|
||
| # This preamble does two things: | ||
| # * Sets argv[0] to the original application's name; otherwise it would be .foo-wrapped. | ||
| # Python doesn't support `exec -a`. | ||
| # * Adds all required libraries to sys.path via `site.addsitedir`. It also handles *.pth files. | ||
| preamble = '' | ||
| import sys | ||
| import site | ||
| import functools | ||
| sys.argv[0] = '"'$(basename "$f")'"' | ||
|
||
| functools.reduce(lambda k, p: site.addsitedir(p, k), ['"$([ -n "$program_PYTHONPATH" ] && (echo "'$program_PYTHONPATH'" | sed "s|:|','|g") || true)"'], site._init_pathinfo()) | ||
| ''; | ||
|
|
||
| in '' | ||
| 1 { | ||
| :r | ||
| /\\$|,$/{N;br} | ||
| /__future__|^ |^ *(#.*)?$/{n;br} | ||
| ${concatImapStrings mkStringSkipper quoteVariants} | ||
| /^[^# ]/i ${replaceStrings ["\n"] [";"] preamble} | ||
| } | ||
| ''; | ||
| } ./wrap.sh | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this conceptually, but is there really anything wrong with just deeming these to be
buildInputs?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really. As you can read, they are put together anyway. It might save some building when you disable tests. Furthermore, I'm still playing with the idea of separating the building and installing/testing in two separate derivations.