Skip to content

Commit

Permalink
port Python::get_type to Bound API (#3846)
Browse files Browse the repository at this point in the history
* port `Python::get_type` to `Bound` API

* fix `is_subclass_and_is_instance` FIXME
  • Loading branch information
Icxolu authored Feb 18, 2024
1 parent f04ad56 commit 4ce9c35
Show file tree
Hide file tree
Showing 33 changed files with 175 additions and 157 deletions.
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

0 comments on commit 4ce9c35

Please sign in to comment.