Launching external programs from Julia

I’ve been trying to figure out how to launch an external program from Julia, and I am stumped.

In Python, I can do this:

os.system("exec python -m PyQt5.uic.pyuic evaluate.ui -o ui_Evaluate.py -x")

I’ve tried most of the examples in this thread: Better support for running external commands - #25 by StevenSiew

…but none of them work.

For example, even a simple line like this

run(Cmd(`exec python`))

gives me an error:

ERROR: IOError: could not spawn `exec python`: no such file or directory (ENOENT)

or even

run(Cmd(`python`))
ERROR: IOError: could not spawn `python`: no such file or directory (ENOENT)

The “bashit()” example in the above mentioned thread gives the same error.

Finally, I decided to try to use PyCall, which should allow me to use the same code I’ve successfully been using in Python. Instead…

os = pyimport("os")
os.system("exec python -m PyQt5.uic.pyuic evaluate.ui -o ui_Evaluate.py -x")

which yields: sh: line 0: exec: python: not found

Yet, that works in Python, and it works in the command line. So why can’t python be found when calling os.system() from Julia via PyCall? After reading the documentation for Python’s os.system(), apparrently it just calls “Standard C function system()”. So why not skip Python and use ccall instead?

@ccall system("exec python -m PyQt5.uic.pyuic evaluate.ui -o ui_Evaluate.py -x"::Cstring)::Cstring

Failure: sh: line 0: exec: python: not found

So what am I doing wrong? Why does system() work in Python, but but gives me grief when called from Julia, using either PyCall or CCall?

It means the python executable is not in the PATH environment variable, in the environment that launched Julia. Which OS are you using?

This isn’t the problem stumping you, but

is redundant.

julia> typeof(`python`)
Cmd

julia> typeof(Cmd(`python`))
Cmd

julia> Cmd(`python`) == `python`
true

julia> run(`python`)
Python 3.10.11 (tags/v3.10.11:7d4cc5a, Apr  5 2023, 00:38:17) [MSC v.1929 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> ^Z

It’s like saying String("python")

I’m using MacOS and VSCode. Do I need to set this in VSCode, or somewhere else?

Are you 100% sure you have an executable called python in the first place? On many systems it’d be called python3

Yep. When I type “python” in the terminal, I get:

Python 3.10.16 | packaged by conda-forge | (main, Dec  5 2024, 14:20:01) [Clang 18.1.8 ] on darwin
Type "help", "copyright", "credits" or "license" for more information.

Are you on Windows? Can you try this in Julia?

julia> run(`python.exe`)

And/or this?

julia> run(`python3.exe`)

I just tried replacing “python” with “python3”, and I get:

(ModuleNotFoundError: No module named 'PyQt5')

So, whatever environment that is launched with Julia, it’s not the same as the one used by Terminal.app.

If I type which Python3 into the terminal, I get the path to the executable:

eben60@Mac ~ % which python3
/opt/homebrew/bin/python3

Could you probably try

run(Cmd(`/opt/homebrew/bin/python3  -m PyQt5.uic.pyuic evaluate.ui -o ui_Evaluate.py -x `))

(replace by the actual path on your computer)

Update: I ran the following code from within Julia:

@ccall system("printf \"%s\n\" \$PATH"::Cstring)::Cstring

…and apparently the PATH variables used by VScode are not the ones used by Terminal.app or by Spyder.

EDIT: I did the same thing from within the bash shell in VScode, and it has the same environmental variables as Spyder and Terminal.app! Arggghh!

Edit 2: I also checked the REPL in VScode and by launching Julia from Terminal.app

All PATH variables present:
Terminal.app
Spyder
VScode bash shell
Julia (Terminal.app) REPL

Incomplete PATH variables:
running Julia program in VScode
VScode REPL.

ENV["PATH"]

is probably easier :wink:

3 Likes

On my mac, I get following

julia> c = Cmd(`/opt/homebrew/bin/python3 -c 'print("Hi world")' `);

julia> run(c)
Hi world
Process(`/opt/homebrew/bin/python3 -c 'print("Hi world")'`, ProcessExited(0))

julia> c1 = Cmd(`python -c 'print("Hi world")' `);

julia> run(c1)
xcode-select: Failed to locate 'python', requesting installation of command line developer tools.
ERROR: failed process: Process(`python -c 'print("Hi world")'`, ProcessExited(72)) [72]

Stacktrace:
 [1] pipeline_error
   @ ./process.jl:598 [inlined]
 [2] run(::Cmd; wait::Bool)
   @ Base ./process.jl:513
 [3] run(::Cmd)
   @ Base ./process.jl:510
 [4] top-level scope
   @ REPL[9]:1

julia> c2 = Cmd(`python3 -c 'print("Hi world")' `);

julia> run(c2)
Hi world
Process(`python3 -c 'print("Hi world")'`, ProcessExited(0))

I think I had remapped Python to Python3,

And its not that it can’t find Python, but that it is finding the wrong Python. Since it also has the wrong PATH variable, I’m guessing that it’s finding the default Apple Python installation (which is why it can’t find QT).

The solution was to go into VScode’s settings.json and change this line from false to true:

"terminal.integrated.inheritEnv": true,
3 Likes