¿Cómo puedo verificar la versión de Python en un progtwig que usa nuevas características de idioma?

Si tengo un script de Python que requiere al menos una versión particular de Python, ¿cuál es la forma correcta de fallar con gracia cuando se usa una versión anterior de Python para iniciar el script?

¿Cómo obtengo el control lo suficientemente temprano para emitir un mensaje de error y salir?

Por ejemplo, tengo un progtwig que usa el operador ternery (nuevo en 2.5) y bloques “con” (nuevo en 2.6). Escribí una pequeña rutina simple de revisión de la versión del intérprete, que es lo primero que llamaría el script … excepto que no llega tan lejos. En cambio, la secuencia de comandos falla durante la comstackción de Python, antes de que incluso se llame a mis rutinas. Por lo tanto, el usuario de la secuencia de comandos ve algunas trazas de error de synax muy oscuras, que casi requieren que un experto deduzca que es simplemente el caso de ejecutar la versión incorrecta de Python.

Sé cómo comprobar la versión de Python. El problema es que alguna syntax es ilegal en versiones anteriores de Python. Considere este progtwig:

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 

Cuando se ejecuta bajo 2.4, quiero este resultado

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

y no este resultado:

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

(Canalización para un compañero de trabajo.)

Puedes probar usando eval :

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

Además, with está disponible en Python 2.5, solo agregue from __future__ import with_statement .

EDITAR: para obtener el control lo suficientemente temprano, puede dividirlo en diferentes archivos .py y verificar la compatibilidad en el archivo principal antes de importar (por ejemplo, en __init__.py en un paquete):

 # __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 * 

Tenga una envoltura alrededor de su progtwig que haga lo siguiente.

 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." 

También puede considerar el uso de sys.version() , si planea encontrarse con personas que están usando intérpretes de Python anteriores a 2.0, pero luego tiene que hacer algunas expresiones regulares.

Y podría haber formas más elegantes de hacer esto.

Tratar

 plataforma de importación
 plataforma.python_versión ()

Debería darle una cadena como “2.3.1”. Si esto no es exactamente lo que desea, hay un amplio conjunto de datos disponibles a través de la “plataforma” incorporada. Lo que quieras debería estar ahí en alguna parte.

Probablemente, la mejor manera de hacer esta comparación de versión es usar sys.hexversion . Esto es importante porque la comparación de tuplas de versión no le dará el resultado deseado en todas las versiones de python.

 import sys if sys.hexversion < 0x02060000: print "yep!" else: print "oops!" 
 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") 

Respuesta de Nykakin en AskUbuntu :

También puede verificar la versión de Python desde el propio código utilizando el módulo de platform de la biblioteca estándar.

Hay dos funciones:

  • platform.python_version() (devuelve cadena).
  • platform.python_version_tuple() (devuelve tupla).

El código de Python

Crea un archivo por ejemplo: version.py )

Método fácil de comprobar la versión:

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

También puedes usar el método eval :

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

Ejecuta el archivo Python en una línea de comando:

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

La salida de Python con CGI a través de un servidor WAMP en Windows 10:

Captura de pantalla 2016-11-16 14.39.01 por Suriyaa Kudo


Recursos útiles

Los conjuntos se convirtieron en parte del lenguaje central en Python 2.4, para mantenerse compatibles con versiones anteriores. Hice esto en ese entonces, que también funcionará para ti:

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

Aunque la pregunta es: ¿Cómo obtengo el control lo suficientemente temprano para emitir un mensaje de error y salir ?

La pregunta que respondo es: ¿Cómo obtengo el control lo suficientemente temprano para emitir un mensaje de error antes de iniciar la aplicación ?

Puedo responder de manera muy diferente a las otras publicaciones. Parece que las respuestas intentan resolver tu pregunta desde Python.

Digo, verifique la versión antes de iniciar Python. Veo que tu camino es Linux o unix. Sin embargo solo puedo ofrecerte un script de Windows. La imagen de adaptación a la syntax de scripts de Linux no sería demasiado difícil.

Aquí está el script de DOS con la versión 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 

Esto no ejecuta ninguna parte de su aplicación y, por lo tanto, no generará una excepción de Python. No crea ningún archivo temporal ni agrega ninguna variable de entorno del sistema operativo. Y no finaliza su aplicación a una excepción debido a las diferentes reglas de syntax de la versión. Eso es tres puntos de acceso de seguridad menos posibles.

La línea FOR /F es la clave.

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

Para ver la versión múltiple de python, echa un vistazo a url: http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17

Y mi versión hack:

[MS script; Versión de Python verifique el prelanzamiento del módulo Python] http://pastebin.com/aAuJ91FQ

 import sys sys.version 

obtendré una respuesta como esta

‘2.7.6 (predeterminado, 26 de octubre de 2016, 20:30:19) \ n [GCC 4.8.4]’

aquí 2.7.6 es la versión

Como se indicó anteriormente, los errores de syntax ocurren en tiempo de comstackción, no en tiempo de ejecución. Si bien Python es un “lenguaje interpretado”, el código de Python no se interpreta directamente; Se comstack a un código de bytes, que luego se interpreta. Hay un paso de comstackción que ocurre cuando se importa un módulo (si no hay una versión ya comstackda disponible en forma de archivo .pyc o .pyd) y es cuando recibe su error, no (exactamente) cuando su código se está ejecutando.

Puede posponer el paso de comstackción y hacerlo realidad en tiempo de ejecución para una sola línea de código, si lo desea, utilizando eval, como se indicó anteriormente, pero personalmente prefiero evitar hacerlo, ya que hace que Python tenga un rendimiento potencial. Recostackción innecesaria en tiempo de ejecución, para una cosa, y para otra, crea lo que para mí se siente como un desorden de código. (Si lo desea, puede generar un código que genere un código que genere un código, y tendrá un tiempo absolutamente fabuloso para modificar y depurar eso en 6 meses a partir de ahora). Entonces, lo que recomendaría es algo más como esto:

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

.. que haría incluso si solo tuviera una función que usara una syntax más nueva y fuera muy corta. (De hecho, tomaría todas las medidas razonables para minimizar el número y el tamaño de dichas funciones. Incluso podría escribir una función como ifTrueAElseB (cond, a, b) con esa única línea de syntax en ella).

Otra cosa que vale la pena señalar (que estoy un poco sorprendido de que nadie haya señalado todavía) es que, aunque las versiones anteriores de Python no admitían códigos como

 value = 'yes' if MyVarIsTrue else 'no' 

..es apoyaba el código como

 value = MyVarIsTrue and 'yes' or 'no' 

Esa era la antigua forma de escribir expresiones ternarias. Aún no tengo Python 3 instalado, pero por lo que sé, esa forma "antigua" todavía funciona hasta el día de hoy, por lo que puedes decidir si vale la pena o no usar la nueva syntax condicional, si es necesario. para soportar el uso de versiones anteriores de Python.

Coloque lo siguiente en la parte superior de su archivo:

 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) 

Luego continúe con el código normal de Python:

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

Creo que la mejor manera es probar la funcionalidad en lugar de las versiones. En algunos casos, esto es trivial, no así en otros.

p.ej:

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

Siempre y cuando seas lo suficientemente específico para usar los bloques try / except, puedes cubrir la mayoría de tus bases.

Acabo de encontrar esta pregunta después de una búsqueda rápida mientras intentaba resolver el problema yo mismo y se me ocurrió un híbrido basado en algunas de las sugerencias anteriores.

Me gusta la idea de DevPlayer de usar un script de envoltorio, pero la desventaja es que terminas manteniendo múltiples envoltorios para diferentes sistemas operativos, así que decidí escribir el envoltorio en python, pero usas la misma lógica básica de “agarrar la versión ejecutando el exe” y se le ocurrió esto.

Creo que debería funcionar para 2.5 en adelante. Lo he probado en 2.66, 2.7.0 y 3.1.2 en Linux y 2.6.1 en OS X hasta ahora.

 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") ) 

Sí, sé que la última línea de deencoding / tira es horrible, pero solo quería obtener rápidamente el número de versión. Voy a refinar eso.

Esto funciona lo suficientemente bien para mí por ahora, pero si alguien puede mejorarlo (o decirme por qué es una idea terrible), eso también sería genial.

Para las secuencias de comandos de Python independientes , el siguiente truco de la cadena de documentación del módulo para imponer una versión de python (aquí v2.7.x) funciona (probado en * nix).

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

Esto también debería manejar el ejecutable faltante de Python, pero tiene una dependencia de grep. Vea aquí para el fondo.

Puede consultar con sys.hexversion o sys.version_info .

sys.hexversion no es muy amigable para los humanos porque es un número hexadecimal. sys.version_info es una tupla, por lo que es más amigable para los humanos.

Compruebe si hay Python 3.6 o más nuevo con 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() 

Compruebe si hay Python 3.6 o más nuevo con 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 es más amigable para los humanos, pero toma más personajes. sys.hexversion , aunque sea menos amigable para los humanos.

¡Espero que esto te ayude!

Estoy ampliando la excelente respuesta de akhan, que imprime un mensaje útil antes de que se compile el script de Python.

Si desea asegurarse de que el script se ejecute con Python 3.6 o posterior, agregue estas dos líneas en la parte superior de su script de Python:

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

(Nota: la segunda línea comienza con cuatro comillas simples y termina con tres comillas simples. Esto puede parecer extraño, pero no es un error tipográfico).

La ventaja de esta solución es que el código como print(f'Hello, {name}!') No causará un SyntaxError si se SyntaxError una versión de Python anterior a 3.6. Verás este mensaje útil en su lugar:

 This script requires Python 3.6 or newer. 

Por supuesto, esta solución solo funciona en shells similares a Unix, y solo cuando el script se invoca directamente (como: ./script.py ), y con los bits de permiso de ejecución correctos establecidos.

Qué tal esto:

 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 

El problema es bastante simple. Usted verificó si la versión era menor que 2.4, no menor o igual que . Entonces, si la versión de Python es 2.4, no es menos de 2.4. Lo que deberías haber tenido fue:

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

no

  if sys.version_info < (2, 4):