Как изящно справиться с неудачной функцией будущего (__future__) импорта из-за старой версии интерпретатора?

Как вы грациозно обрабатываете неудачные будущие функции импорта? Если пользователь работает с Python 2.5, а первый оператор в моем модуле:

from __future__ import print_function

Компиляция этого модуля для Python 2.5 завершится с ошибкой:

  File "__init__.py", line 1
    from __future__ import print_function
SyntaxError: future feature print_function is not defined

Я хочу сообщить пользователю, что им нужно перезапустить программу с помощью Python >= 2.6 и, возможно, предоставить некоторые инструкции о том, как это сделать. Однако, чтобы процитировать PEP 236:

Единственные строки, которые могут появляться до будущее_значение:

  • Модуль docstring (если есть).
  • Комментарии.
  • Пустые строки.
  • Другие future_statements.

Поэтому я не могу сделать что-то вроде:

import __future__

if hasattr(__future__, 'print_function'):
    from __future__ import print_function
else:
    raise ImportError('Python >= 2.6 is required')

Потому что он дает:

  File "__init__.py", line 4
    from __future__ import print_function
SyntaxError: from __future__ imports must occur at the beginning of the file

Этот фрагмент из PEP, похоже, дает надежду сделать это inline:

В: Я хочу свернуть future_statements в try/except blocks, поэтому я могу использовать разные коды, в зависимости от которых версия Python Я бегу. Зачем не могу я?

A: Извините! try/except - это время выполнения особенность; future_statements - прежде всего компиляционные трюки, и ваша попытка/исключается компилятор сделан. То есть, время, которое вы пытаетесь/кроме, семантика в действительности для модуля уже есть сделано сделка. Поскольку try/except не выполнит то, что выглядит как это должно быть, просто не допускается. Мы также хотим сохранить эти специальные заявления очень легко найти и распознать.

Обратите внимание, что вы можете импортировать __future__ напрямую, и используйте информацию в он, наряду с sys.version_info, выяснить, где релиз вы работа под подставками относительно данный статус функции.

Идеи?

Ответ 1

"Я хочу сообщить пользователю, что им нужно перезапустить программу с помощью Python >= 2.6 и, возможно, предоставить некоторые инструкции о том, как это сделать".

Разве это не файл README?

Вот ваша альтернатива. "Обертка": немного капли Python, которая проверяет среду перед запуском целевого aop.

Файл: appwrapper.py

import sys
major, minor, micro, releaselevel, serial = sys.version_info
if (major,minor) <= (2,5):
    # provide advice on getting version 2.6 or higher.
    sys.exit(2)
import app
app.main()

Что означает "прямой импорт". Вы можете просмотреть содержимое __future__. Вы по-прежнему связаны тем фактом, что a from __future__ import print_function является информацией для компилятора, но вы можете выкалывать перед импортом модуля, который выполняет настоящую работу.

import __future__, sys
if hasattr(__future__, 'print_function'): 
    # Could also check sys.version_info >= __future__. print_function.optional
    import app
    app.main()
else:
    print "instructions for upgrading"

Ответ 2

Довольно хакерский, но простой метод, который я использовал ранее, заключается в том, чтобы использовать тот факт, что байтовые литералы были введены в Python 2.6 и используют что-то вроде этого в начале файла:

b'This module needs Python 2.6 or later. Please do xxx.'

Это безвредно для Python 2.6 или новее, но SyntaxError в любых более ранних версиях. Любой, кто пытается скомпилировать ваш файл, все равно получит ошибку, но также получит любое сообщение, которое вы хотите дать.

Вы могли бы подумать, что, поскольку вам придется иметь эту строку после from __future__ import print_function, тогда будет импорт, который генерирует SyntaxError, и вы не увидите полезное сообщение об ошибке, но, как ни странно, ошибка имеет приоритет. Я подозреваю, что, поскольку ошибка импорта не является синтаксической ошибкой сама по себе, она не возникает при первом проходе компиляции, и поэтому реальные ошибки синтаксиса возникают сначала (но я предполагаю).

Это может не соответствовать вашим критериям для того, чтобы быть "изящным", и это очень специфичный для Python 2.6, но это быстро и легко сделать.

Ответ 3

Просто добавьте комментарий к той же строке с помощью "from __future__ import ...", например:

from __future__ import print_function, division  # We require Python 2.6 or later

Так как Python отображает строку, содержащую ошибку, при попытке запустить модуль с Python 2.5 вы получите приятную описательную ошибку:

    from __future__ import print_function, division  # We require Python 2.6 or later
SyntaxError: future feature print_function is not defined