diff --git a/pkgs/development/interpreters/python/default.nix b/pkgs/development/interpreters/python/default.nix index 3cc0eecb1b08..94f04b73f498 100644 --- a/pkgs/development/interpreters/python/default.nix +++ b/pkgs/development/interpreters/python/default.nix @@ -44,6 +44,10 @@ with pkgs; pythonAtLeast = lib.versionAtLeast pythonVersion; pythonOlder = lib.versionOlder pythonVersion; inherit hasDistutilsCxxPatch pythonForBuild; + + tests = callPackage ./tests.nix { + python = self; + }; }; in { diff --git a/pkgs/development/interpreters/python/tests.nix b/pkgs/development/interpreters/python/tests.nix new file mode 100644 index 000000000000..37fbe6701148 --- /dev/null +++ b/pkgs/development/interpreters/python/tests.nix @@ -0,0 +1,63 @@ +{ python +, runCommand +, substituteAll +, lib +}: + +let + envs = let + inherit python; + pythonEnv = python.withPackages(ps: with ps; [ ]); + in { + # Plain Python interpreter + plain = rec { + env = python; + interpreter = env.interpreter; + is_venv = "False"; + is_nixenv = "False"; + }; + } // lib.optionalAttrs (python.implementation != "graal") { + # Python Nix environment (python.buildEnv) + nixenv = rec { + env = pythonEnv; + interpreter = env.interpreter; + is_venv = "False"; + is_nixenv = "True"; + }; + } // lib.optionalAttrs (python.isPy3k && (!python.isPyPy)) rec { + # Venv built using plain Python + # Python 2 does not support venv + # TODO: PyPy executable name is incorrect, it should be pypy-c or pypy-3c instead of pypy and pypy3. + plain-venv = rec { + env = runCommand "${python.name}-venv" {} '' + ${python.interpreter} -m venv $out + ''; + interpreter = "${env}/bin/${python.executable}"; + is_venv = "True"; + is_nixenv = "False"; + }; + # Venv built using Python Nix environment (python.buildEnv) + # TODO: Cannot create venv from a nix env + # Error: Command '['/nix/store/ddc8nqx73pda86ibvhzdmvdsqmwnbjf7-python3-3.7.6-venv/bin/python3.7', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 1. + # nixenv-venv = rec { + # env = runCommand "${python.name}-venv" {} '' + # ${pythonEnv.interpreter} -m venv $out + # ''; + # interpreter = "${env}/bin/${pythonEnv.executable}"; + # is_venv = "True"; + # is_nixenv = "True"; + # }; + }; + + testfun = name: attrs: runCommand "${python.name}-tests-${name}" ({ + inherit (python) pythonVersion; + } // attrs) '' + cp -r ${./tests} tests + chmod -R +w tests + substituteAllInPlace tests/test_python.py + ${attrs.interpreter} -m unittest discover --verbose tests #/test_python.py + mkdir $out + touch $out/success + ''; + +in lib.mapAttrs testfun envs \ No newline at end of file diff --git a/pkgs/development/interpreters/python/tests/test_python.py b/pkgs/development/interpreters/python/tests/test_python.py new file mode 100644 index 000000000000..f631a172ccc6 --- /dev/null +++ b/pkgs/development/interpreters/python/tests/test_python.py @@ -0,0 +1,50 @@ +""" +Python interpreter and environment tests. + +These need to be executed with the standard library unittest. +Third party test runners such as pytest cannot be used because +that would interfere with the tests. +""" + +import platform +import sys +import unittest +import site + + +ENV = "@env@" +INTERPRETER = "@interpreter@" +PYTHON_VERSION = "@pythonVersion@" + +IS_VENV = @is_venv@ +IS_NIXENV = @is_nixenv@ +IS_PYPY = platform.python_implementation() == "PyPy" + + +class TestCasePython(unittest.TestCase): + + @unittest.skipIf(IS_PYPY, "Executable is incorrect and needs to be fixed.") + def test_interpreter(self): + self.assertEqual(sys.executable, INTERPRETER) + + @unittest.skipIf(IS_NIXENV or IS_PYPY, "Prefix is incorrect and needs to be fixed.") + def test_prefix(self): + self.assertEqual(sys.prefix, ENV) + self.assertEqual(sys.prefix, sys.exec_prefix) + + def test_site_prefix(self): + self.assertTrue(sys.prefix in site.PREFIXES) + + @unittest.skipIf(sys.version_info.major==2, "Python 2 does not have base_prefix") + def test_base_prefix(self): + if IS_VENV: + self.assertNotEqual(sys.prefix, sys.base_prefix) + else: + self.assertEqual(sys.prefix, sys.base_prefix) + + def test_python_version(self): + self.assertTrue(platform.python_version().startswith(PYTHON_VERSION)) + + +if __name__ == "__main__": + unittest.main()