Run custom task when call `pip install`
Asked Answered
M

2

21

I want to make my python package "pip installable". The problem is that the package has shell script that must be sourced in the user's init shell script (e.g. .bashrc).

But after the installation, the user don't exactly know where the script went (presumably /usr/bin, but we can't garantee). Of course the user can runs which myscript.sh and manually edits his init script.

But I want to automate this step. I can create a new distutils command, but pip install doesn't call it. And I can extend distutils.command.install.install, but the installation breaks via pip (although works via python setup.py install):

setup.py

from distutils.command.install import install

class CustomInstall(install):
    def run(self):
        install.run(self)
        # custom stuff here
        do_my_stuff()

setup(..., cmdclass={'install': CustomInstall})

shell

$ pip install dist/mypackage.tar.gz
Unpacking ./dist/mypackage.tar.gz
  Running setup.py egg_info for package from file:///path/to/mypackage/dist/mypackage.tar.gz

Installing collected packages: mypackage
  Running setup.py install for mypackage
    usage: -c [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
       or: -c --help [cmd1 cmd2 ...]
       or: -c --help-commands
       or: -c cmd --help

    error: option --single-version-externally-managed not recognized
    Complete output from command /path/to/.virtualenvs/myvirtualenv/bin/python -c "import setuptools;__file__='/tmp/pip-OFjrqU-build/setup.py';exec(compile(open(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-s4Yo4d-record/install-record.txt --single-version-externally-managed --install-headers /path/to/.virtualenvs/myvirtualenv/include/site/python2.7:
    usage: -c [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
       or: -c --help [cmd1 cmd2 ...]
       or: -c --help-commands
       or: -c cmd --help

error: option --single-version-externally-managed not recognized

----------------------------------------
Command /path/to/.virtualenvs/myvirtualenv/bin/python -c "import setuptools;__file__='/tmp/pip-OFjrqU-build/setup.py';exec(compile(open(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-s4Yo4d-record/install-record.txt --single-version-externally-managed --install-headers /path/to/.virtualenvs/myvirtualenv/include/site/python2.7 failed with error code 1 in /tmp/pip-OFjrqU-build
Storing complete log in /path/to/myhome/.pip/pip.log

What is the best aproach to run a custom task after install a package via pip?

Misshapen answered 6/4, 2013 at 16:12 Comment(2)
Could you try with from setuptools.command.install import install instead of using distutils?Underdog
@Alok, it worked! please answer so I can accept it. :)Misshapen
U
15

Could you try with from setuptools.command.install import install instead of using distutils?

Underdog answered 6/4, 2013 at 16:37 Comment(5)
Thanks, this really helped me out. I had followed (stackoverflow.com/questions/17806485/…) and received the same issue, documented it in (blog.diffbrent.com/…) and gave you propsRaven
I'm getting the same problem as here - I get the custom behaviour when running python setup.py install, but not when I run pip install <path>. Any thoughts?Sequester
I have the same issue. pip install -e . runs the command class and then it runs when I do bdist_wheel but during pip install nothing happens.Gamut
@Sequester did you ever arrive at a solution to this?Jon
I did not, sorry! This was a while ago, so I'd need to ramp back up to re-understand the issue - hopefully one of the other commenters can help you out, though?Sequester
P
1

I update the code to work with the

pip install <path>

as well. In this example, we create a directory structure during installation. All this goes into the setup.py file, followed by $ pip install . This solution also answers this related post: Custom pip install commands not running

from setuptools import setup
from setuptools.command.install import install
import pip
import os, errno

my_dir_paths = ['1', '2', '3']

class CustomInstall(install):

    def __init__(self, dist):
        super(install, self).__init__(dist)
        self.__current  = "/home/..."
        self.__post_install(self.__current)
        
    def run(self):
        install.run(self)
        
    def __post_install(self, curr):
        try:
            os.makedirs(os.path.join(curr, "data2"))
        except FileExistsError:
            print("Directory %s already exists!"%("data2"))
            pass

        for path in my_dir_paths:
            try:
                os.makedirs(os.path.join(curr, "data2", path))
            except FileExistsError:
                print("Directory %s already exists!"%(path))
                pass



setup(
    name='some_name',
    version='0.1.0',
    author='me',
    author_email='...',
    url='http://...',
    packages=setuptools.find_packages(),
    license='...',
    description='....',
    long_description=open('README.txt').read(),
    install_requires=[
       "pandas >= 1.0.5",
    ],
    python_requires='>=3.6',
    
    cmdclass={'install': CustomInstall}
    
)

Purposeless answered 28/9, 2021 at 17:26 Comment(2)
Mind to explain what is dist here? Does it support pip from pypi?Cockleshell
replace dist with *args if that helps (less specific). The setuptools.command.install did not work for me without it.Purposeless

© 2022 - 2024 — McMap. All rights reserved.