Skip to main content

nautilus_derive/python/
mod.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Python bindings from `pyo3`.
17
18pub mod config;
19pub mod enums;
20pub mod factories;
21
22use nautilus_common::factories::{ClientConfig, DataClientFactory, ExecutionClientFactory};
23use nautilus_core::python::{to_pyruntime_err, to_pyvalue_err};
24use nautilus_system::get_global_pyo3_registry;
25use pyo3::prelude::*;
26
27use crate::{
28    common::{
29        consts::{DERIVE, DERIVE_CLIENT_ID, DERIVE_VENUE},
30        enums::DeriveEnvironment,
31    },
32    config::{DeriveDataClientConfig, DeriveExecutionClientConfig},
33    factories::{DeriveDataClientFactory, DeriveExecutionClientFactory},
34};
35
36#[expect(clippy::needless_pass_by_value)]
37fn extract_derive_data_factory(
38    py: Python<'_>,
39    factory: Py<PyAny>,
40) -> PyResult<Box<dyn DataClientFactory>> {
41    match factory.extract::<DeriveDataClientFactory>(py) {
42        Ok(f) => Ok(Box::new(f)),
43        Err(e) => Err(to_pyvalue_err(format!(
44            "Failed to extract DeriveDataClientFactory: {e}"
45        ))),
46    }
47}
48
49#[expect(clippy::needless_pass_by_value)]
50fn extract_derive_exec_factory(
51    py: Python<'_>,
52    factory: Py<PyAny>,
53) -> PyResult<Box<dyn ExecutionClientFactory>> {
54    match factory.extract::<DeriveExecutionClientFactory>(py) {
55        Ok(f) => Ok(Box::new(f)),
56        Err(e) => Err(to_pyvalue_err(format!(
57            "Failed to extract DeriveExecutionClientFactory: {e}"
58        ))),
59    }
60}
61
62#[expect(clippy::needless_pass_by_value)]
63fn extract_derive_data_config(
64    py: Python<'_>,
65    config: Py<PyAny>,
66) -> PyResult<Box<dyn ClientConfig>> {
67    match config.extract::<DeriveDataClientConfig>(py) {
68        Ok(c) => Ok(Box::new(c)),
69        Err(e) => Err(to_pyvalue_err(format!(
70            "Failed to extract DeriveDataClientConfig: {e}"
71        ))),
72    }
73}
74
75#[expect(clippy::needless_pass_by_value)]
76fn extract_derive_exec_config(
77    py: Python<'_>,
78    config: Py<PyAny>,
79) -> PyResult<Box<dyn ClientConfig>> {
80    match config.extract::<DeriveExecutionClientConfig>(py) {
81        Ok(c) => Ok(Box::new(c)),
82        Err(e) => Err(to_pyvalue_err(format!(
83            "Failed to extract DeriveExecutionClientConfig: {e}"
84        ))),
85    }
86}
87
88/// Exposed through `nautilus_trader.adapters.derive`.
89///
90/// # Errors
91///
92/// Returns an error if any bindings fail to register with the Python module.
93#[pymodule]
94pub fn derive(_: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
95    m.add(stringify!(DERIVE), DERIVE)?;
96    m.add(stringify!(DERIVE_CLIENT_ID), *DERIVE_CLIENT_ID)?;
97    m.add(stringify!(DERIVE_VENUE), *DERIVE_VENUE)?;
98    m.add_class::<DeriveEnvironment>()?;
99    m.add_class::<DeriveDataClientConfig>()?;
100    m.add_class::<DeriveDataClientFactory>()?;
101    m.add_class::<DeriveExecutionClientConfig>()?;
102    m.add_class::<DeriveExecutionClientFactory>()?;
103
104    let registry = get_global_pyo3_registry();
105
106    if let Err(e) =
107        registry.register_factory_extractor(DERIVE.to_string(), extract_derive_data_factory)
108    {
109        return Err(to_pyruntime_err(format!(
110            "Failed to register Derive data factory extractor: {e}"
111        )));
112    }
113
114    if let Err(e) =
115        registry.register_exec_factory_extractor(DERIVE.to_string(), extract_derive_exec_factory)
116    {
117        return Err(to_pyruntime_err(format!(
118            "Failed to register Derive exec factory extractor: {e}"
119        )));
120    }
121
122    if let Err(e) = registry.register_config_extractor(
123        "DeriveDataClientConfig".to_string(),
124        extract_derive_data_config,
125    ) {
126        return Err(to_pyruntime_err(format!(
127            "Failed to register Derive data config extractor: {e}"
128        )));
129    }
130
131    if let Err(e) = registry.register_config_extractor(
132        "DeriveExecutionClientConfig".to_string(),
133        extract_derive_exec_config,
134    ) {
135        return Err(to_pyruntime_err(format!(
136            "Failed to register Derive exec config extractor: {e}"
137        )));
138    }
139
140    Ok(())
141}