Question:
Is it possible to import a module I wrote in python 2.7 into a 3.4 program that I wrote?
Background:
I've tried doing this and as expected it throws a SyntaxError: Invalid Syntax, once it sees the first print "string literal" statement instead of 3.4's print(). There are a few additional incompatible code snippets, like import Tkinter instead of tkinter. The 2.7 module must remain in 2.7 because one of its dependencies doesn't seem to work in 3.X (a python binding for the switchvox api).
I'm building a display app that will call any module specified in its config file and display that module's output (a string, or in the future possible a dict) in a tkinter widget. All my program needs to do is import the 2.7 module and call one function once (every x number of seconds) to receive that string of data.
You can make your python 2.7 code be 3.4 compatible - this way you can import it from 3.4 and use the same classes and functions.
For running you have to run it on different process using python 2.7 - using subprocess.
Assume main27.py has the following line:
print 1
To run it using subprocess, you do as follow:
import subprocess
cmd = [r'c:\python27\python.exe', 'main27.py']
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
Than in stdout you have the following output:
1
For more complex data exchange you can use json or pickle using files.
Indeed it is possible to make your code compatible with both versions. The obvious one and potentially more annoying is the print statement.
Let's say you have the following Python 2.x code:
name = "beautiful"
print "Hallo"
print "I mean, hallo ", name
The first line works fine in both versions. The second line, can just become:
print("Hallo")
Which is compatible with both versions too. Note that you can use single or double quotes.
The last line requires a little trick, otherwise, Python 2 will print the brackets as well. In order to make it work the same way in Python 2 as it does in Python 3, you have to import print_function from future, at the top of your module.
In summary, this is the dual compatible code:
#Works in Python 2.x or Python 3.x
from __future__ import print_function
print("Hallo")
print("I mean, hallo ", name)
See this cheat sheet for more details.
Related
I am making code that works on both Python 2 and Python 3.
But there was no problem in theory, but there was a Python problem.
Now I'm build and use both Python 2.7.5 and Python 3.7.4.
This is part of my code
ex)
if sys.version_info < (3,):
print(keys),;
print(values)
else:
print(keys,'/ ', end='')
print(values)
This code that checks Python version with sys.version, corresponding 'if' will be working.
But, of course there is a syntax error.
Python 2 does not support [end=''].
In my opinion...
Even if you actually ignore it and act on it, there's no problem code.
I tried 'Try-except', but syntax errors were not ignored.
How can both Python2 and Python3 not change lines while weaving compatible codes?
Import the package print_function and try
from __future__ import print_function
In this particular case, just get the Python 3 print function in both Python 2 and Python 3 by adding:
from __future__ import print_function
to the very top of your file, then only use the Python 3 syntax.
As for avoiding the SyntaxError from actually incompatible constructs that can't be fixed with a __future__ import, the only solutions are putting the incompatible code in separate modules (a public module can do version testing to import the implementations from the private module appropriate to the Python version), or evaling a string containing the code for the appropriate version (exec won't typically work, because it also changed from keyword statement to built-in function in the transition; eval+compile is the same in both though).
There is no way to just "turn off syntax checking", because invalid syntax definitionally means the parser has encountered an unrecoverable error; you don't want it to try to stumble onwards, guessing at what everything else means in the context of the garbage state it was left in.
Using reposurgeon and trying to extend its functionality, I am faced with:
reposurgeon: invalid syntax in extension function
which translates to a SyntaxError extension raised from the execfile() call in RepoSurgeon.do_exec(). What gives? The code I am trying to exec is as simple as:
print "Hello world"
I have also used the Python CLI and execfile and there are no complaints whatsoever?
Used version: reposurgeon 3.10
This one took me a while to figure out, which is why I am posting it here.
The key is indeed in the single line of code we're trying to "source". While this is perfectly valid Python 2.x code, reposurgeon uses the print function from Python 3.x by doing:
from __future__ import print_function
Which causes print to require the use of parentheses, as it makes print a function instead of a statement.
Obviously we're running our extension code in the context of reposurgeon, which means that we're dependent on the rules it defines.
See this document.
Hence the following will work just fine:
print("Hello world")
I am using Python 2.7.
When I try to print a simple string to a file, I get the following error:
Syntax error: invalid tuple
Syntax error while detecting tuple
minimal example:
fly = open('workfile', 'w')
print('a', file=fly)
writing to the same file via fly.write('a') works just fine.
You are using the Python 3 syntax in Python 2.
In Python 2, it's like this:
print >> fly, 'a'
However, a better idea is to do this:
from __future__ import print_function
Which will enable the Python 3 syntax if you are using Python 2.6 or 2.7.
See also: http://docs.python.org/2/library/functions.html#print
Check the documentation
Note This function is not normally available as a built-in since the name print is recognized as the print statement. To disable the statement and use the print() function, use this future statement at the top of your module:
from future import print_function
I'm using the new print from Python 3.x and I observed that the following code does not compile due to the end=' '.
from __future__ import print_function
import sys
if sys.hexversion < 0x02060000:
raise Exception("py too old")
...
print("x",end=" ") # fails to compile with py24
How can I continue using the new syntax but make the script fails nicely? Is it mandatory to call another script and use only safe syntax in this one?
The easy method for Python 2.6 is just to add a line like:
b'You need Python 2.6 or later.'
at the start of the file. This exploits the fact that byte literals were introduced in 2.6 and so any earlier versions will raise a SyntaxError with whatever message you write given as the stack trace.
There are some suggestions in this question here, but it looks like it is not easily possible. You'll have to create a wrapper script.
One way is to write your module using python 2.x print statement, then when you want to port it into python 3, you use 2to3 script. I think there are scripts for 3to2 conversion as well, although they seems to be less mature than 2to3.
Either way, in biggers scripts, you should always separate domain logic and input/output; that way, all the print statements/functions are bunched up together in a single file. For logging, you should use the logging module.
Does a easy to use Ruby to Python bridge exist? Or am I better off using system()?
You could try Masaki Fukushima's library for embedding python in ruby, although it doesn't appear to be maintained. YMMV
With this library, Ruby scripts can directly call arbitrary Python modules. Both extension modules and modules written in Python can be used.
The amusingly named Unholy from the ingenious Why the Lucky Stiff might also be of use:
Compile Ruby to Python bytecode.
And, in addition, translate that
bytecode back to Python source code
using Decompyle (included.)
Requires Ruby 1.9 and Python 2.5.
gem install rubypython
rubypython home page
I don't think there's any way to invoke Python from Ruby without forking a process, via system() or something. The language run times are utterly diferent, they'd need to be in separate processes anyway.
If you want to use Python code like your Python script is a function, try IO.popen .
If you wanted to reverse each string in an array using the python script "reverse.py", your ruby code would be as follows.
strings = ["hello", "my", "name", "is", "jimmy"]
#IO.popen: 1st arg is exactly what you would type into the command line to execute your python script.
#(You can do this for non-python scripts as well.)
pythonPortal = IO.popen("python reverse.py", "w+")
pythonPortal.puts strings #anything you puts will be available to your python script from stdin
pythonPortal.close_write
reversed = []
temp = pythonPortal.gets #everything your python script writes to stdout (usually using 'print') will be available using gets
while temp!= nil
reversed<<temp
temp = pythonPortal.gets
end
puts reversed
Then your python script would look something like this
import sys
def reverse(str):
return str[::-1]
temp = sys.stdin.readlines() #Everything your ruby programs "puts" is available to python through stdin
for item in temp:
print reverse(item[:-1]) #Everything your python script "prints" to stdout is available to the ruby script through .gets
#[:-1] to not include the newline at the end, puts "hello" passes "hello\n" to the python script
Output:
olleh
ym
eman
si
ymmij
For python code to run the interpreter needs to be launched as a process. So system() is your best option.
For calling the python code you could use RPC or network sockets, got for the simplest thing which could possibly work.