Может типун (или setuptools, распространять и т. д.) перечень лицензий, используемых каждого установленного пакета?
Я пытаюсь провести аудит проекта Python с большим количеством зависимостей, и хотя я могу вручную просмотреть домашнюю страницу каждого проекта/условия лицензии, похоже, что большинство пакетов OSS уже должны содержать имя лицензии и версию в своих метаданных.
К сожалению, я не могу найти никаких параметров в pip или easy_install, чтобы перечислить больше, чем имя пакета и установленную версию (через pip freeze).
Есть ли у кого-нибудь указатели на инструмент для перечисления метаданных лицензии для Python пакеты?
9 ответов:
Вы можете использовать
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
Пример использования:
>>> get_pkg_license('mercurial') 'GNU GPLv2+' >>> get_pkg_license('pytz') 'MIT' >>> get_pkg_license('django') 'UNKNOWN'
Вот способ сделать это с помощью yolk3k (инструмент командной строки для запроса пакетов PyPI и Python, установленных в вашей системе.)
pip install yolk3k yolk -l -f license #-l lists all installed packages #-f Show specific metadata fields (In this case, License)
Вот фрагмент с возможностью копирования и вставки, который будет печатать ваши пакеты.
Требуется: 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 | +---------------------------+--------------------------------------------------------------+
С Пипом:
pip show django | grep License
Если вы хотите получить классификатор PyPI для лицензии, используйте опцию verbose:
pip show -v django | grep 'License ::'
1. Выбор
Pip-лицензии пакет PyPI.
2. Релевантность
Этот ответ актуален для марта 2018 года. В будущем данные этого ответа могут устареть.
3. Аргументация
- просто установка -
pip install pip-licenses
,- больше возможностей и опций, чем желток3к,
- активный поддерживается.
4. Демонстрация
Пример вывода:
D:\KristinitaPelican>pipenv run pip-licenses --with-system --order=license --format-markdown | Name | Version | License | |---------------------|-----------|--------------------------------------------------------------| | requests | 2.18.4 | Apache 2.0 | | actdiag | 0.5.4 | Apache License 2.0 | | blockdiag | 1.5.3 | Apache License 2.0 | | nwdiag | 1.0.4 | Apache License 2.0 | | seqdiag | 0.9.5 | Apache License 2.0 | | Jinja2 | 2.10 | BSD | | MarkupSafe | 1.0 | BSD | | license-info | 0.8.7 | BSD | | pip-review | 1.0 | BSD | | pylicense | 1 | BSD | | PTable | 0.9.2 | BSD (3 clause) | | webcolors | 1.8.1 | BSD 3-Clause | | Markdown | 2.6.11 | BSD License | | Pygments | 2.2.0 | BSD License | | yolk3k | 0.9 | BSD License | | packaging | 17.1 | BSD or Apache License, Version 2.0 | | idna | 2.6 | BSD-like | | markdown-newtab | 0.2.0 | CC0 | | pyembed | 1.3.3 | Copyright © 2013 Matt Thomson | | pyembed-markdown | 1.1.0 | Copyright © 2013 Matt Thomson | | python-dateutil | 2.7.2 | Dual License | | Unidecode | 1.0.22 | GPL | | chardet | 3.0.4 | LGPL | | beautifulsoup4 | 4.6.0 | MIT | | funcparserlib | 0.3.6 | MIT | | gevent | 1.2.2 | MIT | | markdown-blockdiag | 0.7.0 | MIT | | pip | 9.0.1 | MIT | | pkgtools | 0.7.3 | MIT | | pytz | 2018.3 | MIT | | six | 1.11.0 | MIT | | urllib3 | 1.22 | MIT | | wheel | 0.30.0 | MIT | | blinker | 1.4 | MIT License | | greenlet | 0.4.13 | MIT License | | pip-licenses | 1.7.0 | MIT License | | pymdown-extensions | 4.9.2 | MIT License | | pyparsing | 2.2.0 | MIT License | | certifi | 2018.1.18 | MPL-2.0 | | markdown-downheader | 1.1.0 | Simplified BSD License | | Pillow | 5.0.0 | Standard PIL License | | feedgenerator | 1.9 | UNKNOWN | | license-lister | 0.1.1 | UNKNOWN | | md-environ | 0.1.0 | UNKNOWN | | mdx-cite | 1.0 | UNKNOWN | | mdx-customspanclass | 1.1.1 | UNKNOWN | | pelican | 3.7.1 | UNKNOWN | | setuptools | 38.5.1 | UNKNOWN | | docutils | 0.14 | public domain, Python, 2-Clause BSD, GPL 3 (see COPYING.txt) |
[2]}5. Внешний Ссылка
Я нашел несколько идей из ответов и комментариев к этому вопросу, чтобы быть релевантным и написал короткий сценарий для генерации информации о лицензии для применимого virtualenv:
import pkg_resources import copy def get_packages_info(): KEY_MAP = { "Name": 'name', "Version": 'version', "License": 'license', } empty_info = {} for key, name in KEY_MAP.iteritems(): empty_info[name] = "" packages = pkg_resources.working_set.by_key infos = [] for pkg_name, pkg in packages.iteritems(): info = copy.deepcopy(empty_info) try: lines = pkg.get_metadata_lines('METADATA') except (KeyError, IOError): lines = pkg.get_metadata_lines('PKG-INFO') for line in lines: try: key, value = line.split(': ', 1) if KEY_MAP.has_key(key): info[KEY_MAP[key]] = value except ValueError: pass infos += [info] return "name,version,license\n%s" % "\n".join(['"%s","%s","%s"' % (info['name'], info['version'], info['license']) for info in sorted(infos, key=(lambda item: item['name'].lower()))])
Основываясь на ответе, предоставленном @garromark и настроенном для Python 3, я использую это в командной строке:
import pkg_resources import copy def get_packages_info(): KEY_MAP = { "Name": 'name', "Version": 'version', "License": 'license', } empty_info = {} for key, name in KEY_MAP.items(): empty_info[name] = "" packages = pkg_resources.working_set.by_key infos = [] for pkg_name, pkg in packages.items(): info = copy.deepcopy(empty_info) try: lines = pkg.get_metadata_lines('METADATA') except (KeyError, IOError): lines = pkg.get_metadata_lines('PKG-INFO') for line in lines: try: key, value = line.split(': ', 1) if key in KEY_MAP: info[KEY_MAP[key]] = value except ValueError: pass infos += [info] return "name,version,license\n%s" % "\n".join(['"%s","%s","%s"' % (info['name'], info['version'], info['license']) for info in sorted(infos, key=(lambda item: item['name'].lower()))]) print(get_packages_info())
Ответ не сработал для меня многие из этих библиотек генерировали исключение.
Так же поступила и небольшая грубая сила
def get_pkg_license_use_show(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. """ out = subprocess.check_output(["pip", 'show', pkgname]) pattern = re.compile(r"License: (.*)") license_line = [i for i in out.split("\n") if i.startswith('License')] match = pattern.match(license_line[0]) license = match.group(1) return license