I'm trying to audit a Python project with a large number of dependencies and while I can manually look up each project's homepage/license terms, it seems like most OSS packages should already contain the license name and version in their metadata.
Unfortunately I can't find any options in pip or easy_install to list more than the package name and installed version (via pip freeze).
Does anyone have pointers to a tool to list license metadata for Python packages?
pip is a higher-level interface on top of setuptools or Distribute. It uses them to perform many of its functions but avoids some of their more controversial features, like zipped eggs.
Setuptools is a collection of enhancements to the Python distutils that allow developers to more easily build and distribute Python packages, especially ones that have dependencies on other packages. Packages built and distributed using setuptools look to the user like ordinary Python packages based on the distutils .
To do so, we can use the pip list -o or pip list --outdated command, which returns a list of packages with the version currently installed and the latest available. On the other hand, to list out all the packages that are up to date, we can use the pip list -u or pip list --uptodate command.
the setuptools is not part of the python vanilla codebase, hence not a vanilla modules. python.org installers or mac homebrew will install it for you, but if someone compile the python by himself or install it on some linux distribution he may not get it and will need to install it by himself.
Here is a copy-pasteable snippet which will print your packages.
Requires: prettytable (pip install prettytable
)
import pkg_resources import prettytable def get_pkg_license(pkg): try: lines = pkg.get_metadata_lines('METADATA') except: lines = pkg.get_metadata_lines('PKG-INFO') for line in lines: if line.startswith('License:'): return line[9:] return '(Licence not found)' def print_packages_and_licenses(): t = prettytable.PrettyTable(['Package', 'License']) for pkg in sorted(pkg_resources.working_set, key=lambda x: str(x).lower()): t.add_row((str(pkg), get_pkg_license(pkg))) print(t) if __name__ == "__main__": print_packages_and_licenses()
+---------------------------+--------------------------------------------------------------+ | Package | License | +---------------------------+--------------------------------------------------------------+ | appdirs 1.4.3 | MIT | | argon2-cffi 16.3.0 | MIT | | boto3 1.4.4 | Apache License 2.0 | | botocore 1.5.21 | Apache License 2.0 | | cffi 1.10.0 | MIT | | colorama 0.3.9 | BSD | | decorator 4.0.11 | new BSD License | | Django 1.11 | BSD | | django-debug-toolbar 1.7 | BSD | | django-environ 0.4.3 | MIT License | | django-storages 1.5.2 | BSD | | django-uuslug 1.1.8 | BSD | | djangorestframework 3.6.2 | BSD | | docutils 0.13.1 | public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt) | | EasyProcess 0.2.3 | BSD | | ipython 6.0.0 | BSD | | ipython-genutils 0.2.0 | BSD | | jedi 0.10.2 | MIT | | jmespath 0.9.1 | MIT | | packaging 16.8 | BSD or Apache License, Version 2.0 | | pickleshare 0.7.4 | MIT | | pip 9.0.1 | MIT | | prettytable 0.7.2 | BSD (3 clause) | | prompt-toolkit 1.0.14 | UNKNOWN | | psycopg2 2.6.2 | LGPL with exceptions or ZPL | | pycparser 2.17 | BSD | | Pygments 2.2.0 | BSD License | | pyparsing 2.2.0 | MIT License | | python-dateutil 2.6.0 | Simplified BSD | | python-slugify 1.2.4 | MIT | | pytz 2017.2 | MIT | | PyVirtualDisplay 0.2.1 | BSD | | s3transfer 0.1.10 | Apache License 2.0 | | selenium 3.0.2 | UNKNOWN | | setuptools 35.0.2 | UNKNOWN | | simplegeneric 0.8.1 | ZPL 2.1 | | six 1.10.0 | MIT | | sqlparse 0.2.3 | BSD | | traitlets 4.3.2 | BSD | | Unidecode 0.4.20 | GPL | | wcwidth 0.1.7 | MIT | | wheel 0.30.0a0 | MIT | | win-unicode-console 0.5 | MIT | +---------------------------+--------------------------------------------------------------+
You can use pkg_resources
:
import pkg_resources def get_pkg_license(pkgname): """ Given a package reference (as from requirements.txt), return license listed in package metadata. NOTE: This function does no error checking and is for demonstration purposes only. """ pkgs = pkg_resources.require(pkgname) pkg = pkgs[0] for line in pkg.get_metadata_lines('PKG-INFO'): (k, v) = line.split(': ', 1) if k == "License": return v return None
Example use:
>>> get_pkg_license('mercurial') 'GNU GPLv2+' >>> get_pkg_license('pytz') 'MIT' >>> get_pkg_license('django') 'UNKNOWN'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With