If I have a Python script that requires at least a particular
version of Python, what is the correct way to fail gracefully
when an earlier version of Python is used to launch the script?
How do I get control early enough to issue an error message
and exit?
For example, I have a program that uses the ternery operator (new in 2.5) and “with” blocks
(new in 2.6). I wrote a simple little interpreter-version
checker routine which is the first thing the script would
call … except it doesn’t get that far. Instead, the
script fails during python compilation, before my routines
are even called. Thus the user of the script sees some very
obscure synax error tracebacks – which pretty much require
an expert to deduce that it is simply the case of running
the wrong version of Python.
I know how to check the version of Python. The issue is that some syntax is illegal in older versions of Python. Consider this program:
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
When run under 2.4, I want this result
$ ~/bin/python2.4 tern.py
must use python 2.5 or greater
and not this result:
$ ~/bin/python2.4 tern.py
File "tern.py", line 5
x = 1 if True else 2
^
SyntaxError: invalid syntax
(Channeling for a coworker.)
回答 0
您可以使用进行测试eval:
try:
eval("1 if True else 2")exceptSyntaxError:# doesn't have ternary
try:
eval("1 if True else 2")
except SyntaxError:
# doesn't have ternary
Also, withis available in Python 2.5, just add from __future__ import with_statement.
EDIT: to get control early enough, you could split it into different .py files and check compatibility in the main file before importing (e.g. in __init__.py in a 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 *
回答 1
围绕您的程序执行以下操作的包装器。
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."
Have a wrapper around your program that does the following.
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."
You can also consider using sys.version(), if you plan to encounter people who are using pre-2.0 Python interpreters, but then you have some regular expressions to do.
Should give you a string like “2.3.1”. If this is not exactly waht you want there is a rich set of data available through the “platform” build-in. What you want should be in there somewhere.
Probably the best way to do do this version comparison is to use the sys.hexversion. This is important because comparing version tuples will not give you the desired result in all python versions.
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")
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")
@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 ErrorLevel1 GOTO Python27
ECHO must use python2.7or greater
GOTO EOF
:Python27
python.exe tern.py
GOTO EOF
:EOF
Although the question is:
How do I get control early enough to issue an error message and exit?
The question that I answer is:
How do I get control early enough to issue an error message before starting the app?
I can answer it a lot differently then the other posts.
Seems answers so far are trying to solve your question from within Python.
I say, do version checking before launching Python. I see your path is Linux or unix.
However I can only offer you a Windows script. I image adapting it to linux scripting syntax wouldn’t be too hard.
Here is the DOS script with 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
This does not run any part of your application and therefore will not raise a Python Exception. It does not create any temp file or add any OS environment variables. And it doesn’t end your app to an exception due to different version syntax rules. That’s three less possible security points of access.
The FOR /F line is the key.
FOR /F "tokens=1,2" %%G IN ('"python.exe -V 2>&1"') DO ECHO %%H | find "2.7" > Nul
As noted above, syntax errors occur at compile time, not at run time. While Python is an “interpreted language”, Python code is not actually directly interpreted; it’s compiled to byte code, which is then interpreted. There is a compile step that happens when a module is imported (if there is no already-compiled version available in the form of a .pyc or .pyd file) and that’s when you’re getting your error, not (quite exactly) when your code is running.
You can put off the compile step and make it happen at run time for a single line of code, if you want to, by using eval, as noted above, but I personally prefer to avoid doing that, because it causes Python to perform potentially unnecessary run-time compilation, for one thing, and for another, it creates what to me feels like code clutter. (If you want, you can generate code that generates code that generates code – and have an absolutely fabulous time modifying and debugging that in 6 months from now.) So what I would recommend instead is something more like this:
import sys
if sys.hexversion < 0x02060000:
from my_module_2_5 import thisFunc, thatFunc, theOtherFunc
else:
from my_module import thisFunc, thatFunc, theOtherFunc
.. which I would do even if I only had one function that used newer syntax and it was very short. (In fact I would take every reasonable measure to minimize the number and size of such functions. I might even write a function like ifTrueAElseB(cond, a, b) with that single line of syntax in it.)
Another thing that might be worth pointing out (that I’m a little amazed no one has pointed out yet) is that while earlier versions of Python did not support code like
value = 'yes' if MyVarIsTrue else 'no'
..it did support code like
value = MyVarIsTrue and 'yes' or 'no'
That was the old way of writing ternary expressions. I don’t have Python 3 installed yet, but as far as I know, that “old” way still works to this day, so you can decide for yourself whether or not it’s worth it to conditionally use the new syntax, if you need to support the use of older versions of Python.
回答 10
将以下内容放在文件的最上方:
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)
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)
Then continue on with the normal Python code:
import ...
import ...
other code...
回答 11
我认为最好的方法是测试功能而不是版本。在某些情况下,这是微不足道的,而在其他情况下则并非如此。
例如:
try:# Do stuffexcept:# Features weren't found.# Do stuff for older versions.
I just found this question after a quick search whilst trying to solve the problem myself and I’ve come up with a hybrid based on a few of the suggestions above.
I like DevPlayer’s idea of using a wrapper script, but the downside is that you end up maintaining multiple wrappers for different OSes, so I decided to write the wrapper in python, but use the same basic “grab the version by running the exe” logic and came up with this.
I think it should work for 2.5 and onwards. I’ve tested it on 2.66, 2.7.0 and 3.1.2 on Linux and 2.6.1 on OS X so far.
You can check with sys.hexversion or sys.version_info.
sys.hexversion isn’t very human-friendly because it’s a hexadecimal number. sys.version_info is a tuple, so it’s more human-friendly.
Check for Python 3.6 or newer with 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()
Check for Python 3.6 or newer with 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 is more human-friendly, but takes more characters. I would reccomend sys.hexversion, even though it is less human-friendly.
(Note: The second line starts with four single-quotes and ends with three single-quotes. This may look strange, but it is not a typo.)
The advantage of this solution is that code like print(f'Hello, {name}!') won’t cause a SyntaxError if a Python version older than 3.6 is used. You’ll see this helpful message instead:
This script requires Python 3.6 or newer.
Of course, this solution only works on Unix-like shells, and only when the script is invoked directly (such as: ./script.py), and with the proper eXecute permission bits set.
The problem is quite simple. You checked if the version was less than 2.4, not less than or equal to. So if the Python version is 2.4, it’s not less than 2.4.
What you should have had was: