Что делать, если нужный вам модуль поддерживает только Python 2: пошаговое руководство

python

Рассказывает Энтони Шоу


Перед вами небольшая инструкция по решению довольно распространенной проблемы: при работе над проектом оказывается, что один из необходимых вам модулей не поддерживает Python 3. Для примера взята клиентская библиотека для Qualys (средство обеспечения безопасности). Вот что вам следует сделать:

0. Удостовериться, что этот вопрос еще не решен

Прежде чем начать, проверьте, не сталкивался ли кто-то ранее с такой же проблемой, исследуйте GitHub. Посмотрите — может быть, на PyPi найдется подходящий пакет, в котором содержатся обновления для Python 3.

1. Сделать форк

Если поиски все же ни к чему не привели, приступайте к изменению выбранного модуля. Стоит заметить, что обычно на PyPi указываются поддерживаемые версии Python. У модулей, работающих только с Python 2, данная информация часто бывает опущена. В рассматриваемом примере эта часть описания модуля выглядит следующим образом:

python

Итак, откройте основной проект на GitHub. Прежде чем вносить любые изменения, обязательно создайте его форк, затем скачайте или клонируйте репозиторий и создайте новую ветку. Говорящим названием для неё будет, например, «python3».

python

Если вам неясно, как проделать эти действия, читайте наше руководство по Git для новичков.

2. Исправить операторы print

Первое, с чем нужно разобраться до решения проблем с импортированием — это самые обычные операторы вывода. Старые операторы print без скобок — одно из самых распространенных препятствий, с которым можно столкнуться в контексте перехода от Python 2 к Python 3. В третьем шаге мы будем использовать пакет Python-Modernize, облегчающий этот переход, но его работа не затронет README, документацию и некоторые другие файлы. Чтобы найти абсолютно все старые операторы print в пределах модуля, воспользуйтесь рекурсивным поиском по вложенным директориям:

fgrep -r "print " .

 

Вы увидите, что некоторые из выведенных на экран соответствий находятся в директории git, игнорируйте их. Все остальные найденные операторы print замените на функции print() в любом текстовом редакторе, а после создайте из исправлений единый коммит командой:

git commit -a -m "print to python 3"

 

3. Провести тесты

«Лучший» способ проверить совместимость Python 2 и 3 — через полное тестирование и CI сервисы вроде Circle, Snap или Travis. Но вот незадача — для модернизируемого вами модуля никаких тестов нет. И у вас остается два варианта:

  • написать тесты самому;
  • провести статический анализ кода.

Если вы сомневаетесь, что второй вариант может вам чем-то помочь, прочитайте нашу статью о статическом анализаторе.

Статический анализ. Установите Python-Modernize:

pip install modernize

 

Сначала запустите его в режиме info:

python-modernize qualysapi

 

Это позволит получить общее представление о том, какие изменения будут внесены. Все устраивает? Тогда запускайте процесс изменений следующей командой:

python-modernize -wn qualysapi

 

Затем сделайте из них отдельный коммит.

Добавление тестов. Первая проверка: можно ли импортировать модуль, пакет, подмодуль? Этот тест вскрывает много проблем в Python 3, связанных с пространствами имен. Используйте Tox для проведения тестирования в различном окружении.

Вторая проверка: есть ли в проекте обработка строк. На тему строк в Python 3 информации гораздо больше, чем можно уместить в этом посте, но вы можете обратиться к проекту six, в котором рассматривается проблема определения, является ли объект строкой, а также использование юникода и методов байтовой конвертации.

Третья проверка подразумевает наличие некоторого опыта в работе с модулем. Вы не сможете сразу заняться юнит-тестированием на основе существующей кодовой базы, если не будете понимать, насколько корректно она работает на данный момент. Двигайтесь в обратном направлении — сфокусируйтесь на интеграционном тестировании, а от него перейдите к юнит-тестам. Попробуйте для начала написать простой скрипт, который использует модуль по его прямому назначению, а затем дополняйте его другими сценариями использования. Если вы уже настроились пропустить данную проверку, почитайте наш материал о пользе юнит-тестирования.

4. Обновить setup.py

Откройте setup.py и посмотрите, какие изменения в него нужно внести, чтобы уверенно заявлять, что рассматриваемый нами модуль теперь поддерживает Python 3:

setup(name=__pkgname__,
      version=__version__,
      author='Parag Baxi',
      author_email='parag.baxi@gmail.com',
      description='QualysGuard(R) Qualys API Package',
      license ='BSD-new',
      keywords ='Qualys QualysGuard API helper network security',
      url='https://github.com/paragbaxi/qualysapi',
      package_dir={'': '.'},
      packages=['qualysapi',],
      # package_data={'qualysapi':['LICENSE']},
      # scripts=['src/scripts/qhostinfo.py', 'src/scripts/qscanhist.py', 'src/scripts/qreports.py'],
      long_description=read('README.md'),
      classifiers=[
          'Development Status :: 5 - Production/Stable',
          'Topic :: Utilities',
          'License :: OSI Approved :: Apache Software License',
          'Intended Audience :: Developers',
      ],
      install_requires=[
          'requests',
      ],
     )

 

На что точно стоит обратить внимание:

  1. В коде выше обнаружилось как указание лицензии BSD, так и лицензии Apache 2. При этом в кодовых файлах говорится Apache 2, а в директории вообще нет файла LICENSE. Такая ситуация могла возникнуть из-за ошибки, связанной с копипастом, поэтому в данном случае её логично исправить в setup.py, а потом добавить соответствующий файл LICENSE.
  2. Разметка в PyPi не отображается. Можно с этим смириться, можно добавить RST файл. Главное, помните о том, что это все же не ваш проект.
  3. Не написано, какую версию Python поддерживает модуль. Добавьте эту информацию в setup.py.
  4. Использование Python-Modernize означает, что данный модуль зависим от пакета six. Отметьте это в поле install_requires. А заодно проверьте, что все указанные там пакеты, от которых зависит изменяемый модуль, тоже поддерживают Python 3.

Посмотрим, что получилось:

setup(name=__pkgname__,
      version=__version__,
      author='Parag Baxi',
      author_email='parag.baxi@gmail.com',
      description='QualysGuard(R) Qualys API Package',
      license="Apache License (2.0)",
      keywords ='Qualys QualysGuard API helper network security',
      url='https://github.com/paragbaxi/qualysapi',
      package_dir={'': '.'},
      packages=['qualysapi',],
      # package_data={'qualysapi':['LICENSE']},
      # scripts=['src/scripts/qhostinfo.py', 'src/scripts/qscanhist.py', 'src/scripts/qreports.py'],
      long_description=read('README.md'),
      classifiers=[
          'Development Status :: 5 - Production/Stable',
          'Topic :: Utilities',
          'License :: OSI Approved :: Apache Software License',
          'Intended Audience :: Developers',
          'Programming Language :: Python :: 2',
          'Programming Language :: Python :: 3'
      ],
      install_requires=[
          'requests', 'six'
      ],
     )

 

5. Загрузить в основной проект

Вернемся к началу. При работе над вашим проектом вы столкнулись с тем, что один из модулей не поддерживает Python 3. Вы избавились от проблем совместимости, теперь нужно указать обновленную версию модуля в файле requirements.txt. Убедитесь в том, что вы сначала запушили изменения на GitHub. Это делается командой:

git push origin python3

Pip позволяет вам устанавливать необходимое не только из PyPi, но и прямо из репозитория Git. Вы можете указать конкретную ветку, используя символ @. Параметр egg= используется, чтобы передать Pip имя пакета.

pip -e git+https://github.com/tonybaloney/qualysapi@python3#egg=qualysapi

 

На этом этапе можно продолжить запуск интеграционных тестов для новой версии.

6. Отправить пулл реквест

Теперь нужно поделиться своей работой с автором и сообществом Python на GitHub. Придерживайтесь следующих правил общения:

  1. Будьте вежливы.
  2. Поясните, что хотели бы использовать этот модуль с Python 3.
  3. Поблагодарите автора за его работу по созданию модуля.
  4. Прокомментируйте, что сделали.

Вот такой пулл реквест получился по итогам рассмотренного примера. Подождите, пока ваши изменения зальют в проект, после чего ожидайте, когда на PyPi появится обновление. (Вернее, надейтесь, что оно там появится.)

7. Наконец, три месяца спустя…

…автор пакета не залил ваш код. Такое случается. Обычно это происходит, когда человек поддерживал проект, пока использовал его в рамках своей рабочей деятельности, а потом сменил место работы. Вернитесь к setup.py и задайте модулю новое имя (не изменяя поле packages), по типу «qualysapi-py3». Сделайте пуш в PyPi, а потом обновите сообщение в вашем пулл реквесте, указав это новое имя. Теперь, когда кто-то еще будет искать помощь по Python 3 для использования данного модуля, он увидит ваш пост.

Перевод статьи «Oh no! This package is Python 2 only»