i wanted to know how to use python script with tauri app, i tried a few things but failed i try to take an input from the user using html tag then want to pass it to python and then after the python code does the adding wanted to display the result back in the html page, i got confused how to municate the two of them(python and javascript) i saved my python script in the same directory as the html but when i click the button there is not response,
this is my python script
num1 = int(sys.argv[1])
num2 = int(sys.argv[2])
result = num1 + num2
print(str(result))
and this is the html part
<html>
<head>
<meta charset="UTF-8">
<title>My Tauri App</title>
</head>
<body>
<label for="num1">Enter number 1:</label>
<input type="number" id="num1">
<label for="num2">Enter number 2:</label>
<input type="number" id="num2">
<button id="addBtn">Add Numbers</button>
<div id="result"></div>
<script>
const { spawn } = require('child_process');
const addBtn = document.getElementById('addBtn');
const num1Input = document.getElementById('num1');
const num2Input = document.getElementById('num2');
const resultDiv = document.getElementById('result');
addBtn.addEventListener('click', () => {
const num1 = parseInt(num1Input.value);
const num2 = parseInt(num2Input.value);
const python = spawn('python', ['add_numbers.py', num1.toString(), num2.toString()]);
python.stdout.on('data', data => {
const result = data.toString().trim();
resultDiv.textContent = `Result: ${result}`;
});
python.stderr.on('data', error => {
console.error(error.toString());
});
});
</script>
</body>
</html>
i saved my python script in the same directory as the html but when i click the button there is not response,
i wanted to know how to use python script with tauri app, i tried a few things but failed i try to take an input from the user using html tag then want to pass it to python and then after the python code does the adding wanted to display the result back in the html page, i got confused how to municate the two of them(python and javascript) i saved my python script in the same directory as the html but when i click the button there is not response,
this is my python script
num1 = int(sys.argv[1])
num2 = int(sys.argv[2])
result = num1 + num2
print(str(result))
and this is the html part
<html>
<head>
<meta charset="UTF-8">
<title>My Tauri App</title>
</head>
<body>
<label for="num1">Enter number 1:</label>
<input type="number" id="num1">
<label for="num2">Enter number 2:</label>
<input type="number" id="num2">
<button id="addBtn">Add Numbers</button>
<div id="result"></div>
<script>
const { spawn } = require('child_process');
const addBtn = document.getElementById('addBtn');
const num1Input = document.getElementById('num1');
const num2Input = document.getElementById('num2');
const resultDiv = document.getElementById('result');
addBtn.addEventListener('click', () => {
const num1 = parseInt(num1Input.value);
const num2 = parseInt(num2Input.value);
const python = spawn('python', ['add_numbers.py', num1.toString(), num2.toString()]);
python.stdout.on('data', data => {
const result = data.toString().trim();
resultDiv.textContent = `Result: ${result}`;
});
python.stderr.on('data', error => {
console.error(error.toString());
});
});
</script>
</body>
</html>
i saved my python script in the same directory as the html but when i click the button there is not response,
Share Improve this question asked Apr 2, 2023 at 17:38 Faiza AbdellaFaiza Abdella 811 gold badge1 silver badge2 bronze badges 2- Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Community Bot Commented Apr 3, 2023 at 2:30
- You can use Eel library to use Python to build web app. – Dinh Quang Tuan Commented Jul 21, 2023 at 22:37
5 Answers
Reset to default 5I am building an app utilising Tauri, Python and React. You can spawn the python instance as a "sidecar" as they're called in the Tauri platform.
Tauri offers several ways to municate between tauri-sidecar & tauri-react frontend.
You may find documentation on embedding binaries as a sidecar to the Tauri app here; https://tauri.app/v1/guides/building/sidecar/
Once you build your python script into a standalone executable using PyInstaller, you can place it in your project folder, and then initiate that as a sidecar executable.
Once you initiate the sidecar; at the very simplest, you can listen to the stdout of the python executable, from the tauri app.
let (mut rx, mut child) = Command::new_sidecar("pythonexecutablename")
.expect("failed to create `pythonexecutablename` binary mand")
.spawn()
.expect("Failed to spawn sidecar");
tauri::async_runtime::spawn(async move {
let main_window = app.get_window("main").unwrap();
while let Some(event) = rx.recv().await {
if let CommandEvent::Stdout(line) = event {
println!("Output from sidecar mand: {}", line);
if line.contains("MESSAGE:STARTED") {
main_window
.emit("sidecar-ready", Some(()))
.expect("failed to emit event");
}
main_window
.emit("message", Some(format!("'{}'", line)))
.expect("failed to emit event");
child.write("message from Rust\n".as_bytes()).unwrap();
}
}
});
In a similar fashion, you can also municate between the React app and the Tauri app as well.
import { emit, listen } from "@tauri-apps/api/event";
import { invoke } from "@tauri-apps/api/tauri";
invoke("is_app_ready").then((message) => {
console.log("RN - tauri app responded : ", message);
if (message === true) {
// Call listenUp when sidecar is ready
initiateListening();
} else {
const handler = listen("sidecar-ready", (event) => {
initiateListening();
});
}
});
I personally wouldn't depend heavily on the specialised munication interface provided by the Tauri API, because you never know when you may switch your UI layer, or have another user interface for the backend, so once I plete the initialisation and initial handshake, I start an SSE endpoint (server-side sent events) directly to the python backend. Then listen to that from the react app.
You basically have two options: use a Tauri sidecar (i.e. embedded executable), or simply call Python from Rust via PyO3.
At the end of the day, one way or another, you're running a Python interpreter, and then municating with it. The sidecar lets you call from both the JavaScript front-end and the Rust back-end; PyO3 lets you call from the Rust back-end, but in a more convenient way, since it's meant for calling Python specifically, not just any binary.
Using Tauri with PyO3 can also be done, but both take some work to setup and started (in Rust no less). Either way, sidecar or PyO3, the python interpreter is needed in the binary.
Using PyO3, setup in Rust is needed for linker into Python interpreter and path/stdlib dir, which you may find details from: https://pyo3.rs/v0.10.1/python_from_rust.
And between html/vanilla JS with Tauri, the tauri::mand
should be added in Rust and Tauri's invoke
API should be added in JS , a simple guide may be find the later part of this:
https://tauri.app/v1/guides/getting-started/setup/html-css-js
For which, the main.rs
would be like so:
fn main() {
let app = tauri::Builder::default().setup(|app| {
Ok(())
});
app.invoke_handler(tauri::generate_handler![
add_numbers,
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
#[tauri::mand(rename_all = "snake_case")]
fn add_numbers(num1: i32, num2: i32) -> String {
let pysrc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "./relative_path_to_python_script.py"));
let py_res = Python::with_gil(|py| -> PyResult<Py<PyAny>> {
let app: Py<PyAny> = PyModule::from_code(py, pysrc, "", "")?
.getattr("add_numbers")?
.into();
app.call1(py, (num1, num2))
});
dbg!(&py_res);
match py_res {
Ok(py) => py.to_string(),
Err(e) => {
let err_string = e.to_string();
err_string
}
}
}
And the html script tag:
<script>
// access the pre-bundled global API functions
const { invoke } = window.__TAURI__.tauri
window.addEventListener("change", callPy)
function callPy() {
const num1Value = document.getElementById('num1').value;
const num2Value = document.getElementById('num2').value;
console.log([num1Value, num2Value])
invoke('add_numbers', { num1: parseInt(num1Value), num2: parseInt(num2Value) })
.then((response) => {
window.answer.innerHTML = response
})
}
</script>
A working example, with both implemented, can be found on my github repo (use cargo tauri dev
to run) github example.
But for a quick and easy way to wrap a Web GUI around python, the python-eel library may be the way to go: https://github./python-eel/Eel
[Edit] For bundled build (with stdlib/ site-packages), the pyo3 linker points the corresponding python paths to current directory, e.g. where stdlib should be copied to (below code shows the paths after pyo3 linker). (Further steps could be done in adopting the approach of how pyinstaller finds and bundles dependencies (https://pyinstaller/en/stable/operating-mode.html))
Python path configuration:
PYTHONHOME = (not set)
PYTHONPATH = (not set)
program name = 'python'
isolated = 0
environment = 1
user site = 1
safe_path = 0
import site = 1
is in build tree = 0
stdlib dir = '<current directory>\Lib'
sys._base_executable = '<current directory>\\<exe_name>.exe'
sys.base_prefix = '<current directory>'
sys.base_exec_prefix = '<current directory>'
sys.platlibdir = 'DLLs'
sys.executable = '<current directory>\\<exe_name>.exe'
sys.prefix = '<current directory>'
sys.exec_prefix = '<current directory>'
sys.path = [
'<current directory>\\python311.zip',
'<current directory>',
'<current directory>\\Lib',
]
There is also now tauri-plugin-python to run python code in the tauri backend. This doesn't spawn a new python process on each click but creates a RustPython / PyO3 python interpreter in tauri, which then parses and executes the python code during runtime. The python process doesn't end on each click, so you can also use persistent globals in your python code.
This mostly simplifies python usage in tauri. You don't need to touch any rust code anymore, you just need to have rust&npm installed so you can pile your tauri app. To create a new tauri project using python, you can just use the tauri cli to add the python interpreter.
npm create tauri-app@latest #make sure you use tauri 2
cd tauri-app
npx @tauri-apps/cli add python
# modify src/index.html and add src-tauri/src-python/main.py
npm install
npm run tauri dev
<!-- src/index.html -->
<html>
<head>
<meta charset="UTF-8">
<title>My Tauri App</title>
</head>
<body>
<label for="num1">Enter number 1:</label>
<input type="number" id="num1">
<label for="num2">Enter number 2:</label>
<input type="number" id="num2">
<button id="addBtn">Add Numbers</button>
<div id="result"></div>
<script>
// this should be moved to a main.js file
const tauri = window.__TAURI__;
let num1Input;
let num2Input;
let resultDiv;
async function add_numbers() {
let num1 = parseInt(num1Input.value);
let num2 = parseInt(num2Input.value);
resultDiv.textContent = `Result: ` + await tauri.python.callFunction("add_numbers", [num1, num2]);
}
window.addEventListener("DOMContentLoaded", () => {
num1Input = document.querySelector("#num1");
num2Input = document.querySelector("#num2");
resultDiv = document.querySelector("#result");
document.querySelector("#addBtn").addEventListener("click", (e) => {
add_numbers();
e.preventDefault();
});
});
</script>
</body>
</html>
# src-tauri/src-python/main.py
_tauri_plugin_functions = ["add_numbers"] # allow function(s) to be callable from UI
print("initialized python")
def add_numbers(num1, num2):
result = str(num1 + num2)
print(result)
return "from python: " + result
Disclaimer: I am the author of the python plugin.
Disclaimer
What you are asking for, can be achieved, but I will assume that you are a beginner dev, since you want to use python alongside HTML.
With that in mind, let me tell you that this is a horrible idea.
Yes, it isn't impossible, but it has no real benefit to it.
You should be using JavaScript or TypeScript in the frontend part of a Tauri app.
Answer
If you kept reading, that means you are still interested in using python.
There are two ways of going about this.
- The first way is to use a library like PyScript that runs python natively on the browser.
- The second way has two options.
-
- Using RustPython as a library to evaluate python code, that alongside tauri's Command API would work.
-
- Bundling the python interpreter with your app, and spawn a child process from the Rust backend using tauri's Command API (what you were already attempting to do from the frontend)
Comment
I can't stress enough how bad of an idea this is, python was not made for the web, and you already have a great language as your backend...Rust.
When you find yourself in a situation where nothing works the way you want it to, you should think if what you want to do actually makes sense.