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:
|
rust-target:
|
||||||
required: true
|
required: true
|
||||||
type: string
|
type: string
|
||||||
|
MSRV:
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -51,9 +54,9 @@ jobs:
|
||||||
name: Prepare LD_LIBRARY_PATH (Ubuntu only)
|
name: Prepare LD_LIBRARY_PATH (Ubuntu only)
|
||||||
run: echo LD_LIBRARY_PATH=${pythonLocation}/lib >> $GITHUB_ENV
|
run: echo LD_LIBRARY_PATH=${pythonLocation}/lib >> $GITHUB_ENV
|
||||||
|
|
||||||
- if: inputs.rust == '1.63.0'
|
- if: inputs.rust == inputs.MSRV
|
||||||
name: Prepare minimal package versions (MSRV only)
|
name: Prepare MSRV package versions
|
||||||
run: nox -s set-minimal-package-versions
|
run: nox -s set-msrv-package-versions
|
||||||
|
|
||||||
- if: inputs.rust != 'stable'
|
- if: inputs.rust != 'stable'
|
||||||
name: Ignore changed error messages when using trybuild
|
name: Ignore changed error messages when using trybuild
|
||||||
|
|
|
@ -31,6 +31,18 @@ jobs:
|
||||||
- name: Check rust formatting (rustfmt)
|
- name: Check rust formatting (rustfmt)
|
||||||
run: nox -s 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:
|
semver-checks:
|
||||||
if: github.ref != 'refs/heads/main'
|
if: github.ref != 'refs/heads/main'
|
||||||
needs: [fmt]
|
needs: [fmt]
|
||||||
|
@ -41,13 +53,13 @@ jobs:
|
||||||
- uses: obi1kenobi/cargo-semver-checks-action@v2
|
- uses: obi1kenobi/cargo-semver-checks-action@v2
|
||||||
|
|
||||||
check-msrv:
|
check-msrv:
|
||||||
needs: [fmt]
|
needs: [fmt, resolve]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: dtolnay/rust-toolchain@master
|
- uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: 1.63.0
|
toolchain: ${{ needs.resolve.outputs.MSRV }}
|
||||||
targets: x86_64-unknown-linux-gnu
|
targets: x86_64-unknown-linux-gnu
|
||||||
components: rust-src
|
components: rust-src
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
|
@ -57,9 +69,11 @@ jobs:
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.event_name != 'merge_group' }}
|
save-if: ${{ github.event_name != 'merge_group' }}
|
||||||
- run: python -m pip install --upgrade pip && pip install nox
|
- run: python -m pip install --upgrade pip && pip install nox
|
||||||
- name: Prepare minimal package versions
|
# This is a smoke test to confirm that CI will run on MSRV (including dev dependencies)
|
||||||
run: nox -s set-minimal-package-versions
|
- name: Check with MSRV package versions
|
||||||
- run: nox -s check-all
|
run: |
|
||||||
|
nox -s set-msrv-package-versions
|
||||||
|
nox -s check-all
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CARGO_BUILD_TARGET: x86_64-unknown-linux-gnu
|
CARGO_BUILD_TARGET: x86_64-unknown-linux-gnu
|
||||||
|
@ -141,7 +155,7 @@ jobs:
|
||||||
build-pr:
|
build-pr:
|
||||||
if: ${{ !contains(github.event.pull_request.labels.*.name, 'CI-build-full') && github.event_name == 'pull_request' }}
|
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 }}
|
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
|
uses: ./.github/workflows/build.yml
|
||||||
with:
|
with:
|
||||||
os: ${{ matrix.platform.os }}
|
os: ${{ matrix.platform.os }}
|
||||||
|
@ -149,6 +163,7 @@ jobs:
|
||||||
python-architecture: ${{ matrix.platform.python-architecture }}
|
python-architecture: ${{ matrix.platform.python-architecture }}
|
||||||
rust: ${{ matrix.rust }}
|
rust: ${{ matrix.rust }}
|
||||||
rust-target: ${{ matrix.platform.rust-target }}
|
rust-target: ${{ matrix.platform.rust-target }}
|
||||||
|
MSRV: ${{ needs.resolve.outputs.MSRV }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
strategy:
|
strategy:
|
||||||
# If one platform fails, allow the rest to keep testing if `CI-no-fail-fast` label is present
|
# 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:
|
build-full:
|
||||||
if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }}
|
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 }}
|
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
|
uses: ./.github/workflows/build.yml
|
||||||
with:
|
with:
|
||||||
os: ${{ matrix.platform.os }}
|
os: ${{ matrix.platform.os }}
|
||||||
|
@ -206,6 +221,7 @@ jobs:
|
||||||
python-architecture: ${{ matrix.platform.python-architecture }}
|
python-architecture: ${{ matrix.platform.python-architecture }}
|
||||||
rust: ${{ matrix.rust }}
|
rust: ${{ matrix.rust }}
|
||||||
rust-target: ${{ matrix.platform.rust-target }}
|
rust-target: ${{ matrix.platform.rust-target }}
|
||||||
|
MSRV: ${{ needs.resolve.outputs.MSRV }}
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
strategy:
|
strategy:
|
||||||
# If one platform fails, allow the rest to keep testing if `CI-no-fail-fast` label is present
|
# If one platform fails, allow the rest to keep testing if `CI-no-fail-fast` label is present
|
||||||
|
@ -251,7 +267,7 @@ jobs:
|
||||||
]
|
]
|
||||||
include:
|
include:
|
||||||
# Test minimal supported Rust version
|
# Test minimal supported Rust version
|
||||||
- rust: 1.63.0
|
- rust: ${{ needs.resolve.outputs.MSRV }}
|
||||||
python-version: "3.12"
|
python-version: "3.12"
|
||||||
platform:
|
platform:
|
||||||
{
|
{
|
||||||
|
@ -487,21 +503,31 @@ jobs:
|
||||||
- run: python3 -m nox -s test-version-limits
|
- run: python3 -m nox -s test-version-limits
|
||||||
|
|
||||||
check-feature-powerset:
|
check-feature-powerset:
|
||||||
needs: [fmt]
|
needs: [fmt, resolve]
|
||||||
if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }}
|
if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }}
|
||||||
runs-on: ubuntu-latest
|
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:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
- uses: Swatinem/rust-cache@v2
|
- uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
save-if: ${{ github.event_name != 'merge_group' }}
|
save-if: ${{ github.event_name != 'merge_group' }}
|
||||||
- uses: dtolnay/rust-toolchain@stable
|
- uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
components: rust-src
|
toolchain: stable
|
||||||
- uses: taiki-e/install-action@cargo-hack
|
- 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 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:
|
test-cross-compilation:
|
||||||
needs: [fmt]
|
needs: [fmt]
|
||||||
|
|
|
@ -22,7 +22,7 @@ jobs:
|
||||||
tag_name: ${{ steps.prepare_tag.outputs.tag_name }}
|
tag_name: ${{ steps.prepare_tag.outputs.tag_name }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
- uses: dtolnay/rust-toolchain@nightly
|
- uses: dtolnay/rust-toolchain@nightly
|
||||||
|
|
||||||
- name: Setup mdBook
|
- name: Setup mdBook
|
||||||
|
|
16
Cargo.toml
16
Cargo.toml
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3"
|
name = "pyo3"
|
||||||
version = "0.22.1"
|
version = "0.23.0-dev"
|
||||||
description = "Bindings to Python interpreter"
|
description = "Bindings to Python interpreter"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -18,13 +18,13 @@ rust-version = "1.63"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
libc = "0.2.62"
|
libc = "0.2.62"
|
||||||
memoffset = "0.9"
|
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
|
# 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
|
# 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 }
|
indoc = { version = "2.0.1", optional = true }
|
||||||
unindent = { version = "0.2.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 }
|
inventory = { version = "0.3.0", optional = true }
|
||||||
|
|
||||||
# crate integrations that can be added using the eponymous features
|
# 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 = { version = "0.4.25", default-features = false, optional = true }
|
||||||
chrono-tz = { version = ">= 0.6, < 0.10", default-features = false, optional = true }
|
chrono-tz = { version = ">= 0.6, < 0.10", default-features = false, optional = true }
|
||||||
either = { version = "1.9", optional = true }
|
either = { version = "1.9", optional = true }
|
||||||
eyre = { version = ">= 0.4, < 0.7", optional = true }
|
eyre = { version = ">= 0.4, < 0.7", optional = true }
|
||||||
hashbrown = { version = ">= 0.9, < 0.15", optional = true }
|
hashbrown = { version = ">= 0.9, < 0.15", optional = true }
|
||||||
indexmap = { version = ">= 1.6, < 3", 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-complex = { version = ">= 0.2, < 0.5", optional = true }
|
||||||
num-rational = {version = "0.4.1", 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 }
|
serde = { version = "1.0", optional = true }
|
||||||
smallvec = { version = "1.0", optional = true }
|
smallvec = { version = "1.0", optional = true }
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ rayon = "1.6.1"
|
||||||
futures = "0.3.28"
|
futures = "0.3.28"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
pyo3-build-config = { path = "pyo3-build-config", version = "=0.22.1", features = ["resolve-config"] }
|
pyo3-build-config = { path = "pyo3-build-config", version = "=0.23.0-dev", features = ["resolve-config"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["macros"]
|
default = ["macros"]
|
||||||
|
|
|
@ -193,6 +193,7 @@ about this topic.
|
||||||
- [fastuuid](https://github.com/thedrow/fastuuid/) _Python bindings to Rust's UUID library._
|
- [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._
|
- [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._
|
- [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_
|
- [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._
|
- [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._
|
- [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/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/pyproject.toml", "pyproject.toml");
|
file::rename(".template/pyproject.toml", "pyproject.toml");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -75,8 +75,7 @@ impl ExampleContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(name = "getitem")]
|
||||||
#[pyo3(name = "getitem")]
|
|
||||||
fn example(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn example(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
// ? -https://github.com/PyO3/maturin/issues/475
|
// ? -https://github.com/PyO3/maturin/issues/475
|
||||||
m.add_class::<ExampleContainer>()?;
|
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/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/pyproject.toml", "pyproject.toml");
|
file::rename(".template/pyproject.toml", "pyproject.toml");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
variable::set("PYO3_VERSION", "0.22.1");
|
variable::set("PYO3_VERSION", "0.23.0-dev");
|
||||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/plugin_api/Cargo.toml", "plugin_api/Cargo.toml");
|
file::rename(".template/plugin_api/Cargo.toml", "plugin_api/Cargo.toml");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
variable::set("PYO3_VERSION", "0.22.1");
|
variable::set("PYO3_VERSION", "0.23.0-dev");
|
||||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/setup.cfg", "setup.cfg");
|
file::rename(".template/setup.cfg", "setup.cfg");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
variable::set("PYO3_VERSION", "0.22.1");
|
variable::set("PYO3_VERSION", "0.23.0-dev");
|
||||||
file::rename(".template/Cargo.toml", "Cargo.toml");
|
file::rename(".template/Cargo.toml", "Cargo.toml");
|
||||||
file::rename(".template/pyproject.toml", "pyproject.toml");
|
file::rename(".template/pyproject.toml", "pyproject.toml");
|
||||||
file::delete(".template");
|
file::delete(".template");
|
||||||
|
|
|
@ -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).
|
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
|
### The `extension-module` feature
|
||||||
|
|
||||||
|
|
|
@ -129,9 +129,7 @@ fn rust_sleep(py: Python<'_>) -> PyResult<&Bound<'_, PyAny>> {
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn my_async_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn my_async_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(rust_sleep, m)?)?;
|
m.add_function(wrap_pyfunction!(rust_sleep, m)?)
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -152,8 +150,7 @@ fn rust_sleep(py: Python<'_>) -> PyResult<&Bound<'_, PyAny>>> {
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn my_async_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn my_async_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(rust_sleep, m)?)?;
|
m.add_function(wrap_pyfunction!(rust_sleep, m)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -257,7 +254,7 @@ async def py_sleep():
|
||||||
await_coro(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
|
```rust
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
|
|
|
@ -14,8 +14,7 @@ fn double(x: usize) -> usize {
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
m.add_function(wrap_pyfunction!(double, m)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -56,8 +55,7 @@ The `#[pyo3]` attribute can be used to modify properties of the generated Python
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn module_with_functions(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn module_with_functions(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(no_args_py, m)?)?;
|
m.add_function(wrap_pyfunction!(no_args_py, m)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Python::with_gil(|py| {
|
# Python::with_gil(|py| {
|
||||||
|
@ -113,8 +111,7 @@ The `#[pyo3]` attribute can be used on individual arguments to modify properties
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
fn get_length(obj: &Bound<'_, PyAny>) -> PyResult<usize> {
|
fn get_length(obj: &Bound<'_, PyAny>) -> PyResult<usize> {
|
||||||
let length = obj.len()?;
|
obj.len()
|
||||||
Ok(length)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
|
@ -204,8 +201,7 @@ fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
x * 2
|
x * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
m.add_function(wrap_pyfunction!(double, m)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,7 @@ fn num_kwds(kwds: Option<&Bound<'_, PyDict>>) -> usize {
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn module_with_functions(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn module_with_functions(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(num_kwds, m)?).unwrap();
|
m.add_function(wrap_pyfunction!(num_kwds, m)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -159,8 +159,7 @@ fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
|
||||||
/// import the module.
|
/// import the module.
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn pyo3_example(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn pyo3_example(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(sum_as_string, m)?)?;
|
m.add_function(wrap_pyfunction!(sum_as_string, m)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,15 @@ For a detailed list of all changes, see the [CHANGELOG](changelog.md).
|
||||||
|
|
||||||
## from 0.21.* to 0.22
|
## 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
|
### Deprecation of implicit default for trailing optional arguments
|
||||||
<details open>
|
<details open>
|
||||||
<summary><small>Click to expand</small></summary>
|
<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.
|
Starting with an implementation of a Python iterator using `IterNextOutput`, e.g.
|
||||||
|
|
||||||
```rust
|
```rust,ignore
|
||||||
#![allow(deprecated)]
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::iter::IterNextOutput;
|
use pyo3::iter::IterNextOutput;
|
||||||
|
|
||||||
|
@ -529,6 +537,7 @@ assert_eq!(&*name, "list");
|
||||||
# }
|
# }
|
||||||
# Python::with_gil(example).unwrap();
|
# Python::with_gil(example).unwrap();
|
||||||
```
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
## from 0.19.* to 0.20
|
## from 0.19.* to 0.20
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,7 @@ fn double(x: usize) -> usize {
|
||||||
/// This module is implemented in Rust.
|
/// This module is implemented in Rust.
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
m.add_function(wrap_pyfunction!(double, m)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -32,11 +31,9 @@ fn double(x: usize) -> usize {
|
||||||
x * 2
|
x * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(name = "custom_name")]
|
||||||
#[pyo3(name = "custom_name")]
|
|
||||||
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn my_extension(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(double, m)?)?;
|
m.add_function(wrap_pyfunction!(double, m)?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -80,8 +77,7 @@ fn parent_module(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
fn register_child_module(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn register_child_module(parent_module: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
let child_module = PyModule::new_bound(parent_module.py(), "child_module")?;
|
let child_module = PyModule::new_bound(parent_module.py(), "child_module")?;
|
||||||
child_module.add_function(wrap_pyfunction!(func, &child_module)?)?;
|
child_module.add_function(wrap_pyfunction!(func, &child_module)?)?;
|
||||||
parent_module.add_submodule(&child_module)?;
|
parent_module.add_submodule(&child_module)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
|
@ -143,8 +139,7 @@ mod my_extension {
|
||||||
#[pymodule_init]
|
#[pymodule_init]
|
||||||
fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn init(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
// Arbitrary code to run at the module initialization
|
// Arbitrary code to run at the module initialization
|
||||||
m.add("double2", m.getattr("double")?)?;
|
m.add("double2", m.getattr("double")?)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# }
|
# }
|
||||||
|
@ -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
|
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.
|
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
|
```rust
|
||||||
# mod declarative_module_module_attr_test {
|
# mod declarative_module_module_attr_test {
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
@ -170,7 +164,7 @@ mod my_extension {
|
||||||
#[pymodule_export]
|
#[pymodule_export]
|
||||||
use super::Ext;
|
use super::Ext;
|
||||||
|
|
||||||
#[pymodule(submodule)]
|
#[pymodule]
|
||||||
mod submodule {
|
mod submodule {
|
||||||
use super::*;
|
use super::*;
|
||||||
// This is a submodule
|
// 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.
|
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 functools import lru_cache
|
||||||
from glob import glob
|
from glob import glob
|
||||||
from pathlib import Path
|
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
|
||||||
import nox.command
|
import nox.command
|
||||||
|
@ -394,8 +394,17 @@ def check_guide(session: nox.Session):
|
||||||
docs(session)
|
docs(session)
|
||||||
session.posargs.extend(posargs)
|
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 = {
|
remaps = {
|
||||||
f"file://{PYO3_GUIDE_SRC}/([^/]*/)*?%7B%7B#PYO3_DOCS_URL}}}}": f"file://{PYO3_DOCS_TARGET}",
|
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",
|
"%7B%7B#PYO3_DOCS_VERSION}}": "latest",
|
||||||
}
|
}
|
||||||
remap_args = []
|
remap_args = []
|
||||||
|
@ -416,8 +425,7 @@ def check_guide(session: nox.Session):
|
||||||
session,
|
session,
|
||||||
"lychee",
|
"lychee",
|
||||||
str(PYO3_DOCS_TARGET),
|
str(PYO3_DOCS_TARGET),
|
||||||
f"--remap=https://pyo3.rs/main/ file://{PYO3_GUIDE_TARGET}/",
|
*remap_args,
|
||||||
f"--remap=https://pyo3.rs/latest/ file://{PYO3_GUIDE_TARGET}/",
|
|
||||||
f"--exclude=file://{PYO3_DOCS_TARGET}",
|
f"--exclude=file://{PYO3_DOCS_TARGET}",
|
||||||
"--exclude=http://www.adobe.com/",
|
"--exclude=http://www.adobe.com/",
|
||||||
*session.posargs,
|
*session.posargs,
|
||||||
|
@ -543,8 +551,8 @@ def check_changelog(session: nox.Session):
|
||||||
print(fragment.name)
|
print(fragment.name)
|
||||||
|
|
||||||
|
|
||||||
@nox.session(name="set-minimal-package-versions", venv_backend="none")
|
@nox.session(name="set-msrv-package-versions", venv_backend="none")
|
||||||
def set_minimal_package_versions(session: nox.Session):
|
def set_msrv_package_versions(session: nox.Session):
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
if toml is None:
|
if toml is None:
|
||||||
|
@ -647,6 +655,14 @@ def test_version_limits(session: nox.Session):
|
||||||
config_file.set("PyPy", "3.11")
|
config_file.set("PyPy", "3.11")
|
||||||
_run_cargo(session, "check", env=env, expect_error=True)
|
_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")
|
@nox.session(name="check-feature-powerset", venv_backend="none")
|
||||||
def check_feature_powerset(session: nox.Session):
|
def check_feature_powerset(session: nox.Session):
|
||||||
|
@ -708,10 +724,14 @@ def check_feature_powerset(session: nox.Session):
|
||||||
rust_flags = env.get("RUSTFLAGS", "")
|
rust_flags = env.get("RUSTFLAGS", "")
|
||||||
env["RUSTFLAGS"] = f"{rust_flags} -Dwarnings"
|
env["RUSTFLAGS"] = f"{rust_flags} -Dwarnings"
|
||||||
|
|
||||||
|
subcommand = "hack"
|
||||||
|
if "minimal-versions" in session.posargs:
|
||||||
|
subcommand = "minimal-versions"
|
||||||
|
|
||||||
comma_join = ",".join
|
comma_join = ",".join
|
||||||
_run_cargo(
|
_run_cargo(
|
||||||
session,
|
session,
|
||||||
"hack",
|
subcommand,
|
||||||
"--feature-powerset",
|
"--feature-powerset",
|
||||||
'--optional-deps=""',
|
'--optional-deps=""',
|
||||||
f'--skip="{comma_join(features_to_skip)}"',
|
f'--skip="{comma_join(features_to_skip)}"',
|
||||||
|
@ -907,7 +927,9 @@ class _ConfigFile:
|
||||||
def __init__(self, config_file) -> None:
|
def __init__(self, config_file) -> None:
|
||||||
self._config_file = config_file
|
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."""
|
"""Set the contents of this config file to the given implementation and version."""
|
||||||
self._config_file.seek(0)
|
self._config_file.seek(0)
|
||||||
self._config_file.truncate(0)
|
self._config_file.truncate(0)
|
||||||
|
@ -915,6 +937,7 @@ class _ConfigFile:
|
||||||
f"""\
|
f"""\
|
||||||
implementation={implementation}
|
implementation={implementation}
|
||||||
version={version}
|
version={version}
|
||||||
|
build_flags={','.join(build_flags)}
|
||||||
suppress_build_script_link_lines=true
|
suppress_build_script_link_lines=true
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3-build-config"
|
name = "pyo3-build-config"
|
||||||
version = "0.22.1"
|
version = "0.23.0-dev"
|
||||||
description = "Build configuration for the PyO3 ecosystem"
|
description = "Build configuration for the PyO3 ecosystem"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
|
|
@ -996,6 +996,7 @@ pub enum BuildFlag {
|
||||||
Py_DEBUG,
|
Py_DEBUG,
|
||||||
Py_REF_DEBUG,
|
Py_REF_DEBUG,
|
||||||
Py_TRACE_REFS,
|
Py_TRACE_REFS,
|
||||||
|
Py_GIL_DISABLED,
|
||||||
COUNT_ALLOCS,
|
COUNT_ALLOCS,
|
||||||
Other(String),
|
Other(String),
|
||||||
}
|
}
|
||||||
|
@ -1016,6 +1017,7 @@ impl FromStr for BuildFlag {
|
||||||
"Py_DEBUG" => Ok(BuildFlag::Py_DEBUG),
|
"Py_DEBUG" => Ok(BuildFlag::Py_DEBUG),
|
||||||
"Py_REF_DEBUG" => Ok(BuildFlag::Py_REF_DEBUG),
|
"Py_REF_DEBUG" => Ok(BuildFlag::Py_REF_DEBUG),
|
||||||
"Py_TRACE_REFS" => Ok(BuildFlag::Py_TRACE_REFS),
|
"Py_TRACE_REFS" => Ok(BuildFlag::Py_TRACE_REFS),
|
||||||
|
"Py_GIL_DISABLED" => Ok(BuildFlag::Py_GIL_DISABLED),
|
||||||
"COUNT_ALLOCS" => Ok(BuildFlag::COUNT_ALLOCS),
|
"COUNT_ALLOCS" => Ok(BuildFlag::COUNT_ALLOCS),
|
||||||
other => Ok(BuildFlag::Other(other.to_owned())),
|
other => Ok(BuildFlag::Other(other.to_owned())),
|
||||||
}
|
}
|
||||||
|
@ -1039,10 +1041,11 @@ impl FromStr for BuildFlag {
|
||||||
pub struct BuildFlags(pub HashSet<BuildFlag>);
|
pub struct BuildFlags(pub HashSet<BuildFlag>);
|
||||||
|
|
||||||
impl BuildFlags {
|
impl BuildFlags {
|
||||||
const ALL: [BuildFlag; 4] = [
|
const ALL: [BuildFlag; 5] = [
|
||||||
BuildFlag::Py_DEBUG,
|
BuildFlag::Py_DEBUG,
|
||||||
BuildFlag::Py_REF_DEBUG,
|
BuildFlag::Py_REF_DEBUG,
|
||||||
BuildFlag::Py_TRACE_REFS,
|
BuildFlag::Py_TRACE_REFS,
|
||||||
|
BuildFlag::Py_GIL_DISABLED,
|
||||||
BuildFlag::COUNT_ALLOCS,
|
BuildFlag::COUNT_ALLOCS,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,9 @@ use target_lexicon::OperatingSystem;
|
||||||
/// | `#[cfg(PyPy)]` | This marks code which is run when compiling for PyPy. |
|
/// | `#[cfg(PyPy)]` | This marks code which is run when compiling for PyPy. |
|
||||||
/// | `#[cfg(GraalPy)]` | This marks code which is run when compiling for GraalPy. |
|
/// | `#[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")]
|
#[cfg(feature = "resolve-config")]
|
||||||
pub fn use_pyo3_cfgs() {
|
pub fn use_pyo3_cfgs() {
|
||||||
print_expected_cfgs();
|
print_expected_cfgs();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3-ffi"
|
name = "pyo3-ffi"
|
||||||
version = "0.22.1"
|
version = "0.23.0-dev"
|
||||||
description = "Python-API bindings for the PyO3 ecosystem"
|
description = "Python-API bindings for the PyO3 ecosystem"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
@ -38,7 +38,7 @@ abi3-py312 = ["abi3", "pyo3-build-config/abi3-py312"]
|
||||||
generate-import-lib = ["pyo3-build-config/python3-dll-a"]
|
generate-import-lib = ["pyo3-build-config/python3-dll-a"]
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.22.1", features = ["resolve-config"] }
|
pyo3-build-config = { path = "../pyo3-build-config", version = "=0.23.0-dev", features = ["resolve-config"] }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -4,8 +4,9 @@ use pyo3_build_config::{
|
||||||
cargo_env_var, env_var, errors::Result, is_linking_libpython, resolve_interpreter_config,
|
cargo_env_var, env_var, errors::Result, is_linking_libpython, resolve_interpreter_config,
|
||||||
InterpreterConfig, PythonVersion,
|
InterpreterConfig, PythonVersion,
|
||||||
},
|
},
|
||||||
warn, PythonImplementation,
|
warn, BuildFlag, PythonImplementation,
|
||||||
};
|
};
|
||||||
|
use std::ops::Not;
|
||||||
|
|
||||||
/// Minimum Python version PyO3 supports.
|
/// Minimum Python version PyO3 supports.
|
||||||
struct SupportedVersions {
|
struct SupportedVersions {
|
||||||
|
@ -120,6 +121,24 @@ fn ensure_python_version(interpreter_config: &InterpreterConfig) -> Result<()> {
|
||||||
Ok(())
|
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<()> {
|
fn ensure_target_pointer_width(interpreter_config: &InterpreterConfig) -> Result<()> {
|
||||||
if let Some(pointer_width) = interpreter_config.pointer_width {
|
if let Some(pointer_width) = interpreter_config.pointer_width {
|
||||||
// Try to check whether the target architecture matches the python library
|
// 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_python_version(&interpreter_config)?;
|
||||||
ensure_target_pointer_width(&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.
|
// Serialize the whole interpreter config into DEP_PYTHON_PYO3_CONFIG env var.
|
||||||
interpreter_config.to_cargo_dep_env()?;
|
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"
|
//! [`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
|
//! [`pyo3-build-config`]: https://docs.rs/pyo3-build-config
|
||||||
//! [feature flags]: https://doc.rust-lang.org/cargo/reference/features.html "Features - The Cargo Book"
|
//! [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"
|
//! [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"
|
//! [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(
|
#![allow(
|
||||||
missing_docs,
|
missing_docs,
|
||||||
non_camel_case_types,
|
non_camel_case_types,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3-macros-backend"
|
name = "pyo3-macros-backend"
|
||||||
version = "0.22.1"
|
version = "0.23.0-dev"
|
||||||
description = "Code generation for PyO3 package"
|
description = "Code generation for PyO3 package"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
@ -16,7 +16,7 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
heck = "0.5"
|
heck = "0.5"
|
||||||
proc-macro2 = { version = "1.0.60", default-features = false }
|
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 }
|
quote = { version = "1", default-features = false }
|
||||||
|
|
||||||
[dependencies.syn]
|
[dependencies.syn]
|
||||||
|
@ -25,7 +25,7 @@ default-features = false
|
||||||
features = ["derive", "parsing", "printing", "clone-impls", "full", "extra-traits"]
|
features = ["derive", "parsing", "printing", "clone-impls", "full", "extra-traits"]
|
||||||
|
|
||||||
[build-dependencies]
|
[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]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -1,53 +1,6 @@
|
||||||
use crate::{
|
use crate::method::{FnArg, FnSpec};
|
||||||
method::{FnArg, FnSpec},
|
use proc_macro2::TokenStream;
|
||||||
utils::Ctx,
|
use quote::quote_spanned;
|
||||||
};
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn deprecate_trailing_option_default(spec: &FnSpec<'_>) -> TokenStream {
|
pub(crate) fn deprecate_trailing_option_default(spec: &FnSpec<'_>) -> TokenStream {
|
||||||
if spec.signature.attribute.is_none()
|
if spec.signature.attribute.is_none()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use crate::attributes::{self, get_pyo3_options, CrateAttribute, FromPyWithAttribute};
|
use crate::attributes::{self, get_pyo3_options, CrateAttribute, FromPyWithAttribute};
|
||||||
use crate::utils::Ctx;
|
use crate::utils::Ctx;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use quote::{format_ident, quote, quote_spanned};
|
use quote::{format_ident, quote};
|
||||||
use syn::{
|
use syn::{
|
||||||
parenthesized,
|
parenthesized,
|
||||||
parse::{Parse, ParseStream},
|
parse::{Parse, ParseStream},
|
||||||
|
@ -44,16 +44,14 @@ impl<'a> Enum<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build derivation body for enums.
|
/// Build derivation body for enums.
|
||||||
fn build(&self, ctx: &Ctx) -> (TokenStream, TokenStream) {
|
fn build(&self, ctx: &Ctx) -> TokenStream {
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let mut var_extracts = Vec::new();
|
let mut var_extracts = Vec::new();
|
||||||
let mut variant_names = Vec::new();
|
let mut variant_names = Vec::new();
|
||||||
let mut error_names = Vec::new();
|
let mut error_names = Vec::new();
|
||||||
|
|
||||||
let mut deprecations = TokenStream::new();
|
|
||||||
for var in &self.variants {
|
for var in &self.variants {
|
||||||
let (struct_derive, dep) = var.build(ctx);
|
let struct_derive = var.build(ctx);
|
||||||
deprecations.extend(dep);
|
|
||||||
let ext = quote!({
|
let ext = quote!({
|
||||||
let maybe_ret = || -> #pyo3_path::PyResult<Self> {
|
let maybe_ret = || -> #pyo3_path::PyResult<Self> {
|
||||||
#struct_derive
|
#struct_derive
|
||||||
|
@ -70,7 +68,6 @@ impl<'a> Enum<'a> {
|
||||||
error_names.push(&var.err_name);
|
error_names.push(&var.err_name);
|
||||||
}
|
}
|
||||||
let ty_name = self.enum_ident.to_string();
|
let ty_name = self.enum_ident.to_string();
|
||||||
(
|
|
||||||
quote!(
|
quote!(
|
||||||
let errors = [
|
let errors = [
|
||||||
#(#var_extracts),*
|
#(#var_extracts),*
|
||||||
|
@ -84,8 +81,6 @@ impl<'a> Enum<'a> {
|
||||||
&errors
|
&errors
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
|
||||||
deprecations,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -244,7 +239,7 @@ impl<'a> Container<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build derivation body for a struct.
|
/// Build derivation body for a struct.
|
||||||
fn build(&self, ctx: &Ctx) -> (TokenStream, TokenStream) {
|
fn build(&self, ctx: &Ctx) -> TokenStream {
|
||||||
match &self.ty {
|
match &self.ty {
|
||||||
ContainerType::StructNewtype(ident, from_py_with) => {
|
ContainerType::StructNewtype(ident, from_py_with) => {
|
||||||
self.build_newtype_struct(Some(ident), from_py_with, ctx)
|
self.build_newtype_struct(Some(ident), from_py_with, ctx)
|
||||||
|
@ -262,73 +257,42 @@ impl<'a> Container<'a> {
|
||||||
field_ident: Option<&Ident>,
|
field_ident: Option<&Ident>,
|
||||||
from_py_with: &Option<FromPyWithAttribute>,
|
from_py_with: &Option<FromPyWithAttribute>,
|
||||||
ctx: &Ctx,
|
ctx: &Ctx,
|
||||||
) -> (TokenStream, TokenStream) {
|
) -> TokenStream {
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let self_ty = &self.path;
|
let self_ty = &self.path;
|
||||||
let struct_name = self.name();
|
let struct_name = self.name();
|
||||||
if let Some(ident) = field_ident {
|
if let Some(ident) = field_ident {
|
||||||
let field_name = ident.to_string();
|
let field_name = ident.to_string();
|
||||||
match from_py_with {
|
match from_py_with {
|
||||||
None => (
|
None => quote! {
|
||||||
quote! {
|
|
||||||
Ok(#self_ty {
|
Ok(#self_ty {
|
||||||
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field(obj, #struct_name, #field_name)?
|
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field(obj, #struct_name, #field_name)?
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
TokenStream::new(),
|
|
||||||
),
|
|
||||||
Some(FromPyWithAttribute {
|
Some(FromPyWithAttribute {
|
||||||
value: expr_path, ..
|
value: expr_path, ..
|
||||||
}) => (
|
}) => quote! {
|
||||||
quote! {
|
|
||||||
Ok(#self_ty {
|
Ok(#self_ty {
|
||||||
#ident: #pyo3_path::impl_::frompyobject::extract_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, #field_name)?
|
#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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match from_py_with {
|
match from_py_with {
|
||||||
None => (
|
None => quote! {
|
||||||
quote!(
|
|
||||||
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field(obj, #struct_name, 0).map(#self_ty)
|
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field(obj, #struct_name, 0).map(#self_ty)
|
||||||
),
|
},
|
||||||
TokenStream::new(),
|
|
||||||
),
|
|
||||||
Some(FromPyWithAttribute {
|
Some(FromPyWithAttribute {
|
||||||
value: expr_path, ..
|
value: expr_path, ..
|
||||||
}) => (
|
}) => quote! {
|
||||||
quote! (
|
|
||||||
#pyo3_path::impl_::frompyobject::extract_tuple_struct_field_with(#expr_path as fn(_) -> _, obj, #struct_name, 0).map(#self_ty)
|
#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();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_tuple_struct(
|
fn build_tuple_struct(&self, struct_fields: &[TupleStructField], ctx: &Ctx) -> TokenStream {
|
||||||
&self,
|
|
||||||
struct_fields: &[TupleStructField],
|
|
||||||
ctx: &Ctx,
|
|
||||||
) -> (TokenStream, TokenStream) {
|
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let self_ty = &self.path;
|
let self_ty = &self.path;
|
||||||
let struct_name = &self.name();
|
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!(
|
quote!(
|
||||||
match #pyo3_path::types::PyAnyMethods::extract(obj) {
|
match #pyo3_path::types::PyAnyMethods::extract(obj) {
|
||||||
::std::result::Result::Ok((#(#field_idents),*)) => ::std::result::Result::Ok(#self_ty(#(#fields),*)),
|
::std::result::Result::Ok((#(#field_idents),*)) => ::std::result::Result::Ok(#self_ty(#(#fields),*)),
|
||||||
::std::result::Result::Err(err) => ::std::result::Result::Err(err),
|
::std::result::Result::Err(err) => ::std::result::Result::Err(err),
|
||||||
}
|
}
|
||||||
),
|
|
||||||
deprecations,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_struct(
|
fn build_struct(&self, struct_fields: &[NamedStructField<'_>], ctx: &Ctx) -> TokenStream {
|
||||||
&self,
|
|
||||||
struct_fields: &[NamedStructField<'_>],
|
|
||||||
ctx: &Ctx,
|
|
||||||
) -> (TokenStream, TokenStream) {
|
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let self_ty = &self.path;
|
let self_ty = &self.path;
|
||||||
let struct_name = &self.name();
|
let struct_name = &self.name();
|
||||||
|
@ -420,28 +359,7 @@ impl<'a> Container<'a> {
|
||||||
fields.push(quote!(#ident: #extractor));
|
fields.push(quote!(#ident: #extractor));
|
||||||
}
|
}
|
||||||
|
|
||||||
let deprecations = struct_fields
|
quote!(::std::result::Result::Ok(#self_ty{#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,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -673,7 +591,7 @@ pub fn build_derive_from_pyobject(tokens: &DeriveInput) -> Result<TokenStream> {
|
||||||
let ctx = &Ctx::new(&options.krate, None);
|
let ctx = &Ctx::new(&options.krate, None);
|
||||||
let Ctx { pyo3_path, .. } = &ctx;
|
let Ctx { pyo3_path, .. } = &ctx;
|
||||||
|
|
||||||
let (derives, from_py_with_deprecations) = match &tokens.data {
|
let derives = match &tokens.data {
|
||||||
syn::Data::Enum(en) => {
|
syn::Data::Enum(en) => {
|
||||||
if options.transparent || options.annotation.is_some() {
|
if options.transparent || options.annotation.is_some() {
|
||||||
bail_spanned!(tokens.span() => "`transparent` or `annotation` is not supported \
|
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
|
#derives
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#from_py_with_deprecations
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
|
||||||
|
use crate::attributes::{self, get_pyo3_options, take_attributes, NameAttribute};
|
||||||
use crate::utils::{Ctx, LitCStr};
|
use crate::utils::{Ctx, LitCStr};
|
||||||
use crate::{
|
|
||||||
attributes::{self, get_pyo3_options, take_attributes, NameAttribute},
|
|
||||||
deprecations::Deprecations,
|
|
||||||
};
|
|
||||||
use proc_macro2::{Ident, Span};
|
use proc_macro2::{Ident, Span};
|
||||||
use syn::{
|
use syn::{
|
||||||
ext::IdentExt,
|
ext::IdentExt,
|
||||||
|
@ -14,12 +11,12 @@ use syn::{
|
||||||
Result,
|
Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ConstSpec<'ctx> {
|
pub struct ConstSpec {
|
||||||
pub rust_ident: syn::Ident,
|
pub rust_ident: syn::Ident,
|
||||||
pub attributes: ConstAttributes<'ctx>,
|
pub attributes: ConstAttributes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstSpec<'_> {
|
impl ConstSpec {
|
||||||
pub fn python_name(&self) -> Cow<'_, Ident> {
|
pub fn python_name(&self) -> Cow<'_, Ident> {
|
||||||
if let Some(name) = &self.attributes.name {
|
if let Some(name) = &self.attributes.name {
|
||||||
Cow::Borrowed(&name.value.0)
|
Cow::Borrowed(&name.value.0)
|
||||||
|
@ -35,10 +32,9 @@ impl ConstSpec<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ConstAttributes<'ctx> {
|
pub struct ConstAttributes {
|
||||||
pub is_class_attr: bool,
|
pub is_class_attr: bool,
|
||||||
pub name: Option<NameAttribute>,
|
pub name: Option<NameAttribute>,
|
||||||
pub deprecations: Deprecations<'ctx>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum PyO3ConstAttribute {
|
pub enum PyO3ConstAttribute {
|
||||||
|
@ -56,12 +52,11 @@ impl Parse for PyO3ConstAttribute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> ConstAttributes<'ctx> {
|
impl ConstAttributes {
|
||||||
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>, ctx: &'ctx Ctx) -> syn::Result<Self> {
|
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>) -> syn::Result<Self> {
|
||||||
let mut attributes = ConstAttributes {
|
let mut attributes = ConstAttributes {
|
||||||
is_class_attr: false,
|
is_class_attr: false,
|
||||||
name: None,
|
name: None,
|
||||||
deprecations: Deprecations::new(ctx),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
take_attributes(attrs, |attr| {
|
take_attributes(attrs, |attr| {
|
||||||
|
|
|
@ -10,7 +10,6 @@ use crate::deprecations::deprecate_trailing_option_default;
|
||||||
use crate::utils::{Ctx, LitCStr};
|
use crate::utils::{Ctx, LitCStr};
|
||||||
use crate::{
|
use crate::{
|
||||||
attributes::{FromPyWithAttribute, TextSignatureAttribute, TextSignatureAttributeValue},
|
attributes::{FromPyWithAttribute, TextSignatureAttribute, TextSignatureAttributeValue},
|
||||||
deprecations::{Deprecation, Deprecations},
|
|
||||||
params::{impl_arg_params, Holders},
|
params::{impl_arg_params, Holders},
|
||||||
pyfunction::{
|
pyfunction::{
|
||||||
FunctionSignature, PyFunctionArgPyO3Attributes, PyFunctionOptions, SignatureAttribute,
|
FunctionSignature, PyFunctionArgPyO3Attributes, PyFunctionOptions, SignatureAttribute,
|
||||||
|
@ -411,7 +410,6 @@ pub struct FnSpec<'a> {
|
||||||
pub text_signature: Option<TextSignatureAttribute>,
|
pub text_signature: Option<TextSignatureAttribute>,
|
||||||
pub asyncness: Option<syn::Token![async]>,
|
pub asyncness: Option<syn::Token![async]>,
|
||||||
pub unsafety: Option<syn::Token![unsafe]>,
|
pub unsafety: Option<syn::Token![unsafe]>,
|
||||||
pub deprecations: Deprecations<'a>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_method_receiver(arg: &syn::FnArg) -> Result<SelfType> {
|
pub fn parse_method_receiver(arg: &syn::FnArg) -> Result<SelfType> {
|
||||||
|
@ -443,7 +441,6 @@ impl<'a> FnSpec<'a> {
|
||||||
sig: &'a mut syn::Signature,
|
sig: &'a mut syn::Signature,
|
||||||
meth_attrs: &mut Vec<syn::Attribute>,
|
meth_attrs: &mut Vec<syn::Attribute>,
|
||||||
options: PyFunctionOptions,
|
options: PyFunctionOptions,
|
||||||
ctx: &'a Ctx,
|
|
||||||
) -> Result<FnSpec<'a>> {
|
) -> Result<FnSpec<'a>> {
|
||||||
let PyFunctionOptions {
|
let PyFunctionOptions {
|
||||||
text_signature,
|
text_signature,
|
||||||
|
@ -453,9 +450,8 @@ impl<'a> FnSpec<'a> {
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
let mut python_name = name.map(|name| name.value.0);
|
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())?;
|
ensure_signatures_on_valid_method(&fn_type, signature.as_ref(), text_signature.as_ref())?;
|
||||||
|
|
||||||
let name = &sig.ident;
|
let name = &sig.ident;
|
||||||
|
@ -493,7 +489,6 @@ impl<'a> FnSpec<'a> {
|
||||||
text_signature,
|
text_signature,
|
||||||
asyncness: sig.asyncness,
|
asyncness: sig.asyncness,
|
||||||
unsafety: sig.unsafety,
|
unsafety: sig.unsafety,
|
||||||
deprecations,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,9 +502,8 @@ impl<'a> FnSpec<'a> {
|
||||||
sig: &syn::Signature,
|
sig: &syn::Signature,
|
||||||
meth_attrs: &mut Vec<syn::Attribute>,
|
meth_attrs: &mut Vec<syn::Attribute>,
|
||||||
python_name: &mut Option<syn::Ident>,
|
python_name: &mut Option<syn::Ident>,
|
||||||
deprecations: &mut Deprecations<'_>,
|
|
||||||
) -> Result<FnType> {
|
) -> 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 name = &sig.ident;
|
||||||
let parse_receiver = |msg: &'static str| {
|
let parse_receiver = |msg: &'static str| {
|
||||||
|
@ -683,11 +677,10 @@ impl<'a> FnSpec<'a> {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(self_arg) = self_arg() {
|
if let Some(self_arg) = self_arg() {
|
||||||
let self_checker = holders.push_gil_refs_checker(self_arg.span());
|
|
||||||
quote! {
|
quote! {
|
||||||
function(
|
function(
|
||||||
// NB #self_arg includes a comma, so none inserted here
|
// NB #self_arg includes a comma, so none inserted here
|
||||||
#pyo3_path::impl_::deprecations::inspect_type(#self_arg &#self_checker),
|
#self_arg
|
||||||
#(#args),*
|
#(#args),*
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -714,11 +707,10 @@ impl<'a> FnSpec<'a> {
|
||||||
}
|
}
|
||||||
call
|
call
|
||||||
} else if let Some(self_arg) = self_arg() {
|
} else if let Some(self_arg) = self_arg() {
|
||||||
let self_checker = holders.push_gil_refs_checker(self_arg.span());
|
|
||||||
quote! {
|
quote! {
|
||||||
function(
|
function(
|
||||||
// NB #self_arg includes a comma, so none inserted here
|
// NB #self_arg includes a comma, so none inserted here
|
||||||
#pyo3_path::impl_::deprecations::inspect_type(#self_arg &#self_checker),
|
#self_arg
|
||||||
#(#args),*
|
#(#args),*
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -762,7 +754,6 @@ impl<'a> FnSpec<'a> {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
let call = rust_call(args, &mut holders);
|
let call = rust_call(args, &mut holders);
|
||||||
let check_gil_refs = holders.check_gil_refs();
|
|
||||||
let init_holders = holders.init_holders(ctx);
|
let init_holders = holders.init_holders(ctx);
|
||||||
quote! {
|
quote! {
|
||||||
unsafe fn #ident<'py>(
|
unsafe fn #ident<'py>(
|
||||||
|
@ -774,7 +765,6 @@ impl<'a> FnSpec<'a> {
|
||||||
let function = #rust_name; // Shadow the function name to avoid #3017
|
let function = #rust_name; // Shadow the function name to avoid #3017
|
||||||
#init_holders
|
#init_holders
|
||||||
let result = #call;
|
let result = #call;
|
||||||
#check_gil_refs
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -784,7 +774,6 @@ impl<'a> FnSpec<'a> {
|
||||||
let (arg_convert, args) = impl_arg_params(self, cls, true, &mut holders, ctx);
|
let (arg_convert, args) = impl_arg_params(self, cls, true, &mut holders, ctx);
|
||||||
let call = rust_call(args, &mut holders);
|
let call = rust_call(args, &mut holders);
|
||||||
let init_holders = holders.init_holders(ctx);
|
let init_holders = holders.init_holders(ctx);
|
||||||
let check_gil_refs = holders.check_gil_refs();
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
unsafe fn #ident<'py>(
|
unsafe fn #ident<'py>(
|
||||||
|
@ -800,7 +789,6 @@ impl<'a> FnSpec<'a> {
|
||||||
#arg_convert
|
#arg_convert
|
||||||
#init_holders
|
#init_holders
|
||||||
let result = #call;
|
let result = #call;
|
||||||
#check_gil_refs
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -810,7 +798,6 @@ impl<'a> FnSpec<'a> {
|
||||||
let (arg_convert, args) = impl_arg_params(self, cls, false, &mut holders, ctx);
|
let (arg_convert, args) = impl_arg_params(self, cls, false, &mut holders, ctx);
|
||||||
let call = rust_call(args, &mut holders);
|
let call = rust_call(args, &mut holders);
|
||||||
let init_holders = holders.init_holders(ctx);
|
let init_holders = holders.init_holders(ctx);
|
||||||
let check_gil_refs = holders.check_gil_refs();
|
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
unsafe fn #ident<'py>(
|
unsafe fn #ident<'py>(
|
||||||
|
@ -825,7 +812,6 @@ impl<'a> FnSpec<'a> {
|
||||||
#arg_convert
|
#arg_convert
|
||||||
#init_holders
|
#init_holders
|
||||||
let result = #call;
|
let result = #call;
|
||||||
#check_gil_refs
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -838,7 +824,6 @@ impl<'a> FnSpec<'a> {
|
||||||
.self_arg(cls, ExtractErrorMode::Raise, &mut holders, ctx);
|
.self_arg(cls, ExtractErrorMode::Raise, &mut holders, ctx);
|
||||||
let call = quote_spanned! {*output_span=> #rust_name(#self_arg #(#args),*) };
|
let call = quote_spanned! {*output_span=> #rust_name(#self_arg #(#args),*) };
|
||||||
let init_holders = holders.init_holders(ctx);
|
let init_holders = holders.init_holders(ctx);
|
||||||
let check_gil_refs = holders.check_gil_refs();
|
|
||||||
quote! {
|
quote! {
|
||||||
unsafe fn #ident(
|
unsafe fn #ident(
|
||||||
py: #pyo3_path::Python<'_>,
|
py: #pyo3_path::Python<'_>,
|
||||||
|
@ -854,7 +839,6 @@ impl<'a> FnSpec<'a> {
|
||||||
#init_holders
|
#init_holders
|
||||||
let result = #call;
|
let result = #call;
|
||||||
let initializer: #pyo3_path::PyClassInitializer::<#cls> = result.convert(py)?;
|
let initializer: #pyo3_path::PyClassInitializer::<#cls> = result.convert(py)?;
|
||||||
#check_gil_refs
|
|
||||||
#pyo3_path::impl_::pymethods::tp_new_impl(py, initializer, _slf)
|
#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)`.
|
/// If the attribute does not match one of the attribute names, returns `Ok(None)`.
|
||||||
///
|
///
|
||||||
/// Otherwise will either return a parse error or the attribute.
|
/// Otherwise will either return a parse error or the attribute.
|
||||||
fn parse_if_matching_attribute(
|
fn parse_if_matching_attribute(attr: &syn::Attribute) -> Result<Option<Self>> {
|
||||||
attr: &syn::Attribute,
|
|
||||||
deprecations: &mut Deprecations<'_>,
|
|
||||||
) -> Result<Option<Self>> {
|
|
||||||
fn ensure_no_arguments(meta: &syn::Meta, ident: &str) -> syn::Result<()> {
|
fn ensure_no_arguments(meta: &syn::Meta, ident: &str) -> syn::Result<()> {
|
||||||
match meta {
|
match meta {
|
||||||
syn::Meta::Path(_) => Ok(()),
|
syn::Meta::Path(_) => Ok(()),
|
||||||
|
@ -1039,11 +1020,6 @@ impl MethodTypeAttribute {
|
||||||
if path.is_ident("new") {
|
if path.is_ident("new") {
|
||||||
ensure_no_arguments(meta, "new")?;
|
ensure_no_arguments(meta, "new")?;
|
||||||
Ok(Some(MethodTypeAttribute::New(path.span())))
|
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") {
|
} else if path.is_ident("classmethod") {
|
||||||
ensure_no_arguments(meta, "classmethod")?;
|
ensure_no_arguments(meta, "classmethod")?;
|
||||||
Ok(Some(MethodTypeAttribute::ClassMethod(path.span())))
|
Ok(Some(MethodTypeAttribute::ClassMethod(path.span())))
|
||||||
|
@ -1078,15 +1054,12 @@ impl Display for MethodTypeAttribute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_method_attributes(
|
fn parse_method_attributes(attrs: &mut Vec<syn::Attribute>) -> Result<Vec<MethodTypeAttribute>> {
|
||||||
attrs: &mut Vec<syn::Attribute>,
|
|
||||||
deprecations: &mut Deprecations<'_>,
|
|
||||||
) -> Result<Vec<MethodTypeAttribute>> {
|
|
||||||
let mut new_attrs = Vec::new();
|
let mut new_attrs = Vec::new();
|
||||||
let mut found_attrs = Vec::new();
|
let mut found_attrs = Vec::new();
|
||||||
|
|
||||||
for attr in attrs.drain(..) {
|
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),
|
Some(attr) => found_attrs.push(attr),
|
||||||
None => new_attrs.push(attr),
|
None => new_attrs.push(attr),
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
attributes::{
|
attributes::{
|
||||||
self, take_attributes, take_pyo3_options, CrateAttribute, ModuleAttribute, NameAttribute,
|
self, kw, take_attributes, take_pyo3_options, CrateAttribute, ModuleAttribute,
|
||||||
SubmoduleAttribute,
|
NameAttribute, SubmoduleAttribute,
|
||||||
},
|
},
|
||||||
get_doc,
|
get_doc,
|
||||||
pyclass::PyClassPyO3Option,
|
pyclass::PyClassPyO3Option,
|
||||||
|
@ -26,97 +26,88 @@ use syn::{
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct PyModuleOptions {
|
pub struct PyModuleOptions {
|
||||||
krate: Option<CrateAttribute>,
|
krate: Option<CrateAttribute>,
|
||||||
name: Option<syn::Ident>,
|
name: Option<NameAttribute>,
|
||||||
module: Option<ModuleAttribute>,
|
module: Option<ModuleAttribute>,
|
||||||
is_submodule: bool,
|
submodule: Option<kw::submodule>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PyModuleOptions {
|
impl Parse for PyModuleOptions {
|
||||||
pub fn from_attrs(attrs: &mut Vec<syn::Attribute>) -> Result<Self> {
|
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
|
||||||
let mut options: PyModuleOptions = Default::default();
|
let mut options: PyModuleOptions = Default::default();
|
||||||
|
|
||||||
for option in take_pyo3_options(attrs)? {
|
options.add_attributes(
|
||||||
match option {
|
Punctuated::<PyModulePyO3Option, syn::Token![,]>::parse_terminated(input)?,
|
||||||
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)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(options)
|
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(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_crate(&mut self, path: CrateAttribute) -> Result<()> {
|
impl PyModuleOptions {
|
||||||
ensure_spanned!(
|
fn take_pyo3_options(&mut self, attrs: &mut Vec<syn::Attribute>) -> Result<()> {
|
||||||
self.krate.is_none(),
|
self.add_attributes(take_pyo3_options(attrs)?)
|
||||||
path.span() => "`crate` may only be specified once"
|
|
||||||
);
|
|
||||||
|
|
||||||
self.krate = Some(path);
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_module(&mut self, name: ModuleAttribute) -> Result<()> {
|
fn add_attributes(
|
||||||
|
&mut self,
|
||||||
|
attrs: impl IntoIterator<Item = PyModulePyO3Option>,
|
||||||
|
) -> Result<()> {
|
||||||
|
macro_rules! set_option {
|
||||||
|
($key:ident $(, $extra:literal)?) => {
|
||||||
|
{
|
||||||
ensure_spanned!(
|
ensure_spanned!(
|
||||||
self.module.is_none(),
|
self.$key.is_none(),
|
||||||
name.span() => "`module` may only be specified once"
|
$key.span() => concat!("`", stringify!($key), "` may only be specified once" $(, $extra)?)
|
||||||
);
|
);
|
||||||
|
self.$key = Some($key);
|
||||||
self.module = Some(name);
|
}
|
||||||
Ok(())
|
};
|
||||||
|
}
|
||||||
|
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)"
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pymodule_module_impl(
|
pub fn pymodule_module_impl(
|
||||||
mut module: syn::ItemMod,
|
module: &mut syn::ItemMod,
|
||||||
mut is_submodule: bool,
|
mut options: PyModuleOptions,
|
||||||
) -> Result<TokenStream> {
|
) -> Result<TokenStream> {
|
||||||
let syn::ItemMod {
|
let syn::ItemMod {
|
||||||
attrs,
|
attrs,
|
||||||
vis,
|
vis,
|
||||||
unsafety: _,
|
unsafety: _,
|
||||||
ident,
|
ident,
|
||||||
mod_token: _,
|
mod_token,
|
||||||
content,
|
content,
|
||||||
semi: _,
|
semi: _,
|
||||||
} = &mut module;
|
} = module;
|
||||||
let items = if let Some((_, items)) = content {
|
let items = if let Some((_, items)) = content {
|
||||||
items
|
items
|
||||||
} else {
|
} 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 = &Ctx::new(&options.krate, None);
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let doc = get_doc(attrs, None, 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 {
|
let full_name = if let Some(module) = &options.module {
|
||||||
format!("{}.{}", module.value.value(), name)
|
format!("{}.{}", module.value.value(), name)
|
||||||
} else {
|
} else {
|
||||||
name.to_string()
|
name.to_string()
|
||||||
};
|
};
|
||||||
is_submodule = is_submodule || options.is_submodule;
|
|
||||||
|
|
||||||
let mut module_items = Vec::new();
|
let mut module_items = Vec::new();
|
||||||
let mut module_items_cfg_attrs = 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);
|
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) => {
|
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!(
|
Ok(quote!(
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#vis mod #ident {
|
#vis #mod_token #ident {
|
||||||
#(#items)*
|
#(#items)*
|
||||||
|
|
||||||
#initialization
|
#initialization
|
||||||
|
@ -365,7 +360,7 @@ pub fn pymodule_module_impl(
|
||||||
#module_items::_PYO3_DEF.add_to_module(module)?;
|
#module_items::_PYO3_DEF.add_to_module(module)?;
|
||||||
)*
|
)*
|
||||||
#pymodule_init
|
#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
|
/// Generates the function that is called by the python interpreter to initialize the native
|
||||||
/// module
|
/// module
|
||||||
pub fn pymodule_function_impl(mut function: syn::ItemFn) -> Result<TokenStream> {
|
pub fn pymodule_function_impl(
|
||||||
let options = PyModuleOptions::from_attrs(&mut function.attrs)?;
|
function: &mut syn::ItemFn,
|
||||||
process_functions_in_module(&options, &mut function)?;
|
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 ctx = &Ctx::new(&options.krate, None);
|
||||||
let stmts = std::mem::take(&mut function.block.stmts);
|
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let ident = &function.sig.ident;
|
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 vis = &function.vis;
|
||||||
let doc = get_doc(&function.attrs, None, ctx);
|
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
|
module_args
|
||||||
.push(quote!(::std::convert::Into::into(#pyo3_path::impl_::pymethods::BoundRef(module))));
|
.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! {
|
Ok(quote! {
|
||||||
#function
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
#vis mod #ident {
|
#vis mod #ident {
|
||||||
#initialization
|
#initialization
|
||||||
|
|
|
@ -10,14 +10,12 @@ use syn::spanned::Spanned;
|
||||||
|
|
||||||
pub struct Holders {
|
pub struct Holders {
|
||||||
holders: Vec<syn::Ident>,
|
holders: Vec<syn::Ident>,
|
||||||
gil_refs_checkers: Vec<GilRefChecker>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Holders {
|
impl Holders {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Holders {
|
Holders {
|
||||||
holders: Vec::new(),
|
holders: Vec::new(),
|
||||||
gil_refs_checkers: Vec::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,58 +25,14 @@ impl Holders {
|
||||||
holder
|
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 {
|
pub fn init_holders(&self, ctx: &Ctx) -> TokenStream {
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let holders = &self.holders;
|
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! {
|
quote! {
|
||||||
#[allow(clippy::let_unit_value)]
|
#[allow(clippy::let_unit_value)]
|
||||||
#(let mut #holders = #pyo3_path::impl_::extract_argument::FunctionArgumentHolder::INIT;)*
|
#(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).
|
/// 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(
|
pub fn impl_arg_params(
|
||||||
spec: &FnSpec<'_>,
|
spec: &FnSpec<'_>,
|
||||||
self_: Option<&syn::Type>,
|
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 = &arg.from_py_with()?.value;
|
||||||
let from_py_with_holder = format_ident!("from_py_with_{}", i);
|
let from_py_with_holder = format_ident!("from_py_with_{}", i);
|
||||||
Some(quote_spanned! { from_py_with.span() =>
|
Some(quote_spanned! { from_py_with.span() =>
|
||||||
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
let #from_py_with_holder = #from_py_with;
|
||||||
let #from_py_with_holder = #pyo3_path::impl_::deprecations::inspect_fn(#from_py_with, &e);
|
|
||||||
e.from_py_with_arg();
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect::<TokenStream>();
|
.collect::<TokenStream>();
|
||||||
|
@ -250,8 +191,7 @@ fn impl_arg_param(
|
||||||
let from_py_with = format_ident!("from_py_with_{}", pos);
|
let from_py_with = format_ident!("from_py_with_{}", pos);
|
||||||
let arg_value = quote!(#args_array[#option_pos].as_deref());
|
let arg_value = quote!(#args_array[#option_pos].as_deref());
|
||||||
*option_pos += 1;
|
*option_pos += 1;
|
||||||
let tokens = impl_regular_arg_param(arg, from_py_with, arg_value, holders, ctx);
|
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)
|
|
||||||
}
|
}
|
||||||
FnArg::VarArgs(arg) => {
|
FnArg::VarArgs(arg) => {
|
||||||
let holder = holders.push_holder(arg.name.span());
|
let holder = holders.push_holder(arg.name.span());
|
||||||
|
|
|
@ -12,7 +12,6 @@ use crate::attributes::{
|
||||||
self, kw, take_pyo3_options, CrateAttribute, ExtendsAttribute, FreelistAttribute,
|
self, kw, take_pyo3_options, CrateAttribute, ExtendsAttribute, FreelistAttribute,
|
||||||
ModuleAttribute, NameAttribute, NameLitStr, RenameAllAttribute,
|
ModuleAttribute, NameAttribute, NameLitStr, RenameAllAttribute,
|
||||||
};
|
};
|
||||||
use crate::deprecations::Deprecations;
|
|
||||||
use crate::konst::{ConstAttributes, ConstSpec};
|
use crate::konst::{ConstAttributes, ConstSpec};
|
||||||
use crate::method::{FnArg, FnSpec, PyArg, RegularArg};
|
use crate::method::{FnArg, FnSpec, PyArg, RegularArg};
|
||||||
use crate::pyfunction::ConstructorAttribute;
|
use crate::pyfunction::ConstructorAttribute;
|
||||||
|
@ -232,17 +231,19 @@ pub fn build_py_class(
|
||||||
|
|
||||||
if let Some(lt) = class.generics.lifetimes().next() {
|
if let Some(lt) = class.generics.lifetimes().next() {
|
||||||
bail_spanned!(
|
bail_spanned!(
|
||||||
lt.span() =>
|
lt.span() => concat!(
|
||||||
"#[pyclass] cannot have lifetime parameters. \
|
"#[pyclass] cannot have lifetime parameters. For an explanation, see \
|
||||||
For an explanation, see https://pyo3.rs/latest/class.html#no-lifetime-parameters"
|
https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#no-lifetime-parameters"
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_spanned!(
|
ensure_spanned!(
|
||||||
class.generics.params.is_empty(),
|
class.generics.params.is_empty(),
|
||||||
class.generics.span() =>
|
class.generics.span() => concat!(
|
||||||
"#[pyclass] cannot have generic parameters. \
|
"#[pyclass] cannot have generic parameters. For an explanation, see \
|
||||||
For an explanation, see https://pyo3.rs/latest/class.html#no-generic-parameters"
|
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 {
|
let mut field_options: Vec<(&syn::Field, FieldPyO3Options)> = match &mut class.fields {
|
||||||
|
@ -384,7 +385,7 @@ fn impl_class(
|
||||||
ctx: &Ctx,
|
ctx: &Ctx,
|
||||||
) -> syn::Result<TokenStream> {
|
) -> syn::Result<TokenStream> {
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
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) =
|
let (default_richcmp, default_richcmp_slot) =
|
||||||
pyclass_richcmp(&args.options, &syn::parse_quote!(#cls), ctx)?;
|
pyclass_richcmp(&args.options, &syn::parse_quote!(#cls), ctx)?;
|
||||||
|
@ -779,7 +780,7 @@ fn impl_simple_enum(
|
||||||
let cls = simple_enum.ident;
|
let cls = simple_enum.ident;
|
||||||
let ty: syn::Type = syn::parse_quote!(#cls);
|
let ty: syn::Type = syn::parse_quote!(#cls);
|
||||||
let variants = simple_enum.variants;
|
let variants = simple_enum.variants;
|
||||||
let pytypeinfo = impl_pytypeinfo(cls, args, None, ctx);
|
let pytypeinfo = impl_pytypeinfo(cls, args, ctx);
|
||||||
|
|
||||||
for variant in &variants {
|
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");
|
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 ctx = &Ctx::new(&args.options.krate, None);
|
||||||
let cls = complex_enum.ident;
|
let cls = complex_enum.ident;
|
||||||
let variants = complex_enum.variants;
|
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_richcmp, default_richcmp_slot) = pyclass_richcmp(&args.options, &ty, ctx)?;
|
||||||
let (default_hash, default_hash_slot) = pyclass_hash(&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);
|
variant_cls_pytypeinfos.push(variant_cls_pytypeinfo);
|
||||||
|
|
||||||
let (variant_cls_impl, field_getters, mut slots) =
|
let (variant_cls_impl, field_getters, mut slots) =
|
||||||
|
@ -1057,7 +1058,6 @@ fn impl_complex_enum_variant_match_args(
|
||||||
attributes: ConstAttributes {
|
attributes: ConstAttributes {
|
||||||
is_class_attr: true,
|
is_class_attr: true,
|
||||||
name: None,
|
name: None,
|
||||||
deprecations: Deprecations::new(ctx),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1318,7 +1318,6 @@ fn generate_protocol_slot(
|
||||||
&mut method.sig,
|
&mut method.sig,
|
||||||
&mut Vec::new(),
|
&mut Vec::new(),
|
||||||
PyFunctionOptions::default(),
|
PyFunctionOptions::default(),
|
||||||
ctx,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
slot.generate_type_slot(&syn::parse_quote!(#cls), &spec, name, ctx)
|
slot.generate_type_slot(&syn::parse_quote!(#cls), &spec, name, ctx)
|
||||||
|
@ -1334,7 +1333,6 @@ fn generate_default_protocol_slot(
|
||||||
&mut method.sig,
|
&mut method.sig,
|
||||||
&mut Vec::new(),
|
&mut Vec::new(),
|
||||||
PyFunctionOptions::default(),
|
PyFunctionOptions::default(),
|
||||||
ctx,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let name = spec.name.to_string();
|
let name = spec.name.to_string();
|
||||||
|
@ -1360,7 +1358,6 @@ fn simple_enum_default_methods<'a>(
|
||||||
kw: syn::parse_quote! { name },
|
kw: syn::parse_quote! { name },
|
||||||
value: NameLitStr(py_ident.clone()),
|
value: NameLitStr(py_ident.clone()),
|
||||||
}),
|
}),
|
||||||
deprecations: Deprecations::new(ctx),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
unit_variant_names
|
unit_variant_names
|
||||||
|
@ -1383,7 +1380,6 @@ fn complex_enum_default_methods<'a>(
|
||||||
kw: syn::parse_quote! { name },
|
kw: syn::parse_quote! { name },
|
||||||
value: NameLitStr(py_ident.clone()),
|
value: NameLitStr(py_ident.clone()),
|
||||||
}),
|
}),
|
||||||
deprecations: Deprecations::new(ctx),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
variant_names
|
variant_names
|
||||||
|
@ -1397,19 +1393,17 @@ fn complex_enum_default_methods<'a>(
|
||||||
pub fn gen_complex_enum_variant_attr(
|
pub fn gen_complex_enum_variant_attr(
|
||||||
cls: &syn::Ident,
|
cls: &syn::Ident,
|
||||||
cls_type: &syn::Type,
|
cls_type: &syn::Type,
|
||||||
spec: &ConstSpec<'_>,
|
spec: &ConstSpec,
|
||||||
ctx: &Ctx,
|
ctx: &Ctx,
|
||||||
) -> MethodAndMethodDef {
|
) -> MethodAndMethodDef {
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let member = &spec.rust_ident;
|
let member = &spec.rust_ident;
|
||||||
let wrapper_ident = format_ident!("__pymethod_variant_cls_{}__", member);
|
let wrapper_ident = format_ident!("__pymethod_variant_cls_{}__", member);
|
||||||
let deprecations = &spec.attributes.deprecations;
|
|
||||||
let python_name = spec.null_terminated_python_name(ctx);
|
let python_name = spec.null_terminated_python_name(ctx);
|
||||||
|
|
||||||
let variant_cls = format_ident!("{}_{}", cls, member);
|
let variant_cls = format_ident!("{}_{}", cls, member);
|
||||||
let associated_method = quote! {
|
let associated_method = quote! {
|
||||||
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
|
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())
|
::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,
|
text_signature: None,
|
||||||
asyncness: None,
|
asyncness: None,
|
||||||
unsafety: None,
|
unsafety: None,
|
||||||
deprecations: Deprecations::new(ctx),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::pymethod::impl_py_method_def_new(&variant_cls_type, &spec, 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,
|
text_signature: None,
|
||||||
asyncness: None,
|
asyncness: None,
|
||||||
unsafety: None,
|
unsafety: None,
|
||||||
deprecations: Deprecations::new(ctx),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
crate::pymethod::impl_py_method_def_new(&variant_cls_type, &spec, 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,
|
text_signature: None,
|
||||||
asyncness: None,
|
asyncness: None,
|
||||||
unsafety: None,
|
unsafety: None,
|
||||||
deprecations: Deprecations::new(ctx),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let property_type = crate::pymethod::PropertyType::Function {
|
let property_type = crate::pymethod::PropertyType::Function {
|
||||||
|
@ -1641,12 +1632,7 @@ fn descriptors_to_items(
|
||||||
Ok(items)
|
Ok(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_pytypeinfo(
|
fn impl_pytypeinfo(cls: &syn::Ident, attr: &PyClassArgs, ctx: &Ctx) -> TokenStream {
|
||||||
cls: &syn::Ident,
|
|
||||||
attr: &PyClassArgs,
|
|
||||||
deprecations: Option<&Deprecations<'_>>,
|
|
||||||
ctx: &Ctx,
|
|
||||||
) -> TokenStream {
|
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
let cls_name = get_class_python_name(cls, attr).to_string();
|
let cls_name = get_class_python_name(cls, attr).to_string();
|
||||||
|
|
||||||
|
@ -1677,8 +1663,6 @@ fn impl_pytypeinfo(
|
||||||
#[inline]
|
#[inline]
|
||||||
fn type_object_raw(py: #pyo3_path::Python<'_>) -> *mut #pyo3_path::ffi::PyTypeObject {
|
fn type_object_raw(py: #pyo3_path::Python<'_>) -> *mut #pyo3_path::ffi::PyTypeObject {
|
||||||
use #pyo3_path::prelude::PyTypeMethods;
|
use #pyo3_path::prelude::PyTypeMethods;
|
||||||
#deprecations
|
|
||||||
|
|
||||||
<#cls as #pyo3_path::impl_::pyclass::PyClassImpl>::lazy_type_object()
|
<#cls as #pyo3_path::impl_::pyclass::PyClassImpl>::lazy_type_object()
|
||||||
.get_or_init(py)
|
.get_or_init(py)
|
||||||
.as_type_ptr()
|
.as_type_ptr()
|
||||||
|
|
|
@ -4,7 +4,6 @@ use crate::{
|
||||||
self, get_pyo3_options, take_attributes, take_pyo3_options, CrateAttribute,
|
self, get_pyo3_options, take_attributes, take_pyo3_options, CrateAttribute,
|
||||||
FromPyWithAttribute, NameAttribute, TextSignatureAttribute,
|
FromPyWithAttribute, NameAttribute, TextSignatureAttribute,
|
||||||
},
|
},
|
||||||
deprecations::Deprecations,
|
|
||||||
method::{self, CallingConvention, FnArg},
|
method::{self, CallingConvention, FnArg},
|
||||||
pymethod::check_generic,
|
pymethod::check_generic,
|
||||||
};
|
};
|
||||||
|
@ -252,7 +251,6 @@ pub fn impl_wrap_pyfunction(
|
||||||
text_signature,
|
text_signature,
|
||||||
asyncness: func.sig.asyncness,
|
asyncness: func.sig.asyncness,
|
||||||
unsafety: func.sig.unsafety,
|
unsafety: func.sig.unsafety,
|
||||||
deprecations: Deprecations::new(ctx),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let vis = &func.vis;
|
let vis = &func.vis;
|
||||||
|
|
|
@ -130,7 +130,7 @@ pub fn impl_methods(
|
||||||
}
|
}
|
||||||
syn::ImplItem::Const(konst) => {
|
syn::ImplItem::Const(konst) => {
|
||||||
let ctx = &Ctx::new(&options.krate, None);
|
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 {
|
if attributes.is_class_attr {
|
||||||
let spec = ConstSpec {
|
let spec = ConstSpec {
|
||||||
rust_ident: konst.ident.clone(),
|
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 member = &spec.rust_ident;
|
||||||
let wrapper_ident = format_ident!("__pymethod_{}__", member);
|
let wrapper_ident = format_ident!("__pymethod_{}__", member);
|
||||||
let deprecations = &spec.attributes.deprecations;
|
|
||||||
let python_name = spec.null_terminated_python_name(ctx);
|
let python_name = spec.null_terminated_python_name(ctx);
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
|
|
||||||
let associated_method = quote! {
|
let associated_method = quote! {
|
||||||
fn #wrapper_ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::PyObject> {
|
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))
|
::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::attributes::{NameAttribute, RenamingRule};
|
||||||
use crate::deprecations::deprecate_trailing_option_default;
|
use crate::deprecations::deprecate_trailing_option_default;
|
||||||
use crate::method::{CallingConvention, ExtractErrorMode, PyArg};
|
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::PythonDoc;
|
||||||
use crate::utils::{Ctx, LitCStr};
|
use crate::utils::{Ctx, LitCStr};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -164,9 +164,8 @@ impl<'a> PyMethod<'a> {
|
||||||
sig: &'a mut syn::Signature,
|
sig: &'a mut syn::Signature,
|
||||||
meth_attrs: &mut Vec<syn::Attribute>,
|
meth_attrs: &mut Vec<syn::Attribute>,
|
||||||
options: PyFunctionOptions,
|
options: PyFunctionOptions,
|
||||||
ctx: &'a Ctx,
|
|
||||||
) -> Result<Self> {
|
) -> 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 method_name = spec.python_name.to_string();
|
||||||
let kind = PyMethodKind::from_name(&method_name);
|
let kind = PyMethodKind::from_name(&method_name);
|
||||||
|
@ -195,7 +194,7 @@ pub fn gen_py_method(
|
||||||
) -> Result<GeneratedPyMethod> {
|
) -> Result<GeneratedPyMethod> {
|
||||||
check_generic(sig)?;
|
check_generic(sig)?;
|
||||||
ensure_function_options_valid(&options)?;
|
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 spec = &method.spec;
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
let Ctx { pyo3_path, .. } = ctx;
|
||||||
|
|
||||||
|
@ -356,7 +355,6 @@ pub fn impl_py_method_def_new(
|
||||||
|| quote!(::std::option::Option::None),
|
|| quote!(::std::option::Option::None),
|
||||||
|text_signature| quote!(::std::option::Option::Some(#text_signature)),
|
|text_signature| quote!(::std::option::Option::Some(#text_signature)),
|
||||||
);
|
);
|
||||||
let deprecations = &spec.deprecations;
|
|
||||||
let slot_def = quote! {
|
let slot_def = quote! {
|
||||||
#pyo3_path::ffi::PyType_Slot {
|
#pyo3_path::ffi::PyType_Slot {
|
||||||
slot: #pyo3_path::ffi::Py_tp_new,
|
slot: #pyo3_path::ffi::Py_tp_new,
|
||||||
|
@ -365,10 +363,7 @@ pub fn impl_py_method_def_new(
|
||||||
subtype: *mut #pyo3_path::ffi::PyTypeObject,
|
subtype: *mut #pyo3_path::ffi::PyTypeObject,
|
||||||
args: *mut #pyo3_path::ffi::PyObject,
|
args: *mut #pyo3_path::ffi::PyObject,
|
||||||
kwargs: *mut #pyo3_path::ffi::PyObject,
|
kwargs: *mut #pyo3_path::ffi::PyObject,
|
||||||
) -> *mut #pyo3_path::ffi::PyObject
|
) -> *mut #pyo3_path::ffi::PyObject {
|
||||||
{
|
|
||||||
#deprecations
|
|
||||||
|
|
||||||
use #pyo3_path::impl_::pyclass::*;
|
use #pyo3_path::impl_::pyclass::*;
|
||||||
#[allow(unknown_lints, non_local_definitions)]
|
#[allow(unknown_lints, non_local_definitions)]
|
||||||
impl PyClassNewTextSignature<#cls> for PyClassImplCollector<#cls> {
|
impl PyClassNewTextSignature<#cls> for PyClassImplCollector<#cls> {
|
||||||
|
@ -612,15 +607,12 @@ pub fn impl_py_setter_def(
|
||||||
PropertyType::Function { spec, .. } => {
|
PropertyType::Function { spec, .. } => {
|
||||||
let (_, args) = split_off_python_arg(&spec.signature.arguments);
|
let (_, args) = split_off_python_arg(&spec.signature.arguments);
|
||||||
let value_arg = &args[0];
|
let value_arg = &args[0];
|
||||||
let (from_py_with, ident) = if let Some(from_py_with) =
|
let (from_py_with, ident) =
|
||||||
&value_arg.from_py_with().as_ref().map(|f| &f.value)
|
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());
|
let ident = syn::Ident::new("from_py_with", from_py_with.span());
|
||||||
(
|
(
|
||||||
quote_spanned! { from_py_with.span() =>
|
quote_spanned! { from_py_with.span() =>
|
||||||
let e = #pyo3_path::impl_::deprecations::GilRefs::new();
|
let #ident = #from_py_with;
|
||||||
let #ident = #pyo3_path::impl_::deprecations::inspect_fn(#from_py_with, &e);
|
|
||||||
e.from_py_with_arg();
|
|
||||||
},
|
},
|
||||||
ident,
|
ident,
|
||||||
)
|
)
|
||||||
|
@ -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`.");
|
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,
|
arg,
|
||||||
ident,
|
ident,
|
||||||
quote!(::std::option::Option::Some(_value.into())),
|
quote!(::std::option::Option::Some(_value.into())),
|
||||||
&mut holders,
|
&mut holders,
|
||||||
ctx,
|
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);
|
let deprecation = deprecate_trailing_option_default(spec);
|
||||||
quote! {
|
quote! {
|
||||||
|
@ -660,12 +650,8 @@ pub fn impl_py_setter_def(
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let holder = holders.push_holder(span);
|
let holder = holders.push_holder(span);
|
||||||
let gil_refs_checker = holders.push_gil_refs_checker(span);
|
|
||||||
quote! {
|
quote! {
|
||||||
let _val = #pyo3_path::impl_::deprecations::inspect_type(
|
let _val = #pyo3_path::impl_::extract_argument::extract_argument(_value.into(), &mut #holder, #name)?;
|
||||||
#pyo3_path::impl_::extract_argument::extract_argument(_value.into(), &mut #holder, #name)?,
|
|
||||||
&#gil_refs_checker
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -682,7 +668,6 @@ pub fn impl_py_setter_def(
|
||||||
}
|
}
|
||||||
|
|
||||||
let init_holders = holders.init_holders(ctx);
|
let init_holders = holders.init_holders(ctx);
|
||||||
let check_gil_refs = holders.check_gil_refs();
|
|
||||||
let associated_method = quote! {
|
let associated_method = quote! {
|
||||||
#cfg_attrs
|
#cfg_attrs
|
||||||
unsafe fn #wrapper_ident(
|
unsafe fn #wrapper_ident(
|
||||||
|
@ -698,7 +683,6 @@ pub fn impl_py_setter_def(
|
||||||
#init_holders
|
#init_holders
|
||||||
#extract
|
#extract
|
||||||
let result = #setter_impl;
|
let result = #setter_impl;
|
||||||
#check_gil_refs
|
|
||||||
#pyo3_path::callback::convert(py, result)
|
#pyo3_path::callback::convert(py, result)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -824,7 +808,6 @@ pub fn impl_py_getter_def(
|
||||||
};
|
};
|
||||||
|
|
||||||
let init_holders = holders.init_holders(ctx);
|
let init_holders = holders.init_holders(ctx);
|
||||||
let check_gil_refs = holders.check_gil_refs();
|
|
||||||
let associated_method = quote! {
|
let associated_method = quote! {
|
||||||
#cfg_attrs
|
#cfg_attrs
|
||||||
unsafe fn #wrapper_ident(
|
unsafe fn #wrapper_ident(
|
||||||
|
@ -833,7 +816,6 @@ pub fn impl_py_getter_def(
|
||||||
) -> #pyo3_path::PyResult<*mut #pyo3_path::ffi::PyObject> {
|
) -> #pyo3_path::PyResult<*mut #pyo3_path::ffi::PyObject> {
|
||||||
#init_holders
|
#init_holders
|
||||||
let result = #body;
|
let result = #body;
|
||||||
#check_gil_refs
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1139,18 +1121,15 @@ fn extract_object(
|
||||||
ctx: &Ctx,
|
ctx: &Ctx,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let Ctx { pyo3_path, .. } = ctx;
|
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 name = arg.name().unraw().to_string();
|
||||||
|
|
||||||
let extract = if let Some(from_py_with) =
|
let extract =
|
||||||
arg.from_py_with().map(|from_py_with| &from_py_with.value)
|
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! {
|
quote! {
|
||||||
#pyo3_path::impl_::extract_argument::from_py_with(
|
#pyo3_path::impl_::extract_argument::from_py_with(
|
||||||
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0,
|
#pyo3_path::impl_::pymethods::BoundRef::ref_from_ptr(py, &#source_ptr).0,
|
||||||
#name,
|
#name,
|
||||||
#pyo3_path::impl_::deprecations::inspect_fn(#from_py_with, &#from_py_with_checker) as fn(_) -> _,
|
#from_py_with as fn(_) -> _,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1165,9 +1144,7 @@ fn extract_object(
|
||||||
};
|
};
|
||||||
|
|
||||||
let extracted = extract_error_mode.handle_error(extract, ctx);
|
let extracted = extract_error_mode.handle_error(extract, ctx);
|
||||||
quote! {
|
quote!(#extracted)
|
||||||
#pyo3_path::impl_::deprecations::inspect_type(#extracted, &#gil_refs_checker)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ReturnMode {
|
enum ReturnMode {
|
||||||
|
@ -1177,15 +1154,13 @@ enum ReturnMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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 Ctx { pyo3_path, .. } = ctx;
|
||||||
let check_gil_refs = holders.check_gil_refs();
|
|
||||||
match self {
|
match self {
|
||||||
ReturnMode::Conversion(conversion) => {
|
ReturnMode::Conversion(conversion) => {
|
||||||
let conversion = TokenGeneratorCtx(*conversion, ctx);
|
let conversion = TokenGeneratorCtx(*conversion, ctx);
|
||||||
quote! {
|
quote! {
|
||||||
let _result: #pyo3_path::PyResult<#conversion> = #pyo3_path::callback::convert(py, #call);
|
let _result: #pyo3_path::PyResult<#conversion> = #pyo3_path::callback::convert(py, #call);
|
||||||
#check_gil_refs
|
|
||||||
#pyo3_path::callback::convert(py, _result)
|
#pyo3_path::callback::convert(py, _result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1195,14 +1170,12 @@ impl ReturnMode {
|
||||||
quote! {
|
quote! {
|
||||||
let _result = #call;
|
let _result = #call;
|
||||||
use #pyo3_path::impl_::pymethods::{#traits};
|
use #pyo3_path::impl_::pymethods::{#traits};
|
||||||
#check_gil_refs
|
|
||||||
(&_result).#tag().convert(py, _result)
|
(&_result).#tag().convert(py, _result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ReturnMode::ReturnSelf => quote! {
|
ReturnMode::ReturnSelf => quote! {
|
||||||
let _result: #pyo3_path::PyResult<()> = #pyo3_path::callback::convert(py, #call);
|
let _result: #pyo3_path::PyResult<()> = #pyo3_path::callback::convert(py, #call);
|
||||||
_result?;
|
_result?;
|
||||||
#check_gil_refs
|
|
||||||
#pyo3_path::ffi::Py_XINCREF(_raw_slf);
|
#pyo3_path::ffi::Py_XINCREF(_raw_slf);
|
||||||
::std::result::Result::Ok(_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 args = extract_proto_arguments(spec, arguments, extract_error_mode, holders, ctx)?;
|
||||||
let call = quote! { #cls::#rust_name(#self_arg #(#args),*) };
|
let call = quote! { #cls::#rust_name(#self_arg #(#args),*) };
|
||||||
Ok(if let Some(return_mode) = return_mode {
|
Ok(if let Some(return_mode) = return_mode {
|
||||||
return_mode.return_call_output(call, ctx, holders)
|
return_mode.return_call_output(call, ctx)
|
||||||
} else {
|
} else {
|
||||||
let check_gil_refs = holders.check_gil_refs();
|
|
||||||
quote! {
|
quote! {
|
||||||
let result = #call;
|
let result = #call;
|
||||||
#check_gil_refs;
|
|
||||||
#pyo3_path::callback::convert(py, result)
|
#pyo3_path::callback::convert(py, result)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3-macros"
|
name = "pyo3-macros"
|
||||||
version = "0.22.1"
|
version = "0.23.0-dev"
|
||||||
description = "Proc macros for PyO3 package"
|
description = "Proc macros for PyO3 package"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
@ -22,7 +22,7 @@ gil-refs = ["pyo3-macros-backend/gil-refs"]
|
||||||
proc-macro2 = { version = "1.0.60", default-features = false }
|
proc-macro2 = { version = "1.0.60", default-features = false }
|
||||||
quote = "1"
|
quote = "1"
|
||||||
syn = { version = "2", features = ["full", "extra-traits"] }
|
syn = { version = "2", features = ["full", "extra-traits"] }
|
||||||
pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.22.1" }
|
pyo3-macros-backend = { path = "../pyo3-macros-backend", version = "=0.23.0-dev" }
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
|
@ -3,14 +3,14 @@
|
||||||
|
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use pyo3_macros_backend::{
|
use pyo3_macros_backend::{
|
||||||
build_derive_from_pyobject, build_py_class, build_py_enum, build_py_function, build_py_methods,
|
build_derive_from_pyobject, build_py_class, build_py_enum, build_py_function, build_py_methods,
|
||||||
pymodule_function_impl, pymodule_module_impl, PyClassArgs, PyClassMethodsType,
|
pymodule_function_impl, pymodule_module_impl, PyClassArgs, PyClassMethodsType,
|
||||||
PyFunctionOptions,
|
PyFunctionOptions, PyModuleOptions,
|
||||||
};
|
};
|
||||||
use quote::quote;
|
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.
|
/// A proc macro used to implement Python modules.
|
||||||
///
|
///
|
||||||
|
@ -24,6 +24,9 @@ use syn::{parse::Nothing, parse_macro_input, Item};
|
||||||
/// | Annotation | Description |
|
/// | Annotation | Description |
|
||||||
/// | :- | :- |
|
/// | :- | :- |
|
||||||
/// | `#[pyo3(name = "...")]` | Defines the name of the module in Python. |
|
/// | `#[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].
|
/// 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
|
/// `#[pymodule]` implementation generates a hidden module with the same name containing
|
||||||
/// metadata about the module, which is used by `wrap_pymodule!`).
|
/// 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]
|
#[proc_macro_attribute]
|
||||||
pub fn pymodule(args: TokenStream, input: TokenStream) -> TokenStream {
|
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) => {
|
Item::Mod(module) => {
|
||||||
let is_submodule = match parse_macro_input!(args as Option<syn::Ident>) {
|
match pymodule_module_impl(module, options) {
|
||||||
Some(i) if i == "submodule" => true,
|
// #[pymodule] on a module will rebuild the original ast, so we don't emit it here
|
||||||
Some(_) => {
|
Ok(expanded) => return expanded.into(),
|
||||||
return syn::Error::new(
|
Err(e) => Err(e),
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
Item::Fn(function) => pymodule_function_impl(function, options),
|
||||||
unsupported => Err(syn::Error::new_spanned(
|
unsupported => Err(syn::Error::new_spanned(
|
||||||
unsupported,
|
unsupported,
|
||||||
"#[pymodule] only supports modules and functions.",
|
"#[pymodule] only supports modules and functions.",
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
.unwrap_or_compile_error()
|
.unwrap_or_compile_error();
|
||||||
|
|
||||||
|
quote!(
|
||||||
|
#ast
|
||||||
|
#expanded
|
||||||
|
)
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,17 +99,17 @@ pub fn pyclass(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
/// multiple `#[pymethods]` blocks for a single `#[pyclass]`.
|
/// multiple `#[pymethods]` blocks for a single `#[pyclass]`.
|
||||||
/// This will add a transitive dependency on the [`inventory`][3] crate.
|
/// This will add a transitive dependency on the [`inventory`][3] crate.
|
||||||
///
|
///
|
||||||
/// [1]: https://pyo3.rs/latest/class.html#instance-methods
|
#[doc = concat!("[1]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#instance-methods")]
|
||||||
/// [2]: https://pyo3.rs/latest/features.html#multiple-pymethods
|
#[doc = concat!("[2]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/features.html#multiple-pymethods")]
|
||||||
/// [3]: https://docs.rs/inventory/
|
/// [3]: https://docs.rs/inventory/
|
||||||
/// [4]: https://pyo3.rs/latest/class.html#constructor
|
#[doc = concat!("[4]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#constructor")]
|
||||||
/// [5]: https://pyo3.rs/latest/class.html#object-properties-using-getter-and-setter
|
#[doc = concat!("[5]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#object-properties-using-getter-and-setter")]
|
||||||
/// [6]: https://pyo3.rs/latest/class.html#static-methods
|
#[doc = concat!("[6]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#static-methods")]
|
||||||
/// [7]: https://pyo3.rs/latest/class.html#class-methods
|
#[doc = concat!("[7]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#class-methods")]
|
||||||
/// [8]: https://pyo3.rs/latest/class.html#callable-objects
|
#[doc = concat!("[8]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#callable-objects")]
|
||||||
/// [9]: https://pyo3.rs/latest/class.html#class-attributes
|
#[doc = concat!("[9]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#class-attributes")]
|
||||||
/// [10]: https://pyo3.rs/latest/class.html#method-arguments
|
#[doc = concat!("[10]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#method-arguments")]
|
||||||
/// [11]: https://pyo3.rs/latest/class.html#object-properties-using-pyo3get-set
|
#[doc = concat!("[11]: https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/class.html#object-properties-using-pyo3get-set")]
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn pymethods(attr: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn pymethods(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let methods_type = if cfg!(feature = "multiple-pymethods") {
|
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
|
/// `#[pyfunction]` implementation generates a hidden module with the same name containing
|
||||||
/// metadata about the function, which is used by `wrap_pyfunction!`).
|
/// 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]
|
#[proc_macro_attribute]
|
||||||
pub fn pyfunction(attr: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn pyfunction(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let mut ast = parse_macro_input!(input as syn::ItemFn);
|
let mut ast = parse_macro_input!(input as syn::ItemFn);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
[tool.towncrier]
|
[tool.towncrier]
|
||||||
filename = "CHANGELOG.md"
|
filename = "CHANGELOG.md"
|
||||||
version = "0.22.1"
|
version = "0.23.0-dev"
|
||||||
start_string = "<!-- towncrier release notes start -->\n"
|
start_string = "<!-- towncrier release notes start -->\n"
|
||||||
template = ".towncrier.template.md"
|
template = ".towncrier.template.md"
|
||||||
title_format = "## [{version}] - {project_date}"
|
title_format = "## [{version}] - {project_date}"
|
||||||
|
|
|
@ -8,10 +8,7 @@ use crate::types::PyTuple;
|
||||||
use crate::{ffi, Borrowed, Bound, Py, PyAny, PyClass, PyObject, PyRef, PyRefMut, Python};
|
use crate::{ffi, Borrowed, Bound, Py, PyAny, PyClass, PyObject, PyRef, PyRefMut, Python};
|
||||||
#[cfg(feature = "gil-refs")]
|
#[cfg(feature = "gil-refs")]
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{err, gil, PyNativeType},
|
||||||
err::{self, PyDowncastError},
|
|
||||||
gil, PyNativeType,
|
|
||||||
},
|
|
||||||
std::ptr::NonNull,
|
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.
|
/// Converts `()` to an empty Python tuple.
|
||||||
impl IntoPy<Py<PyTuple>> for () {
|
impl IntoPy<Py<PyTuple>> for () {
|
||||||
fn into_py(self, py: Python<'_>) -> Py<PyTuple> {
|
fn into_py(self, py: Python<'_>) -> Py<PyTuple> {
|
||||||
|
@ -665,51 +547,3 @@ where
|
||||||
/// })
|
/// })
|
||||||
/// ```
|
/// ```
|
||||||
mod test_no_clone {}
|
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")]
|
#[cfg(feature = "experimental-async")]
|
||||||
pub mod coroutine;
|
pub mod coroutine;
|
||||||
pub mod deprecations;
|
|
||||||
pub mod exceptions;
|
pub mod exceptions;
|
||||||
pub mod extract_argument;
|
pub mod extract_argument;
|
||||||
pub mod freelist;
|
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)]
|
#[repr(transparent)]
|
||||||
pub struct Bound<'py, T>(Python<'py>, ManuallyDrop<Py<T>>);
|
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`],
|
/// - [`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`].
|
/// 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.
|
/// for more information.
|
||||||
/// - You can call methods directly on `Py` with [`Py::call_bound`], [`Py::call_method_bound`] and friends.
|
/// - 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]
|
#[inline]
|
||||||
pub fn clone_ref(&self, py: Python<'_>) -> Py<T> {
|
pub fn clone_ref(&self, _py: Python<'_>) -> Py<T> {
|
||||||
unsafe { Py::from_borrowed_ptr(py, self.0.as_ptr()) }
|
unsafe {
|
||||||
|
ffi::Py_INCREF(self.as_ptr());
|
||||||
|
Self::from_non_null(self.0)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Drops `self` and immediately decreases its reference count.
|
/// Drops `self` and immediately decreases its reference count.
|
||||||
|
@ -1369,22 +1385,6 @@ impl<T> Py<T> {
|
||||||
unsafe { ffi::Py_None() == self.as_ptr() }
|
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.
|
/// Returns whether the object is considered to be true.
|
||||||
///
|
///
|
||||||
/// This applies truth value testing equivalent to the Python expression `bool(self)`.
|
/// 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]
|
#[test]
|
||||||
fn test_debug_fmt() {
|
fn test_debug_fmt() {
|
||||||
Python::with_gil(|py| {
|
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."
|
//! [`rust_decimal`]: ./rust_decimal/index.html "Documenation about the `rust_decimal` feature."
|
||||||
//! [`Decimal`]: https://docs.rs/rust_decimal/latest/rust_decimal/struct.Decimal.html
|
//! [`Decimal`]: https://docs.rs/rust_decimal/latest/rust_decimal/struct.Decimal.html
|
||||||
//! [`serde`]: <./serde/index.html> "Documentation about the `serde` feature."
|
//! [`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
|
//! [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"
|
//! [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
|
//! [global interpreter lock]: https://docs.python.org/3/glossary.html#term-global-interpreter-lock
|
||||||
//! [hashbrown]: https://docs.rs/hashbrown
|
//! [hashbrown]: https://docs.rs/hashbrown
|
||||||
//! [smallvec]: https://docs.rs/smallvec
|
//! [smallvec]: https://docs.rs/smallvec
|
||||||
//! [indexmap]: https://docs.rs/indexmap
|
//! [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-bigint]: https://docs.rs/num-bigint
|
||||||
//! [num-complex]: https://docs.rs/num-complex
|
//! [num-complex]: https://docs.rs/num-complex
|
||||||
//! [num-rational]: https://docs.rs/num-rational
|
//! [num-rational]: https://docs.rs/num-rational
|
||||||
//! [serde]: https://docs.rs/serde
|
//! [serde]: https://docs.rs/serde
|
||||||
//! [setuptools-rust]: https://github.com/PyO3/setuptools-rust "Setuptools plugin for Rust extensions"
|
//! [setuptools-rust]: https://github.com/PyO3/setuptools-rust "Setuptools plugin for Rust extensions"
|
||||||
//! [the guide]: https://pyo3.rs "PyO3 user guide"
|
//! [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"
|
//! [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
|
//! [Python from Rust]: https://github.com/PyO3/pyo3#using-python-from-rust
|
||||||
//! [Rust from Python]: https://github.com/PyO3/pyo3#using-rust-from-python
|
//! [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
|
//! [`Ungil`]: crate::marker::Ungil
|
||||||
pub use crate::class::*;
|
pub use crate::class::*;
|
||||||
pub use crate::conversion::{AsPyPointer, FromPyObject, IntoPy, ToPyObject};
|
pub use crate::conversion::{AsPyPointer, FromPyObject, IntoPy, ToPyObject};
|
||||||
#[cfg(feature = "gil-refs")]
|
#[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::PyDowncastError;
|
||||||
pub use crate::err::{DowncastError, DowncastIntoError, PyErr, PyErrArguments, PyResult, ToPyErr};
|
pub use crate::err::{DowncastError, DowncastIntoError, PyErr, PyErrArguments, PyResult, ToPyErr};
|
||||||
#[cfg(feature = "gil-refs")]
|
#[cfg(feature = "gil-refs")]
|
||||||
|
@ -382,30 +379,6 @@ pub mod class {
|
||||||
pub use crate::pyclass::CompareOp;
|
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.
|
/// 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
|
/// Prefer using the same content from `pyo3::pyclass`, e.g. `use pyo3::pyclass::PyTraverseError` instead
|
||||||
|
@ -461,7 +434,6 @@ pub mod marshal;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub mod panic;
|
pub mod panic;
|
||||||
pub mod prelude;
|
|
||||||
pub mod pybacked;
|
pub mod pybacked;
|
||||||
pub mod pycell;
|
pub mod pycell;
|
||||||
pub mod pyclass;
|
pub mod pyclass;
|
||||||
|
@ -484,7 +456,7 @@ pub use pyo3_macros::{pyfunction, pymethods, pymodule, FromPyObject};
|
||||||
/// For more on creating Python classes,
|
/// For more on creating Python classes,
|
||||||
/// see the [class section of the guide][1].
|
/// 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")]
|
#[cfg(feature = "macros")]
|
||||||
pub use pyo3_macros::pyclass;
|
pub use pyo3_macros::pyclass;
|
||||||
|
|
||||||
|
@ -495,15 +467,9 @@ mod macros;
|
||||||
#[cfg(feature = "experimental-inspect")]
|
#[cfg(feature = "experimental-inspect")]
|
||||||
pub mod inspect;
|
pub mod inspect;
|
||||||
|
|
||||||
/// Ths module only contains re-exports of pyo3 deprecation warnings and exists
|
// Putting the declaration of prelude at the end seems to help encourage rustc and rustdoc to prefer using
|
||||||
/// purely to make compiler error messages nicer.
|
// other paths to the same items. (e.g. `pyo3::types::PyAnyMethods` instead of `pyo3::prelude::PyAnyMethods`).
|
||||||
///
|
pub mod prelude;
|
||||||
/// (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::*;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Test readme and user guide
|
/// Test readme and user guide
|
||||||
#[cfg(doctest)]
|
#[cfg(doctest)]
|
||||||
|
|
|
@ -145,12 +145,8 @@ macro_rules! wrap_pyfunction {
|
||||||
};
|
};
|
||||||
($function:path, $py_or_module:expr) => {{
|
($function:path, $py_or_module:expr) => {{
|
||||||
use $function as wrapped_pyfunction;
|
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(
|
$crate::impl_::pyfunction::WrapPyFunctionArg::wrap_pyfunction(
|
||||||
py_or_module,
|
$py_or_module,
|
||||||
&wrapped_pyfunction::_PYO3_DEF,
|
&wrapped_pyfunction::_PYO3_DEF,
|
||||||
)
|
)
|
||||||
}};
|
}};
|
||||||
|
|
|
@ -126,10 +126,10 @@ use crate::types::{
|
||||||
PyAny, PyDict, PyEllipsis, PyModule, PyNone, PyNotImplemented, PyString, PyType,
|
PyAny, PyDict, PyEllipsis, PyModule, PyNone, PyNotImplemented, PyString, PyType,
|
||||||
};
|
};
|
||||||
use crate::version::PythonVersionInfo;
|
use crate::version::PythonVersionInfo;
|
||||||
use crate::{ffi, Bound, IntoPy, Py, PyObject, PyTypeInfo};
|
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
#[cfg(feature = "gil-refs")]
|
#[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::ffi::{CStr, CString};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
@ -801,42 +801,6 @@ impl<'py> Python<'py> {
|
||||||
PythonVersionInfo::from_str(version_number_str).unwrap()
|
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,
|
/// Registers the object pointer in the release pool,
|
||||||
/// and does an unchecked downcast to the specific type.
|
/// and does an unchecked downcast to the specific type.
|
||||||
///
|
///
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
pub use crate::conversion::{FromPyObject, IntoPy, ToPyObject};
|
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::err::{PyErr, PyResult};
|
||||||
pub use crate::instance::{Borrowed, Bound, Py, PyObject};
|
pub use crate::instance::{Borrowed, Bound, Py, PyObject};
|
||||||
pub use crate::marker::Python;
|
pub use crate::marker::Python;
|
||||||
|
|
110
src/pyclass.rs
110
src/pyclass.rs
|
@ -1,8 +1,5 @@
|
||||||
//! `PyClass` and related traits.
|
//! `PyClass` and related traits.
|
||||||
use crate::{
|
use crate::{ffi, impl_::pyclass::PyClassImpl, PyTypeInfo};
|
||||||
callback::IntoPyCallbackOutput, ffi, impl_::pyclass::PyClassImpl, IntoPy, PyObject, PyResult,
|
|
||||||
PyTypeInfo, Python,
|
|
||||||
};
|
|
||||||
use std::{cmp::Ordering, os::raw::c_int};
|
use std::{cmp::Ordering, os::raw::c_int};
|
||||||
|
|
||||||
mod create_type_object;
|
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).
|
/// 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.
|
/// 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
|
/// 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
|
/// 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
|
/// `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:
|
/// Note that:
|
||||||
/// 1) `get_or_init` and `get_or_try_init` do not protect against infinite recursion
|
/// 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)]
|
#[derive(crate::FromPyObject)]
|
||||||
#[pyo3(crate = "crate")]
|
#[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
|
struct Derive2(i32, i32); // tuple case
|
||||||
|
|
||||||
#[derive(crate::FromPyObject)]
|
#[derive(crate::FromPyObject)]
|
||||||
#[pyo3(crate = "crate")]
|
#[pyo3(crate = "crate")]
|
||||||
#[allow(dead_code)]
|
|
||||||
struct Derive3 {
|
struct Derive3 {
|
||||||
f: i32,
|
f: i32,
|
||||||
#[pyo3(item(42))]
|
#[pyo3(item(42))]
|
||||||
|
@ -20,7 +16,6 @@ struct Derive3 {
|
||||||
|
|
||||||
#[derive(crate::FromPyObject)]
|
#[derive(crate::FromPyObject)]
|
||||||
#[pyo3(crate = "crate")]
|
#[pyo3(crate = "crate")]
|
||||||
#[allow(dead_code)]
|
|
||||||
enum Derive4 {
|
enum Derive4 {
|
||||||
A(i32),
|
A(i32),
|
||||||
B { f: i32 },
|
B { f: i32 },
|
||||||
|
@ -29,23 +24,16 @@ enum Derive4 {
|
||||||
crate::create_exception!(mymodule, CustomError, crate::exceptions::PyException);
|
crate::create_exception!(mymodule, CustomError, crate::exceptions::PyException);
|
||||||
crate::import_exception!(socket, gaierror);
|
crate::import_exception!(socket, gaierror);
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn intern(py: crate::Python<'_>) {
|
fn intern(py: crate::Python<'_>) {
|
||||||
let _foo = crate::intern!(py, "foo");
|
let _foo = crate::intern!(py, "foo");
|
||||||
let _bar = crate::intern!(py, stringify!(bar));
|
let _bar = crate::intern!(py, stringify!(bar));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[cfg(not(PyPy))]
|
#[cfg(not(PyPy))]
|
||||||
fn append_to_inittab() {
|
fn append_to_inittab() {
|
||||||
#[crate::pymodule]
|
#[crate::pymodule]
|
||||||
#[pyo3(crate = "crate")]
|
#[pyo3(crate = "crate")]
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
mod module_for_inittab {}
|
||||||
fn module_for_inittab(
|
|
||||||
_: crate::Python<'_>,
|
|
||||||
_: &crate::Bound<'_, crate::types::PyModule>,
|
|
||||||
) -> crate::PyResult<()> {
|
|
||||||
::std::result::Result::Ok(())
|
|
||||||
}
|
|
||||||
crate::append_to_inittab!(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
|
// 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
|
// 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.
|
// #[pyo3(crate = "crate")] this validates that all macro expansion respects the setting.
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
#![no_implicit_prelude]
|
|
||||||
#![allow(unused_variables)]
|
|
||||||
|
|
||||||
#[crate::pyclass]
|
#[crate::pyclass]
|
||||||
#[pyo3(crate = "crate")]
|
#[pyo3(crate = "crate")]
|
||||||
#[derive(::std::clone::Clone)]
|
#[derive(::std::clone::Clone)]
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
#![no_implicit_prelude]
|
|
||||||
#![allow(unused_variables, clippy::unnecessary_wraps)]
|
|
||||||
|
|
||||||
#[crate::pyfunction]
|
#[crate::pyfunction]
|
||||||
#[pyo3(crate = "crate")]
|
#[pyo3(crate = "crate")]
|
||||||
fn do_something(x: i32) -> crate::PyResult<i32> {
|
fn do_something(x: i32) -> crate::PyResult<i32> {
|
||||||
|
@ -8,19 +5,9 @@ fn do_something(x: i32) -> crate::PyResult<i32> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "gil-refs")]
|
|
||||||
fn invoke_wrap_pyfunction() {
|
fn invoke_wrap_pyfunction() {
|
||||||
crate::Python::with_gil(|py| {
|
crate::Python::with_gil(|py| {
|
||||||
#[allow(deprecated)]
|
let func = crate::wrap_pyfunction!(do_something, py).unwrap();
|
||||||
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();
|
|
||||||
crate::py_run!(py, func, r#"func(5)"#);
|
crate::py_run!(py, func, r#"func(5)"#);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
#![no_implicit_prelude]
|
|
||||||
#![allow(unused_variables, clippy::unnecessary_wraps)]
|
|
||||||
|
|
||||||
#[crate::pyclass]
|
#[crate::pyclass]
|
||||||
#[pyo3(crate = "crate")]
|
#[pyo3(crate = "crate")]
|
||||||
pub struct Dummy;
|
pub struct Dummy;
|
||||||
|
|
|
@ -1,51 +1,36 @@
|
||||||
#![no_implicit_prelude]
|
|
||||||
#![allow(unused_variables, clippy::unnecessary_wraps)]
|
|
||||||
|
|
||||||
#[crate::pyfunction]
|
#[crate::pyfunction]
|
||||||
#[pyo3(crate = "crate")]
|
#[pyo3(crate = "crate")]
|
||||||
fn do_something(x: i32) -> crate::PyResult<i32> {
|
fn do_something(x: i32) -> crate::PyResult<i32> {
|
||||||
::std::result::Result::Ok(x)
|
::std::result::Result::Ok(x)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gil-refs")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
#[crate::pymodule]
|
#[crate::pymodule]
|
||||||
#[pyo3(crate = "crate")]
|
#[pyo3(crate = "crate")]
|
||||||
fn foo(_py: crate::Python<'_>, _m: &crate::types::PyModule) -> crate::PyResult<()> {
|
fn foo(
|
||||||
::std::result::Result::Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[crate::pymodule]
|
|
||||||
#[pyo3(crate = "crate")]
|
|
||||||
fn foo_bound(
|
|
||||||
_py: crate::Python<'_>,
|
_py: crate::Python<'_>,
|
||||||
_m: &crate::Bound<'_, crate::types::PyModule>,
|
_m: &crate::Bound<'_, crate::types::PyModule>,
|
||||||
) -> crate::PyResult<()> {
|
) -> crate::PyResult<()> {
|
||||||
::std::result::Result::Ok(())
|
::std::result::Result::Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "gil-refs")]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
#[crate::pymodule]
|
#[crate::pymodule]
|
||||||
#[pyo3(crate = "crate")]
|
#[pyo3(crate = "crate")]
|
||||||
fn my_module(_py: crate::Python<'_>, m: &crate::types::PyModule) -> crate::PyResult<()> {
|
fn my_module(m: &crate::Bound<'_, 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<()> {
|
|
||||||
<crate::Bound<'_, crate::types::PyModule> as crate::types::PyModuleMethods>::add_function(
|
<crate::Bound<'_, crate::types::PyModule> as crate::types::PyModuleMethods>::add_function(
|
||||||
m,
|
m,
|
||||||
crate::wrap_pyfunction_bound!(do_something, m)?,
|
crate::wrap_pyfunction_bound!(do_something, m)?,
|
||||||
)?;
|
)?;
|
||||||
<crate::Bound<'_, crate::types::PyModule> as crate::types::PyModuleMethods>::add_wrapped(
|
<crate::Bound<'_, crate::types::PyModule> as crate::types::PyModuleMethods>::add_wrapped(
|
||||||
m,
|
m,
|
||||||
crate::wrap_pymodule!(foo_bound),
|
crate::wrap_pymodule!(foo),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
::std::result::Result::Ok(())
|
::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.
|
/// Represents any Python object.
|
||||||
///
|
///
|
||||||
/// It currently only appears as a *reference*, `&PyAny`,
|
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||||
/// with a lifetime that represents the scope during which the GIL is held.
|
/// [`Py<PyAny>`][crate::Py] or [`Bound<'py, PyAny>`][Bound].
|
||||||
///
|
///
|
||||||
/// `PyAny` has some interesting properties, which it shares
|
/// For APIs available on all Python objects, see the [`PyAnyMethods`] trait which is implemented for
|
||||||
/// with the other [native Python types](crate::types):
|
/// [`Bound<'py, PyAny>`][Bound].
|
||||||
///
|
///
|
||||||
/// - It can only be obtained and used while the GIL is held,
|
/// See
|
||||||
/// therefore its API does not require a [`Python<'py>`](crate::Python) token.
|
#[doc = concat!("[the guide](https://pyo3.rs/v", env!("CARGO_PKG_VERSION"), "/types.html#concrete-python-types)")]
|
||||||
/// - It can't be used in situations where the GIL is temporarily released,
|
/// for an explanation of the different Python object types.
|
||||||
/// 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.
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct PyAny(UnsafeCell<ffi::PyObject>);
|
pub struct PyAny(UnsafeCell<ffi::PyObject>);
|
||||||
|
|
||||||
|
@ -592,14 +581,6 @@ impl PyAny {
|
||||||
.map(Bound::into_gil_ref)
|
.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.
|
/// Returns whether the object is considered to be true.
|
||||||
///
|
///
|
||||||
/// This applies truth value testing equivalent to the Python expression `bool(self)`.
|
/// This applies truth value testing equivalent to the Python expression `bool(self)`.
|
||||||
|
@ -615,14 +596,6 @@ impl PyAny {
|
||||||
self.as_borrowed().is_none()
|
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.
|
/// Returns true if the sequence or mapping has a length of 0.
|
||||||
///
|
///
|
||||||
/// This is equivalent to the Python expression `len(self) == 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. `...`.
|
/// Returns whether the object is Ellipsis, e.g. `...`.
|
||||||
///
|
///
|
||||||
/// This is equivalent to the Python expression `self is ...`.
|
/// 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;
|
fn is_ellipsis(&self) -> bool;
|
||||||
|
|
||||||
/// Returns true if the sequence or mapping has a length of 0.
|
/// Returns true if the sequence or mapping has a length of 0.
|
||||||
|
@ -2796,6 +2770,7 @@ class SimpleClass:
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(deprecated)]
|
||||||
fn test_is_ellipsis() {
|
fn test_is_ellipsis() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
let v = py
|
let v = py
|
||||||
|
|
|
@ -11,6 +11,12 @@ use crate::{
|
||||||
use super::any::PyAnyMethods;
|
use super::any::PyAnyMethods;
|
||||||
|
|
||||||
/// Represents a Python `bool`.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyBool(PyAny);
|
pub struct PyBool(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,12 @@ use crate::{AsPyPointer, PyNativeType};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
/// Represents a Python `bytearray`.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyByteArray(PyAny);
|
pub struct PyByteArray(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,16 @@ use std::str;
|
||||||
///
|
///
|
||||||
/// This type is immutable.
|
/// 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
|
/// # Equality
|
||||||
///
|
///
|
||||||
/// For convenience, [`Bound<'py, PyBytes>`] implements [`PartialEq<[u8]>`] to allow comparing the
|
/// For convenience, [`Bound<'py, PyBytes>`][Bound] implements [`PartialEq<[u8]>`][PartialEq] to allow comparing the
|
||||||
/// data in the Python bytes to a Rust `[u8]`.
|
/// 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
|
/// 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
|
/// 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
|
/// > in one module available to other modules, so the regular import mechanism can
|
||||||
/// > be used to access C APIs defined in dynamically loaded modules.
|
/// > 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
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
|
|
|
@ -2,6 +2,9 @@ use crate::ffi;
|
||||||
use crate::PyAny;
|
use crate::PyAny;
|
||||||
|
|
||||||
/// Represents a Python code object.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyCode(PyAny);
|
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.
|
/// 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
|
/// Note that `PyComplex` supports only basic operations. For advanced operations
|
||||||
/// consider using [num-complex](https://docs.rs/num-complex)'s [`Complex`] type instead.
|
/// 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.
|
/// 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>>;
|
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)]
|
#[repr(transparent)]
|
||||||
pub struct PyDate(PyAny);
|
pub struct PyDate(PyAny);
|
||||||
pyobject_native_type!(
|
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)]
|
#[repr(transparent)]
|
||||||
pub struct PyDateTime(PyAny);
|
pub struct PyDateTime(PyAny);
|
||||||
pyobject_native_type!(
|
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)]
|
#[repr(transparent)]
|
||||||
pub struct PyTime(PyAny);
|
pub struct PyTime(PyAny);
|
||||||
pyobject_native_type!(
|
pyobject_native_type!(
|
||||||
|
@ -781,6 +790,9 @@ impl<'py> PyTzInfoAccess<'py> for Bound<'py, PyTime> {
|
||||||
|
|
||||||
/// Bindings for `datetime.tzinfo`.
|
/// 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.
|
/// This is an abstract base class and cannot be constructed directly.
|
||||||
/// For concrete time zone implementations, see [`timezone_utc_bound`] and
|
/// For concrete time zone implementations, see [`timezone_utc_bound`] and
|
||||||
/// the [`zoneinfo` module](https://docs.python.org/3/library/zoneinfo.html).
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyDelta(PyAny);
|
pub struct PyDelta(PyAny);
|
||||||
pyobject_native_type!(
|
pyobject_native_type!(
|
||||||
|
|
|
@ -11,6 +11,12 @@ use crate::PyNativeType;
|
||||||
use crate::{ffi, Python, ToPyObject};
|
use crate::{ffi, Python, ToPyObject};
|
||||||
|
|
||||||
/// Represents a Python `dict`.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyDict(PyAny);
|
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.
|
/// Sets an item value.
|
||||||
///
|
///
|
||||||
/// This is equivalent to the Python statement `self[key] = 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]
|
#[test]
|
||||||
fn test_set_item() {
|
fn test_set_item() {
|
||||||
Python::with_gil(|py| {
|
Python::with_gil(|py| {
|
||||||
|
|
|
@ -4,6 +4,9 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents the Python `Ellipsis` object.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyEllipsis(PyAny);
|
pub struct PyEllipsis(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,15 @@ use std::os::raw::c_double;
|
||||||
|
|
||||||
/// Represents a Python `float` object.
|
/// 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
|
/// You can usually avoid directly working with this type
|
||||||
/// by using [`ToPyObject`] and [`extract`](PyAnyMethods::extract)
|
/// by using [`ToPyObject`] and [`extract`][PyAnyMethods::extract]
|
||||||
/// with `f32`/`f64`.
|
/// with [`f32`]/[`f64`].
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct PyFloat(PyAny);
|
pub struct PyFloat(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@ use crate::ffi;
|
||||||
use crate::PyAny;
|
use crate::PyAny;
|
||||||
|
|
||||||
/// Represents a Python frame.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyFrame(PyAny);
|
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)]
|
#[repr(transparent)]
|
||||||
pub struct PyFrozenSet(PyAny);
|
pub struct PyFrozenSet(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,9 @@ use std::cell::UnsafeCell;
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
|
|
||||||
/// Represents a builtin Python function object.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyCFunction(PyAny);
|
pub struct PyCFunction(PyAny);
|
||||||
|
|
||||||
|
@ -241,6 +244,9 @@ struct ClosureDestructor<F> {
|
||||||
unsafe impl<F: Send> Send for ClosureDestructor<F> {}
|
unsafe impl<F: Send> Send for ClosureDestructor<F> {}
|
||||||
|
|
||||||
/// Represents a Python function object.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
#[cfg(all(not(Py_LIMITED_API), not(all(PyPy, not(Py_3_8)))))]
|
#[cfg(all(not(Py_LIMITED_API), not(all(PyPy, not(Py_3_8)))))]
|
||||||
pub struct PyFunction(PyAny);
|
pub struct PyFunction(PyAny);
|
||||||
|
|
|
@ -3,10 +3,13 @@ use crate::instance::Borrowed;
|
||||||
use crate::py_result_ext::PyResultExt;
|
use crate::py_result_ext::PyResultExt;
|
||||||
use crate::{ffi, Bound, PyAny, PyErr, PyResult, PyTypeCheck};
|
use crate::{ffi, Bound, PyAny, PyErr, PyResult, PyTypeCheck};
|
||||||
#[cfg(feature = "gil-refs")]
|
#[cfg(feature = "gil-refs")]
|
||||||
use crate::{AsPyPointer, PyDowncastError, PyNativeType};
|
use crate::{AsPyPointer, PyNativeType};
|
||||||
|
|
||||||
/// A Python iterator object.
|
/// 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
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::PyIterator;
|
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]
|
#[test]
|
||||||
#[cfg(feature = "macros")]
|
#[cfg(feature = "macros")]
|
||||||
fn python_class_not_iterator() {
|
fn python_class_not_iterator() {
|
||||||
|
|
|
@ -14,6 +14,12 @@ use crate::types::any::PyAnyMethods;
|
||||||
use crate::types::sequence::PySequenceMethods;
|
use crate::types::sequence::PySequenceMethods;
|
||||||
|
|
||||||
/// Represents a Python `list`.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyList(PyAny);
|
pub struct PyList(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,16 @@ use crate::type_object::PyTypeInfo;
|
||||||
use crate::types::any::PyAnyMethods;
|
use crate::types::any::PyAnyMethods;
|
||||||
use crate::types::{PyAny, PyDict, PySequence, PyType};
|
use crate::types::{PyAny, PyDict, PySequence, PyType};
|
||||||
#[cfg(feature = "gil-refs")]
|
#[cfg(feature = "gil-refs")]
|
||||||
use crate::{err::PyDowncastError, PyNativeType};
|
use crate::PyNativeType;
|
||||||
use crate::{ffi, Py, PyTypeCheck, Python, ToPyObject};
|
use crate::{ffi, Py, PyTypeCheck, Python, ToPyObject};
|
||||||
|
|
||||||
/// Represents a reference to a Python object supporting the mapping protocol.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyMapping(PyAny);
|
pub struct PyMapping(PyAny);
|
||||||
pyobject_native_type_named!(PyMapping);
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -439,16 +417,4 @@ mod tests {
|
||||||
assert_eq!(32 + 42 + 123, values_sum);
|
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};
|
use crate::{AsPyPointer, PyNativeType};
|
||||||
|
|
||||||
/// Represents a Python `memoryview`.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyMemoryView(PyAny);
|
pub struct PyMemoryView(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,12 @@ use {super::PyStringMethods, crate::PyNativeType};
|
||||||
|
|
||||||
/// Represents a Python [`module`][1] object.
|
/// 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.
|
/// As with all other Python objects, modules are first class citizens.
|
||||||
/// This means they can be passed to or returned from functions,
|
/// This means they can be passed to or returned from functions,
|
||||||
/// created dynamically, assigned to variables and so forth.
|
/// 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
|
/// make an *instance* of `Foo` (or *get* one for that matter, as we haven't exported
|
||||||
/// anything that can return instances of `Foo`).
|
/// 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<()>
|
pub fn add_class<T>(&self) -> PyResult<()>
|
||||||
where
|
where
|
||||||
T: PyClass,
|
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
|
/// make an *instance* of `Foo` (or *get* one for that matter, as we haven't exported
|
||||||
/// anything that can return instances of `Foo`).
|
/// 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<()>
|
fn add_class<T>(&self) -> PyResult<()>
|
||||||
where
|
where
|
||||||
T: PyClass;
|
T: PyClass;
|
||||||
|
|
|
@ -5,6 +5,9 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents the Python `None` object.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyNone(PyAny);
|
pub struct PyNone(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,9 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Represents the Python `NotImplemented` object.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyNotImplemented(PyAny);
|
pub struct PyNotImplemented(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@ use crate::{ffi, PyAny};
|
||||||
|
|
||||||
/// Represents a Python `int` object.
|
/// 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
|
/// You can usually avoid directly working with this type
|
||||||
/// by using [`ToPyObject`](crate::conversion::ToPyObject)
|
/// by using [`ToPyObject`](crate::conversion::ToPyObject)
|
||||||
/// and [`extract`](super::PyAnyMethods::extract)
|
/// and [`extract`](super::PyAnyMethods::extract)
|
||||||
|
|
|
@ -6,7 +6,8 @@ use crate::{PyAny, PyResult};
|
||||||
|
|
||||||
/// Represents a Python `super` object.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PySuper(PyAny);
|
pub struct PySuper(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,16 @@ use crate::sync::GILOnceCell;
|
||||||
use crate::type_object::PyTypeInfo;
|
use crate::type_object::PyTypeInfo;
|
||||||
use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType};
|
use crate::types::{any::PyAnyMethods, PyAny, PyList, PyString, PyTuple, PyType};
|
||||||
#[cfg(feature = "gil-refs")]
|
#[cfg(feature = "gil-refs")]
|
||||||
use crate::{err::PyDowncastError, PyNativeType};
|
use crate::PyNativeType;
|
||||||
use crate::{ffi, FromPyObject, Py, PyTypeCheck, Python, ToPyObject};
|
use crate::{ffi, FromPyObject, Py, PyTypeCheck, Python, ToPyObject};
|
||||||
|
|
||||||
/// Represents a reference to a Python object supporting the sequence protocol.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PySequence(PyAny);
|
pub struct PySequence(PyAny);
|
||||||
pyobject_native_type_named!(PySequence);
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::types::{PyAnyMethods, PyList, PySequence, PySequenceMethods, PyTuple};
|
use crate::types::{PyAnyMethods, PyList, PySequence, PySequenceMethods, PyTuple};
|
||||||
|
@ -1101,16 +1080,4 @@ mod tests {
|
||||||
assert!(seq_from.to_list().is_ok());
|
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 crate::{ffi, PyAny, PyObject, Python, ToPyObject};
|
||||||
use std::ptr;
|
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)]
|
#[repr(transparent)]
|
||||||
pub struct PySet(PyAny);
|
pub struct PySet(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,12 @@ use crate::{Bound, PyAny, PyObject, Python, ToPyObject};
|
||||||
|
|
||||||
/// Represents a Python `slice`.
|
/// 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.
|
/// Only `isize` indices supported at the moment by the `PySlice` object.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct PySlice(PyAny);
|
pub struct PySlice(PyAny);
|
||||||
|
|
|
@ -123,10 +123,11 @@ impl<'a> PyStringData<'a> {
|
||||||
|
|
||||||
/// Represents a Python `string` (a Unicode string object).
|
/// Represents a Python `string` (a Unicode string object).
|
||||||
///
|
///
|
||||||
/// This type is only seen inside PyO3's smart pointers as [`Py<PyString>`], [`Bound<'py, PyString>`],
|
/// Values of this type are accessed via PyO3's smart pointers, e.g. as
|
||||||
/// and [`Borrowed<'a, 'py, PyString>`].
|
/// [`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
|
/// # Equality
|
||||||
///
|
///
|
||||||
|
|
|
@ -5,6 +5,12 @@ use crate::PyNativeType;
|
||||||
use crate::{ffi, Bound, PyAny};
|
use crate::{ffi, Bound, PyAny};
|
||||||
|
|
||||||
/// Represents a Python traceback.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyTraceback(PyAny);
|
pub struct PyTraceback(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,11 @@ fn new_from_iter<'py>(
|
||||||
|
|
||||||
/// Represents a Python `tuple` object.
|
/// 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)]
|
#[repr(transparent)]
|
||||||
pub struct PyTuple(PyAny);
|
pub struct PyTuple(PyAny);
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,14 @@ use crate::PyNativeType;
|
||||||
use crate::{ffi, Bound, PyAny, PyTypeInfo, Python};
|
use crate::{ffi, Bound, PyAny, PyTypeInfo, Python};
|
||||||
|
|
||||||
use super::PyString;
|
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)]
|
#[repr(transparent)]
|
||||||
pub struct PyType(PyAny);
|
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_pymethod_names.rs");
|
||||||
t.compile_fail("tests/ui/invalid_pymodule_args.rs");
|
t.compile_fail("tests/ui/invalid_pymodule_args.rs");
|
||||||
t.compile_fail("tests/ui/reject_generics.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/deprecations.rs");
|
||||||
t.compile_fail("tests/ui/invalid_closure.rs");
|
t.compile_fail("tests/ui/invalid_closure.rs");
|
||||||
t.compile_fail("tests/ui/pyclass_send.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");
|
t.compile_fail("tests/ui/abi3_weakref.rs");
|
||||||
#[cfg(all(Py_LIMITED_API, not(Py_3_9)))]
|
#[cfg(all(Py_LIMITED_API, not(Py_3_9)))]
|
||||||
t.compile_fail("tests/ui/abi3_dict.rs");
|
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."
|
"Some description."
|
||||||
);
|
);
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(submodule)]
|
||||||
#[pyo3(submodule)]
|
|
||||||
mod external_submodule {}
|
mod external_submodule {}
|
||||||
|
|
||||||
/// A module written using declarative syntax.
|
/// A module written using declarative syntax.
|
||||||
|
@ -115,7 +114,7 @@ mod declarative_module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule(submodule)]
|
#[pymodule]
|
||||||
#[pyo3(module = "custom_root")]
|
#[pyo3(module = "custom_root")]
|
||||||
mod inner_custom_root {
|
mod inner_custom_root {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -144,8 +143,7 @@ mod declarative_submodule {
|
||||||
use super::{double, double_value};
|
use super::{double, double_value};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(name = "declarative_module_renamed")]
|
||||||
#[pyo3(name = "declarative_module_renamed")]
|
|
||||||
mod declarative_module2 {
|
mod declarative_module2 {
|
||||||
#[pymodule_export]
|
#[pymodule_export]
|
||||||
use super::double;
|
use super::double;
|
||||||
|
|
|
@ -138,8 +138,7 @@ fn test_module_with_explicit_py_arg() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule(name = "other_name")]
|
||||||
#[pyo3(name = "other_name")]
|
|
||||||
fn some_name(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn some_name(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add("other_name", "other_name")?;
|
m.add("other_name", "other_name")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -2,125 +2,11 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
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>> {
|
fn extract_options(obj: &Bound<'_, PyAny>) -> PyResult<Option<i32>> {
|
||||||
obj.extract()
|
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]
|
#[pyfunction]
|
||||||
#[pyo3(signature = (_i, _any=None))]
|
#[pyo3(signature = (_i, _any=None))]
|
||||||
fn pyfunction_option_1(_i: u32, _any: Option<i32>) {}
|
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]
|
#[pyclass]
|
||||||
pub enum SimpleEnumWithoutEq {
|
pub enum SimpleEnumWithoutEq {
|
||||||
VariamtA,
|
VariamtA,
|
||||||
VariantB,
|
VariantB,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
error: use of deprecated constant `pyo3::deprecations::PYMETHODS_NEW_DEPRECATED_FORM`: use `#[new]` instead of `#[__new__]`
|
error: use of deprecated constant `__pyfunction_pyfunction_option_2::SIGNATURE`: this function has implicit defaults for the trailing `Option<T>` arguments
|
||||||
--> tests/ui/deprecations.rs:12:7
|
= 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
|
note: the lint level is defined here
|
||||||
--> tests/ui/deprecations.rs:1:9
|
--> tests/ui/deprecations.rs:1:9
|
||||||
|
@ -10,144 +12,26 @@ note: the lint level is defined here
|
||||||
1 | #![deny(deprecated)]
|
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
|
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
|
= 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
|
= 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
|
--> tests/ui/deprecations.rs:18:4
|
||||||
|
|
|
|
||||||
132 | fn pyfunction_option_3(_i: u32, _any: Option<i32>, _foo: Option<String>) {}
|
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
|
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
|
= 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
|
= 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
|
--> tests/ui/deprecations.rs:21:4
|
||||||
|
|
|
|
||||||
135 | fn pyfunction_option_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.
|
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
|
--> tests/ui/deprecations.rs:28:1
|
||||||
|
|
|
|
||||||
197 | #[pyclass]
|
28 | #[pyclass]
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
|
|
||||||
= note: this error originates in the attribute macro `pyclass` (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)
|
||||||
|
|
||||||
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
|
|
||||||
|
|
|
||||||
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
|
|
||||||
|
|
|
||||||
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)
|
|
||||||
|
|
|
@ -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