Skip to content

Commit 1b5c844

Browse files
authored
Merge pull request #70 from davidhewitt/lifetimes
tidy up some lifetimes
2 parents d7f54f1 + 12ab817 commit 1b5c844

File tree

2 files changed

+57
-51
lines changed

2 files changed

+57
-51
lines changed

CHANGELOG.md

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
11
## Unreleased
22

3+
### Packaging
34
- Bump MSRV to 1.63
45
- Update to PyO3 0.22
6+
7+
### Added
58
- Support `u128` / `i128` integers.
6-
- Remove support for PyO3's `gil-refs` feature
7-
- `pythonize()` now returns `Bound<'py, PyAny>` instead of `Py<PyAny>`
8-
- `depythonize()` now take a `&Bound` and is no longer deprecated
9-
- `depythonize_bound()` is now deprecated
10-
- `Depythonizer` now contains a `&Bound` and so has an extra lifetime `'bound`
11-
- `Depythonizer::from_object()` now takes a `&Bound` and is no longer deprecated
12-
- Fix overflow error attempting to depythonize `u64` values greater than `i64::MAX` to types like `serde_json::Value`
139
- Implement `PythonizeListType` for `PyTuple`
1410
- Support deserializing enums from any `PyMapping` instead of just `PyDict`
1511
- Support serializing struct-like types to named mappings using `PythonizeTypes::NamedMap`
1612

13+
### Changed
14+
- `pythonize()` now returns `Bound<'py, PyAny>` instead of `Py<PyAny>`
15+
- `depythonize()` now take `&'a Bound` and is no longer deprecated
16+
- `depythonize_bound()` is now deprecated
17+
- `Depythonizer::from_object()` now takes `&'a Bound` and is no longer deprecated
18+
- `Depythonizer` now contains `&'a Bound` and so has an extra lifetime `'a`
19+
20+
### Removed
21+
- Remove support for PyO3's `gil-refs` feature
22+
23+
### Fixed
24+
- Fix overflow error attempting to depythonize `u64` values greater than `i64::MAX` to types like `serde_json::Value`
25+
1726
## 0.21.1 - 2024-04-02
1827

1928
- Fix compile error when using PyO3 `abi3` feature targeting a minimum version below 3.10

src/de.rs

+41-44
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,38 @@
11
use pyo3::{types::*, Bound};
2-
use serde::de::{self, IntoDeserializer};
2+
use serde::de::{self, DeserializeOwned, IntoDeserializer};
33
use serde::Deserialize;
44

55
use crate::error::{PythonizeError, Result};
66

77
/// Attempt to convert a Python object to an instance of `T`
8-
pub fn depythonize<'py, 'obj, T>(obj: &'obj Bound<'py, PyAny>) -> Result<T>
8+
pub fn depythonize<'a, 'py, T>(obj: &'a Bound<'py, PyAny>) -> Result<T>
99
where
10-
T: Deserialize<'obj>,
10+
T: Deserialize<'a>,
1111
{
12-
let mut depythonizer = Depythonizer::from_object(obj);
13-
T::deserialize(&mut depythonizer)
12+
T::deserialize(&mut Depythonizer::from_object(obj))
1413
}
1514

1615
/// Attempt to convert a Python object to an instance of `T`
1716
#[deprecated(since = "0.22.0", note = "use `depythonize` instead")]
1817
pub fn depythonize_bound<'py, T>(obj: Bound<'py, PyAny>) -> Result<T>
1918
where
20-
T: for<'a> Deserialize<'a>,
19+
T: DeserializeOwned,
2120
{
22-
let mut depythonizer = Depythonizer::from_object(&obj);
23-
T::deserialize(&mut depythonizer)
21+
T::deserialize(&mut Depythonizer::from_object(&obj))
2422
}
2523

2624
/// A structure that deserializes Python objects into Rust values
27-
pub struct Depythonizer<'py, 'bound> {
28-
input: &'bound Bound<'py, PyAny>,
25+
pub struct Depythonizer<'a, 'py> {
26+
input: &'a Bound<'py, PyAny>,
2927
}
3028

31-
impl<'py, 'bound> Depythonizer<'py, 'bound> {
29+
impl<'a, 'py> Depythonizer<'a, 'py> {
3230
/// Create a deserializer from a Python object
33-
pub fn from_object<'input>(input: &'input Bound<'py, PyAny>) -> Depythonizer<'py, 'input> {
31+
pub fn from_object(input: &'a Bound<'py, PyAny>) -> Self {
3432
Depythonizer { input }
3533
}
3634

37-
fn sequence_access(
38-
&self,
39-
expected_len: Option<usize>,
40-
) -> Result<PySequenceAccess<'py, 'bound>> {
35+
fn sequence_access(&self, expected_len: Option<usize>) -> Result<PySequenceAccess<'a, 'py>> {
4136
let seq = self.input.downcast::<PySequence>()?;
4237
let len = self.input.len()?;
4338

@@ -97,14 +92,14 @@ macro_rules! deserialize_type {
9792
};
9893
}
9994

100-
impl<'a, 'py, 'de, 'bound> de::Deserializer<'de> for &'a mut Depythonizer<'py, 'bound> {
95+
impl<'de> de::Deserializer<'de> for &'_ mut Depythonizer<'_, '_> {
10196
type Error = PythonizeError;
10297

10398
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
10499
where
105100
V: de::Visitor<'de>,
106101
{
107-
let obj = &self.input;
102+
let obj = self.input;
108103

109104
// First check for cases which are cheap to check due to pointer
110105
// comparison or bitflag checks
@@ -307,8 +302,7 @@ impl<'a, 'py, 'de, 'bound> de::Deserializer<'de> for &'a mut Depythonizer<'py, '
307302
.downcast_into::<PyString>()
308303
.map_err(|_| PythonizeError::dict_key_not_string())?;
309304
let value = m.get_item(&variant)?;
310-
let mut de = Depythonizer::from_object(&value);
311-
visitor.visit_enum(PyEnumAccess::new(&mut de, variant))
305+
visitor.visit_enum(PyEnumAccess::new(&value, variant))
312306
} else {
313307
Err(PythonizeError::invalid_enum_type())
314308
}
@@ -333,19 +327,19 @@ impl<'a, 'py, 'de, 'bound> de::Deserializer<'de> for &'a mut Depythonizer<'py, '
333327
}
334328
}
335329

336-
struct PySequenceAccess<'py, 'bound> {
337-
seq: &'bound Bound<'py, PySequence>,
330+
struct PySequenceAccess<'a, 'py> {
331+
seq: &'a Bound<'py, PySequence>,
338332
index: usize,
339333
len: usize,
340334
}
341335

342-
impl<'py, 'bound> PySequenceAccess<'py, 'bound> {
343-
fn new(seq: &'bound Bound<'py, PySequence>, len: usize) -> Self {
336+
impl<'a, 'py> PySequenceAccess<'a, 'py> {
337+
fn new(seq: &'a Bound<'py, PySequence>, len: usize) -> Self {
344338
Self { seq, index: 0, len }
345339
}
346340
}
347341

348-
impl<'de, 'py, 'bound> de::SeqAccess<'de> for PySequenceAccess<'py, 'bound> {
342+
impl<'de> de::SeqAccess<'de> for PySequenceAccess<'_, '_> {
349343
type Error = PythonizeError;
350344

351345
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
@@ -354,9 +348,9 @@ impl<'de, 'py, 'bound> de::SeqAccess<'de> for PySequenceAccess<'py, 'bound> {
354348
{
355349
if self.index < self.len {
356350
let item = self.seq.get_item(self.index)?;
357-
let mut item_de = Depythonizer::from_object(&item);
358351
self.index += 1;
359-
seed.deserialize(&mut item_de).map(Some)
352+
seed.deserialize(&mut Depythonizer::from_object(&item))
353+
.map(Some)
360354
} else {
361355
Ok(None)
362356
}
@@ -386,7 +380,7 @@ impl<'py> PyMappingAccess<'py> {
386380
}
387381
}
388382

389-
impl<'de, 'py> de::MapAccess<'de> for PyMappingAccess<'py> {
383+
impl<'de> de::MapAccess<'de> for PyMappingAccess<'_> {
390384
type Error = PythonizeError;
391385

392386
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
@@ -395,9 +389,9 @@ impl<'de, 'py> de::MapAccess<'de> for PyMappingAccess<'py> {
395389
{
396390
if self.key_idx < self.len {
397391
let item = self.keys.get_item(self.key_idx)?;
398-
let mut item_de = Depythonizer::from_object(&item);
399392
self.key_idx += 1;
400-
seed.deserialize(&mut item_de).map(Some)
393+
seed.deserialize(&mut Depythonizer::from_object(&item))
394+
.map(Some)
401395
} else {
402396
Ok(None)
403397
}
@@ -408,24 +402,26 @@ impl<'de, 'py> de::MapAccess<'de> for PyMappingAccess<'py> {
408402
V: de::DeserializeSeed<'de>,
409403
{
410404
let item = self.values.get_item(self.val_idx)?;
411-
let mut item_de = Depythonizer::from_object(&item);
412405
self.val_idx += 1;
413-
seed.deserialize(&mut item_de)
406+
seed.deserialize(&mut Depythonizer::from_object(&item))
414407
}
415408
}
416409

417-
struct PyEnumAccess<'a, 'py, 'bound> {
418-
de: &'a mut Depythonizer<'py, 'bound>,
410+
struct PyEnumAccess<'a, 'py> {
411+
de: Depythonizer<'a, 'py>,
419412
variant: Bound<'py, PyString>,
420413
}
421414

422-
impl<'a, 'py, 'bound> PyEnumAccess<'a, 'py, 'bound> {
423-
fn new(de: &'a mut Depythonizer<'py, 'bound>, variant: Bound<'py, PyString>) -> Self {
424-
Self { de, variant }
415+
impl<'a, 'py> PyEnumAccess<'a, 'py> {
416+
fn new(obj: &'a Bound<'py, PyAny>, variant: Bound<'py, PyString>) -> Self {
417+
Self {
418+
de: Depythonizer::from_object(obj),
419+
variant,
420+
}
425421
}
426422
}
427423

428-
impl<'a, 'py, 'de, 'bound> de::EnumAccess<'de> for PyEnumAccess<'a, 'py, 'bound> {
424+
impl<'de> de::EnumAccess<'de> for PyEnumAccess<'_, '_> {
429425
type Error = PythonizeError;
430426
type Variant = Self;
431427

@@ -440,7 +436,7 @@ impl<'a, 'py, 'de, 'bound> de::EnumAccess<'de> for PyEnumAccess<'a, 'py, 'bound>
440436
}
441437
}
442438

443-
impl<'a, 'py, 'de, 'bound> de::VariantAccess<'de> for PyEnumAccess<'a, 'py, 'bound> {
439+
impl<'de> de::VariantAccess<'de> for PyEnumAccess<'_, '_> {
444440
type Error = PythonizeError;
445441

446442
fn unit_variant(self) -> Result<()> {
@@ -451,7 +447,7 @@ impl<'a, 'py, 'de, 'bound> de::VariantAccess<'de> for PyEnumAccess<'a, 'py, 'bou
451447
where
452448
T: de::DeserializeSeed<'de>,
453449
{
454-
seed.deserialize(self.de)
450+
seed.deserialize(&mut { self.de })
455451
}
456452

457453
fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
@@ -482,14 +478,15 @@ mod test {
482478
T: de::DeserializeOwned + PartialEq + std::fmt::Debug,
483479
{
484480
Python::with_gil(|py| {
485-
let locals = PyDict::new_bound(py);
486-
py.run_bound(&format!("obj = {}", code), None, Some(&locals))
487-
.unwrap();
488-
let obj = locals.get_item("obj").unwrap().unwrap();
481+
let obj = py.eval_bound(code, None, None).unwrap();
489482
let actual: T = depythonize(&obj).unwrap();
490483
assert_eq!(&actual, expected);
491484
let actual_json: JsonValue = depythonize(&obj).unwrap();
492485
assert_eq!(&actual_json, expected_json);
486+
487+
#[allow(deprecated)]
488+
let actual: T = depythonize_bound(obj.clone()).unwrap();
489+
assert_eq!(&actual, expected);
493490
});
494491
}
495492

0 commit comments

Comments
 (0)