Skip to content

port Python::get_type to Bound API #3846

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ impl SubSubClass {
# pyo3::py_run!(py, subsub, "assert subsub.method3() == 3000");
# let subsub = SubSubClass::factory_method(py, 2).unwrap();
# let subsubsub = SubSubClass::factory_method(py, 3).unwrap();
# let cls = py.get_type::<SubSubClass>();
# let cls = py.get_type_bound::<SubSubClass>();
# pyo3::py_run!(py, subsub cls, "assert not isinstance(subsub, cls)");
# pyo3::py_run!(py, subsubsub cls, "assert isinstance(subsubsub, cls)");
# });
Expand Down Expand Up @@ -497,7 +497,7 @@ impl MyDict {
// some custom methods that use `private` here...
}
# Python::with_gil(|py| {
# let cls = py.get_type::<MyDict>();
# let cls = py.get_type_bound::<MyDict>();
# pyo3::py_run!(py, cls, "cls(a=1, b=2)")
# });
# }
Expand Down Expand Up @@ -767,7 +767,7 @@ impl MyClass {
}

Python::with_gil(|py| {
let my_class = py.get_type::<MyClass>();
let my_class = py.get_type_bound::<MyClass>();
pyo3::py_run!(py, my_class, "assert my_class.my_attribute == 'hello'")
});
```
Expand Down Expand Up @@ -1026,7 +1026,7 @@ enum MyEnum {
Python::with_gil(|py| {
let x = Py::new(py, MyEnum::Variant).unwrap();
let y = Py::new(py, MyEnum::OtherVariant).unwrap();
let cls = py.get_type::<MyEnum>();
let cls = py.get_type_bound::<MyEnum>();
pyo3::py_run!(py, x y cls, r#"
assert x == cls.Variant
assert y == cls.OtherVariant
Expand All @@ -1046,7 +1046,7 @@ enum MyEnum {
}

Python::with_gil(|py| {
let cls = py.get_type::<MyEnum>();
let cls = py.get_type_bound::<MyEnum>();
let x = MyEnum::Variant as i32; // The exact value is assigned by the compiler.
pyo3::py_run!(py, cls x, r#"
assert int(cls.Variant) == x
Expand All @@ -1068,7 +1068,7 @@ enum MyEnum{
}

Python::with_gil(|py| {
let cls = py.get_type::<MyEnum>();
let cls = py.get_type_bound::<MyEnum>();
let x = Py::new(py, MyEnum::Variant).unwrap();
pyo3::py_run!(py, cls x, r#"
assert repr(x) == 'MyEnum.Variant'
Expand All @@ -1094,7 +1094,7 @@ impl MyEnum {
}

Python::with_gil(|py| {
let cls = py.get_type::<MyEnum>();
let cls = py.get_type_bound::<MyEnum>();
pyo3::py_run!(py, cls, "assert repr(cls.Answer) == '42'")
})
```
Expand All @@ -1111,7 +1111,7 @@ enum MyEnum {

Python::with_gil(|py| {
let x = Py::new(py, MyEnum::Variant).unwrap();
let cls = py.get_type::<MyEnum>();
let cls = py.get_type_bound::<MyEnum>();
pyo3::py_run!(py, x cls, r#"
assert repr(x) == 'RenamedEnum.UPPERCASE'
assert x == cls.UPPERCASE
Expand Down Expand Up @@ -1165,7 +1165,7 @@ enum Shape {
Python::with_gil(|py| {
let circle = Shape::Circle { radius: 10.0 }.into_py(py);
let square = Shape::RegularPolygon { side_count: 4, radius: 10.0 }.into_py(py);
let cls = py.get_type::<Shape>();
let cls = py.get_type_bound::<Shape>();
pyo3::py_run!(py, circle square cls, r#"
assert isinstance(circle, cls)
assert isinstance(circle, cls.Circle)
Expand Down Expand Up @@ -1204,7 +1204,7 @@ enum MyEnum {

Python::with_gil(|py| {
let x = Py::new(py, MyEnum::Variant { i: 42 }).unwrap();
let cls = py.get_type::<MyEnum>();
let cls = py.get_type_bound::<MyEnum>();
pyo3::py_run!(py, x cls, r#"
assert isinstance(x, cls)
assert not isinstance(x, cls.Variant)
Expand Down Expand Up @@ -1308,7 +1308,7 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
}

# Python::with_gil(|py| {
# let cls = py.get_type::<MyClass>();
# let cls = py.get_type_bound::<MyClass>();
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")
# });
# }
Expand Down
4 changes: 2 additions & 2 deletions guide/src/exception.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use pyo3::exceptions::PyException;
create_exception!(mymodule, CustomError, PyException);

Python::with_gil(|py| {
let ctx = [("CustomError", py.get_type::<CustomError>())].into_py_dict_bound(py);
let ctx = [("CustomError", py.get_type_bound::<CustomError>())].into_py_dict_bound(py);
pyo3::py_run!(
py,
*ctx,
Expand All @@ -46,7 +46,7 @@ pyo3::create_exception!(mymodule, CustomError, PyException);
#[pymodule]
fn mymodule(py: Python<'_>, m: &PyModule) -> PyResult<()> {
// ... other elements added to module ...
m.add("CustomError", py.get_type::<CustomError>())?;
m.add("CustomError", py.get_type_bound::<CustomError>())?;

Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,7 @@ pub fn gen_complex_enum_variant_attr(
let associated_method = quote! {
fn #wrapper_ident(py: _pyo3::Python<'_>) -> _pyo3::PyResult<_pyo3::PyObject> {
#deprecations
::std::result::Result::Ok(py.get_type::<#variant_cls>().into())
::std::result::Result::Ok(py.get_type_bound::<#variant_cls>().into_any().unbind())
}
};

Expand Down
6 changes: 2 additions & 4 deletions src/conversions/chrono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ use crate::types::{
};
#[cfg(Py_LIMITED_API)]
use crate::{intern, DowncastError};
use crate::{
Bound, FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ToPyObject,
};
use crate::{Bound, FromPyObject, IntoPy, PyAny, PyErr, PyObject, PyResult, Python, ToPyObject};
use chrono::offset::{FixedOffset, Utc};
use chrono::{
DateTime, Datelike, Duration, NaiveDate, NaiveDateTime, NaiveTime, Offset, TimeZone, Timelike,
Expand Down Expand Up @@ -461,7 +459,7 @@ fn warn_truncated_leap_second(obj: &Bound<'_, PyAny>) {
let py = obj.py();
if let Err(e) = PyErr::warn_bound(
py,
&py.get_type::<PyUserWarning>().as_borrowed(),
&py.get_type_bound::<PyUserWarning>(),
"ignored leap-second, `datetime` does not support leap-seconds",
0,
) {
Expand Down
8 changes: 2 additions & 6 deletions src/conversions/num_bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,8 @@ macro_rules! bigint_conversion {
} else {
None
};
py.get_type::<PyLong>()
.call_method(
"from_bytes",
(bytes_obj, "little"),
kwargs.as_ref().map(crate::Bound::as_gil_ref),
)
py.get_type_bound::<PyLong>()
.call_method("from_bytes", (bytes_obj, "little"), kwargs.as_ref())
.expect("int.from_bytes() failed during to_object()") // FIXME: #1813 or similar
.into()
}
Expand Down
10 changes: 5 additions & 5 deletions src/err/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -724,7 +724,7 @@ impl PyErr {
/// # use pyo3::prelude::*;
/// # fn main() -> PyResult<()> {
/// Python::with_gil(|py| {
/// let user_warning = py.get_type::<pyo3::exceptions::PyUserWarning>().as_borrowed();
/// let user_warning = py.get_type_bound::<pyo3::exceptions::PyUserWarning>();
/// PyErr::warn_bound(py, &user_warning, "I am warning you", 0)?;
/// Ok(())
/// })
Expand Down Expand Up @@ -1080,7 +1080,7 @@ impl_signed_integer!(isize);
mod tests {
use super::PyErrState;
use crate::exceptions::{self, PyTypeError, PyValueError};
use crate::{PyErr, PyNativeType, PyTypeInfo, Python};
use crate::{PyErr, PyTypeInfo, Python};

#[test]
fn no_error() {
Expand Down Expand Up @@ -1278,7 +1278,7 @@ mod tests {
// GIL locked should prevent effects to be visible to other testing
// threads.
Python::with_gil(|py| {
let cls = py.get_type::<exceptions::PyUserWarning>().as_borrowed();
let cls = py.get_type_bound::<exceptions::PyUserWarning>();

// Reset warning filter to default state
let warnings = py.import_bound("warnings").unwrap();
Expand All @@ -1293,14 +1293,14 @@ mod tests {

// Test with raising
warnings
.call_method1("simplefilter", ("error", cls))
.call_method1("simplefilter", ("error", &cls))
.unwrap();
PyErr::warn_bound(py, &cls, "I am warning you", 0).unwrap_err();

// Test with error for an explicit module
warnings.call_method0("resetwarnings").unwrap();
warnings
.call_method1("filterwarnings", ("error", "", cls, "pyo3test"))
.call_method1("filterwarnings", ("error", "", &cls, "pyo3test"))
.unwrap();

// This has the wrong module and will not raise, just be emitted
Expand Down
17 changes: 8 additions & 9 deletions src/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ macro_rules! impl_exception_boilerplate {
/// import_exception!(socket, gaierror);
///
/// Python::with_gil(|py| {
/// let ctx = [("gaierror", py.get_type::<gaierror>())].into_py_dict_bound(py);
/// let ctx = [("gaierror", py.get_type_bound::<gaierror>())].into_py_dict_bound(py);
/// pyo3::py_run!(py, *ctx, "import socket; assert gaierror is socket.gaierror");
/// });
///
Expand Down Expand Up @@ -160,15 +160,15 @@ macro_rules! import_exception {
///
/// #[pymodule]
/// fn my_module(py: Python<'_>, m: &PyModule) -> PyResult<()> {
/// m.add("MyError", py.get_type::<MyError>())?;
/// m.add("MyError", py.get_type_bound::<MyError>())?;
/// m.add_function(wrap_pyfunction!(raise_myerror, py)?)?;
/// Ok(())
/// }
/// # fn main() -> PyResult<()> {
/// # Python::with_gil(|py| -> PyResult<()> {
/// # let fun = wrap_pyfunction!(raise_myerror, py)?;
/// # let locals = pyo3::types::PyDict::new_bound(py);
/// # locals.set_item("MyError", py.get_type::<MyError>())?;
/// # locals.set_item("MyError", py.get_type_bound::<MyError>())?;
/// # locals.set_item("raise_myerror", fun)?;
/// #
/// # py.run_bound(
Expand Down Expand Up @@ -241,7 +241,6 @@ macro_rules! create_exception_type_object {
impl $name {
fn type_object_raw(py: $crate::Python<'_>) -> *mut $crate::ffi::PyTypeObject {
use $crate::sync::GILOnceCell;
use $crate::PyNativeType;
static TYPE_OBJECT: GILOnceCell<$crate::Py<$crate::types::PyType>> =
GILOnceCell::new();

Expand All @@ -251,7 +250,7 @@ macro_rules! create_exception_type_object {
py,
concat!(stringify!($module), ".", stringify!($name)),
$doc,
::std::option::Option::Some(&py.get_type::<$base>().as_borrowed()),
::std::option::Option::Some(&py.get_type_bound::<$base>()),
::std::option::Option::None,
).expect("Failed to initialize new exception type.")
).as_ptr() as *mut $crate::ffi::PyTypeObject
Expand Down Expand Up @@ -904,7 +903,7 @@ mod tests {
create_exception!(mymodule, CustomError, PyException);

Python::with_gil(|py| {
let error_type = py.get_type::<CustomError>();
let error_type = py.get_type_bound::<CustomError>();
let ctx = [("CustomError", error_type)].into_py_dict_bound(py);
let type_description: String = py
.eval_bound("str(CustomError)", None, Some(&ctx))
Expand All @@ -927,7 +926,7 @@ mod tests {
fn custom_exception_dotted_module() {
create_exception!(mymodule.exceptions, CustomError, PyException);
Python::with_gil(|py| {
let error_type = py.get_type::<CustomError>();
let error_type = py.get_type_bound::<CustomError>();
let ctx = [("CustomError", error_type)].into_py_dict_bound(py);
let type_description: String = py
.eval_bound("str(CustomError)", None, Some(&ctx))
Expand All @@ -946,7 +945,7 @@ mod tests {
create_exception!(mymodule, CustomError, PyException, "Some docs");

Python::with_gil(|py| {
let error_type = py.get_type::<CustomError>();
let error_type = py.get_type_bound::<CustomError>();
let ctx = [("CustomError", error_type)].into_py_dict_bound(py);
let type_description: String = py
.eval_bound("str(CustomError)", None, Some(&ctx))
Expand Down Expand Up @@ -979,7 +978,7 @@ mod tests {
);

Python::with_gil(|py| {
let error_type = py.get_type::<CustomError>();
let error_type = py.get_type_bound::<CustomError>();
let ctx = [("CustomError", error_type)].into_py_dict_bound(py);
let type_description: String = py
.eval_bound("str(CustomError)", None, Some(&ctx))
Expand Down
5 changes: 4 additions & 1 deletion src/impl_/extract_argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,10 @@ pub fn from_py_with_with_default<'a, 'py, T>(
#[cold]
pub fn argument_extraction_error(py: Python<'_>, arg_name: &str, error: PyErr) -> PyErr {
use crate::types::any::PyAnyMethods;
if error.get_type_bound(py).is(py.get_type::<PyTypeError>()) {
if error
.get_type_bound(py)
.is(&py.get_type_bound::<PyTypeError>())
{
let remapped_error = PyTypeError::new_err(format!(
"argument '{}': {}",
arg_name,
Expand Down
2 changes: 1 addition & 1 deletion src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
/// }
///
/// Python::with_gil(|py| {
/// let locals = [("C", py.get_type::<MyClass>())].into_py_dict_bound(py);
/// let locals = [("C", py.get_type_bound::<MyClass>())].into_py_dict_bound(py);
/// pyo3::py_run!(py, *locals, "c = C()");
/// });
/// ```
Expand Down
18 changes: 17 additions & 1 deletion src/marker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -728,12 +728,28 @@ impl<'py> Python<'py> {
}

/// Gets the Python type object for type `T`.
#[cfg_attr(
not(feature = "gil-refs"),
deprecated(
since = "0.21.0",
note = "`Python::get_type` will be replaced by `Python::get_type_bound` in a future PyO3 version"
)
)]
#[inline]
pub fn get_type<T>(self) -> &'py PyType
where
T: PyTypeInfo,
{
T::type_object_bound(self).into_gil_ref()
self.get_type_bound::<T>().into_gil_ref()
}

/// Gets the Python type object for type `T`.
#[inline]
pub fn get_type_bound<T>(self) -> Bound<'py, PyType>
where
T: PyTypeInfo,
{
T::type_object_bound(self)
}

/// Deprecated form of [`Python::import_bound`]
Expand Down
2 changes: 1 addition & 1 deletion src/pyclass_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
/// }
/// }
/// Python::with_gil(|py| {
/// let typeobj = py.get_type::<SubSubClass>();
/// let typeobj = py.get_type_bound::<SubSubClass>();
/// let sub_sub_class = typeobj.call((), None).unwrap();
/// py_run!(
/// py,
Expand Down
2 changes: 1 addition & 1 deletion src/tests/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ mod inner {
($py:expr, *$dict:expr, $code:expr, $err:ident) => {{
let res = $py.run_bound($code, None, Some(&$dict.as_borrowed()));
let err = res.expect_err(&format!("Did not raise {}", stringify!($err)));
if !err.matches($py, $py.get_type::<pyo3::exceptions::$err>()) {
if !err.matches($py, $py.get_type_bound::<pyo3::exceptions::$err>()) {
panic!("Expected {} but got {:?}", stringify!($err), err)
}
err
Expand Down
12 changes: 8 additions & 4 deletions src/types/typeobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,22 +217,26 @@ impl<'a> Borrowed<'a, '_, PyType> {

#[cfg(test)]
mod tests {
use crate::types::typeobject::PyTypeMethods;
use crate::types::{PyBool, PyLong};
use crate::Python;

#[test]
fn test_type_is_subclass() {
Python::with_gil(|py| {
let bool_type = py.get_type::<PyBool>();
let long_type = py.get_type::<PyLong>();
assert!(bool_type.is_subclass(long_type).unwrap());
let bool_type = py.get_type_bound::<PyBool>();
let long_type = py.get_type_bound::<PyLong>();
assert!(bool_type.is_subclass(&long_type).unwrap());
});
}

#[test]
fn test_type_is_subclass_of() {
Python::with_gil(|py| {
assert!(py.get_type::<PyBool>().is_subclass_of::<PyLong>().unwrap());
assert!(py
.get_type_bound::<PyBool>()
.is_subclass_of::<PyLong>()
.unwrap());
});
}
}
Loading