Search code examples
pythonsetuptoolspackaging

Python setuptools symlinks and custom install extension


I would like to achieve both of the following for my python package that has a setup.py and uses setuptools:

  1. allow for installation with symlinks rather than copying package files
  2. allow for custom code to run when "install" is used with setup.py

For the first, I usually do pip this way:

pip install -e . --user

and it works fine.

For the second, I do in setup.py:

from __future__ import print_function                                                                                                                
from setuptools import setup                                                                                                                         
from setuptools.command.install import install                                                                                                       
import os                                                                                                                                            


class CustomInstallCommand(install):                                                                                                                 
    def run(self):                                                                                                                                   
        print ("Custom code here")                                                                                                  
        install.run(self)                                                                                                                            

setup(...,
packages=['package_name'],                                                                                                                         
      package_dir={'package_name':'package_name'},                                                                                                           
      cmdclass={'install': CustomInstallCommand},                                                                                                    
      zip_safe=False)     

However, I find that:

  1. If I run pip as above, the custom code is never called
  2. The custom code does run if I do:

    python setup.py install --user

but I'm not sure how to use this command with the equivalent -e option such that symlinks are installed instead of copies of files. How can I achieve both of these?


Solution

  • That's because install won't be called. There are two modes available:

    • "real" installation mode is invoked via python setup.py install and will copy the sources,
    • the "development" mode is invoked via python setup.py develop and will only create symlinks to sources.

    So you will have to override the develop command same way you do it with the install already:

    from setuptools.command.develop import develop
    
    ...
    
    class CustomDevInstallCommand(develop):
        def run(self):
            print('running custom develop command')
            super(CustomDevInstallCommand, self).run()
    
    
    setup(
        ...,
        cmdclass={
            'install': CustomInstallCommand,
            'develop': CustomDevInstallCommand,
        },
    )
    

    Installing via pip install --editable . yields:

    $ pip install --editable . -v
    Created temporary directory: /private/var/folders/_y/2qk6029j4c7bwv0ddk3p96r00000gn/T/pip-ephem-wheel-cache-1yw7baz2
    ...
    Installing collected packages: spam
      Running setup.py develop for spam
        Running command python -c "import setuptools"
        Running command /Users/hoefling/.virtualenvs/stackoverflow/bin/python -c "import setuptools, tokenize;__file__='/Users/hoefling/projects/private/stackoverflow/so-49326214/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" develop --no-deps
        running develop
        running custom develop command
        running egg_info
    ...
    Successfully installed spam
    Cleaning up...