2024-06-17 01:28:20 +00:00
|
|
|
#![cfg(feature = "macros")]
|
2024-02-24 13:50:18 +00:00
|
|
|
|
|
|
|
use pyo3::create_exception;
|
|
|
|
use pyo3::exceptions::PyException;
|
|
|
|
use pyo3::prelude::*;
|
2024-06-06 07:54:26 +00:00
|
|
|
use pyo3::sync::GILOnceCell;
|
2024-03-06 18:20:02 +00:00
|
|
|
#[cfg(not(Py_LIMITED_API))]
|
|
|
|
use pyo3::types::PyBool;
|
2024-02-24 13:50:18 +00:00
|
|
|
|
|
|
|
#[path = "../src/tests/common.rs"]
|
|
|
|
mod common;
|
|
|
|
|
2024-04-12 06:34:27 +00:00
|
|
|
mod some_module {
|
2024-04-16 20:12:18 +00:00
|
|
|
use pyo3::create_exception;
|
|
|
|
use pyo3::exceptions::PyException;
|
2024-04-12 06:34:27 +00:00
|
|
|
use pyo3::prelude::*;
|
|
|
|
|
|
|
|
#[pyclass]
|
|
|
|
pub struct SomePyClass;
|
2024-04-16 20:12:18 +00:00
|
|
|
|
|
|
|
create_exception!(some_module, SomeException, PyException);
|
2024-04-12 06:34:27 +00:00
|
|
|
}
|
|
|
|
|
2024-02-24 13:50:18 +00:00
|
|
|
#[pyclass]
|
|
|
|
struct ValueClass {
|
|
|
|
value: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[pymethods]
|
|
|
|
impl ValueClass {
|
|
|
|
#[new]
|
2024-03-06 00:31:56 +00:00
|
|
|
fn new(value: usize) -> Self {
|
|
|
|
Self { value }
|
2024-02-24 13:50:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[pyclass(module = "module")]
|
|
|
|
struct LocatedClass {}
|
|
|
|
|
|
|
|
#[pyfunction]
|
|
|
|
fn double(x: usize) -> usize {
|
|
|
|
x * 2
|
|
|
|
}
|
|
|
|
|
|
|
|
create_exception!(
|
|
|
|
declarative_module,
|
|
|
|
MyError,
|
|
|
|
PyException,
|
|
|
|
"Some description."
|
|
|
|
);
|
|
|
|
|
2024-07-10 22:38:38 +00:00
|
|
|
#[pymodule(submodule)]
|
2024-07-02 11:24:47 +00:00
|
|
|
mod external_submodule {}
|
|
|
|
|
2024-02-24 13:50:18 +00:00
|
|
|
/// A module written using declarative syntax.
|
|
|
|
#[pymodule]
|
|
|
|
mod declarative_module {
|
|
|
|
#[pymodule_export]
|
|
|
|
use super::declarative_submodule;
|
|
|
|
#[pymodule_export]
|
|
|
|
// This is not a real constraint but to test cfg attribute support
|
|
|
|
#[cfg(not(Py_LIMITED_API))]
|
|
|
|
use super::LocatedClass;
|
|
|
|
use super::*;
|
|
|
|
#[pymodule_export]
|
|
|
|
use super::{declarative_module2, double, MyError, ValueClass as Value};
|
|
|
|
|
2024-04-12 06:34:27 +00:00
|
|
|
// test for #4036
|
|
|
|
#[pymodule_export]
|
|
|
|
use super::some_module::SomePyClass;
|
|
|
|
|
2024-04-16 20:12:18 +00:00
|
|
|
// test for #4036
|
|
|
|
#[pymodule_export]
|
|
|
|
use super::some_module::SomeException;
|
|
|
|
|
2024-07-02 11:24:47 +00:00
|
|
|
#[pymodule_export]
|
|
|
|
use super::external_submodule;
|
|
|
|
|
2024-03-06 00:31:56 +00:00
|
|
|
#[pymodule]
|
|
|
|
mod inner {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[pyfunction]
|
|
|
|
fn triple(x: usize) -> usize {
|
|
|
|
x * 3
|
|
|
|
}
|
|
|
|
|
2024-06-06 07:54:26 +00:00
|
|
|
#[pyclass(name = "Struct")]
|
2024-03-06 00:31:56 +00:00
|
|
|
struct Struct;
|
|
|
|
|
|
|
|
#[pymethods]
|
|
|
|
impl Struct {
|
|
|
|
#[new]
|
|
|
|
fn new() -> Self {
|
|
|
|
Self
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-06 07:54:26 +00:00
|
|
|
#[pyclass(module = "foo")]
|
|
|
|
struct StructInCustomModule;
|
|
|
|
|
|
|
|
#[pyclass(eq, eq_int, name = "Enum")]
|
2024-05-31 14:13:30 +00:00
|
|
|
#[derive(PartialEq)]
|
2024-03-06 00:31:56 +00:00
|
|
|
enum Enum {
|
|
|
|
A,
|
|
|
|
B,
|
|
|
|
}
|
2024-06-06 07:54:26 +00:00
|
|
|
|
|
|
|
#[pyclass(eq, eq_int, module = "foo")]
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
enum EnumInCustomModule {
|
|
|
|
A,
|
|
|
|
B,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-09 12:15:12 +00:00
|
|
|
#[pymodule]
|
2024-06-06 07:54:26 +00:00
|
|
|
#[pyo3(module = "custom_root")]
|
|
|
|
mod inner_custom_root {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[pyclass]
|
|
|
|
struct Struct;
|
2024-03-06 00:31:56 +00:00
|
|
|
}
|
|
|
|
|
2024-07-05 09:16:06 +00:00
|
|
|
#[pyo3::prelude::pymodule]
|
|
|
|
mod full_path_inner {}
|
|
|
|
|
2024-02-24 13:50:18 +00:00
|
|
|
#[pymodule_init]
|
|
|
|
fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|
|
|
m.add("double2", m.getattr("double")?)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[pyfunction]
|
|
|
|
fn double_value(v: &ValueClass) -> usize {
|
|
|
|
v.value * 2
|
|
|
|
}
|
|
|
|
|
|
|
|
#[pymodule]
|
|
|
|
mod declarative_submodule {
|
|
|
|
#[pymodule_export]
|
|
|
|
use super::{double, double_value};
|
|
|
|
}
|
|
|
|
|
2024-07-10 22:38:38 +00:00
|
|
|
#[pymodule(name = "declarative_module_renamed")]
|
2024-02-24 13:50:18 +00:00
|
|
|
mod declarative_module2 {
|
|
|
|
#[pymodule_export]
|
|
|
|
use super::double;
|
|
|
|
}
|
|
|
|
|
2024-06-06 07:54:26 +00:00
|
|
|
fn declarative_module(py: Python<'_>) -> &Bound<'_, PyModule> {
|
|
|
|
static MODULE: GILOnceCell<Py<PyModule>> = GILOnceCell::new();
|
|
|
|
MODULE
|
|
|
|
.get_or_init(py, || pyo3::wrap_pymodule!(declarative_module)(py))
|
|
|
|
.bind(py)
|
|
|
|
}
|
|
|
|
|
2024-02-24 13:50:18 +00:00
|
|
|
#[test]
|
|
|
|
fn test_declarative_module() {
|
|
|
|
Python::with_gil(|py| {
|
2024-06-06 07:54:26 +00:00
|
|
|
let m = declarative_module(py);
|
2024-02-24 13:50:18 +00:00
|
|
|
py_assert!(
|
|
|
|
py,
|
|
|
|
m,
|
|
|
|
"m.__doc__ == 'A module written using declarative syntax.'"
|
|
|
|
);
|
|
|
|
|
|
|
|
py_assert!(py, m, "m.double(2) == 4");
|
2024-03-06 00:31:56 +00:00
|
|
|
py_assert!(py, m, "m.inner.triple(3) == 9");
|
2024-02-24 13:50:18 +00:00
|
|
|
py_assert!(py, m, "m.declarative_submodule.double(4) == 8");
|
|
|
|
py_assert!(
|
|
|
|
py,
|
|
|
|
m,
|
|
|
|
"m.declarative_submodule.double_value(m.ValueClass(1)) == 2"
|
|
|
|
);
|
|
|
|
py_assert!(py, m, "str(m.MyError('foo')) == 'foo'");
|
|
|
|
py_assert!(py, m, "m.declarative_module_renamed.double(2) == 4");
|
|
|
|
#[cfg(Py_LIMITED_API)]
|
|
|
|
py_assert!(py, m, "not hasattr(m, 'LocatedClass')");
|
|
|
|
#[cfg(not(Py_LIMITED_API))]
|
|
|
|
py_assert!(py, m, "hasattr(m, 'LocatedClass')");
|
2024-03-06 00:31:56 +00:00
|
|
|
py_assert!(py, m, "isinstance(m.inner.Struct(), m.inner.Struct)");
|
|
|
|
py_assert!(py, m, "isinstance(m.inner.Enum.A, m.inner.Enum)");
|
2024-07-02 11:24:47 +00:00
|
|
|
py_assert!(py, m, "hasattr(m, 'external_submodule')")
|
2024-02-24 13:50:18 +00:00
|
|
|
})
|
|
|
|
}
|
2024-03-06 18:20:02 +00:00
|
|
|
|
|
|
|
#[cfg(not(Py_LIMITED_API))]
|
|
|
|
#[pyclass(extends = PyBool)]
|
|
|
|
struct ExtendsBool;
|
|
|
|
|
|
|
|
#[cfg(not(Py_LIMITED_API))]
|
|
|
|
#[pymodule]
|
|
|
|
mod class_initialization_module {
|
|
|
|
#[pymodule_export]
|
|
|
|
use super::ExtendsBool;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[cfg(not(Py_LIMITED_API))]
|
|
|
|
fn test_class_initialization_fails() {
|
|
|
|
Python::with_gil(|py| {
|
2024-03-29 11:54:33 +00:00
|
|
|
let err = class_initialization_module::_PYO3_DEF
|
2024-03-06 18:20:02 +00:00
|
|
|
.make_module(py)
|
|
|
|
.unwrap_err();
|
|
|
|
assert_eq!(
|
|
|
|
err.to_string(),
|
|
|
|
"RuntimeError: An error occurred while initializing class ExtendsBool"
|
|
|
|
);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[pymodule]
|
|
|
|
mod r#type {
|
|
|
|
#[pymodule_export]
|
|
|
|
use super::double;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_raw_ident_module() {
|
|
|
|
Python::with_gil(|py| {
|
|
|
|
let m = pyo3::wrap_pymodule!(r#type)(py).into_bound(py);
|
|
|
|
py_assert!(py, m, "m.double(2) == 4");
|
|
|
|
})
|
|
|
|
}
|
2024-06-06 07:54:26 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_module_names() {
|
|
|
|
Python::with_gil(|py| {
|
|
|
|
let m = declarative_module(py);
|
|
|
|
py_assert!(
|
|
|
|
py,
|
|
|
|
m,
|
|
|
|
"m.inner.Struct.__module__ == 'declarative_module.inner'"
|
|
|
|
);
|
|
|
|
py_assert!(py, m, "m.inner.StructInCustomModule.__module__ == 'foo'");
|
|
|
|
py_assert!(
|
|
|
|
py,
|
|
|
|
m,
|
|
|
|
"m.inner.Enum.__module__ == 'declarative_module.inner'"
|
|
|
|
);
|
|
|
|
py_assert!(py, m, "m.inner.EnumInCustomModule.__module__ == 'foo'");
|
|
|
|
py_assert!(
|
|
|
|
py,
|
|
|
|
m,
|
|
|
|
"m.inner_custom_root.Struct.__module__ == 'custom_root.inner_custom_root'"
|
|
|
|
);
|
|
|
|
})
|
|
|
|
}
|
2024-07-05 09:16:06 +00:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_inner_module_full_path() {
|
|
|
|
Python::with_gil(|py| {
|
|
|
|
let m = declarative_module(py);
|
|
|
|
py_assert!(py, m, "m.full_path_inner");
|
|
|
|
})
|
|
|
|
}
|