66

How could I make my setup.py pre-delete and post-delete the build directory?

Ram Rachum
  • 84,019
  • 84
  • 236
  • 374

4 Answers4

145

Does this answer it? IIRC, you'll need to use the --all flag to get rid of stuff outside of build/lib:

python setup.py clean --all
Jim Pivarski
  • 5,568
  • 2
  • 35
  • 47
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 3
    It seems not all `setup.py` scripts support `clean`. Example: NumPy – kevinarpe Jun 15 '16 at 07:14
  • clean works in my case for some files, but e.g. the .egg directory stays there... any way to "deep clean"? – ntg May 20 '20 at 08:50
  • ahhh, and in my case there was a makefile, so I could `make clean` from there... (simple module created with cookiecutter) – ntg May 20 '20 at 10:17
  • 2
    Unfortunately this does not also clean the `dist` and `egg-info` directories, so I just made a shell script to `rm -rf ./build ./dist ./*egg-info`, letting PyCharm's run configuration manage the working directory. – hlongmore Jul 02 '20 at 00:23
15

For pre-deletion, just delete it with distutils.dir_util.remove_tree before calling setup.

For post-delete, I assume you only want to post-delete after selected commands. Subclass the respective command, override its run method (to invoke remove_tree after calling the base run), and pass the new command into the cmdclass dictionary of setup.

Martin v. Löwis
  • 124,830
  • 17
  • 198
  • 235
11

This clears the build directory before to install

python setup.py clean --all install

But according to your requirements: This will do it before, and after

python setup.py clean --all install clean --all
Adrian Lopez
  • 2,601
  • 5
  • 31
  • 48
  • Second `clean --all` is being ignored. I tried the following `python3 ./setup.py clean --all install clean --all` and the `build` directory persists. In the output, no mention about any cleaning after `install`. – Hans Deragon Jul 16 '20 at 14:57
6

Here's an answer that combines the programmatic approach of Martin's answer with the functionality of Matt's answer (a clean that takes care of all possible build areas):

from distutils.core import setup
from distutils.command.clean import clean
from distutils.command.install import install

class MyInstall(install):

    # Calls the default run command, then deletes the build area
    # (equivalent to "setup clean --all").
    def run(self):
        install.run(self)
        c = clean(self.distribution)
        c.all = True
        c.finalize_options()
        c.run()

if __name__ == '__main__':

    setup(
        name="myname",
        ...
        cmdclass={'install': MyInstall}
    )
Alan
  • 1,889
  • 2
  • 18
  • 30
  • to simply run a command after another, an "alias" seems like a better solution: https://setuptools.readthedocs.io/en/latest/setuptools.html#alias-define-shortcuts-for-commonly-used-commands – Florian Mar 08 '19 at 10:24
  • @Florian, I imagine that an alias could be a better solution in some situations. In my situation, however, I generate the setup.py file once for each package I produce. It's only a one-time cost to put the logic in the template that generates the setup.py file. – Alan Mar 08 '19 at 16:08