Home » Python » How can I check for Python version in a program that uses new language features?

How can I check for Python version in a program that uses new language features?

Posted by: admin January 29, 2018 Leave a comment

Questions:

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

Answers:

You can test using eval:

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

Also, 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 *

Questions:
Answers:

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.

Questions:
Answers:

Try

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.

Questions:
Answers:

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

Questions:
Answers:
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")

Questions:
Answers:

Answer from Nykakin at AskUbuntu:

You can also check Python version from code itself using platform module from standard library.

There are two functions:

  • platform.python_version() (returns string).
  • platform.python_version_tuple() (returns tuple).

The Python code

Create a file for example: version.py)

Easy method to check version:

import platform

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

You can also use the eval method:

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:

Screenshot 2016-11-16 14.39.01 by Suriyaa Kudo


Helpful resources

Questions:
Answers:

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:
http://www.fpschultze.de/modules/smartfaq/faq.php?faqid=17

And my hack version:

[MS script; Python version check prelaunch of Python module] http://pastebin.com/aAuJ91FQ

Questions:
Answers:

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

Questions:
Answers:

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.

Questions:
Answers:

Put the following at the very top of your file:

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

Questions:
Answers:
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

Questions:
Answers:

I think the best way is to test for functionality rather than versions. In some cases, this is trivial, not so in others.

eg:

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.

Questions:
Answers:

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.

Questions:
Answers:

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.

I hope this helped you!

Questions:
Answers:

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

Questions:
Answers:

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

, not

    if sys.version_info < (2, 4):