Skip to content

Commit

Permalink
change GILOnceCell::get_or_try_init_type_ref to GILOnceCell::import
Browse files Browse the repository at this point in the history
  • Loading branch information
glevco committed Sep 14, 2024
1 parent 5b16662 commit 245dae4
Show file tree
Hide file tree
Showing 11 changed files with 24 additions and 25 deletions.
12 changes: 6 additions & 6 deletions guide/src/python-from-rust/calling-existing-code.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

If you already have some existing Python code that you need to execute from Rust, the following FAQs can help you select the right PyO3 functionality for your situation:

## Want to access Python APIs? Then use `import`.
## Want to access Python APIs? Then use `PyModule::import`.

[`Python::import`] can be used to get handle to a Python module from Rust. You can use this to import and use any Python
[`PyModule::import`] can be used to get handle to a Python module from Rust. You can use this to import and use any Python
module available in your environment.

```rust
use pyo3::prelude::*;

fn main() -> PyResult<()> {
Python::with_gil(|py| {
let builtins = py.import("builtins")?;
let builtins = PyModule::import(py, "builtins")?;
let total: i32 = builtins
.getattr("sum")?
.call1((vec![1, 2, 3],))?
Expand All @@ -23,12 +23,12 @@ fn main() -> PyResult<()> {
}
```

[`Python::import`] introduces an overhead each time it's called. To avoid this in functions that are called multiple times,
[`PyModule::import`] introduces an overhead each time it's called. To avoid this in functions that are called multiple times,
using a [`GILOnceCell`]({{#PYO3_DOCS_URL}}/pyo3/sync/struct.GILOnceCell.html) is recommended. Specifically, for importing types,
[`GILOnceCell::get_or_try_init_type_ref`]({{#PYO3_DOCS_URL}}/pyo3/sync/struct.GILOnceCell.html#method.get_or_try_init_type_ref) is provided
[`GILOnceCell::import`]({{#PYO3_DOCS_URL}}/pyo3/sync/struct.GILOnceCell.html#method.import) is provided
(check out the [example]({{#PYO3_DOCS_URL}}/pyo3/sync/struct.GILOnceCell.html#example-using-giloncecell-to-avoid-the-overhead-of-importing-a-class-multiple-times)).

[`Python::import`]: {{#PYO3_DOCS_URL}}/pyo3/marker/struct.Python.html#method.import
[`PyModule::import`]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PyModule.html#method.import

## Want to run just an expression? Then use `eval`.

Expand Down
2 changes: 1 addition & 1 deletion newsfragments/4542.changed.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Change `GILOnceCell::get_or_try_init_type_ref` to public.
Change `GILOnceCell::get_or_try_init_type_ref` to `GILOnceCell::import` and make it public API.
2 changes: 1 addition & 1 deletion src/conversions/chrono_tz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl<'py> IntoPyObject<'py> for Tz {
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
static ZONE_INFO: GILOnceCell<Py<PyType>> = GILOnceCell::new();
ZONE_INFO
.get_or_try_init_type_ref(py, "zoneinfo", "ZoneInfo")
.import(py, "zoneinfo", "ZoneInfo")
.and_then(|obj| obj.call1((self.name(),)))
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/conversions/num_rational.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ use num_rational::Ratio;
static FRACTION_CLS: GILOnceCell<Py<PyType>> = GILOnceCell::new();

fn get_fraction_cls(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
FRACTION_CLS.get_or_try_init_type_ref(py, "fractions", "Fraction")
FRACTION_CLS.import(py, "fractions", "Fraction")
}

macro_rules! rational_conversion {
Expand Down
2 changes: 1 addition & 1 deletion src/conversions/rust_decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl FromPyObject<'_> for Decimal {
static DECIMAL_CLS: GILOnceCell<Py<PyType>> = GILOnceCell::new();

fn get_decimal_cls(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
DECIMAL_CLS.get_or_try_init_type_ref(py, "decimal", "Decimal")
DECIMAL_CLS.import(py, "decimal", "Decimal")
}

impl ToPyObject for Decimal {
Expand Down
4 changes: 2 additions & 2 deletions src/conversions/std/ipaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl<'py> IntoPyObject<'py> for Ipv4Addr {
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
static IPV4_ADDRESS: GILOnceCell<Py<PyType>> = GILOnceCell::new();
IPV4_ADDRESS
.get_or_try_init_type_ref(py, "ipaddress", "IPv4Address")?
.import(py, "ipaddress", "IPv4Address")?
.call1((u32::from_be_bytes(self.octets()),))
}
}
Expand Down Expand Up @@ -77,7 +77,7 @@ impl<'py> IntoPyObject<'py> for Ipv6Addr {
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
static IPV6_ADDRESS: GILOnceCell<Py<PyType>> = GILOnceCell::new();
IPV6_ADDRESS
.get_or_try_init_type_ref(py, "ipaddress", "IPv6Address")?
.import(py, "ipaddress", "IPv6Address")?
.call1((u128::from_be_bytes(self.octets()),))
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/conversions/std/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl<'py> IntoPyObject<'py> for Duration {
{
static TIMEDELTA: GILOnceCell<Py<PyType>> = GILOnceCell::new();
TIMEDELTA
.get_or_try_init_type_ref(py, "datetime", "timedelta")?
.import(py, "datetime", "timedelta")?
.call1((days, seconds, microseconds))
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/impl_/exceptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl ImportedExceptionTypeObject {

pub fn get<'py>(&self, py: Python<'py>) -> &Bound<'py, PyType> {
self.imported_value
.get_or_try_init_type_ref(py, self.module, self.name)
.import(py, self.module, self.name)
.unwrap_or_else(|e| {
panic!(
"failed to import exception {}.{}: {}",
Expand Down
17 changes: 8 additions & 9 deletions src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
//! are likely to undergo significant developments in the future.
//!
//! [PEP 703]: https://peps.python.org/pep-703/
use crate::{
types::{any::PyAnyMethods, PyString, PyType},
Bound, Py, PyResult, Python,
};
use crate::{types::{any::PyAnyMethods, PyString, PyType}, Bound, Py, PyResult, PyTypeCheck, Python};
use std::cell::UnsafeCell;

#[cfg(not(Py_GIL_DISABLED))]
Expand Down Expand Up @@ -214,7 +211,10 @@ impl<T> GILOnceCell<Py<T>> {
}
}

impl GILOnceCell<Py<PyType>> {
impl<T> GILOnceCell<Py<T>>
where
T: PyTypeCheck
{
/// Get a reference to the contained Python type, initializing it if needed.
///
/// This is a shorthand method for `get_or_init` which imports the type from Python on init.
Expand All @@ -233,7 +233,7 @@ impl GILOnceCell<Py<PyType>> {
/// // the `OrderedDict` class will be imported only once.
/// static ORDERED_DICT: GILOnceCell<Py<PyType>> = GILOnceCell::new();
/// ORDERED_DICT
/// .get_or_try_init_type_ref(py, "collections", "OrderedDict")?
/// .import(py, "collections", "OrderedDict")?
/// .call1((dict,))
/// }
///
Expand All @@ -245,13 +245,12 @@ impl GILOnceCell<Py<PyType>> {
/// # assert!(dict.eq(ordered_dict).unwrap());
/// # });
/// ```
///
pub fn get_or_try_init_type_ref<'py>(
pub fn import<'py>(
&self,
py: Python<'py>,
module_name: &str,
attr_name: &str,
) -> PyResult<&Bound<'py, PyType>> {
) -> PyResult<&Bound<'py, T>> {
self.get_or_try_init(py, || {
let type_object = py
.import(module_name)?
Expand Down
2 changes: 1 addition & 1 deletion src/types/mapping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl<'py> PyMappingMethods<'py> for Bound<'py, PyMapping> {
fn get_mapping_abc(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
static MAPPING_ABC: GILOnceCell<Py<PyType>> = GILOnceCell::new();

MAPPING_ABC.get_or_try_init_type_ref(py, "collections.abc", "Mapping")
MAPPING_ABC.import(py, "collections.abc", "Mapping")
}

impl PyTypeCheck for PyMapping {
Expand Down
2 changes: 1 addition & 1 deletion src/types/sequence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ where
fn get_sequence_abc(py: Python<'_>) -> PyResult<&Bound<'_, PyType>> {
static SEQUENCE_ABC: GILOnceCell<Py<PyType>> = GILOnceCell::new();

SEQUENCE_ABC.get_or_try_init_type_ref(py, "collections.abc", "Sequence")
SEQUENCE_ABC.import(py, "collections.abc", "Sequence")
}

impl PyTypeCheck for PySequence {
Expand Down

0 comments on commit 245dae4

Please sign in to comment.