Compare commits
14 Commits
master
...
release-0.
Author | SHA1 | Date |
---|---|---|
Paul Stemmet | 1a65112ba7 | |
David Hewitt | a646a820fd | |
David Hewitt | bd15f92a56 | |
Adam Reichold | 4f7c7065c2 | |
Adam Reichold | 3f6faf00ff | |
messense | 4e13c0eae8 | |
Icxolu | e501377587 | |
Icxolu | fd18955da8 | |
Liam | e174a04bb3 | |
dependabot[bot] | a8abe508ba | |
Jeong, Heon | 68d19738e7 | |
Joseph Perez | b8ec43e469 | |
Icxolu | 0b888cb934 | |
David Hewitt | e4cc98607e |
|
@ -46,7 +46,7 @@ jobs:
|
||||||
|
|
||||||
- name: Deploy docs and the guide
|
- name: Deploy docs and the guide
|
||||||
if: ${{ github.event_name == 'release' }}
|
if: ${{ github.event_name == 'release' }}
|
||||||
uses: peaceiris/actions-gh-pages@v3
|
uses: peaceiris/actions-gh-pages@v4
|
||||||
with:
|
with:
|
||||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
publish_dir: ./target/guide/
|
publish_dir: ./target/guide/
|
||||||
|
|
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -10,6 +10,20 @@ To see unreleased changes, please see the [CHANGELOG on the main branch guide](h
|
||||||
|
|
||||||
<!-- towncrier release notes start -->
|
<!-- towncrier release notes start -->
|
||||||
|
|
||||||
|
## [0.21.2] - 2024-04-16
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Deprecate the `PySet::empty()` gil-ref constructor. [#4082](https://github.com/PyO3/pyo3/pull/4082)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix compile error for `async fn` in `#[pymethods]` with a `&self` receiver and more than one additional argument. [#4035](https://github.com/PyO3/pyo3/pull/4035)
|
||||||
|
- Improve error message for wrong receiver type in `__traverse__`. [#4045](https://github.com/PyO3/pyo3/pull/4045)
|
||||||
|
- Fix compile error when exporting a `#[pyclass]` living in a different Rust module using the `experimental-declarative-modules` feature. [#4054](https://github.com/PyO3/pyo3/pull/4054)
|
||||||
|
- Fix `missing_docs` lint triggering on documented `#[pymodule]` functions. [#4067](https://github.com/PyO3/pyo3/pull/4067)
|
||||||
|
- Fix undefined symbol errors for extension modules on AIX (by linking `libpython`). [#4073](https://github.com/PyO3/pyo3/pull/4073)
|
||||||
|
|
||||||
## [0.21.1] - 2024-04-01
|
## [0.21.1] - 2024-04-01
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -1731,7 +1745,8 @@ Yanked
|
||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|
||||||
[Unreleased]: https://github.com/pyo3/pyo3/compare/v0.21.1...HEAD
|
[Unreleased]: https://github.com/pyo3/pyo3/compare/v0.21.2...HEAD
|
||||||
|
[0.21.2]: https://github.com/pyo3/pyo3/compare/v0.21.1...v0.21.2
|
||||||
[0.21.1]: https://github.com/pyo3/pyo3/compare/v0.21.0...v0.21.1
|
[0.21.1]: https://github.com/pyo3/pyo3/compare/v0.21.0...v0.21.1
|
||||||
[0.21.0]: https://github.com/pyo3/pyo3/compare/v0.20.3...v0.21.0
|
[0.21.0]: https://github.com/pyo3/pyo3/compare/v0.20.3...v0.21.0
|
||||||
[0.21.0-beta.0]: https://github.com/pyo3/pyo3/compare/v0.20.3...v0.21.0-beta.0
|
[0.21.0-beta.0]: https://github.com/pyo3/pyo3/compare/v0.20.3...v0.21.0-beta.0
|
||||||
|
|
11
Cargo.toml
11
Cargo.toml
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3"
|
name = "pyo3"
|
||||||
version = "0.21.1"
|
version = "0.21.2"
|
||||||
description = "Bindings to Python interpreter"
|
description = "Bindings to Python interpreter"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -22,10 +22,10 @@ memoffset = "0.9"
|
||||||
portable-atomic = "1.0"
|
portable-atomic = "1.0"
|
||||||
|
|
||||||
# ffi bindings to the python interpreter, split into a separate crate so they can be used independently
|
# ffi bindings to the python interpreter, split into a separate crate so they can be used independently
|
||||||
pyo3-ffi = { path = "pyo3-ffi", version = "=0.21.1" }
|
pyo3-ffi = { path = "pyo3-ffi", version = "=0.21.2" }
|
||||||
|
|
||||||
# support crates for macros feature
|
# support crates for macros feature
|
||||||
pyo3-macros = { path = "pyo3-macros", version = "=0.21.1", optional = true }
|
pyo3-macros = { path = "pyo3-macros", version = "=0.21.2", optional = true }
|
||||||
indoc = { version = "2.0.1", optional = true }
|
indoc = { version = "2.0.1", optional = true }
|
||||||
unindent = { version = "0.2.1", optional = true }
|
unindent = { version = "0.2.1", optional = true }
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ rayon = "1.6.1"
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
pyo3-build-config = { path = "pyo3-build-config", version = "=0.21.1", features = ["resolve-config"] }
|
pyo3-build-config = { path = "pyo3-build-config", version = "=0.21.2", features = ["resolve-config"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["macros"]
|
default = ["macros"]
|
||||||
|
@ -109,6 +109,9 @@ gil-refs = []
|
||||||
# Optimizes PyObject to Vec conversion and so on.
|
# Optimizes PyObject to Vec conversion and so on.
|
||||||
nightly = []
|
nightly = []
|
||||||
|
|
||||||
|
# Disables the checks for use in subinterpreters.
|
||||||
|
unsafe-allow-subinterpreters = []
|
||||||
|
|
||||||
# Activates all additional features
|
# Activates all additional features
|
||||||
# This is mostly intended for testing purposes - activating *all* of these isn't particularly useful.
|
# This is mostly intended for testing purposes - activating *all* of these isn't particularly useful.
|
||||||
full = [
|
full = [
|
||||||
|
|
|
@ -190,7 +190,7 @@ Second, there is a Python-based benchmark contained in the `pytests` subdirector
|
||||||
|
|
||||||
You can view what code is and isn't covered by PyO3's tests. We aim to have 100% coverage - please check coverage and add tests if you notice a lack of coverage!
|
You can view what code is and isn't covered by PyO3's tests. We aim to have 100% coverage - please check coverage and add tests if you notice a lack of coverage!
|
||||||
|
|
||||||
- First, ensure the llmv-cov cargo plugin is installed. You may need to run the plugin through cargo once before using it with `nox`.
|
- First, ensure the llvm-cov cargo plugin is installed. You may need to run the plugin through cargo once before using it with `nox`.
|
||||||
```shell
|
```shell
|
||||||
cargo install cargo-llvm-cov
|
cargo install cargo-llvm-cov
|
||||||
cargo llvm-cov
|
cargo llvm-cov
|
||||||
|
|
|
@ -68,7 +68,7 @@ name = "string_sum"
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pyo3 = { version = "0.21.1", features = ["extension-module"] }
|
pyo3 = { version = "0.21.2", features = ["extension-module"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
**`src/lib.rs`**
|
**`src/lib.rs`**
|
||||||
|
@ -137,7 +137,7 @@ Start a new project with `cargo new` and add `pyo3` to the `Cargo.toml` like th
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies.pyo3]
|
[dependencies.pyo3]
|
||||||
version = "0.21.1"
|
version = "0.21.2"
|
||||||
features = ["auto-initialize"]
|
features = ["auto-initialize"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
variable::set("PYO3_VERSION", "0.21.1");
|
variable::set("PYO3_VERSION", "0.21.2");
|
||||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/pyproject.toml", "pyproject.toml");
|
file::rename(".template/pyproject.toml", "pyproject.toml");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
variable::set("PYO3_VERSION", "0.21.1");
|
variable::set("PYO3_VERSION", "0.21.2");
|
||||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/pyproject.toml", "pyproject.toml");
|
file::rename(".template/pyproject.toml", "pyproject.toml");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
variable::set("PYO3_VERSION", "0.21.1");
|
variable::set("PYO3_VERSION", "0.21.2");
|
||||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/plugin_api/Cargo.toml", "plugin_api/Cargo.toml");
|
file::rename(".template/plugin_api/Cargo.toml", "plugin_api/Cargo.toml");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
variable::set("PYO3_VERSION", "0.21.1");
|
variable::set("PYO3_VERSION", "0.21.2");
|
||||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/setup.cfg", "setup.cfg");
|
file::rename(".template/setup.cfg", "setup.cfg");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
variable::set("PYO3_VERSION", "0.21.1");
|
variable::set("PYO3_VERSION", "0.21.2");
|
||||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/pyproject.toml", "pyproject.toml");
|
file::rename(".template/pyproject.toml", "pyproject.toml");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -998,6 +998,44 @@ impl MyClass {
|
||||||
Note that `text_signature` on `#[new]` is not compatible with compilation in
|
Note that `text_signature` on `#[new]` is not compatible with compilation in
|
||||||
`abi3` mode until Python 3.10 or greater.
|
`abi3` mode until Python 3.10 or greater.
|
||||||
|
|
||||||
|
### Method receivers and lifetime elision
|
||||||
|
|
||||||
|
PyO3 supports writing instance methods using the normal method receivers for shared `&self` and unique `&mut self` references. This interacts with [lifetime elision][lifetime-elision] insofar as the lifetime of a such a receiver is assigned to all elided output lifetime parameters.
|
||||||
|
|
||||||
|
This is a good default for general Rust code where return values are more likely to borrow from the receiver than from the other arguments, if they contain any lifetimes at all. However, when returning bound references `Bound<'py, T>` in PyO3-based code, the GIL lifetime `'py` should usually be derived from a GIL token `py: Python<'py>` passed as an argument instead of the receiver.
|
||||||
|
|
||||||
|
Specifically, signatures like
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
fn frobnicate(&self, py: Python) -> Bound<Foo>;
|
||||||
|
```
|
||||||
|
|
||||||
|
will not work as they are inferred as
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
fn frobnicate<'a, 'py>(&'a self, py: Python<'py>) -> Bound<'a, Foo>;
|
||||||
|
```
|
||||||
|
|
||||||
|
instead of the intended
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
fn frobnicate<'a, 'py>(&'a self, py: Python<'py>) -> Bound<'py, Foo>;
|
||||||
|
```
|
||||||
|
|
||||||
|
and should usually be written as
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
fn frobnicate<'py>(&self, py: Python<'py>) -> Bound<'py, Foo>;
|
||||||
|
```
|
||||||
|
|
||||||
|
The same problem does not exist for `#[pyfunction]`s as the special case for receiver lifetimes does not apply and indeed a signature like
|
||||||
|
|
||||||
|
```rust,ignore
|
||||||
|
fn frobnicate(bar: &Bar, py: Python) -> Bound<Foo>;
|
||||||
|
```
|
||||||
|
|
||||||
|
will yield compiler error [E0106 "missing lifetime specifier"][compiler-error-e0106].
|
||||||
|
|
||||||
## `#[pyclass]` enums
|
## `#[pyclass]` enums
|
||||||
|
|
||||||
Enum support in PyO3 comes in two flavors, depending on what kind of variants the enum has: simple and complex.
|
Enum support in PyO3 comes in two flavors, depending on what kind of variants the enum has: simple and complex.
|
||||||
|
@ -1329,3 +1367,6 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
|
||||||
[classattr]: https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables
|
[classattr]: https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables
|
||||||
|
|
||||||
[`multiple-pymethods`]: features.md#multiple-pymethods
|
[`multiple-pymethods`]: features.md#multiple-pymethods
|
||||||
|
|
||||||
|
[lifetime-elision]: https://doc.rust-lang.org/reference/lifetime-elision.html
|
||||||
|
[compiler-error-e0106]: https://doc.rust-lang.org/error_codes/E0106.html
|
||||||
|
|
|
@ -120,7 +120,7 @@ Export an async function that makes use of `async-std`:
|
||||||
use pyo3::{prelude::*, wrap_pyfunction};
|
use pyo3::{prelude::*, wrap_pyfunction};
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn rust_sleep(py: Python<'_>) -> PyResult<&Bound<'_, PyAny>>> {
|
fn rust_sleep(py: Python<'_>) -> PyResult<&Bound<'_, PyAny>> {
|
||||||
pyo3_asyncio::async_std::future_into_py(py, async {
|
pyo3_asyncio::async_std::future_into_py(py, async {
|
||||||
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
|
async_std::task::sleep(std::time::Duration::from_secs(1)).await;
|
||||||
Ok(Python::with_gil(|py| py.None()))
|
Ok(Python::with_gil(|py| py.None()))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3-build-config"
|
name = "pyo3-build-config"
|
||||||
version = "0.21.1"
|
version = "0.21.2"
|
||||||
description = "Build configuration for the PyO3 ecosystem"
|
description = "Build configuration for the PyO3 ecosystem"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
|
|
@ -775,6 +775,8 @@ pub fn is_linking_libpython() -> bool {
|
||||||
/// Must be called from a PyO3 crate build script.
|
/// Must be called from a PyO3 crate build script.
|
||||||
fn is_linking_libpython_for_target(target: &Triple) -> bool {
|
fn is_linking_libpython_for_target(target: &Triple) -> bool {
|
||||||
target.operating_system == OperatingSystem::Windows
|
target.operating_system == OperatingSystem::Windows
|
||||||
|
// See https://github.com/PyO3/pyo3/issues/4068#issuecomment-2051159852
|
||||||
|
|| target.operating_system == OperatingSystem::Aix
|
||||||
|| target.environment == Environment::Android
|
|| target.environment == Environment::Android
|
||||||
|| target.environment == Environment::Androideabi
|
|| target.environment == Environment::Androideabi
|
||||||
|| !is_extension_module()
|
|| !is_extension_module()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3-ffi"
|
name = "pyo3-ffi"
|
||||||
version = "0.21.1"
|
version = "0.21.2"
|
||||||
description = "Python-API bindings for the PyO3 ecosystem"
|
description = "Python-API bindings for the PyO3 ecosystem"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
@ -38,7 +38,7 @@ abi3-py312 = ["abi3", "pyo3-build-config/abi3-py312"]
|
||||||
generate-import-lib = ["pyo3-build-config/python3-dll-a"]
|
generate-import-lib = ["pyo3-build-config/python3-dll-a"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.1", features = ["resolve-config"] }
|
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.2", features = ["resolve-config"] }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -11,8 +11,8 @@ pub type Py_ssize_t = ::libc::ssize_t;
|
||||||
pub type Py_hash_t = Py_ssize_t;
|
pub type Py_hash_t = Py_ssize_t;
|
||||||
pub type Py_uhash_t = ::libc::size_t;
|
pub type Py_uhash_t = ::libc::size_t;
|
||||||
|
|
||||||
pub const PY_SSIZE_T_MIN: Py_ssize_t = std::isize::MIN as Py_ssize_t;
|
pub const PY_SSIZE_T_MIN: Py_ssize_t = isize::MIN as Py_ssize_t;
|
||||||
pub const PY_SSIZE_T_MAX: Py_ssize_t = std::isize::MAX as Py_ssize_t;
|
pub const PY_SSIZE_T_MAX: Py_ssize_t = isize::MAX as Py_ssize_t;
|
||||||
|
|
||||||
#[cfg(target_endian = "big")]
|
#[cfg(target_endian = "big")]
|
||||||
pub const PY_BIG_ENDIAN: usize = 1;
|
pub const PY_BIG_ENDIAN: usize = 1;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3-macros-backend"
|
name = "pyo3-macros-backend"
|
||||||
version = "0.21.1"
|
version = "0.21.2"
|
||||||
description = "Code generation for PyO3 package"
|
description = "Code generation for PyO3 package"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
@ -16,7 +16,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
heck = "0.4"
|
heck = "0.4"
|
||||||
proc-macro2 = { version = "1", default-features = false }
|
proc-macro2 = { version = "1", default-features = false }
|
||||||
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.1", features = ["resolve-config"] }
|
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.21.2", features = ["resolve-config"] }
|
||||||
quote = { version = "1", default-features = false }
|
quote = { version = "1", default-features = false }
|
||||||
|
|
||||||
[dependencies.syn]
|
[dependencies.syn]
|
||||||
|
|
|
@ -522,33 +522,22 @@ impl<'a> FnSpec<'a> {
|
||||||
Some(cls) => quote!(Some(<#cls as #pyo3_path::PyTypeInfo>::NAME)),
|
Some(cls) => quote!(Some(<#cls as #pyo3_path::PyTypeInfo>::NAME)),
|
||||||
None => quote!(None),
|
None => quote!(None),
|
||||||
};
|
};
|
||||||
let evaluate_args = || -> (Vec<Ident>, TokenStream) {
|
let arg_names = (0..args.len())
|
||||||
let mut arg_names = Vec::with_capacity(args.len());
|
.map(|i| format_ident!("arg_{}", i))
|
||||||
let mut evaluate_arg = quote! {};
|
.collect::<Vec<_>>();
|
||||||
for arg in &args {
|
|
||||||
let arg_name = format_ident!("arg_{}", arg_names.len());
|
|
||||||
arg_names.push(arg_name.clone());
|
|
||||||
evaluate_arg.extend(quote! {
|
|
||||||
let #arg_name = #arg
|
|
||||||
});
|
|
||||||
}
|
|
||||||
(arg_names, evaluate_arg)
|
|
||||||
};
|
|
||||||
let future = match self.tp {
|
let future = match self.tp {
|
||||||
FnType::Fn(SelfType::Receiver { mutable: false, .. }) => {
|
FnType::Fn(SelfType::Receiver { mutable: false, .. }) => {
|
||||||
let (arg_name, evaluate_arg) = evaluate_args();
|
|
||||||
quote! {{
|
quote! {{
|
||||||
#evaluate_arg;
|
#(let #arg_names = #args;)*
|
||||||
let __guard = #pyo3_path::impl_::coroutine::RefGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?;
|
let __guard = #pyo3_path::impl_::coroutine::RefGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?;
|
||||||
async move { function(&__guard, #(#arg_name),*).await }
|
async move { function(&__guard, #(#arg_names),*).await }
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
FnType::Fn(SelfType::Receiver { mutable: true, .. }) => {
|
FnType::Fn(SelfType::Receiver { mutable: true, .. }) => {
|
||||||
let (arg_name, evaluate_arg) = evaluate_args();
|
|
||||||
quote! {{
|
quote! {{
|
||||||
#evaluate_arg;
|
#(let #arg_names = #args;)*
|
||||||
let mut __guard = #pyo3_path::impl_::coroutine::RefMutGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?;
|
let mut __guard = #pyo3_path::impl_::coroutine::RefMutGuard::<#cls>::new(&#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &_slf))?;
|
||||||
async move { function(&mut __guard, #(#arg_name),*).await }
|
async move { function(&mut __guard, #(#arg_names),*).await }
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
|
|
@ -249,6 +249,7 @@ pub fn pymodule_module_impl(mut module: syn::ItemMod) -> Result<TokenStream> {
|
||||||
|
|
||||||
#initialization
|
#initialization
|
||||||
|
|
||||||
|
#[allow(unknown_lints, non_local_definitions)]
|
||||||
impl MakeDef {
|
impl MakeDef {
|
||||||
const fn make_def() -> #pyo3_path::impl_::pymodule::ModuleDef {
|
const fn make_def() -> #pyo3_path::impl_::pymodule::ModuleDef {
|
||||||
use #pyo3_path::impl_::pymodule as impl_;
|
use #pyo3_path::impl_::pymodule as impl_;
|
||||||
|
@ -324,6 +325,7 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream>
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#function
|
#function
|
||||||
|
#[doc(hidden)]
|
||||||
#vis mod #ident {
|
#vis mod #ident {
|
||||||
#initialization
|
#initialization
|
||||||
}
|
}
|
||||||
|
@ -332,6 +334,7 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream>
|
||||||
// this avoids complications around the fact that the generated module has a different scope
|
// this avoids complications around the fact that the generated module has a different scope
|
||||||
// (and `super` doesn't always refer to the outer scope, e.g. if the `#[pymodule] is
|
// (and `super` doesn't always refer to the outer scope, e.g. if the `#[pymodule] is
|
||||||
// inside a function body)
|
// inside a function body)
|
||||||
|
#[allow(unknown_lints, non_local_definitions)]
|
||||||
impl #ident::MakeDef {
|
impl #ident::MakeDef {
|
||||||
const fn make_def() -> #pyo3_path::impl_::pymodule::ModuleDef {
|
const fn make_def() -> #pyo3_path::impl_::pymodule::ModuleDef {
|
||||||
fn __pyo3_pymodule(module: &#pyo3_path::Bound<'_, #pyo3_path::types::PyModule>) -> #pyo3_path::PyResult<()> {
|
fn __pyo3_pymodule(module: &#pyo3_path::Bound<'_, #pyo3_path::types::PyModule>) -> #pyo3_path::PyResult<()> {
|
||||||
|
|
|
@ -1614,7 +1614,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
quote! {
|
quote! {
|
||||||
impl #cls {
|
impl #cls {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
const _PYO3_DEF: #pyo3_path::impl_::pymodule::AddClassToModule<Self> = #pyo3_path::impl_::pymodule::AddClassToModule::new();
|
pub const _PYO3_DEF: #pyo3_path::impl_::pymodule::AddClassToModule<Self> = #pyo3_path::impl_::pymodule::AddClassToModule::new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,6 +273,7 @@ pub fn impl_wrap_pyfunction(
|
||||||
// this avoids complications around the fact that the generated module has a different scope
|
// this avoids complications around the fact that the generated module has a different scope
|
||||||
// (and `super` doesn't always refer to the outer scope, e.g. if the `#[pyfunction] is
|
// (and `super` doesn't always refer to the outer scope, e.g. if the `#[pyfunction] is
|
||||||
// inside a function body)
|
// inside a function body)
|
||||||
|
#[allow(unknown_lints, non_local_definitions)]
|
||||||
impl #name::MakeDef {
|
impl #name::MakeDef {
|
||||||
const _PYO3_DEF: #pyo3_path::impl_::pymethods::PyMethodDef = #methoddef;
|
const _PYO3_DEF: #pyo3_path::impl_::pymethods::PyMethodDef = #methoddef;
|
||||||
}
|
}
|
||||||
|
|
|
@ -366,6 +366,7 @@ pub fn impl_py_method_def_new(
|
||||||
#deprecations
|
#deprecations
|
||||||
|
|
||||||
use #pyo3_path::impl_::pyclass::*;
|
use #pyo3_path::impl_::pyclass::*;
|
||||||
|
#[allow(unknown_lints, non_local_definitions)]
|
||||||
impl PyClassNewTextSignature<#cls> for PyClassImplCollector<#cls> {
|
impl PyClassNewTextSignature<#cls> for PyClassImplCollector<#cls> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new_text_signature(self) -> ::std::option::Option<&'static str> {
|
fn new_text_signature(self) -> ::std::option::Option<&'static str> {
|
||||||
|
@ -434,9 +435,24 @@ fn impl_traverse_slot(
|
||||||
let Ctx { pyo3_path } = ctx;
|
let Ctx { pyo3_path } = ctx;
|
||||||
if let (Some(py_arg), _) = split_off_python_arg(&spec.signature.arguments) {
|
if let (Some(py_arg), _) = split_off_python_arg(&spec.signature.arguments) {
|
||||||
return Err(syn::Error::new_spanned(py_arg.ty, "__traverse__ may not take `Python`. \
|
return Err(syn::Error::new_spanned(py_arg.ty, "__traverse__ may not take `Python`. \
|
||||||
Usually, an implementation of `__traverse__` should do nothing but calls to `visit.call`. \
|
Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` \
|
||||||
Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, \
|
should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited \
|
||||||
i.e. `Python::with_gil` will panic."));
|
inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the receiver does not try to smuggle an (implicit) `Python` token into here
|
||||||
|
if let FnType::Fn(SelfType::TryFromBoundRef(span))
|
||||||
|
| FnType::Fn(SelfType::Receiver {
|
||||||
|
mutable: true,
|
||||||
|
span,
|
||||||
|
}) = spec.tp
|
||||||
|
{
|
||||||
|
bail_spanned! { span =>
|
||||||
|
"__traverse__ may not take a receiver other than `&self`. Usually, an implementation of \
|
||||||
|
`__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` \
|
||||||
|
should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited \
|
||||||
|
inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic."
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let rust_fn_ident = spec.name;
|
let rust_fn_ident = spec.name;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3-macros"
|
name = "pyo3-macros"
|
||||||
version = "0.21.1"
|
version = "0.21.2"
|
||||||
description = "Proc macros for PyO3 package"
|
description = "Proc macros for PyO3 package"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
@ -22,7 +22,7 @@ experimental-declarative-modules = []
|
||||||
proc-macro2 = { version = "1", default-features = false }
|
proc-macro2 = { version = "1", default-features = false }
|
||||||
quote = "1"
|
quote = "1"
|
||||||
syn = { version = "2", features = ["full", "extra-traits"] }
|
syn = { version = "2", features = ["full", "extra-traits"] }
|
||||||
pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.21.1" }
|
pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.21.2" }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
[tool.towncrier]
|
[tool.towncrier]
|
||||||
filename = "CHANGELOG.md"
|
filename = "CHANGELOG.md"
|
||||||
version = "0.21.1"
|
version = "0.21.2"
|
||||||
start_string = "<!-- towncrier release notes start -->\n"
|
start_string = "<!-- towncrier release notes start -->\n"
|
||||||
template = ".towncrier.template.md"
|
template = ".towncrier.template.md"
|
||||||
title_format = "## [{version}] - {project_date}"
|
title_format = "## [{version}] - {project_date}"
|
||||||
|
|
|
@ -4,7 +4,6 @@ use crate::err::{PyErr, PyResult};
|
||||||
use crate::exceptions::PyOverflowError;
|
use crate::exceptions::PyOverflowError;
|
||||||
use crate::ffi::{self, Py_hash_t};
|
use crate::ffi::{self, Py_hash_t};
|
||||||
use crate::{IntoPy, PyObject, Python};
|
use crate::{IntoPy, PyObject, Python};
|
||||||
use std::isize;
|
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
/// A type which can be the return type of a python C-API callback
|
/// A type which can be the return type of a python C-API callback
|
||||||
|
@ -85,11 +84,7 @@ impl IntoPyCallbackOutput<()> for () {
|
||||||
impl IntoPyCallbackOutput<ffi::Py_ssize_t> for usize {
|
impl IntoPyCallbackOutput<ffi::Py_ssize_t> for usize {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn convert(self, _py: Python<'_>) -> PyResult<ffi::Py_ssize_t> {
|
fn convert(self, _py: Python<'_>) -> PyResult<ffi::Py_ssize_t> {
|
||||||
if self <= (isize::MAX as usize) {
|
self.try_into().map_err(|_err| PyOverflowError::new_err(()))
|
||||||
Ok(self as isize)
|
|
||||||
} else {
|
|
||||||
Err(PyOverflowError::new_err(()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -445,7 +445,7 @@ mod test_128bit_integers {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_i128_max() {
|
fn test_i128_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = std::i128::MAX;
|
let v = i128::MAX;
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<i128>(py).unwrap());
|
assert_eq!(v, obj.extract::<i128>(py).unwrap());
|
||||||
assert_eq!(v as u128, obj.extract::<u128>(py).unwrap());
|
assert_eq!(v as u128, obj.extract::<u128>(py).unwrap());
|
||||||
|
@ -456,7 +456,7 @@ mod test_128bit_integers {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_i128_min() {
|
fn test_i128_min() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = std::i128::MIN;
|
let v = i128::MIN;
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<i128>(py).unwrap());
|
assert_eq!(v, obj.extract::<i128>(py).unwrap());
|
||||||
assert!(obj.extract::<i64>(py).is_err());
|
assert!(obj.extract::<i64>(py).is_err());
|
||||||
|
@ -467,7 +467,7 @@ mod test_128bit_integers {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_u128_max() {
|
fn test_u128_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = std::u128::MAX;
|
let v = u128::MAX;
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<u128>(py).unwrap());
|
assert_eq!(v, obj.extract::<u128>(py).unwrap());
|
||||||
assert!(obj.extract::<i128>(py).is_err());
|
assert!(obj.extract::<i128>(py).is_err());
|
||||||
|
@ -495,7 +495,7 @@ mod test_128bit_integers {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nonzero_i128_max() {
|
fn test_nonzero_i128_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = NonZeroI128::new(std::i128::MAX).unwrap();
|
let v = NonZeroI128::new(i128::MAX).unwrap();
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<NonZeroI128>(py).unwrap());
|
assert_eq!(v, obj.extract::<NonZeroI128>(py).unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -509,7 +509,7 @@ mod test_128bit_integers {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nonzero_i128_min() {
|
fn test_nonzero_i128_min() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = NonZeroI128::new(std::i128::MIN).unwrap();
|
let v = NonZeroI128::new(i128::MIN).unwrap();
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<NonZeroI128>(py).unwrap());
|
assert_eq!(v, obj.extract::<NonZeroI128>(py).unwrap());
|
||||||
assert!(obj.extract::<NonZeroI64>(py).is_err());
|
assert!(obj.extract::<NonZeroI64>(py).is_err());
|
||||||
|
@ -520,7 +520,7 @@ mod test_128bit_integers {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nonzero_u128_max() {
|
fn test_nonzero_u128_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = NonZeroU128::new(std::u128::MAX).unwrap();
|
let v = NonZeroU128::new(u128::MAX).unwrap();
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<NonZeroU128>(py).unwrap());
|
assert_eq!(v, obj.extract::<NonZeroU128>(py).unwrap());
|
||||||
assert!(obj.extract::<NonZeroI128>(py).is_err());
|
assert!(obj.extract::<NonZeroI128>(py).is_err());
|
||||||
|
@ -573,7 +573,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_u32_max() {
|
fn test_u32_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = std::u32::MAX;
|
let v = u32::MAX;
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<u32>(py).unwrap());
|
assert_eq!(v, obj.extract::<u32>(py).unwrap());
|
||||||
assert_eq!(u64::from(v), obj.extract::<u64>(py).unwrap());
|
assert_eq!(u64::from(v), obj.extract::<u64>(py).unwrap());
|
||||||
|
@ -584,7 +584,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_i64_max() {
|
fn test_i64_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = std::i64::MAX;
|
let v = i64::MAX;
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<i64>(py).unwrap());
|
assert_eq!(v, obj.extract::<i64>(py).unwrap());
|
||||||
assert_eq!(v as u64, obj.extract::<u64>(py).unwrap());
|
assert_eq!(v as u64, obj.extract::<u64>(py).unwrap());
|
||||||
|
@ -595,7 +595,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_i64_min() {
|
fn test_i64_min() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = std::i64::MIN;
|
let v = i64::MIN;
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<i64>(py).unwrap());
|
assert_eq!(v, obj.extract::<i64>(py).unwrap());
|
||||||
assert!(obj.extract::<i32>(py).is_err());
|
assert!(obj.extract::<i32>(py).is_err());
|
||||||
|
@ -606,7 +606,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_u64_max() {
|
fn test_u64_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = std::u64::MAX;
|
let v = u64::MAX;
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<u64>(py).unwrap());
|
assert_eq!(v, obj.extract::<u64>(py).unwrap());
|
||||||
assert!(obj.extract::<i64>(py).is_err());
|
assert!(obj.extract::<i64>(py).is_err());
|
||||||
|
@ -664,7 +664,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nonzero_u32_max() {
|
fn test_nonzero_u32_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = NonZeroU32::new(std::u32::MAX).unwrap();
|
let v = NonZeroU32::new(u32::MAX).unwrap();
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<NonZeroU32>(py).unwrap());
|
assert_eq!(v, obj.extract::<NonZeroU32>(py).unwrap());
|
||||||
assert_eq!(NonZeroU64::from(v), obj.extract::<NonZeroU64>(py).unwrap());
|
assert_eq!(NonZeroU64::from(v), obj.extract::<NonZeroU64>(py).unwrap());
|
||||||
|
@ -675,7 +675,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nonzero_i64_max() {
|
fn test_nonzero_i64_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = NonZeroI64::new(std::i64::MAX).unwrap();
|
let v = NonZeroI64::new(i64::MAX).unwrap();
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<NonZeroI64>(py).unwrap());
|
assert_eq!(v, obj.extract::<NonZeroI64>(py).unwrap());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -689,7 +689,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nonzero_i64_min() {
|
fn test_nonzero_i64_min() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = NonZeroI64::new(std::i64::MIN).unwrap();
|
let v = NonZeroI64::new(i64::MIN).unwrap();
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<NonZeroI64>(py).unwrap());
|
assert_eq!(v, obj.extract::<NonZeroI64>(py).unwrap());
|
||||||
assert!(obj.extract::<NonZeroI32>(py).is_err());
|
assert!(obj.extract::<NonZeroI32>(py).is_err());
|
||||||
|
@ -700,7 +700,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_nonzero_u64_max() {
|
fn test_nonzero_u64_max() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = NonZeroU64::new(std::u64::MAX).unwrap();
|
let v = NonZeroU64::new(u64::MAX).unwrap();
|
||||||
let obj = v.to_object(py);
|
let obj = v.to_object(py);
|
||||||
assert_eq!(v, obj.extract::<NonZeroU64>(py).unwrap());
|
assert_eq!(v, obj.extract::<NonZeroU64>(py).unwrap());
|
||||||
assert!(obj.extract::<NonZeroI64>(py).is_err());
|
assert!(obj.extract::<NonZeroI64>(py).is_err());
|
||||||
|
|
|
@ -852,6 +852,7 @@ slot_fragment_trait! {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! generate_pyclass_richcompare_slot {
|
macro_rules! generate_pyclass_richcompare_slot {
|
||||||
($cls:ty) => {{
|
($cls:ty) => {{
|
||||||
|
#[allow(unknown_lints, non_local_definitions)]
|
||||||
impl $cls {
|
impl $cls {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
unsafe extern "C" fn __pymethod___richcmp____(
|
unsafe extern "C" fn __pymethod___richcmp____(
|
||||||
|
|
|
@ -102,7 +102,7 @@ impl ModuleDef {
|
||||||
// that static data is not reused across interpreters.
|
// that static data is not reused across interpreters.
|
||||||
//
|
//
|
||||||
// PyPy does not have subinterpreters, so no need to check interpreter ID.
|
// PyPy does not have subinterpreters, so no need to check interpreter ID.
|
||||||
#[cfg(not(any(PyPy, GraalPy)))]
|
#[cfg(not(any(PyPy, GraalPy, feature = "unsafe-allow-subinterpreters")))]
|
||||||
{
|
{
|
||||||
// PyInterpreterState_Get is only available on 3.9 and later, but is missing
|
// PyInterpreterState_Get is only available on 3.9 and later, but is missing
|
||||||
// from python3.dll for Windows stable API on 3.9
|
// from python3.dll for Windows stable API on 3.9
|
||||||
|
|
|
@ -280,6 +280,7 @@ mod nightly {
|
||||||
impl !Ungil for crate::PyAny {}
|
impl !Ungil for crate::PyAny {}
|
||||||
|
|
||||||
// All the borrowing wrappers
|
// All the borrowing wrappers
|
||||||
|
#[allow(deprecated)]
|
||||||
impl<T> !Ungil for crate::PyCell<T> {}
|
impl<T> !Ungil for crate::PyCell<T> {}
|
||||||
impl<T> !Ungil for crate::PyRef<'_, T> {}
|
impl<T> !Ungil for crate::PyRef<'_, T> {}
|
||||||
impl<T> !Ungil for crate::PyRefMut<'_, T> {}
|
impl<T> !Ungil for crate::PyRefMut<'_, T> {}
|
||||||
|
|
|
@ -55,7 +55,7 @@ struct BorrowFlag(usize);
|
||||||
|
|
||||||
impl BorrowFlag {
|
impl BorrowFlag {
|
||||||
pub(crate) const UNUSED: BorrowFlag = BorrowFlag(0);
|
pub(crate) const UNUSED: BorrowFlag = BorrowFlag(0);
|
||||||
const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::max_value());
|
const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::MAX);
|
||||||
const fn increment(self) -> Self {
|
const fn increment(self) -> Self {
|
||||||
Self(self.0 + 1)
|
Self(self.0 + 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2491,6 +2491,7 @@ class SimpleClass:
|
||||||
|
|
||||||
#[cfg(feature = "macros")]
|
#[cfg(feature = "macros")]
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(unknown_lints, non_local_definitions)]
|
||||||
fn test_hasattr_error() {
|
fn test_hasattr_error() {
|
||||||
use crate::exceptions::PyValueError;
|
use crate::exceptions::PyValueError;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
|
@ -58,7 +58,14 @@ impl PySet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deprecated form of [`PySet::empty_bound`].
|
/// Deprecated form of [`PySet::empty_bound`].
|
||||||
pub fn empty(py: Python<'_>) -> PyResult<&'_ PySet> {
|
#[cfg_attr(
|
||||||
|
not(feature = "gil-refs"),
|
||||||
|
deprecated(
|
||||||
|
since = "0.21.2",
|
||||||
|
note = "`PySet::empty` will be replaced by `PySet::empty_bound` in a future PyO3 version"
|
||||||
|
)
|
||||||
|
)]
|
||||||
|
pub fn empty(py: Python<'_>) -> PyResult<&PySet> {
|
||||||
Self::empty_bound(py).map(Bound::into_gil_ref)
|
Self::empty_bound(py).map(Bound::into_gil_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,4 +53,5 @@ fn test_compile_errors() {
|
||||||
#[cfg(feature = "experimental-async")]
|
#[cfg(feature = "experimental-async")]
|
||||||
#[cfg(any(not(Py_LIMITED_API), Py_3_10))] // to avoid PyFunctionArgument for &str
|
#[cfg(any(not(Py_LIMITED_API), Py_3_10))] // to avoid PyFunctionArgument for &str
|
||||||
t.compile_fail("tests/ui/invalid_cancel_handle.rs");
|
t.compile_fail("tests/ui/invalid_cancel_handle.rs");
|
||||||
|
t.pass("tests/ui/pymodule_missing_docs.rs");
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,39 +245,6 @@ fn coroutine_panic() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_async_method_receiver_with_other_args() {
|
|
||||||
#[pyclass]
|
|
||||||
struct Value(i32);
|
|
||||||
#[pymethods]
|
|
||||||
impl Value {
|
|
||||||
#[new]
|
|
||||||
fn new() -> Self {
|
|
||||||
Self(0)
|
|
||||||
}
|
|
||||||
async fn get_value_plus_with(&self, v: i32) -> i32 {
|
|
||||||
self.0 + v
|
|
||||||
}
|
|
||||||
async fn set_value(&mut self, new_value: i32) -> i32 {
|
|
||||||
self.0 = new_value;
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Python::with_gil(|gil| {
|
|
||||||
let test = r#"
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
v = Value()
|
|
||||||
assert asyncio.run(v.get_value_plus_with(3)) == 3
|
|
||||||
assert asyncio.run(v.set_value(10)) == 10
|
|
||||||
assert asyncio.run(v.get_value_plus_with(1)) == 11
|
|
||||||
"#;
|
|
||||||
let locals = [("Value", gil.get_type_bound::<Value>())].into_py_dict_bound(gil);
|
|
||||||
py_run!(gil, *locals, test);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_async_method_receiver() {
|
fn test_async_method_receiver() {
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
|
@ -341,3 +308,36 @@ fn test_async_method_receiver() {
|
||||||
|
|
||||||
assert!(IS_DROPPED.load(Ordering::SeqCst));
|
assert!(IS_DROPPED.load(Ordering::SeqCst));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_async_method_receiver_with_other_args() {
|
||||||
|
#[pyclass]
|
||||||
|
struct Value(i32);
|
||||||
|
#[pymethods]
|
||||||
|
impl Value {
|
||||||
|
#[new]
|
||||||
|
fn new() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
async fn get_value_plus_with(&self, v1: i32, v2: i32) -> i32 {
|
||||||
|
self.0 + v1 + v2
|
||||||
|
}
|
||||||
|
async fn set_value(&mut self, new_value: i32) -> i32 {
|
||||||
|
self.0 = new_value;
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Python::with_gil(|gil| {
|
||||||
|
let test = r#"
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
v = Value()
|
||||||
|
assert asyncio.run(v.get_value_plus_with(3, 0)) == 3
|
||||||
|
assert asyncio.run(v.set_value(10)) == 10
|
||||||
|
assert asyncio.run(v.get_value_plus_with(1, 1)) == 12
|
||||||
|
"#;
|
||||||
|
let locals = [("Value", gil.get_type_bound::<Value>())].into_py_dict_bound(gil);
|
||||||
|
py_run!(gil, *locals, test);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,13 @@ use pyo3::types::PyBool;
|
||||||
#[path = "../src/tests/common.rs"]
|
#[path = "../src/tests/common.rs"]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
|
mod some_module {
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
pub struct SomePyClass;
|
||||||
|
}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct ValueClass {
|
struct ValueClass {
|
||||||
value: usize,
|
value: usize,
|
||||||
|
@ -50,6 +57,10 @@ mod declarative_module {
|
||||||
#[pymodule_export]
|
#[pymodule_export]
|
||||||
use super::{declarative_module2, double, MyError, ValueClass as Value};
|
use super::{declarative_module2, double, MyError, ValueClass as Value};
|
||||||
|
|
||||||
|
// test for #4036
|
||||||
|
#[pymodule_export]
|
||||||
|
use super::some_module::SomePyClass;
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
mod inner {
|
mod inner {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
use pyo3::exceptions::{PyAttributeError, PyIndexError, PyValueError};
|
use pyo3::exceptions::{PyAttributeError, PyIndexError, PyValueError};
|
||||||
use pyo3::types::{PyDict, PyList, PyMapping, PySequence, PySlice, PyType};
|
use pyo3::types::{PyDict, PyList, PyMapping, PySequence, PySlice, PyType};
|
||||||
use pyo3::{prelude::*, py_run};
|
use pyo3::{prelude::*, py_run};
|
||||||
use std::{isize, iter};
|
use std::iter;
|
||||||
|
|
||||||
#[path = "../src/tests/common.rs"]
|
#[path = "../src/tests/common.rs"]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
//! Some crate docs
|
||||||
|
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
/// Some module documentation
|
||||||
|
#[pymodule]
|
||||||
|
pub fn python_module(_m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -1,13 +1,55 @@
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::PyVisit;
|
|
||||||
use pyo3::PyTraverseError;
|
use pyo3::PyTraverseError;
|
||||||
|
use pyo3::PyVisit;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct TraverseTriesToTakePyRef {}
|
struct TraverseTriesToTakePyRef {}
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl TraverseTriesToTakePyRef {
|
impl TraverseTriesToTakePyRef {
|
||||||
fn __traverse__(slf: PyRef<Self>, visit: PyVisit) {}
|
fn __traverse__(slf: PyRef<Self>, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
struct TraverseTriesToTakePyRefMut {}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl TraverseTriesToTakePyRefMut {
|
||||||
|
fn __traverse__(slf: PyRefMut<Self>, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
struct TraverseTriesToTakeBound {}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl TraverseTriesToTakeBound {
|
||||||
|
fn __traverse__(slf: Bound<'_, Self>, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
struct TraverseTriesToTakeMutSelf {}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl TraverseTriesToTakeMutSelf {
|
||||||
|
fn __traverse__(&mut self, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
struct TraverseTriesToTakeSelf {}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl TraverseTriesToTakeSelf {
|
||||||
|
fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
|
@ -19,9 +61,7 @@ impl Class {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn __clear__(&mut self) {
|
fn __clear__(&mut self) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
|
@ -1,23 +1,29 @@
|
||||||
error: __traverse__ may not take `Python`. Usually, an implementation of `__traverse__` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic.
|
error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic.
|
||||||
--> tests/ui/traverse.rs:18:32
|
--> tests/ui/traverse.rs:10:26
|
||||||
|
|
|
|
||||||
18 | fn __traverse__(&self, py: Python<'_>, visit: PyVisit<'_>) -> Result<(), PyTraverseError> {
|
10 | fn __traverse__(slf: PyRef<Self>, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||||
| ^^^^^^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic.
|
||||||
--> tests/ui/traverse.rs:9:6
|
--> tests/ui/traverse.rs:20:26
|
||||||
|
|
|
|
||||||
8 | #[pymethods]
|
20 | fn __traverse__(slf: PyRefMut<Self>, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||||
| ------------ arguments to this function are incorrect
|
| ^^^^^^^^
|
||||||
9 | impl TraverseTriesToTakePyRef {
|
|
||||||
| ______^
|
error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic.
|
||||||
10 | | fn __traverse__(slf: PyRef<Self>, visit: PyVisit) {}
|
--> tests/ui/traverse.rs:30:26
|
||||||
| |___________________^ expected fn pointer, found fn item
|
|
||||||
|
|
|
|
||||||
= note: expected fn pointer `for<'a, 'b> fn(&'a TraverseTriesToTakePyRef, PyVisit<'b>) -> Result<(), PyTraverseError>`
|
30 | fn __traverse__(slf: Bound<'_, Self>, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||||
found fn item `for<'a, 'b> fn(pyo3::PyRef<'a, TraverseTriesToTakePyRef, >, PyVisit<'b>) {TraverseTriesToTakePyRef::__traverse__}`
|
| ^^^^^
|
||||||
note: function defined here
|
|
||||||
--> src/impl_/pymethods.rs
|
error: __traverse__ may not take a receiver other than `&self`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic.
|
||||||
|
--> tests/ui/traverse.rs:40:21
|
||||||
|
|
|
|
||||||
| pub unsafe fn _call_traverse<T>(
|
40 | fn __traverse__(&mut self, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||||
| ^^^^^^^^^^^^^^
|
| ^
|
||||||
|
|
||||||
|
error: __traverse__ may not take `Python`. Usually, an implementation of `__traverse__(&self, visit: PyVisit<'_>) -> Result<(), PyTraverseError>` should do nothing but calls to `visit.call`. Most importantly, safe access to the GIL is prohibited inside implementations of `__traverse__`, i.e. `Python::with_gil` will panic.
|
||||||
|
--> tests/ui/traverse.rs:60:32
|
||||||
|
|
|
||||||
|
60 | fn __traverse__(&self, py: Python<'_>, visit: PyVisit<'_>) -> Result<(), PyTraverseError> {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
Loading…
Reference in New Issue