1# Tests for the Python interpreters, package sets and environments. 2# 3# Each Python interpreter has a `passthru.tests` which is the attribute set 4# returned by this function. For example, for Python 3 the tests are run with 5# 6# $ nix-build -A python3.tests 7# 8{ stdenv 9, python 10, runCommand 11, lib 12, callPackage 13, pkgs 14}: 15 16let 17 # Test whether the interpreter behaves in the different types of environments 18 # we aim to support. 19 environmentTests = let 20 envs = let 21 inherit python; 22 pythonEnv = python.withPackages(ps: with ps; [ ]); 23 pythonVirtualEnv = if python.isPy3k 24 then 25 python.withPackages(ps: with ps; [ virtualenv ]) 26 else 27 python.buildEnv.override { 28 extraLibs = with python.pkgs; [ virtualenv ]; 29 # Collisions because of namespaces __init__.py 30 ignoreCollisions = true; 31 }; 32 in { 33 # Plain Python interpreter 34 plain = rec { 35 env = python; 36 interpreter = env.interpreter; 37 is_venv = "False"; 38 is_nixenv = "False"; 39 is_virtualenv = "False"; 40 }; 41 } // lib.optionalAttrs (!python.isPyPy) { 42 # Use virtualenv from a Nix env. 43 nixenv-virtualenv = rec { 44 env = runCommand "${python.name}-virtualenv" {} '' 45 ${pythonVirtualEnv.interpreter} -m virtualenv venv 46 mv venv $out 47 ''; 48 interpreter = "${env}/bin/${python.executable}"; 49 is_venv = "False"; 50 is_nixenv = "True"; 51 is_virtualenv = "True"; 52 }; 53 } // lib.optionalAttrs (python.implementation != "graal") { 54 # Python Nix environment (python.buildEnv) 55 nixenv = rec { 56 env = pythonEnv; 57 interpreter = env.interpreter; 58 is_venv = "False"; 59 is_nixenv = "True"; 60 is_virtualenv = "False"; 61 }; 62 } // lib.optionalAttrs (python.isPy3k && (!python.isPyPy)) { 63 # Venv built using plain Python 64 # Python 2 does not support venv 65 # TODO: PyPy executable name is incorrect, it should be pypy-c or pypy-3c instead of pypy and pypy3. 66 plain-venv = rec { 67 env = runCommand "${python.name}-venv" {} '' 68 ${python.interpreter} -m venv $out 69 ''; 70 interpreter = "${env}/bin/${python.executable}"; 71 is_venv = "True"; 72 is_nixenv = "False"; 73 is_virtualenv = "False"; 74 }; 75 76 } // lib.optionalAttrs (python.pythonAtLeast "3.8") { 77 # Venv built using Python Nix environment (python.buildEnv) 78 # TODO: Cannot create venv from a nix env 79 # Error: Command '['/nix/store/ddc8nqx73pda86ibvhzdmvdsqmwnbjf7-python3-3.7.6-venv/bin/python3.7', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 1. 80 nixenv-venv = rec { 81 env = runCommand "${python.name}-venv" {} '' 82 ${pythonEnv.interpreter} -m venv $out 83 ''; 84 interpreter = "${env}/bin/${pythonEnv.executable}"; 85 is_venv = "True"; 86 is_nixenv = "True"; 87 is_virtualenv = "False"; 88 }; 89 }; 90 91 testfun = name: attrs: runCommand "${python.name}-tests-${name}" ({ 92 inherit (python) pythonVersion; 93 } // attrs) '' 94 cp -r ${./tests/test_environments} tests 95 chmod -R +w tests 96 substituteAllInPlace tests/test_python.py 97 ${attrs.interpreter} -m unittest discover --verbose tests #/test_python.py 98 mkdir $out 99 touch $out/success 100 ''; 101 102 in lib.mapAttrs testfun envs; 103 104 # Integration tests involving the package set. 105 # All PyPy package builds are broken at the moment 106 integrationTests = lib.optionalAttrs (!python.isPyPy) ( 107 lib.optionalAttrs (python.isPy3k && !stdenv.isDarwin) { # darwin has no split-debug 108 cpython-gdb = callPackage ./tests/test_cpython_gdb { 109 interpreter = python; 110 }; 111 } // lib.optionalAttrs (python.pythonAtLeast "3.7") { 112 # Before the addition of NIX_PYTHONPREFIX mypy was broken with typed packages 113 nix-pythonprefix-mypy = callPackage ./tests/test_nix_pythonprefix { 114 interpreter = python; 115 }; 116 # Make sure tkinter is importable. See https://github.com/NixOS/nixpkgs/issues/238990 117 tkinter = callPackage ./tests/test_tkinter { 118 interpreter = python; 119 }; 120 } 121 ); 122 123 # Tests to ensure overriding works as expected. 124 overrideTests = let 125 extension = self: super: { 126 foobar = super.numpy; 127 }; 128 in lib.optionalAttrs (python.isPy3k) ({ 129 test-packageOverrides = let 130 myPython = let 131 self = python.override { 132 packageOverrides = extension; 133 inherit self; 134 }; 135 in self; 136 in assert myPython.pkgs.foobar == myPython.pkgs.numpy; myPython.withPackages(ps: with ps; [ foobar ]); 137 # overrideScope is broken currently 138 # test-overrideScope = let 139 # myPackages = python.pkgs.overrideScope extension; 140 # in assert myPackages.foobar == myPackages.numpy; myPackages.python.withPackages(ps: with ps; [ foobar ]); 141 } // lib.optionalAttrs (python ? pythonAttr) { 142 # Test applying overrides using pythonPackagesOverlays. 143 test-pythonPackagesExtensions = let 144 pkgs_ = pkgs.extend(final: prev: { 145 pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [ 146 (python-final: python-prev: { 147 foo = python-prev.setuptools; 148 }) 149 ]; 150 }); 151 in pkgs_.${python.pythonAttr}.pkgs.foo; 152 }); 153 154 condaTests = let 155 requests = callPackage ({ 156 autoPatchelfHook, 157 fetchurl, 158 pythonCondaPackages, 159 }: 160 python.pkgs.buildPythonPackage { 161 pname = "requests"; 162 version = "2.24.0"; 163 format = "other"; 164 src = fetchurl { 165 url = "https://repo.anaconda.com/pkgs/main/noarch/requests-2.24.0-py_0.tar.bz2"; 166 sha256 = "02qzaf6gwsqbcs69pix1fnjxzgnngwzvrsy65h1d521g750mjvvp"; 167 }; 168 nativeBuildInputs = [ autoPatchelfHook ] ++ (with python.pkgs; [ 169 condaUnpackHook condaInstallHook 170 ]); 171 buildInputs = [ 172 pythonCondaPackages.condaPatchelfLibs 173 ]; 174 propagatedBuildInputs = with python.pkgs; [ 175 chardet idna urllib3 certifi 176 ]; 177 } 178 ) {}; 179 pythonWithRequests = requests.pythonModule.withPackages (ps: [ requests ]); 180 in lib.optionalAttrs (python.isPy3k && stdenv.isLinux) 181 { 182 condaExamplePackage = runCommand "import-requests" {} '' 183 ${pythonWithRequests.interpreter} -c "import requests" > $out 184 ''; 185 }; 186 187in lib.optionalAttrs (stdenv.hostPlatform == stdenv.buildPlatform ) (environmentTests // integrationTests // overrideTests // condaTests)