How do I invoke Python code from Ruby? - python

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.

Related

Python logging doesn't work when script is called from another program

I have a python script that I use with LibreOffice Calc to do some more advanced macros. I need to debug this script and I'm trying to use logging for this. Logging works fine when the script is called from the command line, but it doesn't work at all when the script is called by LibreOffice.
Here is my logging test code:
import logging
logging.basicConfig(filename='test.log', level=logging.INFO)
logging.warning('test')
As requested, here is the LibreOffice Basic script that calls the Python script (this was mostly just a copy/paste from a guide on how to call Python scripts from LO):
function cev(a as String) as double
Dim scriptPro As Object, myScript As Object
Dim a1(1), b1(0), c1(0) as variant
a1(0) = ThisComponent
a1(1) = a
scriptPro = ThisComponent.getScriptProvider()
myScript = scriptPro.getScript( _
"vnd.sun.star.script:Cell_Functions.py$calcEffectValue?language=Python&location=user")
cev = myScript.invoke(a1, b1, c1)
end function
The basic script is called on a single cell using CEV(cellAddress), which passes the contents of the cell through to the Python script as a string.
Well, I updated to LibreOffice 7 and this started working. The Python version in LO 7 is 3.8 instead of 3.5, so maybe that made the difference.
Maybe it is working but you just don't know where test.log file is getting placed when it runs from LibreOffice. Try providing an absolute file path for test.log, like let's say C:/test.log.

How do I print to terminal with an AppleScript executed with Python?

I have a Python script that executes an apple script. I'd like to print to terminal from within the apple script.
Here is my Python code.
import applescript
myfunction = """
do shell script "echo " & "words to terminal"
"""
def runfunction():
applescript.tell.app("Terminal", myfunction, background = False)
And then I execute this with python -c 'import myapplescript; print myapplescript.runfunction()'
I've tried to print to terminal from within the apple script using the "do shell script" phrase and also copy "Hello World!" to stdout
import applescript
That is not a very good library. If your needs are simple, I would just use subprocess directly.
Also be aware that osascript is limited in its own IO support. There’s no built-in way to access stdin, and the only data that gets written to stdout is the last value (if any) returned at the end of the script. (You can write to stderr at any time using the log command, though that will have its own set of issues.)
If you want to access stdin/stdout directly in your AppleScript code, you’ll have to use Cocoa’s NSFileHandle class. I wrote a File library some years back that provided easy-to-use wrappers around that, though I don’t maintain or support it.
If your needs are more advanced—e.g. you want to call one or more AppleScript handlers or pass anything more complex than simple (short) strings—and you have PyObjC installed, you’d be better using [this library] (https://pypi.org/project/py-applescript/) or the AppleScript-ObjC bridge.

Using my Python program

I'm really new to python and I have made the following program:
class AddressBook:
def __init__(self):
self.b = {}
def insert(self,name, phone):
self.b[name]=phone
print "I am confused"
def get(self,name):
return self.b[name]
def has_name(self,name):
return self.b.has_key(name)
def list(self):
for n,p in self.b.iteritems():
print n,p
def delete(self, name):
del self.b[name]
def orderedList(self):
orderedkeys = self.b.keys()
orderedkeys.sort()
for n in orderedkeys:
print n, self.b[n]
I now want to compile it test it out in terminal to see if it all works.
I went to the directory and compiled it with
python address.py
Now I want to add things to the list, print the contents of the list, delete them (pretty much play around with my program) but I don't know how...
After compiling, how do I manually test (play around) with my python program?
Thanks in advance.
Python is an interpreted language, and .py files do not require direct compilation. There are a few ways to run Python code, but for "playing around" you can simply activate the Python interpreter and import the class.
In a command prompt:
> python
In Python:
>>> from address import AddressBook
>>> a = Addressbook()
>>> a.insert("Jenny", "867-5309")
>>> a.get("Jenny")
'867-5309'
The python script is not compiled. At least not in ways as other languages, like Fortran and C. From this answer:
Python has a compiler! You just don't notice it because it runs automatically. You can tell it's there, though: look at the .pyc (or .pyo if you have the optimizer turned on) files that are generated for modules that you import.
Also, it does not compile to the native machine's code. Instead, it compiles to a byte code that is used by a virtual machine. The virtual machine is itself a compiled program. This is very similar to how Java works; so similar, in fact, that there is a Python variant (Jython) that compiles to the Java Virtual Machine's byte code instead! There's also IronPython, which compiles to Microsoft's CLR (used by .NET). (The normal Python byte code compiler is sometimes called CPython to disambiguate it from these alternatives.)
You have two ways to test it out:
type python -i address.py in the terminal. This will run the script and enter the python shell.
You enter the python shell and then type from address.py import AddressBook.
On both ways, you can
play around with your code.

Running code with another interpreter on a Perl script

This thread discusses a way of running Python code from within a Bash script.
Is there any way to do something similar from within a Perl script? i.e. is there any way to run Python code typed on a Perl script? Note that I am not asking about running a Python file from a Perl script. I am asking about running Python code directly typed within the same file that has the Perl script (in the same way that the other thread discussed how to run Perl code from which a Bash script).
Example:
# /bin/perl
use 5.010
my $some_perl_variable = 'hello';
# ... BEGIN PYTHON BLOCK ...
# We are still in the same file. But we are now running Python code
import sys;
print some_perl_variable # Notice that this is a perl variable
for r in range(3):
print r
# ... END PYTHON BLOCK ...
say "We are done with the Perl script!"
say "The output of the Python block is:"
print $output"
1;
Should print:
We are done with the Perl script!
The output of the Python block is:
hello
1
2
3
We are done with the perl script
It sounds like you would be interested in the Inline module. It allows Perl to call code in many other languages, and relies on support modules for each language.
You don't say what you want to do, but you mention Python and there is an Inline::Python.
Yes, the same technique (here-docs) can be used for Perl.
Perl in Bash:
perl <<'END' # note single quotes to avoid $variable interpolation
use 5.010;
say "hello world";
END
or
perl -E'say "hello from perl"'
Bash in Perl:
use autodie; # less error handling
open my $bash, "|-", "bash";
print $bash <<'END'; # single quotes again
echo hello from bash
END
Perl in Bash in Perl:
use autodie; # less error handling
open my $bash, "|-", "bash";
print $bash <<'END'; # single quotes again
perl <<'INNER_END'
use 5.010;
say "hello inception";
INNER_END
END
(which I ironically tested on the commandline, in another heredoc)

How to write a Python 2.6+ script that gracefully fails with older Python?

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.

Categories