为 PyO3 项目自动生成 Python 类型存根:nautilus_trader 中的 pyo3-stub-gen 实战指南
2026/9/12 2:56:02 网站建设 项目流程

为 PyO3 项目自动生成 Python 类型存根:nautilus_trader 中的 pyo3-stub-gen 实战指南

【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader

导读

patches/pyo3-stub-gen/README.md记录了 Jij Inc. 开源的pyo3-stub-gencrate——一个面向 PyO3 与 maturin 项目的 Python 类型存根(*.pyi)生成器。它通过半自动化的方式,把 Rust 侧的 PyO3 绑定自动翻译成 Python 类型存根,并在默认翻译器无法覆盖的边缘场景提供手工覆写能力。在 nautilus_trader 仓库中,这套机制被完整落地:nautilus-pyo3crate 把全工作区各 crate 的 Python 绑定聚合到nautilus_trader._libnautilus单一扩展模块,再由pyo3-stub-gen生成整套python/nautilus_trader/下的.pyi存根。读完本文,你将掌握如何为 PyO3 项目接入 stub 生成、如何使用#[gen_stub_*]系列过程宏、如何通过python参数 /override_type/submit!手工修正复杂类型、如何用type_alias!定义语义化类型别名,以及如何集成mypy stubtest校验与 Sphinx 文档生成,最后还能看到 nautilus_trader 在生产规模下的工程化实践。

设计动机:为什么需要"半自动化"翻译

Rust 与 Python 的类型系统存在根本差异,加之过程宏的能力边界,从 Rust 代码自动、完整地翻译出 Python 存根在原理上并不可行。因此pyo3-stub-gen采用半自动化策略(对应 README Design 一节):

  • 提供一套默认翻译器,覆盖"大多数"(most)而非"全部"(all)场景;
  • 同时提供手工指定翻译的途径,让用户只对默认翻译不生效的边缘情况做局部修正;
  • 手工翻译可以与默认翻译器的产物合并集成,从而最大化默认翻译器的复用率。

整个 crate 家族分为两个部分:

  • pyo3-stub-gen:提供手工指定翻译的运行时机制(StubInfoinventory注册、type_alias!等);
  • pyo3-stub-gen-derive:基于pyo3-stub-gen的机制实现默认翻译器——即#[gen_stub_pyfunction]#[gen_stub_pyclass]#[gen_stub_pymethods]等过程宏。

从仓库内的 Cargo.toml 可以看到,pyo3-stub-gen0.20.0 的默认 feature 为eitherinfer_signaturenumpyordered-float,另有可选的rust_decimal;依赖上通过pyo3 >= 0.26inventory 0.3numpyserde等支撑类型翻译与信息收集,并用toml读取pyproject.toml配置。

[!NOTE] 最低支持 Python 版本为3.10,不要在 PyO3 配置中启用 3.9 或更早版本。

版本 0.15.0–0.17.1 曾无意中包含一个 LGPL 依赖,该依赖在 0.17.2 中移除,受影响版本已被 yank。

快速上手:给 PyO3 函数生成第一个.pyi

用过程宏注解 Rust 代码

pyo3-stub-gen提供#[gen_stub_pyfunction]等过程宏,与 PyO3 的#[pyfunction]配合使用。一个最简单的 PyO3 项目原本如下:

use pyo3::prelude::*; #[pyfunction] fn sum_as_string(a: usize, b: usize) -> PyResult<String> { Ok((a + b).to_string()) } #[pymodule] fn your_module_name(m: &Bound<PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; Ok(()) }

接入 stub 生成只需三处修改(对应 README Usage):

use pyo3::prelude::*; use pyo3_stub_gen::{derive::gen_stub_pyfunction, define_stub_info_gatherer}; #[gen_stub_pyfunction] // Proc-macro attribute to register a function to stub file generator. #[pyfunction] fn sum_as_string(a: usize, b: usize) -> PyResult<String> { Ok((a + b).to_string()) } #[pymodule] fn your_module_name(m: &Bound<PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(sum_as_string, m)?)?; Ok(()) } // Define a function to gather stub information. define_stub_info_gatherer!(stub_info);

其中define_stub_info_gatherer!(stub_info)会生成一个名为stub_info的函数,用于在运行时收集所有被注册的 stub 信息。

[!NOTE]#[gen_stub_pyfunction]宏必须放在#[pyfunction]之前

nautilus_trader 仓库里,nautilus-pyo3crate(crates/pyo3/Cargo.toml)正是这种模式的产品级实例:它以lib.name = "nautilus_pyo3"crate-type = ["rlib", "cdylib"]聚合全工作区各 crate 的pythonfeature 绑定,再通过#[pymodule] fn _libnautilus(...)(见 crates/pyo3/src/lib.rs#L79-L307)把 analysis、core、common、model、trading、backtest 以及 binance、bybit、okx 等 20 余个适配器子模块逐一wrap_pymodule!后挂载到nautilus_trader._libnautilus命名空间,并写入sys.modules使它们可作为子模块导入。

生成存根文件的可执行目标

接着创建一个可执行目标src/bin/stub_gen.rs,调用stub_info()并触发生成(对应 README 对应小节):

use pyo3_stub_gen::Result; fn main() -> Result<()> { // `stub_info` is a function defined by `define_stub_info_gatherer!` macro. let stub = pure::stub_info()?; stub.generate()?; Ok(()) }

Cargo.toml[lib]段同时声明rlibcdylib

[lib] crate-type = ["cdylib", "rlib"]

然后运行:

cargo run --bin stub_gen

该命令会在项目根生成存根文件(如pure.pyi)。maturin 会自动发现该存根并打包进 wheel——对应 maturin 的 "adding python type information" 项目布局约定。

nautilus_trader 中的对应实现位于 crates/pyo3/bin/stub_gen.rs,且[bin] name = "python-stub-gen"在 crates/pyo3/Cargo.toml#L176-L181 中声明。nautilus_pyo3::stub_info()(见 crates/pyo3/src/lib.rs#L326-L335)与文档示例略有不同:它不依赖 crate 内部的 pyproject,而是向上定位工作区根目录并显式加载python/pyproject.toml,再调用pyo3_stub_gen::StubInfo::from_pyproject_toml(&pyproject_path)完成初始化——这正是多 crate 工作区聚合绑定的必然形态。

#[gen_stub(skip)]:从存根中排除目标

对不想出现在.pyi文件中的函数或方法,使用#[gen_stub(skip)]

use pyo3::prelude::*; use pyo3_stub_gen::derive::*; #[gen_stub_pyclass] #[pyclass] struct MyClass; #[gen_stub_pymethods] #[pymethods] impl MyClass { #[gen_stub(skip)] fn internal_method(&self) { // This method will not appear in the .pyi file } }

#[gen_stub(default = xx)]:为 getter/setter/类属性指定默认值

对 getter、setter 与类属性,可以用default参数指定会出现在存根中的默认值:

use pyo3::prelude::*; use pyo3_stub_gen::derive::*; #[gen_stub_pyclass] #[pyclass] struct Config { #[pyo3(get, set)] #[gen_stub(default = Config::default().timeout)] timeout: usize, } impl Default for Config { fn default() -> Self { Config { timeout: 30 } } } #[gen_stub_pymethods] #[pymethods] impl Config { #[getter] #[gen_stub(default = Config::default().timeout)] fn get_timeout(&self) -> usize { self.timeout } }

手工覆写:默认翻译器不够用时

当自动类型翻译结果不理想时,可用 Python 存根语法手工指定类型,共有两条主线、三种方法(对应 README Manual Overriding):

方法一:python参数整体覆写签名

当需要完整替换函数签名的 Python 表达时,用#[gen_stub_pyfunction(python = "...")]

use pyo3::prelude::*; use pyo3_stub_gen::derive::*; #[gen_stub_pyfunction(python = r#" import collections.abc import typing def fn_with_callback(callback: collections.abc.Callable[[str], typing.Any]) -> collections.abc.Callable[[str], typing.Any]: """Example using python parameter for complete override.""" "#)] #[pyfunction] pub fn fn_with_callback<'a>(callback: Bound<'a, PyAny>) -> PyResult<Bound<'a, PyAny>> { callback.call1(("Hello!",))?; Ok(callback) }

该方式的特点:

  • ✅ 对生成的存根拥有完整控制权;
  • ✅ 支持collections.abc.Callable等复杂类型;
  • ✅ 允许附带自定义 docstring;
  • ✅ import 语句会被自动抽取。

方法二:#[gen_stub(override_type(...))]局部覆写

当大多数类型翻译正确、仅个别参数需要调整时,用override_type覆写参数、用override_return_type覆写返回值:

use pyo3::prelude::*; use pyo3_stub_gen::derive::*; #[gen_stub_pyfunction] #[pyfunction] #[gen_stub(override_return_type(type_repr="collections.abc.Callable[[str], typing.Any]", imports=("collections.abc", "typing")))] pub fn get_callback<'a>( #[gen_stub(override_type(type_repr="collections.abc.Callable[[str], typing.Any]", imports=("collections.abc", "typing")))] cb: Bound<'a, PyAny>, ) -> PyResult<Bound<'a, PyAny>> { Ok(cb) }

该方式的特点:

  • ✅ 对单个类型进行细粒度控制;
  • ✅ 其余参数仍保持自动生成;
  • ✅ 明确标注哪些类型需要手工指定。

方法三:submit!宏独立提交定义

#[gen_stub_pyfunction]#[gen_stub_pyclass]内部会自动生成submit!块来注册类型信息;你也可以手工追加submit!块补充或覆写自动注册。当同一函数/方法存在多个类型签名时,生成器会自动在.pyi中输出@overload装饰器,让类型检查器正确识别多签名函数。

实现函数重载有两种途径:

  1. python_overload参数:随函数内联定义重载;
  2. submit!块:独立维护 stub 定义——尤其适合过程宏/代码生成场景。

函数重载(内联方式)

use pyo3::prelude::*; use pyo3_stub_gen::derive::*; // Define overloads inline with python_overload parameter #[gen_stub_pyfunction( python_overload = r#" @overload def process(x: int) -> int: """Process integer input""" "# )] #[pyfunction] pub fn process(x: f64) -> f64 { x + 1.0 }

生成的存根:

@overload def process(x: int) -> int: """Process integer input""" @overload def process(x: float) -> float: ... # Auto-generated from Rust

no_default_overload = true抑制自动生成(当运行时做动态类型分发、Rust 签名不具代表性时):

use pyo3::prelude::*; use pyo3_stub_gen::derive::*; #[gen_stub_pyfunction( python_overload = r#" @overload def func(x: int) -> int: ... @overload def func(x: str) -> str: ... "#, no_default_overload = true // Don't generate from Rust signature )] #[pyfunction] pub fn func(ob: Bound<PyAny>) -> PyResult<PyObject> { // Runtime type checking todo!() }

类方法重载(submit!方式)

use pyo3::prelude::*; use pyo3_stub_gen::{derive::*, inventory::submit}; #[gen_stub_pyclass] #[pyclass] pub struct Calculator {} #[gen_stub_pymethods] #[pymethods] impl Calculator { fn add(&self, x: f64) -> f64 { x + 1.0 } } // Alternative: Use submit! for method overloads (useful for proc-macro/code generation) submit! { gen_methods_from_python! { r#" class Calculator: @overload def add(self, x: int) -> int: """Add integer (overload)""" "# } }

submit!体系的核心收益:

  • ✅ 用python_overload参数内联定义重载;
  • ✅ 自动生成@overload装饰器;
  • ✅ 基于索引排序保证确定性顺序;
  • ✅ 为过程宏/代码生成场景提供submit!语法。

更进阶的类方法模式(完全手工提交方法签名、以及用#[gen_stub(skip)]混合过程宏与手工提交)可参考 README 指向的examples/pure/src/manual_submit.rs与 "Python Stub Syntax Support" 文档。

进阶:RustType标记在 Python 语法中引用 Rust 类型

在 Python stub 语法内部,可以直接用pyo3_stub_gen.RustType["TypeName"]引用 Rust 类型,其展开依赖该 Rust 类型对PyStubTypetrait 的实现:

use pyo3::prelude::*; use pyo3_stub_gen::{derive::*, inventory::submit}; #[pyfunction] pub fn sum_list(values: Vec<i32>) -> i32 { values.iter().sum() } submit! { gen_function_from_python! { r#" def sum_list(values: pyo3_stub_gen.RustType["Vec<i32>"]) -> pyo3_stub_gen.RustType["i32"]: """Sum a list of integers""" "# } }

RustType标记会自动展开为合适的 Python 类型:

  • RustType["Vec<i32>"]typing.Sequence[int](用于参数);
  • RustType["i32"]int(用于返回值)。

它尤其适用于:Vec<T>HashMap<K, V>等泛型;实现了PyStubType的自定义类型;以及需要保证 Rust 与 Python 类型映射一致性的场景。

何时选用哪种方法

场景推荐方法
复杂类型(如CallableProtocol方法一:python = "..."参数
覆写一两个参数方法二:#[gen_stub(override_type(...))]
函数重载(@overloadpython_overload = "..."参数
在 Python 语法中引用 Rust 类型RustType["..."]标记
完整替换函数签名方法一:python = "..."参数

类型别名:type_alias!gen_type_alias_from_python!

类型别名可以为复杂或频繁使用的类型定义语义化名称,提升存根可读性与可维护性(对应 README Type Aliases)。

基础用法

use pyo3_stub_gen::type_alias; use std::collections::HashMap; // Simple type alias type_alias!("your_module", SimpleAlias = Option<usize>); // Collection types type_alias!("your_module", StrIntMap = HashMap<String, i32>); // Nested option types type_alias!("your_module", MaybeString = Option<Option<String>>);

直接联合类型语法

type_alias!支持直接书写联合类型,大多数情况下无需单独的impl_stub_type!声明:

use pyo3_stub_gen::type_alias; // Simple union types type_alias!("your_module", NumberOrStringAlias = i32 | String); // Multiple types in a union type_alias!("your_module", TripleUnion = i32 | String | bool); // Unions of generic types type_alias!("your_module", GenericUnion = Option<i32> | Vec<String>); // Complex nested unions type_alias!("your_module", ComplexUnion = Option<Vec<i32>> | Option<Vec<String>>);

备选:与impl_stub_type!组合复用

若同一联合类型需要在多处引用,仍可采用两步式impl_stub_type!+type_alias!模式:

use pyo3_stub_gen::{impl_stub_type, type_alias}; // Define a reusable union type struct NumberOrString; impl_stub_type!(NumberOrString = i32 | String); // Use it in multiple type aliases type_alias!("your_module", NumberOrStringAlias = NumberOrString); type_alias!("your_module", AnotherAlias = NumberOrString);

生成输出与语法配置

类型别名在 Python 存根中以TypeAlias注解渲染(兼容 Python 3.11+):

from typing import TypeAlias __all__ = [ "MaybeDecimal", "NumberOrStringAlias", "SimpleAlias", "StrIntMap", "StructUnion", ] MaybeDecimal: TypeAlias = typing.Optional[DecimalHolder] NumberOrStringAlias: TypeAlias = builtins.int | builtins.str SimpleAlias: TypeAlias = typing.Optional[builtins.int] StrIntMap: TypeAlias = builtins.dict[builtins.str, builtins.int] StructUnion: TypeAlias = ComparableStruct | HashableStruct

默认生成的是 Python 3.12 之前的TypeAlias语法;若项目面向 Python 3.12+,可在pyproject.toml中开启type语句语法:

[tool.pyo3-stub-gen] use-type-statement = true

输出将变为:

type MyAlias = int | str

[!NOTE] 使用use-type-statement = true时,请确保项目最低 Python 版本为 3.12 或更高——type语句在更早版本中不可用。

用 Python 语法定义复杂别名

需要 Python 特定语法(如特定 import、复杂泛型、难以用PyStubType表达的类型)时,可用gen_type_alias_from_python!

use pyo3_stub_gen::derive::gen_type_alias_from_python; gen_type_alias_from_python!( "your_module", r#" import collections.abc from typing import TypeAlias CallbackType: TypeAlias = collections.abc.Callable[[str], None] "# );

解析器同时接受 3.12 前后两种语法,输出格式统一由use-type-statement配置控制。

类型别名是"仅存根"(stub-only)构造,运行时并不存在,纯粹服务于静态类型检查与 IDE 支持;同时它天然兼容自动__all__生成以及 mypy、pyright、ruff 等类型检查器。

质量保障:mypy stubtest 集成

mypy stubtest):

uv run stubtest your_module_name --ignore-missing-stub --ignore-disjoint-bases

PyO3/maturin 项目必需的标志

  • --ignore-missing-stub:maturin 会创建内部原生模块(.so文件)并向__init__.py再导出;stubtest 会为这些内部模块寻找存根,但实际并不存在(所有类型都在__init__.pyi中),该标志用于消除此类误报。
  • --ignore-disjoint-bases:PyO3 类在运行时属于 disjoint bases,而 pyo3-stub-gen 不会生成@typing.disjoint_base装饰器。

已知限制:嵌套子模块

stubtest 不适用于 PyO3 嵌套子模块。嵌套的#[pymodule]在运行时创建的是属性(attribute)而非可导入模块,而存根文件使用目录结构组织。对于含嵌套子模块的项目,需要对这些包禁用 stubtest。

nautilus_trader 的 python/generate_stubs.py 在生成完成后执行了一整套与之配套的存根后处理(post_process_stubs):修正文件头(# This file is automatically generated by pyo3_stub_gen)、按rename_all = "SCREAMING_SNAKE_CASE"重命名枚举变体、py_new -> __init__等方法重命名、从#[pyo3(signature = (...))]属性还原真实默认值(并安全地抑制"必选参数出现在带默认参数之后"的非法签名)、为缺失默认值的Optional参数补= None、对后向引用局部类的默认值替换为...以避免类体内非法运行时表达式、注入手写 Python 符号的再导出(如ReportProviderTearsheetChart等)、以及剥离 docstring(运行时__doc__才是唯一事实来源)。这些正是 stubtest 能在 nautilus_trader 数千个绑定上通过的必要工程支撑。

进阶:用同一份元数据生成 Sphinx API 文档

除了存根,pyo3-stub-gen 还能用同一份 Rust 类型元数据生成 Sphinx)。

配置

pyproject.toml中添加[tool.pyo3-stub-gen.doc-gen]段:

[tool.pyo3-stub-gen.doc-gen] output-dir = "docs/api" json-output = "api_reference.json" index-title = "API Reference"

src/bin/stub_gen.rs无需任何改动——只要存在该配置段,stub.generate()就会自动生成文档。可用选项:

选项类型默认值描述
output-dirPath"docs/api"生成文件输出目录(相对pyproject.toml
json-outputString"api_reference.json"JSON 数据文件名
separate-pagesBooleantrue每个模块生成独立.rst页面
index-titleString"{package} API Reference"index.rst标题
intro-messageString(默认简介文本)index.rst的简介文字(空字符串则省略)
contents-tableBooleanfalse显示模块内容汇总表

Sphinx 搭建

在开发依赖中加入 Sphinx 相关包:

[dependency-groups] dev = ["myst-parser", "sphinx", "sphinx-rtd-theme"]

创建docs/conf.py加载生成的扩展:

import sys from pathlib import Path # Add the API docs directory so Sphinx can find the generated extension sys.path.insert(0, str(Path(__file__).parent / "api")) project = "your_project" extensions = [ "pyo3_stub_gen_ext", # Generated extension — reads api_reference.json "sphinx.ext.intersphinx", # Enables cross-references to external projects ] intersphinx_mapping = { "python": ("https://docs.python.org/3", None), } html_theme = "sphinx_rtd_theme"

生成文件与构建

运行cargo run --bin stub_gen会在output-dir产出:

  • api_reference.json—— 结构化 API 数据(JSON 中间表示);
  • pyo3_stub_gen_ext.py—— 把 JSON 渲染为文档的 Sphinx 扩展;
  • index.rst—— 含 toctree 的目录页(separate-pages = true时);
  • <module>.rst—— 每个模块一页(separate-pages = true时)。

每个模块.rst只含一个由扩展展开的指令:

pure ==== .. pyo3-api:: pure

构建命令:

cargo run --bin stub_gen # Generate API data + Sphinx files uv run --with sphinx sphinx-build -W -b html docs docs/_build # Build HTML

生成的扩展提供两个 RST 指令:

  • .. pyo3-api:: module_name—— 渲染单个模块的 API 参考;
  • .. pyo3-api-package:: package_name—— 渲染包内所有模块。

Rust 文档注释(/// ...)会渲染为 MyST Markdown,支持交叉引用(:class:`ClassName`)、代码块、admonition 等 Sphinx/MyST 特性,因此myst-parser是必需的。README 还提示了单模块项目(examples/pure/docs/)与含子模块的多模块项目(examples/mixed/docs/)两套完整参考实现。

生产级实践:nautilus_trader 如何落地 stub 生成

nautilus_trader 将上述机制规模化,形成了一条可复现的存根生产线:

  1. 聚合绑定nautilus-pyo3(crates/pyo3/src/lib.rs)把所有 crate 的 Python 绑定收拢到单一_libnautilus扩展模块,并在 crates/pyo3/Cargo.toml#L20-L21 声明crate-type = ["rlib", "cdylib"],同时满足 stub 生成(rlib)与 wheel 构建(cdylib)两种用途。
  2. 生成入口cargo run --bin python-stub-gen(crates/pyo3/bin/stub_gen.rs)调用nautilus_pyo3::stub_info(),后者显式读取 python/pyproject.toml 并构造StubInfo(crates/pyo3/src/lib.rs#L326-L335)。
  3. 构建集成python/pyproject.toml[tool.maturin]指向../crates/pyo3/Cargo.tomlmodule-name = "nautilus_trader._libnautilus",并通过include = ["**/*.pyi"]把生成的存根打进 wheel;[build-system]使用maturin==1.15.0
  4. 脚本驱动与后处理:python/generate_stubs.py 既可作为独立脚本(python generate_stubs.py),也可作为自定义构建脚本(python generate_stubs.py build);它解析[tool.maturin]的 feature 列表(剔除extension-module并补入nautilus-interactive-brokers/gateway)后调用 stub 生成器,再执行类重定位(如把_libnautilus中的AmmTypeDexChain等迁回model模块)、__all__同步、配置门面存根生成、格式化与陈旧存根清理。
  5. 兼容性补丁:由于上游pyo3-stub-gen 0.20.0之后版本拒绝pymodule根之外的模块路径,而本仓库的gen_stub_*注解指向nautilus_trader包路径(位于nautilus_trader._libnautilus根之外),patches/README.md 明确说明该 crate 被固定在 0.20.0,并通过本地补丁适配pyo3 0.29.0src/util.rs中用cast::<T>()替换三处已移除的Bound<PyAny>::downcast::<T>()调用,src/exception.rs移除PyEnvironmentError/PyIOError的 stub 类型实现(PyO3 0.29 将两者别名到PyOSError,保留会造成重复 trait impl)。补丁刻意不改变存根布局、类重定位、模块命名与签名规范化等行为——这些仍由python/generate_stubs.py与固定的 0.20.0 代码控制。

这套链路回答了"一个工作区、几十个 crate、上千个绑定类如何产出可信的.pyi"这一问题:过程宏负责自动化翻译,python/override_type/submit!/type_alias!负责边缘修正,stubtest 负责校验,Sphinx doc-gen 负责文档化,而generate_stubs.py负责把这一切编排进构建管线。

结语与进一步阅读

pyo3-stub-gen的价值在于把"Python 类型存根"从手写维护的负担转化为"从 Rust 绑定半自动生成 + 边缘手工修正"的工程流程。其设计(默认翻译器 + 手工覆写 + 元数据合并)与 nautilus_trader 的规模化实践(聚合 crate、脚本化后处理、版本锁定与兼容性补丁)共同证明:即便面对 Rust/Python 类型系统差异与过程宏局限,仍然可以获得类型完整、IDE 友好、经 stubtest 校验的 Python API 层。

可以继续深入阅读的仓库文件:

  • patches/pyo3-stub-gen/README.md —— 本文的直接来源(用法、重载、类型别名、stubtest、Sphinx 文档生成);
  • patches/README.md —— 本仓库为何固定 0.20.0 并打补丁的决策记录;
  • patches/pyo3-stub-gen/src/lib.rs 与 patches/pyo3-stub-gen/src/stub_type.rs —— 核心StubInfo与类型翻译实现;
  • crates/pyo3/src/lib.rs 与 crates/pyo3/bin/stub_gen.rs —— 聚合绑定与生成入口;
  • python/generate_stubs.py —— 存根后处理与构建编排;
  • python/pyproject.toml —— maturin 与 stub 打包配置。

【免费下载链接】nautilus_traderProduction-grade Rust-native trading engine with deterministic event-driven architecture项目地址: https://gitcode.com/GitHub_Trending/na/nautilus_trader

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询