web-dev-qa-db-fra.com

Comment vérifier la version de Python dans un programme utilisant de nouvelles fonctionnalités de langage?

Si j'ai un script Python qui requiert au moins une version Particulière de Python, quelle est la bonne méthode pour échouer gracieusement Lorsqu'une version antérieure de Python est utilisée pour lancer le script?

Comment obtenir le contrôle suffisamment tôt pour émettre un message d'erreur Et quitter?

Par exemple, j'ai un programme qui utilise l'opérateur ternery (nouveau dans 2.5) et les blocs "with" (Nouveau dans 2.6). J'ai écrit une petite routine simple interpréteur-version Checker qui est la première chose que ferait le script call ... sauf que cela ne va pas aussi loin. Au lieu de cela, le script Échoue lors de la compilation python, avant même que mes routines Soient appelées. Ainsi, l’utilisateur du script voit une trace très proche de l’erreur de synaxe obscure - qui demande à peu près à un expert de déduire qu’il s’agit simplement d’exécuter la mauvaise version de Python.

Je sais comment vérifier la version de Python. Le problème est que certaines syntaxes sont illégales dans les anciennes versions de Python. Considérez ce programme:

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

Quand je suis sous 2.4, je veux ce résultat

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

et pas ce résultat:

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

(Canalisation pour un collègue.)

234
Mark Harrison

Vous pouvez tester en utilisant eval:

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

De plus, with est disponible dans Python 2.5, ajoutez simplement from __future__ import with_statement.

EDIT: pour prendre le contrôle suffisamment tôt, vous pouvez le scinder en différents fichiers .py et vérifier la compatibilité dans le fichier principal avant de l'importer (par exemple, dans __init__.py dans un package):

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

Avoir un wrapper autour de votre programme qui fait ce qui suit.

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

Vous pouvez également envisager d'utiliser sys.version(), si vous envisagez de rencontrer des personnes utilisant des interpréteurs Python antérieurs à 2.0, mais que vous avez ensuite des expressions régulières à faire.

Et il pourrait y avoir des moyens plus élégants de le faire.

102
Ed Carrel

Essayer 

 plateforme d'importation 
 plateforme.python_version () 

Devrait vous donner une chaîne comme "2.3.1". Si ce n'est pas exactement ce que vous voulez, il existe un riche ensemble de données disponibles via le module "plate-forme". Ce que vous voulez devrait être quelque part. 

30
James Anderson

La meilleure façon de faire cette comparaison de version consiste probablement à utiliser le sys.hexversion. Ceci est important car comparer les tuples de version ne vous donnera pas le résultat souhaité dans toutes les versions de Python.

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

Réponse de Nykakin à AskUbuntu :

Vous pouvez également vérifier la version Python à partir du code lui-même en utilisant le module platform de la bibliothèque standard.

Il y a deux fonctions:

  • platform.python_version() (retourne une chaîne).
  • platform.python_version_Tuple() (retourne le tuple).

Le code Python

Créez un fichier par exemple: version.py)

Méthode facile pour vérifier la version:

import platform

print(platform.python_version())
print(platform.python_version_Tuple())

Vous pouvez également utiliser la méthode eval:

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

Exécutez le fichier Python dans une ligne de commande:

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

La sortie de Python avec CGI via un serveur WAMP sous Windows 10:

 Screenshot 2016-11-16 14.39.01 by Suriyaa Kudo


Ressources utiles

9
Suriyaa

Bien que la question soit: Comment puis-je prendre le contrôle suffisamment tôt pour émettre un message d'erreur et quitter ?

La question à laquelle je réponds est la suivante: Comment puis-je prendre le contrôle suffisamment tôt pour envoyer un message d'erreur avant de lancer l'application ?

Je peux répondre très différemment aux autres messages. Il semble que les réponses tentent jusqu'à présent de résoudre votre question depuis Python.

Je dis, vérifiez la version avant de lancer Python. Je vois que votre chemin est Linux ou Unix. Cependant, je ne peux vous proposer qu'un script Windows. Je pense que l'adapter à la syntaxe de script Linux ne serait pas trop difficile.

Voici le script DOS avec la version 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

Cela n'exécute aucune partie de votre application et ne génère donc pas d'exception Python. Il ne crée aucun fichier temporaire et n'ajoute aucune variable d'environnement de système d'exploitation. Et cela ne met pas fin à votre application à une exception en raison de règles de syntaxe de version différentes. C'est trois points d'accès de sécurité possibles de moins.

La ligne FOR /F est la clé.

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

Pour plusieurs python, vérifiez l'url: http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17

Et ma version de hack:

[Script MS; Python vérification de la version avant le lancement du module Python] http://Pastebin.com/aAuJ91FQ

7
DevPlayer

Les ensembles sont devenus partie intégrante du langage de base de Python 2.4, afin de rester compatible avec les versions antérieures. Je l'ai fait à l'époque, ce qui fonctionnera pour vous aussi:

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

obtiendra la réponse comme ceci 

'2.7.6 (défaut, le 26 octobre 2016, 20:30:19)\n [GCC 4.8.4]'

ici 2.7.6 est la version

3
Janarthanan Ramu

Comme indiqué ci-dessus, les erreurs de syntaxe se produisent au moment de la compilation, pas au moment de l'exécution. Bien que Python soit un "langage interprété", le code Python n'est pas interprété directement; il est compilé en code octet, qui est ensuite interprété. Il y a une étape de compilation qui se produit quand un module est importé (s'il n'y a pas de version déjà compilée disponible sous la forme d'un fichier .pyc ou .pyd) et c'est quand vous obtenez votre erreur, pas (tout à fait) quand votre code est en cours d'exécution. 

Vous pouvez différer l'étape de compilation et la réaliser au moment de l'exécution pour une seule ligne de code, si vous le souhaitez, en utilisant eval, comme indiqué ci-dessus, mais personnellement, je préfère éviter de le faire, car Python s'exécute potentiellement Une compilation inutile au moment de l'exécution, d'une part, et d'autre part, elle crée ce que je ressens comme du fouillis de code. (Si vous le souhaitez, vous pouvez générer du code qui génère du code qui génère du code - et passez ainsi un temps absolument fabuleux à modifier et à déboguer dans 6 mois.) Ce que je recommanderais plutôt est plutôt quelque chose qui ressemble à ceci:

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

.. ce que je ferais même si je n'avais qu'une fonction utilisant la syntaxe la plus récente et qu'elle était très courte. (En fait, je prendrais toutes les mesures raisonnables pour minimiser le nombre et la taille de telles fonctions. Je pourrais même écrire une fonction comme ifTrueAElseB (cond, a, b) avec cette seule ligne de syntaxe.)

Une autre chose qui mérite d’être soulignée (que je suis un peu étonné que personne n’a encore signalé) est que, même si les versions précédentes de Python ne prenaient pas en charge le code tel que

value = 'yes' if MyVarIsTrue else 'no'

..il a soutenu le code comme

value = MyVarIsTrue and 'yes' or 'no'

C'était l'ancienne manière d'écrire des expressions ternaires. Je n'ai pas encore Python 3 installé, mais autant que je sache, cette "ancienne" méthode fonctionne encore de nos jours, vous pouvez donc décider vous-même s'il est utile ou non d'utiliser conditionnellement la nouvelle syntaxe, si vous en avez besoin. pour supporter l'utilisation d'anciennes versions de Python.

2
Shavais

Placez les éléments suivants en haut de votre fichier:

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)

Continuez ensuite avec le code Python normal:

import ...
import ...
other code...
2
jml

Je pense que le meilleur moyen est de tester la fonctionnalité plutôt que les versions. Dans certains cas, c'est trivial, pas dans d'autres.

par exemple:

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

Tant que vous utilisez suffisamment les blocs try/except, vous pouvez couvrir la plupart de vos bases.

1
sykora

Pour les scripts standalone python, l'astuce suivante relative au module docstring pour appliquer une version python (ici v2.7.x) fonctionne (testée sur * 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
[...]

Cela devrait également gérer l'exécutable python manquant mais dépend de grep. Voir ici pour le fond.

1
akhan

Je viens juste de trouver cette question après une recherche rapide alors que j'essayais de résoudre le problème moi-même et j'ai proposé un hybride basé sur quelques-unes des suggestions ci-dessus.

J'aime l'idée de DevPlayer d'utiliser un script de wrapper, mais l'inconvénient est que vous devez conserver plusieurs wrappers pour différents systèmes d'exploitation. J'ai donc décidé d'écrire le wrapper en python, tout en utilisant la même logique de base "saisir la version en exécutant l'exe" et est venu avec cela. 

Je pense que cela devrait fonctionner pour 2.5 et les années suivantes. Je l'ai testé sur les versions 2.66, 2.7.0 et 3.1.2 sous Linux et 2.6.1 sous OS X jusqu'à présent.

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

Oui, je sais que la dernière ligne de décodage/bande est horrible, mais je voulais juste saisir rapidement le numéro de version. Je vais raffiner ça.

Cela fonctionne assez bien pour moi pour le moment, mais si quelqu'un peut l'améliorer (ou me dire pourquoi c'est une si mauvaise idée), ce serait bien aussi.

1
Steve

Je développe l'excellente réponse d'Akhan, qui affiche un message utile avant le script Python est même compilé.

Si vous voulez vous assurer que le script est exécuté avec Python 3.6 ou plus récent, ajoutez ces deux lignes en haut de votre script 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 # '''

(Remarque: la deuxième ligne commence par quatre guillemets simples et se termine par trois guillemets simples. Cela peut paraître étrange, mais ce n'est pas une faute de frappe.)

L'avantage de cette solution est qu'un code tel que print(f'Hello, {name}!') ne provoquera pas une SyntaxError si une version de Python antérieure à 3.6 est utilisée. Vous verrez ce message utile à la place:

This script requires Python 3.6 or newer.

Bien entendu, cette solution ne fonctionne que sur les shells de type Unix, et uniquement lorsque le script est appelé directement (tel que: ./script.py) et que les bits d'autorisation eXecute appropriés sont définis.

0
J-L

Vous pouvez vérifier avec sys.hexversion ou sys.version_info.

sys.hexversion n'est pas très convivial, car c'est un nombre hexadécimal. sys.version_info est un tuple, il est donc plus convivial.

Recherchez Python 3.6 ou une version plus récente avec 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()

Recherchez Python 3.6 ou une version plus récente avec 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 est plus convivial, mais prend plus de caractères. Je recommanderais sys.hexversion, même si c'est moins humain.

J'espère que cela vous a aidé!

0
Pb2007