3203: support ordering magic methods for `#[pyclass]` r=adamreichold a=davidhewitt
Closes#2089
This adds `__lt__`, `__le__`, `__eq__`, `__ne__`, `__gt__`, and `__ge__` as per the Python implementations of what we call `__richcmp__`.
There's a UI test confirming that the user cannot implement split forms and `__richcmp__` simultaneously.
There's also a benchmark comparing implementing these split methods against using `__richcmp__`. I couldn't see a meaningful performance difference, so I'm tempted to deprecate `__richcmp__`, given that's not a magic method which exists in Python. Potentially we can provide options such as the opt-in `#[pyclass(eq, ord)]` to avoid boilerplate for people who don't want to implement six different methods.
Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
3208: bump msrv to 1.56 r=davidhewitt a=davidhewitt
The MSRV changes from #3204, plus a commit which should hopefully make CI pass.
With luck this is mergeable and resolves CI pain while we decide what to do about the Python version.
Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
3200: RFC: remove copyright headers from source files r=davidhewitt a=davidhewitt
As part of our relicensing effort - I've observed that over time we haven't applied COPYRIGHT headers consistently to source files.
I've seen different organisations take different approaches to this. I note that for [`rust-lang/rust`, headers only exist where code has been moved inside the Rust repo without relicensing](https://github.com/search?q=repo%3Arust-lang%2Frust+copyright+language%3ARust&type=code&l=Rust).
For PyO3, I suggest we follow this and remove COPYRIGHT headers from source. We may wish to consider attributing to `rust-cpython` as the original project from which PyO3 was forked, possibly in the License section of the readme?
Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
3198: Add abi3 + num_bigint conversion r=davidhewitt a=youknowone
<!--
Please consider adding the following to your pull request:
- an entry for this PR in newsfragments - see [https://pyo3.rs/main/contributing.html#documenting-changes]
- docs to all new functions and / or detail in the guide
- tests for all new or changed functions
PyO3's CI pipeline will check your pull request. To run its tests
locally, you can run ```cargo xtask ci```. See its documentation
[here](https://github.com/PyO3/pyo3/tree/main/xtask#readme).
-->
Fix#3196
Co-authored-by: Jeong YunWon <jeong@youknowone.org>
3185: Fix `abi3` conversion of `__complex__` classes r=adamreichold a=jakelishman
Python classes that were not `complex` but implemented the `__complex__` magic would have that method called via `PyComplex_AsCComplex` when running against the full API, but the limited-API version `PyComplex_RealAsDouble` does not attempt this conversion. If the input object is not already complex, we can call the magic before proceeding.
Happy to modify if I've made a mess of testing strategy - I'm not sure I've managed to do it in the same style as other tests.
Fix#3164.
Co-authored-by: Jake Lishman <jake.lishman@ibm.com>
3199: update PR template to detail state of licensing r=davidhewitt a=davidhewitt
Adds detail about #3108 to the README and the PR template.
`@DataTriny` - I thought that adding this would help encourage new contributors to be aware of the licensing terms and also that they would need to explicitly accept the future license.
Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
Python classes that were not `complex` but implemented the `__complex__`
magic would have that method called via `PyComplex_AsCComplex` when
running against the full API, but the limited-API version
`PyComplex_RealAsDouble` does not attempt this conversion. If the input
object is not already complex, we can call the magic before proceeding.
`PyAny::lookup_special` is an approximate equivalent to the CPython
internal `_PyObject_LookupSpecial`, which is used to resolve lookups of
"magic" methods. These are only looked up from the type, and skip the
instance dictionary during the lookup. Despite this, they are still
required to resolve the descriptor protocol.
Many magic methods have slots on the `PyTypeObject` or respective
subobjects, but these are not necessarily available when targeting the
limited API or PyPy. In these cases, the requisite logic can be worked
around using safe but likely slower APIs.
Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
Fix up lookup-special
3187: release: 0.19.0 r=davidhewitt a=davidhewitt
As per #3154 I think we're ready to push 0.19.
I'll put this live on Tuesday evening unless I hear a reason to postpone.
Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
3188: Verify that macros do work without any imports r=adamreichold a=lifthrasiir
Currently virtually all (positive) tests import `pyo3::prelude::*`, making it hard to detect a certain class of bugs. This PR adds an explicit test that never imports from `pyo3` to fix this.
Also this fixes a minor bug from #3157 which didn't work without `use pyo3::types::PyType;`. I think this should be a part of 0.19.0 (#3187), so no additional changelog would be required (as this feature is new in 0.19.0).
Co-authored-by: Kang Seonghoon <public+git@mearie.org>
3183: Add benchmark showing that extract::<i64> is costly due to PyNumber_Index trying hard. r=davidhewitt a=adamreichold
The benchmarks from #3182 to keep around for later and to play around with.
Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
3171: RFC: Simplify version handling of UI tests. r=davidhewitt a=adamreichold
Due to checking in error outputs these tests only work reliably on stable and not on intermediate version between our MSRV (currently 1.48) and the current stable version.
Hence this simplifies things to run only MSRV-compatible tests for the MSRV builds, anything else for stable builds except for those tests which require the nightly feature, i.e. the `Ungil` being distinct from the `Send` trait.
Finally, `not_send3` is disabled when using the nightly feature since while `Rc` is not send, it also not GIL-bound and hence can be passed into `allow_threads` as it does not actually spawn a new thread.
Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
Due to checking in error outputs these tests only work reliably on stable and
not on intermediate version between our MSRV (currently 1.48) and the current
stable version.
Hence this simplifies things to run only MSRV-compatible tests for the MSRV
builds, anything else for stable builds except for those tests which require the
nightly feature, i.e. the `Ungil` being distinct from the `Send` trait.
Finally, `not_send3` is disabled when using the nightly feature since while `Rc`
is not send, it also not GIL-bound and hence can be passed into `allow_threads`
as it does not actually spawn a new thread.
3184: Additional tests for #3168 r=adamreichold a=adamreichold
These were a part of tests `@lifthrasiir` was preparing for https://github.com/PyO3/pyo3/issues/3165, and I believe it's worthy to add them (any single of them fails in the current main branch).
Co-authored-by: Kang Seonghoon <public+git@mearie.org>
3168: Do not apply deferred ref count updates and prevent the GIL from being acquired inside of __traverse__ implementations. r=davidhewitt a=adamreichold
Closes#2301Closes#3165
3176: Prevent dropping unsendable classes on other threads. r=davidhewitt a=adamreichold
Continuing the discussed from https://github.com/PyO3/pyo3/pull/3169#issuecomment-1556571504 and https://github.com/PyO3/pyo3/pull/3169#issuecomment-1556661723:
We already have checks in place to avoid borrowing these classes on other threads but it was still possible to send them to another thread and drop them there (while holding the GIL).
This change avoids running the `Drop` implementation in such a case even though Python will still free the underlying memory. This might leak resources owned by the object, but it avoids undefined behaviour due to access the unsendable type from another thread.
This does assume that the object was not unsafely integrated into an intrusive data structures which still point to the now freed memory. In that case, the only recourse would be to abort the process as freeing the memory is unavoidable when the tp_dealloc slot is called. (And moving it elsewhere into a new allocation would still break any existing pointers.)
Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
We already have checks in place to avoid borrowing these classes on other
threads but it was still possible to send them to another thread and drop them
there (while holding the GIL).
This change avoids running the `Drop` implementation in such a case even though
Python will still free the underlying memory. This might leak resources owned by
the object, but it avoids undefined behaviour due to access the unsendable type
from another thread.
This does assume that the object was not unsafely integrated into an intrusive
data structures which still point to the now freed memory. In that case, the
only recourse would be to abort the process as freeing the memory is unavoidable
when the tp_dealloc slot is called. (And moving it elsewhere into a new
allocation would still break any existing pointers.)
3177: RFC: Use a const initializer for `GIL_COUNT` if possible r=adamreichold a=lifthrasiir
Normally [`LocalKey::try_with`](https://doc.rust-lang.org/stable/std/thread/struct.LocalKey.html#method.try_with) needs to check for the initialization flag to lazily initialize the TLS. This behaves badly with a compiler optimization and it seems that multiple calls to `gil_is_acquired()` cannot be correctly eliminated. Rust 1.59 added a `const { ... }` initializer (a special form only allowed here for now) in `thread_local!` which removes the initialization flag, allowing those kind of optimizations.
I should note that the performance impact is probably minimal, because the check branch is extremely well predicted and the optimization is only possible when every PyO3 code that leads to `gil_is_acquired()` is inlined, a pretty uncommon situation. I couldn't demonstrate any consistent improvement or regression from my machine, which performance seems to be flaky as well. But at least we would have one less branch there. I'll leave this as an RFC so that someone else can prove or disprove that this is indeed beneficial.
Co-authored-by: Kang Seonghoon <public+git@mearie.org>
3166: RFC: Drop EnsureGIL to remove one layer of indirection from the implementation of Python::with_gil r=davidhewitt a=adamreichold
I am not sure if other people would consider this a simplification as well, but it helped me to remove one layer of indirection used by the implementation of `Python::with_gil`, especially flattening the `Option<_>` layers in `EnsureGIL` and `GILGuard::pool`. This makes it obvious that we always create `GILPool` when we actually acquire the GIL. (Of course, there still might be extra `GILPool` instances created manually.)
Co-authored-by: Adam Reichold <adam.reichold@t-online.de>