1

Most Python packages follow the convention that the version is provided as a string at [package_name].version.version. Let's use Numpy as an example. Say I wanted to import Numpy but ensure that the minimum version is 1.18.1. This is what I do currently:

import numpy as np

if tuple(map(int, np.version.version.split('.'))) < (1, 18, 1):
    raise ImportError('Numpy version too low! Must be >= 1.18.1')

While this seems to work, it requires me to import the package before the version can be checked. It would be nice to not have to import the package if the condition is not satisfied.

It also seems a bit "hacky" and it feels like there's probably a method using the Python standard library that does this. Something like version('numpy') > '1.18.1'. But I haven't been able to find one.

Is there a way to check the version of a package BEFORE importing it within the bounds of the Python standard library?

I am looking for a programmatic solution in Python code. Telling me to use a requirements.txt or pip install is not answering the question.


Edit to add context: Adding this package to my requirements.txt is not useful as the imported package is supposed to be an optional dependency. This code would go in a submodule that is optionally loaded in the __init__.py via a try statement. Essentially, some functionality of the package is only available if a package of minimum version is found and successfully imported.

XYZT
  • 605
  • 5
  • 17
  • 1
    Usually one controls what version of packages they get with a `requirements.txt` file or more recently using python-poetry to manage versions in a project. This does not answer your question about how to handle it in python code though. – Andrew Allaire Oct 09 '20 at 14:52
  • In my case, I am concerned with optional dependencies. So, I can't have the package listed in the `requirements.txt`, but I have submodules in the package that are loaded up if the optional dependency exists. – XYZT Oct 09 '20 at 14:54
  • `pip show package` or `pip list`? I imagine there is an SO Q&A related to your question. – wwii Oct 09 '20 at 14:55
  • It is very obvious from my post that I am looking for a programmatic solution in Python. – XYZT Oct 09 '20 at 14:56
  • Maybe the answer to this question might help https://stackoverflow.com/questions/11887762/how-do-i-compare-version-numbers-in-python – Andrew Allaire Oct 09 '20 at 17:08

2 Answers2

0

Run pip show for a specific package using subprocess then parse the result to compare the installed version to your requirment(s).

>>> import subprocess
>>> result = subprocess.run(['pip', 'show', 'numpy'], stdout=subprocess.PIPE)
>>> result.stdout
b'Name: numpy\r\nVersion: 1.17.4\r\nSummary: NumPy is the fundamental package for array computing with Python.\r\nHome-page: https://www.numpy.org\r\nAuthor: Travis E. Oliphant et al.\r\nAuthor-email: None\r\nLicense: BSD\r\nLocation: c:\\python38\\lib\\site-packages\r\nRequires: \r\nRequired-by: scipy, scikit-learn, perfplot, pandas, opencv-python, matplotlib\r\n'

>>> result = subprocess.run(['pip', 'show', 'pandas'], stdout=subprocess.PIPE)
>>> for thing in result.stdout.splitlines():
...     print(thing)

    
b'Name: pandas'
b'Version: 0.25.3'
b'Summary: Powerful data structures for data analysis, time series, and statistics'
b'Home-page: http://pandas.pydata.org'
b'Author: None'
b'Author-email: None'
b'License: BSD'
b'Location: c:\\python38\\lib\\site-packages'
b'Requires: numpy, python-dateutil, pytz'
b'Required-by: '
>>>

>>> from email.header import Header
>>> result = subprocess.run(['pip', 'show', 'pandas'], stdout=subprocess.PIPE)
>>> h = Header(result.stdout)
>>> print(str(h))
Name: pandas
Version: 0.25.3
Summary: Powerful data structures for data analysis, time series, and statistics
Home-page: http://pandas.pydata.org
Author: None
Author-email: None
License: BSD
Location: c:\python38\lib\site-packages
Requires: python-dateutil, pytz, numpy
Required-by: 

>>> d = {}
>>> for line in result.stdout.decode().splitlines():
...     k,v = line.split(':',1)
...     d[k] = v
    
>>> d['Version']
' 0.25.3'
>>>

Or look at everything:

>>> result = subprocess.run(['pip', 'list'], stdout=subprocess.PIPE)
>>> for thing in result.stdout.splitlines():
    print(thing)

    
b'Package          Version   '
b'---------------- ----------'
b'-illow           6.2.1     '
b'aiohttp          3.6.2     '
b'appdirs          1.4.3     '
...
wwii
  • 23,232
  • 7
  • 37
  • 77
-1

Use containers to control all the dependencies and runtime environment of your program. An easy way to do it would be to create a Docker image that holds the exact version of python that you require. Then use a requirements.txt to install the correct python modules you need with the exact versions.

Lastly, you can create a shell script or something similar to actually spin-up the docker container with one click.

Alternatively (if Docker seems overkill), check out venv

Aziz Sonawalla
  • 2,482
  • 1
  • 5
  • 6
  • It is obvious from my post that I am looking for a programmatic solution in Python. – XYZT Oct 09 '20 at 14:57