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
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.)
You can test using
try: eval("1 if True else 2") except SyntaxError: # doesn't have ternary
with is 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 *
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.
And there might be more elegant ways to do this.
import platform platform.python_version()
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 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")
Answer from Nykakin at AskUbuntu:
You can also check Python version from code itself using
platform module from standard library.
There are two functions:
The Python code
Create a file for example:
Easy method to check version:
import platform print(platform.python_version()) print(platform.python_version_tuple())
You can also use the
try: eval("1 if True else 2") except SyntaxError: raise ImportError("requires ternary support")
Run the Python file in a command line:
$ python version.py 2.7.11 ('2', '7', '11')
The output of Python with CGI via a WAMP Server on Windows 10:
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
For multiple python version check check out url:
And my hack version:[MS script; Python version check prelaunch of Python module] http://pastebin.com/aAuJ91FQ
Sets became part of the core language in Python 2.4, in order to stay backwards compatible. I did this back then, which will work for you as well:
if sys.version_info < (2, 4): from sets import Set as set
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.
Put the following at the very top of your file:
import sys if float(sys.version.split()[:3]) < 2.7: print "Python 2.7 or higher required to run this code, " + sys.version.split() + " detected, exiting." exit(1)
Then continue on with the normal Python code:
import ... import ... other code...
import sys sys.version
will be getting answer like this
‘2.7.6 (default, Oct 26 2016, 20:30:19) \n[GCC 4.8.4]’
here 2.7.6 is version
I think the best way is to test for functionality rather than versions. In some cases, this is trivial, not so in others.
try : # Do stuff except : # Features weren't found. # Do stuff for older versions.
As long as you’re specific in enough in using the try/except blocks, you can cover most of your bases.
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.
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") )
Yes, I know the final decode/strip line is horrible, but I just wanted to quickly grab the version number. I’m going to refine that.
This works well enough for me for now, but if anyone can improve it (or tell me why it’s a terrible idea) that’d be cool too.
You can check with
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
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
import sys, time if sys.version_info < 3 and sys.version_info < 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.
I hope this helped you!
How about this:
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
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:
if sys.version_info **<=** (2, 4):
if sys.version_info < (2, 4):