Is it possible to specify a post-install Python script file as part of the setuptools setup.py file so that a user can run the command:
python setup.py install
on a local project file archive, or
pip install <name>
for a PyPI project and the script will be run at the completion of the standard setuptools install? I am looking to perform post-install tasks that can be coded in a single Python script file (e.g. deliver a custom post-install message to the user, pull additional data files from a different remote source repository).
I came across this SO answer from several years ago that addresses the topic and it sounds as though the consensus at that time was that you need to create an install subcommand. If that is still the case, would it be possible for someone to provide an example of how to do this so that it is not necessary for the user to enter a second command to run the script?
Type “ pip install setuptools ” (without quotes) in the command line and hit Enter again. This installs setuptools for your default Python installation. The previous command may not work if you have both Python versions 2 and 3 on your computer.
the setuptools is not part of the python vanilla codebase, hence not a vanilla modules. python.org installers or mac homebrew will install it for you, but if someone compile the python by himself or install it on some linux distribution he may not get it and will need to install it by himself.
Note: The solution below only works when installing a source distribution zip or tarball, or installing in editable mode from a source tree. It will not work when installing from a binary wheel (.whl
)
This solution is more transparent:
You will make a few additions to setup.py
and there is no need for an extra file.
Also you need to consider two different post-installations; one for development/editable mode and the other one for install mode.
Add these two classes that includes your post-install script to setup.py
:
from setuptools import setup from setuptools.command.develop import develop from setuptools.command.install import install class PostDevelopCommand(develop): """Post-installation for development mode.""" def run(self): develop.run(self) # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION class PostInstallCommand(install): """Post-installation for installation mode.""" def run(self): install.run(self) # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION
and insert cmdclass
argument to setup()
function in setup.py
:
setup( ... cmdclass={ 'develop': PostDevelopCommand, 'install': PostInstallCommand, }, ... )
You can even call shell commands during installation, like in this example which does pre-installation preparation:
from setuptools import setup from setuptools.command.develop import develop from setuptools.command.install import install from subprocess import check_call class PreDevelopCommand(develop): """Pre-installation for development mode.""" def run(self): check_call("apt-get install this-package".split()) develop.run(self) class PreInstallCommand(install): """Pre-installation for installation mode.""" def run(self): check_call("apt-get install this-package".split()) install.run(self) setup( ...
P.S. there are no any pre-install entry points available on setuptools. Read this discussion if you are wondering why there is none.
Note: The solution below only works when installing a source distribution zip or tarball, or installing in editable mode from a source tree. It will not work when installing from a binary wheel (.whl
)
This is the only strategy that has worked for me when the post-install script requires that the package dependencies have already been installed:
import atexit from setuptools.command.install import install def _post_install(): print('POST INSTALL') class new_install(install): def __init__(self, *args, **kwargs): super(new_install, self).__init__(*args, **kwargs) atexit.register(_post_install) setuptools.setup( cmdclass={'install': new_install},
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With