diff --git a/modules/kernels/python/kernel.nix b/modules/kernels/python/kernel.nix index 9d606260..4c443188 100644 --- a/modules/kernels/python/kernel.nix +++ b/modules/kernels/python/kernel.nix @@ -32,7 +32,8 @@ common.makeJupyterKernel ( displayName = displayName; language = kernelName; argv = [ - "${python}/bin/python" + # PyPy environments name the binary pypy3, so take the path the environment reports. + python.interpreter "-m" "ipykernel" "-f" diff --git a/modules/kernels/python/module.nix b/modules/kernels/python/module.nix index 49b241f9..d90f5c56 100644 --- a/modules/kernels/python/module.nix +++ b/modules/kernels/python/module.nix @@ -192,7 +192,27 @@ in config.pkgs.callPackage ./. { name = "PyPy"; - python3 = lib.getAttr config.kernels.pypy3.python3Package config.pkgs; + python3 = (lib.getAttr config.kernels.pypy3.python3Package config.pkgs).override { + packageOverrides = pyFinal: pyPrev: + # Test suites are the main thing standing between PyPy and a working kernel: a + # package unsupported on PyPy throws when its outPath is evaluated even as a mere + # check input, and several check inputs are C extensions that don't compile here. + (lib.mapAttrs (_name: value: + let isPythonPackage = builtins.tryEval (lib.isDerivation value && value ? overridePythonAttrs); + in if isPythonPackage.success && isPythonPackage.value + then value.overridePythonAttrs (_: { doCheck = false; }) + else value + ) pyPrev) + // { + # On PyPy, pyzmq builds and runs against cffi rather than Cython, but nixpkgs + # only wires up the Cython path. + pyzmq = pyPrev.pyzmq.overridePythonAttrs (old: { + doCheck = false; + build-system = (old.build-system or []) ++ [ pyFinal.cffi pyFinal.pycparser ]; + dependencies = (old.dependencies or []) ++ [ pyFinal.cffi pyFinal.pycparser ]; + }); + }; + }; settings = config.kernels.pypy3; settingsSchema = nixosOptionsToSettingsSchema { componentsToDrop = 2; } options.kernels.pypy3; diff --git a/sample_environments/pypy3.nix b/sample_environments/pypy3.nix index 25cc33da..5eace115 100644 --- a/sample_environments/pypy3.nix +++ b/sample_environments/pypy3.nix @@ -5,10 +5,5 @@ codedown.makeEnvironment { name = "pypy3"; - # kernels.pypy3.enable = true; - # kernels.pypy3.packages = [ - # "matplotlib" - # "scipy" - # "rope" - # ]; + kernels.pypy3.enable = true; } diff --git a/tests/app/Spec/Tests/Python.hs b/tests/app/Spec/Tests/Python.hs index c1889cc3..d23cea0d 100644 --- a/tests/app/Spec/Tests/Python.hs +++ b/tests/app/Spec/Tests/Python.hs @@ -26,7 +26,7 @@ tests = describe "Python" $ parallel $ do tests' ("python3", "python313") -- tests' ("python3", "python314") - -- tests' ("pypy3", "pypy3") + pypyTests tests' :: (Text, Text) -> LanguageSpec tests' (kernelName, pythonPackage) = introduceNixEnvironment [kernelSpec kernelName pythonPackage] [] [i|Python (#{pythonPackage})|] $ introduceJupyterRunner $ do @@ -72,6 +72,26 @@ tests' (kernelName, pythonPackage) = introduceNixEnvironment [kernelSpec kernelN assertDiagnosticRanges diagnostics [] +-- | Nixpkgs carries far less for PyPy than for CPython, so this covers the kernel itself +-- rather than the package and language server stack the CPython tests exercise. +pypyTests :: LanguageSpec +pypyTests = introduceNixEnvironment [pypyKernelSpec] [] "Python (pypy3)" $ introduceJupyterRunner $ do + testHasExpectedFields "pypy3" + + testKernelStdout "pypy3" [i|print("hi")|] "hi\n" + testKernelStdout "pypy3" [i|import platform; print(platform.python_implementation())|] "PyPy\n" + +pypyKernelSpec :: NixKernelSpec +pypyKernelSpec = NixKernelSpec { + nixKernelName = "pypy3" + , nixKernelChannel = "codedown" + , nixKernelDisplayName = Just "PyPy" + , nixKernelPackages = [] + , nixKernelMeta = Nothing + , nixKernelIcon = Nothing + , nixKernelExtraConfig = Nothing + } + kernelSpec :: Text -> Text -> NixKernelSpec kernelSpec kernelName pythonPackage = NixKernelSpec { nixKernelName = kernelName