Skip to content

docs: add guide chapter detailing current way to share classes between modules#5938

Merged
davidhewitt merged 9 commits intoPyO3:mainfrom
davidhewitt:pyclass-sharing-doc
May 1, 2026
Merged

docs: add guide chapter detailing current way to share classes between modules#5938
davidhewitt merged 9 commits intoPyO3:mainfrom
davidhewitt:pyclass-sharing-doc

Conversation

@davidhewitt
Copy link
Copy Markdown
Member

@davidhewitt davidhewitt commented Apr 3, 2026

I had some time recently to investigate #1444 and plan how this might be one day addressed inside PyO3.

I came up with a protoype which shows a current (working) solution to this, with a bunch of limitations and caveats.

This PR writes up documentation about that prototype and proposes future work we could pursue to make this pattern easier in future. (It's hard, not supported well by rustc, cargo, or us, so lots of surface for possible improvement.)

@davidhewitt
Copy link
Copy Markdown
Member Author

Copy link
Copy Markdown
Contributor

@Tpt Tpt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the great writing.

I tend to feel using the cpython API is sometime a bit simpler than relying on the C-API.

For example if base-package expose a constant __version__ = (major, minor, patch, abi) and then classes like:

class Foo:
    @staticmethod
    def __from_capsule__(capsule: CapsuleType) -> Self: ...
    def __capsule__(self) -> CapsuleType: ...

then external crates can just do py.import("base_package").getattr("__version__") and py.import("base_package").getattr("Foo").call_method1("__from_capsule__", (my_capsule,)) (the actual repr(C) type for Foo being defined in a shared base-package-ffi crate or something similar). This is the approach used by Arrow and some other libraries.

To me, it feels slightly simple and less error prone than the C-ABI way but does not change much.

Comment thread src/types/capsule.rs Outdated

At a minimum, this will probably include:

- `get_shared_type: extern "C" fn() -> Py<PyType>` - a function to get the `#[pyclass]` Python type object for `SharedType`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we guarantee that Py is ffi-safe? If yes, it might be worth it to mention it in its documentation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, added some documentation for this.

Co-authored-by: Thomas Tanon <thomas@pellissier-tanon.fr>
@davidhewitt
Copy link
Copy Markdown
Member Author

Thanks for the review!

Interesting idea to use __version__ constant at the Python level, I hadn't considered that. I think I prefer to keep it inside the capsule, because otherwise it's possible to have Python code reassign __version__ to defeat the safety checks. Agreed it's more fiddly, but this is all fairly fiddly FFI code :/

@davidhewitt davidhewitt force-pushed the pyclass-sharing-doc branch from 2c0fa42 to 8773874 Compare May 1, 2026 08:49
@davidhewitt davidhewitt enabled auto-merge May 1, 2026 08:50
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 1, 2026

Merging this PR will improve performance by 13.8%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
✅ 104 untouched benchmarks
⏩ 1 skipped benchmark1

Performance Changes

Benchmark BASE HEAD Efficiency
bench_pyclass_create 4.6 µs 4 µs +13.8%

Comparing davidhewitt:pyclass-sharing-doc (8773874) with main (bd3dab0)

Open in CodSpeed

Footnotes

  1. 1 benchmark was skipped, so the baseline result was used instead. If it was deleted from the codebase, click here and archive it to remove it from the performance reports.

@davidhewitt davidhewitt added this pull request to the merge queue May 1, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks May 1, 2026
@davidhewitt davidhewitt added this pull request to the merge queue May 1, 2026
Merged via the queue into PyO3:main with commit 8a00673 May 1, 2026
46 checks passed
@davidhewitt davidhewitt deleted the pyclass-sharing-doc branch May 1, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants