nautilus_pyo3/
lib.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Posei Systems Pty Ltd. All rights reserved.
3//  https://poseitrader.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#![warn(rustc::all)]
17#![deny(unsafe_code)]
18#![deny(nonstandard_style)]
19#![deny(missing_debug_implementations)]
20#![deny(clippy::missing_errors_doc)]
21#![deny(clippy::missing_panics_doc)]
22#![deny(rustdoc::broken_intra_doc_links)]
23
24use pyo3::prelude::*;
25
26/// We modify sys modules so that submodule can be loaded directly as
27/// import supermodule.submodule
28///
29/// Also re-exports all submodule attributes so they can be imported directly from `nautilus_pyo3`
30/// refer: <https://github.com/PyO3/pyo3/issues/2644>
31#[pymodule]
32fn nautilus_pyo3(py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
33    let sys = PyModule::import(py, "sys")?;
34    let modules = sys.getattr("modules")?;
35    let sys_modules: &Bound<'_, PyAny> = modules.downcast()?;
36    let module_name = "posei_trader.core.nautilus_pyo3";
37
38    // Set pyo3_nautilus to be recognized as a subpackage
39    sys_modules.set_item(module_name, m)?;
40
41    let n = "core";
42    let submodule = pyo3::wrap_pymodule!(nautilus_core::python::core);
43    m.add_wrapped(submodule)?;
44    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
45    re_export_module_attributes(m, n)?;
46
47    let n = "common";
48    let submodule = pyo3::wrap_pymodule!(nautilus_common::python::common);
49    m.add_wrapped(submodule)?;
50    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
51    re_export_module_attributes(m, n)?;
52
53    let n = "cryptography";
54    let submodule = pyo3::wrap_pymodule!(nautilus_cryptography::python::cryptography);
55    m.add_wrapped(submodule)?;
56    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
57    re_export_module_attributes(m, n)?;
58
59    let n = "model";
60    let submodule = pyo3::wrap_pymodule!(nautilus_model::python::model);
61    m.add_wrapped(submodule)?;
62    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
63    re_export_module_attributes(m, n)?;
64
65    let n = "indicators";
66    let submodule = pyo3::wrap_pymodule!(nautilus_indicators::python::indicators);
67    m.add_wrapped(submodule)?;
68    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
69    re_export_module_attributes(m, n)?;
70
71    let n = "infrastructure";
72    let submodule = pyo3::wrap_pymodule!(nautilus_infrastructure::python::infrastructure);
73    m.add_wrapped(submodule)?;
74    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
75    re_export_module_attributes(m, n)?;
76
77    let n = "network";
78    let submodule = pyo3::wrap_pymodule!(nautilus_network::python::network);
79    m.add_wrapped(submodule)?;
80    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
81    re_export_module_attributes(m, n)?;
82
83    let n = "persistence";
84    let submodule = pyo3::wrap_pymodule!(nautilus_persistence::python::persistence);
85    m.add_wrapped(submodule)?;
86    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
87    re_export_module_attributes(m, n)?;
88
89    let n = "serialization";
90    let submodule = pyo3::wrap_pymodule!(nautilus_serialization::python::serialization);
91    m.add_wrapped(submodule)?;
92    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
93    re_export_module_attributes(m, n)?;
94
95    let n = "testkit";
96    let submodule = pyo3::wrap_pymodule!(nautilus_testkit::python::testkit);
97    m.add_wrapped(submodule)?;
98    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
99    re_export_module_attributes(m, n)?;
100
101    let n = "trading";
102    let submodule = pyo3::wrap_pymodule!(nautilus_trading::python::trading);
103    m.add_wrapped(submodule)?;
104    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
105    re_export_module_attributes(m, n)?;
106
107    // Adapters
108
109    let n = "coinbase_intx";
110    let submodule = pyo3::wrap_pymodule!(nautilus_coinbase_intx::python::coinbase_intx);
111    m.add_wrapped(submodule)?;
112    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
113    re_export_module_attributes(m, n)?;
114
115    let n = "databento";
116    let submodule = pyo3::wrap_pymodule!(posei_traderbento::python::databento);
117    m.add_wrapped(submodule)?;
118    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
119    re_export_module_attributes(m, n)?;
120
121    let n = "tardis";
122    let submodule = pyo3::wrap_pymodule!(nautilus_tardis::python::tardis);
123    m.add_wrapped(submodule)?;
124    sys_modules.set_item(format!("{module_name}.{n}"), m.getattr(n)?)?;
125    re_export_module_attributes(m, n)?;
126
127    Ok(())
128}
129
130fn re_export_module_attributes(
131    parent_module: &Bound<'_, PyModule>,
132    submodule_name: &str,
133) -> PyResult<()> {
134    let submodule = parent_module.getattr(submodule_name)?;
135    for item_name in submodule.dir()? {
136        let item_name_str: &str = item_name.extract()?;
137        if let Ok(attr) = submodule.getattr(item_name_str) {
138            parent_module.add(item_name_str, attr)?;
139        }
140    }
141
142    Ok(())
143}