Как я могу проверить версию Python в программе, использующей новые языковые функции?

Если у меня есть Python script, который требует, по крайней мере, определенного версия Python, каков правильный способ неудачного изложения когда более ранняя версия Python используется для запуска script?

Как мне получить контроль на достаточно раннем этапе, чтобы выпустить сообщение об ошибке и выйти?

Например, у меня есть программа, которая использует оператор ternery (новый в 2.5) и "с" блоками (новый в 2.6). Я написал простую небольшую интерпретационную версию который является первым, что script звоните... кроме того, что это не так далеко. Вместо этого script сбой во время компиляции python, перед моими подпрограммами даже называются. Таким образом, пользователь script видит очень скрытые ошибки отслеживания синаксии - которые в значительной степени требуют эксперт, чтобы вывести, что это просто случай запуска неправильная версия Python.

Я знаю, как проверить версию Python. Проблема в том, что некоторый синтаксис является незаконным в более старых версиях Python. Рассмотрим эту программу:

import sys
if sys.version_info < (2, 4):
    raise "must use python 2.5 or greater"
else:
    # syntax error in 2.4, ok in 2.5
    x = 1 if True else 2
    print x

При запуске под 2.4 я хочу получить этот результат

$ ~/bin/python2.4 tern.py 
must use python 2.5 or greater

а не этот результат:

$ ~/bin/python2.4 tern.py 
  File "tern.py", line 5
    x = 1 if True else 2
           ^
SyntaxError: invalid syntax

(Канал для сотрудника.)

Ответы

Ответ 1

Вы можете протестировать с помощью eval:

try:
  eval("1 if True else 2")
except SyntaxError:
  # doesn't have ternary

Кроме того, with доступен в Python 2.5, просто добавьте from __future__ import with_statement.

EDIT: чтобы получить управление достаточно рано, вы можете разбить его на разные файлы .py и проверить совместимость в основном файле перед импортом (например, в __init__.py в пакете):

# __init__.py

# Check compatibility
try:
  eval("1 if True else 2")
except SyntaxError:
  raise ImportError("requires ternary support")

# import from another module
from impl import *

Ответ 2

У вас есть обертка вокруг вашей программы, которая делает следующее.

import sys

req_version = (2,5)
cur_version = sys.version_info

if cur_version >= req_version:
   import myApp
   myApp.run()
else:
   print "Your Python interpreter is too old. Please consider upgrading."

Вы также можете рассмотреть возможность использования sys.version(), если вы планируете столкнуться с людьми, которые используют интерпретаторы Python до 2.0, но тогда у вас есть регулярные выражения.

И может быть более элегантный способ сделать это.

Ответ 3

Попробуйте

import platform
platform.python_version()

Должна дать вам строку типа "2.3.1". Если это не так, вы хотите получить богатый набор данных, доступных через встроенную платформу. То, что вы хотите, должно быть где-то там.

Ответ 4

Вероятно, лучший способ сделать это сравнение версий - использовать sys.hexversion. Это важно, потому что сравнение кортежей версий не даст вам желаемого результата во всех версиях python.

import sys
if sys.hexversion < 0x02060000:
    print "yep!"
else:
    print "oops!"

Ответ 5

import sys    
# prints whether python is version 3 or not
python_version = sys.version_info.major
if python_version == 3:
    print("is python 3")
else:
    print("not python 3")

Ответ 6

Ответ от Nykakin в AskUbuntu:

Вы также можете проверить версию Python из самого кода, используя модуль platform из стандартной библиотеки.

Есть две функции:

  • platform.python_version() (возвращает строку).
  • platform.python_version_tuple() (возвращает кортеж).

Код Python

Создайте файл, например: version.py)

Простой способ проверить версию:

import platform

print(platform.python_version())
print(platform.python_version_tuple())

Вы также можете использовать метод eval:

try:
  eval("1 if True else 2")
except SyntaxError:
  raise ImportError("requires ternary support")

Запустите файл Python из командной строки:

$ python version.py 
2.7.11
('2', '7', '11')

Вывод Python с CGI через сервер WAMP в Windows 10:

Screenshot 2016-11-16 14.39.01 by Suriyaa Kudo


Полезные ресурсы

Ответ 7

Наборы стали частью основного языка в Python 2.4, чтобы оставаться обратно совместимыми. Я сделал это тогда, и это сработает и для вас:

if sys.version_info < (2, 4):
    from sets import Set as set

Ответ 8

Хотя вопрос таков: как получить контроль достаточно рано, чтобы выдать сообщение об ошибке и выйти?

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

Я могу ответить на это по-другому, чем другие посты. Кажется, ответы до сих пор пытаются решить ваш вопрос изнутри Python.

Я говорю, сделайте проверку версии перед запуском Python. Я вижу, ваш путь - Linux или Unix. Однако я могу предложить вам только сценарий Windows. Я представляю, что адаптировать его к синтаксису сценариев Linux не будет слишком сложно.

Вот сценарий DOS с версией 2.7:

@ECHO OFF
REM see http://ss64.com/nt/for_f.html
FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul
IF NOT ErrorLevel 1 GOTO Python27
ECHO must use python2.7 or greater
GOTO EOF
:Python27
python.exe tern.py
GOTO EOF
:EOF

Это не запускает какую-либо часть вашего приложения и, следовательно, не вызовет исключение Python. Он не создает временный файл и не добавляет никаких переменных среды ОС. И это не заканчивает ваше приложение исключением из-за различных правил синтаксиса версий. Это три менее возможных точки безопасности доступа.

Линия FOR/F - это ключ.

FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul

Для нескольких версий Python проверьте URL: http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17

И моя версия взлома:

[MS скрипт; Проверка версии Python перед запуском модуля Python] http://pastebin.com/aAuJ91FQ

Ответ 9

import sys
sys.version

будет получать ответ вроде этого

'2.7.6 (по умолчанию, 26 октября 2016, 20:30:19)\n [GCC 4.8.4]'

здесь 2.7.6 - версия

Ответ 10

Как отмечалось выше, ошибки синтаксиса возникают во время компиляции, а не во время выполнения. Хотя Python является "интерпретируемым языком", код Python фактически не интерпретируется напрямую; он скомпилирован в байтовый код, который затем интерпретируется. Существует этап компиляции, который выполняется, когда модуль импортируется (если нет уже скомпилированной версии, доступной в виде файла .pyc или .pyd), и когда вы получаете свою ошибку, не (совершенно точно), когда ваш код работает.

Вы можете отложить шаг компиляции и сделать это во время выполнения для отдельной строки кода, если хотите, используя eval, как указано выше, но я лично предпочитаю избегать этого, потому что это вызывает Python для выполнения потенциально ненужной компиляции во время выполнения, во-первых, и для другого, он создает то, что для меня похоже на беспорядок кода. (Если вы хотите, вы можете сгенерировать код, который генерирует код, который генерирует код, - и у вас есть абсолютно потрясающее время для изменения и отладки, которое через 6 месяцев.) Так что я бы рекомендовал вместо этого - это нечто большее:

import sys
if sys.hexversion < 0x02060000:
    from my_module_2_5 import thisFunc, thatFunc, theOtherFunc
else:
    from my_module import thisFunc, thatFunc, theOtherFunc

.., который я бы сделал, даже если бы у меня была только одна функция, которая использовала новый синтаксис, и она была очень короткой. (На самом деле я бы принял все разумные меры, чтобы свести к минимуму количество и размер таких функций. Я мог бы даже написать такую ​​функцию, как ifTrueAElseB (cond, a, b) с этой единственной строкой синтаксиса.)

Еще одна вещь, которая может быть стоит отметить (что я немного удивлен, никто еще не указал), что, хотя более ранние версии Python не поддерживали такой код, как

value = 'yes' if MyVarIsTrue else 'no'

.. он поддерживал код вроде

value = MyVarIsTrue and 'yes' or 'no'

Это был старый способ написания тернарных выражений. У меня еще нет Python 3, но, насколько я знаю, этот "старый" способ по-прежнему работает по сей день, поэтому вы можете сами решить, стоит ли ему условно использовать новый синтаксис, если вам нужно для поддержки использования более старых версий Python.

Ответ 11

Поместите следующее в самый верх файла:

import sys

if float(sys.version.split()[0][:3]) < 2.7:
    print "Python 2.7 or higher required to run this code, " + sys.version.split()[0] + " detected, exiting."
    exit(1)

Затем продолжайте с нормальным кодом Python:

import ...
import ...
other code...

Ответ 12

Я думаю, что лучший способ - проверить функциональность, а не версии. В некоторых случаях это тривиально, а не в других.

например:

try :
    # Do stuff
except : # Features weren't found.
    # Do stuff for older versions.

До тех пор, пока вы достаточно подробно используете блоки try/except, вы можете охватить большинство своих баз.

Ответ 13

Я просто нашел этот вопрос после быстрого поиска, пытаясь решить проблему самостоятельно, и я придумал гибрид, основанный на нескольких приведенных выше предложениях.

Мне нравится идея DevPlayer об использовании обертки script, но недостатком является то, что вы в конечном итоге поддерживаете несколько оболочек для разных ОС, поэтому я решил написать оболочку в python, но использовать тот же базовый "захватить версию управляя exe-логикой и придумал это.

Я думаю, что он должен работать в течение 2,5 и более лет. Я тестировал его на 2.66, 2.7.0 и 3.1.2 на Linux и 2.6.1 на OS X до сих пор.

import sys, subprocess
args = [sys.executable,"--version"]

output, error = subprocess.Popen(args ,stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()
print("The version is: '%s'"  %error.decode(sys.stdout.encoding).strip("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLMNBVCXZ,.+ \n") )

Да, я знаю, что окончательная строка декодирования/полосы ужасна, но я просто хотел быстро захватить номер версии. Я собираюсь уточнить это.

Теперь это достаточно хорошо для меня, но если кто-то может его улучшить (или сказать мне, почему это ужасная идея), это тоже будет круто.

Ответ 14

Для автономных сценариев Python работает следующий трюк docstring модуля для обеспечения исполнения версии Python (здесь v2.7.x) (протестировано на * nix).

#!/bin/sh
''''python -V 2>&1 | grep -q 2.7 && exec python -u -- "$0" ${1+"[email protected]"}; echo "python 2.7.x missing"; exit 1 # '''

import sys
[...]

Это должно обрабатывать и отсутствующий исполняемый файл Python, но зависит от grep. Смотрите здесь для фона.

Ответ 15

Вы можете проверить с помощью sys.hexversion или sys.version_info.

sys.hexversion не очень sys.hexversion человека, потому что это шестнадцатеричное число. sys.version_info - это кортеж, поэтому он более дружественный для человека.

Проверьте для Python 3.6 или новее с sys.hexversion:

import sys, time
if sys.hexversion < 0x30600F0:
    print("You need Python 3.6 or greater.")
    for _ in range(1, 5): time.sleep(1)
    exit()

Проверьте для Python 3.6 или новее с sys.version_info:

import sys, time
if sys.version_info[0] < 3 and sys.version_info[1] < 6:
    print("You need Python 3.6 or greater.")
    for _ in range(1, 5): time.sleep(1)
    exit()

sys.version_info более дружественен к человеку, но требует больше символов. Я бы sys.hexversion, хотя он менее дружественный для человека.

Я надеюсь, что это помогло вам!

Ответ 16

Я расширяю акханский отличный ответ, который выводит полезное сообщение еще до компиляции скрипта Python.

Если вы хотите убедиться, что скрипт запускается с Python 3.6 или новее, добавьте эти две строки в начало вашего скрипта Python:

#!/bin/sh
''''python3 -c 'import sys; sys.exit(sys.version_info < (3, 6))' && exec python3 -u -- "$0" ${1+"[email protected]"}; echo 'This script requires Python 3.6 or newer.'; exit 1 # '''

(Примечание. Вторая строка начинается с четырех одинарных кавычек и заканчивается тремя одинарными кавычками. Это может показаться странным, но это не опечатка.)

Преимущество этого решения состоит в том, что код наподобие print(f'Hello, {name}!') Не вызовет SyntaxError если используется версия Python старше 3.6. Вместо этого вы увидите это полезное сообщение:

This script requires Python 3.6 or newer.

Конечно, это решение работает только на Unix-подобных оболочках и только тогда, когда скрипт вызывается напрямую (например: ./script.py), и с установленными битами разрешений eXecute.

Ответ 17

Вот быстрый и простой способ убедиться, что python script завершит работу, если вы не соответствуете требованиям к версии, чтобы запустить script

# Check python version
import sys

if sys.version_info < ( 3, 2):
    # python too old, kill the script
    sys.exit("This script requires Python 3.2 or newer!")

# This part will only run if the version check passes
print("Yay, this Python works!")

Вы также можете использовать этот метод для загрузки перекрестно-совместимых библиотек для вашего script. Сделайте одну вещь для одной версии python, другую для другой и т.д. Предел - ваше воображение.

Ответ 18

Как насчет этого:

import sys

def testPyVer(reqver):
  if float(sys.version[:3]) >= reqver:
    return 1
  else:
    return 0

#blah blah blah, more code

if testPyVer(3.0) == 1:
  #do stuff
else:
  #print python requirement, exit statement

Ответ 19

Проблема довольно проста. Вы проверили, была ли версия меньше 2.4, не менее или равна. Поэтому, если версия Python равна 2,4, она не менее 2,4. То, что вам нужно было:

    if sys.version_info **<=** (2, 4):

не

    if sys.version_info < (2, 4):