I need to run a simple script after the modules and programs have been installed. I'm having a little trouble finding straight-forward documentation on how to do this. It looks like I need to inherit from distutils.command.install, override some methods and add this object to the setup script. The specifics are a bit hazy though and it seems like a lot of effort for such a simple hook. Does anyone know an easy way to do this?
4 Answers
I dug through distutils source for a day to learn enough about it to make a bunch of custom commands. It's not pretty, but it does work.
import distutils.core
from distutils.command.install import install
...
class my_install(install):
def run(self):
install.run(self)
# Custom stuff here
# distutils.command.install actually has some nice helper methods
# and interfaces. I strongly suggest reading the docstrings.
...
distutils.core.setup(..., cmdclass=dict(install=my_install), ...)

- 16,328
- 12
- 61
- 75
-
2Thanks, Joe. I already found out and posted a similar answer. You were earlier though, so enjoy the green :) – blokkie Aug 24 '09 at 09:38
-
1An example can be found in the [`setup.py`](https://github.com/eliben/pycparser/blob/aa47db488c2966c2c998abe8853f881bf8feb37e/setup.py#L18) of `pycparser`. – 0 _ Mar 27 '15 at 08:18
-
Anyone know a good way to do this as a library author? I.e. so that everyone using the library (setup_requires) gets the new install command? – DylanYoung May 23 '20 at 03:50
OK, I figured it out. The idea is basically to extend one of the distutils commands and overwrite the run method. To tell distutils to use the new class you can use the cmdclass variable.
from distutils.core import setup
from distutils.command.install_data import install_data
class post_install(install_data):
def run(self):
# Call parent
install_data.run(self)
# Execute commands
print "Running"
setup(name="example",
cmdclass={"install_data": post_install},
...
)
Hope this will help someone else.

- 5,375
- 7
- 24
- 18
-
1been looking around on how to add custom commands for ages and nothing that I found would work, till I found this post of yours! thanks! – dm76 Jan 18 '13 at 12:08
I couldn't make Joe Wreschnigs answer work and tweaked his answer analogous to the extending distutils documentation. I came up with this code which works fine on my machine.
from distutils import core
from distutils.command.install import install
...
class my_install(install):
def run(self):
install.run(self)
# Custom stuff here
# distutils.command.install actually has some nice helper methods
# and interfaces. I strongly suggest reading the docstrings.
...
distutils.core.setup(..., cmdclass={'install': my_install})
Note: I didn't edit the answer of Joe since I am uncertain why his answer wasn't working on my machine.
-
2Joe Wreschnig's answer didn't work because `distutils.command.install` is the install module, the class he intended to extend was `distutils.command.install.install`. – Uyghur Lives Matter Dec 28 '12 at 17:28
-
3@cpburnz I fixed the other answer since it's most likely what people will try first. – kynan Jul 23 '13 at 11:21
I got an error when I tried the accepted answer here (might be because I'm using Python 2.6 in this particular case, not sure). This occurred for both 'setup.py install' and 'pip install':
sudo python setup.py install
fails with error: error in setup.cfg: command 'my_install' has no such option 'single_version_externally_managed'
AND
sudo pip install . -U
fails more verbosely but also with error: option --single-version-externally-managed not recognized
Variation on the accepted answer
Replacing the imports from distutils with setuptools solved the problem for me:
from setuptools import setup
from setuptools.command.install import install

- 330
- 4
- 7