diff --git a/pkgs/development/interpreters/python/sitecustomize.py b/pkgs/development/interpreters/python/sitecustomize.py index 72ce951328f1..d79a4696d8ea 100644 --- a/pkgs/development/interpreters/python/sitecustomize.py +++ b/pkgs/development/interpreters/python/sitecustomize.py @@ -21,9 +21,11 @@ paths = os.environ.pop('NIX_PYTHONPATH', None) if paths: functools.reduce(lambda k, p: site.addsitedir(p, k), paths.split(':'), site._init_pathinfo()) -# Check whether we are in a venv. -# Note Python 2 does not support base_prefix so we assume we are not in a venv. -in_venv = sys.version_info.major == 3 and sys.prefix != sys.base_prefix +# Check whether we are in a venv or virtualenv. +# For Python 3 we check whether our `base_prefix` is different from our current `prefix`. +# For Python 2 we check whether the non-standard `real_prefix` is set. +# https://stackoverflow.com/questions/1871549/determine-if-python-is-running-inside-virtualenv +in_venv = (sys.version_info.major == 3 and sys.prefix != sys.base_prefix) or (sys.version_info.major == 2 and hasattr(sys, "real_prefix")) if not in_venv: executable = os.environ.pop('NIX_PYTHONEXECUTABLE', None) @@ -32,8 +34,6 @@ if not in_venv: if 'PYTHONEXECUTABLE' not in os.environ and executable is not None: sys.executable = executable if prefix is not None: - # Because we cannot check with Python 2 whether we are in a venv, - # creating a venv from a Nix env won't work as well with Python 2. - # Also, note that sysconfig does not like it when sys.prefix is set to None + # Sysconfig does not like it when sys.prefix is set to None sys.prefix = sys.exec_prefix = prefix site.PREFIXES.insert(0, prefix) diff --git a/pkgs/development/interpreters/python/tests.nix b/pkgs/development/interpreters/python/tests.nix index 35da373e79c5..03a3b9537090 100644 --- a/pkgs/development/interpreters/python/tests.nix +++ b/pkgs/development/interpreters/python/tests.nix @@ -19,10 +19,8 @@ let is_nixenv = "False"; is_virtualenv = "False"; }; - } // lib.optionalAttrs (python.isPy3k && !python.isPyPy) { + } // lib.optionalAttrs (!python.isPyPy) { # Use virtualenv from a Nix env. - # Does not function with Python 2 - # ValueError: source and destination is the same /nix/store/38kz3j1a87cq5y59k5w7k9yk4cqgc5b2-python-2.7.18/lib/python2.7/os.py nixenv-virtualenv = rec { env = runCommand "${python.name}-virtualenv" {} '' ${pythonVirtualEnv.interpreter} -m virtualenv $out diff --git a/pkgs/development/interpreters/python/tests/test_python.py b/pkgs/development/interpreters/python/tests/test_python.py index 41a7e687d263..0fc4b8a9e91c 100644 --- a/pkgs/development/interpreters/python/tests/test_python.py +++ b/pkgs/development/interpreters/python/tests/test_python.py @@ -43,6 +43,10 @@ class TestCasePython(unittest.TestCase): else: self.assertEqual(sys.prefix, sys.base_prefix) + @unittest.skipIf(sys.version_info.major==3, "sys.real_prefix is only set by virtualenv in case of Python 2.") + def test_real_prefix(self): + self.assertTrue(hasattr(sys, "real_prefix") == IS_VIRTUALENV) + def test_python_version(self): self.assertTrue(platform.python_version().startswith(PYTHON_VERSION)) diff --git a/pkgs/development/python-modules/virtualenv/0001-Check-base_prefix-and-base_exec_prefix-for-Python-2.patch b/pkgs/development/python-modules/virtualenv/0001-Check-base_prefix-and-base_exec_prefix-for-Python-2.patch new file mode 100644 index 000000000000..2b34da289e2d --- /dev/null +++ b/pkgs/development/python-modules/virtualenv/0001-Check-base_prefix-and-base_exec_prefix-for-Python-2.patch @@ -0,0 +1,37 @@ +From 21563405d6e2348ee457187f7fb61beb102bb367 Mon Sep 17 00:00:00 2001 +From: Frederik Rietdijk +Date: Sun, 24 May 2020 09:33:13 +0200 +Subject: [PATCH] Check base_prefix and base_exec_prefix for Python 2 + +This is a Nixpkgs-specific change so it can support virtualenvs from Nix envs. +--- + src/virtualenv/discovery/py_info.py | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/src/virtualenv/discovery/py_info.py b/src/virtualenv/discovery/py_info.py +index 6f12128..74e9218 100644 +--- a/src/virtualenv/discovery/py_info.py ++++ b/src/virtualenv/discovery/py_info.py +@@ -51,13 +51,17 @@ class PythonInfo(object): + self.version = u(sys.version) + self.os = u(os.name) + ++ config_vars = {} if sys.version_info.major is not 2 else sysconfig._CONFIG_VARS ++ base_prefix = config_vars.get("prefix") ++ base_exec_prefix = config_vars.get("exec_prefix") ++ + # information about the prefix - determines python home + self.prefix = u(abs_path(getattr(sys, "prefix", None))) # prefix we think +- self.base_prefix = u(abs_path(getattr(sys, "base_prefix", None))) # venv ++ self.base_prefix = u(abs_path(getattr(sys, "base_prefix", base_prefix))) # venv + self.real_prefix = u(abs_path(getattr(sys, "real_prefix", None))) # old virtualenv + + # information about the exec prefix - dynamic stdlib modules +- self.base_exec_prefix = u(abs_path(getattr(sys, "base_exec_prefix", None))) ++ self.base_exec_prefix = u(abs_path(getattr(sys, "base_exec_prefix", base_exec_prefix))) + self.exec_prefix = u(abs_path(getattr(sys, "exec_prefix", None))) + + self.executable = u(abs_path(sys.executable)) # the executable we were invoked via +-- +2.25.1 + diff --git a/pkgs/development/python-modules/virtualenv/default.nix b/pkgs/development/python-modules/virtualenv/default.nix index ff5172d415f7..5ca27330103d 100644 --- a/pkgs/development/python-modules/virtualenv/default.nix +++ b/pkgs/development/python-modules/virtualenv/default.nix @@ -43,6 +43,10 @@ buildPythonPackage rec { importlib-metadata ]; + patches = lib.optionals (isPy27) [ + ./0001-Check-base_prefix-and-base_exec_prefix-for-Python-2.patch + ]; + meta = { description = "A tool to create isolated Python environments"; homepage = "http://www.virtualenv.org";