Skip to content

Commit

Permalink
for now just change return type of intern!
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Jan 30, 2024
1 parent aa139ad commit 2f00eb1
Show file tree
Hide file tree
Showing 23 changed files with 117 additions and 155 deletions.
4 changes: 2 additions & 2 deletions guide/src/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ The following sections are laid out in this order.

To make the transition for the PyO3 ecosystem away from the GIL Refs API as smooth as possible, in PyO3 0.21 no APIs consuming or producing GIL Refs have been altered. Instead, variants using `Bound<T>` smart pointers have been introduced, for example `PyTuple::new_bound` which returns `Bound<PyTuple>` is the replacement form of `PyTuple::new`. The GIL Ref APIs have been deprecated, but to make migration easier it is possible to disable these deprecation warnings by enabling the `gil-refs` feature.

> The one single exception where an existing API was changed in-place is the `pyo3::intern!` macro. Almost all uses of this macro did not need to update code to account it changing to return `&Bound<PyString>` immediately, and adding an `intern_bound!` replacement was perceived as adding more work for users.
It is recommended that users do this as a first step of updating to PyO3 0.21 so that the deprecation warnings do not get in the way of resolving the rest of the migration steps.

Before:
Expand All @@ -40,7 +42,6 @@ After:
pyo3 = { version = "0.21", features = ["gil-refs"] }
```


### `PyTypeInfo` and `PyTryFrom` have been adjusted

The `PyTryFrom` trait has aged poorly, its [`try_from`] method now conflicts with `try_from` in the 2021 edition prelude. A lot of its functionality was also duplicated with `PyTypeInfo`.
Expand Down Expand Up @@ -242,7 +243,6 @@ To minimise breakage of code using the GIL-Refs API, the `Bound<T>` smart pointe
For example, the following APIs have gained updated variants:
- `PyList::new`, `PyTyple::new` and similar constructors have replacements `PyList::new_bound`, `PyTuple::new_bound` etc.
- `FromPyObject::extract` has a new `FromPyObject::extract_bound` (see the section below)
- `pyo3::intern!` macro has a new replacement `pyo3::intern_bound!`

Because the new `Bound<T>` API brings ownership out of the PyO3 framework and into user code, there are a few places where user code is expected to need to adjust while switching to the new API:
- Code will need to add the occasional `&` to borrow the new smart pointer as `&Bound<T>` to pass these types around (or use `.clone()` at the very small cost of increasing the Python reference count)
Expand Down
4 changes: 2 additions & 2 deletions pyo3-benches/benches/bench_intern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use codspeed_criterion_compat::{criterion_group, criterion_main, Bencher, Criter

use pyo3::prelude::*;

use pyo3::intern_bound;
use pyo3::intern;

fn getattr_direct(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
Expand All @@ -16,7 +16,7 @@ fn getattr_intern(b: &mut Bencher<'_>) {
Python::with_gil(|py| {
let sys = py.import("sys").unwrap();

b.iter(|| sys.getattr(intern_bound!(py, "version")).unwrap());
b.iter(|| sys.getattr(intern!(py, "version")).unwrap());
});
}

Expand Down
8 changes: 4 additions & 4 deletions pyo3-macros-backend/src/frompyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,17 +324,17 @@ impl<'a> Container<'a> {
let field_name = ident.to_string();
let getter = match field.getter.as_ref().unwrap_or(&FieldGetter::GetAttr(None)) {
FieldGetter::GetAttr(Some(name)) => {
quote!(getattr(_pyo3::intern_bound!(obj.py(), #name)))
quote!(getattr(_pyo3::intern!(obj.py(), #name)))
}
FieldGetter::GetAttr(None) => {
quote!(getattr(_pyo3::intern_bound!(obj.py(), #field_name)))
quote!(getattr(_pyo3::intern!(obj.py(), #field_name)))
}
FieldGetter::GetItem(Some(syn::Lit::Str(key))) => {
quote!(get_item(_pyo3::intern_bound!(obj.py(), #key)))
quote!(get_item(_pyo3::intern!(obj.py(), #key)))
}
FieldGetter::GetItem(Some(key)) => quote!(get_item(#key)),
FieldGetter::GetItem(None) => {
quote!(get_item(_pyo3::intern_bound!(obj.py(), #field_name)))
quote!(get_item(_pyo3::intern!(obj.py(), #field_name)))
}
};
let extractor = match &field.from_py_with {
Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/src/method.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ impl<'a> FnSpec<'a> {
let mut call = quote! {{
let future = #future;
_pyo3::impl_::coroutine::new_coroutine(
_pyo3::intern_bound!(py, stringify!(#python_name)),
_pyo3::intern!(py, stringify!(#python_name)),
#qualname_prefix,
#throw_callback,
async move { _pyo3::impl_::wrap::OkWrap::wrap(future.await) },
Expand Down
35 changes: 13 additions & 22 deletions src/conversions/chrono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use crate::types::{
PyTzInfo, PyTzInfoAccess,
};
#[cfg(Py_LIMITED_API)]
use crate::{intern_bound, PyDowncastError};
use crate::{intern, PyDowncastError};
use crate::{
FromPyObject, IntoPy, PyAny, PyErr, PyNativeType, PyObject, PyResult, Python, ToPyObject,
};
Expand Down Expand Up @@ -127,10 +127,9 @@ impl FromPyObject<'_> for Duration {
let (days, seconds, microseconds) = {
check_type(ob, &DatetimeTypes::get(ob.py()).timedelta, "PyDelta")?;
(
ob.getattr(intern_bound!(ob.py(), "days"))?.extract()?,
ob.getattr(intern_bound!(ob.py(), "seconds"))?.extract()?,
ob.getattr(intern_bound!(ob.py(), "microseconds"))?
.extract()?,
ob.getattr(intern!(ob.py(), "days"))?.extract()?,
ob.getattr(intern!(ob.py(), "seconds"))?.extract()?,
ob.getattr(intern!(ob.py(), "microseconds"))?.extract()?,
)
};
Ok(
Expand Down Expand Up @@ -251,7 +250,7 @@ impl FromPyObject<'_> for NaiveDateTime {
#[cfg(not(Py_LIMITED_API))]
let has_tzinfo = dt.get_tzinfo_bound().is_some();
#[cfg(Py_LIMITED_API)]
let has_tzinfo = !dt.getattr(intern_bound!(dt.py(), "tzinfo"))?.is_none();
let has_tzinfo = !dt.getattr(intern!(dt.py(), "tzinfo"))?.is_none();
if has_tzinfo {
return Err(PyTypeError::new_err("expected a datetime without tzinfo"));
}
Expand Down Expand Up @@ -287,7 +286,7 @@ impl<Tz: TimeZone + for<'a> FromPyObject<'a>> FromPyObject<'_> for DateTime<Tz>
#[cfg(not(Py_LIMITED_API))]
let tzinfo = dt.get_tzinfo_bound();
#[cfg(Py_LIMITED_API)]
let tzinfo: Option<&PyAny> = dt.getattr(intern_bound!(dt.py(), "tzinfo"))?.extract()?;
let tzinfo: Option<&PyAny> = dt.getattr(intern!(dt.py(), "tzinfo"))?.extract()?;

let tz = if let Some(tzinfo) = tzinfo {
tzinfo.extract()?
Expand Down Expand Up @@ -483,15 +482,9 @@ fn py_date_to_naive_date(py_date: &impl PyDateAccess) -> PyResult<NaiveDate> {
#[cfg(Py_LIMITED_API)]
fn py_date_to_naive_date(py_date: &PyAny) -> PyResult<NaiveDate> {
NaiveDate::from_ymd_opt(
py_date
.getattr(intern_bound!(py_date.py(), "year"))?
.extract()?,
py_date
.getattr(intern_bound!(py_date.py(), "month"))?
.extract()?,
py_date
.getattr(intern_bound!(py_date.py(), "day"))?
.extract()?,
py_date.getattr(intern!(py_date.py(), "year"))?.extract()?,
py_date.getattr(intern!(py_date.py(), "month"))?.extract()?,
py_date.getattr(intern!(py_date.py(), "day"))?.extract()?,
)
.ok_or_else(|| PyValueError::new_err("invalid or out-of-range date"))
}
Expand All @@ -510,17 +503,15 @@ fn py_time_to_naive_time(py_time: &impl PyTimeAccess) -> PyResult<NaiveTime> {
#[cfg(Py_LIMITED_API)]
fn py_time_to_naive_time(py_time: &PyAny) -> PyResult<NaiveTime> {
NaiveTime::from_hms_micro_opt(
py_time.getattr(intern!(py_time.py(), "hour"))?.extract()?,
py_time
.getattr(intern_bound!(py_time.py(), "hour"))?
.extract()?,
py_time
.getattr(intern_bound!(py_time.py(), "minute"))?
.getattr(intern!(py_time.py(), "minute"))?
.extract()?,
py_time
.getattr(intern_bound!(py_time.py(), "second"))?
.getattr(intern!(py_time.py(), "second"))?
.extract()?,
py_time
.getattr(intern_bound!(py_time.py(), "microsecond"))?
.getattr(intern!(py_time.py(), "microsecond"))?
.extract()?,
)
.ok_or_else(|| PyValueError::new_err("invalid or out-of-range time"))
Expand Down
6 changes: 2 additions & 4 deletions src/conversions/chrono_tz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@
use crate::exceptions::PyValueError;
use crate::sync::GILOnceCell;
use crate::types::PyType;
use crate::{
intern_bound, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject,
};
use crate::{intern, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject};
use chrono_tz::Tz;
use std::str::FromStr;

Expand All @@ -62,7 +60,7 @@ impl IntoPy<PyObject> for Tz {

impl FromPyObject<'_> for Tz {
fn extract(ob: &PyAny) -> PyResult<Tz> {
Tz::from_str(ob.getattr(intern_bound!(ob.py(), "key"))?.extract()?)
Tz::from_str(ob.getattr(intern!(ob.py(), "key"))?.extract()?)
.map_err(|e| PyValueError::new_err(e.to_string()))
}
}
Expand Down
14 changes: 6 additions & 8 deletions src/conversions/num_bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,7 @@ macro_rules! bigint_conversion {
let bytes_obj = PyBytes::new(py, &bytes);
let kwargs = if $is_signed > 0 {
let kwargs = PyDict::new(py);
kwargs
.set_item(crate::intern_bound!(py, "signed"), true)
.unwrap();
kwargs.set_item(crate::intern!(py, "signed"), true).unwrap();
Some(kwargs)
} else {
None
Expand Down Expand Up @@ -210,18 +208,18 @@ fn int_to_u32_vec(long: &PyLong, n_digits: usize, is_signed: bool) -> PyResult<V

#[cfg(Py_LIMITED_API)]
fn int_to_py_bytes(long: &PyLong, n_bytes: usize, is_signed: bool) -> PyResult<&PyBytes> {
use crate::intern_bound;
use crate::intern;
let py = long.py();
let kwargs = if is_signed {
let kwargs = PyDict::new(py);
kwargs.set_item(intern_bound!(py, "signed"), true)?;
kwargs.set_item(intern!(py, "signed"), true)?;
Some(kwargs)
} else {
None
};
let bytes = long.call_method(
intern_bound!(py, "to_bytes"),
(n_bytes, intern_bound!(py, "little")),
intern!(py, "to_bytes"),
(n_bytes, intern!(py, "little")),
kwargs,
)?;
Ok(bytes.downcast()?)
Expand All @@ -243,7 +241,7 @@ fn int_n_bits(long: &PyLong) -> PyResult<usize> {
#[cfg(Py_LIMITED_API)]
{
// slow path
long.call_method0(crate::intern_bound!(py, "bit_length"))
long.call_method0(crate::intern!(py, "bit_length"))
.and_then(PyAny::extract)
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/conversions/num_complex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ macro_rules! complex_conversion {
let obj = if obj.is_instance_of::<PyComplex>() {
obj
} else if let Some(method) =
obj.lookup_special(crate::intern_bound!(obj.py(), "__complex__"))?
obj.lookup_special(crate::intern!(obj.py(), "__complex__"))?
{
complex = method.call0()?;
&complex
Expand Down
8 changes: 3 additions & 5 deletions src/conversions/rust_decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@
use crate::exceptions::PyValueError;
use crate::sync::GILOnceCell;
use crate::types::PyType;
use crate::{
intern_bound, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject,
};
use crate::{intern, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject};
use rust_decimal::Decimal;
use std::str::FromStr;

Expand All @@ -75,8 +73,8 @@ static DECIMAL_CLS: GILOnceCell<Py<PyType>> = GILOnceCell::new();
fn get_decimal_cls(py: Python<'_>) -> PyResult<&PyType> {
DECIMAL_CLS
.get_or_try_init(py, || {
py.import(intern_bound!(py, "decimal"))?
.getattr(intern_bound!(py, "Decimal"))?
py.import(intern!(py, "decimal"))?
.getattr(intern!(py, "Decimal"))?
.extract()
})
.map(|ty| ty.as_ref(py))
Expand Down
9 changes: 4 additions & 5 deletions src/conversions/std/duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::types::PyType;
#[cfg(not(Py_LIMITED_API))]
use crate::types::{PyDelta, PyDeltaAccess};
#[cfg(Py_LIMITED_API)]
use crate::{intern_bound, Py};
use crate::{intern, Py};
use crate::{FromPyObject, IntoPy, PyAny, PyObject, PyResult, Python, ToPyObject};
use std::time::Duration;

Expand All @@ -26,10 +26,9 @@ impl FromPyObject<'_> for Duration {
#[cfg(Py_LIMITED_API)]
let (days, seconds, microseconds): (i32, i32, i32) = {
(
obj.getattr(intern_bound!(obj.py(), "days"))?.extract()?,
obj.getattr(intern_bound!(obj.py(), "seconds"))?.extract()?,
obj.getattr(intern_bound!(obj.py(), "microseconds"))?
.extract()?,
obj.getattr(intern!(obj.py(), "days"))?.extract()?,
obj.getattr(intern!(obj.py(), "seconds"))?.extract()?,
obj.getattr(intern!(obj.py(), "microseconds"))?.extract()?,
)
};

Expand Down
6 changes: 2 additions & 4 deletions src/conversions/std/ipaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use crate::exceptions::PyValueError;
use crate::sync::GILOnceCell;
use crate::types::PyType;
use crate::{
intern_bound, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject,
};
use crate::{intern, FromPyObject, IntoPy, Py, PyAny, PyObject, PyResult, Python, ToPyObject};

impl FromPyObject<'_> for IpAddr {
fn extract(obj: &PyAny) -> PyResult<Self> {
match obj.getattr(intern_bound!(obj.py(), "packed")) {
match obj.getattr(intern!(obj.py(), "packed")) {
Ok(packed) => {
if let Ok(packed) = packed.extract::<[u8; 4]>() {
Ok(IpAddr::V4(Ipv4Addr::from(packed)))
Expand Down
11 changes: 4 additions & 7 deletions src/coroutine/waker.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::sync::GILOnceCell;
use crate::types::PyCFunction;
use crate::{intern_bound, wrap_pyfunction, Py, PyAny, PyObject, PyResult, Python};
use crate::{intern, wrap_pyfunction, Py, PyAny, PyObject, PyResult, Python};
use pyo3_macros::pyfunction;
use std::sync::Arc;
use std::task::Wake;
Expand Down Expand Up @@ -72,7 +72,7 @@ impl LoopAndFuture {
// so it requires `call_soon_threadsafe`
let call_soon_threadsafe = self.event_loop.call_method1(
py,
intern_bound!(py, "call_soon_threadsafe"),
intern!(py, "call_soon_threadsafe"),
(release_waiter, self.future.as_ref(py)),
);
if let Err(err) = call_soon_threadsafe {
Expand All @@ -93,12 +93,9 @@ impl LoopAndFuture {
/// See <https://github.com/python/cpython/blob/main/Lib/asyncio/tasks.py#L452C5-L452C5>
#[pyfunction(crate = "crate")]
fn release_waiter(future: &PyAny) -> PyResult<()> {
let done = future.call_method0(intern_bound!(future.py(), "done"))?;
let done = future.call_method0(intern!(future.py(), "done"))?;
if !done.extract::<bool>()? {
future.call_method1(
intern_bound!(future.py(), "set_result"),
(future.py().None(),),
)?;
future.call_method1(intern!(future.py(), "set_result"), (future.py().None(),))?;
}
Ok(())
}
Loading

0 comments on commit 2f00eb1

Please sign in to comment.