nate barrett
nate barrett

Reputation: 43

have python script check for missing modules and install if missing

I am seeking to make a script I have written more portable.

Several of the tools used in my script require that certain modules be installed. I have been able to have the script install the modules on its own, but would like to have a mechanism that would check if they are already installed and only attempt to install if missing.

I am sure this is possible, but I cannot seem to find a solution.

Upvotes: 4

Views: 5378

Answers (3)

sytech
sytech

Reputation: 40891

Normally, it's not nice to download and install things on behalf of somebody running your script. As triplee's answer mentions, using a requirements.txt and a proper setup.py is a standard and far better practice.

At any rate, the following is a hack to get the behavior you want in a script.

import pip
import importlib
modules = ['requests', 'fake_module_name_that_does_not_exist']
for modname in modules:
    try:
        # try to import the module normally and put it in globals
        globals()[modname] = importlib.import_module(modname)
    except ImportError as e:
        result = pip.main(['install', modname])
        if result != 0: # if pip could not install it reraise the error
            raise
        else:
            # if the install was sucessful, put modname in globals
            globals()[modname] = importlib.import_module(modname)

If you were to execute this example, you would get output something like as follows

Collecting requests
  Using cached requests-2.18.4-py2.py3-none-any.whl
Requirement already satisfied: idna<2.7,>=2.5 in c:\users\spenceryoung\envs\test_venv\lib\site-packages (from requests)
Requirement already satisfied: urllib3<1.23,>=1.21.1 in c:\users\spenceryoung\envs\test_venv\lib\site-packages (from requests)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in c:\users\spenceryoung\envs\test_venv\lib\site-packages (from requests)
Requirement already satisfied: certifi>=2017.4.17 in c:\users\spenceryoung\envs\test_venv\lib\site-packages (from requests)
Installing collected packages: requests
Successfully installed requests-2.18.4
Collecting fake_module_name_that_does_not_exist
  Could not find a version that satisfies the requirement fake_module_name_that_does_not_exist (from versions: )
No matching distribution found for fake_module_name_that_does_not_exist
Traceback (most recent call last):
  File "<stdin>", line 3, in <module>
  File "C:\Users\spenceryoung\AppData\Local\Programs\Python\Python36-32\lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 994, in _gcd_import
  File "<frozen importlib._bootstrap>", line 971, in _find_and_load
  File "<frozen importlib._bootstrap>", line 953, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'fake_module_name_that_does_not_exist'

Upvotes: 2

tripleee
tripleee

Reputation: 189387

The standard solution to this is to make your script into a module, and declare its dependencies in the setup.py of the module.

from setuptools import setup

setup(name='foo',
  ...
  install_requires=['dependency', 'other', ...])

A supporting, weaker convention is to keep a list in requirements.txt so you can

pip install -r requirements.txt

Having your own script do these chores is not usually useful or necessary; the existing packaging infrastructure already provides what you need, and is the natural point to manipulate and manage package dependencies.

Historically, there was some turmoil as different packaging regimes competed for dominance in the Python ecosystem, but things seem to have pretty much settled on setuptools and pip now.

Upvotes: 3

Narendra
Narendra

Reputation: 1529

You can try with this:

import pip
def install(package):
    pip.main(['install', package])

try:
    import your_module
except ImportError:
    print 'Module not installed'
    install('your_module')

Upvotes: 3

Related Questions