I am trying to get pywbem working in Python 3.2 (it works fine in 2.6) but the build fails on this part of code in mof_compiler.py:
File "pywbem-0.7.0\mof_compiler.py", line 1341
print s
^
SyntaxError: invalid syntax
It's a macro, defined like this:
def _print_logger(s):
print s
I don't understand why this is invalid, please explain how to do the same in Python 3.2.
Note: I have little or no experience with Python.
PS: I have already done some small changes to the code for 3.2 like
changing
except CIMError, ce:
to
except CIMError as ce:
based on Lennart Regebro's answer here are some other changes I found (placing them here since it may be useful for others).
exec "import %s as lextab" % tabfile -> exec ("import %s as lextab" % tabfile)
raise ValueError,"Expected a string" -> raise ValueError("Expected a string")
That's not a macro, it's a function definition, and in Python 3 the print statement is now a function. So do print(s) instead.
The list of changes between Python 2 and Python 3 is here: http://docs.python.org/release/3.0.1/whatsnew/3.0.html
It's not so easy to read, but I don't know if there is a better one online (although books exist).
If you are going to use Python 3, you would probably do good to get a Python 3 book. There are a couple of them out now. Or at least refer to the Python 3 documentation: http://docs.python.org/release/3.2/ It has a decent tutorial.
One of the most visible changes in python 3 is print is no longer a statement, but is a function, so you have to use parenthesis for calling that function. print(s)
Also, if you have your Python2 code, just use 2to3 which can do a source to source translation of your python2 to python3, which can fix most of the syntax level changes for you like the above problems. 2to3 is installed with python3 binary.
Sorry for answering an old question, but I just recently wanted to get PyWBEM running under Python 3, so I forked it, made the required changes, and removed a Python 2.x dependency (M2Crypto) from it for the 3.x series. Here's the source from GitHub:
https://github.com/deejross/python3-pywbem
Quick note, this supports Python 2.6, 2.7, and 3.4+
Related
Using features from newer python versions, e.g. f-string debugging feature: f'{some_var=}', results into a SyntaxError.
Suppose I have a python script which I would like to provide, and the user executes said script with an old python version, he will just get this error. Instead I would like to provide him with some meaningful text, e.g. "Please update python to version >=3.7"
I can solve it with a main file, which checks the version and then imports my script.
Is there a way to achieve this, while still having only a single file script?
Possible approaches:
Check sys.version or platfrom.python_version_tuple
-> Not possible, SyntaxError gets in the way, as python parses whole files
Use eval to determine SyntaxError: -> Not possible for same reasons
try:
a = "hello"
eval("f'{a=}'")
except SyntaxError:
raise ImportError('Update your Python version!!!!')
Can I trick Python somehow to not syntactically check the whole file?
(I could "pack" the whole file into a string, check for the version and then eval the string, but that is not a very clean solution and it is terrible for development)
Edit:
This question is not about "HOW to check for python version". Instead it is about "How to check for python version, before I receive SyntaxError due to new features.
I can think of one potential solution for this, where you wrap your entire script in a triple-quoted string (you'll need to make sure that it doesn't conflict with any triple-quoted strings in your script), and pass that to exec, like so:
import sys
if sys.version_info < (3, 7):
raise ImportError("I need python 3.7 or higher to run!")
exec('''
# your entire script
''')
... at this point I recommend either just using two files, or documenting on your website or wherever what the syntax error means.
I have the following code which runs fine on python 2 but throws error on python 3
import sys
if sys.version_info > (3,):
#print("Python 3")
#Try Block
except urllib2.HTTPError as err:
else:
#print "Python 2" # Throws error on python 3
#Try Block
except urllib2.HTTPError, err: # Throws error on python 3.
The above code returns "Python 2" in python 2, but throws syntax error on python 3 (For python 2 syntax ).
Can anyone tell me why is this happening ? And what is the work around to fix those syntax errors in python 3 ?
Note : I am aware of print syntax on Python 3
Thanks you!
The problem is that the parser runs before any code is evaluated at runtime. Your check sys.version_info > (3,) runs at run time, after the code was already parsed and compiled. So doing such checks, you are able to make changes at runtime, but that does not help you when dealing with syntax changes.
The syntax is parsed and compiled before any code is interpreted, that is why you get syntax errors even for code that is never run at runtime.
If you are trying to create a polyglot script that is able to run on both Python 3 and Python 2, then you will need to make sure to use a syntax that works on both. For print in particular, you can import the print function in Python 2, so you can use it just like you would in Python 3:
from __future__ import print_function
Some newer features won’t work that way (for example everything async), but for the most part, you can make it work somehow.
If you end up depending on stuff with Python 3 that requires Python 2-incompatible syntax, then you could put that into a separate module and import that module conditionally at runtime. That way it won’t be loaded for Python 2, so the Python 2 parser wouldn’t attempt to load the incompatible syntax.
As for why Python 2 does not throw an error, that’s actually very simple: print('foo bar') is valid syntax in Python 2, even with the print statement. That is because you can put parentheses around anything without impacting the value. So what you actually do there is this:
print ('foo bar')
^^^^^
print statement
^^^^^^^^^^^
value, wrapped in parentheses (that don’t do anything)
That’s also the reason, why the following produces different results in Python 3 and 2:
print('foo', 'bar')
In Python 3, you get foo bar as the output, while Python 2 gives you ('foo', 'bar'). That is because the comma inside the parentheses now makes this a tuple, so you pass a tuple to the print statement. – Importing the print function fixes this to give you the same behavior on Python 2 as on Python 3.
Even though the line print "Python 2" will never be executed in Python 3, it will still be compiled to byte code (or at least attempted). That line is a syntax error in Python 3, which requires the printed items to be in parentheses. Look up the documentation for more details: other changes to print were also made.
So remove the error. Make the line
print("Python 2") # Throws error on python 3
instead. That way it works in both Python 2 and in 3. There are many sites that discuss how to write code that executes in both versions of Python. The parentheses are merely ignored in version 2 but are needed in version 3. This works if you print only one item: more than one gets more complicated.
There is another way to do printing in both versions, using from __future__ import print_function but the way I showed is easier.
Note that your attempted comment in the line is also not proper Python syntax. Change the // to # and it works.
I'm backporting a modern python script to 2.4 to make it compatible with stock RHEL 5.X. While most of the work has been fairly straight-forward, I can't figure out how to handle this case where I am appending to a file:
print("Foo",file=file("/tmp/bar",'ab'))
This is a very common construct in the code I'm porting. I am using the print function from future, which works fine, but here it chokes on the "file=file("filename", 'ab')" part. Apparently this kind of redirection is not supported in 2.4. Likewise, I haven't found a way for the print function to support the >> operator from the old print. It would be an enormous task to re-write this script without the print function, so I'd like a solution based on the print function.
I've found plenty of docs showing how to use >> in the old print, or file=file() in the new print function, but nothing that actually works in 2.4.
What is the equivalent Python 2.4 compatible code for this?
The syntax is pretty awful:
print >> file('/tmp/bar', 'ab'), 'Foo'
Though of course you should rather write:
f = open('/tmp/bar', 'ab')
try:
print >> f, 'Foo'
finally:
f.close()
to make sure that the output is actually closed and flushed. (Python 2.4 doesn't have with statement!).
As an alternative to converting everything to print statement, you could also try the print_ function from the Six: Python 2 and 3 Compatibility Library. I am not sure whether the whole library supports 2.4 any longer, but that one function should be OK in 2.4.
I'm looking for a way to do this without checking for the Python version used.
Please refer to How to write exception reraising code that's compatible with both Python 2 and Python 3? for details about this, since this question extends that one.
Basically, I can generalize this as, "What if the method-based exception raises a language-based exception?"
According to Python try...except comma vs 'as' in except, the following show the right syntax for Python 3 and Python 2:
Python 3:
except MyError as e
Python 2, for versions 2.6+:
except MyError as e
#OR#
except MyError, e
Python 2.5-:
except MyError, e
A little background:
I have a sticky situation in which a script will need to be run on many an ancient Linux machine, in which a variety of different Python versions, including Python 2.5, will be used.
Unfortunately, I have to distribute this as a single, size limited file, which puts some constraints on how much importing I can do.
Also, I'm interested in the case in which one of these may misreport its version, or in code that can be used without necessarily checking for a version. This could be worked around, though, of course.
Your only option is to avoid the exception assignment and pull it out of the result for the sys.exc_info() function instead:
try:
# ...
except Exception: # note, no ", e" or "as e"
import sys
e = sys.exc_info()[1]
This'll work on Python 1.5 and up.
However, you'll likely to encounter other incompatibilities and difficulties; writing polyglot Python code (code that works on both Python 2.x and 3.x) is only really workable on Python 2.6 and up.
I have a Python script that uses Python version 2.6 syntax (Except error as value:) which version 2.5 complains about. So in my script I have included some code to check for the Python interpreter version before proceeding so that the user doesn't get hit with a nasty error, however, no matter where I place that code, it doesn't work. Once it hits the strange syntax it throws the syntax error, disregarding any attempts of mine of version checking.
I know I could simply place a try/except block over the area that the SyntaxError occurs and generate the message there but I am wondering if there is a more "elegant" way. As I am not very keen on placing try/except blocks all over my code to address the version issue. I looked into using an __ init__.py file, but the user won't be importing/using my code as a package, so I don't think that route will work, unless I am missing something...
Here is my version checking code:
import sys
def isPythonVersion(version):
if float(sys.version[:3]) >= version:
return True
else:
return False
if not isPythonVersion(2.6):
print "You are running Python version", sys.version[:3], ", version 2.6 or 2.7 is required. Please update. Aborting..."
exit()
Create a wrapper script that checks the version and calls your real script -- this gives you a chance to check the version before the interpreter tries to syntax-check the real script.
Something like this in beginning of code?
import sys
if sys.version_info<(2,6):
raise SystemExit('Sorry, this code need Python 2.6 or higher')
In sys.version_info you will find the version information stored in a tuple:
sys.version_info
(2, 6, 6, 'final', 0)
Now you can compare:
def isPythonVersion(version):
return version >= sys.version_info[0] + sys.version_info[1] / 10.
If speed is not a priority, you can avoid this problem entirely by using sys.exc_info to grab the details of the last exception.