Skip to content

Commit

Permalink
module::from_code takes CStr instead str
Browse files Browse the repository at this point in the history
  • Loading branch information
bschoenmaeckers committed Aug 13, 2024
1 parent ec245a9 commit c5d05d9
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 55 deletions.
18 changes: 12 additions & 6 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1902,6 +1902,8 @@ mod tests {
use super::{Bound, Py, PyObject};
use crate::types::{dict::IntoPyDict, PyAnyMethods, PyCapsule, PyDict, PyString};
use crate::{ffi, Borrowed, PyAny, PyResult, Python, ToPyObject};
use pyo3_ffi::c_str;
use std::ffi::CStr;

#[test]
fn test_call() {
Expand Down Expand Up @@ -1966,12 +1968,14 @@ mod tests {
use crate::types::PyModule;

Python::with_gil(|py| {
const CODE: &str = r#"
const CODE: &CStr = c_str!(
r#"
class A:
pass
a = A()
"#;
let module = PyModule::from_code(py, CODE, "", "")?;
"#
);
let module = PyModule::from_code(py, CODE, c_str!(""), c_str!(""))?;
let instance: Py<PyAny> = module.getattr("a")?.into();

instance.getattr(py, "foo").unwrap_err();
Expand All @@ -1993,12 +1997,14 @@ a = A()
use crate::types::PyModule;

Python::with_gil(|py| {
const CODE: &str = r#"
const CODE: &CStr = c_str!(
r#"
class A:
pass
a = A()
"#;
let module = PyModule::from_code(py, CODE, "", "")?;
"#
);
let module = PyModule::from_code(py, CODE, c_str!(""), c_str!(""))?;
let instance: Py<PyAny> = module.getattr("a")?.into();

let foo = crate::intern!(py, "foo");
Expand Down
61 changes: 38 additions & 23 deletions src/types/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,17 +404,19 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::PyDict;
/// use pyo3_ffi::c_str;
/// use std::ffi::CStr;
///
/// const CODE: &str = r#"
/// const CODE: &CStr = c_str!(r#"
/// def function(*args, **kwargs):
/// assert args == ("hello",)
/// assert kwargs == {"cruel": "world"}
/// return "called with args and kwargs"
/// "#;
/// "#);
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?;
/// let module = PyModule::from_code(py, CODE, c_str!(""), c_str!(""))?;
/// let fun = module.getattr("function")?;
/// let args = ("hello",);
/// let kwargs = PyDict::new(py);
Expand Down Expand Up @@ -461,17 +463,19 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3_ffi::c_str;
/// use std::ffi::CStr;
///
/// const CODE: &str = r#"
/// const CODE: &CStr = c_str!(r#"
/// def function(*args, **kwargs):
/// assert args == ("hello",)
/// assert kwargs == {}
/// return "called with args"
/// "#;
/// "#);
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?;
/// let module = PyModule::from_code(py, CODE, c_str!(""), c_str!(""))?;
/// let fun = module.getattr("function")?;
/// let args = ("hello",);
/// let result = fun.call1(args)?;
Expand All @@ -494,19 +498,21 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::PyDict;
/// use pyo3_ffi::c_str;
/// use std::ffi::CStr;
///
/// const CODE: &str = r#"
/// const CODE: &CStr = c_str!(r#"
/// class A:
/// def method(self, *args, **kwargs):
/// assert args == ("hello",)
/// assert kwargs == {"cruel": "world"}
/// return "called with args and kwargs"
/// a = A()
/// "#;
/// "#);
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?;
/// let module = PyModule::from_code(py, CODE, c_str!(""), c_str!(""))?;
/// let instance = module.getattr("a")?;
/// let args = ("hello",);
/// let kwargs = PyDict::new(py);
Expand Down Expand Up @@ -538,19 +544,21 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3_ffi::c_str;
/// use std::ffi::CStr;
///
/// const CODE: &str = r#"
/// const CODE: &CStr = c_str!(r#"
/// class A:
/// def method(self, *args, **kwargs):
/// assert args == ()
/// assert kwargs == {}
/// return "called with no arguments"
/// a = A()
/// "#;
/// "#);
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?;
/// let module = PyModule::from_code(py, CODE, c_str!(""), c_str!(""))?;
/// let instance = module.getattr("a")?;
/// let result = instance.call_method0("method")?;
/// assert_eq!(result.extract::<String>()?, "called with no arguments");
Expand All @@ -573,19 +581,21 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3_ffi::c_str;
/// use std::ffi::CStr;
///
/// const CODE: &str = r#"
/// const CODE: &CStr = c_str!(r#"
/// class A:
/// def method(self, *args, **kwargs):
/// assert args == ("hello",)
/// assert kwargs == {}
/// return "called with args"
/// a = A()
/// "#;
/// "#);
///
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| {
/// let module = PyModule::from_code(py, CODE, "", "")?;
/// let module = PyModule::from_code(py, CODE, c_str!(""), c_str!(""))?;
/// let instance = module.getattr("a")?;
/// let args = ("hello",);
/// let result = instance.call_method1("method", args)?;
Expand Down Expand Up @@ -1528,13 +1538,15 @@ mod tests {
types::{IntoPyDict, PyAny, PyAnyMethods, PyBool, PyInt, PyList, PyModule, PyTypeMethods},
Bound, PyTypeInfo, Python, ToPyObject,
};
use pyo3_ffi::c_str;

#[test]
fn test_lookup_special() {
Python::with_gil(|py| {
let module = PyModule::from_code(
py,
r#"
c_str!(
r#"
class CustomCallable:
def __call__(self):
return 1
Expand Down Expand Up @@ -1564,9 +1576,10 @@ class ErrorInDescriptorInt:
class NonHeapNonDescriptorInt:
# A static-typed callable that doesn't implement `__get__`. These are pretty hard to come by.
__int__ = int
"#,
"test.py",
"test",
"#
),
c_str!("test.py"),
c_str!("test"),
)
.unwrap();

Expand Down Expand Up @@ -1627,13 +1640,15 @@ class NonHeapNonDescriptorInt:
Python::with_gil(|py| {
let module = PyModule::from_code(
py,
r#"
c_str!(
r#"
class SimpleClass:
def foo(self):
return 42
"#,
file!(),
"test_module",
"#
),
c_str!(file!()),
c_str!("test_module"),
)
.expect("module creation failed");

Expand Down
33 changes: 18 additions & 15 deletions src/types/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::types::{
any::PyAnyMethods, list::PyListMethods, PyAny, PyCFunction, PyDict, PyList, PyString,
};
use crate::{exceptions, ffi, Bound, IntoPy, Py, PyObject, Python};
use std::ffi::CString;
use std::ffi::{CStr, CString};
use std::str;

/// Represents a Python [`module`][1] object.
Expand Down Expand Up @@ -46,8 +46,9 @@ impl PyModule {
/// # Ok(())}
/// ```
pub fn new<'py>(py: Python<'py>, name: &str) -> PyResult<Bound<'py, PyModule>> {
let name = PyString::new(py, name);
unsafe {
ffi::PyModule_NewObject(name.into_py(py))
ffi::PyModule_NewObject(name.as_ptr())
.assume_owned_or_err(py)
.downcast_into_unchecked()
}
Expand Down Expand Up @@ -123,13 +124,14 @@ impl PyModule {
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::ffi::c_str;
///
/// # fn main() -> PyResult<()> {
/// // This path is resolved relative to this file.
/// let code = include_str!("../../assets/script.py");
/// let code = c_str!(include_str!("../../assets/script.py"));
///
/// Python::with_gil(|py| -> PyResult<()> {
/// PyModule::from_code(py, code, "example.py", "example")?;
/// PyModule::from_code(py, code, c_str!("example.py"), c_str!("example"))?;
/// Ok(())
/// })?;
/// # Ok(())
Expand All @@ -140,6 +142,7 @@ impl PyModule {
///
/// ```rust
/// use pyo3::prelude::*;
/// use std::ffi::CString;
///
/// # fn main() -> PyResult<()> {
/// // This path is resolved by however the platform resolves paths,
Expand All @@ -148,27 +151,23 @@ impl PyModule {
/// let code = std::fs::read_to_string("assets/script.py")?;
///
/// Python::with_gil(|py| -> PyResult<()> {
/// PyModule::from_code(py, &code, "example.py", "example")?;
/// PyModule::from_code(py, CString::new(code)?.as_c_str(), c"example.py", c"example")?;
/// Ok(())
/// })?;
/// Ok(())
/// # }
/// ```
pub fn from_code<'py>(
py: Python<'py>,
code: &str,
file_name: &str,
module_name: &str,
code: &CStr,
file_name: &CStr,
module_name: &CStr,
) -> PyResult<Bound<'py, PyModule>> {
let data = CString::new(code)?;
let filename = CString::new(file_name)?;
let module = CString::new(module_name)?;

unsafe {
let code = ffi::Py_CompileString(data.as_ptr(), filename.as_ptr(), ffi::Py_file_input)
let code = ffi::Py_CompileString(code.as_ptr(), file_name.as_ptr(), ffi::Py_file_input)
.assume_owned_or_err(py)?;

ffi::PyImport_ExecCodeModuleEx(module.as_ptr(), code.as_ptr(), filename.as_ptr())
ffi::PyImport_ExecCodeModuleEx(module_name.as_ptr(), code.as_ptr(), file_name.as_ptr())
.assume_owned_or_err(py)
.downcast_into()
}
Expand All @@ -183,7 +182,11 @@ impl PyModule {
file_name: &str,
module_name: &str,
) -> PyResult<Bound<'py, PyModule>> {
Self::from_code(py, code, file_name, module_name)
let data = CString::new(code)?;
let filename = CString::new(file_name)?;
let module = CString::new(module_name)?;

Self::from_code(py, data.as_c_str(), filename.as_c_str(), module.as_c_str())
}
}

Expand Down
21 changes: 13 additions & 8 deletions src/types/typeobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ mod tests {
use crate::types::{PyAnyMethods, PyBool, PyInt, PyModule, PyTuple, PyType, PyTypeMethods};
use crate::PyAny;
use crate::Python;
use pyo3_ffi::c_str;

#[test]
fn test_type_is_subclass() {
Expand Down Expand Up @@ -315,12 +316,14 @@ mod tests {
Python::with_gil(|py| {
let module = PyModule::from_code(
py,
r#"
c_str!(
r#"
class MyClass:
pass
"#,
file!(),
"test_module",
"#
),
c_str!(file!()),
c_str!("test_module"),
)
.expect("module create failed");

Expand Down Expand Up @@ -352,13 +355,15 @@ class MyClass:
Python::with_gil(|py| {
let module = PyModule::from_code(
py,
r#"
c_str!(
r#"
class OuterClass:
class InnerClass:
pass
"#,
file!(),
"test_module",
"#
),
c_str!(file!()),
c_str!("test_module"),
)
.expect("module create failed");

Expand Down
7 changes: 4 additions & 3 deletions tests/test_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use pyo3::prelude::*;
use pyo3::py_run;
use pyo3::types::PyString;
use pyo3::types::{IntoPyDict, PyDict, PyTuple};
use pyo3_ffi::c_str;

#[path = "../src/tests/common.rs"]
mod common;
Expand Down Expand Up @@ -160,9 +161,9 @@ fn test_module_from_code_bound() {
Python::with_gil(|py| {
let adder_mod = PyModule::from_code(
py,
"def add(a,b):\n\treturn a+b",
"adder_mod.py",
"adder_mod",
c_str!("def add(a,b):\n\treturn a+b"),
c_str!("adder_mod.py"),
c_str!("adder_mod"),
)
.expect("Module code should be loaded");

Expand Down

0 comments on commit c5d05d9

Please sign in to comment.