tags:

views:

12652

answers:

10

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.

update

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

+20  A: 

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 do 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 *
orip
this is a fantastic answer. the main issue from the question that needed addressing is that a program must be syntactically correct for that version of python to even begin executing, so using new syntax precludes a program from starting on older versions of the interpreter. eval works around that
Autoplectic
If the package is being installed by setuptools, byte-compiling the source files will fail then. Also, all the contortions to produce a run-time error message seem a little pointless -- why not just document the requirements and leave it at that?
John Machin
+2  A: 

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.

sykora
You're right. That's what he asked how to do - sometimes testing for features in version Y doesn't even compile to bytecode in version X, so it can't be done directly.
orip
+2  A: 

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.

James Anderson
+6  A: 

Have a wrapper around your program that does the following:

import sys

req_version = (2,5)
cur_version = sys.version_info()

if (cur_version[0] > req_version[0] or
    (cur_version[0] == req_version[0] and
    cur_version[1] >= req_version[1]):
   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 regexing to do.

And there might be more elegant ways to do this, but this is what I could think up in 5 minutes time. YMMV.

Ed Carrel
FYI, "cur_version >= req_version" should work as the conditional.
orip
+1  A: 

sets became part of the core language in 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

HTH

André
A: 

How about

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
Stry
A: 

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):
None
read paragraph 3, and the update. you don't to the point of executing this code because your code won't compile on 2.4 if you are using the new language constructs.
Mark Harrison
A: 

I have 2 instances of Python on my machine. I have a script i want to run using v2.5 but the default is 2.6.

How can I ensure the v2.5 instance runs my script?

Alex Rodriguez
This is not the place for this question, but use `#!/usr/bin/env python2.5` as the shebang line in unix systems. In windows... you're on your own there.
kwatford
A: 

if u start your script by clicking it then change py filetype to use older version of python. If you are doing it from command line in short periods use c:\python2.5\python.exe yourscript.py

python
+3  A: 

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!"
Sorin Sbarnea
I think this is most elegant, but probably not the easiest to understand by other devs.
nbolton