Package and service definition for a python rest api project

Hi,
I am trying to define the package and service definition for a python project that provides a rest api and uses the gunicorn http server. So far I have the following:

The packaging definition (gramps-webapi/default.nix):

{ pkgs ? import <nixpkgs> { } }:
let
  python = pkgs.python3;
  pythonPackages = python.pkgs;
in
pythonPackages.buildPythonApplication rec {
  pname = "gramps-webapi";
  version = "1.1.0";

  src = pkgs.fetchFromGitHub {
    owner = "gramps-project";
    repo = "gramps-webapi";
    rev = "v${version}";
    sha256 = "sha256-sOGzH7g9QVwPR4uTIIhMFikgeUa2yIj6Wz3f2cpPJvk=";
  };

  propagatedBuildInputs = with python.pkgs; [
    flask
    flask-compress
    flask-limiter
    flask-cors
    flask-caching
    flask-sqlalchemy
    flask-jwt-extended
    pillow
    bleach
    tinycss2
    whoosh
    jsonschema
    marshmallow
    celery
    click
    boto3
    alembic
    unidecode
    webargs

    ffmpeg-python
    sqlalchemy
    pdf2image
    redis
    gunicorn
  ];

  doCheck = false;

  passthru = {
    inherit python;
    pythonPath = [
      # Add the path to the gramps-webapi module
      "$out/gramps_webapi"
    ] ++ pythonPackages.buildPythonPath propagatedBuildInputs;
  };

  installPhase = ''
    mkdir -p $out/gramps_webapi
    cp -dr --no-preserve='ownership' ./gramps_webapi $out/gramps_webapi
  '';

  meta = {
    description = "A RESTful web API for Gramps";
    homepage = "https://github.com/gramps-project/gramps-webapi/";
  };
}

The service definition (gramps-web.nix)

{ config, lib, pkgs, ... }:
let
  cfg = config.services.gramps-web;
  inherit (lib) mkIf mkOption types mkEnableOption;
  gramps-webapi = pkgs.callPackage ../gramps-webapi { };
in
{
  options = {
    services.gramps-web = {

      enable = mkEnableOption (lib.mdDoc "Gramps-Web");

      user = mkOption {
        type = types.str;
        default = "gramps-web";
        description = lib.mdDoc "User account under which gramps-web runs.";
      };

      group = mkOption {
        type = types.str;
        default = "gramps-web";
        description = lib.mdDoc "Group account under which gramps-web runs.";
      };

      openFirewall = mkOption {
        type = types.bool;
        default = false;
        description = lib.mdDoc ''
          Open ports in the firewall for the server.
        '';
      };

      dataDir = mkOption {
        type = types.str;
        default = "gramps-web";
        description = lib.mdDoc ''
          The directory below {file}`/var/lib` where gramps-web stores its data.
        '';
      };
    };
  };

  config = mkIf cfg.enable {

    systemd.services.gramps-web = {
      description = "Web app for collaborative genealogy";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];

      serviceConfig =
        {
          Type = "simple";
          User = cfg.user;
          Group = cfg.group;
          ExecStart =
            let
              cmd = "${gramps-webapi.python.pkgs.gunicorn}/bin/gunicorn";
              # appPath = "${gramps-webapi}/gramps_webapi/wsgi:app";
              appPath = "gramps_webapi.wsgi:app";
            in
            ''
              ${cmd} -w 2 -b 0.0.0.0:5000 ${appPath}
            '';
          Restart = "on-failure";
        };
    };

    networking.firewall = mkIf cfg.openFirewall {
      allowedTCPPorts = [ cfg.listen.port ];
    };

    users.users = mkIf (cfg.user == "gramps-web") {
      gramps-web = {
        isSystemUser = true;
        group = cfg.group;
      };
    };

    users.groups = mkIf (cfg.group == "gramps-web") {
      gramps-web = { };
    };
  };
}

The problem is that gunicorn doesn’t find the gramps_web module. journalctl -u gramps-web reports the error:

ModuleNotFoundError: No module named 'gramps_webapi'

Thank you for any help.

1 Like