Working directory for Python script

With the help of evanjs on IRC, I packaged a simple Python script. It is an IRC welcoming bot. It expects a bot_settings.py file, but I am unable to point it to the file I want. So for import bot_settings as settings it says ModuleNotFoundError: No module named 'bot_settings' in the journal.

Below is the expression. You can see that I also tried makeWrapperArgs.

systemd.services.welcomebot = let welcomebotPkg = pkgs.python38.pkgs.buildPythonPackage rec {
  pname = "welcomebot";
  version = "0.1";
  format = "other";

  src = builtins.fetchGit {
    url = "https://github.com/qarkai/WelcomeBot.git";
    ref = "Py3";
  };
  
  doCheck = false;

  checkInputs = [ pkgs.python38.pkgs.coverage ];

  installPhase = ''
    mkdir -p $out/bin
    install -m0755 bot.py $out/bin/bot.py
  '';
  #makeWrapperArgs = [ "--set PYTHONPATH /home/ircbot:$PYTHONPATH" ];

  meta = {
    description = ''
      IRC bot for welcoming people
    '';
  };

}; in {
    description = "Run WelcomeBot";
    after = [ "network-online.target" ];
    wantedBy = [ "network-online.target" ];
    environment = {
      PYTHONPATH = "/home/ircbot/bot_settings.py:$PYTHONPATH";
      LC_ALL = "en_US.UTF-8";
    };
    serviceConfig = {
      Type = "idle";
      WorkingDirectory = "/home/ircbot";
      ExecStart = "${pkgs.python38}/bin/python3 ${welcomebotPkg}/bin/bot.py";
      User = "ircbot";
      TimeoutStopSec = "3";
      PrivateTmp = "true";
      Restart = "on-failure";
      KillSignal = "SIGINT";        
    };
};

Do I interpret correctly that bot_settings.py is supposed to be supplied in the working directory? This cannot work because Python imports relative to the source path, not CWD. You can of course do something like this. For a toy application that is probably good enough.

I just saw the environment settings you have there - pretty sure PYTHONPATH should be a directory, not the file you are targeting.

1 Like

Thanks! I went with a “brute force” method proposed by evanjs earlier and it works:

botSettings = pkgs.writeTextFile {
  name = "bot_settings.py";
  text = ''
    ...insert settings here...
  '';
};

installPhase = ''
  mkdir -p $out/bin
  install -m0755 bot.py $out/bin/bot.py
  install -m0755 ${botSettings} $out/bin/bot_settings.py
'';

I have a video on python packaging, this may help

However, I would probably use buildPythonApplication, ensure that your “application” works, then reference it in a systemd unit file.

Oh, do you have an example of buildPythonApplication and referencing it in a unit? The only info I found about the difference with buildPythonPackage was in an SO comment: “The main difference is that buildPythonApplication doesn’t add the interpreter version to the resulting output name apparently”

There’s more to it, it also wont propagate it’s python packages when included as a dependency in another derivation. That way you could have an application packaged with python2 be used in a python3 environment

1 Like

Many thanks for all your informative videos :smile:

Not to hijack the thread, but I’m creating a package using buildPythonApplication and was curious about the recommended way to add the directory of the compiled binary to PATH. At the moment, I get the following warning when the package builds:

WARNING: The script MyPythonApp is installed in '/nix/store/blahblahblah-MyPythonApp/bin' which is not on PATH.
  Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location.

you can disregard that. By default, $out/bin is not on the PATH. However, we should probably add --no-warn-script-location to the builder

1 Like

I created a PR [staging] python3.pkgs.pipInstallHook: don't warn on script installation by jonringer · Pull Request #104411 · NixOS/nixpkgs · GitHub