getversion¶
Get the version number of any python module or package, reliably.
Do you need a reliable way to get a version number corresponding to a python object ? getversion
was made for this. It combines the best existing strategies to cover the broadest possible set of cases. It is easily extensible so that adding new strategies is extremely easy. Do not hesitate to open an issue or a PR if the current 5 built-in strategies do not work for you!
If you wish to know why "yet another package" is necessary, have a look at the motivation section.
Installing¶
> pip install getversion
Usage¶
a- Already imported¶
from getversion import get_module_version
# Get the version of an imported module
from xml import dom
version, details = get_module_version(dom)
print(version)
yields
3.7.3.final.0
Why was this version found ? You can understand it from the details
:
> print(details)
Version '3.7.3.final.0' found for module 'xml.dom' by strategy 'get_builtin_module_version', after the following failed attempts:
- Attempts for module 'xml.dom':
- <get_module_version_attr>: module 'xml.dom' has no attribute '__version__'
- Attempts for module 'xml':
- <get_module_version_attr>: module 'xml' has no attribute '__version__'
- <get_version_using_pkgresources>: Invalid version number: None
- <get_builtin_module_version>: SUCCESS: 3.7.3.final.0
b- Not yet imported¶
TODO
Motivation¶
Packages, modules, dists¶
In python:
- a module is a file ending with .py
, containing some symbols.
- a package is a folder containing a __init__.py
file, as well as any number of subpackages and submodules.
See also this explanation.
When you distribute python code, you distribute either a single module, or a single package. The name of this "root" module or package is the first name that appears in an import:
import xml # root package 'xml'
import xml.dom # subpackage 'dom' of pkg 'xml'
import xml.dom.minidom # submodule 'minidom' of pkg 'xml.dom'
See distributing python modules.
Why another package ?¶
Version numbers in python can be in very different places depending on the case:
-
for modules and packages, on the optional
__version__
attribute as recommended by PEP396. It should be considered inherited by subpackages and submodules by default if they do not have the attribute. -
for distributed modules and packages, on the
Version
Metadata field as indicated by PEP345, that is located:- for built wheels distributions (PEP427), on the
dist-info
directory, but also in the dist-info folder name - for built eggs distributions (legacy format from setuptools), on the
egg-info
directory, but is also in the egg-info folder name
- for built wheels distributions (PEP427), on the
-
finally, for built-in modules and packages, the default version should be inherited from the python system version except if overridden
In addition to this, at runtime (when you need that version number), packages and modules can be
- already imported or not
- built and pip-installed (in debug mode or not), or simply added to the PYTHON PATH (
sys.path
) - non-built and added to the PYTHON PATH (
sys.path
)
This variety of settings makes it very difficult for existing solutions to tackle all aspects of this problem. pkg_resources
is probably the best way to get it as of today (like this), but does not work for example when a package is an unzipped wheel added to the PYTHON PATH. It also does not support built-in modules.
Main features / benefits¶
- Get module and package version easily: a single method will get you what you need, whatever the variety of ways needed to get the information
- Support for multiple strategies: built-in modules, PEP396/version, setuptools/
pkg_resources
, PEP427/wheel, setuptools/eggs, git...
See Also¶
Concerning the strategies:
- stdlib_list for built-in modules detection
- PEP396/__version__
-
pkg_resources
documentation and PEP365- PEP427/wheel
Discussion on PyPa: here.
Other attempts to reach the same target:
Package versioning best practices¶
If your project uses git, I would recommend the following:
-
in
__init__.py
try: # -- Distribution mode -- # import from _version.py generated by setuptools_scm during release from ._version import version as __version__ except ImportError: # -- Source mode -- # use setuptools_scm to get the current version from src using git from setuptools_scm import get_version as _gv from os import path as _path __version__ = _gv(_path.join(_path.dirname(__file__), _path.pardir))
-
then, EITHER in
setup.py
:setup( ... use_scm_version={'write_to': '%s/_version.py' % <pkgname>} )
-
OR when you wish to create releases, after git-tagging your project and before publishing it, do
from setuptools_scm import get_version get_version('.', write_to='<pkg_name>/_version.py')
for example in your continuous integration engine: python -c "from setuptools_scm import get_version;get_version('.', write_to='<pkg_name>/_version.py')"
Note: the above was inspired by this post and this issue.
Others¶
Do you like this library ? You might also like my other python libraries
Want to contribute ?¶
Details on the github page: https://github.com/smarie/python-getversion