How to perform custom build steps in setup.py?

eigenein picture eigenein · Jan 21, 2013 · Viewed 8.7k times · Source

The distutils module allows to include and install resource files together with Python modules. How to properly include them if resource files should be generated during a building process?

For example, the project is a web application which contains CoffeeScript sources that should be compiled into JavaScript and included in a Python package then. Is there a way to integrate this into a normal sdist/bdist process?

Answer

nerdvegas picture nerdvegas · Jan 17, 2014

I spent a fair while figuring this out, the various suggestions out there are broken in various ways - they break installation of dependencies, or they don't work in pip, etc. Here's my solution:

in setup.py:

from setuptools import setup, find_packages
from setuptools.command.install import install
from distutils.command.install import install as _install

class install_(install):
    # inject your own code into this func as you see fit
    def run(self):
        ret = None
        if self.old_and_unmanageable or self.single_version_externally_managed:
            ret = _install.run(self)
        else:
            caller = sys._getframe(2)
            caller_module = caller.f_globals.get('__name__','')
            caller_name = caller.f_code.co_name

            if caller_module != 'distutils.dist' or caller_name!='run_commands':
                _install.run(self)
            else:
                self.do_egg_install()

        # This is just an example, a post-install hook
        # It's a nice way to get at your installed module though
        import site
        site.addsitedir(self.install_lib)
        sys.path.insert(0, self.install_lib)
        from mymodule import install_hooks
        install_hooks.post_install()
        return ret

Then, in your call to the setup function, pass the arg:

cmdclass={'install': install_}

You could use the same idea for build as opposed to install, write yourself a decorator to make it easier, etc. This has been tested via pip, and direct 'python setup.py install' invocation.