Compare commits
14 Commits
release-0.
...
master
Author | SHA1 | Date |
---|---|---|
David Hewitt | a5a3f3f7f2 | |
Larry Z | 6be80647cb | |
David Hewitt | 90c4799951 | |
David Hewitt | 3c65132da5 | |
David Hewitt | 32b6a1aef1 | |
David Hewitt | c7c1dff710 | |
Giovanni Barillari | 1279232701 | |
David Hewitt | 97d60e869b | |
David Hewitt | 8652ac8e1c | |
Alex Gaynor | e73112f3f6 | |
David Hewitt | 186c7d3315 | |
Sede Soukossi | 1861d6d379 | |
Icxolu | 3c155d9fef | |
David Hewitt | d5c886f4c0 |
|
@ -16,6 +16,9 @@ on:
|
|||
rust-target:
|
||||
required: true
|
||||
type: string
|
||||
MSRV:
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
@ -51,9 +54,9 @@ jobs:
|
|||
name: Prepare LD_LIBRARY_PATH (Ubuntu only)
|
||||
run: echo LD_LIBRARY_PATH=${pythonLocation}/lib >> $GITHUB_ENV
|
||||
|
||||
- if: inputs.rust == '1.63.0'
|
||||
name: Prepare minimal package versions (MSRV only)
|
||||
run: nox -s set-minimal-package-versions
|
||||
- if: inputs.rust == inputs.MSRV
|
||||
name: Prepare MSRV package versions
|
||||
run: nox -s set-msrv-package-versions
|
||||
|
||||
- if: inputs.rust != 'stable'
|
||||
name: Ignore changed error messages when using trybuild
|
||||
|
|
|
@ -31,6 +31,18 @@ jobs:
|
|||
- name: Check rust formatting (rustfmt)
|
||||
run: nox -s rustfmt
|
||||
|
||||
resolve:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
MSRV: ${{ steps.resolve-msrv.outputs.MSRV }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- name: resolve MSRV
|
||||
id: resolve-msrv
|
||||
run:
|
||||
echo MSRV=`python -c 'import tomllib; print(tomllib.load(open("Cargo.toml", "rb"))["package"]["rust-version"])'` >> $GITHUB_OUTPUT
|
||||
|
||||
semver-checks:
|
||||
if: github.ref != 'refs/heads/main'
|
||||
needs: [fmt]
|
||||
|
@ -41,13 +53,13 @@ jobs:
|
|||
- uses: obi1kenobi/cargo-semver-checks-action@v2
|
||||
|
||||
check-msrv:
|
||||
needs: [fmt]
|
||||
needs: [fmt, resolve]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
toolchain: 1.63.0
|
||||
toolchain: ${{ needs.resolve.outputs.MSRV }}
|
||||
targets: x86_64-unknown-linux-gnu
|
||||
components: rust-src
|
||||
- uses: actions/setup-python@v5
|
||||
|
@ -57,9 +69,11 @@ jobs:
|
|||
with:
|
||||
save-if: ${{ github.event_name != 'merge_group' }}
|
||||
- run: python -m pip install --upgrade pip && pip install nox
|
||||
- name: Prepare minimal package versions
|
||||
run: nox -s set-minimal-package-versions
|
||||
- run: nox -s check-all
|
||||
# This is a smoke test to confirm that CI will run on MSRV (including dev dependencies)
|
||||
- name: Check with MSRV package versions
|
||||
run: |
|
||||
nox -s set-msrv-package-versions
|
||||
nox -s check-all
|
||||
|
||||
env:
|
||||
CARGO_BUILD_TARGET: x86_64-unknown-linux-gnu
|
||||
|
@ -141,7 +155,7 @@ jobs:
|
|||
build-pr:
|
||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'CI-build-full') && github.event_name == 'pull_request' }}
|
||||
name: python${{ matrix.python-version }}-${{ matrix.platform.python-architecture }} ${{ matrix.platform.os }} rust-${{ matrix.rust }}
|
||||
needs: [fmt]
|
||||
needs: [fmt, resolve]
|
||||
uses: ./.github/workflows/build.yml
|
||||
with:
|
||||
os: ${{ matrix.platform.os }}
|
||||
|
@ -149,6 +163,7 @@ jobs:
|
|||
python-architecture: ${{ matrix.platform.python-architecture }}
|
||||
rust: ${{ matrix.rust }}
|
||||
rust-target: ${{ matrix.platform.rust-target }}
|
||||
MSRV: ${{ needs.resolve.outputs.MSRV }}
|
||||
secrets: inherit
|
||||
strategy:
|
||||
# If one platform fails, allow the rest to keep testing if `CI-no-fail-fast` label is present
|
||||
|
@ -198,7 +213,7 @@ jobs:
|
|||
build-full:
|
||||
if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }}
|
||||
name: python${{ matrix.python-version }}-${{ matrix.platform.python-architecture }} ${{ matrix.platform.os }} rust-${{ matrix.rust }}
|
||||
needs: [fmt]
|
||||
needs: [fmt, resolve]
|
||||
uses: ./.github/workflows/build.yml
|
||||
with:
|
||||
os: ${{ matrix.platform.os }}
|
||||
|
@ -206,6 +221,7 @@ jobs:
|
|||
python-architecture: ${{ matrix.platform.python-architecture }}
|
||||
rust: ${{ matrix.rust }}
|
||||
rust-target: ${{ matrix.platform.rust-target }}
|
||||
MSRV: ${{ needs.resolve.outputs.MSRV }}
|
||||
secrets: inherit
|
||||
strategy:
|
||||
# If one platform fails, allow the rest to keep testing if `CI-no-fail-fast` label is present
|
||||
|
@ -251,7 +267,7 @@ jobs:
|
|||
]
|
||||
include:
|
||||
# Test minimal supported Rust version
|
||||
- rust: 1.63.0
|
||||
- rust: ${{ needs.resolve.outputs.MSRV }}
|
||||
python-version: "3.12"
|
||||
platform:
|
||||
{
|
||||
|
@ -487,21 +503,31 @@ jobs:
|
|||
- run: python3 -m nox -s test-version-limits
|
||||
|
||||
check-feature-powerset:
|
||||
needs: [fmt]
|
||||
needs: [fmt, resolve]
|
||||
if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }}
|
||||
runs-on: ubuntu-latest
|
||||
name: check-feature-powerset ${{ matrix.rust }}
|
||||
strategy:
|
||||
# run on stable and MSRV to check that all combinations of features are expected to build fine on our supported
|
||||
# range of compilers
|
||||
matrix:
|
||||
rust: ["stable"]
|
||||
include:
|
||||
- rust: ${{ needs.resolve.outputs.MSRV }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
save-if: ${{ github.event_name != 'merge_group' }}
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: dtolnay/rust-toolchain@master
|
||||
with:
|
||||
components: rust-src
|
||||
- uses: taiki-e/install-action@cargo-hack
|
||||
toolchain: stable
|
||||
- uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: cargo-hack,cargo-minimal-versions
|
||||
- run: python3 -m pip install --upgrade pip && pip install nox
|
||||
- run: python3 -m nox -s check-feature-powerset
|
||||
- run: python3 -m nox -s check-feature-powerset -- ${{ matrix.rust != 'stable' && 'minimal-versions' || '' }}
|
||||
|
||||
test-cross-compilation:
|
||||
needs: [fmt]
|
||||
|
|
|
@ -22,7 +22,7 @@ jobs:
|
|||
tag_name: ${{ steps.prepare_tag.outputs.tag_name }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-python@v5
|
||||
- uses: dtolnay/rust-toolchain@nightly
|
||||
|
||||
- name: Setup mdBook
|
||||
|
|
16
Cargo.toml
16
Cargo.toml
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0-dev"
|
||||
description = "Bindings to Python interpreter"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
readme = "README.md"
|
||||
|
@ -18,13 +18,13 @@ rust-version = "1.63"
|
|||
cfg-if = "1.0"
|
||||
libc = "0.2.62"
|
||||
memoffset = "0.9"
|
||||
once_cell = "1.13.0"
|
||||
once_cell = "1.13"
|
||||
|
||||
# ffi bindings to the python interpreter, split into a separate crate so they can be used independently
|
||||
pyo3-ffi = { path = "pyo3-ffi", version = "=0.22.1" }
|
||||
pyo3-ffi = { path = "pyo3-ffi", version = "=0.23.0-dev" }
|
||||
|
||||
# support crates for macros feature
|
||||
pyo3-macros = { path = "pyo3-macros", version = "=0.22.1", optional = true }
|
||||
pyo3-macros = { path = "pyo3-macros", version = "=0.23.0-dev", optional = true }
|
||||
indoc = { version = "2.0.1", optional = true }
|
||||
unindent = { version = "0.2.1", optional = true }
|
||||
|
||||
|
@ -32,17 +32,17 @@ unindent = { version = "0.2.1", optional = true }
|
|||
inventory = { version = "0.3.0", optional = true }
|
||||
|
||||
# crate integrations that can be added using the eponymous features
|
||||
anyhow = { version = "1.0", optional = true }
|
||||
anyhow = { version = "1.0.1", optional = true }
|
||||
chrono = { version = "0.4.25", default-features = false, optional = true }
|
||||
chrono-tz = { version = ">= 0.6, < 0.10", default-features = false, optional = true }
|
||||
either = { version = "1.9", optional = true }
|
||||
eyre = { version = ">= 0.4, < 0.7", optional = true }
|
||||
hashbrown = { version = ">= 0.9, < 0.15", optional = true }
|
||||
indexmap = { version = ">= 1.6, < 3", optional = true }
|
||||
num-bigint = { version = "0.4", optional = true }
|
||||
num-bigint = { version = "0.4.2", optional = true }
|
||||
num-complex = { version = ">= 0.2, < 0.5", optional = true }
|
||||
num-rational = {version = "0.4.1", optional = true }
|
||||
rust_decimal = { version = "1.0.0", default-features = false, optional = true }
|
||||
rust_decimal = { version = "1.15", default-features = false, optional = true }
|
||||
serde = { version = "1.0", optional = true }
|
||||
smallvec = { version = "1.0", optional = true }
|
||||
|
||||
|
@ -63,7 +63,7 @@ rayon = "1.6.1"
|
|||
futures = "0.3.28"
|
||||
|
||||
[build-dependencies]
|
||||
pyo3-build-config = { path = "pyo3-build-config", version = "=0.22.1", features = ["resolve-config"] }
|
||||
pyo3-build-config = { path = "pyo3-build-config", version = "=0.23.0-dev", features = ["resolve-config"] }
|
||||
|
||||
[features]
|
||||
default = ["macros"]
|
||||
|
|
|
@ -193,6 +193,7 @@ about this topic.
|
|||
- [fastuuid](https://github.com/thedrow/fastuuid/) _Python bindings to Rust's UUID library._
|
||||
- [feos](https://github.com/feos-org/feos) _Lightning fast thermodynamic modeling in Rust with fully developed Python interface._
|
||||
- [forust](https://github.com/jinlow/forust) _A lightweight gradient boosted decision tree library written in Rust._
|
||||
- [granian](https://github.com/emmett-framework/granian) _A Rust HTTP server for Python applications._
|
||||
- [greptimedb](https://github.com/GreptimeTeam/greptimedb/tree/main/src/script) _Support [Python scripting](https://docs.greptime.com/user-guide/python-scripts/overview) in the database_
|
||||
- [haem](https://github.com/BooleanCat/haem) _A Python library for working on Bioinformatics problems._
|
||||
- [html-py-ever](https://github.com/PyO3/setuptools-rust/tree/main/examples/html-py-ever) _Using [html5ever](https://github.com/servo/html5ever) through [kuchiki](https://github.com/kuchiki-rs/kuchiki) to speed up html parsing and css-selecting._
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
variable::set("PYO3_VERSION", "0.22.1");
|
||||
variable::set("PYO3_VERSION", "0.23.0-dev");
|
||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||
file::rename(".template/pyproject.toml", "pyproject.toml");
|
||||
file::delete(".template");
|
||||
|
|
|
@ -75,8 +75,7 @@ impl ExampleContainer {
|
|||
}
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
#[pyo3(name = "getitem")]
|
||||
#[pymodule(name = "getitem")]
|
||||
fn example(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
// ? -https://github.com/PyO3/maturin/issues/475
|
||||
m.add_class::<ExampleContainer>()?;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
variable::set("PYO3_VERSION", "0.22.1");
|
||||
variable::set("PYO3_VERSION", "0.23.0-dev");
|
||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||
file::rename(".template/pyproject.toml", "pyproject.toml");
|
||||
file::delete(".template");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
variable::set("PYO3_VERSION", "0.22.1");
|
||||
variable::set("PYO3_VERSION", "0.23.0-dev");
|
||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||
file::rename(".template/plugin_api/Cargo.toml", "plugin_api/Cargo.toml");
|
||||
file::delete(".template");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
variable::set("PYO3_VERSION", "0.22.1");
|
||||
variable::set("PYO3_VERSION", "0.23.0-dev");
|
||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||
file::rename(".template/setup.cfg", "setup.cfg");
|
||||
file::delete(".template");
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
variable::set("PYO3_VERSION", "0.22.1");
|
||||
variable::set("PYO3_VERSION", "0.23.0-dev");
|
||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||
file::rename(".template/pyproject.toml", "pyproject.toml");
|
||||
file::delete(".template");
|
||||
|
|
|
@ -163,7 +163,7 @@ fn main() {
|
|||
|
||||
For more discussion on and workarounds for MacOS linking problems [see this issue](https://github.com/PyO3/pyo3/issues/1800#issuecomment-906786649).
|
||||
|
||||
Finally, don't forget that on MacOS the `extension-module` feature will cause `cargo test` to fail without the `--no-default-features` flag (see [the FAQ](https://pyo3.rs/main/faq.html#i-cant-run-cargo-test-im-having-linker-issues-like-symbol-not-found-or-undefined-reference-to-_pyexc_systemerror)).
|
||||
Finally, don't forget that on MacOS the `extension-module` feature will cause `cargo test` to fail without the `--no-default-features` flag (see [the FAQ](https://pyo3.rs/main/faq.html#i-cant-run-cargo-test-or-i-cant-build-in-a-cargo-workspace-im-having-linker-issues-like-symbol-not-found-or-undefined-reference-to-_pyexc_systemerror)).
|
||||
|
||||
### The `extension-module` feature
|
||||
|
||||
|
|
|
@ -129,9 +129,7 @@ fn rust_sleep(py: Python<'_>) -> PyResult<&Bound<'_, PyAny>> {
|
|||
|
||||
#[pymodule]
|
||||
fn my_async_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(rust_sleep, m)?)?;
|
||||
|
||||
Ok(())
|
||||
m.add_function(wrap_pyfunction!(rust_sleep, m)?)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -152,8 +150,7 @@ fn rust_sleep(py: Python<'_>) -> PyResult<&Bound<'_, PyAny>>> {
|
|||
|
||||
#[pymodule]
|
||||
fn my_async_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(rust_sleep, m)?)?;
|
||||
Ok(())
|
||||
m.add_function(wrap_pyfunction!(rust_sleep, m)?)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -257,7 +254,7 @@ async def py_sleep():
|
|||
await_coro(py_sleep())
|
||||
```
|
||||
|
||||
If for you wanted to pass a callable function to the `#[pyfunction]` instead, (i.e. the last line becomes `await_coro(py_sleep))`, then the above example needs to be tweaked to first call the callable to get the coroutine:
|
||||
If you wanted to pass a callable function to the `#[pyfunction]` instead, (i.e. the last line becomes `await_coro(py_sleep))`, then the above example needs to be tweaked to first call the callable to get the coroutine:
|
||||
|
||||
```rust
|
||||
#[pyfunction]
|
||||
|
|
|
@ -14,8 +14,7 @@ fn double(x: usize) -> usize {
|
|||
|
||||
#[pymodule]
|
||||
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
||||
Ok(())
|
||||
m.add_function(wrap_pyfunction!(double, m)?)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -56,8 +55,7 @@ The `#[pyo3]` attribute can be used to modify properties of the generated Python
|
|||
|
||||
#[pymodule]
|
||||
fn module_with_functions(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(no_args_py, m)?)?;
|
||||
Ok(())
|
||||
m.add_function(wrap_pyfunction!(no_args_py, m)?)
|
||||
}
|
||||
|
||||
# Python::with_gil(|py| {
|
||||
|
@ -113,8 +111,7 @@ The `#[pyo3]` attribute can be used on individual arguments to modify properties
|
|||
use pyo3::prelude::*;
|
||||
|
||||
fn get_length(obj: &Bound<'_, PyAny>) -> PyResult<usize> {
|
||||
let length = obj.len()?;
|
||||
Ok(length)
|
||||
obj.len()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
@ -204,8 +201,7 @@ fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|||
x * 2
|
||||
}
|
||||
|
||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
||||
Ok(())
|
||||
m.add_function(wrap_pyfunction!(double, m)?)
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@ fn num_kwds(kwds: Option<&Bound<'_, PyDict>>) -> usize {
|
|||
|
||||
#[pymodule]
|
||||
fn module_with_functions(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(num_kwds, m)?).unwrap();
|
||||
Ok(())
|
||||
m.add_function(wrap_pyfunction!(num_kwds, m)?)
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -159,8 +159,7 @@ fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
|
|||
/// import the module.
|
||||
#[pymodule]
|
||||
fn pyo3_example(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
|
||||
Ok(())
|
||||
m.add_function(wrap_pyfunction!(sum_as_string, m)?)
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -5,6 +5,15 @@ For a detailed list of all changes, see the [CHANGELOG](changelog.md).
|
|||
|
||||
## from 0.21.* to 0.22
|
||||
|
||||
### Deprecation of `gil-refs` feature continues
|
||||
<details open>
|
||||
<summary><small>Click to expand</small></summary>
|
||||
|
||||
Following the introduction of the "Bound" API in PyO3 0.21 and the planned removal of the "GIL Refs" API, all functionality related to GIL Refs is now gated behind the `gil-refs` feature and emits a deprecation warning on use.
|
||||
|
||||
See <a href="#from-021-to-022">the 0.21 migration entry</a> for help upgrading.
|
||||
</details>
|
||||
|
||||
### Deprecation of implicit default for trailing optional arguments
|
||||
<details open>
|
||||
<summary><small>Click to expand</small></summary>
|
||||
|
@ -235,8 +244,7 @@ The `__next__` and `__anext__` magic methods can now return any type convertible
|
|||
|
||||
Starting with an implementation of a Python iterator using `IterNextOutput`, e.g.
|
||||
|
||||
```rust
|
||||
#![allow(deprecated)]
|
||||
```rust,ignore
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::iter::IterNextOutput;
|
||||
|
||||
|
@ -529,6 +537,7 @@ assert_eq!(&*name, "list");
|
|||
# }
|
||||
# Python::with_gil(example).unwrap();
|
||||
```
|
||||
</details>
|
||||
|
||||
## from 0.19.* to 0.20
|
||||
|
||||
|
|
|
@ -13,8 +13,7 @@ fn double(x: usize) -> usize {
|
|||
/// This module is implemented in Rust.
|
||||
#[pymodule]
|
||||
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
||||
Ok(())
|
||||
m.add_function(wrap_pyfunction!(double, m)?)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -32,11 +31,9 @@ fn double(x: usize) -> usize {
|
|||
x * 2
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
#[pyo3(name = "custom_name")]
|
||||
#[pymodule(name = "custom_name")]
|
||||
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
||||
Ok(())
|
||||
m.add_function(wrap_pyfunction!(double, m)?)
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -80,8 +77,7 @@ fn parent_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|||
fn register_child_module(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
let child_module = PyModule::new_bound(parent_module.py(), "child_module")?;
|
||||
child_module.add_function(wrap_pyfunction!(func, &child_module)?)?;
|
||||
parent_module.add_submodule(&child_module)?;
|
||||
Ok(())
|
||||
parent_module.add_submodule(&child_module)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
@ -143,8 +139,7 @@ mod my_extension {
|
|||
#[pymodule_init]
|
||||
fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
// Arbitrary code to run at the module initialization
|
||||
m.add("double2", m.getattr("double")?)?;
|
||||
Ok(())
|
||||
m.add("double2", m.getattr("double")?)
|
||||
}
|
||||
}
|
||||
# }
|
||||
|
@ -155,7 +150,6 @@ For nested modules, the name of the parent module is automatically added.
|
|||
In the following example, the `Unit` class will have for `module` `my_extension.submodule` because it is properly nested
|
||||
but the `Ext` class will have for `module` the default `builtins` because it not nested.
|
||||
|
||||
You can provide the `submodule` argument to `pymodule()` for modules that are not top-level modules.
|
||||
```rust
|
||||
# mod declarative_module_module_attr_test {
|
||||
use pyo3::prelude::*;
|
||||
|
@ -170,7 +164,7 @@ mod my_extension {
|
|||
#[pymodule_export]
|
||||
use super::Ext;
|
||||
|
||||
#[pymodule(submodule)]
|
||||
#[pymodule]
|
||||
mod submodule {
|
||||
use super::*;
|
||||
// This is a submodule
|
||||
|
@ -183,3 +177,4 @@ mod my_extension {
|
|||
```
|
||||
It is possible to customize the `module` value for a `#[pymodule]` with the `#[pyo3(module = "MY_MODULE")]` option.
|
||||
|
||||
You can provide the `submodule` argument to `pymodule()` for modules that are not top-level modules -- it is automatically set for modules nested inside of a `#[pymodule]`.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Nested declarative `#[pymodule]` are automatically treated as submodules (no `PyInit_` entrypoint is created)
|
|
@ -0,0 +1 @@
|
|||
Deprecate `PyAnyMethods::is_ellipsis` (`Py::is_ellpsis` was deprecated in PyO3 0.20).
|
|
@ -0,0 +1 @@
|
|||
Remove all functionality deprecated in PyO3 0.20.
|
|
@ -0,0 +1 @@
|
|||
Remove all functionality deprecated in PyO3 0.21.
|
|
@ -0,0 +1,3 @@
|
|||
This PR lets PyO3 checks `Py_GIL_DISABLED` build flag and prevents `pyo3-ffi` crate building against GIL-less Python,
|
||||
unless
|
||||
explicitly opt using the `UNSAFE_PYO3_BUILD_FREE_THREADED` environment flag.
|
|
@ -0,0 +1 @@
|
|||
Fix compile failure in declarative `#[pymodule]` under presence of `#![no_implicit_prelude]`.
|
|
@ -0,0 +1 @@
|
|||
`#[pymodule(...)]` now directly accepts all relevant `#[pyo3(...)]` options.
|
37
noxfile.py
37
noxfile.py
|
@ -9,7 +9,7 @@ import tempfile
|
|||
from functools import lru_cache
|
||||
from glob import glob
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple
|
||||
from typing import Any, Callable, Dict, Iterable, Iterator, List, Optional, Tuple
|
||||
|
||||
import nox
|
||||
import nox.command
|
||||
|
@ -394,8 +394,17 @@ def check_guide(session: nox.Session):
|
|||
docs(session)
|
||||
session.posargs.extend(posargs)
|
||||
|
||||
if toml is None:
|
||||
session.error("requires Python 3.11 or `toml` to be installed")
|
||||
pyo3_version = toml.loads((PYO3_DIR / "Cargo.toml").read_text())["package"][
|
||||
"version"
|
||||
]
|
||||
|
||||
remaps = {
|
||||
f"file://{PYO3_GUIDE_SRC}/([^/]*/)*?%7B%7B#PYO3_DOCS_URL}}}}": f"file://{PYO3_DOCS_TARGET}",
|
||||
f"https://pyo3.rs/v{pyo3_version}": f"file://{PYO3_GUIDE_TARGET}",
|
||||
"https://pyo3.rs/main/": f"file://{PYO3_GUIDE_TARGET}/",
|
||||
"https://pyo3.rs/latest/": f"file://{PYO3_GUIDE_TARGET}/",
|
||||
"%7B%7B#PYO3_DOCS_VERSION}}": "latest",
|
||||
}
|
||||
remap_args = []
|
||||
|
@ -416,8 +425,7 @@ def check_guide(session: nox.Session):
|
|||
session,
|
||||
"lychee",
|
||||
str(PYO3_DOCS_TARGET),
|
||||
f"--remap=https://pyo3.rs/main/ file://{PYO3_GUIDE_TARGET}/",
|
||||
f"--remap=https://pyo3.rs/latest/ file://{PYO3_GUIDE_TARGET}/",
|
||||
*remap_args,
|
||||
f"--exclude=file://{PYO3_DOCS_TARGET}",
|
||||
"--exclude=http://www.adobe.com/",
|
||||
*session.posargs,
|
||||
|
@ -543,8 +551,8 @@ def check_changelog(session: nox.Session):
|
|||
print(fragment.name)
|
||||
|
||||
|
||||
@nox.session(name="set-minimal-package-versions", venv_backend="none")
|
||||
def set_minimal_package_versions(session: nox.Session):
|
||||
@nox.session(name="set-msrv-package-versions", venv_backend="none")
|
||||
def set_msrv_package_versions(session: nox.Session):
|
||||
from collections import defaultdict
|
||||
|
||||
if toml is None:
|
||||
|
@ -647,6 +655,14 @@ def test_version_limits(session: nox.Session):
|
|||
config_file.set("PyPy", "3.11")
|
||||
_run_cargo(session, "check", env=env, expect_error=True)
|
||||
|
||||
# Python build with GIL disabled should fail building
|
||||
config_file.set("CPython", "3.13", build_flags=["Py_GIL_DISABLED"])
|
||||
_run_cargo(session, "check", env=env, expect_error=True)
|
||||
|
||||
# Python build with GIL disabled should pass with env flag on
|
||||
env["UNSAFE_PYO3_BUILD_FREE_THREADED"] = "1"
|
||||
_run_cargo(session, "check", env=env)
|
||||
|
||||
|
||||
@nox.session(name="check-feature-powerset", venv_backend="none")
|
||||
def check_feature_powerset(session: nox.Session):
|
||||
|
@ -708,10 +724,14 @@ def check_feature_powerset(session: nox.Session):
|
|||
rust_flags = env.get("RUSTFLAGS", "")
|
||||
env["RUSTFLAGS"] = f"{rust_flags} -Dwarnings"
|
||||
|
||||
subcommand = "hack"
|
||||
if "minimal-versions" in session.posargs:
|
||||
subcommand = "minimal-versions"
|
||||
|
||||
comma_join = ",".join
|
||||
_run_cargo(
|
||||
session,
|
||||
"hack",
|
||||
subcommand,
|
||||
"--feature-powerset",
|
||||
'--optional-deps=""',
|
||||
f'--skip="{comma_join(features_to_skip)}"',
|
||||
|
@ -907,7 +927,9 @@ class _ConfigFile:
|
|||
def __init__(self, config_file) -> None:
|
||||
self._config_file = config_file
|
||||
|
||||
def set(self, implementation: str, version: str) -> None:
|
||||
def set(
|
||||
self, implementation: str, version: str, build_flags: Iterable[str] = ()
|
||||
) -> None:
|
||||
"""Set the contents of this config file to the given implementation and version."""
|
||||
self._config_file.seek(0)
|
||||
self._config_file.truncate(0)
|
||||
|
@ -915,6 +937,7 @@ class _ConfigFile:
|
|||
f"""\
|
||||
implementation={implementation}
|
||||
version={version}
|
||||
build_flags={','.join(build_flags)}
|
||||
suppress_build_script_link_lines=true
|
||||
"""
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3-build-config"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0-dev"
|
||||
description = "Build configuration for the PyO3 ecosystem"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||
|
|
|
@ -996,6 +996,7 @@ pub enum BuildFlag {
|
|||
Py_DEBUG,
|
||||
Py_REF_DEBUG,
|
||||
Py_TRACE_REFS,
|
||||
Py_GIL_DISABLED,
|
||||
COUNT_ALLOCS,
|
||||
Other(String),
|
||||
}
|
||||
|
@ -1016,6 +1017,7 @@ impl FromStr for BuildFlag {
|
|||
"Py_DEBUG" => Ok(BuildFlag::Py_DEBUG),
|
||||
"Py_REF_DEBUG" => Ok(BuildFlag::Py_REF_DEBUG),
|
||||
"Py_TRACE_REFS" => Ok(BuildFlag::Py_TRACE_REFS),
|
||||
"Py_GIL_DISABLED" => Ok(BuildFlag::Py_GIL_DISABLED),
|
||||
"COUNT_ALLOCS" => Ok(BuildFlag::COUNT_ALLOCS),
|
||||
other => Ok(BuildFlag::Other(other.to_owned())),
|
||||
}
|
||||
|
@ -1039,10 +1041,11 @@ impl FromStr for BuildFlag {
|
|||
pub struct BuildFlags(pub HashSet<BuildFlag>);
|
||||
|
||||
impl BuildFlags {
|
||||
const ALL: [BuildFlag; 4] = [
|
||||
const ALL: [BuildFlag; 5] = [
|
||||
BuildFlag::Py_DEBUG,
|
||||
BuildFlag::Py_REF_DEBUG,
|
||||
BuildFlag::Py_TRACE_REFS,
|
||||
BuildFlag::Py_GIL_DISABLED,
|
||||
BuildFlag::COUNT_ALLOCS,
|
||||
];
|
||||
|
||||
|
|
|
@ -39,7 +39,9 @@ use target_lexicon::OperatingSystem;
|
|||
/// | `#[cfg(PyPy)]` | This marks code which is run when compiling for PyPy. |
|
||||
/// | `#[cfg(GraalPy)]` | This marks code which is run when compiling for GraalPy. |
|
||||
///
|
||||
/// For examples of how to use these attributes, [see PyO3's guide](https://pyo3.rs/latest/building-and-distribution/multiple_python_versions.html).
|
||||
/// For examples of how to use these attributes,
|
||||
#[doc = concat!("[see PyO3's guide](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/building-and-distribution/multiple_python_versions.html)")]
|
||||
/// .
|
||||
#[cfg(feature = "resolve-config")]
|
||||
pub fn use_pyo3_cfgs() {
|
||||
print_expected_cfgs();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3-ffi"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0-dev"
|
||||
description = "Python-API bindings for the PyO3 ecosystem"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
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"]
|
||||
|
||||
[build-dependencies]
|
||||
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.22.1", features = ["resolve-config"] }
|
||||
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.23.0-dev", features = ["resolve-config"] }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -4,8 +4,9 @@ use pyo3_build_config::{
|
|||
cargo_env_var, env_var, errors::Result, is_linking_libpython, resolve_interpreter_config,
|
||||
InterpreterConfig, PythonVersion,
|
||||
},
|
||||
warn, PythonImplementation,
|
||||
warn, BuildFlag, PythonImplementation,
|
||||
};
|
||||
use std::ops::Not;
|
||||
|
||||
/// Minimum Python version PyO3 supports.
|
||||
struct SupportedVersions {
|
||||
|
@ -120,6 +121,24 @@ fn ensure_python_version(interpreter_config: &InterpreterConfig) -> Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_gil_enabled(interpreter_config: &InterpreterConfig) -> Result<()> {
|
||||
let gil_enabled = interpreter_config
|
||||
.build_flags
|
||||
.0
|
||||
.contains(&BuildFlag::Py_GIL_DISABLED)
|
||||
.not();
|
||||
ensure!(
|
||||
gil_enabled || std::env::var("UNSAFE_PYO3_BUILD_FREE_THREADED").map_or(false, |os_str| os_str == "1"),
|
||||
"the Python interpreter was built with the GIL disabled, which is not yet supported by PyO3\n\
|
||||
= help: see https://github.com/PyO3/pyo3/issues/4265 for more information\n\
|
||||
= help: please check if an updated version of PyO3 is available. Current version: {}\n\
|
||||
= help: set UNSAFE_PYO3_BUILD_FREE_THREADED=1 to suppress this check and build anyway for free-threaded Python",
|
||||
std::env::var("CARGO_PKG_VERSION").unwrap()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_target_pointer_width(interpreter_config: &InterpreterConfig) -> Result<()> {
|
||||
if let Some(pointer_width) = interpreter_config.pointer_width {
|
||||
// Try to check whether the target architecture matches the python library
|
||||
|
@ -185,6 +204,7 @@ fn configure_pyo3() -> Result<()> {
|
|||
|
||||
ensure_python_version(&interpreter_config)?;
|
||||
ensure_target_pointer_width(&interpreter_config)?;
|
||||
ensure_gil_enabled(&interpreter_config)?;
|
||||
|
||||
// Serialize the whole interpreter config into DEP_PYTHON_PYO3_CONFIG env var.
|
||||
interpreter_config.to_cargo_dep_env()?;
|
||||
|
|
|
@ -221,11 +221,10 @@
|
|||
//! [`maturin`]: https://github.com/PyO3/maturin "Build and publish crates with pyo3, rust-cpython and cffi bindings as well as rust binaries as python packages"
|
||||
//! [`pyo3-build-config`]: https://docs.rs/pyo3-build-config
|
||||
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/features.html "Features - The Cargo Book"
|
||||
//! [manual_builds]: https://pyo3.rs/latest/building-and-distribution.html#manual-builds "Manual builds - Building and Distribution - PyO3 user guide"
|
||||
#![doc = concat!("[manual_builds]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/building-and-distribution.html#manual-builds \"Manual builds - Building and Distribution - PyO3 user guide\"")]
|
||||
//! [setuptools-rust]: https://github.com/PyO3/setuptools-rust "Setuptools plugin for Rust extensions"
|
||||
//! [PEP 384]: https://www.python.org/dev/peps/pep-0384 "PEP 384 -- Defining a Stable ABI"
|
||||
//! [Features chapter of the guide]: https://pyo3.rs/latest/features.html#features-reference "Features Reference - PyO3 user guide"
|
||||
|
||||
#![doc = concat!("[Features chapter of the guide]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/features.html#features-reference \"Features Reference - PyO3 user guide\"")]
|
||||
#![allow(
|
||||
missing_docs,
|
||||
non_camel_case_types,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3-macros-backend"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0-dev"
|
||||
description = "Code generation for PyO3 package"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||
|
@ -16,7 +16,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
heck = "0.5"
|
||||
proc-macro2 = { version = "1.0.60", default-features = false }
|
||||
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.22.1", features = ["resolve-config"] }
|
||||
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.23.0-dev", features = ["resolve-config"] }
|
||||
quote = { version = "1", default-features = false }
|
||||
|
||||
[dependencies.syn]
|
||||
|
@ -25,7 +25,7 @@ default-features = false
|
|||
features = ["derive", "parsing", "printing", "clone-impls", "full", "extra-traits"]
|
||||
|
||||
[build-dependencies]
|
||||
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.22.1" }
|
||||
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.23.0-dev" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -1,53 +1,6 @@
|
|||
use crate::{
|
||||
method::{FnArg, FnSpec},
|
||||
utils::Ctx,
|
||||
};
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{quote_spanned, ToTokens};
|
||||
|
||||
pub enum Deprecation {
|
||||
PyMethodsNewDeprecatedForm,
|
||||
}
|
||||
|
||||
impl Deprecation {
|
||||
fn ident(&self, span: Span) -> syn::Ident {
|
||||
let string = match self {
|
||||
Deprecation::PyMethodsNewDeprecatedForm => "PYMETHODS_NEW_DEPRECATED_FORM",
|
||||
};
|
||||
syn::Ident::new(string, span)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Deprecations<'ctx>(Vec<(Deprecation, Span)>, &'ctx Ctx);
|
||||
|
||||
impl<'ctx> Deprecations<'ctx> {
|
||||
pub fn new(ctx: &'ctx Ctx) -> Self {
|
||||
Deprecations(Vec::new(), ctx)
|
||||
}
|
||||
|
||||
pub fn push(&mut self, deprecation: Deprecation, span: Span) {
|
||||
self.0.push((deprecation, span))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'ctx> ToTokens for Deprecations<'ctx> {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
let Self(deprecations, Ctx { pyo3_path, .. }) = self;
|
||||
|
||||
for (deprecation, span) in deprecations {
|
||||
let pyo3_path = pyo3_path.to_tokens_spanned(*span);
|
||||
let ident = deprecation.ident(*span);
|
||||
quote_spanned!(
|
||||
*span =>
|
||||
#[allow(clippy::let_unit_value)]
|
||||
{
|
||||
let _ = #pyo3_path::impl_::deprecations::#ident;
|
||||
}
|
||||
)
|
||||
.to_tokens(tokens)
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::method::{FnArg, FnSpec};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote_spanned;
|
||||
|
||||
pub(crate) fn deprecate_trailing_option_default(spec: &FnSpec<'_>) -> TokenStream {
|
||||
if spec.signature.attribute.is_none()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::attributes::{self, get_pyo3_options, CrateAttribute, FromPyWithAttribute};
|
||||
use crate::utils::Ctx;
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::{format_ident, quote, quote_spanned};
|
||||
use quote::{format_ident, quote};
|
||||
use syn::{
|
||||
parenthesized,
|
||||
parse::{Parse, ParseStream},
|
||||
|
@ -44,16 +44,14 @@ impl<'a> Enum<'a> {
|
|||
}
|
||||
|
||||
/// Build derivation body for enums.
|
||||
fn build(&self, ctx: &Ctx) -> (TokenStream, TokenStream) {
|
||||
fn build(&self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let mut var_extracts = Vec::new();
|
||||
let mut variant_names = Vec::new();
|
||||
let mut error_names = Vec::new();
|
||||
|
||||
let mut deprecations = TokenStream::new();
|
||||
for var in &self.variants {
|
||||
let (struct_derive, dep) = var.build(ctx);
|
||||
deprecations.extend(dep);
|
||||
let struct_derive = var.build(ctx);
|
||||
let ext = quote!({
|
||||
let maybe_ret = || -> #pyo3_path::PyResult<Self> {
|
||||
#struct_derive
|
||||
|
@ -70,22 +68,19 @@ impl<'a> Enum<'a> {
|
|||
error_names.push(&var.err_name);
|
||||
}
|
||||
let ty_name = self.enum_ident.to_string();
|
||||
(
|
||||
quote!(
|
||||
let errors = [
|
||||
#(#var_extracts),*
|
||||
];
|
||||
::std::result::Result::Err(
|
||||
#pyo3_path::impl_::frompyobject::failed_to_extract_enum(
|
||||
obj.py(),
|
||||
#ty_name,
|
||||
&[#(#variant_names),*],
|
||||
&[#(#error_names),*],
|
||||
&errors
|
||||
)
|
||||
quote!(
|
||||
let errors = [
|
||||
#(#var_extracts),*
|
||||
];
|
||||
::std::result::Result::Err(
|
||||
#pyo3_path::impl_::frompyobject::failed_to_extract_enum(
|
||||
obj.py(),
|
||||
#ty_name,
|
||||
&[#(#variant_names),*],
|
||||
&[#(#error_names),*],
|
||||
&errors
|
||||
)
|
||||
),
|
||||
deprecations,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -244,7 +239,7 @@ impl<'a> Container<'a> {
|
|||
}
|
||||
|
||||
/// Build derivation body for a struct.
|
||||
fn build(&self, ctx: &Ctx) -> (TokenStream, TokenStream) {
|
||||
fn build(&self, ctx: &Ctx) -> TokenStream {
|
||||
match &self.ty {
|
||||
ContainerType::StructNewtype(ident, from_py_with) => {
|
||||
self.build_newtype_struct(Some(ident), from_py_with, ctx)
|
||||
|
@ -262,73 +257,42 @@ impl<'a> Container<'a> {
|
|||
field_ident: Option<&Ident>,
|
||||
from_py_with: &Option<FromPyWithAttribute>,
|
||||
ctx: &Ctx,
|
||||
) -> (TokenStream, TokenStream) {
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let self_ty = &self.path;
|
||||
let struct_name = self.name();
|
||||
if let Some(ident) = field_ident {
|
||||
let field_name = ident.to_string();
|
||||
match from_py_with {
|
||||
None => (
|
||||
quote! {
|
||||
Ok(#self_ty {
|
||||
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field(obj, #struct_name, #field_name)?
|
||||
})
|
||||
},
|
||||
TokenStream::new(),
|
||||
),
|
||||
None => quote! {
|
||||
Ok(#self_ty {
|
||||
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field(obj, #struct_name, #field_name)?
|
||||
})
|
||||
},
|
||||
Some(FromPyWithAttribute {
|
||||
value: expr_path, ..
|
||||
}) => (
|
||||
quote! {
|
||||
Ok(#self_ty {
|
||||
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, #field_name)?
|
||||
})
|
||||
},
|
||||
quote_spanned! { expr_path.span() =>
|
||||
const _: () = {
|
||||
fn check_from_py_with() {
|
||||
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||
#pyo3_path::impl_::deprecations::inspect_fn(#expr_path, &e);
|
||||
e.from_py_with_arg();
|
||||
}
|
||||
};
|
||||
},
|
||||
),
|
||||
}) => quote! {
|
||||
Ok(#self_ty {
|
||||
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, #field_name)?
|
||||
})
|
||||
},
|
||||
}
|
||||
} else {
|
||||
match from_py_with {
|
||||
None => (
|
||||
quote!(
|
||||
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field(obj, #struct_name, 0).map(#self_ty)
|
||||
),
|
||||
TokenStream::new(),
|
||||
),
|
||||
None => quote! {
|
||||
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field(obj, #struct_name, 0).map(#self_ty)
|
||||
},
|
||||
|
||||
Some(FromPyWithAttribute {
|
||||
value: expr_path, ..
|
||||
}) => (
|
||||
quote! (
|
||||
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, 0).map(#self_ty)
|
||||
),
|
||||
quote_spanned! { expr_path.span() =>
|
||||
const _: () = {
|
||||
fn check_from_py_with() {
|
||||
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||
#pyo3_path::impl_::deprecations::inspect_fn(#expr_path, &e);
|
||||
e.from_py_with_arg();
|
||||
}
|
||||
};
|
||||
},
|
||||
),
|
||||
}) => quote! {
|
||||
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, 0).map(#self_ty)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_tuple_struct(
|
||||
&self,
|
||||
struct_fields: &[TupleStructField],
|
||||
ctx: &Ctx,
|
||||
) -> (TokenStream, TokenStream) {
|
||||
fn build_tuple_struct(&self, struct_fields: &[TupleStructField], ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let self_ty = &self.path;
|
||||
let struct_name = &self.name();
|
||||
|
@ -348,40 +312,15 @@ impl<'a> Container<'a> {
|
|||
}
|
||||
});
|
||||
|
||||
let deprecations = struct_fields
|
||||
.iter()
|
||||
.filter_map(|field| {
|
||||
let FromPyWithAttribute {
|
||||
value: expr_path, ..
|
||||
} = field.from_py_with.as_ref()?;
|
||||
Some(quote_spanned! { expr_path.span() =>
|
||||
const _: () = {
|
||||
fn check_from_py_with() {
|
||||
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||
#pyo3_path::impl_::deprecations::inspect_fn(#expr_path, &e);
|
||||
e.from_py_with_arg();
|
||||
}
|
||||
};
|
||||
})
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
(
|
||||
quote!(
|
||||
match #pyo3_path::types::PyAnyMethods::extract(obj) {
|
||||
::std::result::Result::Ok((#(#field_idents),*)) => ::std::result::Result::Ok(#self_ty(#(#fields),*)),
|
||||
::std::result::Result::Err(err) => ::std::result::Result::Err(err),
|
||||
}
|
||||
),
|
||||
deprecations,
|
||||
quote!(
|
||||
match #pyo3_path::types::PyAnyMethods::extract(obj) {
|
||||
::std::result::Result::Ok((#(#field_idents),*)) => ::std::result::Result::Ok(#self_ty(#(#fields),*)),
|
||||
::std::result::Result::Err(err) => ::std::result::Result::Err(err),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn build_struct(
|
||||
&self,
|
||||
struct_fields: &[NamedStructField<'_>],
|
||||
ctx: &Ctx,
|
||||
) -> (TokenStream, TokenStream) {
|
||||
fn build_struct(&self, struct_fields: &[NamedStructField<'_>], ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let self_ty = &self.path;
|
||||
let struct_name = &self.name();
|
||||
|
@ -420,28 +359,7 @@ impl<'a> Container<'a> {
|
|||
fields.push(quote!(#ident: #extractor));
|
||||
}
|
||||
|
||||
let deprecations = struct_fields
|
||||
.iter()
|
||||
.filter_map(|field| {
|
||||
let FromPyWithAttribute {
|
||||
value: expr_path, ..
|
||||
} = field.from_py_with.as_ref()?;
|
||||
Some(quote_spanned! { expr_path.span() =>
|
||||
const _: () = {
|
||||
fn check_from_py_with() {
|
||||
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||
#pyo3_path::impl_::deprecations::inspect_fn(#expr_path, &e);
|
||||
e.from_py_with_arg();
|
||||
}
|
||||
};
|
||||
})
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
||||
(
|
||||
quote!(::std::result::Result::Ok(#self_ty{#fields})),
|
||||
deprecations,
|
||||
)
|
||||
quote!(::std::result::Result::Ok(#self_ty{#fields}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -673,7 +591,7 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
|
|||
let ctx = &Ctx::new(&options.krate, None);
|
||||
let Ctx { pyo3_path, .. } = &ctx;
|
||||
|
||||
let (derives, from_py_with_deprecations) = match &tokens.data {
|
||||
let derives = match &tokens.data {
|
||||
syn::Data::Enum(en) => {
|
||||
if options.transparent || options.annotation.is_some() {
|
||||
bail_spanned!(tokens.span() => "`transparent` or `annotation` is not supported \
|
||||
|
@ -703,7 +621,5 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
|
|||
#derives
|
||||
}
|
||||
}
|
||||
|
||||
#from_py_with_deprecations
|
||||
))
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
use std::borrow::Cow;
|
||||
use std::ffi::CString;
|
||||
|
||||
use crate::attributes::{self, get_pyo3_options, take_attributes, NameAttribute};
|
||||
use crate::utils::{Ctx, LitCStr};
|
||||
use crate::{
|
||||
attributes::{self, get_pyo3_options, take_attributes, NameAttribute},
|
||||
deprecations::Deprecations,
|
||||
};
|
||||
use proc_macro2::{Ident, Span};
|
||||
use syn::{
|
||||
ext::IdentExt,
|
||||
|
@ -14,12 +11,12 @@ use syn::{
|
|||
Result,
|
||||
};
|
||||
|
||||
pub struct ConstSpec<'ctx> {
|
||||
pub struct ConstSpec {
|
||||
pub rust_ident: syn::Ident,
|
||||
pub attributes: ConstAttributes<'ctx>,
|
||||
pub attributes: ConstAttributes,
|
||||
}
|
||||
|
||||
impl ConstSpec<'_> {
|
||||
impl ConstSpec {
|
||||
pub fn python_name(&self) -> Cow<'_, Ident> {
|
||||
if let Some(name) = &self.attributes.name {
|
||||
Cow::Borrowed(&name.value.0)
|
||||
|
@ -35,10 +32,9 @@ impl ConstSpec<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct ConstAttributes<'ctx> {
|
||||
pub struct ConstAttributes {
|
||||
pub is_class_attr: bool,
|
||||
pub name: Option<NameAttribute>,
|
||||
pub deprecations: Deprecations<'ctx>,
|
||||
}
|
||||
|
||||
pub enum PyO3ConstAttribute {
|
||||
|
@ -56,12 +52,11 @@ impl Parse for PyO3ConstAttribute {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'ctx> ConstAttributes<'ctx> {
|
||||
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>, ctx: &'ctx Ctx) -> syn::Result<Self> {
|
||||
impl ConstAttributes {
|
||||
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>) -> syn::Result<Self> {
|
||||
let mut attributes = ConstAttributes {
|
||||
is_class_attr: false,
|
||||
name: None,
|
||||
deprecations: Deprecations::new(ctx),
|
||||
};
|
||||
|
||||
take_attributes(attrs, |attr| {
|
||||
|
|
|
@ -10,7 +10,6 @@ use crate::deprecations::deprecate_trailing_option_default;
|
|||
use crate::utils::{Ctx, LitCStr};
|
||||
use crate::{
|
||||
attributes::{FromPyWithAttribute, TextSignatureAttribute, TextSignatureAttributeValue},
|
||||
deprecations::{Deprecation, Deprecations},
|
||||
params::{impl_arg_params, Holders},
|
||||
pyfunction::{
|
||||
FunctionSignature, PyFunctionArgPyO3Attributes, PyFunctionOptions, SignatureAttribute,
|
||||
|
@ -411,7 +410,6 @@ pub struct FnSpec<'a> {
|
|||
pub text_signature: Option<TextSignatureAttribute>,
|
||||
pub asyncness: Option<syn::Token![async]>,
|
||||
pub unsafety: Option<syn::Token![unsafe]>,
|
||||
pub deprecations: Deprecations<'a>,
|
||||
}
|
||||
|
||||
pub fn parse_method_receiver(arg: &syn::FnArg) -> Result<SelfType> {
|
||||
|
@ -443,7 +441,6 @@ impl<'a> FnSpec<'a> {
|
|||
sig: &'a mut syn::Signature,
|
||||
meth_attrs: &mut Vec<syn::Attribute>,
|
||||
options: PyFunctionOptions,
|
||||
ctx: &'a Ctx,
|
||||
) -> Result<FnSpec<'a>> {
|
||||
let PyFunctionOptions {
|
||||
text_signature,
|
||||
|
@ -453,9 +450,8 @@ impl<'a> FnSpec<'a> {
|
|||
} = options;
|
||||
|
||||
let mut python_name = name.map(|name| name.value.0);
|
||||
let mut deprecations = Deprecations::new(ctx);
|
||||
|
||||
let fn_type = Self::parse_fn_type(sig, meth_attrs, &mut python_name, &mut deprecations)?;
|
||||
let fn_type = Self::parse_fn_type(sig, meth_attrs, &mut python_name)?;
|
||||
ensure_signatures_on_valid_method(&fn_type, signature.as_ref(), text_signature.as_ref())?;
|
||||
|
||||
let name = &sig.ident;
|
||||
|
@ -493,7 +489,6 @@ impl<'a> FnSpec<'a> {
|
|||
text_signature,
|
||||
asyncness: sig.asyncness,
|
||||
unsafety: sig.unsafety,
|
||||
deprecations,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -507,9 +502,8 @@ impl<'a> FnSpec<'a> {
|
|||
sig: &syn::Signature,
|
||||
meth_attrs: &mut Vec<syn::Attribute>,
|
||||
python_name: &mut Option<syn::Ident>,
|
||||
deprecations: &mut Deprecations<'_>,
|
||||
) -> Result<FnType> {
|
||||
let mut method_attributes = parse_method_attributes(meth_attrs, deprecations)?;
|
||||
let mut method_attributes = parse_method_attributes(meth_attrs)?;
|
||||
|
||||
let name = &sig.ident;
|
||||
let parse_receiver = |msg: &'static str| {
|
||||
|
@ -683,11 +677,10 @@ impl<'a> FnSpec<'a> {
|
|||
}
|
||||
_ => {
|
||||
if let Some(self_arg) = self_arg() {
|
||||
let self_checker = holders.push_gil_refs_checker(self_arg.span());
|
||||
quote! {
|
||||
function(
|
||||
// NB #self_arg includes a comma, so none inserted here
|
||||
#pyo3_path::impl_::deprecations::inspect_type(#self_arg &#self_checker),
|
||||
#self_arg
|
||||
#(#args),*
|
||||
)
|
||||
}
|
||||
|
@ -714,11 +707,10 @@ impl<'a> FnSpec<'a> {
|
|||
}
|
||||
call
|
||||
} else if let Some(self_arg) = self_arg() {
|
||||
let self_checker = holders.push_gil_refs_checker(self_arg.span());
|
||||
quote! {
|
||||
function(
|
||||
// NB #self_arg includes a comma, so none inserted here
|
||||
#pyo3_path::impl_::deprecations::inspect_type(#self_arg &#self_checker),
|
||||
#self_arg
|
||||
#(#args),*
|
||||
)
|
||||
}
|
||||
|
@ -762,7 +754,6 @@ impl<'a> FnSpec<'a> {
|
|||
})
|
||||
.collect();
|
||||
let call = rust_call(args, &mut holders);
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
let init_holders = holders.init_holders(ctx);
|
||||
quote! {
|
||||
unsafe fn #ident<'py>(
|
||||
|
@ -774,7 +765,6 @@ impl<'a> FnSpec<'a> {
|
|||
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||
#init_holders
|
||||
let result = #call;
|
||||
#check_gil_refs
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -784,7 +774,6 @@ impl<'a> FnSpec<'a> {
|
|||
let (arg_convert, args) = impl_arg_params(self, cls, true, &mut holders, ctx);
|
||||
let call = rust_call(args, &mut holders);
|
||||
let init_holders = holders.init_holders(ctx);
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
|
||||
quote! {
|
||||
unsafe fn #ident<'py>(
|
||||
|
@ -800,7 +789,6 @@ impl<'a> FnSpec<'a> {
|
|||
#arg_convert
|
||||
#init_holders
|
||||
let result = #call;
|
||||
#check_gil_refs
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -810,7 +798,6 @@ impl<'a> FnSpec<'a> {
|
|||
let (arg_convert, args) = impl_arg_params(self, cls, false, &mut holders, ctx);
|
||||
let call = rust_call(args, &mut holders);
|
||||
let init_holders = holders.init_holders(ctx);
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
|
||||
quote! {
|
||||
unsafe fn #ident<'py>(
|
||||
|
@ -825,7 +812,6 @@ impl<'a> FnSpec<'a> {
|
|||
#arg_convert
|
||||
#init_holders
|
||||
let result = #call;
|
||||
#check_gil_refs
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -838,7 +824,6 @@ impl<'a> FnSpec<'a> {
|
|||
.self_arg(cls, ExtractErrorMode::Raise, &mut holders, ctx);
|
||||
let call = quote_spanned! {*output_span=> #rust_name(#self_arg #(#args),*) };
|
||||
let init_holders = holders.init_holders(ctx);
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
quote! {
|
||||
unsafe fn #ident(
|
||||
py: #pyo3_path::Python<'_>,
|
||||
|
@ -854,7 +839,6 @@ impl<'a> FnSpec<'a> {
|
|||
#init_holders
|
||||
let result = #call;
|
||||
let initializer: #pyo3_path::PyClassInitializer::<#cls> = result.convert(py)?;
|
||||
#check_gil_refs
|
||||
#pyo3_path::impl_::pymethods::tp_new_impl(py, initializer, _slf)
|
||||
}
|
||||
}
|
||||
|
@ -992,10 +976,7 @@ impl MethodTypeAttribute {
|
|||
/// If the attribute does not match one of the attribute names, returns `Ok(None)`.
|
||||
///
|
||||
/// Otherwise will either return a parse error or the attribute.
|
||||
fn parse_if_matching_attribute(
|
||||
attr: &syn::Attribute,
|
||||
deprecations: &mut Deprecations<'_>,
|
||||
) -> Result<Option<Self>> {
|
||||
fn parse_if_matching_attribute(attr: &syn::Attribute) -> Result<Option<Self>> {
|
||||
fn ensure_no_arguments(meta: &syn::Meta, ident: &str) -> syn::Result<()> {
|
||||
match meta {
|
||||
syn::Meta::Path(_) => Ok(()),
|
||||
|
@ -1039,11 +1020,6 @@ impl MethodTypeAttribute {
|
|||
if path.is_ident("new") {
|
||||
ensure_no_arguments(meta, "new")?;
|
||||
Ok(Some(MethodTypeAttribute::New(path.span())))
|
||||
} else if path.is_ident("__new__") {
|
||||
let span = path.span();
|
||||
deprecations.push(Deprecation::PyMethodsNewDeprecatedForm, span);
|
||||
ensure_no_arguments(meta, "__new__")?;
|
||||
Ok(Some(MethodTypeAttribute::New(span)))
|
||||
} else if path.is_ident("classmethod") {
|
||||
ensure_no_arguments(meta, "classmethod")?;
|
||||
Ok(Some(MethodTypeAttribute::ClassMethod(path.span())))
|
||||
|
@ -1078,15 +1054,12 @@ impl Display for MethodTypeAttribute {
|
|||
}
|
||||
}
|
||||
|
||||
fn parse_method_attributes(
|
||||
attrs: &mut Vec<syn::Attribute>,
|
||||
deprecations: &mut Deprecations<'_>,
|
||||
) -> Result<Vec<MethodTypeAttribute>> {
|
||||
fn parse_method_attributes(attrs: &mut Vec<syn::Attribute>) -> Result<Vec<MethodTypeAttribute>> {
|
||||
let mut new_attrs = Vec::new();
|
||||
let mut found_attrs = Vec::new();
|
||||
|
||||
for attr in attrs.drain(..) {
|
||||
match MethodTypeAttribute::parse_if_matching_attribute(&attr, deprecations)? {
|
||||
match MethodTypeAttribute::parse_if_matching_attribute(&attr)? {
|
||||
Some(attr) => found_attrs.push(attr),
|
||||
None => new_attrs.push(attr),
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
use crate::{
|
||||
attributes::{
|
||||
self, take_attributes, take_pyo3_options, CrateAttribute, ModuleAttribute, NameAttribute,
|
||||
SubmoduleAttribute,
|
||||
self, kw, take_attributes, take_pyo3_options, CrateAttribute, ModuleAttribute,
|
||||
NameAttribute, SubmoduleAttribute,
|
||||
},
|
||||
get_doc,
|
||||
pyclass::PyClassPyO3Option,
|
||||
|
@ -26,97 +26,88 @@ use syn::{
|
|||
#[derive(Default)]
|
||||
pub struct PyModuleOptions {
|
||||
krate: Option<CrateAttribute>,
|
||||
name: Option<syn::Ident>,
|
||||
name: Option<NameAttribute>,
|
||||
module: Option<ModuleAttribute>,
|
||||
is_submodule: bool,
|
||||
submodule: Option<kw::submodule>,
|
||||
}
|
||||
|
||||
impl PyModuleOptions {
|
||||
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>) -> Result<Self> {
|
||||
impl Parse for PyModuleOptions {
|
||||
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||
let mut options: PyModuleOptions = Default::default();
|
||||
|
||||
for option in take_pyo3_options(attrs)? {
|
||||
match option {
|
||||
PyModulePyO3Option::Name(name) => options.set_name(name.value.0)?,
|
||||
PyModulePyO3Option::Crate(path) => options.set_crate(path)?,
|
||||
PyModulePyO3Option::Module(module) => options.set_module(module)?,
|
||||
PyModulePyO3Option::Submodule(submod) => options.set_submodule(submod)?,
|
||||
}
|
||||
}
|
||||
options.add_attributes(
|
||||
Punctuated::<PyModulePyO3Option, syn::Token![,]>::parse_terminated(input)?,
|
||||
)?;
|
||||
|
||||
Ok(options)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_name(&mut self, name: syn::Ident) -> Result<()> {
|
||||
ensure_spanned!(
|
||||
self.name.is_none(),
|
||||
name.span() => "`name` may only be specified once"
|
||||
);
|
||||
|
||||
self.name = Some(name);
|
||||
Ok(())
|
||||
impl PyModuleOptions {
|
||||
fn take_pyo3_options(&mut self, attrs: &mut Vec<syn::Attribute>) -> Result<()> {
|
||||
self.add_attributes(take_pyo3_options(attrs)?)
|
||||
}
|
||||
|
||||
fn set_crate(&mut self, path: CrateAttribute) -> Result<()> {
|
||||
ensure_spanned!(
|
||||
self.krate.is_none(),
|
||||
path.span() => "`crate` may only be specified once"
|
||||
);
|
||||
|
||||
self.krate = Some(path);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_module(&mut self, name: ModuleAttribute) -> Result<()> {
|
||||
ensure_spanned!(
|
||||
self.module.is_none(),
|
||||
name.span() => "`module` may only be specified once"
|
||||
);
|
||||
|
||||
self.module = Some(name);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_submodule(&mut self, submod: SubmoduleAttribute) -> Result<()> {
|
||||
ensure_spanned!(
|
||||
!self.is_submodule,
|
||||
submod.span() => "`submodule` may only be specified once"
|
||||
);
|
||||
|
||||
self.is_submodule = true;
|
||||
fn add_attributes(
|
||||
&mut self,
|
||||
attrs: impl IntoIterator<Item = PyModulePyO3Option>,
|
||||
) -> Result<()> {
|
||||
macro_rules! set_option {
|
||||
($key:ident $(, $extra:literal)?) => {
|
||||
{
|
||||
ensure_spanned!(
|
||||
self.$key.is_none(),
|
||||
$key.span() => concat!("`", stringify!($key), "` may only be specified once" $(, $extra)?)
|
||||
);
|
||||
self.$key = Some($key);
|
||||
}
|
||||
};
|
||||
}
|
||||
for attr in attrs {
|
||||
match attr {
|
||||
PyModulePyO3Option::Crate(krate) => set_option!(krate),
|
||||
PyModulePyO3Option::Name(name) => set_option!(name),
|
||||
PyModulePyO3Option::Module(module) => set_option!(module),
|
||||
PyModulePyO3Option::Submodule(submodule) => set_option!(
|
||||
submodule,
|
||||
" (it is implicitly always specified for nested modules)"
|
||||
),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pymodule_module_impl(
|
||||
mut module: syn::ItemMod,
|
||||
mut is_submodule: bool,
|
||||
module: &mut syn::ItemMod,
|
||||
mut options: PyModuleOptions,
|
||||
) -> Result<TokenStream> {
|
||||
let syn::ItemMod {
|
||||
attrs,
|
||||
vis,
|
||||
unsafety: _,
|
||||
ident,
|
||||
mod_token: _,
|
||||
mod_token,
|
||||
content,
|
||||
semi: _,
|
||||
} = &mut module;
|
||||
} = module;
|
||||
let items = if let Some((_, items)) = content {
|
||||
items
|
||||
} else {
|
||||
bail_spanned!(module.span() => "`#[pymodule]` can only be used on inline modules")
|
||||
bail_spanned!(mod_token.span() => "`#[pymodule]` can only be used on inline modules")
|
||||
};
|
||||
let options = PyModuleOptions::from_attrs(attrs)?;
|
||||
options.take_pyo3_options(attrs)?;
|
||||
let ctx = &Ctx::new(&options.krate, None);
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let doc = get_doc(attrs, None, ctx);
|
||||
let name = options.name.unwrap_or_else(|| ident.unraw());
|
||||
let name = options
|
||||
.name
|
||||
.map_or_else(|| ident.unraw(), |name| name.value.0);
|
||||
let full_name = if let Some(module) = &options.module {
|
||||
format!("{}.{}", module.value.value(), name)
|
||||
} else {
|
||||
name.to_string()
|
||||
};
|
||||
is_submodule = is_submodule || options.is_submodule;
|
||||
|
||||
let mut module_items = Vec::new();
|
||||
let mut module_items_cfg_attrs = Vec::new();
|
||||
|
@ -273,6 +264,9 @@ pub fn pymodule_module_impl(
|
|||
)? {
|
||||
set_module_attribute(&mut item_mod.attrs, &full_name);
|
||||
}
|
||||
item_mod
|
||||
.attrs
|
||||
.push(parse_quote_spanned!(item_mod.mod_token.span()=> #[pyo3(submodule)]));
|
||||
}
|
||||
}
|
||||
Item::ForeignMod(item) => {
|
||||
|
@ -350,10 +344,11 @@ pub fn pymodule_module_impl(
|
|||
)
|
||||
}
|
||||
}};
|
||||
let initialization = module_initialization(&name, ctx, module_def, is_submodule);
|
||||
let initialization = module_initialization(&name, ctx, module_def, options.submodule.is_some());
|
||||
|
||||
Ok(quote!(
|
||||
#(#attrs)*
|
||||
#vis mod #ident {
|
||||
#vis #mod_token #ident {
|
||||
#(#items)*
|
||||
|
||||
#initialization
|
||||
|
@ -365,7 +360,7 @@ pub fn pymodule_module_impl(
|
|||
#module_items::_PYO3_DEF.add_to_module(module)?;
|
||||
)*
|
||||
#pymodule_init
|
||||
Ok(())
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
}
|
||||
))
|
||||
|
@ -373,14 +368,18 @@ pub fn pymodule_module_impl(
|
|||
|
||||
/// Generates the function that is called by the python interpreter to initialize the native
|
||||
/// module
|
||||
pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream> {
|
||||
let options = PyModuleOptions::from_attrs(&mut function.attrs)?;
|
||||
process_functions_in_module(&options, &mut function)?;
|
||||
pub fn pymodule_function_impl(
|
||||
function: &mut syn::ItemFn,
|
||||
mut options: PyModuleOptions,
|
||||
) -> Result<TokenStream> {
|
||||
options.take_pyo3_options(&mut function.attrs)?;
|
||||
process_functions_in_module(&options, function)?;
|
||||
let ctx = &Ctx::new(&options.krate, None);
|
||||
let stmts = std::mem::take(&mut function.block.stmts);
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let ident = &function.sig.ident;
|
||||
let name = options.name.unwrap_or_else(|| ident.unraw());
|
||||
let name = options
|
||||
.name
|
||||
.map_or_else(|| ident.unraw(), |name| name.value.0);
|
||||
let vis = &function.vis;
|
||||
let doc = get_doc(&function.attrs, None, ctx);
|
||||
|
||||
|
@ -394,32 +393,7 @@ pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream>
|
|||
module_args
|
||||
.push(quote!(::std::convert::Into::into(#pyo3_path::impl_::pymethods::BoundRef(module))));
|
||||
|
||||
let extractors = function
|
||||
.sig
|
||||
.inputs
|
||||
.iter()
|
||||
.filter_map(|param| {
|
||||
if let syn::FnArg::Typed(pat_type) = param {
|
||||
if let syn::Pat::Ident(pat_ident) = &*pat_type.pat {
|
||||
let ident: &syn::Ident = &pat_ident.ident;
|
||||
return Some([
|
||||
parse_quote!{ let check_gil_refs = #pyo3_path::impl_::deprecations::GilRefs::new(); },
|
||||
parse_quote! { let #ident = #pyo3_path::impl_::deprecations::inspect_type(#ident, &check_gil_refs); },
|
||||
parse_quote_spanned! { pat_type.span() => check_gil_refs.function_arg(); },
|
||||
]);
|
||||
}
|
||||
}
|
||||
None
|
||||
})
|
||||
.flatten();
|
||||
|
||||
function.block.stmts = extractors.chain(stmts).collect();
|
||||
function
|
||||
.attrs
|
||||
.push(parse_quote!(#[allow(clippy::used_underscore_binding)]));
|
||||
|
||||
Ok(quote! {
|
||||
#function
|
||||
#[doc(hidden)]
|
||||
#vis mod #ident {
|
||||
#initialization
|
||||
|
|
|
@ -10,14 +10,12 @@ use syn::spanned::Spanned;
|
|||
|
||||
pub struct Holders {
|
||||
holders: Vec<syn::Ident>,
|
||||
gil_refs_checkers: Vec<GilRefChecker>,
|
||||
}
|
||||
|
||||
impl Holders {
|
||||
pub fn new() -> Self {
|
||||
Holders {
|
||||
holders: Vec::new(),
|
||||
gil_refs_checkers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,58 +25,14 @@ impl Holders {
|
|||
holder
|
||||
}
|
||||
|
||||
pub fn push_gil_refs_checker(&mut self, span: Span) -> syn::Ident {
|
||||
let gil_refs_checker = syn::Ident::new(
|
||||
&format!("gil_refs_checker_{}", self.gil_refs_checkers.len()),
|
||||
span,
|
||||
);
|
||||
self.gil_refs_checkers
|
||||
.push(GilRefChecker::FunctionArg(gil_refs_checker.clone()));
|
||||
gil_refs_checker
|
||||
}
|
||||
|
||||
pub fn push_from_py_with_checker(&mut self, span: Span) -> syn::Ident {
|
||||
let gil_refs_checker = syn::Ident::new(
|
||||
&format!("gil_refs_checker_{}", self.gil_refs_checkers.len()),
|
||||
span,
|
||||
);
|
||||
self.gil_refs_checkers
|
||||
.push(GilRefChecker::FromPyWith(gil_refs_checker.clone()));
|
||||
gil_refs_checker
|
||||
}
|
||||
|
||||
pub fn init_holders(&self, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let holders = &self.holders;
|
||||
let gil_refs_checkers = self.gil_refs_checkers.iter().map(|checker| match checker {
|
||||
GilRefChecker::FunctionArg(ident) => ident,
|
||||
GilRefChecker::FromPyWith(ident) => ident,
|
||||
});
|
||||
quote! {
|
||||
#[allow(clippy::let_unit_value)]
|
||||
#(let mut #holders = #pyo3_path::impl_::extract_argument::FunctionArgumentHolder::INIT;)*
|
||||
#(let #gil_refs_checkers = #pyo3_path::impl_::deprecations::GilRefs::new();)*
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_gil_refs(&self) -> TokenStream {
|
||||
self.gil_refs_checkers
|
||||
.iter()
|
||||
.map(|checker| match checker {
|
||||
GilRefChecker::FunctionArg(ident) => {
|
||||
quote_spanned! { ident.span() => #ident.function_arg(); }
|
||||
}
|
||||
GilRefChecker::FromPyWith(ident) => {
|
||||
quote_spanned! { ident.span() => #ident.from_py_with_arg(); }
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
enum GilRefChecker {
|
||||
FunctionArg(syn::Ident),
|
||||
FromPyWith(syn::Ident),
|
||||
}
|
||||
|
||||
/// Return true if the argument list is simply (*args, **kwds).
|
||||
|
@ -89,17 +43,6 @@ pub fn is_forwarded_args(signature: &FunctionSignature<'_>) -> bool {
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn check_arg_for_gil_refs(
|
||||
tokens: TokenStream,
|
||||
gil_refs_checker: syn::Ident,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
quote! {
|
||||
#pyo3_path::impl_::deprecations::inspect_type(#tokens, &#gil_refs_checker)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn impl_arg_params(
|
||||
spec: &FnSpec<'_>,
|
||||
self_: Option<&syn::Type>,
|
||||
|
@ -119,9 +62,7 @@ pub fn impl_arg_params(
|
|||
let from_py_with = &arg.from_py_with()?.value;
|
||||
let from_py_with_holder = format_ident!("from_py_with_{}", i);
|
||||
Some(quote_spanned! { from_py_with.span() =>
|
||||
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||
let #from_py_with_holder = #pyo3_path::impl_::deprecations::inspect_fn(#from_py_with, &e);
|
||||
e.from_py_with_arg();
|
||||
let #from_py_with_holder = #from_py_with;
|
||||
})
|
||||
})
|
||||
.collect::<TokenStream>();
|
||||
|
@ -250,8 +191,7 @@ fn impl_arg_param(
|
|||
let from_py_with = format_ident!("from_py_with_{}", pos);
|
||||
let arg_value = quote!(#args_array[#option_pos].as_deref());
|
||||
*option_pos += 1;
|
||||
let tokens = impl_regular_arg_param(arg, from_py_with, arg_value, holders, ctx);
|
||||
check_arg_for_gil_refs(tokens, holders.push_gil_refs_checker(arg.ty.span()), ctx)
|
||||
impl_regular_arg_param(arg, from_py_with, arg_value, holders, ctx)
|
||||
}
|
||||
FnArg::VarArgs(arg) => {
|
||||
let holder = holders.push_holder(arg.name.span());
|
||||
|
|
|
@ -12,7 +12,6 @@ use crate::attributes::{
|
|||
self, kw, take_pyo3_options, CrateAttribute, ExtendsAttribute, FreelistAttribute,
|
||||
ModuleAttribute, NameAttribute, NameLitStr, RenameAllAttribute,
|
||||
};
|
||||
use crate::deprecations::Deprecations;
|
||||
use crate::konst::{ConstAttributes, ConstSpec};
|
||||
use crate::method::{FnArg, FnSpec, PyArg, RegularArg};
|
||||
use crate::pyfunction::ConstructorAttribute;
|
||||
|
@ -232,17 +231,19 @@ pub fn build_py_class(
|
|||
|
||||
if let Some(lt) = class.generics.lifetimes().next() {
|
||||
bail_spanned!(
|
||||
lt.span() =>
|
||||
"#[pyclass] cannot have lifetime parameters. \
|
||||
For an explanation, see https://pyo3.rs/latest/class.html#no-lifetime-parameters"
|
||||
lt.span() => concat!(
|
||||
"#[pyclass] cannot have lifetime parameters. For an explanation, see \
|
||||
https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#no-lifetime-parameters"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
ensure_spanned!(
|
||||
class.generics.params.is_empty(),
|
||||
class.generics.span() =>
|
||||
"#[pyclass] cannot have generic parameters. \
|
||||
For an explanation, see https://pyo3.rs/latest/class.html#no-generic-parameters"
|
||||
class.generics.span() => concat!(
|
||||
"#[pyclass] cannot have generic parameters. For an explanation, see \
|
||||
https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#no-generic-parameters"
|
||||
)
|
||||
);
|
||||
|
||||
let mut field_options: Vec<(&syn::Field, FieldPyO3Options)> = match &mut class.fields {
|
||||
|
@ -384,7 +385,7 @@ fn impl_class(
|
|||
ctx: &Ctx,
|
||||
) -> syn::Result<TokenStream> {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let pytypeinfo_impl = impl_pytypeinfo(cls, args, None, ctx);
|
||||
let pytypeinfo_impl = impl_pytypeinfo(cls, args, ctx);
|
||||
|
||||
let (default_richcmp, default_richcmp_slot) =
|
||||
pyclass_richcmp(&args.options, &syn::parse_quote!(#cls), ctx)?;
|
||||
|
@ -779,7 +780,7 @@ fn impl_simple_enum(
|
|||
let cls = simple_enum.ident;
|
||||
let ty: syn::Type = syn::parse_quote!(#cls);
|
||||
let variants = simple_enum.variants;
|
||||
let pytypeinfo = impl_pytypeinfo(cls, args, None, ctx);
|
||||
let pytypeinfo = impl_pytypeinfo(cls, args, ctx);
|
||||
|
||||
for variant in &variants {
|
||||
ensure_spanned!(variant.options.constructor.is_none(), variant.options.constructor.span() => "`constructor` can't be used on a simple enum variant");
|
||||
|
@ -889,7 +890,7 @@ fn impl_complex_enum(
|
|||
let ctx = &Ctx::new(&args.options.krate, None);
|
||||
let cls = complex_enum.ident;
|
||||
let variants = complex_enum.variants;
|
||||
let pytypeinfo = impl_pytypeinfo(cls, &args, None, ctx);
|
||||
let pytypeinfo = impl_pytypeinfo(cls, &args, ctx);
|
||||
|
||||
let (default_richcmp, default_richcmp_slot) = pyclass_richcmp(&args.options, &ty, ctx)?;
|
||||
let (default_hash, default_hash_slot) = pyclass_hash(&args.options, &ty, ctx)?;
|
||||
|
@ -977,7 +978,7 @@ fn impl_complex_enum(
|
|||
},
|
||||
};
|
||||
|
||||
let variant_cls_pytypeinfo = impl_pytypeinfo(&variant_cls, &variant_args, None, ctx);
|
||||
let variant_cls_pytypeinfo = impl_pytypeinfo(&variant_cls, &variant_args, ctx);
|
||||
variant_cls_pytypeinfos.push(variant_cls_pytypeinfo);
|
||||
|
||||
let (variant_cls_impl, field_getters, mut slots) =
|
||||
|
@ -1057,7 +1058,6 @@ fn impl_complex_enum_variant_match_args(
|
|||
attributes: ConstAttributes {
|
||||
is_class_attr: true,
|
||||
name: None,
|
||||
deprecations: Deprecations::new(ctx),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -1318,7 +1318,6 @@ fn generate_protocol_slot(
|
|||
&mut method.sig,
|
||||
&mut Vec::new(),
|
||||
PyFunctionOptions::default(),
|
||||
ctx,
|
||||
)
|
||||
.unwrap();
|
||||
slot.generate_type_slot(&syn::parse_quote!(#cls), &spec, name, ctx)
|
||||
|
@ -1334,7 +1333,6 @@ fn generate_default_protocol_slot(
|
|||
&mut method.sig,
|
||||
&mut Vec::new(),
|
||||
PyFunctionOptions::default(),
|
||||
ctx,
|
||||
)
|
||||
.unwrap();
|
||||
let name = spec.name.to_string();
|
||||
|
@ -1360,7 +1358,6 @@ fn simple_enum_default_methods<'a>(
|
|||
kw: syn::parse_quote! { name },
|
||||
value: NameLitStr(py_ident.clone()),
|
||||
}),
|
||||
deprecations: Deprecations::new(ctx),
|
||||
},
|
||||
};
|
||||
unit_variant_names
|
||||
|
@ -1383,7 +1380,6 @@ fn complex_enum_default_methods<'a>(
|
|||
kw: syn::parse_quote! { name },
|
||||
value: NameLitStr(py_ident.clone()),
|
||||
}),
|
||||
deprecations: Deprecations::new(ctx),
|
||||
},
|
||||
};
|
||||
variant_names
|
||||
|
@ -1397,19 +1393,17 @@ fn complex_enum_default_methods<'a>(
|
|||
pub fn gen_complex_enum_variant_attr(
|
||||
cls: &syn::Ident,
|
||||
cls_type: &syn::Type,
|
||||
spec: &ConstSpec<'_>,
|
||||
spec: &ConstSpec,
|
||||
ctx: &Ctx,
|
||||
) -> MethodAndMethodDef {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let member = &spec.rust_ident;
|
||||
let wrapper_ident = format_ident!("__pymethod_variant_cls_{}__", member);
|
||||
let deprecations = &spec.attributes.deprecations;
|
||||
let python_name = spec.null_terminated_python_name(ctx);
|
||||
|
||||
let variant_cls = format_ident!("{}_{}", cls, member);
|
||||
let associated_method = quote! {
|
||||
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
|
||||
#deprecations
|
||||
::std::result::Result::Ok(py.get_type_bound::<#variant_cls>().into_any().unbind())
|
||||
}
|
||||
};
|
||||
|
@ -1497,7 +1491,6 @@ fn complex_enum_struct_variant_new<'a>(
|
|||
text_signature: None,
|
||||
asyncness: None,
|
||||
unsafety: None,
|
||||
deprecations: Deprecations::new(ctx),
|
||||
};
|
||||
|
||||
crate::pymethod::impl_py_method_def_new(&variant_cls_type, &spec, ctx)
|
||||
|
@ -1552,7 +1545,6 @@ fn complex_enum_tuple_variant_new<'a>(
|
|||
text_signature: None,
|
||||
asyncness: None,
|
||||
unsafety: None,
|
||||
deprecations: Deprecations::new(ctx),
|
||||
};
|
||||
|
||||
crate::pymethod::impl_py_method_def_new(&variant_cls_type, &spec, ctx)
|
||||
|
@ -1577,7 +1569,6 @@ fn complex_enum_variant_field_getter<'a>(
|
|||
text_signature: None,
|
||||
asyncness: None,
|
||||
unsafety: None,
|
||||
deprecations: Deprecations::new(ctx),
|
||||
};
|
||||
|
||||
let property_type = crate::pymethod::PropertyType::Function {
|
||||
|
@ -1641,12 +1632,7 @@ fn descriptors_to_items(
|
|||
Ok(items)
|
||||
}
|
||||
|
||||
fn impl_pytypeinfo(
|
||||
cls: &syn::Ident,
|
||||
attr: &PyClassArgs,
|
||||
deprecations: Option<&Deprecations<'_>>,
|
||||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
fn impl_pytypeinfo(cls: &syn::Ident, attr: &PyClassArgs, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let cls_name = get_class_python_name(cls, attr).to_string();
|
||||
|
||||
|
@ -1677,8 +1663,6 @@ fn impl_pytypeinfo(
|
|||
#[inline]
|
||||
fn type_object_raw(py: #pyo3_path::Python<'_>) -> *mut #pyo3_path::ffi::PyTypeObject {
|
||||
use #pyo3_path::prelude::PyTypeMethods;
|
||||
#deprecations
|
||||
|
||||
<#cls as #pyo3_path::impl_::pyclass::PyClassImpl>::lazy_type_object()
|
||||
.get_or_init(py)
|
||||
.as_type_ptr()
|
||||
|
|
|
@ -4,7 +4,6 @@ use crate::{
|
|||
self, get_pyo3_options, take_attributes, take_pyo3_options, CrateAttribute,
|
||||
FromPyWithAttribute, NameAttribute, TextSignatureAttribute,
|
||||
},
|
||||
deprecations::Deprecations,
|
||||
method::{self, CallingConvention, FnArg},
|
||||
pymethod::check_generic,
|
||||
};
|
||||
|
@ -252,7 +251,6 @@ pub fn impl_wrap_pyfunction(
|
|||
text_signature,
|
||||
asyncness: func.sig.asyncness,
|
||||
unsafety: func.sig.unsafety,
|
||||
deprecations: Deprecations::new(ctx),
|
||||
};
|
||||
|
||||
let vis = &func.vis;
|
||||
|
|
|
@ -130,7 +130,7 @@ pub fn impl_methods(
|
|||
}
|
||||
syn::ImplItem::Const(konst) => {
|
||||
let ctx = &Ctx::new(&options.krate, None);
|
||||
let attributes = ConstAttributes::from_attrs(&mut konst.attrs, ctx)?;
|
||||
let attributes = ConstAttributes::from_attrs(&mut konst.attrs)?;
|
||||
if attributes.is_class_attr {
|
||||
let spec = ConstSpec {
|
||||
rust_ident: konst.ident.clone(),
|
||||
|
@ -182,16 +182,14 @@ pub fn impl_methods(
|
|||
})
|
||||
}
|
||||
|
||||
pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec<'_>, ctx: &Ctx) -> MethodAndMethodDef {
|
||||
pub fn gen_py_const(cls: &syn::Type, spec: &ConstSpec, ctx: &Ctx) -> MethodAndMethodDef {
|
||||
let member = &spec.rust_ident;
|
||||
let wrapper_ident = format_ident!("__pymethod_{}__", member);
|
||||
let deprecations = &spec.attributes.deprecations;
|
||||
let python_name = spec.null_terminated_python_name(ctx);
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
let associated_method = quote! {
|
||||
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
|
||||
#deprecations
|
||||
::std::result::Result::Ok(#pyo3_path::IntoPy::into_py(#cls::#member, py))
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::ffi::CString;
|
|||
use crate::attributes::{NameAttribute, RenamingRule};
|
||||
use crate::deprecations::deprecate_trailing_option_default;
|
||||
use crate::method::{CallingConvention, ExtractErrorMode, PyArg};
|
||||
use crate::params::{check_arg_for_gil_refs, impl_regular_arg_param, Holders};
|
||||
use crate::params::{impl_regular_arg_param, Holders};
|
||||
use crate::utils::PythonDoc;
|
||||
use crate::utils::{Ctx, LitCStr};
|
||||
use crate::{
|
||||
|
@ -164,9 +164,8 @@ impl<'a> PyMethod<'a> {
|
|||
sig: &'a mut syn::Signature,
|
||||
meth_attrs: &mut Vec<syn::Attribute>,
|
||||
options: PyFunctionOptions,
|
||||
ctx: &'a Ctx,
|
||||
) -> Result<Self> {
|
||||
let spec = FnSpec::parse(sig, meth_attrs, options, ctx)?;
|
||||
let spec = FnSpec::parse(sig, meth_attrs, options)?;
|
||||
|
||||
let method_name = spec.python_name.to_string();
|
||||
let kind = PyMethodKind::from_name(&method_name);
|
||||
|
@ -195,7 +194,7 @@ pub fn gen_py_method(
|
|||
) -> Result<GeneratedPyMethod> {
|
||||
check_generic(sig)?;
|
||||
ensure_function_options_valid(&options)?;
|
||||
let method = PyMethod::parse(sig, meth_attrs, options, ctx)?;
|
||||
let method = PyMethod::parse(sig, meth_attrs, options)?;
|
||||
let spec = &method.spec;
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
|
||||
|
@ -356,7 +355,6 @@ pub fn impl_py_method_def_new(
|
|||
|| quote!(::std::option::Option::None),
|
||||
|text_signature| quote!(::std::option::Option::Some(#text_signature)),
|
||||
);
|
||||
let deprecations = &spec.deprecations;
|
||||
let slot_def = quote! {
|
||||
#pyo3_path::ffi::PyType_Slot {
|
||||
slot: #pyo3_path::ffi::Py_tp_new,
|
||||
|
@ -365,10 +363,7 @@ pub fn impl_py_method_def_new(
|
|||
subtype: *mut #pyo3_path::ffi::PyTypeObject,
|
||||
args: *mut #pyo3_path::ffi::PyObject,
|
||||
kwargs: *mut #pyo3_path::ffi::PyObject,
|
||||
) -> *mut #pyo3_path::ffi::PyObject
|
||||
{
|
||||
#deprecations
|
||||
|
||||
) -> *mut #pyo3_path::ffi::PyObject {
|
||||
use #pyo3_path::impl_::pyclass::*;
|
||||
#[allow(unknown_lints, non_local_definitions)]
|
||||
impl PyClassNewTextSignature<#cls> for PyClassImplCollector<#cls> {
|
||||
|
@ -612,21 +607,18 @@ pub fn impl_py_setter_def(
|
|||
PropertyType::Function { spec, .. } => {
|
||||
let (_, args) = split_off_python_arg(&spec.signature.arguments);
|
||||
let value_arg = &args[0];
|
||||
let (from_py_with, ident) = if let Some(from_py_with) =
|
||||
&value_arg.from_py_with().as_ref().map(|f| &f.value)
|
||||
{
|
||||
let ident = syn::Ident::new("from_py_with", from_py_with.span());
|
||||
(
|
||||
quote_spanned! { from_py_with.span() =>
|
||||
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
||||
let #ident = #pyo3_path::impl_::deprecations::inspect_fn(#from_py_with, &e);
|
||||
e.from_py_with_arg();
|
||||
},
|
||||
ident,
|
||||
)
|
||||
} else {
|
||||
(quote!(), syn::Ident::new("dummy", Span::call_site()))
|
||||
};
|
||||
let (from_py_with, ident) =
|
||||
if let Some(from_py_with) = &value_arg.from_py_with().as_ref().map(|f| &f.value) {
|
||||
let ident = syn::Ident::new("from_py_with", from_py_with.span());
|
||||
(
|
||||
quote_spanned! { from_py_with.span() =>
|
||||
let #ident = #from_py_with;
|
||||
},
|
||||
ident,
|
||||
)
|
||||
} else {
|
||||
(quote!(), syn::Ident::new("dummy", Span::call_site()))
|
||||
};
|
||||
|
||||
let arg = if let FnArg::Regular(arg) = &value_arg {
|
||||
arg
|
||||
|
@ -634,15 +626,13 @@ pub fn impl_py_setter_def(
|
|||
bail_spanned!(value_arg.name().span() => "The #[setter] value argument can't be *args, **kwargs or `cancel_handle`.");
|
||||
};
|
||||
|
||||
let tokens = impl_regular_arg_param(
|
||||
let extract = impl_regular_arg_param(
|
||||
arg,
|
||||
ident,
|
||||
quote!(::std::option::Option::Some(_value.into())),
|
||||
&mut holders,
|
||||
ctx,
|
||||
);
|
||||
let extract =
|
||||
check_arg_for_gil_refs(tokens, holders.push_gil_refs_checker(arg.ty.span()), ctx);
|
||||
|
||||
let deprecation = deprecate_trailing_option_default(spec);
|
||||
quote! {
|
||||
|
@ -660,12 +650,8 @@ pub fn impl_py_setter_def(
|
|||
.unwrap_or_default();
|
||||
|
||||
let holder = holders.push_holder(span);
|
||||
let gil_refs_checker = holders.push_gil_refs_checker(span);
|
||||
quote! {
|
||||
let _val = #pyo3_path::impl_::deprecations::inspect_type(
|
||||
#pyo3_path::impl_::extract_argument::extract_argument(_value.into(), &mut #holder, #name)?,
|
||||
&#gil_refs_checker
|
||||
);
|
||||
let _val = #pyo3_path::impl_::extract_argument::extract_argument(_value.into(), &mut #holder, #name)?;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -682,7 +668,6 @@ pub fn impl_py_setter_def(
|
|||
}
|
||||
|
||||
let init_holders = holders.init_holders(ctx);
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
let associated_method = quote! {
|
||||
#cfg_attrs
|
||||
unsafe fn #wrapper_ident(
|
||||
|
@ -698,7 +683,6 @@ pub fn impl_py_setter_def(
|
|||
#init_holders
|
||||
#extract
|
||||
let result = #setter_impl;
|
||||
#check_gil_refs
|
||||
#pyo3_path::callback::convert(py, result)
|
||||
}
|
||||
};
|
||||
|
@ -824,7 +808,6 @@ pub fn impl_py_getter_def(
|
|||
};
|
||||
|
||||
let init_holders = holders.init_holders(ctx);
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
let associated_method = quote! {
|
||||
#cfg_attrs
|
||||
unsafe fn #wrapper_ident(
|
||||
|
@ -833,7 +816,6 @@ pub fn impl_py_getter_def(
|
|||
) -> #pyo3_path::PyResult<*mut #pyo3_path::ffi::PyObject> {
|
||||
#init_holders
|
||||
let result = #body;
|
||||
#check_gil_refs
|
||||
result
|
||||
}
|
||||
};
|
||||
|
@ -1139,35 +1121,30 @@ fn extract_object(
|
|||
ctx: &Ctx,
|
||||
) -> TokenStream {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let gil_refs_checker = holders.push_gil_refs_checker(arg.ty().span());
|
||||
let name = arg.name().unraw().to_string();
|
||||
|
||||
let extract = if let Some(from_py_with) =
|
||||
arg.from_py_with().map(|from_py_with| &from_py_with.value)
|
||||
{
|
||||
let from_py_with_checker = holders.push_from_py_with_checker(from_py_with.span());
|
||||
quote! {
|
||||
#pyo3_path::impl_::extract_argument::from_py_with(
|
||||
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0,
|
||||
#name,
|
||||
#pyo3_path::impl_::deprecations::inspect_fn(#from_py_with, &#from_py_with_checker) as fn(_) -> _,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
let holder = holders.push_holder(Span::call_site());
|
||||
quote! {
|
||||
#pyo3_path::impl_::extract_argument::extract_argument(
|
||||
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0,
|
||||
&mut #holder,
|
||||
#name
|
||||
)
|
||||
}
|
||||
};
|
||||
let extract =
|
||||
if let Some(from_py_with) = arg.from_py_with().map(|from_py_with| &from_py_with.value) {
|
||||
quote! {
|
||||
#pyo3_path::impl_::extract_argument::from_py_with(
|
||||
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0,
|
||||
#name,
|
||||
#from_py_with as fn(_) -> _,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
let holder = holders.push_holder(Span::call_site());
|
||||
quote! {
|
||||
#pyo3_path::impl_::extract_argument::extract_argument(
|
||||
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0,
|
||||
&mut #holder,
|
||||
#name
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let extracted = extract_error_mode.handle_error(extract, ctx);
|
||||
quote! {
|
||||
#pyo3_path::impl_::deprecations::inspect_type(#extracted, &#gil_refs_checker)
|
||||
}
|
||||
quote!(#extracted)
|
||||
}
|
||||
|
||||
enum ReturnMode {
|
||||
|
@ -1177,15 +1154,13 @@ enum ReturnMode {
|
|||
}
|
||||
|
||||
impl ReturnMode {
|
||||
fn return_call_output(&self, call: TokenStream, ctx: &Ctx, holders: &Holders) -> TokenStream {
|
||||
fn return_call_output(&self, call: TokenStream, ctx: &Ctx) -> TokenStream {
|
||||
let Ctx { pyo3_path, .. } = ctx;
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
match self {
|
||||
ReturnMode::Conversion(conversion) => {
|
||||
let conversion = TokenGeneratorCtx(*conversion, ctx);
|
||||
quote! {
|
||||
let _result: #pyo3_path::PyResult<#conversion> = #pyo3_path::callback::convert(py, #call);
|
||||
#check_gil_refs
|
||||
#pyo3_path::callback::convert(py, _result)
|
||||
}
|
||||
}
|
||||
|
@ -1195,14 +1170,12 @@ impl ReturnMode {
|
|||
quote! {
|
||||
let _result = #call;
|
||||
use #pyo3_path::impl_::pymethods::{#traits};
|
||||
#check_gil_refs
|
||||
(&_result).#tag().convert(py, _result)
|
||||
}
|
||||
}
|
||||
ReturnMode::ReturnSelf => quote! {
|
||||
let _result: #pyo3_path::PyResult<()> = #pyo3_path::callback::convert(py, #call);
|
||||
_result?;
|
||||
#check_gil_refs
|
||||
#pyo3_path::ffi::Py_XINCREF(_raw_slf);
|
||||
::std::result::Result::Ok(_raw_slf)
|
||||
},
|
||||
|
@ -1369,12 +1342,10 @@ fn generate_method_body(
|
|||
let args = extract_proto_arguments(spec, arguments, extract_error_mode, holders, ctx)?;
|
||||
let call = quote! { #cls::#rust_name(#self_arg #(#args),*) };
|
||||
Ok(if let Some(return_mode) = return_mode {
|
||||
return_mode.return_call_output(call, ctx, holders)
|
||||
return_mode.return_call_output(call, ctx)
|
||||
} else {
|
||||
let check_gil_refs = holders.check_gil_refs();
|
||||
quote! {
|
||||
let result = #call;
|
||||
#check_gil_refs;
|
||||
#pyo3_path::callback::convert(py, result)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "pyo3-macros"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0-dev"
|
||||
description = "Proc macros for PyO3 package"
|
||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||
|
@ -22,7 +22,7 @@ gil-refs = ["pyo3-macros-backend/gil-refs"]
|
|||
proc-macro2 = { version = "1.0.60", default-features = false }
|
||||
quote = "1"
|
||||
syn = { version = "2", features = ["full", "extra-traits"] }
|
||||
pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.22.1" }
|
||||
pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.23.0-dev" }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||
use proc_macro2::TokenStream as TokenStream2;
|
||||
use pyo3_macros_backend::{
|
||||
build_derive_from_pyobject, build_py_class, build_py_enum, build_py_function, build_py_methods,
|
||||
pymodule_function_impl, pymodule_module_impl, PyClassArgs, PyClassMethodsType,
|
||||
PyFunctionOptions,
|
||||
PyFunctionOptions, PyModuleOptions,
|
||||
};
|
||||
use quote::quote;
|
||||
use syn::{parse::Nothing, parse_macro_input, Item};
|
||||
use syn::{parse_macro_input, Item};
|
||||
|
||||
/// A proc macro used to implement Python modules.
|
||||
///
|
||||
|
@ -24,6 +24,9 @@ use syn::{parse::Nothing, parse_macro_input, Item};
|
|||
/// | Annotation | Description |
|
||||
/// | :- | :- |
|
||||
/// | `#[pyo3(name = "...")]` | Defines the name of the module in Python. |
|
||||
/// | `#[pyo3(submodule)]` | Skips adding a `PyInit_` FFI symbol to the compiled binary. |
|
||||
/// | `#[pyo3(module = "...")]` | Defines the Python `dotted.path` to the parent module for use in introspection. |
|
||||
/// | `#[pyo3(crate = "pyo3")]` | Defines the path to PyO3 to use code generated by the macro. |
|
||||
///
|
||||
/// For more on creating Python modules see the [module section of the guide][1].
|
||||
///
|
||||
|
@ -32,35 +35,32 @@ use syn::{parse::Nothing, parse_macro_input, Item};
|
|||
/// `#[pymodule]` implementation generates a hidden module with the same name containing
|
||||
/// metadata about the module, which is used by `wrap_pymodule!`).
|
||||
///
|
||||
/// [1]: https://pyo3.rs/latest/module.html
|
||||
#[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/module.html")]
|
||||
#[proc_macro_attribute]
|
||||
pub fn pymodule(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
match parse_macro_input!(input as Item) {
|
||||
let options = parse_macro_input!(args as PyModuleOptions);
|
||||
|
||||
let mut ast = parse_macro_input!(input as Item);
|
||||
let expanded = match &mut ast {
|
||||
Item::Mod(module) => {
|
||||
let is_submodule = match parse_macro_input!(args as Option<syn::Ident>) {
|
||||
Some(i) if i == "submodule" => true,
|
||||
Some(_) => {
|
||||
return syn::Error::new(
|
||||
Span::call_site(),
|
||||
"#[pymodule] only accepts submodule as an argument",
|
||||
)
|
||||
.into_compile_error()
|
||||
.into();
|
||||
}
|
||||
None => false,
|
||||
};
|
||||
pymodule_module_impl(module, is_submodule)
|
||||
}
|
||||
Item::Fn(function) => {
|
||||
parse_macro_input!(args as Nothing);
|
||||
pymodule_function_impl(function)
|
||||
match pymodule_module_impl(module, options) {
|
||||
// #[pymodule] on a module will rebuild the original ast, so we don't emit it here
|
||||
Ok(expanded) => return expanded.into(),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
Item::Fn(function) => pymodule_function_impl(function, options),
|
||||
unsupported => Err(syn::Error::new_spanned(
|
||||
unsupported,
|
||||
"#[pymodule] only supports modules and functions.",
|
||||
)),
|
||||
}
|
||||
.unwrap_or_compile_error()
|
||||
.unwrap_or_compile_error();
|
||||
|
||||
quote!(
|
||||
#ast
|
||||
#expanded
|
||||
)
|
||||
.into()
|
||||
}
|
||||
|
||||
|
@ -99,17 +99,17 @@ pub fn pyclass(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||
/// multiple `#[pymethods]` blocks for a single `#[pyclass]`.
|
||||
/// This will add a transitive dependency on the [`inventory`][3] crate.
|
||||
///
|
||||
/// [1]: https://pyo3.rs/latest/class.html#instance-methods
|
||||
/// [2]: https://pyo3.rs/latest/features.html#multiple-pymethods
|
||||
#[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#instance-methods")]
|
||||
#[doc = concat!("[2]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/features.html#multiple-pymethods")]
|
||||
/// [3]: https://docs.rs/inventory/
|
||||
/// [4]: https://pyo3.rs/latest/class.html#constructor
|
||||
/// [5]: https://pyo3.rs/latest/class.html#object-properties-using-getter-and-setter
|
||||
/// [6]: https://pyo3.rs/latest/class.html#static-methods
|
||||
/// [7]: https://pyo3.rs/latest/class.html#class-methods
|
||||
/// [8]: https://pyo3.rs/latest/class.html#callable-objects
|
||||
/// [9]: https://pyo3.rs/latest/class.html#class-attributes
|
||||
/// [10]: https://pyo3.rs/latest/class.html#method-arguments
|
||||
/// [11]: https://pyo3.rs/latest/class.html#object-properties-using-pyo3get-set
|
||||
#[doc = concat!("[4]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#constructor")]
|
||||
#[doc = concat!("[5]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#object-properties-using-getter-and-setter")]
|
||||
#[doc = concat!("[6]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#static-methods")]
|
||||
#[doc = concat!("[7]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#class-methods")]
|
||||
#[doc = concat!("[8]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#callable-objects")]
|
||||
#[doc = concat!("[9]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#class-attributes")]
|
||||
#[doc = concat!("[10]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#method-arguments")]
|
||||
#[doc = concat!("[11]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#object-properties-using-pyo3get-set")]
|
||||
#[proc_macro_attribute]
|
||||
pub fn pymethods(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let methods_type = if cfg!(feature = "multiple-pymethods") {
|
||||
|
@ -138,7 +138,7 @@ pub fn pymethods(attr: TokenStream, input: TokenStream) -> TokenStream {
|
|||
/// `#[pyfunction]` implementation generates a hidden module with the same name containing
|
||||
/// metadata about the function, which is used by `wrap_pyfunction!`).
|
||||
///
|
||||
/// [1]: https://pyo3.rs/latest/function.html
|
||||
#[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/function.html")]
|
||||
#[proc_macro_attribute]
|
||||
pub fn pyfunction(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let mut ast = parse_macro_input!(input as syn::ItemFn);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
[tool.towncrier]
|
||||
filename = "CHANGELOG.md"
|
||||
version = "0.22.1"
|
||||
version = "0.23.0-dev"
|
||||
start_string = "<!-- towncrier release notes start -->\n"
|
||||
template = ".towncrier.template.md"
|
||||
title_format = "## [{version}] - {project_date}"
|
||||
|
|
|
@ -8,10 +8,7 @@ use crate::types::PyTuple;
|
|||
use crate::{ffi, Borrowed, Bound, Py, PyAny, PyClass, PyObject, PyRef, PyRefMut, Python};
|
||||
#[cfg(feature = "gil-refs")]
|
||||
use {
|
||||
crate::{
|
||||
err::{self, PyDowncastError},
|
||||
gil, PyNativeType,
|
||||
},
|
||||
crate::{err, gil, PyNativeType},
|
||||
std::ptr::NonNull,
|
||||
};
|
||||
|
||||
|
@ -395,121 +392,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Trait implemented by Python object types that allow a checked downcast.
|
||||
/// If `T` implements `PyTryFrom`, we can convert `&PyAny` to `&T`.
|
||||
///
|
||||
/// This trait is similar to `std::convert::TryFrom`
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[deprecated(since = "0.21.0")]
|
||||
pub trait PyTryFrom<'v>: Sized + PyNativeType {
|
||||
/// Cast from a concrete Python object type to PyObject.
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `value.downcast::<T>()` instead of `T::try_from(value)`"
|
||||
)]
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>;
|
||||
|
||||
/// Cast from a concrete Python object type to PyObject. With exact type check.
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `value.downcast_exact::<T>()` instead of `T::try_from_exact(value)`"
|
||||
)]
|
||||
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>>;
|
||||
|
||||
/// Cast a PyAny to a specific type of PyObject. The caller must
|
||||
/// have already verified the reference is for this type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Callers must ensure that the type is valid or risk type confusion.
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `value.downcast_unchecked::<T>()` instead of `T::try_from_unchecked(value)`"
|
||||
)]
|
||||
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self;
|
||||
}
|
||||
|
||||
/// Trait implemented by Python object types that allow a checked downcast.
|
||||
/// This trait is similar to `std::convert::TryInto`
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[deprecated(since = "0.21.0")]
|
||||
pub trait PyTryInto<T>: Sized {
|
||||
/// Cast from PyObject to a concrete Python object type.
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `value.downcast()` instead of `value.try_into()`"
|
||||
)]
|
||||
fn try_into(&self) -> Result<&T, PyDowncastError<'_>>;
|
||||
|
||||
/// Cast from PyObject to a concrete Python object type. With exact type check.
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `value.downcast()` instead of `value.try_into_exact()`"
|
||||
)]
|
||||
fn try_into_exact(&self) -> Result<&T, PyDowncastError<'_>>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
mod implementations {
|
||||
use super::*;
|
||||
use crate::type_object::PyTypeInfo;
|
||||
|
||||
// TryFrom implies TryInto
|
||||
impl<U> PyTryInto<U> for PyAny
|
||||
where
|
||||
U: for<'v> PyTryFrom<'v>,
|
||||
{
|
||||
fn try_into(&self) -> Result<&U, PyDowncastError<'_>> {
|
||||
<U as PyTryFrom<'_>>::try_from(self)
|
||||
}
|
||||
fn try_into_exact(&self) -> Result<&U, PyDowncastError<'_>> {
|
||||
U::try_from_exact(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'v, T> PyTryFrom<'v> for T
|
||||
where
|
||||
T: PyTypeInfo<AsRefTarget = Self> + PyNativeType,
|
||||
{
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
|
||||
value.into().downcast()
|
||||
}
|
||||
|
||||
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
|
||||
value.into().downcast_exact()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
|
||||
value.into().downcast_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'v, T> PyTryFrom<'v> for crate::PyCell<T>
|
||||
where
|
||||
T: 'v + PyClass,
|
||||
{
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
|
||||
value.into().downcast()
|
||||
}
|
||||
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
|
||||
let value = value.into();
|
||||
unsafe {
|
||||
if T::is_exact_type_of(value) {
|
||||
Ok(Self::try_from_unchecked(value))
|
||||
} else {
|
||||
Err(PyDowncastError::new(value, T::NAME))
|
||||
}
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
|
||||
value.into().downcast_unchecked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts `()` to an empty Python tuple.
|
||||
impl IntoPy<Py<PyTuple>> for () {
|
||||
fn into_py(self, py: Python<'_>) -> Py<PyTuple> {
|
||||
|
@ -665,51 +547,3 @@ where
|
|||
/// })
|
||||
/// ```
|
||||
mod test_no_clone {}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
mod deprecated {
|
||||
use super::super::PyTryFrom;
|
||||
use crate::types::{IntoPyDict, PyAny, PyDict, PyList};
|
||||
use crate::{Python, ToPyObject};
|
||||
|
||||
#[test]
|
||||
fn test_try_from() {
|
||||
Python::with_gil(|py| {
|
||||
let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py);
|
||||
let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref();
|
||||
|
||||
assert!(<PyList as PyTryFrom<'_>>::try_from(list).is_ok());
|
||||
assert!(<PyDict as PyTryFrom<'_>>::try_from(dict).is_ok());
|
||||
|
||||
assert!(<PyAny as PyTryFrom<'_>>::try_from(list).is_ok());
|
||||
assert!(<PyAny as PyTryFrom<'_>>::try_from(dict).is_ok());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_from_exact() {
|
||||
Python::with_gil(|py| {
|
||||
let list: &PyAny = vec![3, 6, 5, 4, 7].to_object(py).into_ref(py);
|
||||
let dict: &PyAny = vec![("reverse", true)].into_py_dict(py).as_ref();
|
||||
|
||||
assert!(PyList::try_from_exact(list).is_ok());
|
||||
assert!(PyDict::try_from_exact(dict).is_ok());
|
||||
|
||||
assert!(PyAny::try_from_exact(list).is_err());
|
||||
assert!(PyAny::try_from_exact(dict).is_err());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_try_from_unchecked() {
|
||||
Python::with_gil(|py| {
|
||||
let list = PyList::new(py, [1, 2, 3]);
|
||||
let val = unsafe { <PyList as PyTryFrom>::try_from_unchecked(list.as_ref()) };
|
||||
assert!(list.is(val));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#[cfg(feature = "experimental-async")]
|
||||
pub mod coroutine;
|
||||
pub mod deprecations;
|
||||
pub mod exceptions;
|
||||
pub mod extract_argument;
|
||||
pub mod freelist;
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
//! Symbols used to denote deprecated usages of PyO3's proc macros.
|
||||
|
||||
use crate::{PyResult, Python};
|
||||
|
||||
#[deprecated(since = "0.20.0", note = "use `#[new]` instead of `#[__new__]`")]
|
||||
pub const PYMETHODS_NEW_DEPRECATED_FORM: () = ();
|
||||
|
||||
pub fn inspect_type<T>(t: T, _: &GilRefs<T>) -> T {
|
||||
t
|
||||
}
|
||||
|
||||
pub fn inspect_fn<A, T>(f: fn(A) -> PyResult<T>, _: &GilRefs<A>) -> fn(A) -> PyResult<T> {
|
||||
f
|
||||
}
|
||||
|
||||
pub struct GilRefs<T>(OptionGilRefs<T>);
|
||||
pub struct OptionGilRefs<T>(NotAGilRef<T>);
|
||||
pub struct NotAGilRef<T>(std::marker::PhantomData<T>);
|
||||
|
||||
pub trait IsGilRef {}
|
||||
|
||||
#[cfg(feature = "gil-refs")]
|
||||
impl<T: crate::PyNativeType> IsGilRef for &'_ T {}
|
||||
|
||||
impl<T> GilRefs<T> {
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new() -> Self {
|
||||
GilRefs(OptionGilRefs(NotAGilRef(std::marker::PhantomData)))
|
||||
}
|
||||
}
|
||||
|
||||
impl GilRefs<Python<'_>> {
|
||||
#[deprecated(since = "0.21.0", note = "use `wrap_pyfunction_bound!` instead")]
|
||||
pub fn is_python(&self) {}
|
||||
}
|
||||
|
||||
impl<T: IsGilRef> GilRefs<T> {
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `&Bound<'_, T>` instead for this function argument"
|
||||
)]
|
||||
pub fn function_arg(&self) {}
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor"
|
||||
)]
|
||||
pub fn from_py_with_arg(&self) {}
|
||||
}
|
||||
|
||||
impl<T: IsGilRef> OptionGilRefs<Option<T>> {
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `Option<&Bound<'_, T>>` instead for this function argument"
|
||||
)]
|
||||
pub fn function_arg(&self) {}
|
||||
}
|
||||
|
||||
impl<T> NotAGilRef<T> {
|
||||
pub fn function_arg(&self) {}
|
||||
pub fn from_py_with_arg(&self) {}
|
||||
pub fn is_python(&self) {}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for GilRefs<T> {
|
||||
type Target = OptionGilRefs<T>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for OptionGilRefs<T> {
|
||||
type Target = NotAGilRef<T>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
|
@ -65,7 +65,19 @@ pub unsafe trait PyNativeType: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
/// A GIL-attached equivalent to `Py`.
|
||||
/// A GIL-attached equivalent to [`Py<T>`].
|
||||
///
|
||||
/// This type can be thought of as equivalent to the tuple `(Py<T>, Python<'py>)`. By having the `'py`
|
||||
/// lifetime of the [`Python<'py>`] token, this ties the lifetime of the [`Bound<'py, T>`] smart pointer
|
||||
/// to the lifetime of the GIL and allows PyO3 to call Python APIs at maximum efficiency.
|
||||
///
|
||||
/// To access the object in situations where the GIL is not held, convert it to [`Py<T>`]
|
||||
/// using [`.unbind()`][Bound::unbind]. This includes situations where the GIL is temporarily
|
||||
/// released, such as [`Python::allow_threads`](crate::Python::allow_threads)'s closure.
|
||||
///
|
||||
/// See
|
||||
#[doc = concat!("[the guide](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/types.html#boundpy-t)")]
|
||||
/// for more detail.
|
||||
#[repr(transparent)]
|
||||
pub struct Bound<'py, T>(Python<'py>, ManuallyDrop<Py<T>>);
|
||||
|
||||
|
@ -732,7 +744,8 @@ impl<T> IntoPy<PyObject> for Borrowed<'_, '_, T> {
|
|||
/// - [`Py::borrow`], [`Py::try_borrow`], [`Py::borrow_mut`], or [`Py::try_borrow_mut`],
|
||||
///
|
||||
/// to get a (mutable) reference to a contained pyclass, using a scheme similar to std's [`RefCell`].
|
||||
/// See the [guide entry](https://pyo3.rs/latest/class.html#bound-and-interior-mutability)
|
||||
/// See the
|
||||
#[doc = concat!("[guide entry](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#bound-and-interior-mutability)")]
|
||||
/// for more information.
|
||||
/// - You can call methods directly on `Py` with [`Py::call_bound`], [`Py::call_method_bound`] and friends.
|
||||
///
|
||||
|
@ -1329,8 +1342,11 @@ impl<T> Py<T> {
|
|||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn clone_ref(&self, py: Python<'_>) -> Py<T> {
|
||||
unsafe { Py::from_borrowed_ptr(py, self.0.as_ptr()) }
|
||||
pub fn clone_ref(&self, _py: Python<'_>) -> Py<T> {
|
||||
unsafe {
|
||||
ffi::Py_INCREF(self.as_ptr());
|
||||
Self::from_non_null(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Drops `self` and immediately decreases its reference count.
|
||||
|
@ -1369,22 +1385,6 @@ impl<T> Py<T> {
|
|||
unsafe { ffi::Py_None() == self.as_ptr() }
|
||||
}
|
||||
|
||||
/// Returns whether the object is Ellipsis, e.g. `...`.
|
||||
///
|
||||
/// This is equivalent to the Python expression `self is ...`.
|
||||
#[deprecated(since = "0.20.0", note = "use `.is(py.Ellipsis())` instead")]
|
||||
pub fn is_ellipsis(&self) -> bool {
|
||||
unsafe { ffi::Py_Ellipsis() == self.as_ptr() }
|
||||
}
|
||||
|
||||
/// Returns whether the object is considered to be true.
|
||||
///
|
||||
/// This is equivalent to the Python expression `bool(self)`.
|
||||
#[deprecated(since = "0.21.0", note = "use `.is_truthy()` instead")]
|
||||
pub fn is_true(&self, py: Python<'_>) -> PyResult<bool> {
|
||||
self.is_truthy(py)
|
||||
}
|
||||
|
||||
/// Returns whether the object is considered to be true.
|
||||
///
|
||||
/// This applies truth value testing equivalent to the Python expression `bool(self)`.
|
||||
|
@ -2158,23 +2158,6 @@ a = A()
|
|||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_is_ellipsis() {
|
||||
Python::with_gil(|py| {
|
||||
let v = py
|
||||
.eval_bound("...", None, None)
|
||||
.map_err(|e| e.display(py))
|
||||
.unwrap()
|
||||
.to_object(py);
|
||||
|
||||
assert!(v.is_ellipsis());
|
||||
|
||||
let not_ellipsis = 5.to_object(py);
|
||||
assert!(!not_ellipsis.is_ellipsis());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_debug_fmt() {
|
||||
Python::with_gil(|py| {
|
||||
|
@ -2374,18 +2357,5 @@ a = A()
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
fn cell_tryfrom() {
|
||||
use crate::{PyCell, PyTryInto};
|
||||
// More detailed tests of the underlying semantics in pycell.rs
|
||||
Python::with_gil(|py| {
|
||||
let instance: &PyAny = Py::new(py, SomeClass(0)).unwrap().into_ref(py);
|
||||
let _: &PyCell<SomeClass> = PyTryInto::try_into(instance).unwrap();
|
||||
let _: &PyCell<SomeClass> = PyTryInto::try_into_exact(instance).unwrap();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
50
src/lib.rs
50
src/lib.rs
|
@ -295,32 +295,29 @@
|
|||
//! [`rust_decimal`]: ./rust_decimal/index.html "Documenation about the `rust_decimal` feature."
|
||||
//! [`Decimal`]: https://docs.rs/rust_decimal/latest/rust_decimal/struct.Decimal.html
|
||||
//! [`serde`]: <./serde/index.html> "Documentation about the `serde` feature."
|
||||
//! [calling_rust]: https://pyo3.rs/latest/python-from-rust.html "Calling Python from Rust - PyO3 user guide"
|
||||
#![doc = concat!("[calling_rust]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/python-from-rust.html \"Calling Python from Rust - PyO3 user guide\"")]
|
||||
//! [examples subdirectory]: https://github.com/PyO3/pyo3/tree/main/examples
|
||||
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/features.html "Features - The Cargo Book"
|
||||
//! [global interpreter lock]: https://docs.python.org/3/glossary.html#term-global-interpreter-lock
|
||||
//! [hashbrown]: https://docs.rs/hashbrown
|
||||
//! [smallvec]: https://docs.rs/smallvec
|
||||
//! [indexmap]: https://docs.rs/indexmap
|
||||
//! [manual_builds]: https://pyo3.rs/latest/building-and-distribution.html#manual-builds "Manual builds - Building and Distribution - PyO3 user guide"
|
||||
#![doc = concat!("[manual_builds]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/building-and-distribution.html#manual-builds \"Manual builds - Building and Distribution - PyO3 user guide\"")]
|
||||
//! [num-bigint]: https://docs.rs/num-bigint
|
||||
//! [num-complex]: https://docs.rs/num-complex
|
||||
//! [num-rational]: https://docs.rs/num-rational
|
||||
//! [serde]: https://docs.rs/serde
|
||||
//! [setuptools-rust]: https://github.com/PyO3/setuptools-rust "Setuptools plugin for Rust extensions"
|
||||
//! [the guide]: https://pyo3.rs "PyO3 user guide"
|
||||
//! [types]: https://pyo3.rs/latest/types.html "GIL lifetimes, mutability and Python object types"
|
||||
#![doc = concat!("[types]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/types.html \"GIL lifetimes, mutability and Python object types\"")]
|
||||
//! [PEP 384]: https://www.python.org/dev/peps/pep-0384 "PEP 384 -- Defining a Stable ABI"
|
||||
//! [Python from Rust]: https://github.com/PyO3/pyo3#using-python-from-rust
|
||||
//! [Rust from Python]: https://github.com/PyO3/pyo3#using-rust-from-python
|
||||
//! [Features chapter of the guide]: https://pyo3.rs/latest/features.html#features-reference "Features Reference - PyO3 user guide"
|
||||
#![doc = concat!("[Features chapter of the guide]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/features.html#features-reference \"Features Reference - PyO3 user guide\"")]
|
||||
//! [`Ungil`]: crate::marker::Ungil
|
||||
pub use crate::class::*;
|
||||
pub use crate::conversion::{AsPyPointer, FromPyObject, IntoPy, ToPyObject};
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
pub use crate::conversion::{FromPyPointer, PyTryFrom, PyTryInto};
|
||||
#[cfg(feature = "gil-refs")]
|
||||
pub use crate::err::PyDowncastError;
|
||||
pub use crate::err::{DowncastError, DowncastIntoError, PyErr, PyErrArguments, PyResult, ToPyErr};
|
||||
#[cfg(feature = "gil-refs")]
|
||||
|
@ -382,30 +379,6 @@ pub mod class {
|
|||
pub use crate::pyclass::CompareOp;
|
||||
}
|
||||
|
||||
/// Old module which contained some implementation details of the `#[pyproto]` module.
|
||||
///
|
||||
/// Prefer using the same content from `pyo3::pyclass`, e.g. `use pyo3::pyclass::IterANextOutput` instead
|
||||
/// of `use pyo3::class::pyasync::IterANextOutput`.
|
||||
///
|
||||
/// For compatibility reasons this has not yet been removed, however will be done so
|
||||
/// once <https://github.com/rust-lang/rust/issues/30827> is resolved.
|
||||
pub mod pyasync {
|
||||
#[allow(deprecated)]
|
||||
pub use crate::pyclass::{IterANextOutput, PyIterANextOutput};
|
||||
}
|
||||
|
||||
/// Old module which contained some implementation details of the `#[pyproto]` module.
|
||||
///
|
||||
/// Prefer using the same content from `pyo3::pyclass`, e.g. `use pyo3::pyclass::IterNextOutput` instead
|
||||
/// of `use pyo3::class::pyasync::IterNextOutput`.
|
||||
///
|
||||
/// For compatibility reasons this has not yet been removed, however will be done so
|
||||
/// once <https://github.com/rust-lang/rust/issues/30827> is resolved.
|
||||
pub mod iter {
|
||||
#[allow(deprecated)]
|
||||
pub use crate::pyclass::{IterNextOutput, PyIterNextOutput};
|
||||
}
|
||||
|
||||
/// Old module which contained some implementation details of the `#[pyproto]` module.
|
||||
///
|
||||
/// Prefer using the same content from `pyo3::pyclass`, e.g. `use pyo3::pyclass::PyTraverseError` instead
|
||||
|
@ -461,7 +434,6 @@ pub mod marshal;
|
|||
#[macro_use]
|
||||
pub mod sync;
|
||||
pub mod panic;
|
||||
pub mod prelude;
|
||||
pub mod pybacked;
|
||||
pub mod pycell;
|
||||
pub mod pyclass;
|
||||
|
@ -484,7 +456,7 @@ pub use pyo3_macros::{pyfunction, pymethods, pymodule, FromPyObject};
|
|||
/// For more on creating Python classes,
|
||||
/// see the [class section of the guide][1].
|
||||
///
|
||||
/// [1]: https://pyo3.rs/latest/class.html
|
||||
#[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html")]
|
||||
#[cfg(feature = "macros")]
|
||||
pub use pyo3_macros::pyclass;
|
||||
|
||||
|
@ -495,15 +467,9 @@ mod macros;
|
|||
#[cfg(feature = "experimental-inspect")]
|
||||
pub mod inspect;
|
||||
|
||||
/// Ths module only contains re-exports of pyo3 deprecation warnings and exists
|
||||
/// purely to make compiler error messages nicer.
|
||||
///
|
||||
/// (The compiler uses this module in error messages, probably because it's a public
|
||||
/// re-export at a shorter path than `pyo3::impl_::deprecations`.)
|
||||
#[doc(hidden)]
|
||||
pub mod deprecations {
|
||||
pub use crate::impl_::deprecations::*;
|
||||
}
|
||||
// Putting the declaration of prelude at the end seems to help encourage rustc and rustdoc to prefer using
|
||||
// other paths to the same items. (e.g. `pyo3::types::PyAnyMethods` instead of `pyo3::prelude::PyAnyMethods`).
|
||||
pub mod prelude;
|
||||
|
||||
/// Test readme and user guide
|
||||
#[cfg(doctest)]
|
||||
|
|
|
@ -145,12 +145,8 @@ macro_rules! wrap_pyfunction {
|
|||
};
|
||||
($function:path, $py_or_module:expr) => {{
|
||||
use $function as wrapped_pyfunction;
|
||||
let check_gil_refs = $crate::impl_::deprecations::GilRefs::new();
|
||||
let py_or_module =
|
||||
$crate::impl_::deprecations::inspect_type($py_or_module, &check_gil_refs);
|
||||
check_gil_refs.is_python();
|
||||
$crate::impl_::pyfunction::WrapPyFunctionArg::wrap_pyfunction(
|
||||
py_or_module,
|
||||
$py_or_module,
|
||||
&wrapped_pyfunction::_PYO3_DEF,
|
||||
)
|
||||
}};
|
||||
|
|
|
@ -126,10 +126,10 @@ use crate::types::{
|
|||
PyAny, PyDict, PyEllipsis, PyModule, PyNone, PyNotImplemented, PyString, PyType,
|
||||
};
|
||||
use crate::version::PythonVersionInfo;
|
||||
use crate::{ffi, Bound, IntoPy, Py, PyObject, PyTypeInfo};
|
||||
#[allow(deprecated)]
|
||||
#[cfg(feature = "gil-refs")]
|
||||
use crate::{gil::GILPool, FromPyPointer, PyNativeType};
|
||||
use crate::{conversion::FromPyPointer, gil::GILPool, PyNativeType};
|
||||
use crate::{ffi, Bound, IntoPy, Py, PyObject, PyTypeInfo};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_int;
|
||||
|
@ -801,42 +801,6 @@ impl<'py> Python<'py> {
|
|||
PythonVersionInfo::from_str(version_number_str).unwrap()
|
||||
}
|
||||
|
||||
/// Registers the object in the release pool, and tries to downcast to specific type.
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `obj.downcast_bound::<T>(py)` instead of `py.checked_cast_as::<T>(obj)`"
|
||||
)]
|
||||
pub fn checked_cast_as<T>(
|
||||
self,
|
||||
obj: PyObject,
|
||||
) -> Result<&'py T, crate::err::PyDowncastError<'py>>
|
||||
where
|
||||
T: crate::PyTypeCheck<AsRefTarget = T>,
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
obj.into_ref(self).downcast()
|
||||
}
|
||||
|
||||
/// Registers the object in the release pool, and does an unchecked downcast
|
||||
/// to the specific type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Callers must ensure that ensure that the cast is valid.
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "use `obj.downcast_bound_unchecked::<T>(py)` instead of `py.cast_as::<T>(obj)`"
|
||||
)]
|
||||
pub unsafe fn cast_as<T>(self, obj: PyObject) -> &'py T
|
||||
where
|
||||
T: crate::type_object::HasPyGilRef<AsRefTarget = T>,
|
||||
{
|
||||
#[allow(deprecated)]
|
||||
obj.into_ref(self).downcast_unchecked()
|
||||
}
|
||||
|
||||
/// Registers the object pointer in the release pool,
|
||||
/// and does an unchecked downcast to the specific type.
|
||||
///
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
//! ```
|
||||
|
||||
pub use crate::conversion::{FromPyObject, IntoPy, ToPyObject};
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
pub use crate::conversion::{PyTryFrom, PyTryInto};
|
||||
pub use crate::err::{PyErr, PyResult};
|
||||
pub use crate::instance::{Borrowed, Bound, Py, PyObject};
|
||||
pub use crate::marker::Python;
|
||||
|
|
110
src/pyclass.rs
110
src/pyclass.rs
|
@ -1,8 +1,5 @@
|
|||
//! `PyClass` and related traits.
|
||||
use crate::{
|
||||
callback::IntoPyCallbackOutput, ffi, impl_::pyclass::PyClassImpl, IntoPy, PyObject, PyResult,
|
||||
PyTypeInfo, Python,
|
||||
};
|
||||
use crate::{ffi, impl_::pyclass::PyClassImpl, PyTypeInfo};
|
||||
use std::{cmp::Ordering, os::raw::c_int};
|
||||
|
||||
mod create_type_object;
|
||||
|
@ -99,111 +96,6 @@ impl CompareOp {
|
|||
}
|
||||
}
|
||||
|
||||
/// Output of `__next__` which can either `yield` the next value in the iteration, or
|
||||
/// `return` a value to raise `StopIteration` in Python.
|
||||
///
|
||||
/// Usage example:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #![allow(deprecated)]
|
||||
/// use pyo3::prelude::*;
|
||||
/// use pyo3::iter::IterNextOutput;
|
||||
///
|
||||
/// #[pyclass]
|
||||
/// struct PyClassIter {
|
||||
/// count: usize,
|
||||
/// }
|
||||
///
|
||||
/// #[pymethods]
|
||||
/// impl PyClassIter {
|
||||
/// #[new]
|
||||
/// pub fn new() -> Self {
|
||||
/// PyClassIter { count: 0 }
|
||||
/// }
|
||||
///
|
||||
/// fn __next__(&mut self) -> IterNextOutput<usize, &'static str> {
|
||||
/// if self.count < 5 {
|
||||
/// self.count += 1;
|
||||
/// // Given an instance `counter`, First five `next(counter)` calls yield 1, 2, 3, 4, 5.
|
||||
/// IterNextOutput::Yield(self.count)
|
||||
/// } else {
|
||||
/// // At the sixth time, we get a `StopIteration` with `'Ended'`.
|
||||
/// // try:
|
||||
/// // next(counter)
|
||||
/// // except StopIteration as e:
|
||||
/// // assert e.value == 'Ended'
|
||||
/// IterNextOutput::Return("Ended")
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[deprecated(since = "0.21.0", note = "Use `Option` or `PyStopIteration` instead.")]
|
||||
pub enum IterNextOutput<T, U> {
|
||||
/// The value yielded by the iterator.
|
||||
Yield(T),
|
||||
/// The `StopIteration` object.
|
||||
Return(U),
|
||||
}
|
||||
|
||||
/// Alias of `IterNextOutput` with `PyObject` yield & return values.
|
||||
#[deprecated(since = "0.21.0", note = "Use `Option` or `PyStopIteration` instead.")]
|
||||
#[allow(deprecated)]
|
||||
pub type PyIterNextOutput = IterNextOutput<PyObject, PyObject>;
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T, U> IntoPyCallbackOutput<*mut ffi::PyObject> for IterNextOutput<T, U>
|
||||
where
|
||||
T: IntoPy<PyObject>,
|
||||
U: IntoPy<PyObject>,
|
||||
{
|
||||
fn convert(self, py: Python<'_>) -> PyResult<*mut ffi::PyObject> {
|
||||
match self {
|
||||
IterNextOutput::Yield(o) => Ok(o.into_py(py).into_ptr()),
|
||||
IterNextOutput::Return(o) => {
|
||||
Err(crate::exceptions::PyStopIteration::new_err(o.into_py(py)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Output of `__anext__`.
|
||||
///
|
||||
/// <https://docs.python.org/3/reference/expressions.html#agen.__anext__>
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "Use `Option` or `PyStopAsyncIteration` instead."
|
||||
)]
|
||||
pub enum IterANextOutput<T, U> {
|
||||
/// An expression which the generator yielded.
|
||||
Yield(T),
|
||||
/// A `StopAsyncIteration` object.
|
||||
Return(U),
|
||||
}
|
||||
|
||||
/// An [IterANextOutput] of Python objects.
|
||||
#[deprecated(
|
||||
since = "0.21.0",
|
||||
note = "Use `Option` or `PyStopAsyncIteration` instead."
|
||||
)]
|
||||
#[allow(deprecated)]
|
||||
pub type PyIterANextOutput = IterANextOutput<PyObject, PyObject>;
|
||||
|
||||
#[allow(deprecated)]
|
||||
impl<T, U> IntoPyCallbackOutput<*mut ffi::PyObject> for IterANextOutput<T, U>
|
||||
where
|
||||
T: IntoPy<PyObject>,
|
||||
U: IntoPy<PyObject>,
|
||||
{
|
||||
fn convert(self, py: Python<'_>) -> PyResult<*mut ffi::PyObject> {
|
||||
match self {
|
||||
IterANextOutput::Yield(o) => Ok(o.into_py(py).into_ptr()),
|
||||
IterANextOutput::Return(o) => Err(crate::exceptions::PyStopAsyncIteration::new_err(
|
||||
o.into_py(py),
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A workaround for [associated const equality](https://github.com/rust-lang/rust/issues/92827).
|
||||
///
|
||||
/// This serves to have True / False values in the [`PyClass`] trait's `Frozen` type.
|
||||
|
|
|
@ -59,7 +59,9 @@ unsafe impl<T> Sync for GILProtected<T> where T: Send {}
|
|||
/// Unlike `once_cell::sync` which blocks threads to achieve thread safety, this implementation
|
||||
/// uses the Python GIL to mediate concurrent access. This helps in cases where `once_cell` or
|
||||
/// `lazy_static`'s synchronization strategy can lead to deadlocks when interacting with the Python
|
||||
/// GIL. For an example, see [the FAQ section](https://pyo3.rs/latest/faq.html) of the guide.
|
||||
/// GIL. For an example, see
|
||||
#[doc = concat!("[the FAQ section](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/faq.html)")]
|
||||
/// of the guide.
|
||||
///
|
||||
/// Note that:
|
||||
/// 1) `get_or_init` and `get_or_try_init` do not protect against infinite recursion
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
#![no_implicit_prelude]
|
||||
#[derive(crate::FromPyObject)]
|
||||
#[pyo3(crate = "crate")]
|
||||
struct Derive1(i32); // newtype case
|
||||
|
||||
#[derive(crate::FromPyObject)]
|
||||
#[pyo3(crate = "crate")]
|
||||
struct Derive1(#[allow(dead_code)] i32); // newtype case
|
||||
|
||||
#[derive(crate::FromPyObject)]
|
||||
#[pyo3(crate = "crate")]
|
||||
#[allow(dead_code)]
|
||||
struct Derive2(i32, i32); // tuple case
|
||||
|
||||
#[derive(crate::FromPyObject)]
|
||||
#[pyo3(crate = "crate")]
|
||||
#[allow(dead_code)]
|
||||
struct Derive3 {
|
||||
f: i32,
|
||||
#[pyo3(item(42))]
|
||||
|
@ -20,7 +16,6 @@ struct Derive3 {
|
|||
|
||||
#[derive(crate::FromPyObject)]
|
||||
#[pyo3(crate = "crate")]
|
||||
#[allow(dead_code)]
|
||||
enum Derive4 {
|
||||
A(i32),
|
||||
B { f: i32 },
|
||||
|
@ -29,23 +24,16 @@ enum Derive4 {
|
|||
crate::create_exception!(mymodule, CustomError, crate::exceptions::PyException);
|
||||
crate::import_exception!(socket, gaierror);
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn intern(py: crate::Python<'_>) {
|
||||
let _foo = crate::intern!(py, "foo");
|
||||
let _bar = crate::intern!(py, stringify!(bar));
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(not(PyPy))]
|
||||
fn append_to_inittab() {
|
||||
#[crate::pymodule]
|
||||
#[pyo3(crate = "crate")]
|
||||
#[allow(clippy::unnecessary_wraps)]
|
||||
fn module_for_inittab(
|
||||
_: crate::Python<'_>,
|
||||
_: &crate::Bound<'_, crate::types::PyModule>,
|
||||
) -> crate::PyResult<()> {
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
mod module_for_inittab {}
|
||||
|
||||
crate::append_to_inittab!(module_for_inittab);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
#![no_implicit_prelude]
|
||||
#![allow(dead_code, unused_variables, clippy::unnecessary_wraps)]
|
||||
|
||||
// The modules in this test are used to check PyO3 macro expansion is hygienic. By locating the test
|
||||
// inside the crate the global `::pyo3` namespace is not available, so in combination with
|
||||
// #[pyo3(crate = "crate")] this validates that all macro expansion respects the setting.
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
#![no_implicit_prelude]
|
||||
#![allow(unused_variables)]
|
||||
|
||||
#[crate::pyclass]
|
||||
#[pyo3(crate = "crate")]
|
||||
#[derive(::std::clone::Clone)]
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
#![no_implicit_prelude]
|
||||
#![allow(unused_variables, clippy::unnecessary_wraps)]
|
||||
|
||||
#[crate::pyfunction]
|
||||
#[pyo3(crate = "crate")]
|
||||
fn do_something(x: i32) -> crate::PyResult<i32> {
|
||||
|
@ -8,19 +5,9 @@ fn do_something(x: i32) -> crate::PyResult<i32> {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "gil-refs")]
|
||||
fn invoke_wrap_pyfunction() {
|
||||
crate::Python::with_gil(|py| {
|
||||
#[allow(deprecated)]
|
||||
let func = crate::wrap_pyfunction!(do_something)(py).unwrap();
|
||||
crate::py_run!(py, func, r#"func(5)"#);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invoke_wrap_pyfunction_bound() {
|
||||
crate::Python::with_gil(|py| {
|
||||
let func = crate::wrap_pyfunction_bound!(do_something, py).unwrap();
|
||||
let func = crate::wrap_pyfunction!(do_something, py).unwrap();
|
||||
crate::py_run!(py, func, r#"func(5)"#);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
#![no_implicit_prelude]
|
||||
#![allow(unused_variables, clippy::unnecessary_wraps)]
|
||||
|
||||
#[crate::pyclass]
|
||||
#[pyo3(crate = "crate")]
|
||||
pub struct Dummy;
|
||||
|
|
|
@ -1,51 +1,36 @@
|
|||
#![no_implicit_prelude]
|
||||
#![allow(unused_variables, clippy::unnecessary_wraps)]
|
||||
|
||||
#[crate::pyfunction]
|
||||
#[pyo3(crate = "crate")]
|
||||
fn do_something(x: i32) -> crate::PyResult<i32> {
|
||||
::std::result::Result::Ok(x)
|
||||
}
|
||||
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
#[crate::pymodule]
|
||||
#[pyo3(crate = "crate")]
|
||||
fn foo(_py: crate::Python<'_>, _m: &crate::types::PyModule) -> crate::PyResult<()> {
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
#[crate::pymodule]
|
||||
#[pyo3(crate = "crate")]
|
||||
fn foo_bound(
|
||||
fn foo(
|
||||
_py: crate::Python<'_>,
|
||||
_m: &crate::Bound<'_, crate::types::PyModule>,
|
||||
) -> crate::PyResult<()> {
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
#[crate::pymodule]
|
||||
#[pyo3(crate = "crate")]
|
||||
fn my_module(_py: crate::Python<'_>, m: &crate::types::PyModule) -> crate::PyResult<()> {
|
||||
m.add_function(crate::wrap_pyfunction!(do_something, m)?)?;
|
||||
m.add_wrapped(crate::wrap_pymodule!(foo))?;
|
||||
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
#[crate::pymodule]
|
||||
#[pyo3(crate = "crate")]
|
||||
fn my_module_bound(m: &crate::Bound<'_, crate::types::PyModule>) -> crate::PyResult<()> {
|
||||
fn my_module(m: &crate::Bound<'_, crate::types::PyModule>) -> crate::PyResult<()> {
|
||||
<crate::Bound<'_, crate::types::PyModule> as crate::types::PyModuleMethods>::add_function(
|
||||
m,
|
||||
crate::wrap_pyfunction_bound!(do_something, m)?,
|
||||
)?;
|
||||
<crate::Bound<'_, crate::types::PyModule> as crate::types::PyModuleMethods>::add_wrapped(
|
||||
m,
|
||||
crate::wrap_pymodule!(foo_bound),
|
||||
crate::wrap_pymodule!(foo),
|
||||
)?;
|
||||
|
||||
::std::result::Result::Ok(())
|
||||
}
|
||||
|
||||
#[crate::pymodule(submodule)]
|
||||
#[pyo3(crate = "crate")]
|
||||
mod my_module_declarative {
|
||||
#[pymodule_export]
|
||||
use super::{do_something, foo};
|
||||
}
|
||||
|
|
|
@ -19,26 +19,15 @@ use std::os::raw::c_int;
|
|||
|
||||
/// Represents any Python object.
|
||||
///
|
||||
/// It currently only appears as a *reference*, `&PyAny`,
|
||||
/// with a lifetime that represents the scope during which the GIL is held.
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyAny>`][crate::Py] or [`Bound<'py, PyAny>`][Bound].
|
||||
///
|
||||
/// `PyAny` has some interesting properties, which it shares
|
||||
/// with the other [native Python types](crate::types):
|
||||
/// For APIs available on all Python objects, see the [`PyAnyMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyAny>`][Bound].
|
||||
///
|
||||
/// - It can only be obtained and used while the GIL is held,
|
||||
/// therefore its API does not require a [`Python<'py>`](crate::Python) token.
|
||||
/// - It can't be used in situations where the GIL is temporarily released,
|
||||
/// such as [`Python::allow_threads`](crate::Python::allow_threads)'s closure.
|
||||
/// - The underlying Python object, if mutable, can be mutated through any reference.
|
||||
/// - It can be converted to the GIL-independent [`Py`]`<`[`PyAny`]`>`,
|
||||
/// allowing it to outlive the GIL scope. However, using [`Py`]`<`[`PyAny`]`>`'s API
|
||||
/// *does* require a [`Python<'py>`](crate::Python) token.
|
||||
///
|
||||
/// It can be cast to a concrete type with PyAny::downcast (for native Python types only)
|
||||
/// and FromPyObject::extract. See their documentation for more information.
|
||||
///
|
||||
/// See [the guide](https://pyo3.rs/latest/types.html) for an explanation
|
||||
/// of the different Python object types.
|
||||
/// See
|
||||
#[doc = concat!("[the guide](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/types.html#concrete-python-types)")]
|
||||
/// for an explanation of the different Python object types.
|
||||
#[repr(transparent)]
|
||||
pub struct PyAny(UnsafeCell<ffi::PyObject>);
|
||||
|
||||
|
@ -592,14 +581,6 @@ impl PyAny {
|
|||
.map(Bound::into_gil_ref)
|
||||
}
|
||||
|
||||
/// Returns whether the object is considered to be true.
|
||||
///
|
||||
/// This is equivalent to the Python expression `bool(self)`.
|
||||
#[deprecated(since = "0.21.0", note = "use `.is_truthy()` instead")]
|
||||
pub fn is_true(&self) -> PyResult<bool> {
|
||||
self.is_truthy()
|
||||
}
|
||||
|
||||
/// Returns whether the object is considered to be true.
|
||||
///
|
||||
/// This applies truth value testing equivalent to the Python expression `bool(self)`.
|
||||
|
@ -615,14 +596,6 @@ impl PyAny {
|
|||
self.as_borrowed().is_none()
|
||||
}
|
||||
|
||||
/// Returns whether the object is Ellipsis, e.g. `...`.
|
||||
///
|
||||
/// This is equivalent to the Python expression `self is ...`.
|
||||
#[deprecated(since = "0.20.0", note = "use `.is(py.Ellipsis())` instead")]
|
||||
pub fn is_ellipsis(&self) -> bool {
|
||||
self.as_borrowed().is_ellipsis()
|
||||
}
|
||||
|
||||
/// Returns true if the sequence or mapping has a length of 0.
|
||||
///
|
||||
/// This is equivalent to the Python expression `len(self) == 0`.
|
||||
|
@ -1506,6 +1479,7 @@ pub trait PyAnyMethods<'py>: crate::sealed::Sealed {
|
|||
/// Returns whether the object is Ellipsis, e.g. `...`.
|
||||
///
|
||||
/// This is equivalent to the Python expression `self is ...`.
|
||||
#[deprecated(since = "0.23.0", note = "use `.is(py.Ellipsis())` instead")]
|
||||
fn is_ellipsis(&self) -> bool;
|
||||
|
||||
/// Returns true if the sequence or mapping has a length of 0.
|
||||
|
@ -2796,6 +2770,7 @@ class SimpleClass:
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
fn test_is_ellipsis() {
|
||||
Python::with_gil(|py| {
|
||||
let v = py
|
||||
|
|
|
@ -11,6 +11,12 @@ use crate::{
|
|||
use super::any::PyAnyMethods;
|
||||
|
||||
/// Represents a Python `bool`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyBool>`][crate::Py] or [`Bound<'py, PyBool>`][Bound].
|
||||
///
|
||||
/// For APIs available on `bool` objects, see the [`PyBoolMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyBool>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyBool(PyAny);
|
||||
|
||||
|
|
|
@ -9,6 +9,12 @@ use crate::{AsPyPointer, PyNativeType};
|
|||
use std::slice;
|
||||
|
||||
/// Represents a Python `bytearray`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyByteArray>`][crate::Py] or [`Bound<'py, PyByteArray>`][Bound].
|
||||
///
|
||||
/// For APIs available on `bytearray` objects, see the [`PyByteArrayMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyByteArray>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyByteArray(PyAny);
|
||||
|
||||
|
|
|
@ -12,10 +12,16 @@ use std::str;
|
|||
///
|
||||
/// This type is immutable.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyBytes>`][crate::Py] or [`Bound<'py, PyBytes>`][Bound].
|
||||
///
|
||||
/// For APIs available on `bytes` objects, see the [`PyBytesMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyBytes>`][Bound].
|
||||
///
|
||||
/// # Equality
|
||||
///
|
||||
/// For convenience, [`Bound<'py, PyBytes>`] implements [`PartialEq<[u8]>`] to allow comparing the
|
||||
/// data in the Python bytes to a Rust `[u8]`.
|
||||
/// For convenience, [`Bound<'py, PyBytes>`][Bound] implements [`PartialEq<[u8]>`][PartialEq] to allow comparing the
|
||||
/// data in the Python bytes to a Rust `[u8]` byte slice.
|
||||
///
|
||||
/// This is not always the most appropriate way to compare Python bytes, as Python bytes subclasses
|
||||
/// may have different equality semantics. In situations where subclasses overriding equality might be
|
||||
|
|
|
@ -15,6 +15,11 @@ use std::os::raw::{c_char, c_int, c_void};
|
|||
/// > in one module available to other modules, so the regular import mechanism can
|
||||
/// > be used to access C APIs defined in dynamically loaded modules.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyCapsule>`][crate::Py] or [`Bound<'py, PyCapsule>`][Bound].
|
||||
///
|
||||
/// For APIs available on capsule objects, see the [`PyCapsuleMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyCapsule>`][Bound].
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
|
|
|
@ -2,6 +2,9 @@ use crate::ffi;
|
|||
use crate::PyAny;
|
||||
|
||||
/// Represents a Python code object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyCode>`][crate::Py] or [`Bound<'py, PyCode>`][crate::Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyCode(PyAny);
|
||||
|
||||
|
|
|
@ -7,6 +7,12 @@ use std::os::raw::c_double;
|
|||
|
||||
/// Represents a Python [`complex`](https://docs.python.org/3/library/functions.html#complex) object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyComplex>`][crate::Py] or [`Bound<'py, PyComplex>`][Bound].
|
||||
///
|
||||
/// For APIs available on `complex` objects, see the [`PyComplexMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyComplex>`][Bound].
|
||||
///
|
||||
/// Note that `PyComplex` supports only basic operations. For advanced operations
|
||||
/// consider using [num-complex](https://docs.rs/num-complex)'s [`Complex`] type instead.
|
||||
/// This optional dependency can be activated with the `num-complex` feature flag.
|
||||
|
|
|
@ -191,7 +191,10 @@ pub trait PyTzInfoAccess<'py> {
|
|||
fn get_tzinfo_bound(&self) -> Option<Bound<'py, PyTzInfo>>;
|
||||
}
|
||||
|
||||
/// Bindings around `datetime.date`
|
||||
/// Bindings around `datetime.date`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyDate>`][crate::Py] or [`Bound<'py, PyDate>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyDate(PyAny);
|
||||
pyobject_native_type!(
|
||||
|
@ -279,7 +282,10 @@ impl PyDateAccess for Bound<'_, PyDate> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Bindings for `datetime.datetime`
|
||||
/// Bindings for `datetime.datetime`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyDateTime>`][crate::Py] or [`Bound<'py, PyDateTime>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyDateTime(PyAny);
|
||||
pyobject_native_type!(
|
||||
|
@ -578,7 +584,10 @@ impl<'py> PyTzInfoAccess<'py> for Bound<'py, PyDateTime> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Bindings for `datetime.time`
|
||||
/// Bindings for `datetime.time`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyTime>`][crate::Py] or [`Bound<'py, PyTime>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyTime(PyAny);
|
||||
pyobject_native_type!(
|
||||
|
@ -781,6 +790,9 @@ impl<'py> PyTzInfoAccess<'py> for Bound<'py, PyTime> {
|
|||
|
||||
/// Bindings for `datetime.tzinfo`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyTzInfo>`][crate::Py] or [`Bound<'py, PyTzInfo>`][Bound].
|
||||
///
|
||||
/// This is an abstract base class and cannot be constructed directly.
|
||||
/// For concrete time zone implementations, see [`timezone_utc_bound`] and
|
||||
/// the [`zoneinfo` module](https://docs.python.org/3/library/zoneinfo.html).
|
||||
|
@ -834,7 +846,10 @@ pub(crate) fn timezone_from_offset<'py>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Bindings for `datetime.timedelta`
|
||||
/// Bindings for `datetime.timedelta`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyDelta>`][crate::Py] or [`Bound<'py, PyDelta>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyDelta(PyAny);
|
||||
pyobject_native_type!(
|
||||
|
|
|
@ -11,6 +11,12 @@ use crate::PyNativeType;
|
|||
use crate::{ffi, Python, ToPyObject};
|
||||
|
||||
/// Represents a Python `dict`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyDict>`][crate::Py] or [`Bound<'py, PyDict>`][Bound].
|
||||
///
|
||||
/// For APIs available on `dict` objects, see the [`PyDictMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyDict>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyDict(PyAny);
|
||||
|
||||
|
@ -191,19 +197,6 @@ impl PyDict {
|
|||
}
|
||||
}
|
||||
|
||||
/// Deprecated version of `get_item`.
|
||||
#[deprecated(
|
||||
since = "0.20.0",
|
||||
note = "this is now equivalent to `PyDict::get_item`"
|
||||
)]
|
||||
#[inline]
|
||||
pub fn get_item_with_error<K>(&self, key: K) -> PyResult<Option<&PyAny>>
|
||||
where
|
||||
K: ToPyObject,
|
||||
{
|
||||
self.get_item(key)
|
||||
}
|
||||
|
||||
/// Sets an item value.
|
||||
///
|
||||
/// This is equivalent to the Python statement `self[key] = value`.
|
||||
|
@ -951,31 +944,6 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[allow(deprecated)]
|
||||
#[cfg(all(not(any(PyPy, GraalPy)), feature = "gil-refs"))]
|
||||
fn test_get_item_with_error() {
|
||||
Python::with_gil(|py| {
|
||||
let mut v = HashMap::new();
|
||||
v.insert(7, 32);
|
||||
let ob = v.to_object(py);
|
||||
let dict = ob.downcast::<PyDict>(py).unwrap();
|
||||
assert_eq!(
|
||||
32,
|
||||
dict.get_item_with_error(7i32)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.extract::<i32>()
|
||||
.unwrap()
|
||||
);
|
||||
assert!(dict.get_item_with_error(8i32).unwrap().is_none());
|
||||
assert!(dict
|
||||
.get_item_with_error(dict)
|
||||
.unwrap_err()
|
||||
.is_instance_of::<crate::exceptions::PyTypeError>(py));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set_item() {
|
||||
Python::with_gil(|py| {
|
||||
|
|
|
@ -4,6 +4,9 @@ use crate::{
|
|||
};
|
||||
|
||||
/// Represents the Python `Ellipsis` object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyEllipsis>`][crate::Py] or [`Bound<'py, PyEllipsis>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyEllipsis(PyAny);
|
||||
|
||||
|
|
|
@ -11,9 +11,15 @@ use std::os::raw::c_double;
|
|||
|
||||
/// Represents a Python `float` object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyFloat>`][crate::Py] or [`Bound<'py, PyFloat>`][Bound].
|
||||
///
|
||||
/// For APIs available on `float` objects, see the [`PyFloatMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyFloat>`][Bound].
|
||||
///
|
||||
/// You can usually avoid directly working with this type
|
||||
/// by using [`ToPyObject`] and [`extract`](PyAnyMethods::extract)
|
||||
/// with `f32`/`f64`.
|
||||
/// by using [`ToPyObject`] and [`extract`][PyAnyMethods::extract]
|
||||
/// with [`f32`]/[`f64`].
|
||||
#[repr(transparent)]
|
||||
pub struct PyFloat(PyAny);
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@ use crate::ffi;
|
|||
use crate::PyAny;
|
||||
|
||||
/// Represents a Python frame.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyFrame>`][crate::Py] or [`Bound<'py, PyFrame>`][crate::Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyFrame(PyAny);
|
||||
|
||||
|
|
|
@ -56,7 +56,13 @@ impl<'py> PyFrozenSetBuilder<'py> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Represents a Python `frozenset`
|
||||
/// Represents a Python `frozenset`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyFrozenSet>`][crate::Py] or [`Bound<'py, PyFrozenSet>`][Bound].
|
||||
///
|
||||
/// For APIs available on `frozenset` objects, see the [`PyFrozenSetMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyFrozenSet>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyFrozenSet(PyAny);
|
||||
|
||||
|
|
|
@ -16,6 +16,9 @@ use std::cell::UnsafeCell;
|
|||
use std::ffi::CStr;
|
||||
|
||||
/// Represents a builtin Python function object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyCFunction>`][crate::Py] or [`Bound<'py, PyCFunction>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyCFunction(PyAny);
|
||||
|
||||
|
@ -241,6 +244,9 @@ struct ClosureDestructor<F> {
|
|||
unsafe impl<F: Send> Send for ClosureDestructor<F> {}
|
||||
|
||||
/// Represents a Python function object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyFunction>`][crate::Py] or [`Bound<'py, PyFunction>`][Bound].
|
||||
#[repr(transparent)]
|
||||
#[cfg(all(not(Py_LIMITED_API), not(all(PyPy, not(Py_3_8)))))]
|
||||
pub struct PyFunction(PyAny);
|
||||
|
|
|
@ -3,10 +3,13 @@ use crate::instance::Borrowed;
|
|||
use crate::py_result_ext::PyResultExt;
|
||||
use crate::{ffi, Bound, PyAny, PyErr, PyResult, PyTypeCheck};
|
||||
#[cfg(feature = "gil-refs")]
|
||||
use crate::{AsPyPointer, PyDowncastError, PyNativeType};
|
||||
use crate::{AsPyPointer, PyNativeType};
|
||||
|
||||
/// A Python iterator object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyIterator>`][crate::Py] or [`Bound<'py, PyIterator>`][Bound].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -127,31 +130,6 @@ impl PyTypeCheck for PyIterator {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
impl<'v> crate::PyTryFrom<'v> for PyIterator {
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> {
|
||||
let value = value.into();
|
||||
unsafe {
|
||||
if ffi::PyIter_Check(value.as_ptr()) != 0 {
|
||||
Ok(value.downcast_unchecked())
|
||||
} else {
|
||||
Err(PyDowncastError::new(value, "Iterator"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyIterator, PyDowncastError<'v>> {
|
||||
value.into().downcast()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v PyIterator {
|
||||
let ptr = value.into() as *const _ as *const PyIterator;
|
||||
&*ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::PyIterator;
|
||||
|
@ -295,18 +273,6 @@ def fibonacci(target):
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
fn iterator_try_from() {
|
||||
Python::with_gil(|py| {
|
||||
let obj: crate::Py<crate::PyAny> =
|
||||
vec![10, 20].to_object(py).as_ref(py).iter().unwrap().into();
|
||||
let iter = <PyIterator as crate::PyTryFrom>::try_from(obj.as_ref(py)).unwrap();
|
||||
assert!(obj.is(iter));
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "macros")]
|
||||
fn python_class_not_iterator() {
|
||||
|
|
|
@ -14,6 +14,12 @@ use crate::types::any::PyAnyMethods;
|
|||
use crate::types::sequence::PySequenceMethods;
|
||||
|
||||
/// Represents a Python `list`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyList>`][crate::Py] or [`Bound<'py, PyList>`][Bound].
|
||||
///
|
||||
/// For APIs available on `list` objects, see the [`PyListMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyDict>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyList(PyAny);
|
||||
|
||||
|
|
|
@ -7,10 +7,16 @@ use crate::type_object::PyTypeInfo;
|
|||
use crate::types::any::PyAnyMethods;
|
||||
use crate::types::{PyAny, PyDict, PySequence, PyType};
|
||||
#[cfg(feature = "gil-refs")]
|
||||
use crate::{err::PyDowncastError, PyNativeType};
|
||||
use crate::PyNativeType;
|
||||
use crate::{ffi, Py, PyTypeCheck, Python, ToPyObject};
|
||||
|
||||
/// Represents a reference to a Python object supporting the mapping protocol.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyMapping>`][crate::Py] or [`Bound<'py, PyMapping>`][Bound].
|
||||
///
|
||||
/// For APIs available on mapping objects, see the [`PyMappingMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyMapping>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyMapping(PyAny);
|
||||
pyobject_native_type_named!(PyMapping);
|
||||
|
@ -260,34 +266,6 @@ impl PyTypeCheck for PyMapping {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
impl<'v> crate::PyTryFrom<'v> for PyMapping {
|
||||
/// Downcasting to `PyMapping` requires the concrete class to be a subclass (or registered
|
||||
/// subclass) of `collections.abc.Mapping` (from the Python standard library) - i.e.
|
||||
/// `isinstance(<class>, collections.abc.Mapping) == True`.
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyMapping, PyDowncastError<'v>> {
|
||||
let value = value.into();
|
||||
|
||||
if PyMapping::type_check(&value.as_borrowed()) {
|
||||
unsafe { return Ok(value.downcast_unchecked()) }
|
||||
}
|
||||
|
||||
Err(PyDowncastError::new(value, "Mapping"))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v PyMapping, PyDowncastError<'v>> {
|
||||
value.into().downcast()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v PyMapping {
|
||||
let ptr = value.into() as *const _ as *const PyMapping;
|
||||
&*ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
@ -439,16 +417,4 @@ mod tests {
|
|||
assert_eq!(32 + 42 + 123, values_sum);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
fn test_mapping_try_from() {
|
||||
use crate::PyTryFrom;
|
||||
Python::with_gil(|py| {
|
||||
let dict = PyDict::new(py);
|
||||
let _ = <PyMapping as PyTryFrom>::try_from(dict).unwrap();
|
||||
let _ = PyMapping::try_from_exact(dict).unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@ use crate::{ffi, Bound, PyAny};
|
|||
use crate::{AsPyPointer, PyNativeType};
|
||||
|
||||
/// Represents a Python `memoryview`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyMemoryView>`][crate::Py] or [`Bound<'py, PyMemoryView>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyMemoryView(PyAny);
|
||||
|
||||
|
|
|
@ -15,6 +15,12 @@ use {super::PyStringMethods, crate::PyNativeType};
|
|||
|
||||
/// Represents a Python [`module`][1] object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyModule>`][crate::Py] or [`Bound<'py, PyModule>`][Bound].
|
||||
///
|
||||
/// For APIs available on `module` objects, see the [`PyModuleMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyModule>`][Bound].
|
||||
///
|
||||
/// As with all other Python objects, modules are first class citizens.
|
||||
/// This means they can be passed to or returned from functions,
|
||||
/// created dynamically, assigned to variables and so forth.
|
||||
|
@ -298,7 +304,7 @@ impl PyModule {
|
|||
/// make an *instance* of `Foo` (or *get* one for that matter, as we haven't exported
|
||||
/// anything that can return instances of `Foo`).
|
||||
///
|
||||
/// [1]: https://pyo3.rs/latest/class.html#constructor
|
||||
#[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#constructor")]
|
||||
pub fn add_class<T>(&self) -> PyResult<()>
|
||||
where
|
||||
T: PyClass,
|
||||
|
@ -503,7 +509,7 @@ pub trait PyModuleMethods<'py>: crate::sealed::Sealed {
|
|||
/// make an *instance* of `Foo` (or *get* one for that matter, as we haven't exported
|
||||
/// anything that can return instances of `Foo`).
|
||||
///
|
||||
/// [1]: https://pyo3.rs/latest/class.html#constructor
|
||||
#[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#constructor")]
|
||||
fn add_class<T>(&self) -> PyResult<()>
|
||||
where
|
||||
T: PyClass;
|
||||
|
|
|
@ -5,6 +5,9 @@ use crate::{
|
|||
};
|
||||
|
||||
/// Represents the Python `None` object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyNone>`][crate::Py] or [`Bound<'py, PyNone>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyNone(PyAny);
|
||||
|
||||
|
|
|
@ -4,6 +4,9 @@ use crate::{
|
|||
};
|
||||
|
||||
/// Represents the Python `NotImplemented` object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyNotImplemented>`][crate::Py] or [`Bound<'py, PyNotImplemented>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyNotImplemented(PyAny);
|
||||
|
||||
|
|
|
@ -2,6 +2,9 @@ use crate::{ffi, PyAny};
|
|||
|
||||
/// Represents a Python `int` object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyLong>`][crate::Py] or [`Bound<'py, PyLong>`][crate::Bound].
|
||||
///
|
||||
/// You can usually avoid directly working with this type
|
||||
/// by using [`ToPyObject`](crate::conversion::ToPyObject)
|
||||
/// and [`extract`](super::PyAnyMethods::extract)
|
||||
|
|
|
@ -6,7 +6,8 @@ use crate::{PyAny, PyResult};
|
|||
|
||||
/// Represents a Python `super` object.
|
||||
///
|
||||
/// This type is immutable.
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PySuper>`][crate::Py] or [`Bound<'py, PySuper>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PySuper(PyAny);
|
||||
|
||||
|
|
|
@ -10,10 +10,16 @@ use crate::sync::GILOnceCell;
|
|||
use crate::type_object::PyTypeInfo;
|
||||
use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType};
|
||||
#[cfg(feature = "gil-refs")]
|
||||
use crate::{err::PyDowncastError, PyNativeType};
|
||||
use crate::PyNativeType;
|
||||
use crate::{ffi, FromPyObject, Py, PyTypeCheck, Python, ToPyObject};
|
||||
|
||||
/// Represents a reference to a Python object supporting the sequence protocol.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PySequence>`][crate::Py] or [`Bound<'py, PySequence>`][Bound].
|
||||
///
|
||||
/// For APIs available on sequence objects, see the [`PySequenceMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PySequence>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PySequence(PyAny);
|
||||
pyobject_native_type_named!(PySequence);
|
||||
|
@ -547,33 +553,6 @@ impl PyTypeCheck for PySequence {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
impl<'v> crate::PyTryFrom<'v> for PySequence {
|
||||
/// Downcasting to `PySequence` requires the concrete class to be a subclass (or registered
|
||||
/// subclass) of `collections.abc.Sequence` (from the Python standard library) - i.e.
|
||||
/// `isinstance(<class>, collections.abc.Sequence) == True`.
|
||||
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> {
|
||||
let value = value.into();
|
||||
|
||||
if PySequence::type_check(&value.as_borrowed()) {
|
||||
unsafe { return Ok(value.downcast_unchecked::<PySequence>()) }
|
||||
}
|
||||
|
||||
Err(PyDowncastError::new(value, "Sequence"))
|
||||
}
|
||||
|
||||
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v PySequence, PyDowncastError<'v>> {
|
||||
value.into().downcast()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v PySequence {
|
||||
let ptr = value.into() as *const _ as *const PySequence;
|
||||
&*ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::types::{PyAnyMethods, PyList, PySequence, PySequenceMethods, PyTuple};
|
||||
|
@ -1101,16 +1080,4 @@ mod tests {
|
|||
assert!(seq_from.to_list().is_ok());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "gil-refs")]
|
||||
#[allow(deprecated)]
|
||||
fn test_seq_try_from() {
|
||||
use crate::PyTryFrom;
|
||||
Python::with_gil(|py| {
|
||||
let list = PyList::empty(py);
|
||||
let _ = <PySequence as PyTryFrom>::try_from(list).unwrap();
|
||||
let _ = PySequence::try_from_exact(list).unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,13 @@ use crate::{
|
|||
use crate::{ffi, PyAny, PyObject, Python, ToPyObject};
|
||||
use std::ptr;
|
||||
|
||||
/// Represents a Python `set`
|
||||
/// Represents a Python `set`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PySet>`][crate::Py] or [`Bound<'py, PySet>`][Bound].
|
||||
///
|
||||
/// For APIs available on `set` objects, see the [`PySetMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PySet>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PySet(PyAny);
|
||||
|
||||
|
|
|
@ -8,6 +8,12 @@ use crate::{Bound, PyAny, PyObject, Python, ToPyObject};
|
|||
|
||||
/// Represents a Python `slice`.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PySlice>`][crate::Py] or [`Bound<'py, PySlice>`][Bound].
|
||||
///
|
||||
/// For APIs available on `slice` objects, see the [`PySliceMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PySlice>`][Bound].
|
||||
///
|
||||
/// Only `isize` indices supported at the moment by the `PySlice` object.
|
||||
#[repr(transparent)]
|
||||
pub struct PySlice(PyAny);
|
||||
|
|
|
@ -123,10 +123,11 @@ impl<'a> PyStringData<'a> {
|
|||
|
||||
/// Represents a Python `string` (a Unicode string object).
|
||||
///
|
||||
/// This type is only seen inside PyO3's smart pointers as [`Py<PyString>`], [`Bound<'py, PyString>`],
|
||||
/// and [`Borrowed<'a, 'py, PyString>`].
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyString>`][crate::Py] or [`Bound<'py, PyString>`][Bound].
|
||||
///
|
||||
/// All functionality on this type is implemented through the [`PyStringMethods`] trait.
|
||||
/// For APIs available on `str` objects, see the [`PyStringMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyString>`][Bound].
|
||||
///
|
||||
/// # Equality
|
||||
///
|
||||
|
|
|
@ -5,6 +5,12 @@ use crate::PyNativeType;
|
|||
use crate::{ffi, Bound, PyAny};
|
||||
|
||||
/// Represents a Python traceback.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyTraceback>`][crate::Py] or [`Bound<'py, PyTraceback>`][Bound].
|
||||
///
|
||||
/// For APIs available on traceback objects, see the [`PyTracebackMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyTraceback>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyTraceback(PyAny);
|
||||
|
||||
|
|
|
@ -52,7 +52,11 @@ fn new_from_iter<'py>(
|
|||
|
||||
/// Represents a Python `tuple` object.
|
||||
///
|
||||
/// This type is immutable.
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyTuple>`][crate::Py] or [`Bound<'py, PyTuple>`][Bound].
|
||||
///
|
||||
/// For APIs available on `tuple` objects, see the [`PyTupleMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyTuple>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyTuple(PyAny);
|
||||
|
||||
|
|
|
@ -9,7 +9,14 @@ use crate::PyNativeType;
|
|||
use crate::{ffi, Bound, PyAny, PyTypeInfo, Python};
|
||||
|
||||
use super::PyString;
|
||||
/// Represents a reference to a Python `type object`.
|
||||
|
||||
/// Represents a reference to a Python `type` object.
|
||||
///
|
||||
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||
/// [`Py<PyType>`][crate::Py] or [`Bound<'py, PyType>`][Bound].
|
||||
///
|
||||
/// For APIs available on `type` objects, see the [`PyTypeMethods`] trait which is implemented for
|
||||
/// [`Bound<'py, PyType>`][Bound].
|
||||
#[repr(transparent)]
|
||||
pub struct PyType(PyAny);
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ fn test_compile_errors() {
|
|||
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
|
||||
t.compile_fail("tests/ui/invalid_pymodule_args.rs");
|
||||
t.compile_fail("tests/ui/reject_generics.rs");
|
||||
#[cfg(feature = "gil-refs")]
|
||||
t.compile_fail("tests/ui/deprecations.rs");
|
||||
t.compile_fail("tests/ui/invalid_closure.rs");
|
||||
t.compile_fail("tests/ui/pyclass_send.rs");
|
||||
|
@ -67,4 +66,5 @@ fn test_compile_errors() {
|
|||
t.compile_fail("tests/ui/abi3_weakref.rs");
|
||||
#[cfg(all(Py_LIMITED_API, not(Py_3_9)))]
|
||||
t.compile_fail("tests/ui/abi3_dict.rs");
|
||||
t.compile_fail("tests/ui/duplicate_pymodule_submodule.rs");
|
||||
}
|
||||
|
|
|
@ -49,8 +49,7 @@ create_exception!(
|
|||
"Some description."
|
||||
);
|
||||
|
||||
#[pymodule]
|
||||
#[pyo3(submodule)]
|
||||
#[pymodule(submodule)]
|
||||
mod external_submodule {}
|
||||
|
||||
/// A module written using declarative syntax.
|
||||
|
@ -115,7 +114,7 @@ mod declarative_module {
|
|||
}
|
||||
}
|
||||
|
||||
#[pymodule(submodule)]
|
||||
#[pymodule]
|
||||
#[pyo3(module = "custom_root")]
|
||||
mod inner_custom_root {
|
||||
use super::*;
|
||||
|
@ -144,8 +143,7 @@ mod declarative_submodule {
|
|||
use super::{double, double_value};
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
#[pyo3(name = "declarative_module_renamed")]
|
||||
#[pymodule(name = "declarative_module_renamed")]
|
||||
mod declarative_module2 {
|
||||
#[pymodule_export]
|
||||
use super::double;
|
||||
|
|
|
@ -138,8 +138,7 @@ fn test_module_with_explicit_py_arg() {
|
|||
});
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
#[pyo3(name = "other_name")]
|
||||
#[pymodule(name = "other_name")]
|
||||
fn some_name(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add("other_name", "other_name")?;
|
||||
Ok(())
|
||||
|
|
|
@ -2,125 +2,11 @@
|
|||
#![allow(dead_code)]
|
||||
|
||||
use pyo3::prelude::*;
|
||||
use pyo3::types::{PyString, PyType};
|
||||
|
||||
#[pyclass]
|
||||
struct MyClass;
|
||||
|
||||
#[pymethods]
|
||||
impl MyClass {
|
||||
#[__new__]
|
||||
fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
#[classmethod]
|
||||
fn cls_method_gil_ref(_cls: &PyType) {}
|
||||
|
||||
#[classmethod]
|
||||
fn cls_method_bound(_cls: &Bound<'_, PyType>) {}
|
||||
|
||||
fn method_gil_ref(_slf: &PyCell<Self>) {}
|
||||
|
||||
fn method_bound(_slf: &Bound<'_, Self>) {}
|
||||
|
||||
#[staticmethod]
|
||||
fn static_method_gil_ref(_any: &PyAny) {}
|
||||
|
||||
#[setter]
|
||||
fn set_foo_gil_ref(&self, #[pyo3(from_py_with = "extract_gil_ref")] _value: i32) {}
|
||||
|
||||
#[setter]
|
||||
fn set_foo_bound(&self, #[pyo3(from_py_with = "extract_bound")] _value: i32) {}
|
||||
|
||||
#[setter]
|
||||
fn set_bar_gil_ref(&self, _value: &PyAny) {}
|
||||
|
||||
#[setter]
|
||||
fn set_bar_bound(&self, _value: &Bound<'_, PyAny>) {}
|
||||
|
||||
fn __eq__(&self, #[pyo3(from_py_with = "extract_gil_ref")] _other: i32) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn __contains__(&self, #[pyo3(from_py_with = "extract_bound")] _value: i32) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
||||
#[pyfunction]
|
||||
#[pyo3(pass_module)]
|
||||
fn pyfunction_with_module<'py>(module: &Bound<'py, PyModule>) -> PyResult<Bound<'py, PyString>> {
|
||||
module.name()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
#[pyo3(pass_module)]
|
||||
fn pyfunction_with_module_gil_ref(_module: &PyModule) -> PyResult<&str> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn double(x: usize) -> usize {
|
||||
x * 2
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
fn module_gil_ref(_m: &PyModule) -> PyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
fn module_gil_ref_with_explicit_py_arg(_py: Python<'_>, _m: &PyModule) -> PyResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
fn module_bound(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
fn module_bound_with_explicit_py_arg(_py: Python<'_>, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[pymodule]
|
||||
fn module_bound_by_value(m: Bound<'_, PyModule>) -> PyResult<()> {
|
||||
m.add_function(wrap_pyfunction!(double, &m)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract_gil_ref(obj: &PyAny) -> PyResult<i32> {
|
||||
obj.extract()
|
||||
}
|
||||
|
||||
fn extract_bound(obj: &Bound<'_, PyAny>) -> PyResult<i32> {
|
||||
obj.extract()
|
||||
}
|
||||
|
||||
fn extract_options(obj: &Bound<'_, PyAny>) -> PyResult<Option<i32>> {
|
||||
obj.extract()
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn pyfunction_from_py_with(
|
||||
#[pyo3(from_py_with = "extract_gil_ref")] _gil_ref: i32,
|
||||
#[pyo3(from_py_with = "extract_bound")] _bound: i32,
|
||||
) {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn pyfunction_gil_ref(_any: &PyAny) {}
|
||||
|
||||
#[pyfunction]
|
||||
#[pyo3(signature = (_any))]
|
||||
fn pyfunction_option_gil_ref(_any: Option<&PyAny>) {}
|
||||
|
||||
#[pyfunction]
|
||||
#[pyo3(signature = (_i, _any=None))]
|
||||
fn pyfunction_option_1(_i: u32, _any: Option<i32>) {}
|
||||
|
@ -139,63 +25,10 @@ fn pyfunction_option_4(
|
|||
) {
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPyObject)]
|
||||
pub struct Zap {
|
||||
#[pyo3(item)]
|
||||
name: String,
|
||||
|
||||
#[pyo3(from_py_with = "PyAny::len", item("my_object"))]
|
||||
some_object_length: usize,
|
||||
|
||||
#[pyo3(from_py_with = "extract_bound")]
|
||||
some_number: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPyObject)]
|
||||
pub struct ZapTuple(
|
||||
String,
|
||||
#[pyo3(from_py_with = "PyAny::len")] usize,
|
||||
#[pyo3(from_py_with = "extract_bound")] i32,
|
||||
);
|
||||
|
||||
#[derive(Debug, FromPyObject, PartialEq, Eq)]
|
||||
pub enum ZapEnum {
|
||||
Zip(#[pyo3(from_py_with = "extract_gil_ref")] i32),
|
||||
Zap(String, #[pyo3(from_py_with = "extract_bound")] i32),
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPyObject, PartialEq, Eq)]
|
||||
#[pyo3(transparent)]
|
||||
pub struct TransparentFromPyWithGilRef {
|
||||
#[pyo3(from_py_with = "extract_gil_ref")]
|
||||
len: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPyObject, PartialEq, Eq)]
|
||||
#[pyo3(transparent)]
|
||||
pub struct TransparentFromPyWithBound {
|
||||
#[pyo3(from_py_with = "extract_bound")]
|
||||
len: i32,
|
||||
}
|
||||
|
||||
fn test_wrap_pyfunction(py: Python<'_>, m: &Bound<'_, PyModule>) {
|
||||
// should lint
|
||||
let _ = wrap_pyfunction!(double, py);
|
||||
|
||||
// should lint but currently does not
|
||||
let _ = wrap_pyfunction!(double)(py);
|
||||
|
||||
// should not lint
|
||||
let _ = wrap_pyfunction!(double, m);
|
||||
let _ = wrap_pyfunction!(double)(m);
|
||||
let _ = wrap_pyfunction!(double, m.as_gil_ref());
|
||||
let _ = wrap_pyfunction!(double)(m.as_gil_ref());
|
||||
let _ = wrap_pyfunction_bound!(double, py);
|
||||
let _ = wrap_pyfunction_bound!(double)(py);
|
||||
}
|
||||
|
||||
#[pyclass]
|
||||
pub enum SimpleEnumWithoutEq {
|
||||
VariamtA,
|
||||
VariantB,
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
error: use of deprecated constant `pyo3::deprecations::PYMETHODS_NEW_DEPRECATED_FORM`: use `#[new]` instead of `#[__new__]`
|
||||
--> tests/ui/deprecations.rs:12:7
|
||||
error: use of deprecated constant `__pyfunction_pyfunction_option_2::SIGNATURE`: this function has implicit defaults for the trailing `Option<T>` arguments
|
||||
= note: these implicit defaults are being phased out
|
||||
= help: add `#[pyo3(signature = (_i, _any=None))]` to this function to silence this warning and keep the current behavior
|
||||
--> tests/ui/deprecations.rs:15:4
|
||||
|
|
||||
12 | #[__new__]
|
||||
| ^^^^^^^
|
||||
15 | fn pyfunction_option_2(_i: u32, _any: Option<i32>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
note: the lint level is defined here
|
||||
--> tests/ui/deprecations.rs:1:9
|
||||
|
@ -10,144 +12,26 @@ note: the lint level is defined here
|
|||
1 | #![deny(deprecated)]
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: use of deprecated constant `__pyfunction_pyfunction_option_2::SIGNATURE`: this function has implicit defaults for the trailing `Option<T>` arguments
|
||||
= note: these implicit defaults are being phased out
|
||||
= help: add `#[pyo3(signature = (_i, _any=None))]` to this function to silence this warning and keep the current behavior
|
||||
--> tests/ui/deprecations.rs:129:4
|
||||
|
|
||||
129 | fn pyfunction_option_2(_i: u32, _any: Option<i32>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated constant `__pyfunction_pyfunction_option_3::SIGNATURE`: this function has implicit defaults for the trailing `Option<T>` arguments
|
||||
= note: these implicit defaults are being phased out
|
||||
= help: add `#[pyo3(signature = (_i, _any=None, _foo=None))]` to this function to silence this warning and keep the current behavior
|
||||
--> tests/ui/deprecations.rs:132:4
|
||||
|
|
||||
132 | fn pyfunction_option_3(_i: u32, _any: Option<i32>, _foo: Option<String>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/ui/deprecations.rs:18:4
|
||||
|
|
||||
18 | fn pyfunction_option_3(_i: u32, _any: Option<i32>, _foo: Option<String>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated constant `__pyfunction_pyfunction_option_4::SIGNATURE`: this function has implicit defaults for the trailing `Option<T>` arguments
|
||||
= note: these implicit defaults are being phased out
|
||||
= help: add `#[pyo3(signature = (_i, _any=None, _foo=None))]` to this function to silence this warning and keep the current behavior
|
||||
--> tests/ui/deprecations.rs:135:4
|
||||
|
|
||||
135 | fn pyfunction_option_4(
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
--> tests/ui/deprecations.rs:21:4
|
||||
|
|
||||
21 | fn pyfunction_option_4(
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated constant `SimpleEnumWithoutEq::__pyo3__generated____richcmp__::DEPRECATION`: Implicit equality for simple enums is deprecated. Use `#[pyclass(eq, eq_int)` to keep the current behavior.
|
||||
--> tests/ui/deprecations.rs:197:1
|
||||
|
|
||||
197 | #[pyclass]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: use of deprecated struct `pyo3::PyCell`: `PyCell` was merged into `Bound`, use that instead; see the migration guide for more info
|
||||
--> tests/ui/deprecations.rs:23:30
|
||||
--> tests/ui/deprecations.rs:28:1
|
||||
|
|
||||
23 | fn method_gil_ref(_slf: &PyCell<Self>) {}
|
||||
| ^^^^^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||
--> tests/ui/deprecations.rs:42:44
|
||||
28 | #[pyclass]
|
||||
| ^^^^^^^^^^
|
||||
|
|
||||
42 | fn __eq__(&self, #[pyo3(from_py_with = "extract_gil_ref")] _other: i32) -> bool {
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
|
||||
--> tests/ui/deprecations.rs:18:33
|
||||
|
|
||||
18 | fn cls_method_gil_ref(_cls: &PyType) {}
|
||||
| ^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
|
||||
--> tests/ui/deprecations.rs:23:29
|
||||
|
|
||||
23 | fn method_gil_ref(_slf: &PyCell<Self>) {}
|
||||
| ^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
|
||||
--> tests/ui/deprecations.rs:28:36
|
||||
|
|
||||
28 | fn static_method_gil_ref(_any: &PyAny) {}
|
||||
| ^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||
--> tests/ui/deprecations.rs:31:53
|
||||
|
|
||||
31 | fn set_foo_gil_ref(&self, #[pyo3(from_py_with = "extract_gil_ref")] _value: i32) {}
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
|
||||
--> tests/ui/deprecations.rs:37:39
|
||||
|
|
||||
37 | fn set_bar_gil_ref(&self, _value: &PyAny) {}
|
||||
| ^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
|
||||
--> tests/ui/deprecations.rs:61:44
|
||||
|
|
||||
61 | fn pyfunction_with_module_gil_ref(_module: &PyModule) -> PyResult<&str> {
|
||||
| ^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
|
||||
--> tests/ui/deprecations.rs:71:19
|
||||
|
|
||||
71 | fn module_gil_ref(_m: &PyModule) -> PyResult<()> {
|
||||
| ^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
|
||||
--> tests/ui/deprecations.rs:76:57
|
||||
|
|
||||
76 | fn module_gil_ref_with_explicit_py_arg(_py: Python<'_>, _m: &PyModule) -> PyResult<()> {
|
||||
| ^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||
--> tests/ui/deprecations.rs:112:27
|
||||
|
|
||||
112 | #[pyo3(from_py_with = "extract_gil_ref")] _gil_ref: i32,
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::function_arg`: use `&Bound<'_, T>` instead for this function argument
|
||||
--> tests/ui/deprecations.rs:118:29
|
||||
|
|
||||
118 | fn pyfunction_gil_ref(_any: &PyAny) {}
|
||||
| ^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::OptionGilRefs::<std::option::Option<T>>::function_arg`: use `Option<&Bound<'_, T>>` instead for this function argument
|
||||
--> tests/ui/deprecations.rs:122:36
|
||||
|
|
||||
122 | fn pyfunction_option_gil_ref(_any: Option<&PyAny>) {}
|
||||
| ^^^^^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||
--> tests/ui/deprecations.rs:147:27
|
||||
|
|
||||
147 | #[pyo3(from_py_with = "PyAny::len", item("my_object"))]
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||
--> tests/ui/deprecations.rs:157:27
|
||||
|
|
||||
157 | #[pyo3(from_py_with = "PyAny::len")] usize,
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||
--> tests/ui/deprecations.rs:163:31
|
||||
|
|
||||
163 | Zip(#[pyo3(from_py_with = "extract_gil_ref")] i32),
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<T>::from_py_with_arg`: use `&Bound<'_, PyAny>` as the argument for this `from_py_with` extractor
|
||||
--> tests/ui/deprecations.rs:170:27
|
||||
|
|
||||
170 | #[pyo3(from_py_with = "extract_gil_ref")]
|
||||
| ^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: use of deprecated method `pyo3::deprecations::GilRefs::<pyo3::Python<'_>>::is_python`: use `wrap_pyfunction_bound!` instead
|
||||
--> tests/ui/deprecations.rs:183:13
|
||||
|
|
||||
183 | let _ = wrap_pyfunction!(double, py);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `wrap_pyfunction` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
#[pyo3::pymodule]
|
||||
mod mymodule {
|
||||
#[pyo3::pymodule(submodule)]
|
||||
mod submod {}
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,17 @@
|
|||
error: `submodule` may only be specified once (it is implicitly always specified for nested modules)
|
||||
--> tests/ui/duplicate_pymodule_submodule.rs:4:2
|
||||
|
|
||||
4 | mod submod {}
|
||||
| ^^^
|
||||
|
||||
error[E0425]: cannot find value `_PYO3_DEF` in module `submod`
|
||||
--> tests/ui/duplicate_pymodule_submodule.rs:1:1
|
||||
|
|
||||
1 | #[pyo3::pymodule]
|
||||
| ^^^^^^^^^^^^^^^^^ not found in `submod`
|
||||
|
|
||||
= note: this error originates in the attribute macro `pyo3::pymodule` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: consider importing this static
|
||||
|
|
||||
3 + use crate::mymodule::_PYO3_DEF;
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
// see invalid_pymodule_in_root.rs
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue