pyproto: remove deprecated feature
This commit is contained in:
parent
68f1729a7b
commit
5718adeec7
|
@ -154,7 +154,7 @@ implemented in Python, such as GC support.
|
|||
## 5. Procedural macros to simplify usage for users.
|
||||
|
||||
[`pyo3-macros`] provides five proc-macro APIs: `pymodule`, `pyfunction`, `pyclass`,
|
||||
`pymethods`, and `#[derive(FromPyObject)]`. (And a deprecated `pyproto` macro.)
|
||||
`pymethods`, and `#[derive(FromPyObject)]`.
|
||||
[`pyo3-macros-backend`] has the actual implementations of these APIs.
|
||||
[`src/derive_utils.rs`] contains some utilities used in code generated by these proc-macros,
|
||||
such as parsing function arguments.
|
||||
|
|
|
@ -6,6 +6,12 @@ PyO3 versions, please see the [migration guide](https://pyo3.rs/latest/migration
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Removed
|
||||
|
||||
- Remove the deprecated `pyproto` feature, `#[pyproto]` macro, and all accompanying APIs. [#2587](https://github.com/PyO3/pyo3/pull/2587)
|
||||
|
||||
## [0.17.1] - 2022-08-28
|
||||
|
||||
### Fixed
|
||||
|
|
|
@ -64,9 +64,6 @@ macros = ["pyo3-macros", "indoc", "unindent"]
|
|||
# Enables multiple #[pymethods] per #[pyclass]
|
||||
multiple-pymethods = ["inventory", "pyo3-macros/multiple-pymethods"]
|
||||
|
||||
# Enables deprecated #[pyproto] macro
|
||||
pyproto = ["pyo3-macros/pyproto"]
|
||||
|
||||
# Use this feature when building an extension module.
|
||||
# It tells the linker to keep the python symbols unresolved,
|
||||
# so that the module can also be used with statically linked python interpreters.
|
||||
|
@ -97,7 +94,6 @@ nightly = []
|
|||
# This is mostly intended for testing purposes - activating *all* of these isn't particularly useful.
|
||||
full = [
|
||||
"macros",
|
||||
"pyproto",
|
||||
# "multiple-pymethods", # TODO re-add this when MSRV is greater than 1.62
|
||||
"num-bigint",
|
||||
"num-complex",
|
||||
|
|
|
@ -916,9 +916,9 @@ This simple technique works for the case when there is zero or one implementatio
|
|||
The `#[pyclass]` macro expands to roughly the code seen below. The `PyClassImplCollector` is the type used internally by PyO3 for dtolnay specialization:
|
||||
|
||||
```rust
|
||||
# #[cfg(not(any(feature = "multiple-pymethods", feature = "pyproto")))] {
|
||||
# #[cfg(not(feature = "multiple-pymethods"))] {
|
||||
# use pyo3::prelude::*;
|
||||
// Note: the implementation differs slightly with the `pyproto` or `multiple-pymethods` features enabled.
|
||||
// Note: the implementation differs slightly with the `multiple-pymethods` feature enabled.
|
||||
struct MyClass {
|
||||
# #[allow(dead_code)]
|
||||
num: i32,
|
||||
|
|
|
@ -2,12 +2,7 @@
|
|||
|
||||
Python's object model defines several protocols for different object behavior, such as the sequence, mapping, and number protocols. You may be familiar with implementing these protocols in Python classes by "magic" methods, such as `__str__` or `__repr__`. Because of the double-underscores surrounding their name, these are also known as "dunder" methods.
|
||||
|
||||
In the Python C-API which PyO3 is implemented upon, many of these magic methods have to be placed into special "slots" on the class type object, as covered in the previous section. There are two ways in which this can be done:
|
||||
|
||||
- In `#[pymethods]`, if the name of the method is a recognised magic method, PyO3 will place it in the type object automatically.
|
||||
- [Deprecated since PyO3 0.16] In special traits combined with the `#[pyproto]` attribute.
|
||||
|
||||
(There are also many magic methods which don't have a special slot, such as `__dir__`. These methods can be implemented as normal in `#[pymethods]`.)
|
||||
In the Python C-API which PyO3 is implemented upon, many of these magic methods have to be placed into special "slots" on the class type object, as covered in the previous section.
|
||||
|
||||
If a function name in `#[pymethods]` is a recognised magic method, it will be automatically placed into the correct slot in the Python type object. The function name is taken from the usual rules for naming `#[pymethods]`: the `#[pyo3(name = "...")]` attribute is used if present, otherwise the Rust function name is used.
|
||||
|
||||
|
@ -405,217 +400,5 @@ impl ClassWithGCSupport {
|
|||
```
|
||||
|
||||
[`IterNextOutput`]: {{#PYO3_DOCS_URL}}/pyo3/class/iter/enum.IterNextOutput.html
|
||||
|
||||
|
||||
### `#[pyproto]` traits
|
||||
|
||||
PyO3 can use the `#[pyproto]` attribute in combination with special traits to implement the magic methods which need slots. The special traits are listed below. See also the [documentation for the `pyo3::class` module]({{#PYO3_DOCS_URL}}/pyo3/class/index.html).
|
||||
|
||||
Due to complexity in the implementation and usage, these traits were deprecated in PyO3 0.16 in favour of the `#[pymethods]` solution.
|
||||
|
||||
All `#[pyproto]` methods can return `T` instead of `PyResult<T>` if the method implementation is infallible. In addition, if the return type is `()`, it can be omitted altogether.
|
||||
|
||||
#### Basic object customization
|
||||
|
||||
The [`PyObjectProtocol`] trait provides several basic customizations.
|
||||
|
||||
* `fn __str__(&self) -> PyResult<impl ToPyObject<ObjectType=PyString>>`
|
||||
* `fn __repr__(&self) -> PyResult<impl ToPyObject<ObjectType=PyString>>`
|
||||
* `fn __hash__(&self) -> PyResult<impl PrimInt>`
|
||||
* `fn __richcmp__(&self, other: impl FromPyObject, op: CompareOp) -> PyResult<impl ToPyObject>`
|
||||
* `fn __getattr__(&self, name: impl FromPyObject) -> PyResult<impl IntoPy<PyObject>>`
|
||||
* `fn __setattr__(&mut self, name: impl FromPyObject, value: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __delattr__(&mut self, name: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __bool__(&self) -> PyResult<bool>`
|
||||
|
||||
#### Emulating numeric types
|
||||
|
||||
The [`PyNumberProtocol`] trait can be implemented to emulate [numeric types](https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types).
|
||||
|
||||
* `fn __add__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __sub__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __mul__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __matmul__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __truediv__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __floordiv__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __mod__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __divmod__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __pow__(lhs: impl FromPyObject, rhs: impl FromPyObject, modulo: Option<impl FromPyObject>) -> PyResult<impl ToPyObject>`
|
||||
* `fn __lshift__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rshift__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __and__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __or__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __xor__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
|
||||
These methods are called to implement the binary arithmetic operations.
|
||||
|
||||
The reflected operations are also available:
|
||||
|
||||
* `fn __radd__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rsub__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rmul__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rmatmul__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rtruediv__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rfloordiv__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rmod__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rdivmod__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rpow__(lhs: impl FromPyObject, rhs: impl FromPyObject, modulo: Option<impl FromPyObject>) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rlshift__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rrshift__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rand__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __ror__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
* `fn __rxor__(lhs: impl FromPyObject, rhs: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
|
||||
The code generated for these methods expect that all arguments match the
|
||||
signature, or raise a TypeError.
|
||||
|
||||
* `fn __iadd__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __isub__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __imul__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __imatmul__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __itruediv__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __ifloordiv__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __imod__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __ipow__(&'p mut self, other: impl FromPyObject, modulo: impl FromPyObject) -> PyResult<()>` on Python 3.8^
|
||||
* `fn __ipow__(&'p mut self, other: impl FromPyObject) -> PyResult<()>` on Python 3.7 see https://bugs.python.org/issue36379
|
||||
* `fn __ilshift__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __irshift__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __iand__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __ior__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
* `fn __ixor__(&'p mut self, other: impl FromPyObject) -> PyResult<()>`
|
||||
|
||||
|
||||
The following methods implement the unary arithmetic operations:
|
||||
|
||||
* `fn __neg__(&'p self) -> PyResult<impl ToPyObject>`
|
||||
* `fn __pos__(&'p self) -> PyResult<impl ToPyObject>`
|
||||
* `fn __abs__(&'p self) -> PyResult<impl ToPyObject>`
|
||||
* `fn __invert__(&'p self) -> PyResult<impl ToPyObject>`
|
||||
|
||||
Support for coercions:
|
||||
|
||||
* `fn __int__(&'p self) -> PyResult<impl ToPyObject>`
|
||||
* `fn __float__(&'p self) -> PyResult<impl ToPyObject>`
|
||||
* `fn __index__(&'p self) -> PyResult<impl ToPyObject>`
|
||||
|
||||
#### Emulating sequential containers (such as lists or tuples)
|
||||
|
||||
The [`PySequenceProtocol`] trait can be implemented to emulate
|
||||
[sequential container types](https://docs.python.org/3/reference/datamodel.html#emulating-container-types).
|
||||
|
||||
For a sequence, the keys are the integers _k_ for which _0 <= k < N_,
|
||||
where _N_ is the length of the sequence.
|
||||
|
||||
* `fn __len__(&self) -> PyResult<usize>`
|
||||
|
||||
Implements the built-in function `len()` for the sequence.
|
||||
|
||||
* `fn __getitem__(&self, idx: isize) -> PyResult<impl ToPyObject>`
|
||||
|
||||
Implements evaluation of the `self[idx]` element.
|
||||
If the `idx` value is outside the set of indexes for the sequence, `IndexError` should be raised.
|
||||
|
||||
*Note:* Negative integer indexes are handled as follows: if `__len__()` is defined,
|
||||
it is called and the sequence length is used to compute a positive index,
|
||||
which is passed to `__getitem__()`.
|
||||
If `__len__()` is not defined, the index is passed as is to the function.
|
||||
|
||||
* `fn __setitem__(&mut self, idx: isize, value: impl FromPyObject) -> PyResult<()>`
|
||||
|
||||
Implements assignment to the `self[idx]` element. Same note as for `__getitem__()`.
|
||||
Should only be implemented if sequence elements can be replaced.
|
||||
|
||||
* `fn __delitem__(&mut self, idx: isize) -> PyResult<()>`
|
||||
|
||||
Implements deletion of the `self[idx]` element. Same note as for `__getitem__()`.
|
||||
Should only be implemented if sequence elements can be deleted.
|
||||
|
||||
* `fn __contains__(&self, item: impl FromPyObject) -> PyResult<bool>`
|
||||
|
||||
Implements membership test operators.
|
||||
Should return true if `item` is in `self`, false otherwise.
|
||||
For objects that don’t define `__contains__()`, the membership test simply
|
||||
traverses the sequence until it finds a match.
|
||||
|
||||
* `fn __concat__(&self, other: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
|
||||
Concatenates two sequences.
|
||||
Used by the `+` operator, after trying the numeric addition via
|
||||
the `PyNumberProtocol` trait method.
|
||||
|
||||
* `fn __repeat__(&self, count: isize) -> PyResult<impl ToPyObject>`
|
||||
|
||||
Repeats the sequence `count` times.
|
||||
Used by the `*` operator, after trying the numeric multiplication via
|
||||
the `PyNumberProtocol` trait method.
|
||||
|
||||
* `fn __inplace_concat__(&mut self, other: impl FromPyObject) -> PyResult<Self>`
|
||||
|
||||
Concatenates two sequences in place. Returns the modified first operand.
|
||||
Used by the `+=` operator, after trying the numeric in place addition via
|
||||
the `PyNumberProtocol` trait method.
|
||||
|
||||
* `fn __inplace_repeat__(&mut self, count: isize) -> PyResult<Self>`
|
||||
|
||||
Repeats the sequence `count` times in place. Returns the modified first operand.
|
||||
Used by the `*=` operator, after trying the numeric in place multiplication via
|
||||
the `PyNumberProtocol` trait method.
|
||||
|
||||
#### Emulating mapping containers (such as dictionaries)
|
||||
|
||||
The [`PyMappingProtocol`] trait allows to emulate
|
||||
[mapping container types](https://docs.python.org/3/reference/datamodel.html#emulating-container-types).
|
||||
|
||||
For a mapping, the keys may be Python objects of arbitrary type.
|
||||
|
||||
* `fn __len__(&self) -> PyResult<usize>`
|
||||
|
||||
Implements the built-in function `len()` for the mapping.
|
||||
|
||||
* `fn __getitem__(&self, key: impl FromPyObject) -> PyResult<impl ToPyObject>`
|
||||
|
||||
Implements evaluation of the `self[key]` element.
|
||||
If `key` is of an inappropriate type, `TypeError` may be raised;
|
||||
if `key` is missing (not in the container), `KeyError` should be raised.
|
||||
|
||||
* `fn __setitem__(&mut self, key: impl FromPyObject, value: impl FromPyObject) -> PyResult<()>`
|
||||
|
||||
Implements assignment to the `self[key]` element or insertion of a new `key`
|
||||
mapping to `value`.
|
||||
Should only be implemented if the mapping support changes to the values for keys,
|
||||
or if new keys can be added.
|
||||
The same exceptions should be raised for improper key values as
|
||||
for the `__getitem__()` method.
|
||||
|
||||
* `fn __delitem__(&mut self, key: impl FromPyObject) -> PyResult<()>`
|
||||
|
||||
Implements deletion of the `self[key]` element.
|
||||
Should only be implemented if the mapping supports removal of keys.
|
||||
The same exceptions should be raised for improper key values as
|
||||
for the `__getitem__()` method.
|
||||
|
||||
#### Iterator Types
|
||||
|
||||
Iterators can be defined using the [`PyIterProtocol`] trait.
|
||||
It includes two methods `__iter__` and `__next__`:
|
||||
* `fn __iter__(slf: PyRefMut<'_, Self>) -> PyResult<impl IntoPy<PyObject>>`
|
||||
* `fn __next__(slf: PyRefMut<'_, Self>) -> PyResult<Option<impl IntoPy<PyObject>>>`
|
||||
|
||||
These two methods can be take either `PyRef<'_, Self>` or `PyRefMut<'_, Self>` as their
|
||||
first argument, so that mutable borrow can be avoided if needed.
|
||||
|
||||
For details, look at the `#[pymethods]` regarding iterator methods.
|
||||
|
||||
#### Garbage Collector Integration
|
||||
|
||||
Implement the [`PyGCProtocol`] trait for your struct.
|
||||
For details, look at the `#[pymethods]` regarding GC methods.
|
||||
|
||||
[`PyGCProtocol`]: {{#PYO3_DOCS_URL}}/pyo3/class/gc/trait.PyGCProtocol.html
|
||||
[`PyMappingProtocol`]: {{#PYO3_DOCS_URL}}/pyo3/class/mapping/trait.PyMappingProtocol.html
|
||||
[`PyNumberProtocol`]: {{#PYO3_DOCS_URL}}/pyo3/class/number/trait.PyNumberProtocol.html
|
||||
[`PyObjectProtocol`]: {{#PYO3_DOCS_URL}}/pyo3/class/basic/trait.PyObjectProtocol.html
|
||||
[`PySequenceProtocol`]: {{#PYO3_DOCS_URL}}/pyo3/class/sequence/trait.PySequenceProtocol.html
|
||||
[`PyIterProtocol`]: {{#PYO3_DOCS_URL}}/pyo3/class/iter/trait.PyIterProtocol.html
|
||||
[`PySequence`]: {{#PYO3_DOCS_URL}}/pyo3/types/struct.PySequence.html
|
||||
[`CompareOp::matches`]: {{#PYO3_DOCS_URL}}/pyo3/pyclass/enum.CompareOp.html#method.matches
|
||||
|
|
|
@ -75,10 +75,6 @@ Most users should only need a single `#[pymethods]` per `#[pyclass]`. In additio
|
|||
|
||||
See [the `#[pyclass]` implementation details](class.md#implementation-details) for more information.
|
||||
|
||||
### `pyproto`
|
||||
|
||||
This feature enables the `#[pyproto]` macro, which is a deprecated alternative to `#[pymethods]` for defining magic methods such as `__eq__`.
|
||||
|
||||
### `nightly`
|
||||
|
||||
The `nightly` feature needs the nightly Rust compiler. This allows PyO3 to use the auto_traits and negative_impls features to fix the `Python::allow_threads` function.
|
||||
|
|
|
@ -23,5 +23,4 @@ default-features = false
|
|||
features = ["derive", "parsing", "printing", "clone-impls", "full", "extra-traits"]
|
||||
|
||||
[features]
|
||||
pyproto = []
|
||||
abi3 = []
|
||||
|
|
|
@ -1,543 +0,0 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
use crate::proto_method::MethodProto;
|
||||
use proc_macro2::Span;
|
||||
use std::collections::HashSet;
|
||||
|
||||
/// Predicates for `#[pyproto]`.
|
||||
pub struct Proto {
|
||||
/// The name of this protocol. E.g., Iter.
|
||||
pub name: &'static str,
|
||||
/// The path to the module which contains this proto implementation.
|
||||
module: &'static str,
|
||||
/// Trait which stores the slots
|
||||
/// Trait method which accesses the slots.
|
||||
/// All methods.
|
||||
pub methods: &'static [MethodProto],
|
||||
/// All methods registered as normal methods like `#[pymethods]`.
|
||||
pub py_methods: &'static [PyMethod],
|
||||
/// All methods registered to the slot table.
|
||||
slot_defs: &'static [SlotDef],
|
||||
}
|
||||
|
||||
impl Proto {
|
||||
pub(crate) fn get_proto<Q>(&self, query: Q) -> Option<&'static MethodProto>
|
||||
where
|
||||
Q: PartialEq<&'static str>,
|
||||
{
|
||||
self.methods.iter().find(|m| query == m.name)
|
||||
}
|
||||
|
||||
pub(crate) fn get_method<Q>(&self, query: Q) -> Option<&'static PyMethod>
|
||||
where
|
||||
Q: PartialEq<&'static str>,
|
||||
{
|
||||
self.py_methods.iter().find(|m| query == m.name)
|
||||
}
|
||||
|
||||
// Returns the hard-coded module as a path
|
||||
#[inline]
|
||||
pub(crate) fn module(&self) -> syn::Path {
|
||||
syn::parse_str(self.module).expect("module def not valid path")
|
||||
}
|
||||
|
||||
// Since the order matters, we expose only the iterator instead of the slice.
|
||||
pub(crate) fn slot_defs(
|
||||
&self,
|
||||
mut implemented_protocols: HashSet<String>,
|
||||
) -> impl Iterator<Item = &'static SlotDef> {
|
||||
self.slot_defs.iter().filter(move |slot_def| {
|
||||
// If any required method is not implemented, we skip this def.
|
||||
let all_methods_implemented = slot_def
|
||||
.proto_names
|
||||
.iter()
|
||||
.all(|name| implemented_protocols.contains(*name));
|
||||
|
||||
if all_methods_implemented {
|
||||
// To use 'paired' def in priority, we remove used protocols.
|
||||
// For example, if add_radd is already used, we shouldn't use add and radd.
|
||||
for name in slot_def.proto_names {
|
||||
implemented_protocols.remove(*name);
|
||||
}
|
||||
}
|
||||
|
||||
all_methods_implemented
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn items_trait(&self) -> syn::Ident {
|
||||
syn::Ident::new(&format!("Py{}ProtocolItems", self.name), Span::call_site())
|
||||
}
|
||||
|
||||
pub(crate) fn items_trait_items(&self) -> syn::Ident {
|
||||
syn::Ident::new(
|
||||
&format!("{}_protocol_items", self.name.to_ascii_lowercase()),
|
||||
Span::call_site(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a method registered as a normal method like `#[pymethods]`.
|
||||
// TODO(kngwyu): Currently only __radd__-like methods use METH_COEXIST to prevent
|
||||
// __add__-like methods from overriding them.
|
||||
pub struct PyMethod {
|
||||
pub name: &'static str,
|
||||
pub proto: &'static str,
|
||||
pub can_coexist: bool,
|
||||
}
|
||||
|
||||
impl PyMethod {
|
||||
const fn coexist(name: &'static str, proto: &'static str) -> Self {
|
||||
PyMethod {
|
||||
name,
|
||||
proto,
|
||||
can_coexist: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a slot definition.
|
||||
pub struct SlotDef {
|
||||
/// Protocols necessary to meet this def.
|
||||
/// E.g., we need `__setattr__` and `__delattr__` for invoking `set_setdelitem`.
|
||||
pub proto_names: &'static [&'static str],
|
||||
/// The Python slot name.
|
||||
pub slot: &'static str,
|
||||
/// The name of the function in pyo3 which implements the slot.
|
||||
pub slot_impl: &'static str,
|
||||
}
|
||||
|
||||
impl SlotDef {
|
||||
const fn new(
|
||||
proto_names: &'static [&'static str],
|
||||
slot: &'static str,
|
||||
slot_impl: &'static str,
|
||||
) -> Self {
|
||||
SlotDef {
|
||||
proto_names,
|
||||
slot,
|
||||
slot_impl,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const OBJECT: Proto = Proto {
|
||||
name: "Object",
|
||||
module: "::pyo3::class::basic",
|
||||
methods: &[
|
||||
MethodProto::new("__getattr__", "PyObjectGetAttrProtocol")
|
||||
.args(&["Name"])
|
||||
.has_self(),
|
||||
MethodProto::new("__setattr__", "PyObjectSetAttrProtocol")
|
||||
.args(&["Name", "Value"])
|
||||
.has_self(),
|
||||
MethodProto::new("__delattr__", "PyObjectDelAttrProtocol")
|
||||
.args(&["Name"])
|
||||
.has_self(),
|
||||
MethodProto::new("__str__", "PyObjectStrProtocol").has_self(),
|
||||
MethodProto::new("__repr__", "PyObjectReprProtocol").has_self(),
|
||||
MethodProto::new("__hash__", "PyObjectHashProtocol").has_self(),
|
||||
MethodProto::new("__richcmp__", "PyObjectRichcmpProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__bool__", "PyObjectBoolProtocol").has_self(),
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_defs: &[
|
||||
SlotDef::new(&["__str__"], "Py_tp_str", "str"),
|
||||
SlotDef::new(&["__repr__"], "Py_tp_repr", "repr"),
|
||||
SlotDef::new(&["__hash__"], "Py_tp_hash", "hash"),
|
||||
SlotDef::new(&["__getattr__"], "Py_tp_getattro", "getattr"),
|
||||
SlotDef::new(&["__richcmp__"], "Py_tp_richcompare", "richcmp"),
|
||||
SlotDef::new(
|
||||
&["__setattr__", "__delattr__"],
|
||||
"Py_tp_setattro",
|
||||
"setdelattr",
|
||||
),
|
||||
SlotDef::new(&["__setattr__"], "Py_tp_setattro", "setattr"),
|
||||
SlotDef::new(&["__delattr__"], "Py_tp_setattro", "delattr"),
|
||||
SlotDef::new(&["__bool__"], "Py_nb_bool", "bool"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const ASYNC: Proto = Proto {
|
||||
name: "Async",
|
||||
module: "::pyo3::class::pyasync",
|
||||
methods: &[
|
||||
MethodProto::new("__await__", "PyAsyncAwaitProtocol").args(&["Receiver"]),
|
||||
MethodProto::new("__aiter__", "PyAsyncAiterProtocol").args(&["Receiver"]),
|
||||
MethodProto::new("__anext__", "PyAsyncAnextProtocol").args(&["Receiver"]),
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_defs: &[
|
||||
SlotDef::new(&["__await__"], "Py_am_await", "await_"),
|
||||
SlotDef::new(&["__aiter__"], "Py_am_aiter", "aiter"),
|
||||
SlotDef::new(&["__anext__"], "Py_am_anext", "anext"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const BUFFER: Proto = Proto {
|
||||
name: "Buffer",
|
||||
module: "::pyo3::class::buffer",
|
||||
methods: &[
|
||||
MethodProto::new("bf_getbuffer", "PyBufferGetBufferProtocol").has_self(),
|
||||
MethodProto::new("bf_releasebuffer", "PyBufferReleaseBufferProtocol").has_self(),
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_defs: &[
|
||||
SlotDef::new(&["bf_getbuffer"], "Py_bf_getbuffer", "getbuffer"),
|
||||
SlotDef::new(
|
||||
&["bf_releasebuffer"],
|
||||
"Py_bf_releasebuffer",
|
||||
"releasebuffer",
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
pub const GC: Proto = Proto {
|
||||
name: "GC",
|
||||
module: "::pyo3::class::gc",
|
||||
methods: &[
|
||||
MethodProto::new("__traverse__", "PyGCTraverseProtocol")
|
||||
.has_self()
|
||||
.no_result(),
|
||||
MethodProto::new("__clear__", "PyGCClearProtocol")
|
||||
.has_self()
|
||||
.no_result(),
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_defs: &[
|
||||
SlotDef::new(&["__traverse__"], "Py_tp_traverse", "traverse"),
|
||||
SlotDef::new(&["__clear__"], "Py_tp_clear", "clear"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const DESCR: Proto = Proto {
|
||||
name: "Descr",
|
||||
module: "::pyo3::class::descr",
|
||||
methods: &[
|
||||
MethodProto::new("__get__", "PyDescrGetProtocol").args(&["Receiver", "Inst", "Owner"]),
|
||||
MethodProto::new("__set__", "PyDescrSetProtocol").args(&["Receiver", "Inst", "Value"]),
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_defs: &[
|
||||
SlotDef::new(&["__get__"], "Py_tp_descr_get", "descr_get"),
|
||||
SlotDef::new(&["__set__"], "Py_tp_descr_set", "descr_set"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const ITER: Proto = Proto {
|
||||
name: "Iter",
|
||||
module: "::pyo3::class::iter",
|
||||
py_methods: &[],
|
||||
methods: &[
|
||||
MethodProto::new("__iter__", "PyIterIterProtocol").args(&["Receiver"]),
|
||||
MethodProto::new("__next__", "PyIterNextProtocol").args(&["Receiver"]),
|
||||
],
|
||||
slot_defs: &[
|
||||
SlotDef::new(&["__iter__"], "Py_tp_iter", "iter"),
|
||||
SlotDef::new(&["__next__"], "Py_tp_iternext", "iternext"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const MAPPING: Proto = Proto {
|
||||
name: "Mapping",
|
||||
module: "::pyo3::class::mapping",
|
||||
methods: &[
|
||||
MethodProto::new("__len__", "PyMappingLenProtocol").has_self(),
|
||||
MethodProto::new("__getitem__", "PyMappingGetItemProtocol")
|
||||
.args(&["Key"])
|
||||
.has_self(),
|
||||
MethodProto::new("__setitem__", "PyMappingSetItemProtocol")
|
||||
.args(&["Key", "Value"])
|
||||
.has_self(),
|
||||
MethodProto::new("__delitem__", "PyMappingDelItemProtocol")
|
||||
.args(&["Key"])
|
||||
.has_self(),
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_defs: &[
|
||||
SlotDef::new(&["__len__"], "Py_mp_length", "len"),
|
||||
SlotDef::new(&["__getitem__"], "Py_mp_subscript", "getitem"),
|
||||
SlotDef::new(
|
||||
&["__setitem__", "__delitem__"],
|
||||
"Py_mp_ass_subscript",
|
||||
"setdelitem",
|
||||
),
|
||||
SlotDef::new(&["__setitem__"], "Py_mp_ass_subscript", "setitem"),
|
||||
SlotDef::new(&["__delitem__"], "Py_mp_ass_subscript", "delitem"),
|
||||
],
|
||||
};
|
||||
|
||||
pub const SEQ: Proto = Proto {
|
||||
name: "Sequence",
|
||||
module: "::pyo3::class::sequence",
|
||||
methods: &[
|
||||
MethodProto::new("__len__", "PySequenceLenProtocol").has_self(),
|
||||
MethodProto::new("__getitem__", "PySequenceGetItemProtocol")
|
||||
.args(&["Index"])
|
||||
.has_self(),
|
||||
MethodProto::new("__setitem__", "PySequenceSetItemProtocol")
|
||||
.args(&["Index", "Value"])
|
||||
.has_self(),
|
||||
MethodProto::new("__delitem__", "PySequenceDelItemProtocol")
|
||||
.args(&["Index"])
|
||||
.has_self(),
|
||||
MethodProto::new("__contains__", "PySequenceContainsProtocol")
|
||||
.args(&["Item"])
|
||||
.has_self(),
|
||||
MethodProto::new("__concat__", "PySequenceConcatProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__repeat__", "PySequenceRepeatProtocol")
|
||||
.args(&["Index"])
|
||||
.has_self(),
|
||||
MethodProto::new("__inplace_concat__", "PySequenceInplaceConcatProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__inplace_repeat__", "PySequenceInplaceRepeatProtocol")
|
||||
.args(&["Index"])
|
||||
.has_self(),
|
||||
],
|
||||
py_methods: &[],
|
||||
slot_defs: &[
|
||||
SlotDef::new(&["__len__"], "Py_sq_length", "len"),
|
||||
SlotDef::new(&["__concat__"], "Py_sq_concat", "concat"),
|
||||
SlotDef::new(&["__repeat__"], "Py_sq_repeat", "repeat"),
|
||||
SlotDef::new(&["__getitem__"], "Py_sq_item", "getitem"),
|
||||
SlotDef::new(
|
||||
&["__setitem__", "__delitem__"],
|
||||
"Py_sq_ass_item",
|
||||
"setdelitem",
|
||||
),
|
||||
SlotDef::new(&["__setitem__"], "Py_sq_ass_item", "setitem"),
|
||||
SlotDef::new(&["__delitem__"], "Py_sq_ass_item", "delitem"),
|
||||
SlotDef::new(&["__contains__"], "Py_sq_contains", "contains"),
|
||||
SlotDef::new(
|
||||
&["__inplace_concat__"],
|
||||
"Py_sq_inplace_concat",
|
||||
"inplace_concat",
|
||||
),
|
||||
SlotDef::new(
|
||||
&["__inplace_repeat__"],
|
||||
"Py_sq_inplace_repeat",
|
||||
"inplace_repeat",
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
pub const NUM: Proto = Proto {
|
||||
name: "Number",
|
||||
module: "::pyo3::class::number",
|
||||
methods: &[
|
||||
MethodProto::new("__add__", "PyNumberAddProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__sub__", "PyNumberSubProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__mul__", "PyNumberMulProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__matmul__", "PyNumberMatmulProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__truediv__", "PyNumberTruedivProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__floordiv__", "PyNumberFloordivProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__mod__", "PyNumberModProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__divmod__", "PyNumberDivmodProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__pow__", "PyNumberPowProtocol").args(&["Left", "Right", "Modulo"]),
|
||||
MethodProto::new("__lshift__", "PyNumberLShiftProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__rshift__", "PyNumberRShiftProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__and__", "PyNumberAndProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__xor__", "PyNumberXorProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__or__", "PyNumberOrProtocol").args(&["Left", "Right"]),
|
||||
MethodProto::new("__radd__", "PyNumberRAddProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rsub__", "PyNumberRSubProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rmul__", "PyNumberRMulProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rmatmul__", "PyNumberRMatmulProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rtruediv__", "PyNumberRTruedivProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rfloordiv__", "PyNumberRFloordivProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rmod__", "PyNumberRModProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rdivmod__", "PyNumberRDivmodProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rpow__", "PyNumberRPowProtocol")
|
||||
.args(&["Other", "Modulo"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rlshift__", "PyNumberRLShiftProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rrshift__", "PyNumberRRShiftProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rand__", "PyNumberRAndProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__rxor__", "PyNumberRXorProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__ror__", "PyNumberROrProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__iadd__", "PyNumberIAddProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__isub__", "PyNumberISubProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__imul__", "PyNumberIMulProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__imatmul__", "PyNumberIMatmulProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__itruediv__", "PyNumberITruedivProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__ifloordiv__", "PyNumberIFloordivProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__imod__", "PyNumberIModProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__ipow__", "PyNumberIPowProtocol")
|
||||
.args(&["Other", "Modulo"])
|
||||
.has_self(),
|
||||
MethodProto::new("__ilshift__", "PyNumberILShiftProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__irshift__", "PyNumberIRShiftProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__iand__", "PyNumberIAndProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__ixor__", "PyNumberIXorProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__ior__", "PyNumberIOrProtocol")
|
||||
.args(&["Other"])
|
||||
.has_self(),
|
||||
MethodProto::new("__neg__", "PyNumberNegProtocol").has_self(),
|
||||
MethodProto::new("__pos__", "PyNumberPosProtocol").has_self(),
|
||||
MethodProto::new("__abs__", "PyNumberAbsProtocol").has_self(),
|
||||
MethodProto::new("__invert__", "PyNumberInvertProtocol").has_self(),
|
||||
MethodProto::new("__int__", "PyNumberIntProtocol").has_self(),
|
||||
MethodProto::new("__float__", "PyNumberFloatProtocol").has_self(),
|
||||
MethodProto::new("__index__", "PyNumberIndexProtocol").has_self(),
|
||||
],
|
||||
py_methods: &[
|
||||
PyMethod::coexist("__radd__", "PyNumberRAddProtocolImpl"),
|
||||
PyMethod::coexist("__rsub__", "PyNumberRSubProtocolImpl"),
|
||||
PyMethod::coexist("__rmul__", "PyNumberRMulProtocolImpl"),
|
||||
PyMethod::coexist("__rmatmul__", "PyNumberRMatmulProtocolImpl"),
|
||||
PyMethod::coexist("__rtruediv__", "PyNumberRTruedivProtocolImpl"),
|
||||
PyMethod::coexist("__rfloordiv__", "PyNumberRFloordivProtocolImpl"),
|
||||
PyMethod::coexist("__rmod__", "PyNumberRModProtocolImpl"),
|
||||
PyMethod::coexist("__rdivmod__", "PyNumberRDivmodProtocolImpl"),
|
||||
PyMethod::coexist("__rpow__", "PyNumberRPowProtocolImpl"),
|
||||
PyMethod::coexist("__rlshift__", "PyNumberRLShiftProtocolImpl"),
|
||||
PyMethod::coexist("__rrshift__", "PyNumberRRShiftProtocolImpl"),
|
||||
PyMethod::coexist("__rand__", "PyNumberRAndProtocolImpl"),
|
||||
PyMethod::coexist("__rxor__", "PyNumberRXorProtocolImpl"),
|
||||
PyMethod::coexist("__ror__", "PyNumberROrProtocolImpl"),
|
||||
],
|
||||
slot_defs: &[
|
||||
SlotDef::new(&["__add__", "__radd__"], "Py_nb_add", "add_radd"),
|
||||
SlotDef::new(&["__add__"], "Py_nb_add", "add"),
|
||||
SlotDef::new(&["__radd__"], "Py_nb_add", "radd"),
|
||||
SlotDef::new(&["__sub__", "__rsub__"], "Py_nb_subtract", "sub_rsub"),
|
||||
SlotDef::new(&["__sub__"], "Py_nb_subtract", "sub"),
|
||||
SlotDef::new(&["__rsub__"], "Py_nb_subtract", "rsub"),
|
||||
SlotDef::new(&["__mul__", "__rmul__"], "Py_nb_multiply", "mul_rmul"),
|
||||
SlotDef::new(&["__mul__"], "Py_nb_multiply", "mul"),
|
||||
SlotDef::new(&["__rmul__"], "Py_nb_multiply", "rmul"),
|
||||
SlotDef::new(&["__mod__", "__rmod__"], "Py_nb_remainder", "mod_rmod"),
|
||||
SlotDef::new(&["__mod__"], "Py_nb_remainder", "mod_"),
|
||||
SlotDef::new(&["__rmod__"], "Py_nb_remainder", "rmod"),
|
||||
SlotDef::new(
|
||||
&["__divmod__", "__rdivmod__"],
|
||||
"Py_nb_divmod",
|
||||
"divmod_rdivmod",
|
||||
),
|
||||
SlotDef::new(&["__divmod__"], "Py_nb_divmod", "divmod"),
|
||||
SlotDef::new(&["__rdivmod__"], "Py_nb_divmod", "rdivmod"),
|
||||
SlotDef::new(&["__pow__", "__rpow__"], "Py_nb_power", "pow_rpow"),
|
||||
SlotDef::new(&["__pow__"], "Py_nb_power", "pow"),
|
||||
SlotDef::new(&["__rpow__"], "Py_nb_power", "rpow"),
|
||||
SlotDef::new(&["__neg__"], "Py_nb_negative", "neg"),
|
||||
SlotDef::new(&["__pos__"], "Py_nb_positive", "pos"),
|
||||
SlotDef::new(&["__abs__"], "Py_nb_absolute", "abs"),
|
||||
SlotDef::new(&["__invert__"], "Py_nb_invert", "invert"),
|
||||
SlotDef::new(
|
||||
&["__lshift__", "__rlshift__"],
|
||||
"Py_nb_lshift",
|
||||
"lshift_rlshift",
|
||||
),
|
||||
SlotDef::new(&["__lshift__"], "Py_nb_lshift", "lshift"),
|
||||
SlotDef::new(&["__rlshift__"], "Py_nb_lshift", "rlshift"),
|
||||
SlotDef::new(
|
||||
&["__rshift__", "__rrshift__"],
|
||||
"Py_nb_rshift",
|
||||
"rshift_rrshift",
|
||||
),
|
||||
SlotDef::new(&["__rshift__"], "Py_nb_rshift", "rshift"),
|
||||
SlotDef::new(&["__rrshift__"], "Py_nb_rshift", "rrshift"),
|
||||
SlotDef::new(&["__and__", "__rand__"], "Py_nb_and", "and_rand"),
|
||||
SlotDef::new(&["__and__"], "Py_nb_and", "and"),
|
||||
SlotDef::new(&["__rand__"], "Py_nb_and", "rand"),
|
||||
SlotDef::new(&["__xor__", "__rxor__"], "Py_nb_xor", "xor_rxor"),
|
||||
SlotDef::new(&["__xor__"], "Py_nb_xor", "xor"),
|
||||
SlotDef::new(&["__rxor__"], "Py_nb_xor", "rxor"),
|
||||
SlotDef::new(&["__or__", "__ror__"], "Py_nb_or", "or_ror"),
|
||||
SlotDef::new(&["__or__"], "Py_nb_or", "or"),
|
||||
SlotDef::new(&["__ror__"], "Py_nb_or", "ror"),
|
||||
SlotDef::new(&["__int__"], "Py_nb_int", "int"),
|
||||
SlotDef::new(&["__float__"], "Py_nb_float", "float"),
|
||||
SlotDef::new(&["__iadd__"], "Py_nb_inplace_add", "iadd"),
|
||||
SlotDef::new(&["__isub__"], "Py_nb_inplace_subtract", "isub"),
|
||||
SlotDef::new(&["__imul__"], "Py_nb_inplace_multiply", "imul"),
|
||||
SlotDef::new(&["__imod__"], "Py_nb_inplace_remainder", "imod"),
|
||||
SlotDef::new(&["__ipow__"], "Py_nb_inplace_power", "ipow"),
|
||||
SlotDef::new(&["__ilshift__"], "Py_nb_inplace_lshift", "ilshift"),
|
||||
SlotDef::new(&["__irshift__"], "Py_nb_inplace_rshift", "irshift"),
|
||||
SlotDef::new(&["__iand__"], "Py_nb_inplace_and", "iand"),
|
||||
SlotDef::new(&["__ixor__"], "Py_nb_inplace_xor", "ixor"),
|
||||
SlotDef::new(&["__ior__"], "Py_nb_inplace_or", "ior"),
|
||||
SlotDef::new(
|
||||
&["__floordiv__", "__rfloordiv__"],
|
||||
"Py_nb_floor_divide",
|
||||
"floordiv_rfloordiv",
|
||||
),
|
||||
SlotDef::new(&["__floordiv__"], "Py_nb_floor_divide", "floordiv"),
|
||||
SlotDef::new(&["__rfloordiv__"], "Py_nb_floor_divide", "rfloordiv"),
|
||||
SlotDef::new(
|
||||
&["__truediv__", "__rtruediv__"],
|
||||
"Py_nb_true_divide",
|
||||
"truediv_rtruediv",
|
||||
),
|
||||
SlotDef::new(&["__truediv__"], "Py_nb_true_divide", "truediv"),
|
||||
SlotDef::new(&["__rtruediv__"], "Py_nb_true_divide", "rtruediv"),
|
||||
SlotDef::new(
|
||||
&["__ifloordiv__"],
|
||||
"Py_nb_inplace_floor_divide",
|
||||
"ifloordiv",
|
||||
),
|
||||
SlotDef::new(&["__itruediv__"], "Py_nb_inplace_true_divide", "itruediv"),
|
||||
SlotDef::new(&["__index__"], "Py_nb_index", "index"),
|
||||
SlotDef::new(
|
||||
&["__matmul__", "__rmatmul__"],
|
||||
"Py_nb_matrix_multiply",
|
||||
"matmul_rmatmul",
|
||||
),
|
||||
SlotDef::new(&["__matmul__"], "Py_nb_matrix_multiply", "matmul"),
|
||||
SlotDef::new(&["__rmatmul__"], "Py_nb_matrix_multiply", "rmatmul"),
|
||||
SlotDef::new(&["__imatmul__"], "Py_nb_inplace_matrix_multiply", "imatmul"),
|
||||
],
|
||||
};
|
|
@ -10,28 +10,20 @@
|
|||
mod utils;
|
||||
|
||||
mod attributes;
|
||||
#[cfg(feature = "pyproto")]
|
||||
mod defs;
|
||||
mod deprecations;
|
||||
mod frompyobject;
|
||||
mod konst;
|
||||
mod method;
|
||||
mod module;
|
||||
mod params;
|
||||
#[cfg(feature = "pyproto")]
|
||||
mod proto_method;
|
||||
mod pyclass;
|
||||
mod pyfunction;
|
||||
mod pyimpl;
|
||||
mod pymethod;
|
||||
#[cfg(feature = "pyproto")]
|
||||
mod pyproto;
|
||||
|
||||
pub use frompyobject::build_derive_from_pyobject;
|
||||
pub use module::{process_functions_in_module, pymodule_impl, PyModuleOptions};
|
||||
pub use pyclass::{build_py_class, build_py_enum, PyClassArgs};
|
||||
pub use pyfunction::{build_py_function, PyFunctionOptions};
|
||||
pub use pyimpl::{build_py_methods, PyClassMethodsType};
|
||||
#[cfg(feature = "pyproto")]
|
||||
pub use pyproto::build_py_proto;
|
||||
pub use utils::get_doc;
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{spanned::Spanned, Token};
|
||||
|
||||
// TODO:
|
||||
// Add lifetime support for args with Rptr
|
||||
#[derive(Debug)]
|
||||
pub struct MethodProto {
|
||||
pub name: &'static str,
|
||||
pub args: &'static [&'static str],
|
||||
pub proto: &'static str,
|
||||
pub with_self: bool,
|
||||
pub with_result: bool,
|
||||
}
|
||||
|
||||
impl MethodProto {
|
||||
pub const fn new(name: &'static str, proto: &'static str) -> Self {
|
||||
MethodProto {
|
||||
name,
|
||||
proto,
|
||||
args: &[],
|
||||
with_self: false,
|
||||
with_result: true,
|
||||
}
|
||||
}
|
||||
pub const fn args(mut self, args: &'static [&'static str]) -> MethodProto {
|
||||
self.args = args;
|
||||
self
|
||||
}
|
||||
pub const fn has_self(mut self) -> MethodProto {
|
||||
self.with_self = true;
|
||||
self
|
||||
}
|
||||
pub const fn no_result(mut self) -> MethodProto {
|
||||
self.with_result = false;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn impl_method_proto(
|
||||
cls: &syn::Type,
|
||||
sig: &mut syn::Signature,
|
||||
module: &syn::Path,
|
||||
meth: &MethodProto,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let proto: syn::Path = syn::parse_str(meth.proto).unwrap();
|
||||
|
||||
let mut impl_types = Vec::new();
|
||||
for (i, arg) in meth.args.iter().enumerate() {
|
||||
let idx = if meth.with_self { i + 1 } else { i };
|
||||
let arg_name = syn::Ident::new(arg, Span::call_site());
|
||||
let input = match &mut sig.inputs[idx] {
|
||||
syn::FnArg::Typed(input) => input,
|
||||
receiver @ syn::FnArg::Receiver(_) => {
|
||||
bail_spanned!(receiver.span() => "unexpected receiver in #[pyproto]")
|
||||
}
|
||||
};
|
||||
// replace signature in trait with the parametrised one, which is identical to the declared
|
||||
// function signature.
|
||||
let decl = syn::parse_quote! { <#cls as #module::#proto<'p>>::#arg_name };
|
||||
let mut arg_ty = match crate::utils::option_type_argument(&input.ty) {
|
||||
Some(arg_ty) => {
|
||||
let arg_ty = arg_ty.clone();
|
||||
*input.ty = syn::parse_quote! { Option<#decl> };
|
||||
arg_ty
|
||||
}
|
||||
None => std::mem::replace(&mut *input.ty, decl),
|
||||
};
|
||||
// ensure the type has all lifetimes so it can be used in the protocol trait associated type
|
||||
insert_lifetime(&mut arg_ty);
|
||||
impl_types.push(quote! {type #arg_name = #arg_ty;});
|
||||
}
|
||||
|
||||
if meth.with_self {
|
||||
modify_self_ty(sig);
|
||||
}
|
||||
|
||||
let res_type_def = if meth.with_result {
|
||||
let ret_ty = match &sig.output {
|
||||
syn::ReturnType::Default => quote! { () },
|
||||
syn::ReturnType::Type(_, ty) => {
|
||||
let mut ty = ty.clone();
|
||||
insert_lifetime(&mut ty);
|
||||
ty.to_token_stream()
|
||||
}
|
||||
};
|
||||
|
||||
sig.output = syn::parse_quote! { -> <#cls as #module::#proto<'p>>::Result };
|
||||
quote! { type Result = #ret_ty; }
|
||||
} else {
|
||||
proc_macro2::TokenStream::new()
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
impl<'p> #module::#proto<'p> for #cls {
|
||||
#(#impl_types)*
|
||||
#res_type_def
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Insert lifetime `'p` to `PyRef<Self>` or references (e.g., `&PyType`).
|
||||
fn insert_lifetime(ty: &mut syn::Type) {
|
||||
fn insert_lifetime_for_path(path: &mut syn::TypePath) {
|
||||
if let Some(seg) = path.path.segments.last_mut() {
|
||||
if let syn::PathArguments::AngleBracketed(ref mut args) = seg.arguments {
|
||||
let mut has_lifetime = false;
|
||||
for arg in &mut args.args {
|
||||
match arg {
|
||||
// Insert `'p` recursively for `Option<PyRef<Self>>` or so.
|
||||
syn::GenericArgument::Type(ref mut ty) => insert_lifetime(ty),
|
||||
syn::GenericArgument::Lifetime(_) => has_lifetime = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
// Insert lifetime to PyRef (i.e., PyRef<Self> -> PyRef<'p, Self>)
|
||||
if !has_lifetime && (seg.ident == "PyRef" || seg.ident == "PyRefMut") {
|
||||
args.args.insert(0, syn::parse_quote! {'p});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match ty {
|
||||
syn::Type::Reference(ref mut r) => {
|
||||
r.lifetime.get_or_insert(syn::parse_quote! {'p});
|
||||
insert_lifetime(&mut r.elem);
|
||||
}
|
||||
syn::Type::Path(ref mut path) => insert_lifetime_for_path(path),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn modify_self_ty(sig: &mut syn::Signature) {
|
||||
match sig.inputs[0] {
|
||||
syn::FnArg::Receiver(ref mut slf) => {
|
||||
slf.reference = Some((Token![&](Span::call_site()), syn::parse_quote! {'p}));
|
||||
}
|
||||
syn::FnArg::Typed(_) => {}
|
||||
}
|
||||
}
|
|
@ -914,22 +914,6 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
let pyproto_items = if cfg!(feature = "pyproto") {
|
||||
Some(quote! {
|
||||
collector.object_protocol_items(),
|
||||
collector.number_protocol_items(),
|
||||
collector.iter_protocol_items(),
|
||||
collector.gc_protocol_items(),
|
||||
collector.descr_protocol_items(),
|
||||
collector.mapping_protocol_items(),
|
||||
collector.sequence_protocol_items(),
|
||||
collector.async_protocol_items(),
|
||||
collector.buffer_protocol_items(),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let default_methods = self
|
||||
.default_methods
|
||||
.iter()
|
||||
|
@ -1002,11 +986,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
|||
methods: &[#(#default_method_defs),*],
|
||||
slots: &[#(#default_slot_defs),* #(#freelist_slots),*],
|
||||
};
|
||||
PyClassItemsIter::new(
|
||||
&INTRINSIC_ITEMS,
|
||||
#pymethods_items,
|
||||
#pyproto_items
|
||||
)
|
||||
PyClassItemsIter::new(&INTRINSIC_ITEMS, #pymethods_items)
|
||||
}
|
||||
|
||||
#dict_offset
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
use crate::defs;
|
||||
use crate::method::{FnSpec, FnType};
|
||||
use crate::proto_method::impl_method_proto;
|
||||
use crate::pyfunction::PyFunctionOptions;
|
||||
use crate::pymethod;
|
||||
use crate::pymethod::MethodAndMethodDef;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::quote;
|
||||
use quote::ToTokens;
|
||||
use std::collections::HashSet;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
pub fn build_py_proto(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
|
||||
let (path, proto) = if let Some((_, path, _)) = &mut ast.trait_ {
|
||||
let proto = match path.segments.last() {
|
||||
Some(segment) if segment.ident == "PyObjectProtocol" => &defs::OBJECT,
|
||||
Some(segment) if segment.ident == "PyAsyncProtocol" => &defs::ASYNC,
|
||||
Some(segment) if segment.ident == "PyMappingProtocol" => &defs::MAPPING,
|
||||
Some(segment) if segment.ident == "PyIterProtocol" => &defs::ITER,
|
||||
Some(segment) if segment.ident == "PySequenceProtocol" => &defs::SEQ,
|
||||
Some(segment) if segment.ident == "PyNumberProtocol" => &defs::NUM,
|
||||
Some(segment) if segment.ident == "PyDescrProtocol" => &defs::DESCR,
|
||||
Some(segment) if segment.ident == "PyBufferProtocol" => &defs::BUFFER,
|
||||
Some(segment) if segment.ident == "PyGCProtocol" => &defs::GC,
|
||||
_ => bail_spanned!(path.span() => "unrecognised trait for #[pyproto]"),
|
||||
};
|
||||
(path, proto)
|
||||
} else {
|
||||
bail_spanned!(
|
||||
ast.span() => "#[pyproto] can only be used with protocol trait implementations"
|
||||
);
|
||||
};
|
||||
|
||||
let tokens = impl_proto_impl(&ast.self_ty, &mut ast.items, proto)?;
|
||||
|
||||
// attach lifetime
|
||||
let mut seg = path.segments.pop().unwrap().into_value();
|
||||
seg.arguments = syn::PathArguments::AngleBracketed(syn::parse_quote! {<'p>});
|
||||
path.segments.push(seg);
|
||||
ast.generics.params = syn::parse_quote! {'p};
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
fn impl_proto_impl(
|
||||
ty: &syn::Type,
|
||||
impls: &mut [syn::ImplItem],
|
||||
proto: &defs::Proto,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let mut trait_impls = TokenStream::new();
|
||||
let mut associated_methods = Vec::new();
|
||||
let mut method_defs = Vec::new();
|
||||
let mut method_names = HashSet::new();
|
||||
let module = proto.module();
|
||||
|
||||
for iimpl in impls.iter_mut() {
|
||||
if let syn::ImplItem::Method(met) = iimpl {
|
||||
// impl Py~Protocol<'p> { type = ... }
|
||||
if let Some(m) = proto.get_proto(&met.sig.ident) {
|
||||
impl_method_proto(ty, &mut met.sig, &module, m)?.to_tokens(&mut trait_impls);
|
||||
// Insert the method to the HashSet
|
||||
method_names.insert(met.sig.ident.to_string());
|
||||
}
|
||||
// Add non-slot methods to inventory like `#[pymethods]`
|
||||
if let Some(m) = proto.get_method(&met.sig.ident) {
|
||||
let fn_spec =
|
||||
FnSpec::parse(&mut met.sig, &mut met.attrs, PyFunctionOptions::default())?;
|
||||
|
||||
let flags = if m.can_coexist {
|
||||
// We need METH_COEXIST here to prevent __add__ from overriding __radd__
|
||||
Some(quote!(_pyo3::ffi::METH_COEXIST))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let MethodAndMethodDef {
|
||||
associated_method,
|
||||
method_def,
|
||||
} = if let FnType::Fn(_) = &fn_spec.tp {
|
||||
pymethod::impl_py_method_def(ty, &fn_spec, flags)?
|
||||
} else {
|
||||
bail_spanned!(
|
||||
met.sig.span() => "expected method with receiver for #[pyproto] method"
|
||||
);
|
||||
};
|
||||
|
||||
associated_methods.push(associated_method);
|
||||
method_defs.push(method_def);
|
||||
}
|
||||
}
|
||||
}
|
||||
let items = impl_proto_items(method_names, method_defs, ty, proto);
|
||||
|
||||
Ok(quote! {
|
||||
const _: () = {
|
||||
use ::pyo3 as _pyo3; // pyproto doesn't support specifying #[pyo3(crate)]
|
||||
#trait_impls
|
||||
#items
|
||||
|
||||
#[doc(hidden)]
|
||||
#[allow(non_snake_case)]
|
||||
impl #ty {
|
||||
#(#associated_methods)*
|
||||
}
|
||||
};
|
||||
})
|
||||
}
|
||||
|
||||
fn impl_proto_items(
|
||||
method_names: HashSet<String>,
|
||||
py_methods: Vec<TokenStream>,
|
||||
ty: &syn::Type,
|
||||
proto: &defs::Proto,
|
||||
) -> TokenStream {
|
||||
if method_names.is_empty() && py_methods.is_empty() {
|
||||
return TokenStream::default();
|
||||
}
|
||||
|
||||
let module = proto.module();
|
||||
let items_trait = proto.items_trait();
|
||||
let items_trait_items = proto.items_trait_items();
|
||||
|
||||
let mut tokens = proto
|
||||
.slot_defs(method_names)
|
||||
.map(|def| {
|
||||
let slot = syn::Ident::new(def.slot, Span::call_site());
|
||||
let slot_impl = syn::Ident::new(def.slot_impl, Span::call_site());
|
||||
quote! {{
|
||||
_pyo3::ffi::PyType_Slot {
|
||||
slot: _pyo3::ffi::#slot,
|
||||
pfunc: #module::#slot_impl::<#ty> as _
|
||||
}
|
||||
}}
|
||||
})
|
||||
.peekable();
|
||||
|
||||
if tokens.peek().is_none() {
|
||||
return TokenStream::default();
|
||||
}
|
||||
|
||||
quote! {
|
||||
impl _pyo3::impl_::pyclass::#items_trait<#ty>
|
||||
for _pyo3::impl_::pyclass::PyClassImplCollector<#ty>
|
||||
{
|
||||
fn #items_trait_items(self) -> &'static _pyo3::impl_::pyclass::PyClassItems {
|
||||
static ITEMS: _pyo3::impl_::pyclass::PyClassItems = _pyo3::impl_::pyclass::PyClassItems {
|
||||
methods: &[#(#py_methods),*],
|
||||
slots: &[#(#tokens),*]
|
||||
};
|
||||
&ITEMS
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@ proc-macro = true
|
|||
[features]
|
||||
multiple-pymethods = []
|
||||
|
||||
pyproto = ["pyo3-macros-backend/pyproto"]
|
||||
abi3 = ["pyo3-macros-backend/abi3"]
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -56,29 +56,6 @@ pub fn pymodule(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||
.into()
|
||||
}
|
||||
|
||||
/// A proc macro used to implement Python's [dunder methods][1].
|
||||
///
|
||||
/// This attribute is required on blocks implementing [`PyObjectProtocol`][2],
|
||||
/// [`PyNumberProtocol`][3], [`PyGCProtocol`][4] and [`PyIterProtocol`][5].
|
||||
///
|
||||
/// [1]: https://docs.python.org/3/reference/datamodel.html#special-method-names
|
||||
/// [2]: ../class/basic/trait.PyObjectProtocol.html
|
||||
/// [3]: ../class/number/trait.PyNumberProtocol.html
|
||||
/// [4]: ../class/gc/trait.PyGCProtocol.html
|
||||
/// [5]: ../class/iter/trait.PyIterProtocol.html
|
||||
#[proc_macro_attribute]
|
||||
#[cfg(feature = "pyproto")]
|
||||
pub fn pyproto(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mut ast = parse_macro_input!(input as syn::ItemImpl);
|
||||
let expanded = pyo3_macros_backend::build_py_proto(&mut ast).unwrap_or_compile_error();
|
||||
|
||||
quote!(
|
||||
#ast
|
||||
#expanded
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn pyclass(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
use syn::Item;
|
||||
|
|
|
@ -1,178 +0,0 @@
|
|||
#![allow(deprecated)]
|
||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
//! Basic Python Object customization
|
||||
//!
|
||||
//! Check [the Python C API information](https://docs.python.org/3/reference/datamodel.html#basic-customization)
|
||||
//! for more information.
|
||||
//!
|
||||
//! Parts of the documentation are copied from the respective methods from the
|
||||
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
|
||||
|
||||
use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput};
|
||||
use crate::pyclass::boolean_struct::False;
|
||||
use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyObject};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Basic Python class customization
|
||||
#[allow(unused_variables)]
|
||||
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
|
||||
pub trait PyObjectProtocol<'p>: PyClass {
|
||||
fn __getattr__(&'p self, name: Self::Name) -> Self::Result
|
||||
where
|
||||
Self: PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __setattr__(&'p mut self, name: Self::Name, value: Self::Value) -> Self::Result
|
||||
where
|
||||
Self: PyObjectSetAttrProtocol<'p> + PyClass<Frozen = False>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __delattr__(&'p mut self, name: Self::Name) -> Self::Result
|
||||
where
|
||||
Self: PyObjectDelAttrProtocol<'p> + PyClass<Frozen = False>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __str__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyObjectStrProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __repr__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyObjectReprProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __hash__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyObjectHashProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __richcmp__(&'p self, other: Self::Other, op: CompareOp) -> Self::Result
|
||||
where
|
||||
Self: PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __bool__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyObjectBoolProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> {
|
||||
type Name: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Name: FromPyObject<'p>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Name: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
pub trait PyObjectStrProtocol<'p>: PyObjectProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
pub trait PyObjectReprProtocol<'p>: PyObjectProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
pub trait PyObjectHashProtocol<'p>: PyObjectProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<HashCallbackOutput>;
|
||||
}
|
||||
pub trait PyObjectBoolProtocol<'p>: PyObjectProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<bool>;
|
||||
}
|
||||
pub trait PyObjectRichcmpProtocol<'p>: PyObjectProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
py_unary_func!(str, PyObjectStrProtocol, T::__str__);
|
||||
py_unary_func!(repr, PyObjectReprProtocol, T::__repr__);
|
||||
py_unary_func!(hash, PyObjectHashProtocol, T::__hash__, ffi::Py_hash_t);
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn getattr<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
// Behave like python's __getattr__ (as opposed to __getattribute__) and check
|
||||
// for existing fields and methods first
|
||||
let existing = ffi::PyObject_GenericGetAttr(slf, arg);
|
||||
if existing.is_null() {
|
||||
// PyObject_HasAttr also tries to get an object and clears the error if it fails
|
||||
ffi::PyErr_Clear();
|
||||
} else {
|
||||
return Ok(existing);
|
||||
}
|
||||
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<PyAny>(arg);
|
||||
call_ref!(slf, __getattr__, arg).convert(py)
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn richcmp<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg: *mut ffi::PyObject,
|
||||
op: c_int,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
let arg = extract_or_return_not_implemented!(py, arg);
|
||||
let op = match op {
|
||||
ffi::Py_LT => CompareOp::Lt,
|
||||
ffi::Py_LE => CompareOp::Le,
|
||||
ffi::Py_EQ => CompareOp::Eq,
|
||||
ffi::Py_NE => CompareOp::Ne,
|
||||
ffi::Py_GT => CompareOp::Gt,
|
||||
ffi::Py_GE => CompareOp::Ge,
|
||||
_ => {
|
||||
return Err(exceptions::PyValueError::new_err(
|
||||
"tp_richcompare called with invalid comparison operator",
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
slf.try_borrow()?.__richcmp__(arg, op).convert(py)
|
||||
})
|
||||
}
|
||||
|
||||
py_func_set!(setattr, PyObjectSetAttrProtocol, T::__setattr__);
|
||||
py_func_del!(delattr, PyObjectDelAttrProtocol, T::__delattr__);
|
||||
py_func_set_del!(
|
||||
setdelattr,
|
||||
PyObjectSetAttrProtocol,
|
||||
PyObjectDelAttrProtocol,
|
||||
Self,
|
||||
__setattr__,
|
||||
__delattr__
|
||||
);
|
||||
py_unary_func!(bool, PyObjectBoolProtocol, T::__bool__, c_int);
|
||||
|
||||
pub use crate::pyclass::CompareOp;
|
|
@ -1,67 +0,0 @@
|
|||
#![allow(deprecated)]
|
||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
//! Represent Python Buffer protocol implementation
|
||||
//!
|
||||
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||
//! c-api
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::pyclass::boolean_struct::False;
|
||||
use crate::{ffi, PyCell, PyClass, PyRefMut};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Buffer protocol interface
|
||||
///
|
||||
/// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||
/// c-api.
|
||||
#[allow(unused_variables)]
|
||||
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
|
||||
pub trait PyBufferProtocol<'p>: PyClass<Frozen = False> {
|
||||
// No default implementations so that implementors of this trait provide both methods.
|
||||
|
||||
fn bf_getbuffer(
|
||||
slf: PyRefMut<'_, Self>,
|
||||
view: *mut ffi::Py_buffer,
|
||||
flags: c_int,
|
||||
) -> Self::Result
|
||||
where
|
||||
Self: PyBufferGetBufferProtocol<'p>;
|
||||
|
||||
fn bf_releasebuffer(slf: PyRefMut<'_, Self>, view: *mut ffi::Py_buffer) -> Self::Result
|
||||
where
|
||||
Self: PyBufferReleaseBufferProtocol<'p>;
|
||||
}
|
||||
|
||||
pub trait PyBufferGetBufferProtocol<'p>: PyBufferProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyBufferReleaseBufferProtocol<'p>: PyBufferProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn getbuffer<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
arg1: *mut ffi::Py_buffer,
|
||||
arg2: c_int,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).convert(py)
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn releasebuffer<T>(slf: *mut ffi::PyObject, arg1: *mut ffi::Py_buffer)
|
||||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).convert(py)
|
||||
})
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
#![allow(deprecated)]
|
||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
//! Python Description Interface
|
||||
//!
|
||||
//! [Python information](
|
||||
//! https://docs.python.org/3/reference/datamodel.html#implementing-descriptors)
|
||||
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::{FromPyObject, PyClass, PyObject};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Descriptor interface
|
||||
#[allow(unused_variables)]
|
||||
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
|
||||
pub trait PyDescrProtocol<'p>: PyClass {
|
||||
fn __get__(
|
||||
slf: Self::Receiver,
|
||||
instance: Self::Inst,
|
||||
owner: Option<Self::Owner>,
|
||||
) -> Self::Result
|
||||
where
|
||||
Self: PyDescrGetProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __set__(slf: Self::Receiver, instance: Self::Inst, value: Self::Value) -> Self::Result
|
||||
where
|
||||
Self: PyDescrSetProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PyDescrGetProtocol<'p>: PyDescrProtocol<'p> {
|
||||
type Receiver: crate::derive_utils::TryFromPyCell<'p, Self>;
|
||||
type Inst: FromPyObject<'p>;
|
||||
type Owner: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyDescrSetProtocol<'p>: PyDescrProtocol<'p> {
|
||||
type Receiver: crate::derive_utils::TryFromPyCell<'p, Self>;
|
||||
type Inst: FromPyObject<'p>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
py_ternarys_func!(descr_get, PyDescrGetProtocol, Self::__get__);
|
||||
py_ternarys_func!(descr_set, PyDescrSetProtocol, Self::__set__, c_int);
|
|
@ -1,62 +0,0 @@
|
|||
#![allow(deprecated)]
|
||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
//! Python GC support
|
||||
|
||||
use crate::pyclass::boolean_struct::False;
|
||||
use crate::{ffi, PyCell, PyClass};
|
||||
use std::os::raw::{c_int, c_void};
|
||||
|
||||
pub use crate::impl_::pymethods::{PyTraverseError, PyVisit};
|
||||
|
||||
/// GC support
|
||||
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
|
||||
pub trait PyGCProtocol<'p>: PyClass<Frozen = False> {
|
||||
fn __traverse__(&'p self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>;
|
||||
fn __clear__(&'p mut self);
|
||||
}
|
||||
|
||||
pub trait PyGCTraverseProtocol<'p>: PyGCProtocol<'p> {}
|
||||
|
||||
pub trait PyGCClearProtocol<'p>: PyGCProtocol<'p> {}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn traverse<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
visit: ffi::visitproc,
|
||||
arg: *mut c_void,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
let pool = crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
let visit = PyVisit {
|
||||
visit,
|
||||
arg,
|
||||
_py: py,
|
||||
};
|
||||
let borrow = slf.try_borrow();
|
||||
if let Ok(borrow) = borrow {
|
||||
match borrow.__traverse__(visit) {
|
||||
Ok(()) => 0,
|
||||
Err(PyTraverseError(code)) => code,
|
||||
}
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn clear<T>(slf: *mut ffi::PyObject) -> c_int
|
||||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
let pool = crate::GILPool::new();
|
||||
let slf = pool.python().from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
slf.borrow_mut().__clear__();
|
||||
0
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
#![allow(deprecated)]
|
||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
//! Python Iterator Interface.
|
||||
//! Trait and support implementation for implementing iterators
|
||||
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::derive_utils::TryFromPyCell;
|
||||
use crate::{PyClass, PyObject};
|
||||
|
||||
/// Python Iterator Interface.
|
||||
///
|
||||
/// Check [CPython doc](https://docs.python.org/3/c-api/typeobj.html#c.PyTypeObject.tp_iter)
|
||||
/// for more.
|
||||
///
|
||||
/// # Examples
|
||||
/// The following example shows how to implement a simple Python iterator in Rust which yields
|
||||
/// the integers 1 to 5, before raising `StopIteration("Ended")`.
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(deprecated, elided_lifetimes_in_paths)]
|
||||
/// use pyo3::class::iter::IterNextOutput;
|
||||
/// use pyo3::prelude::*;
|
||||
/// use pyo3::PyIterProtocol;
|
||||
///
|
||||
/// #[pyclass]
|
||||
/// struct Iter {
|
||||
/// count: usize,
|
||||
/// }
|
||||
///
|
||||
/// #[pyproto]
|
||||
/// impl PyIterProtocol for Iter {
|
||||
/// fn __next__(mut slf: PyRefMut<Self>) -> IterNextOutput<usize, &'static str> {
|
||||
/// if slf.count < 5 {
|
||||
/// slf.count += 1;
|
||||
/// IterNextOutput::Yield(slf.count)
|
||||
/// } else {
|
||||
/// IterNextOutput::Return("Ended")
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # Python::with_gil(|py| {
|
||||
/// # let inst = Py::new(py, Iter { count: 0 }).unwrap();
|
||||
/// # pyo3::py_run!(py, inst, "assert next(inst) == 1");
|
||||
/// # }); // test of StopIteration is done in pytests/src/pyclasses.rs
|
||||
/// ```
|
||||
#[allow(unused_variables)]
|
||||
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
|
||||
pub trait PyIterProtocol<'p>: PyClass {
|
||||
fn __iter__(slf: Self::Receiver) -> Self::Result
|
||||
where
|
||||
Self: PyIterIterProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __next__(slf: Self::Receiver) -> Self::Result
|
||||
where
|
||||
Self: PyIterNextProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PyIterIterProtocol<'p>: PyIterProtocol<'p> {
|
||||
type Receiver: TryFromPyCell<'p, Self>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyIterNextProtocol<'p>: PyIterProtocol<'p> {
|
||||
type Receiver: TryFromPyCell<'p, Self>;
|
||||
type Result: IntoPyCallbackOutput<PyIterNextOutput>;
|
||||
}
|
||||
|
||||
py_unarys_func!(iter, PyIterIterProtocol, Self::__iter__);
|
||||
py_unarys_func!(iternext, PyIterNextProtocol, Self::__next__);
|
||||
|
||||
pub use crate::pyclass::{IterNextOutput, PyIterNextOutput};
|
|
@ -1,369 +0,0 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
macro_rules! py_unary_func {
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident, $call:ident, $ret_type: ty) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(slf: *mut $crate::ffi::PyObject) -> $ret_type
|
||||
where
|
||||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
$call!(slf, $f).convert(py)
|
||||
})
|
||||
}
|
||||
};
|
||||
// Use call_ref! by default
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident, $ret_type:ty) => {
|
||||
py_unary_func!($name, $trait, $class::$f, call_ref, $ret_type);
|
||||
};
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
|
||||
py_unary_func!(
|
||||
$name,
|
||||
$trait,
|
||||
$class::$f,
|
||||
call_ref,
|
||||
*mut $crate::ffi::PyObject
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_unarys_func {
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
) -> *mut $crate::ffi::PyObject
|
||||
where
|
||||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let borrow =
|
||||
<T::Receiver as $crate::derive_utils::TryFromPyCell<_>>::try_from_pycell(slf)
|
||||
.map_err(|e| e.into())?;
|
||||
|
||||
T::$f(borrow).convert(py)
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_len_func {
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
|
||||
py_unary_func!($name, $trait, $class::$f, $crate::ffi::Py_ssize_t);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_binary_func {
|
||||
// Use call_ref! by default
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident, $return:ty, $call:ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
arg: *mut $crate::ffi::PyObject,
|
||||
) -> $return
|
||||
where
|
||||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg);
|
||||
$call!(slf, $f, arg).convert(py)
|
||||
})
|
||||
}
|
||||
};
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident, $return:ty) => {
|
||||
py_binary_func!($name, $trait, $class::$f, $return, call_ref);
|
||||
};
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
|
||||
py_binary_func!($name, $trait, $class::$f, *mut $crate::ffi::PyObject);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_binary_num_func {
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
lhs: *mut $crate::ffi::PyObject,
|
||||
rhs: *mut $crate::ffi::PyObject,
|
||||
) -> *mut $crate::ffi::PyObject
|
||||
where
|
||||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
|
||||
let rhs = extract_or_return_not_implemented!(py, rhs);
|
||||
T::$f(lhs.extract()?, rhs).convert(py)
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_binary_reversed_num_func {
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
lhs: *mut $crate::ffi::PyObject,
|
||||
rhs: *mut $crate::ffi::PyObject,
|
||||
) -> *mut $crate::ffi::PyObject
|
||||
where
|
||||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
// Swap lhs <-> rhs
|
||||
let slf: &$crate::PyCell<T> = extract_or_return_not_implemented!(py, rhs);
|
||||
let arg = extract_or_return_not_implemented!(py, lhs);
|
||||
T::$f(&*slf.try_borrow()?, arg).convert(py)
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_binary_fallback_num_func {
|
||||
($name:ident, $class:ident, $lop_trait: ident :: $lop: ident, $rop_trait: ident :: $rop: ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
lhs: *mut $crate::ffi::PyObject,
|
||||
rhs: *mut $crate::ffi::PyObject,
|
||||
) -> *mut $crate::ffi::PyObject
|
||||
where
|
||||
T: for<'p> $lop_trait<'p> + for<'p> $rop_trait<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
|
||||
let rhs = py.from_borrowed_ptr::<$crate::PyAny>(rhs);
|
||||
// First, try the left hand method (e.g., __add__)
|
||||
match (lhs.extract(), rhs.extract()) {
|
||||
(Ok(l), Ok(r)) => T::$lop(l, r).convert(py),
|
||||
_ => {
|
||||
// Next, try the right hand method (e.g., __radd__)
|
||||
let slf: &$crate::PyCell<T> = extract_or_return_not_implemented!(rhs);
|
||||
let arg = extract_or_return_not_implemented!(lhs);
|
||||
T::$rop(&*slf.try_borrow()?, arg).convert(py)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// NOTE(kngwyu): This macro is used only for inplace operations, so I used call_mut here.
|
||||
macro_rules! py_binary_self_func {
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
arg: *mut $crate::ffi::PyObject,
|
||||
) -> *mut $crate::ffi::PyObject
|
||||
where
|
||||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf_ = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg);
|
||||
call_operator_mut!(py, slf_, $f, arg).convert(py)?;
|
||||
$crate::ffi::Py_INCREF(slf);
|
||||
Ok::<_, $crate::err::PyErr>(slf)
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_ssizearg_func {
|
||||
// Use call_ref! by default
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
|
||||
py_ssizearg_func!($name, $trait, $class::$f, call_ref);
|
||||
};
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident, $call:ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
arg: $crate::ffi::Py_ssize_t,
|
||||
) -> *mut $crate::ffi::PyObject
|
||||
where
|
||||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
$call!(slf, $f; arg.into()).convert(py)
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_ternarys_func {
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident, $return_type:ty) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
arg1: *mut $crate::ffi::PyObject,
|
||||
arg2: *mut $crate::ffi::PyObject,
|
||||
) -> $return_type
|
||||
where
|
||||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let slf =
|
||||
<T::Receiver as $crate::derive_utils::TryFromPyCell<_>>::try_from_pycell(slf)
|
||||
.map_err(|e| e.into())?;
|
||||
let arg1 = py
|
||||
.from_borrowed_ptr::<$crate::types::PyAny>(arg1)
|
||||
.extract()?;
|
||||
let arg2 = py
|
||||
.from_borrowed_ptr::<$crate::types::PyAny>(arg2)
|
||||
.extract()?;
|
||||
|
||||
T::$f(slf, arg1, arg2).convert(py)
|
||||
})
|
||||
}
|
||||
};
|
||||
($name:ident, $trait:ident, $class:ident :: $f:ident) => {
|
||||
py_ternarys_func!($name, $trait, $class::$f, *mut $crate::ffi::PyObject);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_func_set {
|
||||
($name:ident, $trait_name:ident, $class:ident :: $fn_set:ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
name: *mut $crate::ffi::PyObject,
|
||||
value: *mut $crate::ffi::PyObject,
|
||||
) -> ::std::os::raw::c_int
|
||||
where
|
||||
T: for<'p> $trait_name<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
Err($crate::exceptions::PyNotImplementedError::new_err(format!(
|
||||
"Subscript deletion not supported by {:?}",
|
||||
stringify!($class)
|
||||
)))
|
||||
} else {
|
||||
let name = py.from_borrowed_ptr::<$crate::PyAny>(name);
|
||||
let value = py.from_borrowed_ptr::<$crate::PyAny>(value);
|
||||
call_mut!(slf, $fn_set, name, value).convert(py)
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_func_del {
|
||||
($name:ident, $trait_name:ident, $class:ident :: $fn_del:ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
name: *mut $crate::ffi::PyObject,
|
||||
value: *mut $crate::ffi::PyObject,
|
||||
) -> ::std::os::raw::c_int
|
||||
where
|
||||
T: for<'p> $trait_name<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
if value.is_null() {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let name = py
|
||||
.from_borrowed_ptr::<$crate::types::PyAny>(name)
|
||||
.extract()?;
|
||||
slf.try_borrow_mut()?.$fn_del(name).convert(py)
|
||||
} else {
|
||||
Err($crate::exceptions::PyNotImplementedError::new_err(
|
||||
"Subscript assignment not supported",
|
||||
))
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! py_func_set_del {
|
||||
($name:ident, $trait1:ident, $trait2:ident, $class:ident, $fn_set:ident, $fn_del:ident) => {
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn $name<T>(
|
||||
slf: *mut $crate::ffi::PyObject,
|
||||
name: *mut $crate::ffi::PyObject,
|
||||
value: *mut $crate::ffi::PyObject,
|
||||
) -> ::std::os::raw::c_int
|
||||
where
|
||||
T: for<'p> $trait1<'p> + for<'p> $trait2<'p>,
|
||||
{
|
||||
$crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let name = py.from_borrowed_ptr::<$crate::PyAny>(name);
|
||||
|
||||
if value.is_null() {
|
||||
call_mut!(slf, $fn_del, name).convert(py)
|
||||
} else {
|
||||
let value = py.from_borrowed_ptr::<$crate::PyAny>(value);
|
||||
call_mut!(slf, $fn_set, name, value).convert(py)
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! extract_or_return_not_implemented {
|
||||
($arg: ident) => {
|
||||
match $arg.extract() {
|
||||
Ok(value) => value,
|
||||
Err(_) => {
|
||||
let res = $crate::ffi::Py_NotImplemented();
|
||||
$crate::ffi::Py_INCREF(res);
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
};
|
||||
($py: ident, $arg: ident) => {
|
||||
match $py
|
||||
.from_borrowed_ptr::<$crate::types::PyAny>($arg)
|
||||
.extract()
|
||||
{
|
||||
Ok(value) => value,
|
||||
Err(_) => return $py.NotImplemented().convert($py),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! _call_impl {
|
||||
($slf: expr, $fn: ident $(; $args: expr)*) => {
|
||||
$slf.$fn($($args,)*)
|
||||
};
|
||||
($slf: expr, $fn: ident, $raw_arg: expr $(,$raw_args: expr)* $(; $args: expr)*) => {
|
||||
_call_impl!($slf, $fn $(,$raw_args)* $(;$args)* ;$raw_arg.extract()?)
|
||||
};
|
||||
(op $py:ident; $slf: expr, $fn: ident, $raw_arg: expr $(,$raw_args: expr)* $(; $args: expr)*) => {
|
||||
_call_impl!(
|
||||
$slf, $fn ;
|
||||
(match $raw_arg.extract() {
|
||||
Ok(res) => res,
|
||||
_=> return $py.NotImplemented().convert($py)
|
||||
})
|
||||
$(;$args)*
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Call `slf.try_borrow()?.$fn(...)`
|
||||
macro_rules! call_ref {
|
||||
($slf: expr, $fn: ident $(,$raw_args: expr)* $(; $args: expr)*) => {
|
||||
_call_impl!($slf.try_borrow()?, $fn $(,$raw_args)* $(;$args)*)
|
||||
};
|
||||
}
|
||||
|
||||
/// Call `slf.try_borrow_mut()?.$fn(...)`
|
||||
macro_rules! call_mut {
|
||||
($slf: expr, $fn: ident $(,$raw_args: expr)* $(; $args: expr)*) => {
|
||||
_call_impl!($slf.try_borrow_mut()?, $fn $(,$raw_args)* $(;$args)*)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! call_operator_mut {
|
||||
($py:ident, $slf: expr, $fn: ident $(,$raw_args: expr)* $(; $args: expr)*) => {
|
||||
_call_impl!(op $py; $slf.try_borrow_mut()?, $fn $(,$raw_args)* $(;$args)*)
|
||||
};
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
#![allow(deprecated)]
|
||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
//! Python Mapping Interface
|
||||
//! Trait and support implementation for implementing mapping support
|
||||
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::pyclass::boolean_struct::False;
|
||||
use crate::{FromPyObject, PyClass, PyObject};
|
||||
|
||||
/// Mapping interface
|
||||
#[allow(unused_variables)]
|
||||
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
|
||||
pub trait PyMappingProtocol<'p>: PyClass<Frozen = False> {
|
||||
fn __len__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyMappingLenProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __getitem__(&'p self, key: Self::Key) -> Self::Result
|
||||
where
|
||||
Self: PyMappingGetItemProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __setitem__(&'p mut self, key: Self::Key, value: Self::Value) -> Self::Result
|
||||
where
|
||||
Self: PyMappingSetItemProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __delitem__(&'p mut self, key: Self::Key) -> Self::Result
|
||||
where
|
||||
Self: PyMappingDelItemProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
// The following are a bunch of marker traits used to detect
|
||||
// the existence of a slotted method.
|
||||
|
||||
pub trait PyMappingLenProtocol<'p>: PyMappingProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<usize>;
|
||||
}
|
||||
|
||||
pub trait PyMappingGetItemProtocol<'p>: PyMappingProtocol<'p> {
|
||||
type Key: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Key: FromPyObject<'p>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Key: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
py_len_func!(len, PyMappingLenProtocol, Self::__len__);
|
||||
py_binary_func!(getitem, PyMappingGetItemProtocol, Self::__getitem__);
|
||||
py_func_set!(setitem, PyMappingSetItemProtocol, Self::__setitem__);
|
||||
py_func_del!(delitem, PyMappingDelItemProtocol, Self::__delitem__);
|
||||
py_func_set_del!(
|
||||
setdelitem,
|
||||
PyMappingSetItemProtocol,
|
||||
PyMappingDelItemProtocol,
|
||||
Self,
|
||||
__setitem__,
|
||||
__delitem__
|
||||
);
|
|
@ -1,35 +0,0 @@
|
|||
#![allow(deprecated)]
|
||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
//! Python object protocols
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
pub mod basic;
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_11))]
|
||||
pub mod buffer;
|
||||
pub mod descr;
|
||||
pub mod gc;
|
||||
pub mod iter;
|
||||
pub mod mapping;
|
||||
#[doc(hidden)]
|
||||
pub use crate::impl_::pymethods as methods;
|
||||
pub mod number;
|
||||
pub mod pyasync;
|
||||
pub mod sequence;
|
||||
|
||||
pub use self::basic::PyObjectProtocol;
|
||||
#[cfg(any(not(Py_LIMITED_API), Py_3_11))]
|
||||
pub use self::buffer::PyBufferProtocol;
|
||||
pub use self::descr::PyDescrProtocol;
|
||||
pub use self::gc::{PyGCProtocol, PyTraverseError, PyVisit};
|
||||
pub use self::iter::PyIterProtocol;
|
||||
pub use self::mapping::PyMappingProtocol;
|
||||
#[doc(hidden)]
|
||||
pub use self::methods::{
|
||||
PyClassAttributeDef, PyGetterDef, PyMethodDef, PyMethodDefType, PyMethodType, PySetterDef,
|
||||
};
|
||||
pub use self::number::PyNumberProtocol;
|
||||
pub use self::pyasync::PyAsyncProtocol;
|
||||
pub use self::sequence::PySequenceProtocol;
|
|
@ -1,783 +0,0 @@
|
|||
#![allow(deprecated)]
|
||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
//! Python Number Interface
|
||||
//! Trait and support implementation for implementing number protocol
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::err::PyErr;
|
||||
use crate::pyclass::boolean_struct::False;
|
||||
use crate::{ffi, FromPyObject, PyClass, PyObject};
|
||||
|
||||
/// Number interface
|
||||
#[allow(unused_variables)]
|
||||
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
|
||||
pub trait PyNumberProtocol<'p>: PyClass {
|
||||
fn __add__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberAddProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __sub__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberSubProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __mul__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberMulProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __matmul__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberMatmulProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __truediv__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberTruedivProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __floordiv__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberFloordivProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __mod__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberModProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __divmod__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberDivmodProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __pow__(lhs: Self::Left, rhs: Self::Right, modulo: Option<Self::Modulo>) -> Self::Result
|
||||
where
|
||||
Self: PyNumberPowProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __lshift__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberLShiftProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rshift__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRShiftProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __and__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberAndProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __xor__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberXorProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __or__(lhs: Self::Left, rhs: Self::Right) -> Self::Result
|
||||
where
|
||||
Self: PyNumberOrProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __radd__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRAddProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rsub__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRSubProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rmul__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRMulProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rmatmul__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRMatmulProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rtruediv__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRTruedivProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rfloordiv__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRFloordivProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rmod__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRModProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rdivmod__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRDivmodProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rpow__(&'p self, other: Self::Other, modulo: Option<Self::Modulo>) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRPowProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rlshift__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRLShiftProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rrshift__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRRShiftProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rand__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRAndProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __rxor__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberRXorProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __ror__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberROrProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __iadd__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIAddProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __isub__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberISubProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __imul__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIMulProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __imatmul__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIMatmulProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __itruediv__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberITruedivProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __ifloordiv__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIFloordivProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __imod__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIModProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __ipow__(&'p mut self, other: Self::Other, modulo: Option<Self::Modulo>) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIPowProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __ilshift__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberILShiftProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __irshift__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIRShiftProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __iand__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIAndProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __ixor__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIXorProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __ior__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIOrProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// Unary arithmetic
|
||||
fn __neg__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyNumberNegProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __pos__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyNumberPosProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __abs__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyNumberAbsProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __invert__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyNumberInvertProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __int__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIntProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __float__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyNumberFloatProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
fn __index__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PyNumberIndexProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PyNumberAddProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberSubProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberMulProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberMatmulProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberTruedivProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberFloordivProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberModProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberDivmodProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberPowProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Modulo: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberLShiftProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRShiftProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberAndProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberXorProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberOrProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Left: FromPyObject<'p>;
|
||||
type Right: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRAddProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRSubProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRMulProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRMatmulProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRTruedivProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRFloordivProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRModProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRDivmodProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRPowProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Modulo: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRLShiftProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRRShiftProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRAndProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberRXorProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
// See https://bugs.python.org/issue36379
|
||||
type Modulo: FromPyObject<'p>;
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberNegProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberPosProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberAbsProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberInvertProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIntProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberFloatProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIndexProtocol<'p>: PyNumberProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
py_binary_fallback_num_func!(
|
||||
add_radd,
|
||||
T,
|
||||
PyNumberAddProtocol::__add__,
|
||||
PyNumberRAddProtocol::__radd__
|
||||
);
|
||||
py_binary_num_func!(add, PyNumberAddProtocol, T::__add__);
|
||||
py_binary_reversed_num_func!(radd, PyNumberRAddProtocol, T::__radd__);
|
||||
py_binary_fallback_num_func!(
|
||||
sub_rsub,
|
||||
T,
|
||||
PyNumberSubProtocol::__sub__,
|
||||
PyNumberRSubProtocol::__rsub__
|
||||
);
|
||||
py_binary_num_func!(sub, PyNumberSubProtocol, T::__sub__);
|
||||
py_binary_reversed_num_func!(rsub, PyNumberRSubProtocol, T::__rsub__);
|
||||
py_binary_fallback_num_func!(
|
||||
mul_rmul,
|
||||
T,
|
||||
PyNumberMulProtocol::__mul__,
|
||||
PyNumberRMulProtocol::__rmul__
|
||||
);
|
||||
py_binary_num_func!(mul, PyNumberMulProtocol, T::__mul__);
|
||||
py_binary_reversed_num_func!(rmul, PyNumberRMulProtocol, T::__rmul__);
|
||||
py_binary_fallback_num_func!(
|
||||
mod_rmod,
|
||||
T,
|
||||
PyNumberModProtocol::__mod__,
|
||||
PyNumberRModProtocol::__rmod__
|
||||
);
|
||||
py_binary_num_func!(mod_, PyNumberModProtocol, T::__mod__);
|
||||
py_binary_reversed_num_func!(rmod, PyNumberRModProtocol, T::__rmod__);
|
||||
py_binary_fallback_num_func!(
|
||||
divmod_rdivmod,
|
||||
T,
|
||||
PyNumberDivmodProtocol::__divmod__,
|
||||
PyNumberRDivmodProtocol::__rdivmod__
|
||||
);
|
||||
py_binary_num_func!(divmod, PyNumberDivmodProtocol, T::__divmod__);
|
||||
py_binary_reversed_num_func!(rdivmod, PyNumberRDivmodProtocol, T::__rdivmod__);
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn pow_rpow<T>(
|
||||
lhs: *mut ffi::PyObject,
|
||||
rhs: *mut ffi::PyObject,
|
||||
modulo: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyNumberPowProtocol<'p> + for<'p> PyNumberRPowProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let lhs = py.from_borrowed_ptr::<crate::PyAny>(lhs);
|
||||
let rhs = py.from_borrowed_ptr::<crate::PyAny>(rhs);
|
||||
let modulo = py.from_borrowed_ptr::<crate::PyAny>(modulo);
|
||||
// First, try __pow__
|
||||
match (lhs.extract(), rhs.extract(), modulo.extract()) {
|
||||
(Ok(l), Ok(r), Ok(m)) => T::__pow__(l, r, m).convert(py),
|
||||
_ => {
|
||||
// Then try __rpow__
|
||||
let slf: &crate::PyCell<T> = extract_or_return_not_implemented!(rhs);
|
||||
let arg = extract_or_return_not_implemented!(lhs);
|
||||
let modulo = extract_or_return_not_implemented!(modulo);
|
||||
slf.try_borrow()?.__rpow__(arg, modulo).convert(py)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn pow<T>(
|
||||
lhs: *mut ffi::PyObject,
|
||||
rhs: *mut ffi::PyObject,
|
||||
modulo: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyNumberPowProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let lhs = extract_or_return_not_implemented!(py, lhs);
|
||||
let rhs = extract_or_return_not_implemented!(py, rhs);
|
||||
let modulo = extract_or_return_not_implemented!(py, modulo);
|
||||
T::__pow__(lhs, rhs, modulo).convert(py)
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn rpow<T>(
|
||||
arg: *mut ffi::PyObject,
|
||||
slf: *mut ffi::PyObject,
|
||||
modulo: *mut ffi::PyObject,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyNumberRPowProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf: &crate::PyCell<T> = extract_or_return_not_implemented!(py, slf);
|
||||
let arg = extract_or_return_not_implemented!(py, arg);
|
||||
let modulo = extract_or_return_not_implemented!(py, modulo);
|
||||
slf.try_borrow()?.__rpow__(arg, modulo).convert(py)
|
||||
})
|
||||
}
|
||||
|
||||
py_unary_func!(neg, PyNumberNegProtocol, T::__neg__);
|
||||
py_unary_func!(pos, PyNumberPosProtocol, T::__pos__);
|
||||
py_unary_func!(abs, PyNumberAbsProtocol, T::__abs__);
|
||||
py_unary_func!(invert, PyNumberInvertProtocol, T::__invert__);
|
||||
py_binary_fallback_num_func!(
|
||||
lshift_rlshift,
|
||||
T,
|
||||
PyNumberLShiftProtocol::__lshift__,
|
||||
PyNumberRLShiftProtocol::__rlshift__
|
||||
);
|
||||
py_binary_num_func!(lshift, PyNumberLShiftProtocol, T::__lshift__);
|
||||
py_binary_reversed_num_func!(rlshift, PyNumberRLShiftProtocol, T::__rlshift__);
|
||||
py_binary_fallback_num_func!(
|
||||
rshift_rrshift,
|
||||
T,
|
||||
PyNumberRShiftProtocol::__rshift__,
|
||||
PyNumberRRShiftProtocol::__rrshift__
|
||||
);
|
||||
py_binary_num_func!(rshift, PyNumberRShiftProtocol, T::__rshift__);
|
||||
py_binary_reversed_num_func!(rrshift, PyNumberRRShiftProtocol, T::__rrshift__);
|
||||
py_binary_fallback_num_func!(
|
||||
and_rand,
|
||||
T,
|
||||
PyNumberAndProtocol::__and__,
|
||||
PyNumberRAndProtocol::__rand__
|
||||
);
|
||||
py_binary_num_func!(and, PyNumberAndProtocol, T::__and__);
|
||||
py_binary_reversed_num_func!(rand, PyNumberRAndProtocol, T::__rand__);
|
||||
py_binary_fallback_num_func!(
|
||||
xor_rxor,
|
||||
T,
|
||||
PyNumberXorProtocol::__xor__,
|
||||
PyNumberRXorProtocol::__rxor__
|
||||
);
|
||||
py_binary_num_func!(xor, PyNumberXorProtocol, T::__xor__);
|
||||
py_binary_reversed_num_func!(rxor, PyNumberRXorProtocol, T::__rxor__);
|
||||
py_binary_fallback_num_func!(
|
||||
or_ror,
|
||||
T,
|
||||
PyNumberOrProtocol::__or__,
|
||||
PyNumberROrProtocol::__ror__
|
||||
);
|
||||
py_binary_num_func!(or, PyNumberOrProtocol, T::__or__);
|
||||
py_binary_reversed_num_func!(ror, PyNumberROrProtocol, T::__ror__);
|
||||
py_unary_func!(int, PyNumberIntProtocol, T::__int__);
|
||||
py_unary_func!(float, PyNumberFloatProtocol, T::__float__);
|
||||
py_binary_self_func!(iadd, PyNumberIAddProtocol, T::__iadd__);
|
||||
py_binary_self_func!(isub, PyNumberISubProtocol, T::__isub__);
|
||||
py_binary_self_func!(imul, PyNumberIMulProtocol, T::__imul__);
|
||||
py_binary_self_func!(imod, PyNumberIModProtocol, T::__imod__);
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn ipow<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
other: *mut ffi::PyObject,
|
||||
modulo: crate::impl_::pymethods::IPowModulo,
|
||||
) -> *mut ffi::PyObject
|
||||
where
|
||||
T: for<'p> PyNumberIPowProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf_cell = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
let other = py.from_borrowed_ptr::<crate::PyAny>(other);
|
||||
slf_cell
|
||||
.try_borrow_mut()?
|
||||
.__ipow__(
|
||||
extract_or_return_not_implemented!(other),
|
||||
match modulo.to_borrowed_any(py).extract() {
|
||||
Ok(value) => value,
|
||||
Err(_) => {
|
||||
let res = crate::ffi::Py_NotImplemented();
|
||||
crate::ffi::Py_INCREF(res);
|
||||
return Ok(res);
|
||||
}
|
||||
},
|
||||
)
|
||||
.convert(py)?;
|
||||
ffi::Py_INCREF(slf);
|
||||
Ok::<_, PyErr>(slf)
|
||||
})
|
||||
}
|
||||
|
||||
py_binary_self_func!(ilshift, PyNumberILShiftProtocol, T::__ilshift__);
|
||||
py_binary_self_func!(irshift, PyNumberIRShiftProtocol, T::__irshift__);
|
||||
py_binary_self_func!(iand, PyNumberIAndProtocol, T::__iand__);
|
||||
py_binary_self_func!(ixor, PyNumberIXorProtocol, T::__ixor__);
|
||||
py_binary_self_func!(ior, PyNumberIOrProtocol, T::__ior__);
|
||||
py_binary_fallback_num_func!(
|
||||
floordiv_rfloordiv,
|
||||
T,
|
||||
PyNumberFloordivProtocol::__floordiv__,
|
||||
PyNumberRFloordivProtocol::__rfloordiv__
|
||||
);
|
||||
py_binary_num_func!(floordiv, PyNumberFloordivProtocol, T::__floordiv__);
|
||||
py_binary_reversed_num_func!(rfloordiv, PyNumberRFloordivProtocol, T::__rfloordiv__);
|
||||
py_binary_fallback_num_func!(
|
||||
truediv_rtruediv,
|
||||
T,
|
||||
PyNumberTruedivProtocol::__truediv__,
|
||||
PyNumberRTruedivProtocol::__rtruediv__
|
||||
);
|
||||
py_binary_num_func!(truediv, PyNumberTruedivProtocol, T::__truediv__);
|
||||
py_binary_reversed_num_func!(rtruediv, PyNumberRTruedivProtocol, T::__rtruediv__);
|
||||
py_binary_self_func!(ifloordiv, PyNumberIFloordivProtocol, T::__ifloordiv__);
|
||||
py_binary_self_func!(itruediv, PyNumberITruedivProtocol, T::__itruediv__);
|
||||
py_unary_func!(index, PyNumberIndexProtocol, T::__index__);
|
||||
py_binary_fallback_num_func!(
|
||||
matmul_rmatmul,
|
||||
T,
|
||||
PyNumberMatmulProtocol::__matmul__,
|
||||
PyNumberRMatmulProtocol::__rmatmul__
|
||||
);
|
||||
py_binary_num_func!(matmul, PyNumberMatmulProtocol, T::__matmul__);
|
||||
py_binary_reversed_num_func!(rmatmul, PyNumberRMatmulProtocol, T::__rmatmul__);
|
||||
py_binary_self_func!(imatmul, PyNumberIMatmulProtocol, T::__imatmul__);
|
|
@ -1,62 +0,0 @@
|
|||
#![allow(deprecated)]
|
||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
//! Python Async/Await Interface.
|
||||
//!
|
||||
//! Check [the Python C API information](
|
||||
//! https://docs.python.org/3/c-api/typeobj.html#async-object-structures)
|
||||
//!
|
||||
//! [PEP-0492](https://www.python.org/dev/peps/pep-0492/)
|
||||
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::derive_utils::TryFromPyCell;
|
||||
use crate::{PyClass, PyObject};
|
||||
|
||||
/// Python Async/Await support interface.
|
||||
///
|
||||
/// Each method in this trait corresponds to Python async/await implementation.
|
||||
#[allow(unused_variables)]
|
||||
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
|
||||
pub trait PyAsyncProtocol<'p>: PyClass {
|
||||
fn __await__(slf: Self::Receiver) -> Self::Result
|
||||
where
|
||||
Self: PyAsyncAwaitProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __aiter__(slf: Self::Receiver) -> Self::Result
|
||||
where
|
||||
Self: PyAsyncAiterProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __anext__(slf: Self::Receiver) -> Self::Result
|
||||
where
|
||||
Self: PyAsyncAnextProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PyAsyncAwaitProtocol<'p>: PyAsyncProtocol<'p> {
|
||||
type Receiver: TryFromPyCell<'p, Self>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyAsyncAiterProtocol<'p>: PyAsyncProtocol<'p> {
|
||||
type Receiver: TryFromPyCell<'p, Self>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyAsyncAnextProtocol<'p>: PyAsyncProtocol<'p> {
|
||||
type Receiver: TryFromPyCell<'p, Self>;
|
||||
type Result: IntoPyCallbackOutput<PyIterANextOutput>;
|
||||
}
|
||||
|
||||
py_unarys_func!(await_, PyAsyncAwaitProtocol, Self::__await__);
|
||||
py_unarys_func!(aiter, PyAsyncAiterProtocol, Self::__aiter__);
|
||||
py_unarys_func!(anext, PyAsyncAnextProtocol, Self::__anext__);
|
||||
|
||||
pub use crate::pyclass::{IterANextOutput, PyIterANextOutput};
|
|
@ -1,228 +0,0 @@
|
|||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||
|
||||
//! Python Sequence Interface
|
||||
//! Trait and support implementation for implementing sequence
|
||||
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::conversion::{FromPyObject, IntoPy};
|
||||
use crate::err::PyErr;
|
||||
use crate::pyclass::boolean_struct::False;
|
||||
use crate::{exceptions, ffi, PyAny, PyCell, PyClass, PyObject};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Sequence interface
|
||||
#[allow(unused_variables)]
|
||||
#[deprecated(since = "0.16.0", note = "prefer `#[pymethods]` to `#[pyproto]`")]
|
||||
pub trait PySequenceProtocol<'p>: PyClass + Sized {
|
||||
fn __len__(&'p self) -> Self::Result
|
||||
where
|
||||
Self: PySequenceLenProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __getitem__(&'p self, idx: Self::Index) -> Self::Result
|
||||
where
|
||||
Self: PySequenceGetItemProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __setitem__(&'p mut self, idx: Self::Index, value: Self::Value) -> Self::Result
|
||||
where
|
||||
Self: PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __delitem__(&'p mut self, idx: Self::Index) -> Self::Result
|
||||
where
|
||||
Self: PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __contains__(&'p self, item: Self::Item) -> Self::Result
|
||||
where
|
||||
Self: PySequenceContainsProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __concat__(&'p self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PySequenceConcatProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __repeat__(&'p self, count: Self::Index) -> Self::Result
|
||||
where
|
||||
Self: PySequenceRepeatProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __inplace_concat__(&'p mut self, other: Self::Other) -> Self::Result
|
||||
where
|
||||
Self: PySequenceInplaceConcatProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __inplace_repeat__(&'p mut self, count: Self::Index) -> Self::Result
|
||||
where
|
||||
Self: PySequenceInplaceRepeatProtocol<'p>,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
// The following are a bunch of marker traits used to detect
|
||||
// the existence of a slotted method.
|
||||
|
||||
pub trait PySequenceLenProtocol<'p>: PySequenceProtocol<'p> {
|
||||
type Result: IntoPyCallbackOutput<usize>;
|
||||
}
|
||||
|
||||
pub trait PySequenceGetItemProtocol<'p>: PySequenceProtocol<'p> {
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> + PyClass<Frozen = False> {
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PySequenceContainsProtocol<'p>: PySequenceProtocol<'p> {
|
||||
type Item: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<bool>;
|
||||
}
|
||||
|
||||
pub trait PySequenceConcatProtocol<'p>: PySequenceProtocol<'p> {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> {
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PySequenceInplaceConcatProtocol<'p>:
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + PyClass<Frozen = False>
|
||||
{
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<Self>;
|
||||
}
|
||||
|
||||
pub trait PySequenceInplaceRepeatProtocol<'p>:
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + PyClass<Frozen = False> + 'p
|
||||
{
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Result: IntoPyCallbackOutput<Self>;
|
||||
}
|
||||
|
||||
py_len_func!(len, PySequenceLenProtocol, Self::__len__);
|
||||
py_binary_func!(concat, PySequenceConcatProtocol, Self::__concat__);
|
||||
py_ssizearg_func!(repeat, PySequenceRepeatProtocol, Self::__repeat__);
|
||||
py_ssizearg_func!(getitem, PySequenceGetItemProtocol, Self::__getitem__);
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn setitem<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
key: ffi::Py_ssize_t,
|
||||
value: *mut ffi::PyObject,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
return Err(exceptions::PyNotImplementedError::new_err(format!(
|
||||
"Item deletion is not supported by {:?}",
|
||||
stringify!(T)
|
||||
)));
|
||||
}
|
||||
|
||||
let mut slf = slf.try_borrow_mut()?;
|
||||
let value = py.from_borrowed_ptr::<PyAny>(value);
|
||||
let value = value.extract()?;
|
||||
crate::callback::convert(py, slf.__setitem__(key.into(), value))
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn delitem<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
key: ffi::Py_ssize_t,
|
||||
value: *mut ffi::PyObject,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
crate::callback::convert(py, slf.borrow_mut().__delitem__(key.into()))
|
||||
} else {
|
||||
Err(PyErr::new::<exceptions::PyNotImplementedError, _>(format!(
|
||||
"Item assignment not supported by {:?}",
|
||||
stringify!(T)
|
||||
)))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub unsafe extern "C" fn setdelitem<T>(
|
||||
slf: *mut ffi::PyObject,
|
||||
key: ffi::Py_ssize_t,
|
||||
value: *mut ffi::PyObject,
|
||||
) -> c_int
|
||||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
crate::callback_body!(py, {
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
call_mut!(slf, __delitem__; key.into()).convert(py)
|
||||
} else {
|
||||
let value = py.from_borrowed_ptr::<PyAny>(value);
|
||||
let mut slf_ = slf.try_borrow_mut()?;
|
||||
let value = value.extract()?;
|
||||
slf_.__setitem__(key.into(), value).convert(py)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
py_binary_func!(
|
||||
contains,
|
||||
PySequenceContainsProtocol,
|
||||
Self::__contains__,
|
||||
c_int
|
||||
);
|
||||
py_binary_func!(
|
||||
inplace_concat,
|
||||
PySequenceInplaceConcatProtocol,
|
||||
Self::__inplace_concat__,
|
||||
*mut ffi::PyObject,
|
||||
call_mut
|
||||
);
|
||||
py_ssizearg_func!(
|
||||
inplace_repeat,
|
||||
PySequenceInplaceRepeatProtocol,
|
||||
Self::__inplace_repeat__,
|
||||
call_mut
|
||||
);
|
|
@ -99,7 +99,7 @@ impl PyClassWeakRef for PyClassWeakRefSlot {
|
|||
}
|
||||
|
||||
/// This type is used as a "dummy" type on which dtolnay specializations are
|
||||
/// applied to apply implementations from `#[pymethods]` & `#[pyproto]`
|
||||
/// applied to apply implementations from `#[pymethods]`
|
||||
pub struct PyClassImplCollector<T>(PhantomData<T>);
|
||||
|
||||
impl<T> PyClassImplCollector<T> {
|
||||
|
@ -205,68 +205,20 @@ pub struct PyClassItemsIter {
|
|||
/// Items from the `#[pymethods]` macro with inventory
|
||||
#[cfg(feature = "multiple-pymethods")]
|
||||
pymethods_items: Box<dyn Iterator<Item = &'static PyClassItems>>,
|
||||
|
||||
// pyproto items, to be removed soon.
|
||||
#[cfg(feature = "pyproto")]
|
||||
object_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")]
|
||||
descr_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")]
|
||||
gc_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")]
|
||||
iter_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")]
|
||||
mapping_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")]
|
||||
number_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")]
|
||||
async_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")]
|
||||
sequence_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")]
|
||||
buffer_protocol_items: &'static PyClassItems,
|
||||
}
|
||||
|
||||
impl PyClassItemsIter {
|
||||
#[cfg_attr(feature = "pyproto", allow(clippy::too_many_arguments))]
|
||||
pub fn new(
|
||||
pyclass_items: &'static PyClassItems,
|
||||
#[cfg(not(feature = "multiple-pymethods"))] pymethods_items: &'static PyClassItems,
|
||||
#[cfg(feature = "multiple-pymethods")] pymethods_items: Box<
|
||||
dyn Iterator<Item = &'static PyClassItems>,
|
||||
>,
|
||||
#[cfg(feature = "pyproto")] object_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")] descr_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")] gc_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")] iter_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")] mapping_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")] number_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")] async_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")] sequence_protocol_items: &'static PyClassItems,
|
||||
#[cfg(feature = "pyproto")] buffer_protocol_items: &'static PyClassItems,
|
||||
) -> Self {
|
||||
Self {
|
||||
idx: 0,
|
||||
pyclass_items,
|
||||
pymethods_items,
|
||||
#[cfg(feature = "pyproto")]
|
||||
object_protocol_items,
|
||||
#[cfg(feature = "pyproto")]
|
||||
descr_protocol_items,
|
||||
#[cfg(feature = "pyproto")]
|
||||
gc_protocol_items,
|
||||
#[cfg(feature = "pyproto")]
|
||||
iter_protocol_items,
|
||||
#[cfg(feature = "pyproto")]
|
||||
mapping_protocol_items,
|
||||
#[cfg(feature = "pyproto")]
|
||||
number_protocol_items,
|
||||
#[cfg(feature = "pyproto")]
|
||||
async_protocol_items,
|
||||
#[cfg(feature = "pyproto")]
|
||||
sequence_protocol_items,
|
||||
#[cfg(feature = "pyproto")]
|
||||
buffer_protocol_items,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -285,53 +237,7 @@ impl Iterator for PyClassItemsIter {
|
|||
self.idx += 1;
|
||||
Some(self.pymethods_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
2 => {
|
||||
self.idx += 1;
|
||||
Some(self.object_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
3 => {
|
||||
self.idx += 1;
|
||||
Some(self.descr_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
4 => {
|
||||
self.idx += 1;
|
||||
Some(self.gc_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
5 => {
|
||||
self.idx += 1;
|
||||
Some(self.iter_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
6 => {
|
||||
self.idx += 1;
|
||||
Some(self.mapping_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
7 => {
|
||||
self.idx += 1;
|
||||
Some(self.number_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
8 => {
|
||||
self.idx += 1;
|
||||
Some(self.async_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
9 => {
|
||||
self.idx += 1;
|
||||
Some(self.sequence_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
10 => {
|
||||
self.idx += 1;
|
||||
Some(self.buffer_protocol_items)
|
||||
}
|
||||
// Termination clause
|
||||
// NB self.idx reaches different final value (2 vs 11) depending on pyproto feature
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -343,53 +249,7 @@ impl Iterator for PyClassItemsIter {
|
|||
self.idx += 1;
|
||||
Some(self.pyclass_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
1 => {
|
||||
self.idx += 1;
|
||||
Some(self.object_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
2 => {
|
||||
self.idx += 1;
|
||||
Some(self.descr_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
3 => {
|
||||
self.idx += 1;
|
||||
Some(self.gc_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
4 => {
|
||||
self.idx += 1;
|
||||
Some(self.iter_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
5 => {
|
||||
self.idx += 1;
|
||||
Some(self.mapping_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
6 => {
|
||||
self.idx += 1;
|
||||
Some(self.number_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
7 => {
|
||||
self.idx += 1;
|
||||
Some(self.async_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
8 => {
|
||||
self.idx += 1;
|
||||
Some(self.sequence_protocol_items)
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
9 => {
|
||||
self.idx += 1;
|
||||
Some(self.buffer_protocol_items)
|
||||
}
|
||||
// Termination clause
|
||||
// NB self.idx reaches different final value (1 vs 10) depending on pyproto feature
|
||||
_ => self.pymethods_items.next(),
|
||||
}
|
||||
}
|
||||
|
@ -964,26 +824,6 @@ unsafe fn bpo_35810_workaround(_py: Python<'_>, ty: *mut ffi::PyTypeObject) {
|
|||
ffi::Py_INCREF(ty as *mut ffi::PyObject);
|
||||
}
|
||||
|
||||
// General methods implementation: either dtolnay specialization trait or inventory if
|
||||
// multiple-pymethods feature is enabled.
|
||||
|
||||
macro_rules! items_trait {
|
||||
($name:ident, $function_name: ident) => {
|
||||
pub trait $name<T> {
|
||||
fn $function_name(self) -> &'static PyClassItems;
|
||||
}
|
||||
|
||||
impl<T> $name<T> for &'_ PyClassImplCollector<T> {
|
||||
fn $function_name(self) -> &'static PyClassItems {
|
||||
&PyClassItems {
|
||||
methods: &[],
|
||||
slots: &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Implementation detail. Only to be used through our proc macro code.
|
||||
/// Method storage for `#[pyclass]`.
|
||||
/// Allows arbitrary `#[pymethod]` blocks to submit their methods,
|
||||
|
@ -996,24 +836,19 @@ pub trait PyClassInventory: inventory::Collect {
|
|||
|
||||
// Items from #[pymethods] if not using inventory.
|
||||
#[cfg(not(feature = "multiple-pymethods"))]
|
||||
items_trait!(PyMethods, py_methods);
|
||||
|
||||
/// Items from `#[pyproto]` implementations
|
||||
#[cfg(feature = "pyproto")]
|
||||
mod pyproto_traits {
|
||||
use super::*;
|
||||
items_trait!(PyObjectProtocolItems, object_protocol_items);
|
||||
items_trait!(PyDescrProtocolItems, descr_protocol_items);
|
||||
items_trait!(PyGCProtocolItems, gc_protocol_items);
|
||||
items_trait!(PyIterProtocolItems, iter_protocol_items);
|
||||
items_trait!(PyMappingProtocolItems, mapping_protocol_items);
|
||||
items_trait!(PyNumberProtocolItems, number_protocol_items);
|
||||
items_trait!(PyAsyncProtocolItems, async_protocol_items);
|
||||
items_trait!(PySequenceProtocolItems, sequence_protocol_items);
|
||||
items_trait!(PyBufferProtocolItems, buffer_protocol_items);
|
||||
pub trait PyMethods<T> {
|
||||
fn py_methods(self) -> &'static PyClassItems;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "multiple-pymethods"))]
|
||||
impl<T> PyMethods<T> for &'_ PyClassImplCollector<T> {
|
||||
fn py_methods(self) -> &'static PyClassItems {
|
||||
&PyClassItems {
|
||||
methods: &[],
|
||||
slots: &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "pyproto")]
|
||||
pub use pyproto_traits::*;
|
||||
|
||||
// Thread checkers
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ impl IPowModulo {
|
|||
}
|
||||
|
||||
/// `PyMethodDefType` represents different types of Python callable objects.
|
||||
/// It is used by the `#[pymethods]` and `#[pyproto]` annotations.
|
||||
/// It is used by the `#[pymethods]` attribute.
|
||||
#[derive(Debug)]
|
||||
pub enum PyMethodDefType {
|
||||
/// Represents class method
|
||||
|
|
|
@ -70,8 +70,7 @@
|
|||
//! ## Default feature flags
|
||||
//!
|
||||
//! The following features are turned on by default:
|
||||
//! - `macros`: Enables various macros, including all the attribute macros excluding the deprecated
|
||||
//! `#[pyproto]` attribute.
|
||||
//! - `macros`: Enables various macros, including all the attribute macros.
|
||||
//!
|
||||
//! ## Optional feature flags
|
||||
//!
|
||||
|
@ -87,7 +86,6 @@
|
|||
//! - `multiple-pymethods`: Enables the use of multiple [`#[pymethods]`](macro@crate::pymethods)
|
||||
//! blocks per [`#[pyclass]`](macro@crate::pyclass). This adds a dependency on the [inventory]
|
||||
//! crate, which is not supported on all platforms.
|
||||
//! - `pyproto`: Enables the deprecated `#[pyproto]` attribute macro. This will be removed in PyO3 0.18.
|
||||
//!
|
||||
//! The following features enable interactions with other crates in the Rust ecosystem:
|
||||
//! - [`anyhow`]: Enables a conversion from [anyhow]’s [`Error`][anyhow_error] type to [`PyErr`].
|
||||
|
@ -313,7 +311,6 @@ pub use crate::types::PyAny;
|
|||
pub use crate::version::PythonVersionInfo;
|
||||
|
||||
// Old directory layout, to be rethought?
|
||||
#[cfg(not(feature = "pyproto"))]
|
||||
pub mod class {
|
||||
#[doc(hidden)]
|
||||
pub use crate::impl_::pymethods as methods;
|
||||
|
@ -359,8 +356,6 @@ mod internal_tricks;
|
|||
pub mod buffer;
|
||||
#[doc(hidden)]
|
||||
pub mod callback;
|
||||
#[cfg(feature = "pyproto")]
|
||||
pub mod class;
|
||||
pub mod conversion;
|
||||
mod conversions;
|
||||
#[macro_use]
|
||||
|
@ -389,8 +384,6 @@ mod version;
|
|||
|
||||
pub use crate::conversions::*;
|
||||
|
||||
#[cfg(all(feature = "macros", feature = "pyproto"))]
|
||||
pub use pyo3_macros::pyproto;
|
||||
#[cfg(feature = "macros")]
|
||||
pub use pyo3_macros::{pyfunction, pymethods, pymodule, FromPyObject};
|
||||
|
||||
|
|
|
@ -24,8 +24,5 @@ pub use crate::types::{PyAny, PyModule};
|
|||
#[cfg(feature = "macros")]
|
||||
pub use pyo3_macros::{pyclass, pyfunction, pymethods, pymodule, FromPyObject};
|
||||
|
||||
#[cfg(all(feature = "macros", feature = "pyproto"))]
|
||||
pub use pyo3_macros::pyproto;
|
||||
|
||||
#[cfg(feature = "macros")]
|
||||
pub use crate::wrap_pyfunction;
|
||||
|
|
|
@ -1,694 +0,0 @@
|
|||
#![allow(deprecated)] // for deprecated protocol methods
|
||||
#![cfg(feature = "macros")]
|
||||
#![cfg(feature = "pyproto")]
|
||||
|
||||
use pyo3::class::basic::CompareOp;
|
||||
use pyo3::class::*;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::py_run;
|
||||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
struct UnaryArithmetic {
|
||||
inner: f64,
|
||||
}
|
||||
|
||||
impl UnaryArithmetic {
|
||||
fn new(value: f64) -> Self {
|
||||
UnaryArithmetic { inner: value }
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyObjectProtocol for UnaryArithmetic {
|
||||
fn __repr__(&self) -> String {
|
||||
format!("UA({})", self.inner)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyNumberProtocol for UnaryArithmetic {
|
||||
fn __neg__(&self) -> Self {
|
||||
Self::new(-self.inner)
|
||||
}
|
||||
|
||||
fn __pos__(&self) -> Self {
|
||||
Self::new(self.inner)
|
||||
}
|
||||
|
||||
fn __abs__(&self) -> Self {
|
||||
Self::new(self.inner.abs())
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unary_arithmetic() {
|
||||
Python::with_gil(|py| {
|
||||
let c = PyCell::new(py, UnaryArithmetic::new(2.7)).unwrap();
|
||||
py_run!(py, c, "assert repr(-c) == 'UA(-2.7)'");
|
||||
py_run!(py, c, "assert repr(+c) == 'UA(2.7)'");
|
||||
py_run!(py, c, "assert repr(abs(c)) == 'UA(2.7)'");
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct BinaryArithmetic {}
|
||||
|
||||
#[pyproto]
|
||||
impl PyObjectProtocol for BinaryArithmetic {
|
||||
fn __repr__(&self) -> &'static str {
|
||||
"BA"
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct InPlaceOperations {
|
||||
value: u32,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyObjectProtocol for InPlaceOperations {
|
||||
fn __repr__(&self) -> String {
|
||||
format!("IPO({:?})", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyNumberProtocol for InPlaceOperations {
|
||||
fn __iadd__(&mut self, other: u32) {
|
||||
self.value += other;
|
||||
}
|
||||
|
||||
fn __isub__(&mut self, other: u32) {
|
||||
self.value -= other;
|
||||
}
|
||||
|
||||
fn __imul__(&mut self, other: u32) {
|
||||
self.value *= other;
|
||||
}
|
||||
|
||||
fn __ilshift__(&mut self, other: u32) {
|
||||
self.value <<= other;
|
||||
}
|
||||
|
||||
fn __irshift__(&mut self, other: u32) {
|
||||
self.value >>= other;
|
||||
}
|
||||
|
||||
fn __iand__(&mut self, other: u32) {
|
||||
self.value &= other;
|
||||
}
|
||||
|
||||
fn __ixor__(&mut self, other: u32) {
|
||||
self.value ^= other;
|
||||
}
|
||||
|
||||
fn __ior__(&mut self, other: u32) {
|
||||
self.value |= other;
|
||||
}
|
||||
|
||||
fn __ipow__(&mut self, other: u32, _modulo: Option<u32>) {
|
||||
self.value = self.value.pow(other);
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn inplace_operations() {
|
||||
Python::with_gil(|py| {
|
||||
let init = |value, code| {
|
||||
let c = PyCell::new(py, InPlaceOperations { value }).unwrap();
|
||||
py_run!(py, c, code);
|
||||
};
|
||||
|
||||
init(0, "d = c; c += 1; assert repr(c) == repr(d) == 'IPO(1)'");
|
||||
init(10, "d = c; c -= 1; assert repr(c) == repr(d) == 'IPO(9)'");
|
||||
init(3, "d = c; c *= 3; assert repr(c) == repr(d) == 'IPO(9)'");
|
||||
init(3, "d = c; c <<= 2; assert repr(c) == repr(d) == 'IPO(12)'");
|
||||
init(12, "d = c; c >>= 2; assert repr(c) == repr(d) == 'IPO(3)'");
|
||||
init(12, "d = c; c &= 10; assert repr(c) == repr(d) == 'IPO(8)'");
|
||||
init(12, "d = c; c |= 3; assert repr(c) == repr(d) == 'IPO(15)'");
|
||||
init(12, "d = c; c ^= 5; assert repr(c) == repr(d) == 'IPO(9)'");
|
||||
init(3, "d = c; c **= 4; assert repr(c) == repr(d) == 'IPO(81)'");
|
||||
init(
|
||||
3,
|
||||
"d = c; c.__ipow__(4); assert repr(c) == repr(d) == 'IPO(81)'",
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyNumberProtocol for BinaryArithmetic {
|
||||
fn __add__(lhs: &PyAny, rhs: &PyAny) -> String {
|
||||
format!("{:?} + {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __sub__(lhs: &PyAny, rhs: &PyAny) -> String {
|
||||
format!("{:?} - {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __mod__(lhs: &PyAny, rhs: &PyAny) -> String {
|
||||
format!("{:?} % {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __mul__(lhs: &PyAny, rhs: &PyAny) -> String {
|
||||
format!("{:?} * {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __lshift__(lhs: &PyAny, rhs: &PyAny) -> String {
|
||||
format!("{:?} << {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __rshift__(lhs: &PyAny, rhs: &PyAny) -> String {
|
||||
format!("{:?} >> {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __and__(lhs: &PyAny, rhs: &PyAny) -> String {
|
||||
format!("{:?} & {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __xor__(lhs: &PyAny, rhs: &PyAny) -> String {
|
||||
format!("{:?} ^ {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __or__(lhs: &PyAny, rhs: &PyAny) -> String {
|
||||
format!("{:?} | {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __pow__(lhs: &PyAny, rhs: &PyAny, mod_: Option<u32>) -> String {
|
||||
format!("{:?} ** {:?} (mod: {:?})", lhs, rhs, mod_)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn binary_arithmetic() {
|
||||
Python::with_gil(|py| {
|
||||
let c = PyCell::new(py, BinaryArithmetic {}).unwrap();
|
||||
py_run!(py, c, "assert c + c == 'BA + BA'");
|
||||
py_run!(py, c, "assert c.__add__(c) == 'BA + BA'");
|
||||
py_run!(py, c, "assert c + 1 == 'BA + 1'");
|
||||
py_run!(py, c, "assert 1 + c == '1 + BA'");
|
||||
py_run!(py, c, "assert c - 1 == 'BA - 1'");
|
||||
py_run!(py, c, "assert 1 - c == '1 - BA'");
|
||||
py_run!(py, c, "assert c * 1 == 'BA * 1'");
|
||||
py_run!(py, c, "assert 1 * c == '1 * BA'");
|
||||
py_run!(py, c, "assert c % 1 == 'BA % 1'");
|
||||
py_run!(py, c, "assert 1 % c == '1 % BA'");
|
||||
|
||||
py_run!(py, c, "assert c << 1 == 'BA << 1'");
|
||||
py_run!(py, c, "assert 1 << c == '1 << BA'");
|
||||
py_run!(py, c, "assert c >> 1 == 'BA >> 1'");
|
||||
py_run!(py, c, "assert 1 >> c == '1 >> BA'");
|
||||
py_run!(py, c, "assert c & 1 == 'BA & 1'");
|
||||
py_run!(py, c, "assert 1 & c == '1 & BA'");
|
||||
py_run!(py, c, "assert c ^ 1 == 'BA ^ 1'");
|
||||
py_run!(py, c, "assert 1 ^ c == '1 ^ BA'");
|
||||
py_run!(py, c, "assert c | 1 == 'BA | 1'");
|
||||
py_run!(py, c, "assert 1 | c == '1 | BA'");
|
||||
py_run!(py, c, "assert c ** 1 == 'BA ** 1 (mod: None)'");
|
||||
py_run!(py, c, "assert 1 ** c == '1 ** BA (mod: None)'");
|
||||
|
||||
py_run!(py, c, "assert pow(c, 1, 100) == 'BA ** 1 (mod: Some(100))'");
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct RhsArithmetic {}
|
||||
|
||||
#[pyproto]
|
||||
impl PyNumberProtocol for RhsArithmetic {
|
||||
fn __radd__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} + RA", other)
|
||||
}
|
||||
|
||||
fn __rsub__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} - RA", other)
|
||||
}
|
||||
|
||||
fn __rmod__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} % RA", other)
|
||||
}
|
||||
|
||||
fn __rmul__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} * RA", other)
|
||||
}
|
||||
|
||||
fn __rlshift__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} << RA", other)
|
||||
}
|
||||
|
||||
fn __rrshift__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} >> RA", other)
|
||||
}
|
||||
|
||||
fn __rand__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} & RA", other)
|
||||
}
|
||||
|
||||
fn __rxor__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} ^ RA", other)
|
||||
}
|
||||
|
||||
fn __ror__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} | RA", other)
|
||||
}
|
||||
|
||||
fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny>) -> String {
|
||||
format!("{:?} ** RA", other)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rhs_arithmetic() {
|
||||
Python::with_gil(|py| {
|
||||
let c = PyCell::new(py, RhsArithmetic {}).unwrap();
|
||||
py_run!(py, c, "assert c.__radd__(1) == '1 + RA'");
|
||||
py_run!(py, c, "assert 1 + c == '1 + RA'");
|
||||
py_run!(py, c, "assert c.__rsub__(1) == '1 - RA'");
|
||||
py_run!(py, c, "assert 1 - c == '1 - RA'");
|
||||
py_run!(py, c, "assert c.__rmod__(1) == '1 % RA'");
|
||||
py_run!(py, c, "assert 1 % c == '1 % RA'");
|
||||
py_run!(py, c, "assert c.__rmul__(1) == '1 * RA'");
|
||||
py_run!(py, c, "assert 1 * c == '1 * RA'");
|
||||
py_run!(py, c, "assert c.__rlshift__(1) == '1 << RA'");
|
||||
py_run!(py, c, "assert 1 << c == '1 << RA'");
|
||||
py_run!(py, c, "assert c.__rrshift__(1) == '1 >> RA'");
|
||||
py_run!(py, c, "assert 1 >> c == '1 >> RA'");
|
||||
py_run!(py, c, "assert c.__rand__(1) == '1 & RA'");
|
||||
py_run!(py, c, "assert 1 & c == '1 & RA'");
|
||||
py_run!(py, c, "assert c.__rxor__(1) == '1 ^ RA'");
|
||||
py_run!(py, c, "assert 1 ^ c == '1 ^ RA'");
|
||||
py_run!(py, c, "assert c.__ror__(1) == '1 | RA'");
|
||||
py_run!(py, c, "assert 1 | c == '1 | RA'");
|
||||
py_run!(py, c, "assert c.__rpow__(1) == '1 ** RA'");
|
||||
py_run!(py, c, "assert 1 ** c == '1 ** RA'");
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct LhsAndRhs {}
|
||||
|
||||
impl std::fmt::Debug for LhsAndRhs {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "LR")
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyNumberProtocol for LhsAndRhs {
|
||||
fn __add__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} + {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __sub__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} - {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __mod__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} % {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __mul__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} * {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __lshift__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} << {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __rshift__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} >> {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __and__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} & {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __xor__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} ^ {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __or__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} | {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __pow__(lhs: PyRef<Self>, rhs: &PyAny, _mod: Option<usize>) -> String {
|
||||
format!("{:?} ** {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __matmul__(lhs: PyRef<Self>, rhs: &PyAny) -> String {
|
||||
format!("{:?} @ {:?}", lhs, rhs)
|
||||
}
|
||||
|
||||
fn __radd__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} + RA", other)
|
||||
}
|
||||
|
||||
fn __rsub__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} - RA", other)
|
||||
}
|
||||
|
||||
fn __rmod__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} % RA", other)
|
||||
}
|
||||
|
||||
fn __rmul__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} * RA", other)
|
||||
}
|
||||
|
||||
fn __rlshift__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} << RA", other)
|
||||
}
|
||||
|
||||
fn __rrshift__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} >> RA", other)
|
||||
}
|
||||
|
||||
fn __rand__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} & RA", other)
|
||||
}
|
||||
|
||||
fn __rxor__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} ^ RA", other)
|
||||
}
|
||||
|
||||
fn __ror__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} | RA", other)
|
||||
}
|
||||
|
||||
fn __rpow__(&self, other: &PyAny, _mod: Option<&'p PyAny>) -> String {
|
||||
format!("{:?} ** RA", other)
|
||||
}
|
||||
|
||||
fn __rmatmul__(&self, other: &PyAny) -> String {
|
||||
format!("{:?} @ RA", other)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyObjectProtocol for LhsAndRhs {
|
||||
fn __repr__(&self) -> &'static str {
|
||||
"BA"
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn lhs_fellback_to_rhs() {
|
||||
Python::with_gil(|py| {
|
||||
let c = PyCell::new(py, LhsAndRhs {}).unwrap();
|
||||
// If the light hand value is `LhsAndRhs`, LHS is used.
|
||||
py_run!(py, c, "assert c + 1 == 'LR + 1'");
|
||||
py_run!(py, c, "assert c - 1 == 'LR - 1'");
|
||||
py_run!(py, c, "assert c % 1 == 'LR % 1'");
|
||||
py_run!(py, c, "assert c * 1 == 'LR * 1'");
|
||||
py_run!(py, c, "assert c << 1 == 'LR << 1'");
|
||||
py_run!(py, c, "assert c >> 1 == 'LR >> 1'");
|
||||
py_run!(py, c, "assert c & 1 == 'LR & 1'");
|
||||
py_run!(py, c, "assert c ^ 1 == 'LR ^ 1'");
|
||||
py_run!(py, c, "assert c | 1 == 'LR | 1'");
|
||||
py_run!(py, c, "assert c ** 1 == 'LR ** 1'");
|
||||
py_run!(py, c, "assert c @ 1 == 'LR @ 1'");
|
||||
// Fellback to RHS because of type mismatching
|
||||
py_run!(py, c, "assert 1 + c == '1 + RA'");
|
||||
py_run!(py, c, "assert 1 - c == '1 - RA'");
|
||||
py_run!(py, c, "assert 1 % c == '1 % RA'");
|
||||
py_run!(py, c, "assert 1 * c == '1 * RA'");
|
||||
py_run!(py, c, "assert 1 << c == '1 << RA'");
|
||||
py_run!(py, c, "assert 1 >> c == '1 >> RA'");
|
||||
py_run!(py, c, "assert 1 & c == '1 & RA'");
|
||||
py_run!(py, c, "assert 1 ^ c == '1 ^ RA'");
|
||||
py_run!(py, c, "assert 1 | c == '1 | RA'");
|
||||
py_run!(py, c, "assert 1 ** c == '1 ** RA'");
|
||||
py_run!(py, c, "assert 1 @ c == '1 @ RA'");
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct RichComparisons {}
|
||||
|
||||
#[pyproto]
|
||||
impl PyObjectProtocol for RichComparisons {
|
||||
fn __repr__(&self) -> &'static str {
|
||||
"RC"
|
||||
}
|
||||
|
||||
fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> String {
|
||||
match op {
|
||||
CompareOp::Lt => format!("{} < {:?}", self.__repr__(), other),
|
||||
CompareOp::Le => format!("{} <= {:?}", self.__repr__(), other),
|
||||
CompareOp::Eq => format!("{} == {:?}", self.__repr__(), other),
|
||||
CompareOp::Ne => format!("{} != {:?}", self.__repr__(), other),
|
||||
CompareOp::Gt => format!("{} > {:?}", self.__repr__(), other),
|
||||
CompareOp::Ge => format!("{} >= {:?}", self.__repr__(), other),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct RichComparisons2 {}
|
||||
|
||||
#[pyproto]
|
||||
impl PyObjectProtocol for RichComparisons2 {
|
||||
fn __repr__(&self) -> &'static str {
|
||||
"RC2"
|
||||
}
|
||||
|
||||
fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyObject {
|
||||
match op {
|
||||
CompareOp::Eq => true.into_py(other.py()),
|
||||
CompareOp::Ne => false.into_py(other.py()),
|
||||
_ => other.py().NotImplemented(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rich_comparisons() {
|
||||
Python::with_gil(|py| {
|
||||
let c = PyCell::new(py, RichComparisons {}).unwrap();
|
||||
py_run!(py, c, "assert (c < c) == 'RC < RC'");
|
||||
py_run!(py, c, "assert (c < 1) == 'RC < 1'");
|
||||
py_run!(py, c, "assert (1 < c) == 'RC > 1'");
|
||||
py_run!(py, c, "assert (c <= c) == 'RC <= RC'");
|
||||
py_run!(py, c, "assert (c <= 1) == 'RC <= 1'");
|
||||
py_run!(py, c, "assert (1 <= c) == 'RC >= 1'");
|
||||
py_run!(py, c, "assert (c == c) == 'RC == RC'");
|
||||
py_run!(py, c, "assert (c == 1) == 'RC == 1'");
|
||||
py_run!(py, c, "assert (1 == c) == 'RC == 1'");
|
||||
py_run!(py, c, "assert (c != c) == 'RC != RC'");
|
||||
py_run!(py, c, "assert (c != 1) == 'RC != 1'");
|
||||
py_run!(py, c, "assert (1 != c) == 'RC != 1'");
|
||||
py_run!(py, c, "assert (c > c) == 'RC > RC'");
|
||||
py_run!(py, c, "assert (c > 1) == 'RC > 1'");
|
||||
py_run!(py, c, "assert (1 > c) == 'RC < 1'");
|
||||
py_run!(py, c, "assert (c >= c) == 'RC >= RC'");
|
||||
py_run!(py, c, "assert (c >= 1) == 'RC >= 1'");
|
||||
py_run!(py, c, "assert (1 >= c) == 'RC <= 1'");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rich_comparisons_python_3_type_error() {
|
||||
Python::with_gil(|py| {
|
||||
let c2 = PyCell::new(py, RichComparisons2 {}).unwrap();
|
||||
py_expect_exception!(py, c2, "c2 < c2", PyTypeError);
|
||||
py_expect_exception!(py, c2, "c2 < 1", PyTypeError);
|
||||
py_expect_exception!(py, c2, "1 < c2", PyTypeError);
|
||||
py_expect_exception!(py, c2, "c2 <= c2", PyTypeError);
|
||||
py_expect_exception!(py, c2, "c2 <= 1", PyTypeError);
|
||||
py_expect_exception!(py, c2, "1 <= c2", PyTypeError);
|
||||
py_run!(py, c2, "assert (c2 == c2) == True");
|
||||
py_run!(py, c2, "assert (c2 == 1) == True");
|
||||
py_run!(py, c2, "assert (1 == c2) == True");
|
||||
py_run!(py, c2, "assert (c2 != c2) == False");
|
||||
py_run!(py, c2, "assert (c2 != 1) == False");
|
||||
py_run!(py, c2, "assert (1 != c2) == False");
|
||||
py_expect_exception!(py, c2, "c2 > c2", PyTypeError);
|
||||
py_expect_exception!(py, c2, "c2 > 1", PyTypeError);
|
||||
py_expect_exception!(py, c2, "1 > c2", PyTypeError);
|
||||
py_expect_exception!(py, c2, "c2 >= c2", PyTypeError);
|
||||
py_expect_exception!(py, c2, "c2 >= 1", PyTypeError);
|
||||
py_expect_exception!(py, c2, "1 >= c2", PyTypeError);
|
||||
});
|
||||
}
|
||||
|
||||
// Checks that binary operations for which the arguments don't match the
|
||||
// required type, return NotImplemented.
|
||||
mod return_not_implemented {
|
||||
use super::*;
|
||||
|
||||
#[pyclass]
|
||||
struct RichComparisonToSelf {}
|
||||
|
||||
#[pyproto]
|
||||
impl<'p> PyObjectProtocol<'p> for RichComparisonToSelf {
|
||||
fn __repr__(&self) -> &'static str {
|
||||
"RC_Self"
|
||||
}
|
||||
|
||||
fn __richcmp__(&self, other: PyRef<'p, Self>, _op: CompareOp) -> PyObject {
|
||||
other.py().None()
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl<'p> PyNumberProtocol<'p> for RichComparisonToSelf {
|
||||
fn __add__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __sub__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __mul__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __matmul__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __truediv__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __floordiv__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __mod__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __pow__(lhs: &'p PyAny, _other: u8, _modulo: Option<u8>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __lshift__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __rshift__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __divmod__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __and__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __or__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
fn __xor__(lhs: &'p PyAny, _other: PyRef<'p, Self>) -> &'p PyAny {
|
||||
lhs
|
||||
}
|
||||
|
||||
// Inplace assignments
|
||||
fn __iadd__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __isub__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __imul__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __imatmul__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __itruediv__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __ifloordiv__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __imod__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __ipow__(&'p mut self, _other: PyRef<'p, Self>, _modulo: Option<u8>) {}
|
||||
fn __ilshift__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __irshift__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __iand__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __ior__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
fn __ixor__(&'p mut self, _other: PyRef<'p, Self>) {}
|
||||
}
|
||||
|
||||
fn _test_binary_dunder(dunder: &str) {
|
||||
Python::with_gil(|py| {
|
||||
let c2 = PyCell::new(py, RichComparisonToSelf {}).unwrap();
|
||||
py_run!(
|
||||
py,
|
||||
c2,
|
||||
&format!(
|
||||
"class Other: pass\nassert c2.__{}__(Other()) is NotImplemented",
|
||||
dunder
|
||||
)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn _test_binary_operator(operator: &str, dunder: &str) {
|
||||
_test_binary_dunder(dunder);
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let c2 = PyCell::new(py, RichComparisonToSelf {}).unwrap();
|
||||
py_expect_exception!(
|
||||
py,
|
||||
c2,
|
||||
&format!("class Other: pass\nc2 {} Other()", operator),
|
||||
PyTypeError
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
fn _test_inplace_binary_operator(operator: &str, dunder: &str) {
|
||||
_test_binary_operator(operator, dunder);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn equality() {
|
||||
_test_binary_dunder("eq");
|
||||
_test_binary_dunder("ne");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ordering() {
|
||||
_test_binary_operator("<", "lt");
|
||||
_test_binary_operator("<=", "le");
|
||||
_test_binary_operator(">", "gt");
|
||||
_test_binary_operator(">=", "ge");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bitwise() {
|
||||
_test_binary_operator("&", "and");
|
||||
_test_binary_operator("|", "or");
|
||||
_test_binary_operator("^", "xor");
|
||||
_test_binary_operator("<<", "lshift");
|
||||
_test_binary_operator(">>", "rshift");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn arith() {
|
||||
_test_binary_operator("+", "add");
|
||||
_test_binary_operator("-", "sub");
|
||||
_test_binary_operator("*", "mul");
|
||||
_test_binary_operator("@", "matmul");
|
||||
_test_binary_operator("/", "truediv");
|
||||
_test_binary_operator("//", "floordiv");
|
||||
_test_binary_operator("%", "mod");
|
||||
_test_binary_operator("**", "pow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn reverse_arith() {
|
||||
_test_binary_dunder("radd");
|
||||
_test_binary_dunder("rsub");
|
||||
_test_binary_dunder("rmul");
|
||||
_test_binary_dunder("rmatmul");
|
||||
_test_binary_dunder("rtruediv");
|
||||
_test_binary_dunder("rfloordiv");
|
||||
_test_binary_dunder("rmod");
|
||||
_test_binary_dunder("rpow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inplace_bitwise() {
|
||||
_test_inplace_binary_operator("&=", "iand");
|
||||
_test_inplace_binary_operator("|=", "ior");
|
||||
_test_inplace_binary_operator("^=", "ixor");
|
||||
_test_inplace_binary_operator("<<=", "ilshift");
|
||||
_test_inplace_binary_operator(">>=", "irshift");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inplace_arith() {
|
||||
_test_inplace_binary_operator("+=", "iadd");
|
||||
_test_inplace_binary_operator("-=", "isub");
|
||||
_test_inplace_binary_operator("*=", "imul");
|
||||
_test_inplace_binary_operator("@=", "imatmul");
|
||||
_test_inplace_binary_operator("/=", "itruediv");
|
||||
_test_inplace_binary_operator("//=", "ifloordiv");
|
||||
_test_inplace_binary_operator("%=", "imod");
|
||||
_test_inplace_binary_operator("**=", "ipow");
|
||||
}
|
||||
}
|
|
@ -1,131 +0,0 @@
|
|||
#![cfg(feature = "macros")]
|
||||
#![cfg(feature = "pyproto")]
|
||||
#![cfg(any(not(Py_LIMITED_API), Py_3_11))]
|
||||
#![allow(deprecated, elided_lifetimes_in_paths)]
|
||||
|
||||
use pyo3::buffer::PyBuffer;
|
||||
use pyo3::class::PyBufferProtocol;
|
||||
use pyo3::exceptions::PyBufferError;
|
||||
use pyo3::ffi;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::IntoPyDict;
|
||||
use pyo3::AsPyPointer;
|
||||
use std::ffi::CStr;
|
||||
use std::os::raw::{c_int, c_void};
|
||||
use std::ptr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
struct TestBufferClass {
|
||||
vec: Vec<u8>,
|
||||
drop_called: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyBufferProtocol for TestBufferClass {
|
||||
fn bf_getbuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer, flags: c_int) -> PyResult<()> {
|
||||
if view.is_null() {
|
||||
return Err(PyBufferError::new_err("View is null"));
|
||||
}
|
||||
|
||||
if (flags & ffi::PyBUF_WRITABLE) == ffi::PyBUF_WRITABLE {
|
||||
return Err(PyBufferError::new_err("Object is not writable"));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(*view).obj = ffi::_Py_NewRef(slf.as_ptr());
|
||||
}
|
||||
|
||||
let bytes = &slf.vec;
|
||||
|
||||
unsafe {
|
||||
(*view).buf = bytes.as_ptr() as *mut c_void;
|
||||
(*view).len = bytes.len() as isize;
|
||||
(*view).readonly = 1;
|
||||
(*view).itemsize = 1;
|
||||
|
||||
(*view).format = ptr::null_mut();
|
||||
if (flags & ffi::PyBUF_FORMAT) == ffi::PyBUF_FORMAT {
|
||||
let msg = CStr::from_bytes_with_nul(b"B\0").unwrap();
|
||||
(*view).format = msg.as_ptr() as *mut _;
|
||||
}
|
||||
|
||||
(*view).ndim = 1;
|
||||
(*view).shape = ptr::null_mut();
|
||||
if (flags & ffi::PyBUF_ND) == ffi::PyBUF_ND {
|
||||
(*view).shape = &mut (*view).len;
|
||||
}
|
||||
|
||||
(*view).strides = ptr::null_mut();
|
||||
if (flags & ffi::PyBUF_STRIDES) == ffi::PyBUF_STRIDES {
|
||||
(*view).strides = &mut (*view).itemsize;
|
||||
}
|
||||
|
||||
(*view).suboffsets = ptr::null_mut();
|
||||
(*view).internal = ptr::null_mut();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn bf_releasebuffer(_slf: PyRefMut<Self>, _view: *mut ffi::Py_buffer) {}
|
||||
}
|
||||
|
||||
impl Drop for TestBufferClass {
|
||||
fn drop(&mut self) {
|
||||
print!("dropped");
|
||||
self.drop_called.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_buffer() {
|
||||
let drop_called = Arc::new(AtomicBool::new(false));
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let instance = Py::new(
|
||||
py,
|
||||
TestBufferClass {
|
||||
vec: vec![b' ', b'2', b'3'],
|
||||
drop_called: drop_called.clone(),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
let env = [("ob", instance)].into_py_dict(py);
|
||||
py_assert!(py, *env, "bytes(ob) == b' 23'");
|
||||
});
|
||||
|
||||
assert!(drop_called.load(Ordering::Relaxed));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_buffer_referenced() {
|
||||
let drop_called = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let buf: PyBuffer<u8> = {
|
||||
let input = vec![b' ', b'2', b'3'];
|
||||
Python::with_gil(|py| {
|
||||
let instance: PyObject = TestBufferClass {
|
||||
vec: input.clone(),
|
||||
drop_called: drop_called.clone(),
|
||||
}
|
||||
.into_py(py);
|
||||
|
||||
let buf = PyBuffer::<u8>::get(instance.as_ref(py)).unwrap();
|
||||
assert_eq!(buf.to_vec(py).unwrap(), input);
|
||||
drop(instance);
|
||||
buf
|
||||
})
|
||||
};
|
||||
|
||||
assert!(!drop_called.load(Ordering::Relaxed));
|
||||
|
||||
Python::with_gil(|_| {
|
||||
drop(buf);
|
||||
});
|
||||
|
||||
assert!(drop_called.load(Ordering::Relaxed));
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
#![cfg(feature = "macros")]
|
||||
#![cfg(feature = "pyproto")]
|
||||
#![allow(deprecated, elided_lifetimes_in_paths)]
|
||||
|
||||
use pyo3::class::PyGCProtocol;
|
||||
use pyo3::class::PyTraverseError;
|
||||
use pyo3::class::PyVisit;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::{py_run, AsPyPointer, PyCell, PyTryInto, PyTypeInfo};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
mod common;
|
||||
|
||||
#[pyclass(freelist = 2)]
|
||||
struct ClassWithFreelist {}
|
||||
|
||||
#[test]
|
||||
fn class_with_freelist() {
|
||||
let ptr = Python::with_gil(|py| {
|
||||
let inst = Py::new(py, ClassWithFreelist {}).unwrap();
|
||||
let _inst2 = Py::new(py, ClassWithFreelist {}).unwrap();
|
||||
let ptr = inst.as_ptr();
|
||||
drop(inst);
|
||||
ptr
|
||||
});
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let inst3 = Py::new(py, ClassWithFreelist {}).unwrap();
|
||||
assert_eq!(ptr, inst3.as_ptr());
|
||||
|
||||
let inst4 = Py::new(py, ClassWithFreelist {}).unwrap();
|
||||
assert_ne!(ptr, inst4.as_ptr())
|
||||
});
|
||||
}
|
||||
|
||||
struct TestDropCall {
|
||||
drop_called: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
impl Drop for TestDropCall {
|
||||
fn drop(&mut self) {
|
||||
self.drop_called.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[pyclass]
|
||||
struct DataIsDropped {
|
||||
member1: TestDropCall,
|
||||
member2: TestDropCall,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn data_is_dropped() {
|
||||
let drop_called1 = Arc::new(AtomicBool::new(false));
|
||||
let drop_called2 = Arc::new(AtomicBool::new(false));
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let data_is_dropped = DataIsDropped {
|
||||
member1: TestDropCall {
|
||||
drop_called: Arc::clone(&drop_called1),
|
||||
},
|
||||
member2: TestDropCall {
|
||||
drop_called: Arc::clone(&drop_called2),
|
||||
},
|
||||
};
|
||||
let inst = Py::new(py, data_is_dropped).unwrap();
|
||||
assert!(!drop_called1.load(Ordering::Relaxed));
|
||||
assert!(!drop_called2.load(Ordering::Relaxed));
|
||||
drop(inst);
|
||||
});
|
||||
|
||||
assert!(drop_called1.load(Ordering::Relaxed));
|
||||
assert!(drop_called2.load(Ordering::Relaxed));
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[pyclass]
|
||||
struct GcIntegration {
|
||||
self_ref: PyObject,
|
||||
dropped: TestDropCall,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyGCProtocol for GcIntegration {
|
||||
fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||
visit.call(&self.self_ref)
|
||||
}
|
||||
|
||||
fn __clear__(&mut self) {
|
||||
Python::with_gil(|py| {
|
||||
self.self_ref = py.None();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gc_integration() {
|
||||
let drop_called = Arc::new(AtomicBool::new(false));
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let inst = PyCell::new(
|
||||
py,
|
||||
GcIntegration {
|
||||
self_ref: py.None(),
|
||||
dropped: TestDropCall {
|
||||
drop_called: Arc::clone(&drop_called),
|
||||
},
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut borrow = inst.borrow_mut();
|
||||
borrow.self_ref = inst.to_object(py);
|
||||
});
|
||||
|
||||
Python::with_gil(|py| {
|
||||
py.run("import gc; gc.collect()", None, None).unwrap();
|
||||
assert!(drop_called.load(Ordering::Relaxed));
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct GcIntegration2 {}
|
||||
|
||||
#[pyproto]
|
||||
impl PyGCProtocol for GcIntegration2 {
|
||||
fn __traverse__(&self, _visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||
Ok(())
|
||||
}
|
||||
fn __clear__(&mut self) {}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gc_integration2() {
|
||||
Python::with_gil(|py| {
|
||||
let inst = PyCell::new(py, GcIntegration2 {}).unwrap();
|
||||
py_run!(py, inst, "import gc; assert inst in gc.get_objects()");
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass(subclass)]
|
||||
struct BaseClassWithDrop {
|
||||
data: Option<Arc<AtomicBool>>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl BaseClassWithDrop {
|
||||
#[new]
|
||||
fn new() -> BaseClassWithDrop {
|
||||
BaseClassWithDrop { data: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BaseClassWithDrop {
|
||||
fn drop(&mut self) {
|
||||
if let Some(data) = &self.data {
|
||||
data.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyclass(extends = BaseClassWithDrop)]
|
||||
struct SubClassWithDrop {
|
||||
data: Option<Arc<AtomicBool>>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl SubClassWithDrop {
|
||||
#[new]
|
||||
fn new() -> (Self, BaseClassWithDrop) {
|
||||
(
|
||||
SubClassWithDrop { data: None },
|
||||
BaseClassWithDrop { data: None },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SubClassWithDrop {
|
||||
fn drop(&mut self) {
|
||||
if let Some(data) = &self.data {
|
||||
data.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inheritance_with_new_methods_with_drop() {
|
||||
let drop_called1 = Arc::new(AtomicBool::new(false));
|
||||
let drop_called2 = Arc::new(AtomicBool::new(false));
|
||||
|
||||
Python::with_gil(|py| {
|
||||
let _typebase = py.get_type::<BaseClassWithDrop>();
|
||||
let typeobj = py.get_type::<SubClassWithDrop>();
|
||||
let inst = typeobj.call((), None).unwrap();
|
||||
|
||||
let obj: &PyCell<SubClassWithDrop> = PyTryInto::try_into(inst).unwrap();
|
||||
let mut obj_ref_mut = obj.borrow_mut();
|
||||
obj_ref_mut.data = Some(Arc::clone(&drop_called1));
|
||||
let base: &mut BaseClassWithDrop = obj_ref_mut.as_mut();
|
||||
base.data = Some(Arc::clone(&drop_called2));
|
||||
});
|
||||
|
||||
assert!(drop_called1.load(Ordering::Relaxed));
|
||||
assert!(drop_called2.load(Ordering::Relaxed));
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct TraversableClass {
|
||||
traversed: AtomicBool,
|
||||
}
|
||||
|
||||
impl TraversableClass {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
traversed: AtomicBool::new(false),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyGCProtocol for TraversableClass {
|
||||
fn __clear__(&mut self) {}
|
||||
fn __traverse__(&self, _visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||
self.traversed.store(true, Ordering::Relaxed);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get_type_traverse(tp: *mut pyo3::ffi::PyTypeObject) -> Option<pyo3::ffi::traverseproc> {
|
||||
std::mem::transmute(pyo3::ffi::PyType_GetSlot(tp, pyo3::ffi::Py_tp_traverse))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gc_during_borrow() {
|
||||
Python::with_gil(|py| {
|
||||
unsafe {
|
||||
// declare a dummy visitor function
|
||||
extern "C" fn novisit(
|
||||
_object: *mut pyo3::ffi::PyObject,
|
||||
_arg: *mut core::ffi::c_void,
|
||||
) -> std::os::raw::c_int {
|
||||
0
|
||||
}
|
||||
|
||||
// get the traverse function
|
||||
let ty = TraversableClass::type_object(py).as_type_ptr();
|
||||
let traverse = get_type_traverse(ty).unwrap();
|
||||
|
||||
// create an object and check that traversing it works normally
|
||||
// when it's not borrowed
|
||||
let cell = PyCell::new(py, TraversableClass::new()).unwrap();
|
||||
let obj = cell.to_object(py);
|
||||
assert!(!cell.borrow().traversed.load(Ordering::Relaxed));
|
||||
traverse(obj.as_ptr(), novisit, std::ptr::null_mut());
|
||||
assert!(cell.borrow().traversed.load(Ordering::Relaxed));
|
||||
|
||||
// create an object and check that it is not traversed if the GC
|
||||
// is invoked while it is already borrowed mutably
|
||||
let cell2 = PyCell::new(py, TraversableClass::new()).unwrap();
|
||||
let obj2 = cell2.to_object(py);
|
||||
let guard = cell2.borrow_mut();
|
||||
assert!(!guard.traversed.load(Ordering::Relaxed));
|
||||
traverse(obj2.as_ptr(), novisit, std::ptr::null_mut());
|
||||
assert!(!guard.traversed.load(Ordering::Relaxed));
|
||||
drop(guard);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
#![cfg(feature = "macros")]
|
||||
#![cfg(feature = "pyproto")]
|
||||
#![allow(deprecated, elided_lifetimes_in_paths)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use pyo3::exceptions::PyKeyError;
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::py_run;
|
||||
use pyo3::types::IntoPyDict;
|
||||
use pyo3::types::PyList;
|
||||
use pyo3::PyMappingProtocol;
|
||||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
struct Mapping {
|
||||
index: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl Mapping {
|
||||
#[new]
|
||||
fn new(elements: Option<&PyList>) -> PyResult<Self> {
|
||||
if let Some(pylist) = elements {
|
||||
let mut elems = HashMap::with_capacity(pylist.len());
|
||||
for (i, pyelem) in pylist.into_iter().enumerate() {
|
||||
let elem = String::extract(pyelem)?;
|
||||
elems.insert(elem, i);
|
||||
}
|
||||
Ok(Self { index: elems })
|
||||
} else {
|
||||
Ok(Self {
|
||||
index: HashMap::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyMappingProtocol for Mapping {
|
||||
fn __len__(&self) -> usize {
|
||||
self.index.len()
|
||||
}
|
||||
|
||||
fn __getitem__(&self, query: String) -> PyResult<usize> {
|
||||
self.index
|
||||
.get(&query)
|
||||
.copied()
|
||||
.ok_or_else(|| PyKeyError::new_err("unknown key"))
|
||||
}
|
||||
|
||||
fn __setitem__(&mut self, key: String, value: usize) {
|
||||
self.index.insert(key, value);
|
||||
}
|
||||
|
||||
fn __delitem__(&mut self, key: String) -> PyResult<()> {
|
||||
if self.index.remove(&key).is_none() {
|
||||
Err(PyKeyError::new_err("unknown key"))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a dict with `m = Mapping(['1', '2', '3'])`.
|
||||
fn map_dict(py: Python<'_>) -> &pyo3::types::PyDict {
|
||||
let d = [("Mapping", py.get_type::<Mapping>())].into_py_dict(py);
|
||||
py_run!(py, *d, "m = Mapping(['1', '2', '3'])");
|
||||
d
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_getitem() {
|
||||
Python::with_gil(|py| {
|
||||
let d = map_dict(py);
|
||||
|
||||
py_assert!(py, *d, "m['1'] == 0");
|
||||
py_assert!(py, *d, "m['2'] == 1");
|
||||
py_assert!(py, *d, "m['3'] == 2");
|
||||
py_expect_exception!(py, *d, "print(m['4'])", PyKeyError);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_setitem() {
|
||||
Python::with_gil(|py| {
|
||||
let d = map_dict(py);
|
||||
|
||||
py_run!(py, *d, "m['1'] = 4; assert m['1'] == 4");
|
||||
py_run!(py, *d, "m['0'] = 0; assert m['0'] == 0");
|
||||
py_assert!(py, *d, "len(m) == 4");
|
||||
py_expect_exception!(py, *d, "m[0] = 'hello'", PyTypeError);
|
||||
py_expect_exception!(py, *d, "m[0] = -1", PyTypeError);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delitem() {
|
||||
Python::with_gil(|py| {
|
||||
let d = map_dict(py);
|
||||
py_run!(
|
||||
py,
|
||||
*d,
|
||||
"del m['1']; assert len(m) == 2 and m['2'] == 1 and m['3'] == 2"
|
||||
);
|
||||
py_expect_exception!(py, *d, "del m[-1]", PyTypeError);
|
||||
py_expect_exception!(py, *d, "del m['4']", PyKeyError);
|
||||
});
|
||||
}
|
|
@ -1,486 +0,0 @@
|
|||
#![cfg(feature = "macros")]
|
||||
#![cfg(feature = "pyproto")]
|
||||
#![allow(deprecated)]
|
||||
|
||||
use pyo3::class::{
|
||||
PyAsyncProtocol, PyDescrProtocol, PyIterProtocol, PyMappingProtocol, PyObjectProtocol,
|
||||
PySequenceProtocol,
|
||||
};
|
||||
use pyo3::exceptions::{PyIndexError, PyValueError};
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PySlice, PyType};
|
||||
use pyo3::{ffi, py_run, AsPyPointer, PyCell};
|
||||
use std::convert::TryFrom;
|
||||
use std::{isize, iter};
|
||||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
pub struct Len {
|
||||
l: usize,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyMappingProtocol for Len {
|
||||
fn __len__(&self) -> usize {
|
||||
self.l
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn len() {
|
||||
Python::with_gil(|py| {
|
||||
let inst = Py::new(py, Len { l: 10 }).unwrap();
|
||||
py_assert!(py, inst, "len(inst) == 10");
|
||||
unsafe {
|
||||
assert_eq!(ffi::PyObject_Size(inst.as_ptr()), 10);
|
||||
assert_eq!(ffi::PyMapping_Size(inst.as_ptr()), 10);
|
||||
}
|
||||
|
||||
let inst = Py::new(
|
||||
py,
|
||||
Len {
|
||||
l: (isize::MAX as usize) + 1,
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
py_expect_exception!(py, inst, "len(inst)", PyOverflowError);
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct Iterator {
|
||||
iter: Box<dyn iter::Iterator<Item = i32> + Send>,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyIterProtocol for Iterator {
|
||||
fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
|
||||
slf
|
||||
}
|
||||
|
||||
fn __next__(mut slf: PyRefMut<Self>) -> Option<i32> {
|
||||
slf.iter.next()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn iterator() {
|
||||
Python::with_gil(|py| {
|
||||
let inst = Py::new(
|
||||
py,
|
||||
Iterator {
|
||||
iter: Box::new(5..8),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
py_assert!(py, inst, "iter(inst) is inst");
|
||||
py_assert!(py, inst, "list(inst) == [5, 6, 7]");
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct StringMethods {}
|
||||
|
||||
#[pyproto]
|
||||
impl PyObjectProtocol for StringMethods {
|
||||
fn __str__(&self) -> &'static str {
|
||||
"str"
|
||||
}
|
||||
|
||||
fn __repr__(&self) -> &'static str {
|
||||
"repr"
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_methods() {
|
||||
Python::with_gil(|py| {
|
||||
let obj = Py::new(py, StringMethods {}).unwrap();
|
||||
py_assert!(py, obj, "str(obj) == 'str'");
|
||||
py_assert!(py, obj, "repr(obj) == 'repr'");
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct Comparisons {
|
||||
val: i32,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyObjectProtocol for Comparisons {
|
||||
fn __hash__(&self) -> isize {
|
||||
self.val as isize
|
||||
}
|
||||
fn __bool__(&self) -> bool {
|
||||
self.val != 0
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn comparisons() {
|
||||
Python::with_gil(|py| {
|
||||
let zero = Py::new(py, Comparisons { val: 0 }).unwrap();
|
||||
let one = Py::new(py, Comparisons { val: 1 }).unwrap();
|
||||
let ten = Py::new(py, Comparisons { val: 10 }).unwrap();
|
||||
let minus_one = Py::new(py, Comparisons { val: -1 }).unwrap();
|
||||
py_assert!(py, one, "hash(one) == 1");
|
||||
py_assert!(py, ten, "hash(ten) == 10");
|
||||
py_assert!(py, minus_one, "hash(minus_one) == -2");
|
||||
|
||||
py_assert!(py, one, "bool(one) is True");
|
||||
py_assert!(py, zero, "not zero");
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
struct Sequence {
|
||||
fields: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for Sequence {
|
||||
fn default() -> Sequence {
|
||||
let mut fields = vec![];
|
||||
for &s in &["A", "B", "C", "D", "E", "F", "G"] {
|
||||
fields.push(s.to_string());
|
||||
}
|
||||
Sequence { fields }
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PySequenceProtocol for Sequence {
|
||||
fn __len__(&self) -> usize {
|
||||
self.fields.len()
|
||||
}
|
||||
|
||||
fn __getitem__(&self, key: isize) -> PyResult<String> {
|
||||
let idx = usize::try_from(key)?;
|
||||
if let Some(s) = self.fields.get(idx) {
|
||||
Ok(s.clone())
|
||||
} else {
|
||||
Err(PyIndexError::new_err(()))
|
||||
}
|
||||
}
|
||||
|
||||
fn __setitem__(&mut self, idx: isize, value: String) -> PyResult<()> {
|
||||
let idx = usize::try_from(idx)?;
|
||||
if let Some(elem) = self.fields.get_mut(idx) {
|
||||
*elem = value;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PyIndexError::new_err(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sequence() {
|
||||
Python::with_gil(|py| {
|
||||
let c = Py::new(py, Sequence::default()).unwrap();
|
||||
py_assert!(py, c, "list(c) == ['A', 'B', 'C', 'D', 'E', 'F', 'G']");
|
||||
py_assert!(py, c, "c[-1] == 'G'");
|
||||
py_run!(
|
||||
py,
|
||||
c,
|
||||
r#"
|
||||
c[0] = 'H'
|
||||
assert c[0] == 'H'
|
||||
"#
|
||||
);
|
||||
py_expect_exception!(py, c, "c['abc']", PyTypeError);
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
#[derive(Debug)]
|
||||
struct SetItem {
|
||||
key: i32,
|
||||
val: i32,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyMappingProtocol for SetItem {
|
||||
fn __setitem__(&mut self, key: i32, val: i32) {
|
||||
self.key = key;
|
||||
self.val = val;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setitem() {
|
||||
Python::with_gil(|py| {
|
||||
let c = PyCell::new(py, SetItem { key: 0, val: 0 }).unwrap();
|
||||
py_run!(py, c, "c[1] = 2");
|
||||
{
|
||||
let c = c.borrow();
|
||||
assert_eq!(c.key, 1);
|
||||
assert_eq!(c.val, 2);
|
||||
}
|
||||
py_expect_exception!(py, c, "del c[1]", PyNotImplementedError);
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct DelItem {
|
||||
key: i32,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyMappingProtocol<'a> for DelItem {
|
||||
fn __delitem__(&mut self, key: i32) {
|
||||
self.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn delitem() {
|
||||
Python::with_gil(|py| {
|
||||
let c = PyCell::new(py, DelItem { key: 0 }).unwrap();
|
||||
py_run!(py, c, "del c[1]");
|
||||
{
|
||||
let c = c.borrow();
|
||||
assert_eq!(c.key, 1);
|
||||
}
|
||||
py_expect_exception!(py, c, "c[1] = 2", PyNotImplementedError);
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct SetDelItem {
|
||||
val: Option<i32>,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyMappingProtocol for SetDelItem {
|
||||
fn __setitem__(&mut self, _key: i32, val: i32) {
|
||||
self.val = Some(val);
|
||||
}
|
||||
|
||||
fn __delitem__(&mut self, _key: i32) {
|
||||
self.val = None;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn setdelitem() {
|
||||
Python::with_gil(|py| {
|
||||
let c = PyCell::new(py, SetDelItem { val: None }).unwrap();
|
||||
py_run!(py, c, "c[1] = 2");
|
||||
{
|
||||
let c = c.borrow();
|
||||
assert_eq!(c.val, Some(2));
|
||||
}
|
||||
py_run!(py, c, "del c[1]");
|
||||
let c = c.borrow();
|
||||
assert_eq!(c.val, None);
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct Contains {}
|
||||
|
||||
#[pyproto]
|
||||
impl PySequenceProtocol for Contains {
|
||||
fn __contains__(&self, item: i32) -> bool {
|
||||
item >= 0
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contains() {
|
||||
Python::with_gil(|py| {
|
||||
let c = Py::new(py, Contains {}).unwrap();
|
||||
py_run!(py, c, "assert 1 in c");
|
||||
py_run!(py, c, "assert -1 not in c");
|
||||
py_expect_exception!(py, c, "assert 'wrong type' not in c", PyTypeError);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_basics() {
|
||||
Python::with_gil(|py| {
|
||||
let v = PySlice::new(py, 1, 10, 2);
|
||||
let indices = v.indices(100).unwrap();
|
||||
assert_eq!(1, indices.start);
|
||||
assert_eq!(10, indices.stop);
|
||||
assert_eq!(2, indices.step);
|
||||
assert_eq!(5, indices.slicelength);
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct Test {}
|
||||
|
||||
#[pyproto]
|
||||
impl<'p> PyMappingProtocol<'p> for Test {
|
||||
fn __getitem__(&self, idx: &PyAny) -> PyResult<&'static str> {
|
||||
if let Ok(slice) = idx.cast_as::<PySlice>() {
|
||||
let indices = slice.indices(1000)?;
|
||||
if indices.start == 100 && indices.stop == 200 && indices.step == 1 {
|
||||
return Ok("slice");
|
||||
}
|
||||
} else if let Ok(idx) = idx.extract::<isize>() {
|
||||
if idx == 1 {
|
||||
return Ok("int");
|
||||
}
|
||||
}
|
||||
Err(PyValueError::new_err("error"))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cls_impl() {
|
||||
Python::with_gil(|py| {
|
||||
let ob = Py::new(py, Test {}).unwrap();
|
||||
|
||||
py_assert!(py, ob, "ob[1] == 'int'");
|
||||
py_assert!(py, ob, "ob[100:200:1] == 'slice'");
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct ClassWithGetAttr {
|
||||
#[pyo3(get, set)]
|
||||
data: u32,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyObjectProtocol for ClassWithGetAttr {
|
||||
fn __getattr__(&self, _name: &str) -> u32 {
|
||||
self.data * 2
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn getattr_doesnt_override_member() {
|
||||
Python::with_gil(|py| {
|
||||
let inst = PyCell::new(py, ClassWithGetAttr { data: 4 }).unwrap();
|
||||
py_assert!(py, inst, "inst.data == 4");
|
||||
py_assert!(py, inst, "inst.a == 8");
|
||||
});
|
||||
}
|
||||
|
||||
/// Wraps a Python future and yield it once.
|
||||
#[pyclass]
|
||||
struct OnceFuture {
|
||||
future: PyObject,
|
||||
polled: bool,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl OnceFuture {
|
||||
#[new]
|
||||
fn new(future: PyObject) -> Self {
|
||||
OnceFuture {
|
||||
future,
|
||||
polled: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyAsyncProtocol for OnceFuture {
|
||||
fn __await__(slf: PyRef<Self>) -> PyRef<Self> {
|
||||
slf
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyIterProtocol for OnceFuture {
|
||||
fn __iter__(slf: PyRef<Self>) -> PyRef<Self> {
|
||||
slf
|
||||
}
|
||||
fn __next__(mut slf: PyRefMut<Self>) -> Option<PyObject> {
|
||||
if !slf.polled {
|
||||
slf.polled = true;
|
||||
Some(slf.future.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_await() {
|
||||
Python::with_gil(|py| {
|
||||
let once = py.get_type::<OnceFuture>();
|
||||
let source = pyo3::indoc::indoc!(
|
||||
r#"
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
async def main():
|
||||
res = await Once(await asyncio.sleep(0.1))
|
||||
return res
|
||||
# For an odd error similar to https://bugs.python.org/issue38563
|
||||
if sys.platform == "win32" and sys.version_info >= (3, 8, 0):
|
||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||
# get_event_loop can raise an error: https://github.com/PyO3/pyo3/pull/961#issuecomment-645238579
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
assert loop.run_until_complete(main()) is None
|
||||
loop.close()
|
||||
"#
|
||||
);
|
||||
let globals = PyModule::import(py, "__main__").unwrap().dict();
|
||||
globals.set_item("Once", once).unwrap();
|
||||
py.run(source, Some(globals), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
/// Increment the count when `__get__` is called.
|
||||
#[pyclass]
|
||||
struct DescrCounter {
|
||||
#[pyo3(get)]
|
||||
count: usize,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl DescrCounter {
|
||||
#[new]
|
||||
fn new() -> Self {
|
||||
DescrCounter { count: 0 }
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PyDescrProtocol for DescrCounter {
|
||||
fn __get__(
|
||||
mut slf: PyRefMut<Self>,
|
||||
_instance: &PyAny,
|
||||
_owner: Option<&PyType>,
|
||||
) -> PyRefMut<Self> {
|
||||
slf.count += 1;
|
||||
slf
|
||||
}
|
||||
fn __set__(_slf: PyRef<Self>, _instance: &PyAny, mut new_value: PyRefMut<Self>) {
|
||||
new_value.count = _slf.count;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn descr_getset() {
|
||||
Python::with_gil(|py| {
|
||||
let counter = py.get_type::<DescrCounter>();
|
||||
let source = pyo3::indoc::indoc!(
|
||||
r#"
|
||||
class Class:
|
||||
counter = Counter()
|
||||
c = Class()
|
||||
c.counter # count += 1
|
||||
assert c.counter.count == 2
|
||||
c.counter = Counter()
|
||||
assert c.counter.count == 3
|
||||
"#
|
||||
);
|
||||
let globals = PyModule::import(py, "__main__").unwrap().dict();
|
||||
globals.set_item("Counter", counter).unwrap();
|
||||
py.run(source, Some(globals), None)
|
||||
.map_err(|e| e.print(py))
|
||||
.unwrap();
|
||||
});
|
||||
}
|
|
@ -1,298 +0,0 @@
|
|||
#![cfg(feature = "macros")]
|
||||
#![cfg(feature = "pyproto")]
|
||||
#![allow(deprecated)]
|
||||
|
||||
use pyo3::class::PySequenceProtocol;
|
||||
use pyo3::exceptions::{PyIndexError, PyValueError};
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{IntoPyDict, PyList};
|
||||
|
||||
use pyo3::py_run;
|
||||
|
||||
mod common;
|
||||
|
||||
#[pyclass]
|
||||
struct ByteSequence {
|
||||
elements: Vec<u8>,
|
||||
}
|
||||
|
||||
#[pymethods]
|
||||
impl ByteSequence {
|
||||
#[new]
|
||||
fn new(elements: Option<&PyList>) -> PyResult<Self> {
|
||||
if let Some(pylist) = elements {
|
||||
let mut elems = Vec::with_capacity(pylist.len());
|
||||
for pyelem in pylist {
|
||||
let elem = u8::extract(pyelem)?;
|
||||
elems.push(elem);
|
||||
}
|
||||
Ok(Self { elements: elems })
|
||||
} else {
|
||||
Ok(Self {
|
||||
elements: Vec::new(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PySequenceProtocol for ByteSequence {
|
||||
fn __len__(&self) -> usize {
|
||||
self.elements.len()
|
||||
}
|
||||
|
||||
fn __getitem__(&self, idx: isize) -> PyResult<u8> {
|
||||
self.elements
|
||||
.get(idx as usize)
|
||||
.copied()
|
||||
.ok_or_else(|| PyIndexError::new_err("list index out of range"))
|
||||
}
|
||||
|
||||
fn __setitem__(&mut self, idx: isize, value: u8) {
|
||||
self.elements[idx as usize] = value;
|
||||
}
|
||||
|
||||
fn __delitem__(&mut self, idx: isize) -> PyResult<()> {
|
||||
if (idx < self.elements.len() as isize) && (idx >= 0) {
|
||||
self.elements.remove(idx as usize);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(PyIndexError::new_err("list index out of range"))
|
||||
}
|
||||
}
|
||||
|
||||
fn __contains__(&self, other: &PyAny) -> bool {
|
||||
match u8::extract(other) {
|
||||
Ok(x) => self.elements.contains(&x),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn __concat__(&self, other: PyRef<'p, Self>) -> Self {
|
||||
let mut elements = self.elements.clone();
|
||||
elements.extend_from_slice(&other.elements);
|
||||
Self { elements }
|
||||
}
|
||||
|
||||
fn __repeat__(&self, count: isize) -> PyResult<Self> {
|
||||
if count >= 0 {
|
||||
let mut elements = Vec::with_capacity(self.elements.len() * count as usize);
|
||||
for _ in 0..count {
|
||||
elements.extend(&self.elements);
|
||||
}
|
||||
Ok(Self { elements })
|
||||
} else {
|
||||
Err(PyValueError::new_err("invalid repeat count"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a dict with `s = ByteSequence([1, 2, 3])`.
|
||||
fn seq_dict(py: Python<'_>) -> &pyo3::types::PyDict {
|
||||
let d = [("ByteSequence", py.get_type::<ByteSequence>())].into_py_dict(py);
|
||||
// Though we can construct `s` in Rust, let's test `__new__` works.
|
||||
py_run!(py, *d, "s = ByteSequence([1, 2, 3])");
|
||||
d
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_getitem() {
|
||||
Python::with_gil(|py| {
|
||||
let d = seq_dict(py);
|
||||
|
||||
py_assert!(py, *d, "s[0] == 1");
|
||||
py_assert!(py, *d, "s[1] == 2");
|
||||
py_assert!(py, *d, "s[2] == 3");
|
||||
py_expect_exception!(py, *d, "print(s[-4])", PyIndexError);
|
||||
py_expect_exception!(py, *d, "print(s[4])", PyIndexError);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_setitem() {
|
||||
Python::with_gil(|py| {
|
||||
let d = seq_dict(py);
|
||||
|
||||
py_run!(py, *d, "s[0] = 4; assert list(s) == [4, 2, 3]");
|
||||
py_expect_exception!(py, *d, "s[0] = 'hello'", PyTypeError);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_delitem() {
|
||||
Python::with_gil(|py| {
|
||||
let d = [("ByteSequence", py.get_type::<ByteSequence>())].into_py_dict(py);
|
||||
|
||||
py_run!(
|
||||
py,
|
||||
*d,
|
||||
"s = ByteSequence([1, 2, 3]); del s[0]; assert list(s) == [2, 3]"
|
||||
);
|
||||
py_run!(
|
||||
py,
|
||||
*d,
|
||||
"s = ByteSequence([1, 2, 3]); del s[1]; assert list(s) == [1, 3]"
|
||||
);
|
||||
py_run!(
|
||||
py,
|
||||
*d,
|
||||
"s = ByteSequence([1, 2, 3]); del s[-1]; assert list(s) == [1, 2]"
|
||||
);
|
||||
py_run!(
|
||||
py,
|
||||
*d,
|
||||
"s = ByteSequence([1, 2, 3]); del s[-2]; assert list(s) == [1, 3]"
|
||||
);
|
||||
py_expect_exception!(
|
||||
py,
|
||||
*d,
|
||||
"s = ByteSequence([1, 2, 3]); del s[-4]; print(list(s))",
|
||||
PyIndexError
|
||||
);
|
||||
py_expect_exception!(
|
||||
py,
|
||||
*d,
|
||||
"s = ByteSequence([1, 2, 3]); del s[4]",
|
||||
PyIndexError
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains() {
|
||||
Python::with_gil(|py| {
|
||||
let d = seq_dict(py);
|
||||
|
||||
py_assert!(py, *d, "1 in s");
|
||||
py_assert!(py, *d, "2 in s");
|
||||
py_assert!(py, *d, "3 in s");
|
||||
py_assert!(py, *d, "4 not in s");
|
||||
py_assert!(py, *d, "'hello' not in s");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_concat() {
|
||||
Python::with_gil(|py| {
|
||||
let d = seq_dict(py);
|
||||
|
||||
py_run!(
|
||||
py,
|
||||
*d,
|
||||
"s1 = ByteSequence([1, 2]); s2 = ByteSequence([3, 4]); assert list(s1 + s2) == [1, 2, 3, 4]"
|
||||
);
|
||||
py_expect_exception!(
|
||||
py,
|
||||
*d,
|
||||
"s1 = ByteSequence([1, 2]); s2 = 'hello'; s1 + s2",
|
||||
PyTypeError
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inplace_concat() {
|
||||
Python::with_gil(|py| {
|
||||
let d = seq_dict(py);
|
||||
|
||||
py_run!(
|
||||
py,
|
||||
*d,
|
||||
"s += ByteSequence([4, 5]); assert list(s) == [1, 2, 3, 4, 5]"
|
||||
);
|
||||
py_expect_exception!(py, *d, "s += 'hello'", PyTypeError);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repeat() {
|
||||
Python::with_gil(|py| {
|
||||
let d = seq_dict(py);
|
||||
|
||||
py_run!(py, *d, "s2 = s * 2; assert list(s2) == [1, 2, 3, 1, 2, 3]");
|
||||
py_expect_exception!(py, *d, "s2 = s * -1", PyValueError);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_inplace_repeat() {
|
||||
Python::with_gil(|py| {
|
||||
let d = [("ByteSequence", py.get_type::<ByteSequence>())].into_py_dict(py);
|
||||
|
||||
py_run!(
|
||||
py,
|
||||
*d,
|
||||
"s = ByteSequence([1, 2]); s *= 3; assert list(s) == [1, 2, 1, 2, 1, 2]"
|
||||
);
|
||||
py_expect_exception!(py, *d, "s = ByteSequence([1, 2]); s *= -1", PyValueError);
|
||||
});
|
||||
}
|
||||
|
||||
// Check that #[pyo3(get, set)] works correctly for Vec<PyObject>
|
||||
|
||||
#[pyclass]
|
||||
struct GenericList {
|
||||
#[pyo3(get, set)]
|
||||
items: Vec<PyObject>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_list_get() {
|
||||
Python::with_gil(|py| {
|
||||
let list: PyObject = GenericList {
|
||||
items: [1, 2, 3].iter().map(|i| i.to_object(py)).collect(),
|
||||
}
|
||||
.into_py(py);
|
||||
|
||||
py_assert!(py, list, "list.items == [1, 2, 3]");
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generic_list_set() {
|
||||
Python::with_gil(|py| {
|
||||
let list = PyCell::new(py, GenericList { items: vec![] }).unwrap();
|
||||
|
||||
py_run!(py, list, "list.items = [1, 2, 3]");
|
||||
assert!(list
|
||||
.borrow()
|
||||
.items
|
||||
.iter()
|
||||
.zip(&[1u32, 2, 3])
|
||||
.all(|(a, b)| a.as_ref(py).eq(&b.into_py(py)).unwrap()));
|
||||
});
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
struct OptionList {
|
||||
#[pyo3(get, set)]
|
||||
items: Vec<Option<i64>>,
|
||||
}
|
||||
|
||||
#[pyproto]
|
||||
impl PySequenceProtocol for OptionList {
|
||||
fn __getitem__(&self, idx: isize) -> PyResult<Option<i64>> {
|
||||
match self.items.get(idx as usize) {
|
||||
Some(x) => Ok(*x),
|
||||
None => Err(PyIndexError::new_err("Index out of bounds")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_option_list_get() {
|
||||
// Regression test for #798
|
||||
Python::with_gil(|py| {
|
||||
let list = PyCell::new(
|
||||
py,
|
||||
OptionList {
|
||||
items: vec![Some(1), None],
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
py_assert!(py, list, "list[0] == 1");
|
||||
py_assert!(py, list, "list[1] == None");
|
||||
py_expect_exception!(py, list, "list[2]", PyIndexError);
|
||||
});
|
||||
}
|
|
@ -1,17 +1,17 @@
|
|||
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
||||
--> tests/ui/abi3_nativetype_inheritance.rs:5:1
|
||||
|
|
||||
5 | #[pyclass(extends=PyDict)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict`
|
||||
|
|
||||
= help: the trait `PyClass` is implemented for `TestClass`
|
||||
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
|
||||
--> tests/ui/abi3_nativetype_inheritance.rs:5:1
|
||||
|
|
||||
5 | #[pyclass(extends=PyDict)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict`
|
||||
|
|
||||
= help: the trait `PyClass` is implemented for `TestClass`
|
||||
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
|
||||
note: required by a bound in `ThreadCheckerInherited`
|
||||
--> src/impl_/pyclass.rs
|
||||
|
|
||||
| pub struct ThreadCheckerInherited<T: PyClass + Send, U: PyClassBaseType>(
|
||||
| ^^^^^^^^^^^^^^^ required by this bound in `ThreadCheckerInherited`
|
||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
--> src/impl_/pyclass.rs
|
||||
|
|
||||
| pub struct ThreadCheckerInherited<T: PyClass + Send, U: PyClassBaseType>(
|
||||
| ^^^^^^^^^^^^^^^ required by this bound in `ThreadCheckerInherited`
|
||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
||||
--> tests/ui/abi3_nativetype_inheritance.rs:5:1
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
error[E0277]: `Rc<i32>` cannot be sent between threads safely
|
||||
--> tests/ui/pyclass_send.rs:4:1
|
||||
|
|
||||
4 | #[pyclass]
|
||||
| ^^^^^^^^^^ `Rc<i32>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `NotThreadSafe`, the trait `Send` is not implemented for `Rc<i32>`
|
||||
--> tests/ui/pyclass_send.rs:4:1
|
||||
|
|
||||
4 | #[pyclass]
|
||||
| ^^^^^^^^^^ `Rc<i32>` cannot be sent between threads safely
|
||||
|
|
||||
= help: within `NotThreadSafe`, the trait `Send` is not implemented for `Rc<i32>`
|
||||
note: required because it appears within the type `NotThreadSafe`
|
||||
--> tests/ui/pyclass_send.rs:5:8
|
||||
|
|
||||
5 | struct NotThreadSafe {
|
||||
| ^^^^^^^^^^^^^
|
||||
--> tests/ui/pyclass_send.rs:5:8
|
||||
|
|
||||
5 | struct NotThreadSafe {
|
||||
| ^^^^^^^^^^^^^
|
||||
note: required by a bound in `ThreadCheckerStub`
|
||||
--> src/impl_/pyclass.rs
|
||||
|
|
||||
| pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||
| ^^^^ required by this bound in `ThreadCheckerStub`
|
||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
--> src/impl_/pyclass.rs
|
||||
|
|
||||
| pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||
| ^^^^ required by this bound in `ThreadCheckerStub`
|
||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
Loading…
Reference in New Issue