Search code examples
pythonpython-module

Include python module (dependencies) installation in your python script


Is there a way to include/invoke python module(s) (dependencies) installation first, before running the actual/main script?

For example, in my main.py:

import os, sys
import MultipartPostHandler

def main():
    # do stuff here

But MultipartPostHandler is not yet installed, so what I want is to have it installed first before actually running main.py... but in an automated manner. When I say automatically, I mean I will just invoke the script one time to start the dependency installation, then to be followed by actual functionalities of the main script. (somehow, a little bit similar with maven. But I just need the installation part)

I already know the basics of setuptools. The problem is I may have to call the installation (setup.py) and the main script (main.py) separately.

Any ideas are greatly appreciated. Thanks in advance!


Solution

  • Is there a way to include/invoke python module(s) (dependencies) installation first, before running the actual/main script?

    • A good way is to use setuptools and explicitly list them in install_requires.
    • Since you are providing a main function, you also probably want to provide entry_points.

    I already know the basics of setuptools. The problem is I may have to call the installation (setup.py) and the main script (main.py) separately.

    That is usually not a problem. It is very common to first install everything with a requirements.txt file and pip install -r requirements.txt. Plus if you list dependencies you can then have reasonable expectations that it will be there when your function is called and not rely on try/except ImporError. It is a reasonable approach to expect required dependencies to be present and only use try/except for optional dependencies.

    setuptools 101:

    create a tree structure like this:

    $ tree
    .
    ├── mymodule
    │   ├── __init__.py
    │   └── script.py
    └── setup.py
    

    your code will go under mymodule; let's imagine some code that does a simple task:

    # module/script.py    
    
    def main():
        try:
            import requests
            print 'requests is present. kudos!'
        except ImportError:
            raise RuntimeError('how the heck did you install this?')
    

    and here is a relevant setup:

    # setup.py
    
    from setuptools import setup
    setup(
        name='mymodule',
        packages=['mymodule'],
        entry_points={
            'console_scripts' : [
                'mycommand = mymodule.script:main',
            ]
        },
        install_requires=[
            'requests',
        ]
    )
    

    This would make your main available as a command, and this would also take care of installing the dependencies you need (e.g requests)

    ~tmp damien$ virtualenv test && source test/bin/activate && pip install mymodule/
    New python executable in test/bin/python
    Installing setuptools, pip...done.
    Unpacking ./mymodule
      Running setup.py (path:/var/folders/cs/nw44s66532x_rdln_cjbkmpm000lk_/T/pip-9uKQFC-build/setup.py) egg_info for package from file:///tmp/mymodule
    
    Downloading/unpacking requests (from mymodule==0.0.0)
      Using download cache from /Users/damien/.pip_download_cache/https%3A%2F%2Fpypi.python.org%2Fpackages%2F2.7%2Fr%2Frequests%2Frequests-2.4.1-py2.py3-none-any.whl
    Installing collected packages: requests, mymodule
      Running setup.py install for mymodule
    
        Installing mycommand script to /tmp/test/bin
    Successfully installed requests mymodule
    Cleaning up...
    (test)~tmp damien$ mycommand 
    requests is present. kudos!
    

    more useful commands with argparse:

    If you want to use argparse then...

    # module/script.py
    
    import argparse
    
    def foobar(args):
        # ...
    
    def main():
        parser = argparse.ArgumentParser()
        # parser.add_argument(...)
        args = parser.parse_args()
        foobar(args)