diff --git a/doc/languages-frameworks/python.md b/doc/languages-frameworks/python.md index 434a9b156e78..89659c2166b1 100644 --- a/doc/languages-frameworks/python.md +++ b/doc/languages-frameworks/python.md @@ -503,9 +503,12 @@ and can be used as: The `buildPythonPackage` mainly does four things: -* In the `buildPhase`, it calls `${python.interpreter} setup.py bdist_wheel` to build a wheel binary zipfile. +* In the `buildPhase`, it calls `${python.interpreter} setup.py bdist_wheel` to + build a wheel binary zipfile. * In the `installPhase`, it installs the wheel file using `pip install *.whl`. -* In the `postFixup` phase, the `wrapPythonPrograms` bash function is called to wrap all programs in the `$out/bin/*` directory to include `$PYTHONPATH` and `$PATH` environment variables. +* In the `postFixup` phase, the `wrapPythonPrograms` bash function is called to + wrap all programs in the `$out/bin/*` directory to include `$PATH` + environment variable and add dependent libraries to script's `sys.path`. * In the `installCheck` phase, `${python.interpreter} setup.py test` is ran. As in Perl, dependencies on other Python packages can be specified in the diff --git a/pkgs/development/python-modules/generic/wrap.sh b/pkgs/development/python-modules/generic/wrap.sh index efbb1e737876..d0c49c36c4b5 100644 --- a/pkgs/development/python-modules/generic/wrap.sh +++ b/pkgs/development/python-modules/generic/wrap.sh @@ -42,12 +42,12 @@ wrapPythonProgramsIn() { # The magicalSedExpression will invoke a "$(basename "$f")", so # if you change $f to something else, be sure to also change it # in pkgs/top-level/python-packages.nix! + # It also uses $program_PYTHONPATH. sed -i "$f" -re '@magicalSedExpression@' # wrapProgram creates the executable shell script described # above. The script will set PYTHONPATH and PATH variables.! # (see pkgs/build-support/setup-hooks/make-wrapper.sh) local -a wrap_args=("$f" - --prefix PYTHONPATH ':' "$program_PYTHONPATH" --prefix PATH ':' "$program_PATH:$dir/bin") # Add any additional arguments provided by makeWrapperArgs diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index d39c8d85cdd2..8f0b85af8c57 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -59,13 +59,25 @@ in modules // { } ''; + # 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 { /^#!/!b; :r /\\$/{N;br} /__future__|^ *(#.*)?$/{n;br} ${concatImapStrings mkStringSkipper quoteVariants} - /^ *[^# ]/i import sys; sys.argv[0] = '"'$(basename "$f")'"' + /^ *[^# ]/i ${replaceStrings ["\n"] [";"] preamble} } ''; }