diff -pruN 0.21.1-1/.cargo_vcs_info.json 0.25.0-1/.cargo_vcs_info.json
--- 0.21.1-1/.cargo_vcs_info.json	1970-01-01 00:00:01.000000000 +0000
+++ 0.25.0-1/.cargo_vcs_info.json	1970-01-01 00:00:01.000000000 +0000
@@ -1,6 +1,6 @@
 {
   "git": {
-    "sha1": "c3a45879ce0455099191c4de26bd62d2743cd7d2"
+    "sha1": "435870cd014456dc13a384434f6f43838152c459"
   },
   "path_in_vcs": ""
 }
\ No newline at end of file
diff -pruN 0.21.1-1/.github/workflows/ci.yml 0.25.0-1/.github/workflows/ci.yml
--- 0.21.1-1/.github/workflows/ci.yml	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/.github/workflows/ci.yml	2006-07-24 01:21:28.000000000 +0000
@@ -10,6 +10,19 @@ env:
   CARGO_TERM_COLOR: always
 
 jobs:
+  resolve:
+    runs-on: ubuntu-latest
+    outputs:
+      MSRV: ${{ steps.resolve-msrv.outputs.MSRV }}
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
+          python-version: "3.12"
+      - name: resolve MSRV
+        id: resolve-msrv
+        run: echo MSRV=`python -c 'import tomllib; print(tomllib.load(open("Cargo.toml", "rb"))["package"]["rust-version"])'` >> $GITHUB_OUTPUT
+
   fmt:
     runs-on: ubuntu-latest
     steps:
@@ -30,23 +43,24 @@ jobs:
       - run: cargo clippy --all
 
   build:
-    needs: [fmt] # don't wait for clippy as fails rarely and takes longer
+    needs: [resolve, fmt] # don't wait for clippy as fails rarely and takes longer
     name: python${{ matrix.python-version }} ${{ matrix.os }} rust-${{ matrix.rust}}
     runs-on: ${{ matrix.os }}
     strategy:
-      fail-fast: false  # If one platform fails, allow the rest to keep testing.
+      fail-fast: false # If one platform fails, allow the rest to keep testing.
       matrix:
-        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
-        os: [
-          "macos-latest",
-          "ubuntu-latest",
-          "windows-latest",
-        ]
+        python-architecture: ["x64"]
+        python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.13t"]
+        os: ["macos-13", "ubuntu-latest", "windows-latest"]
         rust: [stable]
         include:
-          - python-version: "3.12"
+          - python-version: "3.13"
             os: "ubuntu-latest"
-            rust: "1.56"
+            rust: ${{ needs.resolve.outputs.MSRV }}
+          - python-version: "3.13"
+            python-architecture: "arm64"
+            os: "macos-latest"
+            rust: "stable"
 
     steps:
       - uses: actions/checkout@v4
@@ -55,7 +69,7 @@ jobs:
         uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python-version }}
-          architecture: x64
+          architecture: ${{ matrix.python-python-architecture }}
 
       - name: Install Rust toolchain
         uses: dtolnay/rust-toolchain@master
@@ -65,10 +79,18 @@ jobs:
       - uses: Swatinem/rust-cache@v2
         continue-on-error: true
 
+      - if: ${{ matrix.rust == needs.resolve.outputs.MSRV }}
+        name: Set dependencies on MSRV
+        run: cargo +stable update
+        env:
+          CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: fallback
+
       - name: Test
         run: cargo test --verbose
 
-      - name: Test (abi3)
+      # https://github.com/PyO3/pyo3/issues/4709 - can't use abi3 w. freethreaded build
+      - if: ${{ !endsWith(matrix.python-version, 't') }}
+        name: Test (abi3)
         run: cargo test --verbose --features pyo3/abi3-py37
 
     env:
diff -pruN 0.21.1-1/.github/workflows/release.yml 0.25.0-1/.github/workflows/release.yml
--- 0.21.1-1/.github/workflows/release.yml	1970-01-01 00:00:00.000000000 +0000
+++ 0.25.0-1/.github/workflows/release.yml	2006-07-24 01:21:28.000000000 +0000
@@ -0,0 +1,21 @@
+name: Release Rust Crate
+
+on:
+  push:
+    tags:
+      - "v*"
+
+jobs:
+  release:
+    runs-on: ubuntu-latest
+    environment: release
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+
+      - uses: dtolnay/rust-toolchain@stable
+
+      - name: Publish to crates.io
+        run: cargo publish
+        env:
+          CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
diff -pruN 0.21.1-1/CHANGELOG.md 0.25.0-1/CHANGELOG.md
--- 0.21.1-1/CHANGELOG.md	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/CHANGELOG.md	2006-07-24 01:21:28.000000000 +0000
@@ -1,3 +1,42 @@
+## 0.24.0 - 2025-03-26
+
+### Packaging
+- Update to PyO3 0.24
+
+## Removed
+- Remove deprecated `depythonize_bound()`
+
+## 0.23.0 - 2024-11-22
+
+### Packaging
+- Update to PyO3 0.23
+
+## 0.22.0 - 2024-08-10
+
+### Packaging
+- Bump MSRV to 1.63
+- Update to PyO3 0.22
+
+### Added
+- Support `u128` / `i128` integers.
+- Implement `PythonizeListType` for `PyTuple`
+- Support deserializing enums from any `PyMapping` instead of just `PyDict`
+- Support serializing struct-like types to named mappings using `PythonizeTypes::NamedMap`
+
+### Changed
+- `pythonize()` now returns `Bound<'py, PyAny>` instead of `Py<PyAny>`
+- `depythonize()` now take `&'a Bound` and is no longer deprecated
+- `depythonize_bound()` is now deprecated
+- `Depythonizer::from_object()` now takes `&'a Bound` and is no longer deprecated
+- `Depythonizer` now contains `&'a Bound` and so has an extra lifetime `'a`
+
+### Removed
+- Remove support for PyO3's `gil-refs` feature
+
+### Fixed
+- Fix overflow error attempting to depythonize `u64` values greater than `i64::MAX` to types like `serde_json::Value`
+- Fix deserializing `set` and `frozenset` into Rust homogeneous containers
+
 ## 0.21.1 - 2024-04-02
 
 - Fix compile error when using PyO3 `abi3` feature targeting a minimum version below 3.10
diff -pruN 0.21.1-1/Cargo.lock 0.25.0-1/Cargo.lock
--- 0.21.1-1/Cargo.lock	1970-01-01 00:00:00.000000000 +0000
+++ 0.25.0-1/Cargo.lock	1970-01-01 00:00:01.000000000 +0000
@@ -0,0 +1,244 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "autocfg"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
+
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
+[[package]]
+name = "indoc"
+version = "2.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
+
+[[package]]
+name = "itoa"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
+
+[[package]]
+name = "libc"
+version = "0.2.172"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
+
+[[package]]
+name = "maplit"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
+
+[[package]]
+name = "portable-atomic"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.95"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "pyo3"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f239d656363bcee73afef85277f1b281e8ac6212a1d42aa90e55b90ed43c47a4"
+dependencies = [
+ "indoc",
+ "libc",
+ "memoffset",
+ "once_cell",
+ "portable-atomic",
+ "pyo3-build-config",
+ "pyo3-ffi",
+ "pyo3-macros",
+ "unindent",
+]
+
+[[package]]
+name = "pyo3-build-config"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "755ea671a1c34044fa165247aaf6f419ca39caa6003aee791a0df2713d8f1b6d"
+dependencies = [
+ "once_cell",
+ "target-lexicon",
+]
+
+[[package]]
+name = "pyo3-ffi"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc95a2e67091e44791d4ea300ff744be5293f394f1bafd9f78c080814d35956e"
+dependencies = [
+ "libc",
+ "pyo3-build-config",
+]
+
+[[package]]
+name = "pyo3-macros"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a179641d1b93920829a62f15e87c0ed791b6c8db2271ba0fd7c2686090510214"
+dependencies = [
+ "proc-macro2",
+ "pyo3-macros-backend",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pyo3-macros-backend"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dff85ebcaab8c441b0e3f7ae40a6963ecea8a9f5e74f647e33fcf5ec9a1e89e"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "pyo3-build-config",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pythonize"
+version = "0.25.0"
+dependencies = [
+ "maplit",
+ "pyo3",
+ "serde",
+ "serde_bytes",
+ "serde_json",
+ "serde_path_to_error",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "ryu"
+version = "1.0.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
+
+[[package]]
+name = "serde"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.219"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.140"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
+dependencies = [
+ "itoa",
+ "memchr",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_path_to_error"
+version = "0.1.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a"
+dependencies = [
+ "itoa",
+ "serde",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.101"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
+
+[[package]]
+name = "unindent"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
diff -pruN 0.21.1-1/Cargo.toml 0.25.0-1/Cargo.toml
--- 0.21.1-1/Cargo.toml	1970-01-01 00:00:01.000000000 +0000
+++ 0.25.0-1/Cargo.toml	1970-01-01 00:00:01.000000000 +0000
@@ -11,10 +11,16 @@
 
 [package]
 edition = "2021"
-rust-version = "1.56"
+rust-version = "1.63"
 name = "pythonize"
-version = "0.21.1"
+version = "0.25.0"
 authors = ["David Hewitt <1939362+davidhewitt@users.noreply.github.com>"]
+build = false
+autolib = false
+autobins = false
+autoexamples = false
+autotests = false
+autobenches = false
 description = "Serde Serializer & Deserializer from Rust <--> Python, backed by PyO3."
 homepage = "https://github.com/davidhewitt/pythonize"
 documentation = "https://docs.rs/crate/pythonize/"
@@ -22,8 +28,20 @@ readme = "README.md"
 license = "MIT"
 repository = "https://github.com/davidhewitt/pythonize"
 
+[lib]
+name = "pythonize"
+path = "src/lib.rs"
+
+[[test]]
+name = "test_custom_types"
+path = "tests/test_custom_types.rs"
+
+[[test]]
+name = "test_with_serde_path_to_err"
+path = "tests/test_with_serde_path_to_err.rs"
+
 [dependencies.pyo3]
-version = "0.21.0"
+version = "0.25"
 default-features = false
 
 [dependencies.serde]
@@ -35,10 +53,11 @@ default-features = false
 version = "1.0.2"
 
 [dev-dependencies.pyo3]
-version = "0.21.1"
+version = "0.25"
 features = [
     "auto-initialize",
     "macros",
+    "py-clone",
 ]
 default-features = false
 
@@ -47,6 +66,9 @@ version = "1.0"
 features = ["derive"]
 default-features = false
 
+[dev-dependencies.serde_bytes]
+version = "0.11"
+
 [dev-dependencies.serde_json]
 version = "1.0"
 
diff -pruN 0.21.1-1/Cargo.toml.orig 0.25.0-1/Cargo.toml.orig
--- 0.21.1-1/Cargo.toml.orig	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/Cargo.toml.orig	2006-07-24 01:21:28.000000000 +0000
@@ -1,9 +1,9 @@
 [package]
 name = "pythonize"
-version = "0.21.1"
+version = "0.25.0"
 authors = ["David Hewitt <1939362+davidhewitt@users.noreply.github.com>"]
 edition = "2021"
-rust-version = "1.56"
+rust-version = "1.63"
 license = "MIT"
 description = "Serde Serializer & Deserializer from Rust <--> Python, backed by PyO3."
 homepage = "https://github.com/davidhewitt/pythonize"
@@ -13,11 +13,12 @@ documentation = "https://docs.rs/crate/p
 
 [dependencies]
 serde = { version = "1.0", default-features = false, features = ["std"] }
-pyo3 = { version = "0.21.0", default-features = false }
+pyo3 = { version = "0.25", default-features = false }
 
 [dev-dependencies]
 serde = { version = "1.0", default-features = false, features = ["derive"] }
-pyo3 = { version = "0.21.1", default-features = false, features = ["auto-initialize", "macros"] }
+pyo3 = { version = "0.25", default-features = false, features = ["auto-initialize", "macros", "py-clone"] }
 serde_json = "1.0"
+serde_bytes = "0.11"
 maplit = "1.0.2"
 serde_path_to_error = "0.1.15"
diff -pruN 0.21.1-1/README.md 0.25.0-1/README.md
--- 0.21.1-1/README.md	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/README.md	2006-07-24 01:21:28.000000000 +0000
@@ -10,7 +10,9 @@ that which is produced directly by `pyth
 This crate converts Rust types which implement the [Serde] serialization
 traits into Python objects using the [PyO3] library.
 
-Pythonize has two public APIs: `pythonize` and `depythonize`.
+Pythonize has two main public APIs: `pythonize` and `depythonize`.
+
+</div>
 
 [Serde]: https://github.com/serde-rs/serde
 [PyO3]: https://github.com/PyO3/pyo3
@@ -19,7 +21,7 @@ Pythonize has two public APIs: `pythoniz
 
 ```rust
 use serde::{Serialize, Deserialize};
-use pyo3::Python;
+use pyo3::prelude::*;
 use pythonize::{depythonize, pythonize};
 
 #[derive(Debug, Serialize, Deserialize, PartialEq)]
@@ -28,21 +30,20 @@ struct Sample {
     bar: Option<usize>
 }
 
-let gil = Python::acquire_gil();
-let py = gil.python();
-
 let sample = Sample {
     foo: "Foo".to_string(),
     bar: None
 };
 
-// Rust -> Python
-let obj = pythonize(py, &sample).unwrap();
+Python::with_gil(|py| {
+    // Rust -> Python
+    let obj =  pythonize(py, &sample).unwrap();
 
-assert_eq!("{'foo': 'Foo', 'bar': None}", &format!("{}", obj.as_ref(py).repr().unwrap()));
+    assert_eq!("{'foo': 'Foo', 'bar': None}", &format!("{}", obj.repr().unwrap()));
 
-// Python -> Rust
-let new_sample: Sample = depythonize(obj.as_ref(py)).unwrap();
+    // Python -> Rust
+    let new_sample: Sample = depythonize(&obj).unwrap();
 
-assert_eq!(new_sample, sample);
+    assert_eq!(new_sample, sample);
+})
 ```
diff -pruN 0.21.1-1/debian/cargo-checksum.json 0.25.0-1/debian/cargo-checksum.json
--- 0.21.1-1/debian/cargo-checksum.json	2024-07-30 16:39:13.000000000 +0000
+++ 0.25.0-1/debian/cargo-checksum.json	2025-08-22 00:59:04.000000000 +0000
@@ -1 +1 @@
-{"package":"Could not get crate checksum","files":{}}
+{"package":"597907139a488b22573158793aa7539df36ae863eba300c75f3a0d65fc475e27","files":{}}
diff -pruN 0.21.1-1/debian/changelog 0.25.0-1/debian/changelog
--- 0.21.1-1/debian/changelog	2024-07-30 16:39:13.000000000 +0000
+++ 0.25.0-1/debian/changelog	2025-08-22 00:59:04.000000000 +0000
@@ -1,3 +1,11 @@
+rust-pythonize (0.25.0-1) unstable; urgency=medium
+
+  * Team upload.
+  * Package pythonize 0.25.0 from crates.io using debcargo 2.7.8
+  * Drop patch pyo3-0.22, no longer needed.
+
+ -- Peter Michael Green <plugwash@debian.org>  Fri, 22 Aug 2025 00:59:04 +0000
+
 rust-pythonize (0.21.1-1) unstable; urgency=medium
 
   * Team upload.
diff -pruN 0.21.1-1/debian/compat 0.25.0-1/debian/compat
--- 0.21.1-1/debian/compat	2024-07-30 16:39:13.000000000 +0000
+++ 0.25.0-1/debian/compat	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-12
diff -pruN 0.21.1-1/debian/control 0.25.0-1/debian/control
--- 0.21.1-1/debian/control	2024-07-30 16:39:13.000000000 +0000
+++ 0.25.0-1/debian/control	2025-08-22 00:59:04.000000000 +0000
@@ -1,17 +1,17 @@
 Source: rust-pythonize
 Section: rust
 Priority: optional
-Build-Depends: debhelper (>= 12),
- dh-cargo (>= 25),
- cargo:native <!nocheck>,
- rustc:native (>= 1.56) <!nocheck>,
+Build-Depends: debhelper-compat (= 13),
+ dh-sequence-cargo
+Build-Depends-Arch: cargo:native <!nocheck>,
+ rustc:native (>= 1.63) <!nocheck>,
  libstd-rust-dev <!nocheck>,
- librust-pyo3-0.22-dev <!nocheck>,
+ librust-pyo3-0.25-dev <!nocheck>,
  librust-serde-1+std-dev <!nocheck>
 Maintainer: Debian Rust Maintainers <pkg-rust-maintainers@alioth-lists.debian.net>
 Uploaders:
  Antonio Russo <aerusso@aerusso.net>
-Standards-Version: 4.6.2
+Standards-Version: 4.7.0
 Vcs-Git: https://salsa.debian.org/rust-team/debcargo-conf.git [src/pythonize]
 Vcs-Browser: https://salsa.debian.org/rust-team/debcargo-conf/tree/master/src/pythonize
 Homepage: https://github.com/davidhewitt/pythonize
@@ -23,15 +23,15 @@ Architecture: any
 Multi-Arch: same
 Depends:
  ${misc:Depends},
- librust-pyo3-0.22-dev,
+ librust-pyo3-0.25-dev,
  librust-serde-1+std-dev
 Provides:
  librust-pythonize+default-dev (= ${binary:Version}),
  librust-pythonize-0-dev (= ${binary:Version}),
  librust-pythonize-0+default-dev (= ${binary:Version}),
- librust-pythonize-0.21-dev (= ${binary:Version}),
- librust-pythonize-0.21+default-dev (= ${binary:Version}),
- librust-pythonize-0.21.1-dev (= ${binary:Version}),
- librust-pythonize-0.21.1+default-dev (= ${binary:Version})
+ librust-pythonize-0.25-dev (= ${binary:Version}),
+ librust-pythonize-0.25+default-dev (= ${binary:Version}),
+ librust-pythonize-0.25.0-dev (= ${binary:Version}),
+ librust-pythonize-0.25.0+default-dev (= ${binary:Version})
 Description: Rust <-> Python interconnect using Serde and PyO3 - Rust source code
  Source code for Debianized Rust crate "pythonize"
diff -pruN 0.21.1-1/debian/copyright.debcargo.hint 0.25.0-1/debian/copyright.debcargo.hint
--- 0.21.1-1/debian/copyright.debcargo.hint	2024-07-30 16:39:13.000000000 +0000
+++ 0.25.0-1/debian/copyright.debcargo.hint	2025-08-22 00:59:04.000000000 +0000
@@ -21,8 +21,8 @@ Comment:
 
 Files: debian/*
 Copyright:
- 2023-2024 Debian Rust Maintainers <pkg-rust-maintainers@alioth-lists.debian.net>
- 2023-2024 Antonio Russo <aerusso@aerusso.net>
+ 2023-2025 Debian Rust Maintainers <pkg-rust-maintainers@alioth-lists.debian.net>
+ 2023-2025 Antonio Russo <aerusso@aerusso.net>
 License: MIT
 
 License: MIT
diff -pruN 0.21.1-1/debian/patches/pyo3-0.22 0.25.0-1/debian/patches/pyo3-0.22
--- 0.21.1-1/debian/patches/pyo3-0.22	2024-07-30 16:39:13.000000000 +0000
+++ 0.25.0-1/debian/patches/pyo3-0.22	1970-01-01 00:00:00.000000000 +0000
@@ -1,153 +0,0 @@
-Author: Henning Holm <git@henningholm.de>
-Origin: https://github.com/davidhewitt/pythonize/pull/66
-
-Index: pythonize/CHANGELOG.md
-===================================================================
---- pythonize.orig/CHANGELOG.md
-+++ pythonize/CHANGELOG.md
-@@ -1,3 +1,10 @@
-+## Unreleased
-+
-+- Update to PyO3 0.22
-+- Remove deprecated `depythonize`, use `depythonize_bound` instead
-+- Remove deprecated `from_object`, use `from_object_bound` instead
-+- Remove conversion from `PyDowncastError` to `PythonizeError`
-+
- ## 0.21.1 - 2024-04-02
- 
- - Fix compile error when using PyO3 `abi3` feature targeting a minimum version below 3.10
-Index: pythonize/src/de.rs
-===================================================================
---- pythonize.orig/src/de.rs
-+++ pythonize/src/de.rs
-@@ -1,23 +1,10 @@
--use pyo3::{types::*, Bound, PyNativeType};
-+use pyo3::{types::*, Bound};
- use serde::de::{self, IntoDeserializer};
- use serde::Deserialize;
- 
- use crate::error::{PythonizeError, Result};
- 
- /// Attempt to convert a Python object to an instance of `T`
--#[deprecated(
--    since = "0.21.0",
--    note = "will be replaced by `depythonize_bound` in a future release"
--)]
--pub fn depythonize<'de, T>(obj: &'de PyAny) -> Result<T>
--where
--    T: Deserialize<'de>,
--{
--    let mut depythonizer = Depythonizer::from_object_bound(obj.as_borrowed().to_owned());
--    T::deserialize(&mut depythonizer)
--}
--
--/// Attempt to convert a Python object to an instance of `T`
- pub fn depythonize_bound<'py, T>(obj: Bound<'py, PyAny>) -> Result<T>
- where
-     T: for<'a> Deserialize<'a>,
-@@ -33,15 +20,6 @@ pub struct Depythonizer<'py> {
- 
- impl<'py> Depythonizer<'py> {
-     /// Create a deserializer from a Python object
--    #[deprecated(
--        since = "0.21.0",
--        note = "will be replaced by `Depythonizer::from_object_bound` in a future version"
--    )]
--    pub fn from_object(input: &'py PyAny) -> Self {
--        Self::from_object_bound(input.as_borrowed().to_owned())
--    }
--
--    /// Create a deserializer from a Python object
-     pub fn from_object_bound(input: Bound<'py, PyAny>) -> Self {
-         Depythonizer { input }
-     }
-Index: pythonize/src/error.rs
-===================================================================
---- pythonize.orig/src/error.rs
-+++ pythonize/src/error.rs
-@@ -1,5 +1,5 @@
-+use pyo3::PyErr;
- use pyo3::{exceptions::*, DowncastError, DowncastIntoError};
--use pyo3::{PyDowncastError, PyErr};
- use serde::{de, ser};
- use std::error;
- use std::fmt::{self, Debug, Display};
-@@ -144,15 +144,6 @@ impl From<PyErr> for PythonizeError {
-         }
-     }
- }
--
--/// Handle errors that occur when attempting to use `PyAny::cast_as`
--impl<'a> From<PyDowncastError<'a>> for PythonizeError {
--    fn from(other: PyDowncastError) -> Self {
--        Self {
--            inner: Box::new(ErrorImpl::UnexpectedType(other.to_string())),
--        }
--    }
--}
- 
- /// Handle errors that occur when attempting to use `PyAny::cast_as`
- impl<'a, 'py> From<DowncastError<'a, 'py>> for PythonizeError {
-Index: pythonize/src/lib.rs
-===================================================================
---- pythonize.orig/src/lib.rs
-+++ pythonize/src/lib.rs
-@@ -9,8 +9,8 @@
- //! # Examples
- //! ```
- //! use serde::{Serialize, Deserialize};
--//! use pyo3::Python;
--//! use pythonize::{depythonize, pythonize};
-+//! use pyo3::{types::PyAnyMethods, Python};
-+//! use pythonize::{depythonize_bound, pythonize};
- //!
- //! #[derive(Debug, Serialize, Deserialize, PartialEq)]
- //! struct Sample {
-@@ -27,10 +27,10 @@
- //!     // Rust -> Python
- //!     let obj = pythonize(py, &sample).unwrap();
- //!
--//!     assert_eq!("{'foo': 'Foo', 'bar': None}", &format!("{}", obj.as_ref(py).repr().unwrap()));
-+//!     assert_eq!("{'foo': 'Foo', 'bar': None}", &format!("{}", obj.bind(py).repr().unwrap()));
- //!
- //!     // Python -> Rust
--//!     let new_sample: Sample = depythonize(obj.as_ref(py)).unwrap();
-+//!     let new_sample: Sample = depythonize_bound(obj.into_bound(py)).unwrap();
- //!
- //!     assert_eq!(new_sample, sample);
- //! });
-@@ -40,8 +40,6 @@ mod de;
- mod error;
- mod ser;
- 
--#[allow(deprecated)]
--pub use crate::de::depythonize;
- pub use crate::de::{depythonize_bound, Depythonizer};
- pub use crate::error::{PythonizeError, Result};
- pub use crate::ser::{
-Index: pythonize/Cargo.toml
-===================================================================
---- pythonize.orig/Cargo.toml
-+++ pythonize/Cargo.toml
-@@ -23,7 +23,7 @@ license = "MIT"
- repository = "https://github.com/davidhewitt/pythonize"
- 
- [dependencies.pyo3]
--version = "0.21.0"
-+version = "0.22"
- default-features = false
- 
- [dependencies.serde]
-@@ -35,10 +35,11 @@ default-features = false
- version = "1.0.2"
- 
- [dev-dependencies.pyo3]
--version = "0.21.1"
-+version = "0.22"
- features = [
-     "auto-initialize",
-     "macros",
-+    "py-clone",
- ]
- default-features = false
- 
diff -pruN 0.21.1-1/debian/patches/series 0.25.0-1/debian/patches/series
--- 0.21.1-1/debian/patches/series	2024-07-30 16:39:13.000000000 +0000
+++ 0.25.0-1/debian/patches/series	1970-01-01 00:00:00.000000000 +0000
@@ -1 +0,0 @@
-pyo3-0.22
diff -pruN 0.21.1-1/debian/tests/control 0.25.0-1/debian/tests/control
--- 0.21.1-1/debian/tests/control	2024-07-30 16:39:13.000000000 +0000
+++ 0.25.0-1/debian/tests/control	2025-08-22 00:59:04.000000000 +0000
@@ -1,14 +1,14 @@
-Test-Command: /usr/share/cargo/bin/cargo-auto-test pythonize 0.21.1 --all-targets --all-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test pythonize 0.25.0 --all-targets --all-features
 Features: test-name=rust-pythonize:@
-Depends: dh-cargo (>= 18), librust-maplit-1+default-dev (>= 1.0.2-~~), librust-pyo3-0.22+auto-initialize-dev, librust-pyo3-0.22+macros-dev, librust-pyo3-0.22+py-clone-dev, librust-serde-1+derive-dev, librust-serde-json-1+default-dev, librust-serde-path-to-error-0.1+default-dev (>= 0.1.15-~~), @
+Depends: dh-cargo (>= 31), rustc (>= 1.63), librust-maplit-1+default-dev (>= 1.0.2-~~), librust-pyo3-0.25+auto-initialize-dev, librust-pyo3-0.25+macros-dev, librust-pyo3-0.25+py-clone-dev, librust-serde-1+derive-dev, librust-serde-bytes-0.11+default-dev, librust-serde-json-1+default-dev, librust-serde-path-to-error-0.1+default-dev (>= 0.1.15-~~), @
 Restrictions: allow-stderr, skip-not-installable
 
-Test-Command: /usr/share/cargo/bin/cargo-auto-test pythonize 0.21.1 --all-targets
+Test-Command: /usr/share/cargo/bin/cargo-auto-test pythonize 0.25.0 --all-targets
 Features: test-name=librust-pythonize-dev:default
-Depends: dh-cargo (>= 18), librust-maplit-1+default-dev (>= 1.0.2-~~), librust-pyo3-0.22+auto-initialize-dev, librust-pyo3-0.22+macros-dev, librust-pyo3-0.22+py-clone-dev, librust-serde-1+derive-dev, librust-serde-json-1+default-dev, librust-serde-path-to-error-0.1+default-dev (>= 0.1.15-~~), @
+Depends: dh-cargo (>= 31), rustc (>= 1.63), librust-maplit-1+default-dev (>= 1.0.2-~~), librust-pyo3-0.25+auto-initialize-dev, librust-pyo3-0.25+macros-dev, librust-pyo3-0.25+py-clone-dev, librust-serde-1+derive-dev, librust-serde-bytes-0.11+default-dev, librust-serde-json-1+default-dev, librust-serde-path-to-error-0.1+default-dev (>= 0.1.15-~~), @
 Restrictions: allow-stderr, skip-not-installable
 
-Test-Command: /usr/share/cargo/bin/cargo-auto-test pythonize 0.21.1 --all-targets --no-default-features
+Test-Command: /usr/share/cargo/bin/cargo-auto-test pythonize 0.25.0 --all-targets --no-default-features
 Features: test-name=librust-pythonize-dev:
-Depends: dh-cargo (>= 18), librust-maplit-1+default-dev (>= 1.0.2-~~), librust-pyo3-0.22+auto-initialize-dev, librust-pyo3-0.22+macros-dev, librust-pyo3-0.22+py-clone-dev, librust-serde-1+derive-dev, librust-serde-json-1+default-dev, librust-serde-path-to-error-0.1+default-dev (>= 0.1.15-~~), @
+Depends: dh-cargo (>= 31), rustc (>= 1.63), librust-maplit-1+default-dev (>= 1.0.2-~~), librust-pyo3-0.25+auto-initialize-dev, librust-pyo3-0.25+macros-dev, librust-pyo3-0.25+py-clone-dev, librust-serde-1+derive-dev, librust-serde-bytes-0.11+default-dev, librust-serde-json-1+default-dev, librust-serde-path-to-error-0.1+default-dev (>= 0.1.15-~~), @
 Restrictions: allow-stderr, skip-not-installable
diff -pruN 0.21.1-1/debian/watch 0.25.0-1/debian/watch
--- 0.21.1-1/debian/watch	2024-07-30 16:39:13.000000000 +0000
+++ 0.25.0-1/debian/watch	2025-08-22 00:59:04.000000000 +0000
@@ -1,4 +1,4 @@
 version=4
 opts=filenamemangle=s/.*\/(.*)\/download/pythonize-$1\.tar\.gz/g,\
-uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\d*)$/$1~$2/ \
+uversionmangle=s/(\d)[_\.\-\+]?((RC|rc|pre|dev|beta|alpha)\.?\d*)$/$1~$2/ \
 https://qa.debian.org/cgi-bin/fakeupstream.cgi?upstream=crates.io/pythonize .*/crates/pythonize/@ANY_VERSION@/download
diff -pruN 0.21.1-1/src/de.rs 0.25.0-1/src/de.rs
--- 0.21.1-1/src/de.rs	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/src/de.rs	2006-07-24 01:21:28.000000000 +0000
@@ -1,52 +1,29 @@
-use pyo3::{types::*, Bound, PyNativeType};
+use pyo3::{types::*, Bound};
 use serde::de::{self, IntoDeserializer};
 use serde::Deserialize;
 
-use crate::error::{PythonizeError, Result};
+use crate::error::{ErrorImpl, PythonizeError, Result};
 
 /// Attempt to convert a Python object to an instance of `T`
-#[deprecated(
-    since = "0.21.0",
-    note = "will be replaced by `depythonize_bound` in a future release"
-)]
-pub fn depythonize<'de, T>(obj: &'de PyAny) -> Result<T>
+pub fn depythonize<'a, 'py, T>(obj: &'a Bound<'py, PyAny>) -> Result<T>
 where
-    T: Deserialize<'de>,
+    T: Deserialize<'a>,
 {
-    let mut depythonizer = Depythonizer::from_object_bound(obj.as_borrowed().to_owned());
-    T::deserialize(&mut depythonizer)
-}
-
-/// Attempt to convert a Python object to an instance of `T`
-pub fn depythonize_bound<'py, T>(obj: Bound<'py, PyAny>) -> Result<T>
-where
-    T: for<'a> Deserialize<'a>,
-{
-    let mut depythonizer = Depythonizer::from_object_bound(obj);
-    T::deserialize(&mut depythonizer)
+    T::deserialize(&mut Depythonizer::from_object(obj))
 }
 
 /// A structure that deserializes Python objects into Rust values
-pub struct Depythonizer<'py> {
-    input: Bound<'py, PyAny>,
+pub struct Depythonizer<'a, 'py> {
+    input: &'a Bound<'py, PyAny>,
 }
 
-impl<'py> Depythonizer<'py> {
+impl<'a, 'py> Depythonizer<'a, 'py> {
     /// Create a deserializer from a Python object
-    #[deprecated(
-        since = "0.21.0",
-        note = "will be replaced by `Depythonizer::from_object_bound` in a future version"
-    )]
-    pub fn from_object(input: &'py PyAny) -> Self {
-        Self::from_object_bound(input.as_borrowed().to_owned())
-    }
-
-    /// Create a deserializer from a Python object
-    pub fn from_object_bound(input: Bound<'py, PyAny>) -> Self {
+    pub fn from_object(input: &'a Bound<'py, PyAny>) -> Self {
         Depythonizer { input }
     }
 
-    fn sequence_access(&self, expected_len: Option<usize>) -> Result<PySequenceAccess<'py>> {
+    fn sequence_access(&self, expected_len: Option<usize>) -> Result<PySequenceAccess<'a, 'py>> {
         let seq = self.input.downcast::<PySequence>()?;
         let len = self.input.len()?;
 
@@ -54,13 +31,58 @@ impl<'py> Depythonizer<'py> {
             Some(expected) if expected != len => {
                 Err(PythonizeError::incorrect_sequence_length(expected, len))
             }
-            _ => Ok(PySequenceAccess::new(seq.clone(), len)),
+            _ => Ok(PySequenceAccess::new(seq, len)),
+        }
+    }
+
+    fn set_access(&self) -> Result<PySetAsSequence<'py>> {
+        match self.input.downcast::<PySet>() {
+            Ok(set) => Ok(PySetAsSequence::from_set(set)),
+            Err(e) => {
+                if let Ok(f) = self.input.downcast::<PyFrozenSet>() {
+                    Ok(PySetAsSequence::from_frozenset(f))
+                } else {
+                    Err(e.into())
+                }
+            }
         }
     }
 
     fn dict_access(&self) -> Result<PyMappingAccess<'py>> {
         PyMappingAccess::new(self.input.downcast()?)
     }
+
+    fn deserialize_any_int<'de, V>(&self, int: &Bound<'_, PyInt>, visitor: V) -> Result<V::Value>
+    where
+        V: de::Visitor<'de>,
+    {
+        if let Ok(x) = int.extract::<u128>() {
+            if let Ok(x) = u8::try_from(x) {
+                visitor.visit_u8(x)
+            } else if let Ok(x) = u16::try_from(x) {
+                visitor.visit_u16(x)
+            } else if let Ok(x) = u32::try_from(x) {
+                visitor.visit_u32(x)
+            } else if let Ok(x) = u64::try_from(x) {
+                visitor.visit_u64(x)
+            } else {
+                visitor.visit_u128(x)
+            }
+        } else {
+            let x: i128 = int.extract()?;
+            if let Ok(x) = i8::try_from(x) {
+                visitor.visit_i8(x)
+            } else if let Ok(x) = i16::try_from(x) {
+                visitor.visit_i16(x)
+            } else if let Ok(x) = i32::try_from(x) {
+                visitor.visit_i32(x)
+            } else if let Ok(x) = i64::try_from(x) {
+                visitor.visit_i64(x)
+            } else {
+                visitor.visit_i128(x)
+            }
+        }
+    }
 }
 
 macro_rules! deserialize_type {
@@ -74,14 +96,14 @@ macro_rules! deserialize_type {
     };
 }
 
-impl<'a, 'py, 'de> de::Deserializer<'de> for &'a mut Depythonizer<'py> {
+impl<'de> de::Deserializer<'de> for &'_ mut Depythonizer<'_, '_> {
     type Error = PythonizeError;
 
     fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
     where
         V: de::Visitor<'de>,
     {
-        let obj = &self.input;
+        let obj = self.input;
 
         // First check for cases which are cheap to check due to pointer
         // comparison or bitflag checks
@@ -89,8 +111,8 @@ impl<'a, 'py, 'de> de::Deserializer<'de>
             self.deserialize_unit(visitor)
         } else if obj.is_instance_of::<PyBool>() {
             self.deserialize_bool(visitor)
-        } else if obj.is_instance_of::<PyInt>() {
-            self.deserialize_i64(visitor)
+        } else if let Ok(x) = obj.downcast::<PyInt>() {
+            self.deserialize_any_int(x, visitor)
         } else if obj.is_instance_of::<PyList>() || obj.is_instance_of::<PyTuple>() {
             self.deserialize_tuple(obj.len()?, visitor)
         } else if obj.is_instance_of::<PyDict>() {
@@ -104,10 +126,9 @@ impl<'a, 'py, 'de> de::Deserializer<'de>
             self.deserialize_bytes(visitor)
         } else if obj.is_instance_of::<PyFloat>() {
             self.deserialize_f64(visitor)
-        } else if obj.is_instance_of::<PyFrozenSet>()
-            || obj.is_instance_of::<PySet>()
-            || obj.downcast::<PySequence>().is_ok()
-        {
+        } else if obj.is_instance_of::<PyFrozenSet>() || obj.is_instance_of::<PySet>() {
+            self.deserialize_seq(visitor)
+        } else if obj.downcast::<PySequence>().is_ok() {
             self.deserialize_tuple(obj.len()?, visitor)
         } else if obj.downcast::<PyMapping>().is_ok() {
             self.deserialize_map(visitor)
@@ -141,10 +162,12 @@ impl<'a, 'py, 'de> de::Deserializer<'de>
     deserialize_type!(deserialize_i16 => visit_i16);
     deserialize_type!(deserialize_i32 => visit_i32);
     deserialize_type!(deserialize_i64 => visit_i64);
+    deserialize_type!(deserialize_i128 => visit_i128);
     deserialize_type!(deserialize_u8 => visit_u8);
     deserialize_type!(deserialize_u16 => visit_u16);
     deserialize_type!(deserialize_u32 => visit_u32);
     deserialize_type!(deserialize_u64 => visit_u64);
+    deserialize_type!(deserialize_u128 => visit_u128);
     deserialize_type!(deserialize_f32 => visit_f32);
     deserialize_type!(deserialize_f64 => visit_f64);
 
@@ -218,7 +241,18 @@ impl<'a, 'py, 'de> de::Deserializer<'de>
     where
         V: de::Visitor<'de>,
     {
-        visitor.visit_seq(self.sequence_access(None)?)
+        match self.sequence_access(None) {
+            Ok(seq) => visitor.visit_seq(seq),
+            Err(e) => {
+                // we allow sets to be deserialized as sequences, so try that
+                if matches!(*e.inner, ErrorImpl::UnexpectedType(_)) {
+                    if let Ok(set) = self.set_access() {
+                        return visitor.visit_seq(set);
+                    }
+                }
+                Err(e)
+            }
+        }
     }
 
     fn deserialize_tuple<V>(self, len: usize, visitor: V) -> Result<V::Value>
@@ -269,21 +303,20 @@ impl<'a, 'py, 'de> de::Deserializer<'de>
         V: de::Visitor<'de>,
     {
         let item = &self.input;
-        if let Ok(d) = item.downcast::<PyDict>() {
-            // Get the enum variant from the dict key
-            if d.len() != 1 {
+        if let Ok(s) = item.downcast::<PyString>() {
+            visitor.visit_enum(s.to_cow()?.into_deserializer())
+        } else if let Ok(m) = item.downcast::<PyMapping>() {
+            // Get the enum variant from the mapping key
+            if m.len()? != 1 {
                 return Err(PythonizeError::invalid_length_enum());
             }
-            let variant = d
-                .keys()
+            let variant: Bound<PyString> = m
+                .keys()?
                 .get_item(0)?
                 .downcast_into::<PyString>()
                 .map_err(|_| PythonizeError::dict_key_not_string())?;
-            let value = d.get_item(&variant)?.unwrap();
-            let mut de = Depythonizer::from_object_bound(value);
-            visitor.visit_enum(PyEnumAccess::new(&mut de, variant))
-        } else if let Ok(s) = item.downcast::<PyString>() {
-            visitor.visit_enum(s.to_cow()?.into_deserializer())
+            let value = m.get_item(&variant)?;
+            visitor.visit_enum(PyEnumAccess::new(&value, variant))
         } else {
             Err(PythonizeError::invalid_enum_type())
         }
@@ -308,19 +341,19 @@ impl<'a, 'py, 'de> de::Deserializer<'de>
     }
 }
 
-struct PySequenceAccess<'py> {
-    seq: Bound<'py, PySequence>,
+struct PySequenceAccess<'a, 'py> {
+    seq: &'a Bound<'py, PySequence>,
     index: usize,
     len: usize,
 }
 
-impl<'py> PySequenceAccess<'py> {
-    fn new(seq: Bound<'py, PySequence>, len: usize) -> Self {
+impl<'a, 'py> PySequenceAccess<'a, 'py> {
+    fn new(seq: &'a Bound<'py, PySequence>, len: usize) -> Self {
         Self { seq, index: 0, len }
     }
 }
 
-impl<'de, 'py> de::SeqAccess<'de> for PySequenceAccess<'py> {
+impl<'de> de::SeqAccess<'de> for PySequenceAccess<'_, '_> {
     type Error = PythonizeError;
 
     fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
@@ -328,18 +361,53 @@ impl<'de, 'py> de::SeqAccess<'de> for Py
         T: de::DeserializeSeed<'de>,
     {
         if self.index < self.len {
-            let mut item_de = Depythonizer::from_object_bound(self.seq.get_item(self.index)?);
+            let item = self.seq.get_item(self.index)?;
             self.index += 1;
-            seed.deserialize(&mut item_de).map(Some)
+            seed.deserialize(&mut Depythonizer::from_object(&item))
+                .map(Some)
         } else {
             Ok(None)
         }
     }
 }
 
+struct PySetAsSequence<'py> {
+    iter: Bound<'py, PyIterator>,
+}
+
+impl<'py> PySetAsSequence<'py> {
+    fn from_set(set: &Bound<'py, PySet>) -> Self {
+        Self {
+            iter: PyIterator::from_object(set).expect("set is always iterable"),
+        }
+    }
+
+    fn from_frozenset(set: &Bound<'py, PyFrozenSet>) -> Self {
+        Self {
+            iter: PyIterator::from_object(set).expect("frozenset is always iterable"),
+        }
+    }
+}
+
+impl<'de> de::SeqAccess<'de> for PySetAsSequence<'_> {
+    type Error = PythonizeError;
+
+    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
+    where
+        T: de::DeserializeSeed<'de>,
+    {
+        match self.iter.next() {
+            Some(item) => seed
+                .deserialize(&mut Depythonizer::from_object(&item?))
+                .map(Some),
+            None => Ok(None),
+        }
+    }
+}
+
 struct PyMappingAccess<'py> {
-    keys: Bound<'py, PySequence>,
-    values: Bound<'py, PySequence>,
+    keys: Bound<'py, PyList>,
+    values: Bound<'py, PyList>,
     key_idx: usize,
     val_idx: usize,
     len: usize,
@@ -360,7 +428,7 @@ impl<'py> PyMappingAccess<'py> {
     }
 }
 
-impl<'de, 'py> de::MapAccess<'de> for PyMappingAccess<'py> {
+impl<'de> de::MapAccess<'de> for PyMappingAccess<'_> {
     type Error = PythonizeError;
 
     fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
@@ -368,9 +436,10 @@ impl<'de, 'py> de::MapAccess<'de> for Py
         K: de::DeserializeSeed<'de>,
     {
         if self.key_idx < self.len {
-            let mut item_de = Depythonizer::from_object_bound(self.keys.get_item(self.key_idx)?);
+            let item = self.keys.get_item(self.key_idx)?;
             self.key_idx += 1;
-            seed.deserialize(&mut item_de).map(Some)
+            seed.deserialize(&mut Depythonizer::from_object(&item))
+                .map(Some)
         } else {
             Ok(None)
         }
@@ -380,24 +449,27 @@ impl<'de, 'py> de::MapAccess<'de> for Py
     where
         V: de::DeserializeSeed<'de>,
     {
-        let mut item_de = Depythonizer::from_object_bound(self.values.get_item(self.val_idx)?);
+        let item = self.values.get_item(self.val_idx)?;
         self.val_idx += 1;
-        seed.deserialize(&mut item_de)
+        seed.deserialize(&mut Depythonizer::from_object(&item))
     }
 }
 
 struct PyEnumAccess<'a, 'py> {
-    de: &'a mut Depythonizer<'py>,
+    de: Depythonizer<'a, 'py>,
     variant: Bound<'py, PyString>,
 }
 
 impl<'a, 'py> PyEnumAccess<'a, 'py> {
-    fn new(de: &'a mut Depythonizer<'py>, variant: Bound<'py, PyString>) -> Self {
-        Self { de, variant }
+    fn new(obj: &'a Bound<'py, PyAny>, variant: Bound<'py, PyString>) -> Self {
+        Self {
+            de: Depythonizer::from_object(obj),
+            variant,
+        }
     }
 }
 
-impl<'a, 'py, 'de> de::EnumAccess<'de> for PyEnumAccess<'a, 'py> {
+impl<'de> de::EnumAccess<'de> for PyEnumAccess<'_, '_> {
     type Error = PythonizeError;
     type Variant = Self;
 
@@ -412,7 +484,7 @@ impl<'a, 'py, 'de> de::EnumAccess<'de> f
     }
 }
 
-impl<'a, 'py, 'de> de::VariantAccess<'de> for PyEnumAccess<'a, 'py> {
+impl<'de> de::VariantAccess<'de> for PyEnumAccess<'_, '_> {
     type Error = PythonizeError;
 
     fn unit_variant(self) -> Result<()> {
@@ -423,7 +495,7 @@ impl<'a, 'py, 'de> de::VariantAccess<'de
     where
         T: de::DeserializeSeed<'de>,
     {
-        seed.deserialize(self.de)
+        seed.deserialize(&mut { self.de })
     }
 
     fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value>
@@ -443,24 +515,25 @@ impl<'a, 'py, 'de> de::VariantAccess<'de
 
 #[cfg(test)]
 mod test {
+    use std::ffi::CStr;
+
     use super::*;
     use crate::error::ErrorImpl;
     use maplit::hashmap;
-    use pyo3::Python;
+    use pyo3::ffi::c_str;
+    use pyo3::{IntoPyObject, Python};
     use serde_json::{json, Value as JsonValue};
 
-    fn test_de<T>(code: &str, expected: &T, expected_json: &JsonValue)
+    fn test_de<T>(code: &CStr, expected: &T, expected_json: &JsonValue)
     where
         T: de::DeserializeOwned + PartialEq + std::fmt::Debug,
     {
         Python::with_gil(|py| {
-            let locals = PyDict::new_bound(py);
-            py.run_bound(&format!("obj = {}", code), None, Some(&locals))
-                .unwrap();
-            let obj = locals.get_item("obj").unwrap().unwrap();
-            let actual: T = depythonize_bound(obj.clone()).unwrap();
+            let obj = py.eval(code, None, None).unwrap();
+            let actual: T = depythonize(&obj).unwrap();
             assert_eq!(&actual, expected);
-            let actual_json: JsonValue = depythonize_bound(obj).unwrap();
+
+            let actual_json: JsonValue = depythonize(&obj).unwrap();
             assert_eq!(&actual_json, expected_json);
         });
     }
@@ -472,7 +545,7 @@ mod test {
 
         let expected = Empty;
         let expected_json = json!(null);
-        let code = "None";
+        let code = c_str!("None");
         test_de(code, &expected, &expected_json);
     }
 
@@ -498,7 +571,7 @@ mod test {
             "baz": 45.23,
             "qux": true
         });
-        let code = "{'foo': 'Foo', 'bar': 8, 'baz': 45.23, 'qux': True}";
+        let code = c_str!("{'foo': 'Foo', 'bar': 8, 'baz': 45.23, 'qux': True}");
         test_de(code, &expected, &expected_json);
     }
 
@@ -510,15 +583,13 @@ mod test {
             bar: usize,
         }
 
-        let code = "{'foo': 'Foo'}";
+        let code = c_str!("{'foo': 'Foo'}");
 
         Python::with_gil(|py| {
-            let locals = PyDict::new_bound(py);
-            py.run_bound(&format!("obj = {}", code), None, Some(&locals))
-                .unwrap();
-            let obj = locals.get_item("obj").unwrap().unwrap();
+            let locals = PyDict::new(py);
+            let obj = py.eval(code, None, Some(&locals)).unwrap();
             assert!(matches!(
-                *depythonize_bound::<Struct>(obj).unwrap_err().inner,
+                *depythonize::<Struct>(&obj).unwrap_err().inner,
                 ErrorImpl::Message(msg) if msg == "missing field `bar`"
             ));
         })
@@ -531,7 +602,7 @@ mod test {
 
         let expected = TupleStruct("cat".to_string(), -10.05);
         let expected_json = json!(["cat", -10.05]);
-        let code = "('cat', -10.05)";
+        let code = c_str!("('cat', -10.05)");
         test_de(code, &expected, &expected_json);
     }
 
@@ -540,15 +611,13 @@ mod test {
         #[derive(Debug, Deserialize, PartialEq)]
         struct TupleStruct(String, f64);
 
-        let code = "('cat', -10.05, 'foo')";
+        let code = c_str!("('cat', -10.05, 'foo')");
 
         Python::with_gil(|py| {
-            let locals = PyDict::new_bound(py);
-            py.run_bound(&format!("obj = {}", code), None, Some(&locals))
-                .unwrap();
-            let obj = locals.get_item("obj").unwrap().unwrap();
+            let locals = PyDict::new(py);
+            let obj = py.eval(code, None, Some(&locals)).unwrap();
             assert!(matches!(
-                *depythonize_bound::<TupleStruct>(obj).unwrap_err().inner,
+                *depythonize::<TupleStruct>(&obj).unwrap_err().inner,
                 ErrorImpl::IncorrectSequenceLength { expected, got } if expected == 2 && got == 3
             ));
         })
@@ -561,7 +630,7 @@ mod test {
 
         let expected = TupleStruct("cat".to_string(), -10.05);
         let expected_json = json!(["cat", -10.05]);
-        let code = "['cat', -10.05]";
+        let code = c_str!("['cat', -10.05]");
         test_de(code, &expected, &expected_json);
     }
 
@@ -569,7 +638,7 @@ mod test {
     fn test_tuple() {
         let expected = ("foo".to_string(), 5);
         let expected_json = json!(["foo", 5]);
-        let code = "('foo', 5)";
+        let code = c_str!("('foo', 5)");
         test_de(code, &expected, &expected_json);
     }
 
@@ -577,7 +646,23 @@ mod test {
     fn test_tuple_from_pylist() {
         let expected = ("foo".to_string(), 5);
         let expected_json = json!(["foo", 5]);
-        let code = "['foo', 5]";
+        let code = c_str!("['foo', 5]");
+        test_de(code, &expected, &expected_json);
+    }
+
+    #[test]
+    fn test_vec_from_pyset() {
+        let expected = vec!["foo".to_string()];
+        let expected_json = json!(["foo"]);
+        let code = c_str!("{'foo'}");
+        test_de(code, &expected, &expected_json);
+    }
+
+    #[test]
+    fn test_vec_from_pyfrozenset() {
+        let expected = vec!["foo".to_string()];
+        let expected_json = json!(["foo"]);
+        let code = c_str!("frozenset({'foo'})");
         test_de(code, &expected, &expected_json);
     }
 
@@ -585,7 +670,7 @@ mod test {
     fn test_vec() {
         let expected = vec![3, 2, 1];
         let expected_json = json!([3, 2, 1]);
-        let code = "[3, 2, 1]";
+        let code = c_str!("[3, 2, 1]");
         test_de(code, &expected, &expected_json);
     }
 
@@ -593,7 +678,7 @@ mod test {
     fn test_vec_from_tuple() {
         let expected = vec![3, 2, 1];
         let expected_json = json!([3, 2, 1]);
-        let code = "(3, 2, 1)";
+        let code = c_str!("(3, 2, 1)");
         test_de(code, &expected, &expected_json);
     }
 
@@ -601,7 +686,7 @@ mod test {
     fn test_hashmap() {
         let expected = hashmap! {"foo".to_string() => 4};
         let expected_json = json!({"foo": 4 });
-        let code = "{'foo': 4}";
+        let code = c_str!("{'foo': 4}");
         test_de(code, &expected, &expected_json);
     }
 
@@ -614,7 +699,7 @@ mod test {
 
         let expected = Foo::Variant;
         let expected_json = json!("Variant");
-        let code = "'Variant'";
+        let code = c_str!("'Variant'");
         test_de(code, &expected, &expected_json);
     }
 
@@ -627,7 +712,7 @@ mod test {
 
         let expected = Foo::Tuple(12, "cat".to_string());
         let expected_json = json!({"Tuple": [12, "cat"]});
-        let code = "{'Tuple': [12, 'cat']}";
+        let code = c_str!("{'Tuple': [12, 'cat']}");
         test_de(code, &expected, &expected_json);
     }
 
@@ -640,7 +725,7 @@ mod test {
 
         let expected = Foo::NewType("cat".to_string());
         let expected_json = json!({"NewType": "cat" });
-        let code = "{'NewType': 'cat'}";
+        let code = c_str!("{'NewType': 'cat'}");
         test_de(code, &expected, &expected_json);
     }
 
@@ -656,7 +741,7 @@ mod test {
             bar: 25,
         };
         let expected_json = json!({"Struct": {"foo": "cat", "bar": 25 }});
-        let code = "{'Struct': {'foo': 'cat', 'bar': 25}}";
+        let code = c_str!("{'Struct': {'foo': 'cat', 'bar': 25}}");
         test_de(code, &expected, &expected_json);
     }
     #[test]
@@ -669,7 +754,7 @@ mod test {
 
         let expected = Foo::Tuple(12.0, 'c');
         let expected_json = json!([12.0, 'c']);
-        let code = "[12.0, 'c']";
+        let code = c_str!("[12.0, 'c']");
         test_de(code, &expected, &expected_json);
     }
 
@@ -683,7 +768,7 @@ mod test {
 
         let expected = Foo::NewType("cat".to_string());
         let expected_json = json!("cat");
-        let code = "'cat'";
+        let code = c_str!("'cat'");
         test_de(code, &expected, &expected_json);
     }
 
@@ -700,7 +785,7 @@ mod test {
             bar: [2, 5, 3, 1],
         };
         let expected_json = json!({"foo": ["a", "b", "c"], "bar": [2, 5, 3, 1]});
-        let code = "{'foo': ['a', 'b', 'c'], 'bar': [2, 5, 3, 1]}";
+        let code = c_str!("{'foo': ['a', 'b', 'c'], 'bar': [2, 5, 3, 1]}");
         test_de(code, &expected, &expected_json);
     }
 
@@ -733,7 +818,75 @@ mod test {
         };
         let expected_json =
             json!({"name": "SomeFoo", "bar": { "value": 13, "variant": { "Tuple": [-1.5, 8]}}});
-        let code = "{'name': 'SomeFoo', 'bar': {'value': 13, 'variant': {'Tuple': [-1.5, 8]}}}";
+        let code =
+            c_str!("{'name': 'SomeFoo', 'bar': {'value': 13, 'variant': {'Tuple': [-1.5, 8]}}}");
         test_de(code, &expected, &expected_json);
     }
+
+    #[test]
+    fn test_int_limits() {
+        Python::with_gil(|py| {
+            // serde_json::Value supports u64 and i64 as maxiumum sizes
+            let _: serde_json::Value = depythonize(&u8::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&u8::MIN.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&i8::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&i8::MIN.into_pyobject(py).unwrap()).unwrap();
+
+            let _: serde_json::Value = depythonize(&u16::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&u16::MIN.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&i16::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&i16::MIN.into_pyobject(py).unwrap()).unwrap();
+
+            let _: serde_json::Value = depythonize(&u32::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&u32::MIN.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&i32::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&i32::MIN.into_pyobject(py).unwrap()).unwrap();
+
+            let _: serde_json::Value = depythonize(&u64::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&u64::MIN.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&i64::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: serde_json::Value = depythonize(&i64::MIN.into_pyobject(py).unwrap()).unwrap();
+
+            let _: u128 = depythonize(&u128::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: i128 = depythonize(&u128::MIN.into_pyobject(py).unwrap()).unwrap();
+
+            let _: i128 = depythonize(&i128::MAX.into_pyobject(py).unwrap()).unwrap();
+            let _: i128 = depythonize(&i128::MIN.into_pyobject(py).unwrap()).unwrap();
+        });
+    }
+
+    #[test]
+    fn test_deserialize_bytes() {
+        Python::with_gil(|py| {
+            let obj = PyBytes::new(py, "hello".as_bytes());
+            let actual: Vec<u8> = depythonize(&obj).unwrap();
+            assert_eq!(actual, b"hello");
+        })
+    }
+
+    #[test]
+    fn test_char() {
+        let expected = 'a';
+        let expected_json = json!("a");
+        let code = c_str!("'a'");
+        test_de(code, &expected, &expected_json);
+    }
+
+    #[test]
+    fn test_unknown_type() {
+        Python::with_gil(|py| {
+            let obj = py
+                .import("decimal")
+                .unwrap()
+                .getattr("Decimal")
+                .unwrap()
+                .call0()
+                .unwrap();
+            let err = depythonize::<serde_json::Value>(&obj).unwrap_err();
+            assert!(matches!(
+                *err.inner,
+                ErrorImpl::UnsupportedType(name) if name == "Decimal"
+            ));
+        });
+    }
 }
diff -pruN 0.21.1-1/src/error.rs 0.25.0-1/src/error.rs
--- 0.21.1-1/src/error.rs	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/src/error.rs	2006-07-24 01:21:28.000000000 +0000
@@ -1,6 +1,7 @@
+use pyo3::PyErr;
 use pyo3::{exceptions::*, DowncastError, DowncastIntoError};
-use pyo3::{PyDowncastError, PyErr};
 use serde::{de, ser};
+use std::convert::Infallible;
 use std::error;
 use std::fmt::{self, Debug, Display};
 use std::result;
@@ -137,19 +138,17 @@ impl de::Error for PythonizeError {
 }
 
 /// Convert an exception raised in Python to a `PythonizeError`
-impl From<PyErr> for PythonizeError {
-    fn from(other: PyErr) -> Self {
-        Self {
-            inner: Box::new(ErrorImpl::PyErr(other)),
-        }
+impl From<Infallible> for PythonizeError {
+    fn from(other: Infallible) -> Self {
+        match other {}
     }
 }
 
-/// Handle errors that occur when attempting to use `PyAny::cast_as`
-impl<'a> From<PyDowncastError<'a>> for PythonizeError {
-    fn from(other: PyDowncastError) -> Self {
+/// Convert an exception raised in Python to a `PythonizeError`
+impl From<PyErr> for PythonizeError {
+    fn from(other: PyErr) -> Self {
         Self {
-            inner: Box::new(ErrorImpl::UnexpectedType(other.to_string())),
+            inner: Box::new(ErrorImpl::PyErr(other)),
         }
     }
 }
diff -pruN 0.21.1-1/src/lib.rs 0.25.0-1/src/lib.rs
--- 0.21.1-1/src/lib.rs	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/src/lib.rs	2006-07-24 01:21:28.000000000 +0000
@@ -1,50 +1,12 @@
-//! This crate converts Rust types which implement the [Serde] serialization
-//! traits into Python objects using the [PyO3] library.
-//!
-//! Pythonize has two public APIs: `pythonize` and `depythonize`.
-//!
-//! [Serde]: https://github.com/serde-rs/serde
-//! [PyO3]: https://github.com/PyO3/pyo3
-//!
-//! # Examples
-//! ```
-//! use serde::{Serialize, Deserialize};
-//! use pyo3::Python;
-//! use pythonize::{depythonize, pythonize};
-//!
-//! #[derive(Debug, Serialize, Deserialize, PartialEq)]
-//! struct Sample {
-//!     foo: String,
-//!     bar: Option<usize>
-//! }
-//!
-//! Python::with_gil(|py| {
-//!     let sample = Sample {
-//!         foo: "Foo".to_string(),
-//!         bar: None
-//!     };
-//!
-//!     // Rust -> Python
-//!     let obj = pythonize(py, &sample).unwrap();
-//!
-//!     assert_eq!("{'foo': 'Foo', 'bar': None}", &format!("{}", obj.as_ref(py).repr().unwrap()));
-//!
-//!     // Python -> Rust
-//!     let new_sample: Sample = depythonize(obj.as_ref(py)).unwrap();
-//!
-//!     assert_eq!(new_sample, sample);
-//! });
-//!
-//! ```
+#![doc = include_str!("../README.md")]
+
 mod de;
 mod error;
 mod ser;
 
-#[allow(deprecated)]
-pub use crate::de::depythonize;
-pub use crate::de::{depythonize_bound, Depythonizer};
+pub use crate::de::{depythonize, Depythonizer};
 pub use crate::error::{PythonizeError, Result};
 pub use crate::ser::{
-    pythonize, pythonize_custom, PythonizeDefault, PythonizeDictType, PythonizeListType,
-    PythonizeTypes, Pythonizer,
+    pythonize, pythonize_custom, PythonizeDefault, PythonizeListType, PythonizeMappingType,
+    PythonizeNamedMappingType, PythonizeTypes, PythonizeUnnamedMappingAdapter, Pythonizer,
 };
diff -pruN 0.21.1-1/src/ser.rs 0.25.0-1/src/ser.rs
--- 0.21.1-1/src/ser.rs	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/src/ser.rs	2006-07-24 01:21:28.000000000 +0000
@@ -1,68 +1,167 @@
 use std::marker::PhantomData;
 
-use pyo3::types::{PyAnyMethods, PyDict, PyList, PyMapping, PySequence, PyTuple};
-use pyo3::{Bound, IntoPy, PyObject, PyResult, Python, ToPyObject};
+use pyo3::types::{
+    PyDict, PyDictMethods, PyList, PyListMethods, PyMapping, PySequence, PyString, PyTuple,
+    PyTupleMethods,
+};
+use pyo3::{Bound, BoundObject, IntoPyObject, PyAny, PyResult, Python};
 use serde::{ser, Serialize};
 
 use crate::error::{PythonizeError, Result};
 
+// TODO: move 'py lifetime into builder once GATs are available in MSRV
 /// Trait for types which can represent a Python mapping
-pub trait PythonizeDictType {
-    /// Constructor
-    fn create_mapping(py: Python) -> PyResult<Bound<PyMapping>>;
+pub trait PythonizeMappingType<'py> {
+    /// Builder type for Python mappings
+    type Builder;
+
+    /// Create a builder for a Python mapping
+    fn builder(py: Python<'py>, len: Option<usize>) -> PyResult<Self::Builder>;
+
+    /// Adds the key-value item to the mapping being built
+    fn push_item(
+        builder: &mut Self::Builder,
+        key: Bound<'py, PyAny>,
+        value: Bound<'py, PyAny>,
+    ) -> PyResult<()>;
+
+    /// Build the Python mapping
+    fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>>;
+}
+
+// TODO: move 'py lifetime into builder once GATs are available in MSRV
+/// Trait for types which can represent a Python mapping and have a name
+pub trait PythonizeNamedMappingType<'py> {
+    /// Builder type for Python mappings with a name
+    type Builder;
+
+    /// Create a builder for a Python mapping with a name
+    fn builder(py: Python<'py>, len: usize, name: &'static str) -> PyResult<Self::Builder>;
+
+    /// Adds the field to the named mapping being built
+    fn push_field(
+        builder: &mut Self::Builder,
+        name: Bound<'py, PyString>,
+        value: Bound<'py, PyAny>,
+    ) -> PyResult<()>;
+
+    /// Build the Python mapping
+    fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>>;
 }
 
 /// Trait for types which can represent a Python sequence
 pub trait PythonizeListType: Sized {
     /// Constructor
-    fn create_sequence<T, U>(
-        py: Python,
+    fn create_sequence<'py, T, U>(
+        py: Python<'py>,
         elements: impl IntoIterator<Item = T, IntoIter = U>,
-    ) -> PyResult<Bound<PySequence>>
+    ) -> PyResult<Bound<'py, PySequence>>
     where
-        T: ToPyObject,
+        T: IntoPyObject<'py>,
         U: ExactSizeIterator<Item = T>;
 }
 
+// TODO: remove 'py lifetime once GATs are available in MSRV
 /// Custom types for serialization
-pub trait PythonizeTypes {
+pub trait PythonizeTypes<'py> {
     /// Python map type (should be representable as python mapping)
-    type Map: PythonizeDictType;
+    type Map: PythonizeMappingType<'py>;
+    /// Python (struct-like) named map type (should be representable as python mapping)
+    type NamedMap: PythonizeNamedMappingType<'py>;
     /// Python sequence type (should be representable as python sequence)
     type List: PythonizeListType;
 }
 
-impl PythonizeDictType for PyDict {
-    fn create_mapping(py: Python) -> PyResult<Bound<PyMapping>> {
-        Ok(PyDict::new_bound(py).into_any().downcast_into().unwrap())
+impl<'py> PythonizeMappingType<'py> for PyDict {
+    type Builder = Bound<'py, Self>;
+
+    fn builder(py: Python<'py>, _len: Option<usize>) -> PyResult<Self::Builder> {
+        Ok(Self::new(py))
+    }
+
+    fn push_item(
+        builder: &mut Self::Builder,
+        key: Bound<'py, PyAny>,
+        value: Bound<'py, PyAny>,
+    ) -> PyResult<()> {
+        builder.set_item(key, value)
+    }
+
+    fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>> {
+        Ok(builder.into_mapping())
+    }
+}
+
+/// Adapter type to use an unnamed mapping type, i.e. one that implements
+/// [`PythonizeMappingType`], as a named mapping type, i.e. one that implements
+/// [`PythonizeNamedMappingType`]. The adapter simply drops the provided name.
+///
+/// This adapter is commonly applied to use the same unnamed mapping type for
+/// both [`PythonizeTypes::Map`] and [`PythonizeTypes::NamedMap`] while only
+/// implementing [`PythonizeMappingType`].
+pub struct PythonizeUnnamedMappingAdapter<'py, T: PythonizeMappingType<'py>> {
+    _unnamed: T,
+    _marker: PhantomData<&'py ()>,
+}
+
+impl<'py, T: PythonizeMappingType<'py>> PythonizeNamedMappingType<'py>
+    for PythonizeUnnamedMappingAdapter<'py, T>
+{
+    type Builder = <T as PythonizeMappingType<'py>>::Builder;
+
+    fn builder(py: Python<'py>, len: usize, _name: &'static str) -> PyResult<Self::Builder> {
+        <T as PythonizeMappingType>::builder(py, Some(len))
+    }
+
+    fn push_field(
+        builder: &mut Self::Builder,
+        name: Bound<'py, PyString>,
+        value: Bound<'py, PyAny>,
+    ) -> PyResult<()> {
+        <T as PythonizeMappingType>::push_item(builder, name.into_any(), value)
+    }
+
+    fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>> {
+        <T as PythonizeMappingType>::finish(builder)
     }
 }
 
 impl PythonizeListType for PyList {
-    fn create_sequence<T, U>(
-        py: Python,
+    fn create_sequence<'py, T, U>(
+        py: Python<'py>,
+        elements: impl IntoIterator<Item = T, IntoIter = U>,
+    ) -> PyResult<Bound<'py, PySequence>>
+    where
+        T: IntoPyObject<'py>,
+        U: ExactSizeIterator<Item = T>,
+    {
+        Ok(PyList::new(py, elements)?.into_sequence())
+    }
+}
+
+impl PythonizeListType for PyTuple {
+    fn create_sequence<'py, T, U>(
+        py: Python<'py>,
         elements: impl IntoIterator<Item = T, IntoIter = U>,
-    ) -> PyResult<Bound<PySequence>>
+    ) -> PyResult<Bound<'py, PySequence>>
     where
-        T: ToPyObject,
+        T: IntoPyObject<'py>,
         U: ExactSizeIterator<Item = T>,
     {
-        Ok(PyList::new_bound(py, elements)
-            .into_any()
-            .downcast_into()
-            .unwrap())
+        Ok(PyTuple::new(py, elements)?.into_sequence())
     }
 }
 
 pub struct PythonizeDefault;
 
-impl PythonizeTypes for PythonizeDefault {
+impl<'py> PythonizeTypes<'py> for PythonizeDefault {
     type Map = PyDict;
+    type NamedMap = PythonizeUnnamedMappingAdapter<'py, PyDict>;
     type List = PyList;
 }
 
 /// Attempt to convert the given data into a Python object
-pub fn pythonize<T>(py: Python, value: &T) -> Result<PyObject>
+pub fn pythonize<'py, T>(py: Python<'py>, value: &T) -> Result<Bound<'py, PyAny>>
 where
     T: ?Sized + Serialize,
 {
@@ -71,10 +170,10 @@ where
 
 /// Attempt to convert the given data into a Python object.
 /// Also uses custom mapping python class for serialization.
-pub fn pythonize_custom<P, T>(py: Python, value: &T) -> Result<PyObject>
+pub fn pythonize_custom<'py, P, T>(py: Python<'py>, value: &T) -> Result<Bound<'py, PyAny>>
 where
     T: ?Sized + Serialize,
-    P: PythonizeTypes,
+    P: PythonizeTypes<'py>,
 {
     value.serialize(Pythonizer::custom::<P>(py))
 }
@@ -109,121 +208,137 @@ impl<'py> Pythonizer<'py, PythonizeDefau
 
 #[doc(hidden)]
 pub struct PythonCollectionSerializer<'py, P> {
-    items: Vec<PyObject>,
+    items: Vec<Bound<'py, PyAny>>,
     py: Python<'py>,
     _types: PhantomData<P>,
 }
 
 #[doc(hidden)]
 pub struct PythonTupleVariantSerializer<'py, P> {
+    name: &'static str,
     variant: &'static str,
     inner: PythonCollectionSerializer<'py, P>,
 }
 
 #[doc(hidden)]
-pub struct PythonStructVariantSerializer<'py, P: PythonizeTypes> {
+pub struct PythonStructVariantSerializer<'py, P: PythonizeTypes<'py>> {
+    name: &'static str,
     variant: &'static str,
-    inner: PythonDictSerializer<'py, P>,
+    inner: PythonStructDictSerializer<'py, P>,
 }
 
 #[doc(hidden)]
-pub struct PythonDictSerializer<'py, P: PythonizeTypes> {
+pub struct PythonStructDictSerializer<'py, P: PythonizeTypes<'py>> {
     py: Python<'py>,
-    dict: Bound<'py, PyMapping>,
+    builder: <P::NamedMap as PythonizeNamedMappingType<'py>>::Builder,
     _types: PhantomData<P>,
 }
 
 #[doc(hidden)]
-pub struct PythonMapSerializer<'py, P: PythonizeTypes> {
+pub struct PythonMapSerializer<'py, P: PythonizeTypes<'py>> {
     py: Python<'py>,
-    map: Bound<'py, PyMapping>,
-    key: Option<PyObject>,
+    builder: <P::Map as PythonizeMappingType<'py>>::Builder,
+    key: Option<Bound<'py, PyAny>>,
     _types: PhantomData<P>,
 }
 
-impl<'py, P: PythonizeTypes> ser::Serializer for Pythonizer<'py, P> {
-    type Ok = PyObject;
+impl<'py, P: PythonizeTypes<'py>> Pythonizer<'py, P> {
+    /// The default implementation for serialisation functions.
+    #[inline]
+    fn serialise_default<T>(self, v: T) -> Result<Bound<'py, PyAny>>
+    where
+        T: IntoPyObject<'py>,
+        <T as IntoPyObject<'py>>::Error: Into<PythonizeError>,
+    {
+        v.into_pyobject(self.py)
+            .map(|x| x.into_any().into_bound())
+            .map_err(Into::into)
+    }
+}
+
+impl<'py, P: PythonizeTypes<'py>> ser::Serializer for Pythonizer<'py, P> {
+    type Ok = Bound<'py, PyAny>;
     type Error = PythonizeError;
     type SerializeSeq = PythonCollectionSerializer<'py, P>;
     type SerializeTuple = PythonCollectionSerializer<'py, P>;
     type SerializeTupleStruct = PythonCollectionSerializer<'py, P>;
     type SerializeTupleVariant = PythonTupleVariantSerializer<'py, P>;
     type SerializeMap = PythonMapSerializer<'py, P>;
-    type SerializeStruct = PythonDictSerializer<'py, P>;
+    type SerializeStruct = PythonStructDictSerializer<'py, P>;
     type SerializeStructVariant = PythonStructVariantSerializer<'py, P>;
 
-    fn serialize_bool(self, v: bool) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_bool(self, v: bool) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_i8(self, v: i8) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_i8(self, v: i8) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_i16(self, v: i16) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_i16(self, v: i16) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_i32(self, v: i32) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_i32(self, v: i32) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_i64(self, v: i64) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_i64(self, v: i64) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_u8(self, v: u8) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_u8(self, v: u8) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_u16(self, v: u16) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_u16(self, v: u16) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_u32(self, v: u32) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_u32(self, v: u32) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_u64(self, v: u64) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_u64(self, v: u64) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_f32(self, v: f32) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_f32(self, v: f32) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_f64(self, v: f64) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_f64(self, v: f64) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_char(self, v: char) -> Result<PyObject> {
+    fn serialize_char(self, v: char) -> Result<Bound<'py, PyAny>> {
         self.serialize_str(&v.to_string())
     }
 
-    fn serialize_str(self, v: &str) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_str(self, v: &str) -> Result<Bound<'py, PyAny>> {
+        Ok(PyString::new(self.py, v).into_any())
     }
 
-    fn serialize_bytes(self, v: &[u8]) -> Result<PyObject> {
-        Ok(v.into_py(self.py))
+    fn serialize_bytes(self, v: &[u8]) -> Result<Bound<'py, PyAny>> {
+        self.serialise_default(v)
     }
 
-    fn serialize_none(self) -> Result<PyObject> {
-        Ok(self.py.None())
+    fn serialize_none(self) -> Result<Bound<'py, PyAny>> {
+        Ok(self.py.None().into_bound(self.py))
     }
 
-    fn serialize_some<T>(self, value: &T) -> Result<PyObject>
+    fn serialize_some<T>(self, value: &T) -> Result<Bound<'py, PyAny>>
     where
         T: ?Sized + Serialize,
     {
         value.serialize(self)
     }
 
-    fn serialize_unit(self) -> Result<PyObject> {
+    fn serialize_unit(self) -> Result<Bound<'py, PyAny>> {
         self.serialize_none()
     }
 
-    fn serialize_unit_struct(self, _name: &'static str) -> Result<PyObject> {
+    fn serialize_unit_struct(self, _name: &'static str) -> Result<Bound<'py, PyAny>> {
         self.serialize_none()
     }
 
@@ -232,11 +347,15 @@ impl<'py, P: PythonizeTypes> ser::Serial
         _name: &'static str,
         _variant_index: u32,
         variant: &'static str,
-    ) -> Result<PyObject> {
+    ) -> Result<Bound<'py, PyAny>> {
         self.serialize_str(variant)
     }
 
-    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<PyObject>
+    fn serialize_newtype_struct<T>(
+        self,
+        _name: &'static str,
+        value: &T,
+    ) -> Result<Bound<'py, PyAny>>
     where
         T: ?Sized + Serialize,
     {
@@ -245,17 +364,21 @@ impl<'py, P: PythonizeTypes> ser::Serial
 
     fn serialize_newtype_variant<T>(
         self,
-        _name: &'static str,
+        name: &'static str,
         _variant_index: u32,
         variant: &'static str,
         value: &T,
-    ) -> Result<PyObject>
+    ) -> Result<Bound<'py, PyAny>>
     where
         T: ?Sized + Serialize,
     {
-        let d = PyDict::new_bound(self.py);
-        d.set_item(variant, value.serialize(self)?)?;
-        Ok(d.into())
+        let mut m = P::NamedMap::builder(self.py, 1, name)?;
+        P::NamedMap::push_field(
+            &mut m,
+            PyString::new(self.py, variant),
+            value.serialize(self)?,
+        )?;
+        Ok(P::NamedMap::finish(m)?.into_any())
     }
 
     fn serialize_seq(self, len: Option<usize>) -> Result<PythonCollectionSerializer<'py, P>> {
@@ -288,18 +411,22 @@ impl<'py, P: PythonizeTypes> ser::Serial
 
     fn serialize_tuple_variant(
         self,
-        _name: &'static str,
+        name: &'static str,
         _variant_index: u32,
         variant: &'static str,
         len: usize,
     ) -> Result<PythonTupleVariantSerializer<'py, P>> {
         let inner = self.serialize_tuple(len)?;
-        Ok(PythonTupleVariantSerializer { variant, inner })
+        Ok(PythonTupleVariantSerializer {
+            name,
+            variant,
+            inner,
+        })
     }
 
-    fn serialize_map(self, _len: Option<usize>) -> Result<PythonMapSerializer<'py, P>> {
+    fn serialize_map(self, len: Option<usize>) -> Result<PythonMapSerializer<'py, P>> {
         Ok(PythonMapSerializer {
-            map: P::Map::create_mapping(self.py)?,
+            builder: P::Map::builder(self.py, len)?,
             key: None,
             py: self.py,
             _types: PhantomData,
@@ -308,36 +435,37 @@ impl<'py, P: PythonizeTypes> ser::Serial
 
     fn serialize_struct(
         self,
-        _name: &'static str,
-        _len: usize,
-    ) -> Result<PythonDictSerializer<'py, P>> {
-        Ok(PythonDictSerializer {
-            dict: P::Map::create_mapping(self.py)?,
+        name: &'static str,
+        len: usize,
+    ) -> Result<PythonStructDictSerializer<'py, P>> {
+        Ok(PythonStructDictSerializer {
             py: self.py,
+            builder: P::NamedMap::builder(self.py, len, name)?,
             _types: PhantomData,
         })
     }
 
     fn serialize_struct_variant(
         self,
-        _name: &'static str,
+        name: &'static str,
         _variant_index: u32,
         variant: &'static str,
-        _len: usize,
+        len: usize,
     ) -> Result<PythonStructVariantSerializer<'py, P>> {
         Ok(PythonStructVariantSerializer {
+            name,
             variant,
-            inner: PythonDictSerializer {
-                dict: P::Map::create_mapping(self.py)?,
+            inner: PythonStructDictSerializer {
                 py: self.py,
+                builder: P::NamedMap::builder(self.py, len, variant)?,
                 _types: PhantomData,
             },
         })
     }
 }
 
-impl<'py, P: PythonizeTypes> ser::SerializeSeq for PythonCollectionSerializer<'py, P> {
-    type Ok = PyObject;
+impl<'py, P: PythonizeTypes<'py>> ser::SerializeSeq for PythonCollectionSerializer<'py, P> {
+    type Ok = Bound<'py, PyAny>;
     type Error = PythonizeError;
 
     fn serialize_element<T>(&mut self, value: &T) -> Result<()>
@@ -348,14 +476,14 @@ impl<'py, P: PythonizeTypes> ser::Serial
         Ok(())
     }
 
-    fn end(self) -> Result<PyObject> {
+    fn end(self) -> Result<Bound<'py, PyAny>> {
         let instance = P::List::create_sequence(self.py, self.items)?;
-        Ok(instance.to_object(self.py))
+        Ok(instance.into_pyobject(self.py)?.into_any())
     }
 }
 
-impl<'py, P: PythonizeTypes> ser::SerializeTuple for PythonCollectionSerializer<'py, P> {
-    type Ok = PyObject;
+impl<'py, P: PythonizeTypes<'py>> ser::SerializeTuple for PythonCollectionSerializer<'py, P> {
+    type Ok = Bound<'py, PyAny>;
     type Error = PythonizeError;
 
     fn serialize_element<T>(&mut self, value: &T) -> Result<()>
@@ -365,13 +493,13 @@ impl<'py, P: PythonizeTypes> ser::Serial
         ser::SerializeSeq::serialize_element(self, value)
     }
 
-    fn end(self) -> Result<PyObject> {
-        Ok(PyTuple::new_bound(self.py, self.items).into())
+    fn end(self) -> Result<Bound<'py, PyAny>> {
+        Ok(PyTuple::new(self.py, self.items)?.into_any())
     }
 }
 
-impl<'py, P: PythonizeTypes> ser::SerializeTupleStruct for PythonCollectionSerializer<'py, P> {
-    type Ok = PyObject;
+impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleStruct for PythonCollectionSerializer<'py, P> {
+    type Ok = Bound<'py, PyAny>;
     type Error = PythonizeError;
 
     fn serialize_field<T>(&mut self, value: &T) -> Result<()>
@@ -381,13 +509,15 @@ impl<'py, P: PythonizeTypes> ser::Serial
         ser::SerializeSeq::serialize_element(self, value)
     }
 
-    fn end(self) -> Result<PyObject> {
+    fn end(self) -> Result<Bound<'py, PyAny>> {
         ser::SerializeTuple::end(self)
     }
 }
 
-impl<'py, P: PythonizeTypes> ser::SerializeTupleVariant for PythonTupleVariantSerializer<'py, P> {
-    type Ok = PyObject;
+impl<'py, P: PythonizeTypes<'py>> ser::SerializeTupleVariant
+    for PythonTupleVariantSerializer<'py, P>
+{
+    type Ok = Bound<'py, PyAny>;
     type Error = PythonizeError;
 
     fn serialize_field<T>(&mut self, value: &T) -> Result<()>
@@ -397,15 +527,19 @@ impl<'py, P: PythonizeTypes> ser::Serial
         ser::SerializeSeq::serialize_element(&mut self.inner, value)
     }
 
-    fn end(self) -> Result<PyObject> {
-        let d = PyDict::new_bound(self.inner.py);
-        d.set_item(self.variant, ser::SerializeTuple::end(self.inner)?)?;
-        Ok(d.into())
+    fn end(self) -> Result<Bound<'py, PyAny>> {
+        let mut m = P::NamedMap::builder(self.inner.py, 1, self.name)?;
+        P::NamedMap::push_field(
+            &mut m,
+            PyString::new(self.inner.py, self.variant),
+            ser::SerializeTuple::end(self.inner)?,
+        )?;
+        Ok(P::NamedMap::finish(m)?.into_any())
     }
 }
 
-impl<'py, P: PythonizeTypes> ser::SerializeMap for PythonMapSerializer<'py, P> {
-    type Ok = PyObject;
+impl<'py, P: PythonizeTypes<'py>> ser::SerializeMap for PythonMapSerializer<'py, P> {
+    type Ok = Bound<'py, PyAny>;
     type Error = PythonizeError;
 
     fn serialize_key<T>(&mut self, key: &T) -> Result<()>
@@ -420,7 +554,8 @@ impl<'py, P: PythonizeTypes> ser::Serial
     where
         T: ?Sized + Serialize,
     {
-        self.map.set_item(
+        P::Map::push_item(
+            &mut self.builder,
             self.key
                 .take()
                 .expect("serialize_value should always be called after serialize_key"),
@@ -429,47 +564,59 @@ impl<'py, P: PythonizeTypes> ser::Serial
         Ok(())
     }
 
-    fn end(self) -> Result<PyObject> {
-        Ok(self.map.into())
+    fn end(self) -> Result<Bound<'py, PyAny>> {
+        Ok(P::Map::finish(self.builder)?.into_any())
     }
 }
 
-impl<'py, P: PythonizeTypes> ser::SerializeStruct for PythonDictSerializer<'py, P> {
-    type Ok = PyObject;
+impl<'py, P: PythonizeTypes<'py>> ser::SerializeStruct for PythonStructDictSerializer<'py, P> {
+    type Ok = Bound<'py, PyAny>;
     type Error = PythonizeError;
 
     fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
     where
         T: ?Sized + Serialize,
     {
-        Ok(self
-            .dict
-            .set_item(key, pythonize_custom::<P, _>(self.py, value)?)?)
+        P::NamedMap::push_field(
+            &mut self.builder,
+            PyString::new(self.py, key),
+            pythonize_custom::<P, _>(self.py, value)?,
+        )?;
+        Ok(())
     }
 
-    fn end(self) -> Result<PyObject> {
-        Ok(self.dict.into())
+    fn end(self) -> Result<Bound<'py, PyAny>> {
+        Ok(P::NamedMap::finish(self.builder)?.into_any())
     }
 }
 
-impl<'py, P: PythonizeTypes> ser::SerializeStructVariant for PythonStructVariantSerializer<'py, P> {
-    type Ok = PyObject;
+impl<'py, P: PythonizeTypes<'py>> ser::SerializeStructVariant
+    for PythonStructVariantSerializer<'py, P>
+{
+    type Ok = Bound<'py, PyAny>;
     type Error = PythonizeError;
 
     fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
     where
         T: ?Sized + Serialize,
     {
-        self.inner
-            .dict
-            .set_item(key, pythonize_custom::<P, _>(self.inner.py, value)?)?;
+        P::NamedMap::push_field(
+            &mut self.inner.builder,
+            PyString::new(self.inner.py, key),
+            pythonize_custom::<P, _>(self.inner.py, value)?,
+        )?;
         Ok(())
     }
 
-    fn end(self) -> Result<PyObject> {
-        let d = PyDict::new_bound(self.inner.py);
-        d.set_item(self.variant, self.inner.dict)?;
-        Ok(d.into())
+    fn end(self) -> Result<Bound<'py, PyAny>> {
+        let v = P::NamedMap::finish(self.inner.builder)?;
+        let mut m = P::NamedMap::builder(self.inner.py, 1, self.name)?;
+        P::NamedMap::push_field(
+            &mut m,
+            PyString::new(self.inner.py, self.variant),
+            v.into_any(),
+        )?;
+        Ok(P::NamedMap::finish(m)?.into_any())
     }
 }
 
@@ -477,9 +624,10 @@ impl<'py, P: PythonizeTypes> ser::Serial
 mod test {
     use super::pythonize;
     use maplit::hashmap;
+    use pyo3::ffi::c_str;
     use pyo3::prelude::*;
     use pyo3::pybacked::PyBackedStr;
-    use pyo3::types::PyDict;
+    use pyo3::types::{PyBytes, PyDict};
     use serde::Serialize;
 
     fn test_ser<T>(src: T, expected: &str)
@@ -489,11 +637,11 @@ mod test {
         Python::with_gil(|py| -> PyResult<()> {
             let obj = pythonize(py, &src)?;
 
-            let locals = PyDict::new_bound(py);
+            let locals = PyDict::new(py);
             locals.set_item("obj", obj)?;
 
-            py.run_bound(
-                "import json; result = json.dumps(obj, separators=(',', ':'))",
+            py.run(
+                c_str!("import json; result = json.dumps(obj, separators=(',', ':'))"),
                 None,
                 Some(&locals),
             )?;
@@ -534,6 +682,30 @@ mod test {
     }
 
     #[test]
+    fn test_nested_struct() {
+        #[derive(Serialize)]
+        struct Foo {
+            name: String,
+            bar: Bar,
+        }
+
+        #[derive(Serialize)]
+        struct Bar {
+            name: String,
+        }
+
+        test_ser(
+            Foo {
+                name: "foo".to_string(),
+                bar: Bar {
+                    name: "bar".to_string(),
+                },
+            },
+            r#"{"name":"foo","bar":{"name":"bar"}}"#,
+        )
+    }
+
+    #[test]
     fn test_tuple_struct() {
         #[derive(Serialize)]
         struct TupleStruct(String, usize);
@@ -632,6 +804,27 @@ mod test {
     }
 
     #[test]
+    fn test_floats() {
+        #[derive(Serialize)]
+        struct Floats {
+            a: f32,
+            b: f64,
+        }
+
+        test_ser(Floats { a: 1.0, b: 2.0 }, r#"{"a":1.0,"b":2.0}"#)
+    }
+
+    #[test]
+    fn test_char() {
+        #[derive(Serialize)]
+        struct Char {
+            a: char,
+        }
+
+        test_ser(Char { a: 'a' }, r#"{"a":"a"}"#)
+    }
+
+    #[test]
     fn test_bool() {
         test_ser(true, "true");
         test_ser(false, "false");
@@ -644,10 +837,21 @@ mod test {
 
         test_ser((), "null");
         test_ser(S, "null");
+
+        test_ser(Some(1), "1");
+        test_ser(None::<i32>, "null");
     }
 
     #[test]
     fn test_bytes() {
+        // serde treats &[u8] as a sequence of integers due to lack of specialization
         test_ser(b"foo", "[102,111,111]");
+
+        Python::with_gil(|py| {
+            assert!(pythonize(py, serde_bytes::Bytes::new(b"foo"))
+                .expect("bytes will always serialize successfully")
+                .eq(&PyBytes::new(py, b"foo"))
+                .expect("bytes will always compare successfully"));
+        });
     }
 }
diff -pruN 0.21.1-1/tests/test_custom_types.rs 0.25.0-1/tests/test_custom_types.rs
--- 0.21.1-1/tests/test_custom_types.rs	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/tests/test_custom_types.rs	2006-07-24 01:21:28.000000000 +0000
@@ -3,11 +3,12 @@ use std::collections::HashMap;
 use pyo3::{
     exceptions::{PyIndexError, PyKeyError},
     prelude::*,
-    types::{PyDict, PyList, PyMapping, PySequence},
+    types::{PyDict, PyMapping, PySequence, PyTuple},
+    BoundObject,
 };
 use pythonize::{
-    depythonize_bound, pythonize_custom, PythonizeDictType, PythonizeListType, PythonizeTypes,
-    Pythonizer,
+    depythonize, pythonize_custom, PythonizeListType, PythonizeMappingType,
+    PythonizeNamedMappingType, PythonizeTypes, PythonizeUnnamedMappingAdapter, Pythonizer,
 };
 use serde::Serialize;
 use serde_json::{json, Value};
@@ -32,12 +33,12 @@ impl CustomList {
 }
 
 impl PythonizeListType for CustomList {
-    fn create_sequence<T, U>(
-        py: Python,
+    fn create_sequence<'py, T, U>(
+        py: Python<'py>,
         elements: impl IntoIterator<Item = T, IntoIter = U>,
-    ) -> PyResult<Bound<PySequence>>
+    ) -> PyResult<Bound<'py, PySequence>>
     where
-        T: ToPyObject,
+        T: IntoPyObject<'py>,
         U: ExactSizeIterator<Item = T>,
     {
         let sequence = Bound::new(
@@ -45,8 +46,9 @@ impl PythonizeListType for CustomList {
             CustomList {
                 items: elements
                     .into_iter()
-                    .map(|item| item.to_object(py))
-                    .collect(),
+                    .map(|item| item.into_pyobject(py).map(|x| x.into_any().unbind()))
+                    .collect::<Result<Vec<_>, T::Error>>()
+                    .map_err(Into::into)?,
             },
         )?
         .into_any();
@@ -56,8 +58,9 @@ impl PythonizeListType for CustomList {
 }
 
 struct PythonizeCustomList;
-impl PythonizeTypes for PythonizeCustomList {
+impl<'py> PythonizeTypes<'py> for PythonizeCustomList {
     type Map = PyDict;
+    type NamedMap = PythonizeUnnamedMappingAdapter<'py, PyDict>;
     type List = CustomList;
 }
 
@@ -65,12 +68,10 @@ impl PythonizeTypes for PythonizeCustomL
 fn test_custom_list() {
     Python::with_gil(|py| {
         PySequence::register::<CustomList>(py).unwrap();
-        let serialized = pythonize_custom::<PythonizeCustomList, _>(py, &json!([1, 2, 3]))
-            .unwrap()
-            .into_bound(py);
+        let serialized = pythonize_custom::<PythonizeCustomList, _>(py, &json!([1, 2, 3])).unwrap();
         assert!(serialized.is_instance_of::<CustomList>());
 
-        let deserialized: Value = depythonize_bound(serialized).unwrap();
+        let deserialized: Value = depythonize(&serialized).unwrap();
         assert_eq!(deserialized, json!([1, 2, 3]));
     })
 }
@@ -106,23 +107,36 @@ impl CustomDict {
     }
 }
 
-impl PythonizeDictType for CustomDict {
-    fn create_mapping(py: Python) -> PyResult<Bound<PyMapping>> {
-        let mapping = Bound::new(
+impl<'py> PythonizeMappingType<'py> for CustomDict {
+    type Builder = Bound<'py, CustomDict>;
+
+    fn builder(py: Python<'py>, len: Option<usize>) -> PyResult<Self::Builder> {
+        Bound::new(
             py,
             CustomDict {
-                items: HashMap::new(),
+                items: HashMap::with_capacity(len.unwrap_or(0)),
             },
-        )?
-        .into_any();
-        Ok(unsafe { mapping.downcast_into_unchecked() })
+        )
+    }
+
+    fn push_item(
+        builder: &mut Self::Builder,
+        key: Bound<'py, PyAny>,
+        value: Bound<'py, PyAny>,
+    ) -> PyResult<()> {
+        unsafe { builder.downcast_unchecked::<PyMapping>() }.set_item(key, value)
+    }
+
+    fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>> {
+        Ok(unsafe { builder.into_any().downcast_into_unchecked() })
     }
 }
 
 struct PythonizeCustomDict;
-impl PythonizeTypes for PythonizeCustomDict {
+impl<'py> PythonizeTypes<'py> for PythonizeCustomDict {
     type Map = CustomDict;
-    type List = PyList;
+    type NamedMap = PythonizeUnnamedMappingAdapter<'py, CustomDict>;
+    type List = PyTuple;
 }
 
 #[test]
@@ -131,16 +145,28 @@ fn test_custom_dict() {
         PyMapping::register::<CustomDict>(py).unwrap();
         let serialized =
             pythonize_custom::<PythonizeCustomDict, _>(py, &json!({ "hello": 1, "world": 2 }))
-                .unwrap()
-                .into_bound(py);
+                .unwrap();
         assert!(serialized.is_instance_of::<CustomDict>());
 
-        let deserialized: Value = depythonize_bound(serialized).unwrap();
+        let deserialized: Value = depythonize(&serialized).unwrap();
         assert_eq!(deserialized, json!({ "hello": 1, "world": 2 }));
     })
 }
 
 #[test]
+fn test_tuple() {
+    Python::with_gil(|py| {
+        PyMapping::register::<CustomDict>(py).unwrap();
+        let serialized =
+            pythonize_custom::<PythonizeCustomDict, _>(py, &json!([1, 2, 3, 4])).unwrap();
+        assert!(serialized.is_instance_of::<PyTuple>());
+
+        let deserialized: Value = depythonize(&serialized).unwrap();
+        assert_eq!(deserialized, json!([1, 2, 3, 4]));
+    })
+}
+
+#[test]
 fn test_pythonizer_can_be_created() {
     // https://github.com/davidhewitt/pythonize/pull/56
     Python::with_gil(|py| {
@@ -148,13 +174,110 @@ fn test_pythonizer_can_be_created() {
         assert!(sample
             .serialize(Pythonizer::new(py))
             .unwrap()
-            .bind(py)
             .is_instance_of::<PyDict>());
 
         assert!(sample
             .serialize(Pythonizer::custom::<PythonizeCustomDict>(py))
             .unwrap()
-            .bind(py)
             .is_instance_of::<CustomDict>());
     })
 }
+
+#[pyclass(mapping)]
+struct NamedCustomDict {
+    name: String,
+    items: HashMap<String, PyObject>,
+}
+
+#[pymethods]
+impl NamedCustomDict {
+    fn __len__(&self) -> usize {
+        self.items.len()
+    }
+
+    fn __getitem__(&self, key: String) -> PyResult<PyObject> {
+        self.items
+            .get(&key)
+            .cloned()
+            .ok_or_else(|| PyKeyError::new_err(key))
+    }
+
+    fn __setitem__(&mut self, key: String, value: PyObject) {
+        self.items.insert(key, value);
+    }
+
+    fn keys(&self) -> Vec<&String> {
+        self.items.keys().collect()
+    }
+
+    fn values(&self) -> Vec<PyObject> {
+        self.items.values().cloned().collect()
+    }
+}
+
+impl<'py> PythonizeNamedMappingType<'py> for NamedCustomDict {
+    type Builder = Bound<'py, NamedCustomDict>;
+
+    fn builder(py: Python<'py>, len: usize, name: &'static str) -> PyResult<Self::Builder> {
+        Bound::new(
+            py,
+            NamedCustomDict {
+                name: String::from(name),
+                items: HashMap::with_capacity(len),
+            },
+        )
+    }
+
+    fn push_field(
+        builder: &mut Self::Builder,
+        name: Bound<'py, pyo3::types::PyString>,
+        value: Bound<'py, PyAny>,
+    ) -> PyResult<()> {
+        unsafe { builder.downcast_unchecked::<PyMapping>() }.set_item(name, value)
+    }
+
+    fn finish(builder: Self::Builder) -> PyResult<Bound<'py, PyMapping>> {
+        Ok(unsafe { builder.into_any().downcast_into_unchecked() })
+    }
+}
+
+struct PythonizeNamedCustomDict;
+impl<'py> PythonizeTypes<'py> for PythonizeNamedCustomDict {
+    type Map = CustomDict;
+    type NamedMap = NamedCustomDict;
+    type List = PyTuple;
+}
+
+#[derive(Serialize)]
+struct Struct {
+    hello: u8,
+    world: i8,
+}
+
+#[test]
+fn test_custom_unnamed_dict() {
+    Python::with_gil(|py| {
+        PyMapping::register::<CustomDict>(py).unwrap();
+        let serialized =
+            pythonize_custom::<PythonizeCustomDict, _>(py, &Struct { hello: 1, world: 2 }).unwrap();
+        assert!(serialized.is_instance_of::<CustomDict>());
+
+        let deserialized: Value = depythonize(&serialized).unwrap();
+        assert_eq!(deserialized, json!({ "hello": 1, "world": 2 }));
+    })
+}
+
+#[test]
+fn test_custom_named_dict() {
+    Python::with_gil(|py| {
+        PyMapping::register::<NamedCustomDict>(py).unwrap();
+        let serialized =
+            pythonize_custom::<PythonizeNamedCustomDict, _>(py, &Struct { hello: 1, world: 2 })
+                .unwrap();
+        let named: Bound<NamedCustomDict> = serialized.extract().unwrap();
+        assert_eq!(named.borrow().name, "Struct");
+
+        let deserialized: Value = depythonize(&serialized).unwrap();
+        assert_eq!(deserialized, json!({ "hello": 1, "world": 2 }));
+    })
+}
diff -pruN 0.21.1-1/tests/test_with_serde_path_to_err.rs 0.25.0-1/tests/test_with_serde_path_to_err.rs
--- 0.21.1-1/tests/test_with_serde_path_to_err.rs	2006-07-24 01:21:28.000000000 +0000
+++ 0.25.0-1/tests/test_with_serde_path_to_err.rs	2006-07-24 01:21:28.000000000 +0000
@@ -3,9 +3,8 @@ use std::collections::BTreeMap;
 use pyo3::{
     prelude::*,
     types::{PyDict, PyList},
-    Py, PyAny, Python,
 };
-use pythonize::PythonizeTypes;
+use pythonize::{PythonizeTypes, PythonizeUnnamedMappingAdapter};
 use serde::{Deserialize, Serialize};
 
 #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
@@ -14,8 +13,9 @@ struct Root<T> {
     root_map: BTreeMap<String, Nested<T>>,
 }
 
-impl<T> PythonizeTypes for Root<T> {
+impl<'py, T> PythonizeTypes<'py> for Root<T> {
     type Map = PyDict;
+    type NamedMap = PythonizeUnnamedMappingAdapter<'py, PyDict>;
     type List = PyList;
 }
 
@@ -41,20 +41,20 @@ impl Serialize for CannotSerialize {
 #[test]
 fn test_de_valid() {
     Python::with_gil(|py| {
-        let pyroot = PyDict::new_bound(py);
+        let pyroot = PyDict::new(py);
         pyroot.set_item("root_key", "root_value").unwrap();
 
-        let nested = PyDict::new_bound(py);
-        let nested_0 = PyDict::new_bound(py);
+        let nested = PyDict::new(py);
+        let nested_0 = PyDict::new(py);
         nested_0.set_item("nested_key", "nested_value_0").unwrap();
         nested.set_item("nested_0", nested_0).unwrap();
-        let nested_1 = PyDict::new_bound(py);
+        let nested_1 = PyDict::new(py);
         nested_1.set_item("nested_key", "nested_value_1").unwrap();
         nested.set_item("nested_1", nested_1).unwrap();
 
         pyroot.set_item("root_map", nested).unwrap();
 
-        let de = &mut pythonize::Depythonizer::from_object_bound(pyroot.into_any());
+        let de = &mut pythonize::Depythonizer::from_object(&pyroot);
         let root: Root<String> = serde_path_to_error::deserialize(de).unwrap();
 
         assert_eq!(
@@ -83,20 +83,20 @@ fn test_de_valid() {
 #[test]
 fn test_de_invalid() {
     Python::with_gil(|py| {
-        let pyroot = PyDict::new_bound(py);
+        let pyroot = PyDict::new(py);
         pyroot.set_item("root_key", "root_value").unwrap();
 
-        let nested = PyDict::new_bound(py);
-        let nested_0 = PyDict::new_bound(py);
+        let nested = PyDict::new(py);
+        let nested_0 = PyDict::new(py);
         nested_0.set_item("nested_key", "nested_value_0").unwrap();
         nested.set_item("nested_0", nested_0).unwrap();
-        let nested_1 = PyDict::new_bound(py);
+        let nested_1 = PyDict::new(py);
         nested_1.set_item("nested_key", 1).unwrap();
         nested.set_item("nested_1", nested_1).unwrap();
 
         pyroot.set_item("root_map", nested).unwrap();
 
-        let de = &mut pythonize::Depythonizer::from_object_bound(pyroot.into_any());
+        let de = &mut pythonize::Depythonizer::from_object(&pyroot);
         let err = serde_path_to_error::deserialize::<_, Root<String>>(de).unwrap_err();
 
         assert_eq!(err.path().to_string(), "root_map.nested_1.nested_key");
@@ -126,9 +126,9 @@ fn test_ser_valid() {
         };
 
         let ser = pythonize::Pythonizer::<Root<String>>::from(py);
-        let pyroot: Py<PyAny> = serde_path_to_error::serialize(&root, ser).unwrap();
+        let pyroot: Bound<'_, PyAny> = serde_path_to_error::serialize(&root, ser).unwrap();
 
-        let pyroot = pyroot.bind(py).downcast::<PyDict>().unwrap();
+        let pyroot = pyroot.downcast::<PyDict>().unwrap();
         assert_eq!(pyroot.len(), 2);
 
         let root_value: String = pyroot
