1
votes

I have a lua script configured to trigger once a subject's metadata is sent to a specific online Orthanc server. I want it to scrape the subject ID and then call a python script with the ID as an argument. When I put the command manually into my terminal, it works, but the lua script doesn't seem to be executing it.

There is a built-in Orthanc function that scrapes the ID from the subject once it is sent to the server. The initial lua script had the following:

path = "/path/to/python_script.py"
os.execute("python " .. path .. " " .. subjectId)

But the script wasn't getting called.

I first wanted to see if it was even getting triggered, so I added in:

file = io.open("/path/to/textfile.txt", "a")
file:write("\nI am alive, subjectId is " .. subjectId)
file:close()

And that worked!

So then I wanted to see if there was something wrong with os.execute, so I did:

os.execute("touch /same/path/deleteme.txt")

which worked as well. So it doesn't seem like os.execute isn't working. Does anyone have any idea why the script isn't getting called?

EDIT: Does anyone know how to check the status of the os.execute command? EDIT: I am using Python 3.5.6, Lua 5.1.4, and Linux.

1
Does python /path/to/python_script.py work in the shell? Also isn't a way to see if os.execute failed? - CristiFati
@CristiFati yes! - Louise Cullen
@CristiFati I don't know how to see if os.execute failed - Louise Cullen
lua.org/manual/5.1/manual.html#pdf-os.execute covers values returned by os.execute - Nifim
Just a guess, but maybe this is an environment where a shell is not available? Try using the full path to the Python executable instead of just "python", and see if that works. - Jack Taylor

1 Answers

1
votes

Firstly, to address you question about checking the status from os.execute: this function returns a a status code, which is system dependent (https://www.lua.org/manual/5.1/manual.html#pdf-os.execute). I tried to handle an invalid command by recording this status code, but found it to be somewhat unhelpful; additionally, the shell itself printed an error message.

os.execute("hello") -- 'hello' is not a shell command.
> sh: 1: hello: not found

This error message from the shell was not being caught and read by my Lua script, but was instead being sent directly to stderr. (Good reference about that: https://www.jstorimer.com/blogs/workingwithcode/7766119-when-to-use-stderr-instead-of-stdout.)

I found an interesting solution for catching any error output using temp files.

tmpname = os.tmpname()
os.execute(string.format("hello 2> %s", tmpname))
for line in io.lines(tmpname) do
    print("line = " .. line)
end

This prints: line = sh: 1: hello: not found, which is the error described earlier. os.execute should also return the status of the command like this:

a, b, c = os.execute("echo hello")
> hello
print(a, b, c)
> true exit 0
d, e, f = os.execute("hello") -- An invalid command
> sh: 1: hello: not found
print(d, e, f)
> nil exit 127

In this example, c and f are the exit statuses of their respective commands. If the previous command, i.e. executing your Python script, failed, then the exit status should be non-zero.

To address your primary question regarding Python, I would double-check the path to the script--always a good idea to start with a simple sanity check. Consider using string.format to assemble the command like this:

command = string.format("python %s %i", tostring(path), tonumber(subjectId))
os.execute(command)

Also, it would be helpful to know which version of Lua/Python you are using, and perhaps your system as well.

EDIT: depending on whether or not you need them to remain for a bit, you should remove any temp files generated by os.tmpname with os.remove. I also attempted to replicate your situation with a simple test, and I had no trouble executing the Python script with os.execute in a Lua script located in a different directory.

For reference, this is the Lua script, called test.lua, I created in a temp directory called /tmp/throwaway:

#!/usr/bin/lua

local PATH_TO_PY_FILE = "/tmp/py/foo.py"

local function fprintf(fil, formal_arg, ...)
    fil:write(string.format(formal_arg, ...))
    return
end

local function printf(formal_arg, ...)
    io.stdout:write(string.format(formal_arg, ...))
    return
end

local function foo(...)
    local t = {...}
    local cmd = string.format("python3 %s %s", PATH_TO_PY_FILE, table.concat(t, " "))
    local filename = os.tmpname()
    local a, b, status = os.execute(string.format("%s 2> %s", cmd, filename))

    printf("status = %i\n", status)

    local num = 1
    for line in io.lines(filename) do
        printf("line %i = %s\n", num line)
        num = num + 1
    end

    os.remove(filename)

    return
end

local function main(argc, argv)
    foo()
    foo("hello", "there,", "friend")
    return 0
end
main(#arg, arg)

(Please forgive my C-style main function, haha.)

In a separate temp directory, called /tmp/py, I created a Python file that looks like this:

import sys

def main():
    for arg in sys.argv:
        print(arg)

if __name__ == '__main__':
    main()

The Lua script's function foo takes a variable number of arguments and supplies them as command-line arguments to the Python script; the Python script then simply prints those arguments one-by-one. Again, this was just a simple test for proof of concept.

The temp file created by os.tmpname should be in /tmp; as for your files, that is, your Lua and Python scripts, you would make sure you know exactly where those files are located. Hopefully that can resolve your problem.

Also, you could supply the path to the Python script--or any other necessary files--to the Lua script as command-line arguments and then slightly modify the existing code.

$> ./test.lua path-to-python-file

Then simply modify foo in test.lua to accept the Python file's path as an argument:

local function foo(py_path, ...)
    local t = {...}
    local cmd = string.format("python3 %s %s", py_path, table.concat(t, " "))
    -- Everything else should remain the same.
end