mixed_sub/
lib.rs

1use pyo3::prelude::*;
2use pyo3_stub_gen::{define_stub_info_gatherer, derive::*};
3
4// Classes that can be cross-referenced between modules (from mixed_sub_import_type)
5#[gen_stub_pyclass]
6#[pyclass(module = "mixed_sub.main_mod")]
7#[derive(Debug, Clone)]
8struct A {
9    x: usize,
10}
11
12#[gen_stub_pymethods]
13#[pymethods]
14impl A {
15    fn show_x(&self) {
16        println!("x = {}", self.x);
17    }
18}
19
20#[gen_stub_pyfunction(module = "mixed_sub.main_mod")]
21#[pyfunction]
22fn create_a(x: usize) -> A {
23    A { x }
24}
25
26// Class without explicit module specification
27#[gen_stub_pyclass]
28#[pyclass]
29#[derive(Debug, Clone)]
30struct B {
31    x: usize,
32}
33
34#[gen_stub_pymethods]
35#[pymethods]
36impl B {
37    fn show_x(&self) {
38        println!("x = {}", self.x);
39    }
40}
41
42#[gen_stub_pyfunction]
43#[pyfunction]
44fn create_b(x: usize) -> B {
45    B { x }
46}
47
48// Original functions from mixed_sub
49#[gen_stub_pyfunction(module = "mixed_sub.main_mod.mod_a")]
50#[pyfunction(name = "greet_a")]
51pub fn greet_a() {
52    println!("Hello from mod_A!")
53}
54
55#[gen_stub_pyfunction(module = "mixed_sub.main_mod")]
56#[pyfunction(name = "greet_main")]
57pub fn greet_main() {
58    println!("Hello from main_mod!")
59}
60
61#[gen_stub_pyfunction(module = "mixed_sub.main_mod.mod_b")]
62#[pyfunction(name = "greet_b")]
63pub fn greet_b() {
64    println!("Hello from mod_B!")
65}
66
67// Class C in mod_a that references A and B (demonstrates cross-module type references)
68#[gen_stub_pyclass]
69#[pyclass(module = "mixed_sub.main_mod.mod_a")]
70#[derive(Debug)]
71struct C {
72    a: A,
73    b: B,
74}
75
76#[gen_stub_pymethods]
77#[pymethods]
78impl C {
79    fn show_x(&self) {
80        println!("a.x:");
81        self.a.show_x();
82        println!("b.x:");
83        self.b.show_x();
84    }
85}
86
87#[gen_stub_pyfunction(module = "mixed_sub.main_mod.mod_a")]
88#[pyfunction]
89fn create_c(a: A, b: B) -> C {
90    C { a, b }
91}
92
93// Simple class in mod_b (from mixed_sub)
94#[gen_stub_pyclass]
95#[pyclass(module = "mixed_sub.main_mod.mod_b")]
96#[derive(Debug)]
97struct D {
98    x: usize,
99}
100
101#[gen_stub_pymethods]
102#[pymethods]
103impl D {
104    fn show_x(&self) {
105        println!("x = {}", self.x);
106    }
107}
108
109#[gen_stub_pyfunction(module = "mixed_sub.main_mod.mod_b")]
110#[pyfunction]
111fn create_d(x: usize) -> D {
112    D { x }
113}
114
115// Function in int submodule to test namespace collision
116#[gen_stub_pyfunction(module = "mixed_sub.main_mod.int")]
117#[pyfunction]
118fn dummy_int_fun(x: usize) -> usize {
119    x
120}
121
122// Test function with both module and python parameters (bug reproduction case)
123// This should be placed in mod_a submodule
124#[gen_stub_pyfunction(
125    module = "mixed_sub.main_mod.mod_a",
126    python = r#"
127    import typing
128
129    def test_module_with_python(x: typing.Generator[int, None, None]) -> int:
130        """Test function with both module and python parameters"""
131"#
132)]
133#[pyfunction]
134fn test_module_with_python(_x: &Bound<PyAny>) -> PyResult<usize> {
135    Ok(42)
136}
137
138#[pymodule]
139fn main_mod(m: &Bound<PyModule>) -> PyResult<()> {
140    // Add classes and functions to main module
141    m.add_class::<A>()?;
142    m.add_class::<B>()?;
143    m.add_function(wrap_pyfunction!(create_a, m)?)?;
144    m.add_function(wrap_pyfunction!(create_b, m)?)?;
145    m.add_function(wrap_pyfunction!(greet_main, m)?)?;
146
147    // Add submodules
148    mod_a(m)?;
149    mod_b(m)?;
150    int_mod(m)?;
151    Ok(())
152}
153
154fn mod_a(parent: &Bound<PyModule>) -> PyResult<()> {
155    let py = parent.py();
156    let sub = PyModule::new(py, "mod_a")?;
157    sub.add_class::<C>()?;
158    sub.add_function(wrap_pyfunction!(greet_a, &sub)?)?;
159    sub.add_function(wrap_pyfunction!(create_c, &sub)?)?;
160    sub.add_function(wrap_pyfunction!(test_module_with_python, &sub)?)?;
161    parent.add_submodule(&sub)?;
162    Ok(())
163}
164
165fn mod_b(parent: &Bound<PyModule>) -> PyResult<()> {
166    let py = parent.py();
167    let sub = PyModule::new(py, "mod_b")?;
168    sub.add_class::<D>()?;
169    sub.add_function(wrap_pyfunction!(greet_b, &sub)?)?;
170    sub.add_function(wrap_pyfunction!(create_d, &sub)?)?;
171    parent.add_submodule(&sub)?;
172    Ok(())
173}
174
175/// A dummy module to test namespace collision with built-in 'int'
176fn int_mod(parent: &Bound<PyModule>) -> PyResult<()> {
177    let py = parent.py();
178    let sub = PyModule::new(py, "int")?;
179    sub.add_function(wrap_pyfunction!(dummy_int_fun, &sub)?)?;
180    parent.add_submodule(&sub)?;
181    Ok(())
182}
183
184// Test gen_function_from_python! with module parameter
185use pyo3_stub_gen::inventory::submit;
186
187submit! {
188    gen_function_from_python! {
189        module = "mixed_sub.main_mod.mod_b",
190        r#"
191        import typing
192
193        def test_submit_with_module(values: typing.List[int]) -> int:
194            """Test function defined with gen_function_from_python! and module parameter"""
195        "#
196    }
197}
198
199define_stub_info_gatherer!(stub_info);
200
201/// Test of unit test for testing link problem
202#[cfg(test)]
203mod test {
204    #[test]
205    fn test() {
206        assert_eq!(2 + 2, 4);
207    }
208}