#![cfg_attr(
docsrs,
feature(doc_cfg, doc_auto_cfg, doc_cfg_hide),
doc(cfg_hide(doc))
)]
#[cfg(feature = "standalone")]
pub mod standalone;
use pyo3::{
exceptions::PyTypeError,
prelude::*,
types::{PyCFunction, PyDict, PyModule, PyTuple},
wrap_pymodule,
};
use pyo3_utils::{
from_py_dict::{derive_from_py_dict, FromPyDict as _, NotRequired},
py_wrapper::{PyWrapper, PyWrapperT2},
};
use pytauri_core::{ext_mod::PyAppHandleExt as _, tauri_runtime::Runtime, utils::TauriError};
pub use pytauri_core::{ext_mod, pytauri_plugins};
type TauriBuilder = tauri::Builder<Runtime>;
type TauriContext = tauri::Context<Runtime>;
#[non_exhaustive]
pub struct BuilderArgs {
invoke_handler: Option<PyObject>,
setup: NotRequired<PyObject>,
plugins: NotRequired<Vec<Py<ext_mod::plugin::Plugin>>>,
}
derive_from_py_dict!(BuilderArgs {
invoke_handler,
#[pyo3(default)]
setup,
#[pyo3(default)]
plugins,
});
impl BuilderArgs {
fn from_kwargs(kwargs: Option<&Bound<'_, PyDict>>) -> PyResult<Self> {
match kwargs {
Some(kwargs) => Ok(BuilderArgs::from_py_dict(kwargs)?),
None => Err(PyTypeError::new_err(
"Missing required `**kwargs` arguments `BuilderArgs`",
)),
}
}
fn apply_to_builder(self, py: Python<'_>, mut builder: TauriBuilder) -> PyResult<TauriBuilder> {
let Self {
invoke_handler,
setup,
plugins,
} = self;
if let Some(invoke_handler) = invoke_handler {
builder = builder.plugin(tauri_plugin_pytauri::init(invoke_handler.clone_ref(py)));
}
if let Some(setup) = setup.0 {
builder = builder.setup(move |app| {
Python::with_gil(|py| {
let app_handle = app.get_or_init_py_app_handle(py)?;
setup.call1(py, (app_handle,))?;
Ok(())
})
});
}
if let Some(plugins) = plugins.0 {
for plugin in plugins {
let plugin = plugin.get().into_tauri()??;
builder = builder.plugin_boxed(plugin);
}
}
Ok(builder)
}
}
#[pyclass(frozen, unsendable)]
#[non_exhaustive]
pub struct Builder(pub PyWrapper<PyWrapperT2<TauriBuilder>>);
impl Builder {
fn new(builder: TauriBuilder) -> Self {
Self(PyWrapper::new2(builder))
}
}
#[pymethods]
impl Builder {
#[pyo3(signature = (context, **kwargs))]
fn build(
&self,
py: Python<'_>,
context: Py<ext_mod::Context>,
kwargs: Option<&Bound<'_, PyDict>>,
) -> PyResult<ext_mod::App> {
let context = context.get().0.try_take_inner()??;
let args = BuilderArgs::from_kwargs(kwargs)?;
let mut builder = self.0.try_take_inner()??;
builder = args.apply_to_builder(py, builder)?;
let app = builder.build(context).map_err(TauriError::from)?;
ext_mod::App::try_build(py, app)
}
}
pub fn pymodule_export(
parent_module: &Bound<'_, PyModule>,
context_factory: impl Fn(&Bound<'_, PyTuple>, Option<&Bound<'_, PyDict>>) -> PyResult<TauriContext>
+ Send
+ 'static,
builder_factory: impl Fn(&Bound<'_, PyTuple>, Option<&Bound<'_, PyDict>>) -> PyResult<TauriBuilder>
+ Send
+ 'static,
) -> PyResult<()> {
let py = parent_module.py();
let builder_factory =
PyCFunction::new_closure(py, Some(c"builder_factory"), None, move |args, kwargs| {
builder_factory(args, kwargs).map(Builder::new)
})?;
let context_factory =
PyCFunction::new_closure(py, Some(c"context_factory"), None, move |args, kwargs| {
context_factory(args, kwargs).map(ext_mod::Context::new)
})?;
let pytauri_module: Py<PyModule> = wrap_pymodule!(ext_mod)(py);
let pytauri_module = pytauri_module.bind(py);
pytauri_module.add_function(builder_factory)?;
pytauri_module.add_function(context_factory)?;
pytauri_module.add_class::<Builder>()?;
let pytauri_plugins_module = wrap_pymodule!(pytauri_plugins)(py);
let pytauri_plugins_module = pytauri_plugins_module.bind(py);
parent_module.add_submodule(pytauri_module)?;
parent_module.add_submodule(pytauri_plugins_module)?;
Ok(())
}