# Python packages forza_trigger.py imports that aren't in nixpkgs. Returns # an attrset consumed by ./default.nix. # # Bumping a version: change `version` and `hash`, then `nix build` — Nix # fails with the new sha256 in the error message, paste it back in. { lib, pkgs, python ? pkgs.python3, }: let py = python.pkgs; in rec { # CFFI bindings to libhidapi (flok/hidapi-cffi on PyPI). pydualsense's # `import hidapi` resolves to this — nixpkgs' python3Packages.hidapi is the # Cython wrapper from trezor/cython-hidapi which exposes a different # `import hid` API and can't satisfy pydualsense. hidapi-usb = py.buildPythonPackage rec { pname = "hidapi-usb"; version = "0.3.2"; format = "setuptools"; # PyPI's project URL slug uses a hyphen (`hidapi-usb`) but the sdist file # itself is PEP-625-normalized to an underscore (`hidapi_usb-…`). Stock # fetchPypi assumes they match — they don't here, so fetch by direct URL. src = pkgs.fetchurl { url = "https://files.pythonhosted.org/packages/55/80/960ae94b615e26a7d1aeebe8e9fefda2f25608bf1016f9aec268b328c35e/hidapi_usb-${version}.tar.gz"; hash = "sha256-oxp+2i+qqYd1uwiS2Dh8/PzO62iYQQXpR936MnDIFk0="; }; propagatedBuildInputs = [ py.cffi ]; # Upstream's hidapi.py walks a tuple of soname strings via ffi.dlopen() # until one resolves. Pin the two Linux hidraw entries to absolute store # paths so the wrapped Python in our writePython3Bin closure finds them # without LD_LIBRARY_PATH wrapping. The libusb / iohidmanager / dylib / # dll entries are dead code on Linux. --replace-fail makes a rename in # upstream's tuple a loud build error rather than a silent ImportError # at runtime. postPatch = '' substituteInPlace hidapi.py \ --replace-fail "'libhidapi-hidraw.so'," "'${pkgs.hidapi}/lib/libhidapi-hidraw.so'," \ --replace-fail "'libhidapi-hidraw.so.0'," "'${pkgs.hidapi}/lib/libhidapi-hidraw.so.0'," ''; pythonImportsCheck = [ "hidapi" ]; meta = { description = "CFFI wrapper for hidapi (used by pydualsense)"; homepage = "https://github.com/flok/hidapi-cffi"; license = lib.licenses.bsd3; }; }; pydualsense = py.buildPythonPackage rec { pname = "pydualsense"; version = "0.7.5"; format = "pyproject"; src = py.fetchPypi { inherit pname version; hash = "sha256-YgX8AJE4f8p7geKT3xlCD0Mlh1GcyHpBz4rEIqdwKgs="; }; nativeBuildInputs = [ py.poetry-core ]; propagatedBuildInputs = [ hidapi-usb ]; pythonImportsCheck = [ "pydualsense" ]; meta = { description = "Control your PS5 DualSense controller from Python"; homepage = "https://github.com/flok/pydualsense"; license = lib.licenses.mit; }; }; # Single-file Forza UDP packet parser (nettrom/forza_motorsport). Pinned to # a known-good commit; the repo is dormant (last commit 2021) but the FH4 # packet layout is frozen and FH5 reuses it byte-for-byte. fdp = py.buildPythonPackage { pname = "fdp"; version = "0-unstable-2021-05-28"; format = "other"; src = pkgs.fetchurl { url = "https://raw.githubusercontent.com/nettrom/forza_motorsport/61845cb7ff4082211292a51ce3c49edbfd2d6503/fdp.py"; hash = "sha256-osFaVF9VaEzU4dp3x6KN6OF7SXsd9ZBwvilU+xTT7mM="; }; dontUnpack = true; installPhase = '' runHook preInstall install -Dm644 $src $out/${python.sitePackages}/fdp.py runHook postInstall ''; pythonImportsCheck = [ "fdp" ]; meta = { description = "ForzaDataPacket — Forza Motorsport / Horizon UDP packet parser"; homepage = "https://github.com/nettrom/forza_motorsport"; license = lib.licenses.mit; }; }; }