Python module segfaults python interpreter but runs in jupyter?

I’m still (slowly) working on getting cadquery to work on aarch64-darwin.

I’ve never figured out how to build OCP (which I think requires a newer MacOS SDK than nixpkgs offers), but someone recently made a wheel available for aarch64-darwin, so I’ve made it a lot farther!

Curiously, the below flake builds for me, and runs in jupyter – hooray!

Oddly, it segfaults when I try to run it from the console.

{
  description = "";

  outputs = {
    self,
    nixpkgs,
  }: let
    system = "aarch64-darwin";
    pkgs = import nixpkgs {
      inherit system;
    };
    py = pkgs.python311;
    pyPkgs = py.pkgs;
    inherit (pyPkgs) toPythonModule buildPythonPackage;
  in {
    packages.${system} = {
      default =
        py.withPackages
        (ps:
          [
            ps.jupyterlab
          ]
          ++ [self.outputs.packages.${system}.cadquery]);
      cadquery = let
        pname = "cadquery";
        version = "2.4.0";
      in
        buildPythonPackage {
          inherit pname version;
          format = "pyproject";
          propagatedBuildInputs =
            (with pyPkgs; [
              ezdxf
              multimethod
              nptyping
              numpy
              pyparsing
              setuptools
              typing-extensions
              typish
            ])
            ++ (with self.outputs.packages.${system}; [
              casadi-python
              nlopt-python
              ocp
            ]);
          src = pkgs.fetchPypi {
            inherit pname version;
            hash = "sha256-OOjjAgYPLlCUOrD4rKuYXDenMAnpcsewJ2fJC+9/s+c=";
          };
          # nativeCheckInputs = [pyPkgs.pytestCheckHook];
          # segfault? why??
          # pythonImportsCheck = ["cadquery"];
        };
      nlopt-python =
        toPythonModule
        ((pkgs.nlopt.overrideAttrs
            (prev: {
              configureFlags = builtins.filter (each: each != "--without-python") prev.configureFlags or [];
              buildInputs = prev.buildInputs or [] ++ [pkgs.swig];
              propagatedBuildInputs = prev.propagatedBuildInputs or [] ++ [pyPkgs.numpy];
              nativeCheckInputs =
                prev.nativeCheckInputs
                or []
                ++ [
                  (py.withPackages (ps: [ps.numpy]))
                  pyPkgs.pythonImportsCheckHook
                ];
            }))
          .overrideAttrs (_: {
            doCheck = true;
            pythonImportsCheck = ["nlopt"];
          }));

      casadi-python = let
        version = "3.6.4";
      in
        toPythonModule
        ((pkgs.stdenv.mkDerivation {
            inherit version;
            name = "casadi";
            buildInputs = with pkgs; [
              py
              swig4
            ];
            nativeBuildInputs = [pkgs.cmake];
            nativeCheckImports = [pyPkgs.pythonImportsCheckHook];
            propagatedBuildInputs = [pyPkgs.numpy];
            cmakeFlags = [
              "-DWITH_PYTHON=ON"
              "-DWITH_PYTHON3=ON"
              "-DPYTHON_PREFIX=${placeholder "out"}/${py.sitePackages}"
              # Fails with:
              # Broken paths found in a .pc file! /nix/path/to/lib/pkgconfig/tinyxml2.pc
              "-DWITH_TINYXML=OFF"
            ];
            src = pkgs.fetchFromGitHub {
              "owner" = "casadi";
              "repo" = "casadi";
              rev = version;
              hash = "sha256-BfUpSXbllQUNn5BsBQ+ZmQ15OLOp/QegT8igOxSgukE=";
            };
          })
          .overrideAttrs (_: {
            pythonImportsCheck = ["casadi-fake"];
          }));

      ocp = let
        version = "7.7.2";
      in
        buildPythonPackage {
          inherit version;
          pname = "cadquery-ocp";
          format = "wheel";
          src = pkgs.fetchurl {
            url = "https://github.com/jdegenstein/ocp-build-system/releases/download/${version}_macos_arm64/cadquery_ocp-${version}-cp311-cp311-macosx_11_0_arm64.whl";
            hash = "sha256-CkWRA+3g77VVH0Sc75KmXHb1HEdUVl81OvWMZQdHoys=";
          };
          pythonImportsCheck = ["OCP"];
        };
    };

    apps.${system}.default = {
      type = "app";
      program = "${self.packages.${system}.default}/bin/jupyter-lab";
    };
  };
}

If I uncomment even just the import check:

$ nix build .#cadquery
...
Check whether the following modules can be imported: cadquery
/nix/store/6p3h1n7hmgymb7gm6yh9zvm6dckxfg0x-python-imports-check-hook.sh/nix-support/setup-hook: line 10: 89952 Segmentation fault: 11  /nix/store/7b0rz3bnx7msw2wawkv1hhn5lqf1b0wi-python3-3.11.6/bin/python3.11 -c 'import os; import importlib; list(map(lambda mod: importlib.import_module(mod), os.environ["pythonImportsCheck"].split()))'

If I comment out the checks for cadquery (the pytest and import check), it builds and runs fine, and jupyterlab is able to import cadquery, and it seems to work!

$ nix build .#cadquery
$ nix build
$ otool -L result/bin/python
result/bin/python:
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1292.60.1)
$ ./result/bin/python -m jupyterlab

But oddly importing from the python interpreter fails with a segfault (as expected with the failure of the import check):

$ ./result/bin/python -c 'import cadquery'
Segmentation fault: 11

I’ve uploaded ./result/bin/python -v -c 'import cadquery' to gist:bf7654c1871d384a966d0b1eb6633793 · GitHub; I’m not sure if the permission denied errors for creating .pyc (or was it __pycache__) files are relevant?

Any ideas why this module would run fine in jupyterlab but fail to even import (segfault) from the interpreter?