9

Is it possible to automatically remove build products that are generated by a setup.py script based on setuptools?

I've just started with a new Python project and it's the first time I'm using setuptools as a developer, so I may be getting something wrong. when I build the project using python setup.py bdist, three directories, build, dist and one ending in .egg-info are created. When I then run python setup.py clean it doesn't seem to be doing anything and just prints this:

running clean

I've tried adding --all to the clean command and while it does remove some files in the build directory, it doesn't remove the directory itself or any of the files in the other two directories.

I'm assuming that this should be possible very easily and that I'm just looking in the wrong place. I'm used to this functionality e.g. from virtually any project using make where make clean or make distclean will remove any build products.

Feuermurmel
  • 9,490
  • 10
  • 60
  • 90

1 Answers1

9

Standard approach:

distutils.command.clean

From Cleaning build directory in setup.py and the documentation:

This command removes the temporary files created by build and its subcommands, like intermediary compiled object files. With the --all option, the complete build directory will be removed.


Another way to do it:

This may not be the best solution:

It seems from the comment below this answer that python setup.py clean --all sometimes fails to remove everything (Numpy in the example in the comment).

It seems not all setup.py scripts support clean. Example: NumPy – kevinarpe Jun 15 '16 at 7:14


You could use the remove_tree() command in your setup script:

import glob
remove_tree(['dist', glob.glob('*.egg-info')[0],glob.glob('build/bdist.*')[0]]) 

Or in a setup script:

from setuptools import setup
from setuptools.command import install 

class PostInstallCommand(install):

    def run(self):
        import glob
        from distutils.dir_util import remove_tree
        remove_tree(['dist', glob.glob('*.egg-info')[0],glob.glob('build/bdist.*')[0]]) 


setup(name='Some Name',
      version='1.0',
      description='A cross platform library',
      author='Simon',
      platforms = ["windows", "mac", "linux"],
      py_modules = ['UsefulStuff', '__init__'],
      cmdclass = {'install':PostInstallCommand}
     )

Another way I solved it was to remove everything manually manually (using shutil and glob):

import shutil, glob
shutil.rmtree('dist')
shutil.rmtree(glob.glob('*.egg-info')[0])
shutil.rmtree(glob.glob('build/bdist.*')[0])

Adding it to the setup script was harder but using this answer, it should look something like this:

from setuptools import setup
from setuptools.command import install 

class PostInstallCommand(install):

    def run(self):
        import shutil, glob
        shutil.rmtree('dist')
        shutil.rmtree(glob.glob('*.egg-info')[0])
        shutil.rmtree(glob.glob('build/bdist.*')[0])
        install.run(self)



setup(name='Some Name',
      version='1.0',
      description='A cross platform library',
      author='Simon',
      platforms = ["windows", "mac", "linux"],
      py_modules = ['UsefulStuff', '__init__'],
      cmdclass = {'install':PostInstallCommand}
     )

cmdclass = {'install'} allows this class to run after the installation. See this answer for more details.

What gave me the idea to use shutil?

The idea to use shutil came from the old documentation:

Some of this could be replaced with the shutil module?

Xantium
  • 11,201
  • 10
  • 62
  • 89
  • 2
    Thank you, Simon! Do you think there is a reason this problem hasn't manifested enough to have a built-in solution? Do most people just not have a problem here with cleanup? I'm sort of wondering if there is some other approach or tool that subsumes this need, if I'm running into an X-Y problem here. – Daniel Lyons Apr 18 '18 at 19:24
  • @DanielLyons Well I could not say for certain (I am not one of the Python inplamenters), but I can say that I have never encountered a situation where clean up is essential. If you going to just distribute the package, why clean it up at all? After all you are probably just going to distribute what is given in the `build` folder. It's tidier, but once again, the developer who uses your package is likely just to delete the source, once they have installed. Second `python setup.py install` does not take the other folders with it. Just the contents of the lib/build folder. – Xantium Apr 18 '18 at 19:54
  • So you are not installing everything you clean up anyway. As for other approach or tool. I do not know of any other tool that could do this. Approach... I did my best above ;) – Xantium Apr 18 '18 at 19:56
  • 1
    @DanielLyons You can check out https://stackoverflow.com/questions/1594827/cleaning-build-directory-in-setup-py?noredirect=1&lq=1 It seems that there, the generally "accepted" way to go around doing this is by the command used in the question. Probably the inplamenters thought that that would be enough. Actually in the highest voted answer you will see that `distutils.command.clear` is the standard command to use – Xantium Apr 18 '18 at 20:01
  • I don't know, maybe someone could shed some more light on why, more reliably than me. I certainly think that keeping or removing the temporary folders is not going to make a massive difference anyway. – Xantium Apr 18 '18 at 20:15