Running custom code on package install?

Hey all, hope you are having a great day :slight_smile:!

I’m messing around looking to publish a little project I have as a PyPi package and I would like to run some custom python code upon successful installation of my package.

I’ve built a basic package, tested it on the TESTPYPI index and it works, but I’m not sure how to have code run when I install the package; I tried code in setup.py, but obviously thats for when the package is built, putting the code in __init__.py didn’t work either as it only runs when the package is imported.

As of right now I’m not too sure on what exactly I’d like to have run on install, but I was thinking about a simple little GUI with links, info and more.

Thanks in advance,

  • mte

Hi @mte, AFAIK currently the packaging ecosystem in Python does not standardise any kind of mechanism for executing hooks upon installation[1].

Arbitrary code execution is always a complicated topic and can be very dangerous. I would not be surprised if the community never decides to treat this kind of use case as “tier 1”… The advice is to try avoid arbitrary code execution as much as possible.

There are a few techniques that can be used to get around this:

  1. Run arbitrary hooks upon the first program usage.
    You can use platformdirs to save a file into the user’s home directory once you have run the hook. This way you can avoid running it twice by checking if the file exists

  2. You can, in theory, distribute your package only as a sdist.
    This way the installer will be forced to transform the sdist into a wheel before installing it.
    You can take advantage of this to run a hook when building the wheel. However, to be frank this is a hack and I definitely don’t recommend that.


  1. I don’t know about conda packages. ↩︎

2 Likes

That’s my understanding as well. The package build process (converting sources to a wheel) can invoke hooks, plugins, etc. depending on the build backend. But the process of installation (taking a wheel and making its contents available to Python) is by design an entirely static process. That’s deliberate, so that consumers of wheels have a very straightforward security model to review.

We’ve had a number of people ask for some form of post-install hook mechanism, but because of the conflict with the “installation doesn’t involve arbitrary code execution” principle, we’ve always resisted such suggestions. And to date, as far as I know no-one has proposed a use case that wasn’t either (a) solveable by other means, or (b) sufficiently niche that the impact on the packaging ecosystem wasn’t justified.

One thing I would ask is whether the OP is building a library or an application. The packaging ecosystem is designed around the needs of libraries, and this is reflected in some of the constraints. But the description of “a simple little GUI with links, info and more” sounds more like the sort of thing I’d expect in an application installer. If you’re building an application, distributing it via PyPI as a wheel may not be the best fit for what you’re trying to do - tools like PyInstaller might well be a better choice.

2 Likes

To answer your question, conda packages do support this, both as standardized hooks to install things like start menu items, and pre-install, post-install and pre-uninstall to run arbitrary code. However, they are heavily discouraged if at all possible, generally for the same reasons they are for pure Python packages.