2013-09-30 1 views
23

Я пытаюсь выполнить аудит проекта Python с большим количеством зависимостей, и, хотя я могу вручную просмотреть домашнюю страницу/условия лицензии каждого проекта, похоже, что большинство пакетов OSS уже должны содержать имя и версию лицензии в своих метаданных.Может ли pip (или setuptools, распространять и т. Д.) Отображать лицензию, используемую каждым установленным пакетом?

К сожалению, я не могу найти какие-либо опции в pip или easy_install, чтобы перечислить больше, чем имя пакета и установленную версию (через замораживание контура).

У кого-нибудь есть указатели на инструмент для отображения метаданных лицензии для пакетов Python?

ответ

17

Вы можете использовать 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' 
+2

Это прекрасно работает! Оказывается, что pkg_resources.working_set также является итерабельным, что полезно для моей ситуации (перечисление всех лицензий сразу). –

+0

Вы можете использовать встроенный пакет 'mail' для анализа содержимого PKG-INFO, который немного более надежный чем использование разделения на двоеточие.Сначала 'import email.parser', затем настройте' parser = email.parser.HeaderParser() ', а затем' pkg_info = parser.parsestr ('\ n'.join (package.get_metadata_lines (' PKG-INFO '))) ', который дает вам сообщение, из которого вы можете получить' pkg_info ['License'] '. – clj

+4

Отлично работает, заменяя 'PKG-INFO' на' METADATA' и обнаруживая некоторые ошибки здесь и там. – Adversus

14

Вот способ сделать это с помощью инструмента yolk3k (командной строки для выполнения запросов PyPi и Python пакеты, установленные в вашей системе .)

pip install yolk3k 

yolk -l -f license 
#-l lists all installed packages 
#-f Show specific metadata fields (In this case, License) 
+4

Не похоже, что этот проект поддерживается больше. Вот развитая развилка: https://pypi.python.org/pypi/yolk3k – sfridman

1

Я нашел несколько идей от answ ERS и комментарии по данному вопросу, чтобы быть актуальными и написали короткий скрипт для генерации информации о лицензии для соответствующего 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()))]) 
3

С пипом:

pip show django | grep License

Если вы хотите получить PyPi классификатор для лицензии, используйте подробный вариант:

pip show -v django | grep 'License ::'

1

Based на ответ, предоставленной @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()) 
4

Вот копия-pasteable фрагмент кода, который будет печатать пакеты.

Требуется: 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        | 
+---------------------------+--------------------------------------------------------------+ 
0

Другой вариант заключается в использовании Python Package License Checker Брайан Дэйли в.

git clone https://github.com/briandailey/python-packages-license-check.git 
cd python-packages-license-check 
... activate your chosen virtualenv ... 
./check.py 
0

Ответ не работал для меня, многие из этих генерируемых библиотек исключений.

Так сделал немного грубой силы

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