Python3 override for bluezSupport not working?

On aarch64-linux (an RPi3) with hardware.bluetooth enabled and working bluetooth, I tried to build a python with bluetooth support (a dependency requires socket.AF_BLUETOOTH, and I found the issue below).

Based on cpython/default.nix, it seems like this should work:

$ nix shell "$(                                                                                   
    nix eval --raw --apply 'py: py.override { bluezSupport = true; }' github:nixos/nixpkgs#python3
)" -c python -c 'import socket; print(socket.AF_BLUETOOTH)'
AttributeError: module 'socket' has no attribute 'AF_BLUETOOTH' 

But obviously it doesn’t. python3Full seems to be basically defined as the same override I’m using above, but does work (I realize the override is a noop here):

$ nix shell "$(
    nix eval --raw --apply 'py: py.override {}' github:nixos/nixpkgs#python3Full
)" -c python -c 'import socket; print(socket.AF_BLUETOOTH)'
AddressFamily.AF_BLUETOOTH

Why is that? Shouldn’t python3.override { bluezSupport = true; } be basically the same thing as python3Full (at least with regards to bluetooth support)?

EDIT: See below – it only seems to have the broken behavior when I use .withPackages.

Related:

1 Like

Hmmm, now getting a there is no substituter that can build it error with my nix shell $(nix eval) business.

I think this should do the same thing:

$ nix-shell \
    -I nixpkgs=flake:github:nixos/nixpkgs \
    -p '(import <nixpkgs> {}).python3Full.override { }' \
    --command 'python -c "import socket; print(socket.AF_BLUETOOTH)"'
31
$ nix-shell \
    -I nixpkgs=flake:github:nixos/nixpkgs \
    -p '(import <nixpkgs> {}).python3.override { bluezSupport = true; }' \
    --command 'python -c "import socket; print(socket.AF_BLUETOOTH)"'
31

Hmm, so now it seems to be working (with nix-shell).

Huh, no idea why this wasn’t working before, I’m sure user error on my end.

{
  description = "A very basic flake";

  inputs.nixpkgs.url = "github:nixos/nixpkgs/2459917e66c70c80e16c315d62b3533c9239a2fa";
  outputs = {
    self,
    nixpkgs,
  }: let
    system = "aarch64-linux";
    pkgs = import nixpkgs {inherit system;};
  in {
    packages.${system} = {
      py-override = pkgs.python3.override {bluezSupport = true;};
      py-full = pkgs.python3Full;
    };

    apps.${system} = let
      makeApp = package: let
        script = pkgs.writeShellScriptBin "run" ''
          echo ${package}
          ${self.packages.${system}.${package}}/bin/python -c '
          import socket
          print(socket.AF_BLUETOOTH)
          '
        '';
      in {
        type = "app";
        program = "${script}/bin/run";
      };
    in {
      py-override = makeApp "py-override";
      py-full = makeApp "py-full";
    };
  };
}
$ nix run .#py-override; nix run .#py-full
py-override
31
py-full
31

Ah, figured it out – the withPackages seems to break things!

Why is that?

{
  description = "A very basic flake";

  inputs.nixpkgs.url = "github:nixos/nixpkgs/2459917e66c70c80e16c315d62b3533c9239a2fa";
  outputs = {
    self,
    nixpkgs,
  }: let
    system = "aarch64-linux";
    pkgs = import nixpkgs {inherit system;};
  in {
    packages.${system} = {
      py-override = (pkgs.python3.override {bluezSupport = true;}).withPackages (_: []);
      py-full = pkgs.python3Full.withPackages (_: []);
    };

    apps.${system} = let
      makeApp = package: let
        script = pkgs.writeShellScriptBin "run" ''
          echo ${package}
          ${self.packages.${system}.${package}}/bin/python -c '
          import socket
          print(socket.AF_BLUETOOTH)
          '
        '';
      in {
        type = "app";
        program = "${script}/bin/run";
      };
    in {
      py-override = makeApp "py-override";
      py-full = makeApp "py-full";
    };
  };
}
$ nix run .#py-override; nix run .#py-full
py-override
Traceback (most recent call last):
  File "<string>", line 3, in <module>
AttributeError: module 'socket' has no attribute 'AF_BLUETOOTH'
py-full
31

Probably has something to do with withPackages itself being an override: https://github.com/NixOS/nixpkgs/blob/ecef65f019d42310a9aaca41f69ecdca0c8a95de/pkgs/development/interpreters/python/with-packages.nix

I wonder if I need to “compose” overrides somehow.

It looks like the solution is likely to be using buildEnv, which has an example using an override: https://github.com/NixOS/nixpkgs/blob/ecef65f019d42310a9aaca41f69ecdca0c8a95de/doc/languages-frameworks/python.section.md#pythonbuildenv-function-pythonbuildenv-function

buildEnv did not work. I think the issue I’m facing is discussed here: Python: withPackages and overrides does not result in correct `passthru` · Issue #64334 · NixOS/nixpkgs · GitHub

Indeed this was the issue: Python: withPackages and overrides does not result in correct `passthru` · Issue #64334 · NixOS/nixpkgs · GitHub

Adding self to the override seems to be the key. Because there needs to be a value to assign self = ... to, adding a let seems to do the trick:

python = pkgs.python3.override {
        bluezSupport = true;
        self = python;
};
in python.withPackages (ps:
        with ps; [ ... ]
);