Migrate to rust 2018
This commit is contained in:
parent
423b5d1099
commit
936f0153e8
|
@ -14,7 +14,7 @@ dist/
|
||||||
.eggs/
|
.eggs/
|
||||||
venv*
|
venv*
|
||||||
guide/book/
|
guide/book/
|
||||||
examples/*/py
|
examples/*/py*
|
||||||
|
|
||||||
*.so
|
*.so
|
||||||
*.out
|
*.out
|
||||||
|
|
|
@ -8,13 +8,16 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
* Added a `wrap_module!` macro similar to the existing `wrap_function!` macro. Only available on python 3
|
* Added a `wrap_pymodule!` macro similar to the existing `wrap_pyfunction!` macro. Only available on python 3
|
||||||
|
* Added support for cross compiling (e.g. to arm v7) by mtp401 in [#327](https://github.com/PyO3/pyo3/pull/327). See the "Cross Compiling" section in the "Building and Distribution" chapter of the guide for more details.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
* Renamed `add_function` to `add_wrapped` as it now also supports modules.
|
* Renamed `add_function` to `add_wrapped` as it now also supports modules.
|
||||||
* Renamed `#[pymodinit]` to `#[pymodule]`.
|
* Renamed `#[pymodinit]` to `#[pymodule]`.
|
||||||
* Renamed `py_exception` to `create_exception` and refactored the error macros.
|
* Renamed `py_exception` to `create_exception` and refactored the error macros.
|
||||||
|
* Renamed `wrap_function!` to `wrap_pyfunction!`
|
||||||
|
* Migrated to the 2018 edition
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3"
|
name = "pyo3"
|
||||||
version = "0.6.0-alpha.1"
|
version = "0.6.0-alpha.2"
|
||||||
description = "Bindings to Python interpreter"
|
description = "Bindings to Python interpreter"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
@ -12,6 +12,7 @@ categories = ["api-bindings", "development-tools::ffi"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
exclude = ["/.gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
|
exclude = ["/.gitignore", ".travis.yml", ".cargo/config", "appveyor.yml"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
travis-ci = { repository = "PyO3/pyo3", branch = "master" }
|
travis-ci = { repository = "PyO3/pyo3", branch = "master" }
|
||||||
|
@ -22,7 +23,7 @@ codecov = { repository = "PyO3/pyo3", branch = "master", service = "github" }
|
||||||
libc = "0.2.43"
|
libc = "0.2.43"
|
||||||
spin = "0.5.0"
|
spin = "0.5.0"
|
||||||
num-traits = "0.2.6"
|
num-traits = "0.2.6"
|
||||||
pyo3cls = { path = "pyo3cls", version = "=0.6.0-alpha.1" }
|
pyo3cls = { path = "pyo3cls", version = "=0.6.0-alpha.2" }
|
||||||
mashup = "0.1.9"
|
mashup = "0.1.9"
|
||||||
num-complex = { version = "0.2.1", optional = true }
|
num-complex = { version = "0.2.1", optional = true }
|
||||||
|
|
||||||
|
|
20
README.md
20
README.md
|
@ -31,19 +31,20 @@ sudo apt install python3-dev python-dev
|
||||||
|
|
||||||
Pyo3 can be used to generate a native python module.
|
Pyo3 can be used to generate a native python module.
|
||||||
|
|
||||||
**`Cargo.toml`:**
|
**`Cargo.toml`**
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[package]
|
[package]
|
||||||
name = "string-sum"
|
name = "string-sum"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "string_sum"
|
name = "string_sum"
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
|
||||||
[dependencies.pyo3]
|
[dependencies.pyo3]
|
||||||
version = "0.6.0-alpha.1"
|
version = "0.6.0-alpha.2"
|
||||||
features = ["extension-module"]
|
features = ["extension-module"]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -52,10 +53,8 @@ features = ["extension-module"]
|
||||||
```rust
|
```rust
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::wrap_pyfunction;
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
/// Formats the sum of two numbers as string
|
/// Formats the sum of two numbers as string
|
||||||
|
@ -66,7 +65,7 @@ fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
|
||||||
/// This module is a python module implemented in Rust.
|
/// This module is a python module implemented in Rust.
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
|
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_wrapped(wrap_function!(sum_as_string))?;
|
m.add_wrapped(wrap_pyfunction!(sum_as_string))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -92,7 +91,7 @@ Add `pyo3` this to your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
pyo3 = "0.5"
|
pyo3 = "0.6.0-alpha.2"
|
||||||
```
|
```
|
||||||
|
|
||||||
Example program displaying the value of `sys.version`:
|
Example program displaying the value of `sys.version`:
|
||||||
|
@ -100,8 +99,6 @@ Example program displaying the value of `sys.version`:
|
||||||
```rust
|
```rust
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
|
|
||||||
|
@ -110,11 +107,10 @@ fn main() -> PyResult<()> {
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let sys = py.import("sys")?;
|
let sys = py.import("sys")?;
|
||||||
let version: String = sys.get("version")?.extract()?;
|
let version: String = sys.get("version")?.extract()?;
|
||||||
|
|
||||||
let locals = PyDict::new(py);
|
let locals = PyDict::new(py);
|
||||||
locals.set_item("os", py.import("os")?)?;
|
locals.set_item("os", py.import("os")?)?;
|
||||||
let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract()?;
|
let code = "os.getenv('USER') or os.getenv('USERNAME') or 'Unknown'";
|
||||||
|
let user: String = py.eval(code, None, Some(&locals))?.extract()?;
|
||||||
println!("Hello {}, I'm Python {}", user, version);
|
println!("Hello {}, I'm Python {}", user, version);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
extern crate pyo3;
|
|
||||||
extern crate test;
|
|
||||||
use test::Bencher;
|
|
||||||
|
|
||||||
use pyo3::{prelude::*, types::IntoPyDict};
|
extern crate test;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::types::IntoPyDict;
|
||||||
|
use test::Bencher;
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn iter_dict(b: &mut Bencher) {
|
fn iter_dict(b: &mut Bencher) {
|
||||||
|
|
3
build.rs
3
build.rs
|
@ -1,6 +1,3 @@
|
||||||
extern crate regex;
|
|
||||||
extern crate version_check;
|
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::AsRef;
|
use std::convert::AsRef;
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
set -ex
|
set -ex
|
||||||
|
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
cargo test --features "$FEATURES"
|
cargo test --features "$FEATURES num-complex"
|
||||||
cargo clippy --features "$FEATURES"
|
cargo clippy --features "$FEATURES num-complex"
|
||||||
|
|
||||||
for example_dir in examples/*; do
|
for example_dir in examples/*; do
|
||||||
tox -c "$example_dir/tox.ini" -e py
|
tox -c "$example_dir/tox.ini" -e py
|
||||||
|
|
|
@ -3,6 +3,7 @@ authors = ["PyO3 Authors"]
|
||||||
name = "rustapi-module"
|
name = "rustapi-module"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "A Python wrapper for the Rust API for purposes of testing"
|
description = "A Python wrapper for the Rust API for purposes of testing"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,15 @@ use pyo3::types::{
|
||||||
PyDate, PyDateAccess, PyDateTime, PyDelta, PyDeltaAccess, PyTime, PyTimeAccess, PyTuple,
|
PyDate, PyDateAccess, PyDateTime, PyDelta, PyDeltaAccess, PyTime, PyTimeAccess, PyTuple,
|
||||||
PyTzInfo,
|
PyTzInfo,
|
||||||
};
|
};
|
||||||
|
use pyo3::wrap_pyfunction;
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn make_date(py: Python, year: i32, month: u8, day: u8) -> PyResult<Py<PyDate>> {
|
fn make_date(py: Python<'_>, year: i32, month: u8, day: u8) -> PyResult<Py<PyDate>> {
|
||||||
PyDate::new(py, year, month, day)
|
PyDate::new(py, year, month, day)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn get_date_tuple(py: Python, d: &PyDate) -> Py<PyTuple> {
|
fn get_date_tuple(py: Python<'_>, d: &PyDate) -> Py<PyTuple> {
|
||||||
PyTuple::new(
|
PyTuple::new(
|
||||||
py,
|
py,
|
||||||
&[d.get_year(), d.get_month() as i32, d.get_day() as i32],
|
&[d.get_year(), d.get_month() as i32, d.get_day() as i32],
|
||||||
|
@ -18,13 +19,13 @@ fn get_date_tuple(py: Python, d: &PyDate) -> Py<PyTuple> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn date_from_timestamp(py: Python, timestamp: i64) -> PyResult<Py<PyDate>> {
|
fn date_from_timestamp(py: Python<'_>, timestamp: i64) -> PyResult<Py<PyDate>> {
|
||||||
PyDate::from_timestamp(py, timestamp)
|
PyDate::from_timestamp(py, timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn make_time(
|
fn make_time(
|
||||||
py: Python,
|
py: Python<'_>,
|
||||||
hour: u8,
|
hour: u8,
|
||||||
minute: u8,
|
minute: u8,
|
||||||
second: u8,
|
second: u8,
|
||||||
|
@ -64,7 +65,7 @@ fn time_with_fold(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn get_time_tuple(py: Python, dt: &PyTime) -> Py<PyTuple> {
|
fn get_time_tuple(py: Python<'_>, dt: &PyTime) -> Py<PyTuple> {
|
||||||
PyTuple::new(
|
PyTuple::new(
|
||||||
py,
|
py,
|
||||||
&[
|
&[
|
||||||
|
@ -92,12 +93,12 @@ fn get_time_tuple_fold(py: Python, dt: &PyTime) -> Py<PyTuple> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn make_delta(py: Python, days: i32, seconds: i32, microseconds: i32) -> PyResult<Py<PyDelta>> {
|
fn make_delta(py: Python<'_>, days: i32, seconds: i32, microseconds: i32) -> PyResult<Py<PyDelta>> {
|
||||||
PyDelta::new(py, days, seconds, microseconds, true)
|
PyDelta::new(py, days, seconds, microseconds, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn get_delta_tuple(py: Python, delta: &PyDelta) -> Py<PyTuple> {
|
fn get_delta_tuple(py: Python<'_>, delta: &PyDelta) -> Py<PyTuple> {
|
||||||
PyTuple::new(
|
PyTuple::new(
|
||||||
py,
|
py,
|
||||||
&[
|
&[
|
||||||
|
@ -110,7 +111,7 @@ fn get_delta_tuple(py: Python, delta: &PyDelta) -> Py<PyTuple> {
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn make_datetime(
|
fn make_datetime(
|
||||||
py: Python,
|
py: Python<'_>,
|
||||||
year: i32,
|
year: i32,
|
||||||
month: u8,
|
month: u8,
|
||||||
day: u8,
|
day: u8,
|
||||||
|
@ -134,7 +135,7 @@ fn make_datetime(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn get_datetime_tuple(py: Python, dt: &PyDateTime) -> Py<PyTuple> {
|
fn get_datetime_tuple(py: Python<'_>, dt: &PyDateTime) -> Py<PyTuple> {
|
||||||
PyTuple::new(
|
PyTuple::new(
|
||||||
py,
|
py,
|
||||||
&[
|
&[
|
||||||
|
@ -168,7 +169,11 @@ fn get_datetime_tuple_fold(py: Python, dt: &PyDateTime) -> Py<PyTuple> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn datetime_from_timestamp(py: Python, ts: f64, tz: Option<&PyTzInfo>) -> PyResult<Py<PyDateTime>> {
|
fn datetime_from_timestamp(
|
||||||
|
py: Python<'_>,
|
||||||
|
ts: f64,
|
||||||
|
tz: Option<&PyTzInfo>,
|
||||||
|
) -> PyResult<Py<PyDateTime>> {
|
||||||
PyDateTime::from_timestamp(py, ts, tz)
|
PyDateTime::from_timestamp(py, ts, tz)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,41 +194,41 @@ impl TzClass {
|
||||||
obj.init(|| TzClass {})
|
obj.init(|| TzClass {})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn utcoffset(&self, py: Python, _dt: &PyDateTime) -> PyResult<Py<PyDelta>> {
|
fn utcoffset(&self, py: Python<'_>, _dt: &PyDateTime) -> PyResult<Py<PyDelta>> {
|
||||||
PyDelta::new(py, 0, 3600, 0, true)
|
PyDelta::new(py, 0, 3600, 0, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tzname(&self, _py: Python, _dt: &PyDateTime) -> PyResult<String> {
|
fn tzname(&self, _py: Python<'_>, _dt: &PyDateTime) -> PyResult<String> {
|
||||||
Ok(String::from("+01:00"))
|
Ok(String::from("+01:00"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dst(&self, _py: Python, _dt: &PyDateTime) -> PyResult<Option<&PyDelta>> {
|
fn dst(&self, _py: Python<'_>, _dt: &PyDateTime) -> PyResult<Option<&PyDelta>> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn datetime(_py: Python, m: &PyModule) -> PyResult<()> {
|
fn datetime(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_wrapped(wrap_function!(make_date))?;
|
m.add_wrapped(wrap_pyfunction!(make_date))?;
|
||||||
m.add_wrapped(wrap_function!(get_date_tuple))?;
|
m.add_wrapped(wrap_pyfunction!(get_date_tuple))?;
|
||||||
m.add_wrapped(wrap_function!(date_from_timestamp))?;
|
m.add_wrapped(wrap_pyfunction!(date_from_timestamp))?;
|
||||||
m.add_wrapped(wrap_function!(make_time))?;
|
m.add_wrapped(wrap_pyfunction!(make_time))?;
|
||||||
m.add_wrapped(wrap_function!(get_time_tuple))?;
|
m.add_wrapped(wrap_pyfunction!(get_time_tuple))?;
|
||||||
m.add_wrapped(wrap_function!(make_delta))?;
|
m.add_wrapped(wrap_pyfunction!(make_delta))?;
|
||||||
m.add_wrapped(wrap_function!(get_delta_tuple))?;
|
m.add_wrapped(wrap_pyfunction!(get_delta_tuple))?;
|
||||||
m.add_wrapped(wrap_function!(make_datetime))?;
|
m.add_wrapped(wrap_pyfunction!(make_datetime))?;
|
||||||
m.add_wrapped(wrap_function!(get_datetime_tuple))?;
|
m.add_wrapped(wrap_pyfunction!(get_datetime_tuple))?;
|
||||||
m.add_wrapped(wrap_function!(datetime_from_timestamp))?;
|
m.add_wrapped(wrap_pyfunction!(datetime_from_timestamp))?;
|
||||||
|
|
||||||
// Python 3.6+ functions
|
// Python 3.6+ functions
|
||||||
#[cfg(Py_3_6)]
|
#[cfg(Py_3_6)]
|
||||||
{
|
{
|
||||||
m.add_wrapped(wrap_function!(time_with_fold))?;
|
m.add_wrapped(wrap_pyfunction!(time_with_fold))?;
|
||||||
m.add_wrapped(wrap_function!(get_time_tuple_fold))?;
|
m.add_wrapped(wrap_pyfunction!(get_time_tuple_fold))?;
|
||||||
m.add_wrapped(wrap_function!(get_datetime_tuple_fold))?;
|
m.add_wrapped(wrap_pyfunction!(get_datetime_tuple_fold))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
m.add_wrapped(wrap_function!(issue_219))?;
|
m.add_wrapped(wrap_pyfunction!(issue_219))?;
|
||||||
|
|
||||||
m.add_class::<TzClass>()?;
|
m.add_class::<TzClass>()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use pyo3::prelude::*;
|
|
||||||
|
|
||||||
use pyo3::exceptions::RuntimeError;
|
use pyo3::exceptions::RuntimeError;
|
||||||
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn test_dict(_py: Python, m: &PyModule) -> PyResult<()> {
|
fn test_dict(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_class::<DictSize>()?;
|
m.add_class::<DictSize>()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -21,7 +20,7 @@ impl DictSize {
|
||||||
obj.init(|| DictSize { expected })
|
obj.init(|| DictSize { expected })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_dict(&mut self, _py: Python, dict: &PyDict) -> PyResult<u32> {
|
fn iter_dict(&mut self, _py: Python<'_>, dict: &PyDict) -> PyResult<u32> {
|
||||||
let mut seen = 0u32;
|
let mut seen = 0u32;
|
||||||
for (sym, values) in dict.iter() {
|
for (sym, values) in dict.iter() {
|
||||||
seen += 1;
|
seen += 1;
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
pub mod datetime;
|
pub mod datetime;
|
||||||
pub mod dict_iter;
|
pub mod dict_iter;
|
||||||
pub mod othermod;
|
pub mod othermod;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
//! The code below just tries to use the most important code generation paths
|
//! The code below just tries to use the most important code generation paths
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::wrap_pyfunction;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
pub struct ModClass {
|
pub struct ModClass {
|
||||||
|
@ -29,8 +30,8 @@ fn double(x: i32) -> i32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn othermod(_py: Python, m: &PyModule) -> PyResult<()> {
|
fn othermod(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_wrapped(wrap_function!(double))?;
|
m.add_wrapped(wrap_pyfunction!(double))?;
|
||||||
m.add_class::<ModClass>()?;
|
m.add_class::<ModClass>()?;
|
||||||
|
|
||||||
m.add("USIZE_MIN", usize::min_value())?;
|
m.add("USIZE_MIN", usize::min_value())?;
|
||||||
|
|
|
@ -14,7 +14,7 @@ impl Subclassable {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn subclassing(_py: Python, m: &PyModule) -> PyResult<()> {
|
fn subclassing(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_class::<Subclassable>()?;
|
m.add_class::<Subclassable>()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
authors = ["Messense Lv <messense@icloud.com>"]
|
authors = ["Messense Lv <messense@icloud.com>"]
|
||||||
name = "word-count"
|
name = "word-count"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rayon = "1.0.2"
|
rayon = "1.0.2"
|
||||||
|
|
|
@ -2,11 +2,8 @@
|
||||||
// https://github.com/tildeio/helix-website/blob/master/crates/word_count/src/lib.rs
|
// https://github.com/tildeio/helix-website/blob/master/crates/word_count/src/lib.rs
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate pyo3;
|
|
||||||
extern crate rayon;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::wrap_pyfunction;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -27,7 +24,7 @@ impl WordCounter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Searches for the word, parallelized by rayon
|
/// Searches for the word, parallelized by rayon
|
||||||
fn search(&self, py: Python, search: String) -> PyResult<usize> {
|
fn search(&self, py: Python<'_>, search: String) -> PyResult<usize> {
|
||||||
let contents = fs::read_to_string(&self.path)?;
|
let contents = fs::read_to_string(&self.path)?;
|
||||||
|
|
||||||
let count = py.allow_threads(move || {
|
let count = py.allow_threads(move || {
|
||||||
|
@ -79,8 +76,8 @@ fn count_line(line: &str, needle: &str) -> usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn word_count(_py: Python, m: &PyModule) -> PyResult<()> {
|
fn word_count(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_wrapped(wrap_function!(count_line))?;
|
m.add_wrapped(wrap_pyfunction!(count_line))?;
|
||||||
m.add_class::<WordCounter>()?;
|
m.add_class::<WordCounter>()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -6,7 +6,6 @@ To define python custom class, rust struct needs to be annotated with `#[pyclass
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
|
@ -45,7 +44,6 @@ attribute. Only the python `__new__` method can be specified, `__init__` is not
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
#
|
#
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# use pyo3::PyRawObject;
|
# use pyo3::PyRawObject;
|
||||||
|
|
||||||
|
@ -89,7 +87,6 @@ with value of custom class struct. Subclass must call parent's `__new__` method.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# use pyo3::PyRawObject;
|
# use pyo3::PyRawObject;
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
|
@ -140,7 +137,6 @@ attributes. i.e.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
# struct MyClass {
|
# struct MyClass {
|
||||||
|
@ -166,7 +162,6 @@ rust's special keywords like `type`.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
# struct MyClass {
|
# struct MyClass {
|
||||||
|
@ -196,7 +191,6 @@ If parameter is specified, it is used and property name. i.e.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
# struct MyClass {
|
# struct MyClass {
|
||||||
|
@ -225,7 +219,6 @@ For simple cases you can also define getters and setters in your Rust struct fie
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct MyClass {
|
struct MyClass {
|
||||||
|
@ -245,7 +238,6 @@ class method static methods, etc.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
# struct MyClass {
|
# struct MyClass {
|
||||||
|
@ -274,7 +266,6 @@ get injected by method wrapper. i.e
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
# struct MyClass {
|
# struct MyClass {
|
||||||
|
@ -299,7 +290,6 @@ with`#[classmethod]` attribute.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
# struct MyClass {
|
# struct MyClass {
|
||||||
|
@ -332,7 +322,6 @@ for some `T` that implements `IntoPyObject`.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
# struct MyClass {
|
# struct MyClass {
|
||||||
|
@ -356,7 +345,6 @@ with `#[call]` attribute. Arguments of the method are specified same as for inst
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
# struct MyClass {
|
# struct MyClass {
|
||||||
|
@ -400,7 +388,6 @@ Each parameter could one of following type:
|
||||||
Example:
|
Example:
|
||||||
```rust
|
```rust
|
||||||
# #![feature(specialization)]
|
# #![feature(specialization)]
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
#
|
#
|
||||||
# #[pyclass]
|
# #[pyclass]
|
||||||
|
@ -429,7 +416,7 @@ with `#[pyproto]` attribute.
|
||||||
|
|
||||||
### Basic object customization
|
### Basic object customization
|
||||||
|
|
||||||
[`PyObjectProtocol`](https://docs.rs/pyo3/0.5.2/class/basic/trait.PyObjectProtocol.html) trait provide several basic customizations.
|
[`PyObjectProtocol`](https://docs.rs/pyo3/0.6.0-alpha.2/class/basic/trait.PyObjectProtocol.html) trait provide several basic customizations.
|
||||||
|
|
||||||
#### Attribute access
|
#### Attribute access
|
||||||
|
|
||||||
|
@ -493,7 +480,7 @@ Each methods corresponds to python's `self.attr`, `self.attr = value` and `del s
|
||||||
If your type owns references to other python objects, you will need to
|
If your type owns references to other python objects, you will need to
|
||||||
integrate with Python's garbage collector so that the GC is aware of
|
integrate with Python's garbage collector so that the GC is aware of
|
||||||
those references.
|
those references.
|
||||||
To do this, implement [`PyGCProtocol`](https://docs.rs/pyo3/0.5.2/class/gc/trait.PyGCProtocol.html) trait for your struct.
|
To do this, implement [`PyGCProtocol`](https://docs.rs/pyo3/0.6.0-alpha.2/class/gc/trait.PyGCProtocol.html) trait for your struct.
|
||||||
It includes two methods `__traverse__` and `__clear__`.
|
It includes two methods `__traverse__` and `__clear__`.
|
||||||
These correspond to the slots `tp_traverse` and `tp_clear` in the Python C API.
|
These correspond to the slots `tp_traverse` and `tp_clear` in the Python C API.
|
||||||
`__traverse__` must call `visit.call()` for each reference to another python object.
|
`__traverse__` must call `visit.call()` for each reference to another python object.
|
||||||
|
@ -503,7 +490,6 @@ as every cycle must contain at least one mutable reference.
|
||||||
Example:
|
Example:
|
||||||
```rust
|
```rust
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
@ -540,7 +526,7 @@ collector, and it is possible to track them with `gc` module methods.
|
||||||
### Iterator Types
|
### Iterator Types
|
||||||
|
|
||||||
Iterators can be defined using the
|
Iterators can be defined using the
|
||||||
[`PyIterProtocol`](https://docs.rs/pyo3/0.5.2/class/iter/trait.PyIterProtocol.html) trait.
|
[`PyIterProtocol`](https://docs.rs/pyo3/0.6.0-alpha.2/class/iter/trait.PyIterProtocol.html) trait.
|
||||||
It includes two methods `__iter__` and `__next__`:
|
It includes two methods `__iter__` and `__next__`:
|
||||||
* `fn __iter__(&mut self) -> PyResult<impl IntoPyObject>`
|
* `fn __iter__(&mut self) -> PyResult<impl IntoPyObject>`
|
||||||
* `fn __next__(&mut self) -> PyResult<Option<impl IntoPyObject>>`
|
* `fn __next__(&mut self) -> PyResult<Option<impl IntoPyObject>>`
|
||||||
|
@ -552,8 +538,6 @@ Example:
|
||||||
```rust
|
```rust
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
|
|
|
@ -17,7 +17,6 @@ The easiest way to convert a python object to a rust value is using `.extract()?
|
||||||
For example, [`IntoPyTuple`][IntoPyTuple] trait is implemented for `()` so that you can convert it into a empty [`PyTuple`][PyTuple]
|
For example, [`IntoPyTuple`][IntoPyTuple] trait is implemented for `()` so that you can convert it into a empty [`PyTuple`][PyTuple]
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate pyo3;
|
|
||||||
use pyo3::{Python, IntoPyTuple};
|
use pyo3::{Python, IntoPyTuple};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -43,16 +42,15 @@ Both methods accept `args` and `kwargs` arguments. `args` argument is generate o
|
||||||
rust tuple with up to 10 elements. Or `NoArgs` object which represents empty tuple object.
|
rust tuple with up to 10 elements. Or `NoArgs` object which represents empty tuple object.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate pyo3;
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
# struct SomeObject;
|
struct SomeObject;
|
||||||
# impl SomeObject {
|
impl SomeObject {
|
||||||
# fn new(py: Python) -> PyObject {
|
fn new(py: Python) -> PyObject {
|
||||||
# pyo3::PyDict::new(py).to_object(py)
|
pyo3::PyDict::new(py).to_object(py)
|
||||||
# }
|
}
|
||||||
# }
|
}
|
||||||
#
|
|
||||||
fn main() {
|
fn main() {
|
||||||
# let arg1 = "arg1";
|
# let arg1 = "arg1";
|
||||||
# let arg2 = "arg2";
|
# let arg2 = "arg2";
|
||||||
|
@ -80,22 +78,23 @@ fn main() {
|
||||||
[`IntoPyDict`][IntoPyDict] trait to convert other dict-like containers, e.g. `HashMap`, `BTreeMap` as well as tuples with up to 10 elements and `Vec`s where each element is a two element tuple.
|
[`IntoPyDict`][IntoPyDict] trait to convert other dict-like containers, e.g. `HashMap`, `BTreeMap` as well as tuples with up to 10 elements and `Vec`s where each element is a two element tuple.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::types::{IntoPyDict, PyDict};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
struct SomeObject;
|
||||||
|
|
||||||
|
impl SomeObject {
|
||||||
|
fn new(py: Python) -> PyObject {
|
||||||
|
PyDict::new(py).to_object(py)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# struct SomeObject;
|
|
||||||
# impl SomeObject {
|
|
||||||
# fn new(py: Python) -> PyObject {
|
|
||||||
# pyo3::PyDict::new(py).to_object(py)
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
fn main() {
|
fn main() {
|
||||||
# let key1 = "key1";
|
let key1 = "key1";
|
||||||
# let val1 = 1;
|
let val1 = 1;
|
||||||
# let key2 = "key2";
|
let key2 = "key2";
|
||||||
# let val2 = 2;
|
let val2 = 2;
|
||||||
|
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
|
@ -105,26 +104,25 @@ fn main() {
|
||||||
// call object with PyDict
|
// call object with PyDict
|
||||||
let kwargs = PyDict::new(py);
|
let kwargs = PyDict::new(py);
|
||||||
kwargs.set_item(key1, val1);
|
kwargs.set_item(key1, val1);
|
||||||
obj.call(py, NoArgs, kwargs);
|
obj.call(py, NoArgs, Some(kwargs));
|
||||||
|
|
||||||
// pass arguments as rust tuple
|
// pass arguments as Vec
|
||||||
let kwargs = ((key1, val1), (key2, val2));
|
let kwargs = vec![(key1, val1), (key2, val2)];
|
||||||
obj.call(py, NoArgs, kwargs);
|
obj.call(py, NoArgs, Some(kwargs.into_py_dict(py)));
|
||||||
|
|
||||||
// pass arguments as HashMap
|
// pass arguments as HashMap
|
||||||
let mut kwargs = HashMap::<&str, i32>::new();
|
let mut kwargs = HashMap::<&str, i32>::new();
|
||||||
kwargs.insert(key1, 1);
|
kwargs.insert(key1, 1);
|
||||||
obj.call(py, NoArgs, kwargs);
|
obj.call(py, NoArgs, Some(kwargs.into_py_dict(py)));
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
[`ToPyObject`]: https://docs.rs/pyo3/0.5.2/trait.ToPyObject.html
|
[`ToPyObject`]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.ToPyObject.html
|
||||||
[IntoPyObject]: https://docs.rs/pyo3/0.5.2/trait.IntoPyObject.html
|
[IntoPyObject]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.IntoPyObject.html
|
||||||
[PyObject]: https://docs.rs/pyo3/0.5.2/struct.PyObject.html
|
[PyObject]: https://docs.rs/pyo3/0.6.0-alpha.2/struct.PyObject.html
|
||||||
[IntoPyTuple]: https://docs.rs/pyo3/0.5.2/trait.IntoPyTuple.html
|
[IntoPyTuple]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.IntoPyTuple.html
|
||||||
[PyTuple]: https://docs.rs/pyo3/0.5.2/struct.PyTuple.html
|
[PyTuple]: https://docs.rs/pyo3/0.6.0-alpha.2/struct.PyTuple.html
|
||||||
[ObjectProtocol]: https://docs.rs/pyo3/0.5.2/trait.ObjectProtocol.html
|
[ObjectProtocol]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.ObjectProtocol.html
|
||||||
[IntoPyDict]: https://docs.rs/pyo3/0.5.2/trait.IntoPyDict.html
|
[IntoPyDict]: https://docs.rs/pyo3/0.6.0-alpha.2/trait.IntoPyDict.html
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
You can use the `create_exception!` macro to define a new exception type:
|
You can use the `create_exception!` macro to define a new exception type:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use] extern crate pyo3;
|
use pyo3::import_exception;
|
||||||
|
|
||||||
create_exception!(module, MyError, pyo3::exceptions::Exception);
|
create_exception!(module, MyError, pyo3::exceptions::Exception);
|
||||||
```
|
```
|
||||||
|
@ -16,9 +16,8 @@ create_exception!(module, MyError, pyo3::exceptions::Exception);
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use] extern crate pyo3;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::create_exception;
|
||||||
use pyo3::Python;
|
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
use pyo3::exceptions::Exception;
|
use pyo3::exceptions::Exception;
|
||||||
|
|
||||||
|
@ -41,8 +40,6 @@ fn main() {
|
||||||
To raise an exception, first you need to obtain an exception type and construct a new [`PyErr`](https://docs.rs/pyo3/0.2.7/struct.PyErr.html), then call [`PyErr::restore()`](https://docs.rs/pyo3/0.2.7/struct.PyErr.html#method.restore) method to write the exception back to the Python interpreter's global state.
|
To raise an exception, first you need to obtain an exception type and construct a new [`PyErr`](https://docs.rs/pyo3/0.2.7/struct.PyErr.html), then call [`PyErr::restore()`](https://docs.rs/pyo3/0.2.7/struct.PyErr.html#method.restore) method to write the exception back to the Python interpreter's global state.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::{Python, PyErr, exc};
|
use pyo3::{Python, PyErr, exc};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -66,7 +63,6 @@ has corresponding rust type, exceptions defined by `create_exception!` and `impo
|
||||||
have rust type as well.
|
have rust type as well.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# fn check_for_error() -> bool {false}
|
# fn check_for_error() -> bool {false}
|
||||||
fn my_func(arg: PyObject) -> PyResult<()> {
|
fn my_func(arg: PyObject) -> PyResult<()> {
|
||||||
|
@ -84,8 +80,6 @@ Python has an [`isinstance`](https://docs.python.org/3/library/functions.html#is
|
||||||
in `PyO3` there is a [`Python::is_instance()`](https://docs.rs/pyo3/0.2.7/struct.Python.html#method.is_instance) method which does the same thing.
|
in `PyO3` there is a [`Python::is_instance()`](https://docs.rs/pyo3/0.2.7/struct.Python.html#method.is_instance) method which does the same thing.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::{Python, PyBool, PyList};
|
use pyo3::{Python, PyBool, PyList};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -103,7 +97,6 @@ fn main() {
|
||||||
To check the type of an exception, you can simply do:
|
To check the type of an exception, you can simply do:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# extern crate pyo3;
|
|
||||||
# use pyo3::prelude::*;
|
# use pyo3::prelude::*;
|
||||||
# fn main() {
|
# fn main() {
|
||||||
# let gil = Python::acquire_gil();
|
# let gil = Python::acquire_gil();
|
||||||
|
@ -134,7 +127,6 @@ until `Python` object is available.
|
||||||
|
|
||||||
```rust,ignore
|
```rust,ignore
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use std::net::TcpListener;
|
use std::net::TcpListener;
|
||||||
use pyo3::{PyErr, PyResult, exc};
|
use pyo3::{PyErr, PyResult, exc};
|
||||||
|
@ -157,7 +149,6 @@ The code snippet above will raise `OSError` in Python if `TcpListener::bind()` r
|
||||||
types so `try!` macro or `?` operator can be used.
|
types so `try!` macro or `?` operator can be used.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
# extern crate pyo3;
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
fn parse_int(s: String) -> PyResult<usize> {
|
fn parse_int(s: String) -> PyResult<usize> {
|
||||||
|
@ -175,8 +166,8 @@ It is possible to use exception defined in python code as native rust types.
|
||||||
for that exception.
|
for that exception.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#[macro_use] extern crate pyo3;
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::import_exception;
|
||||||
|
|
||||||
import_exception!(io, UnsupportedOperation);
|
import_exception!(io, UnsupportedOperation);
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,8 @@ the function to a [module](./module.md)
|
||||||
One way is defining the function in the module definition.
|
One way is defining the function in the module definition.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![feature(proc_macro)]
|
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn rust2py(py: Python, m: &PyModule) -> PyResult<()> {
|
fn rust2py(py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
|
||||||
|
@ -36,9 +32,8 @@ as third.
|
||||||
```rust
|
```rust
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate pyo3;
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::wrap_pyfunction;
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn double(x: usize) -> usize {
|
fn double(x: usize) -> usize {
|
||||||
|
@ -47,7 +42,7 @@ fn double(x: usize) -> usize {
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
|
fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_wrapped(wrap_function!(double)).unwrap();
|
m.add_wrapped(wrap_pyfunction!(double)).unwrap();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -95,5 +90,5 @@ You can use `ObjectProtocol::is_callable` to check if you got a callable, which
|
||||||
|
|
||||||
### Calling rust `Fn`s in python
|
### Calling rust `Fn`s in python
|
||||||
|
|
||||||
If you have a static function, you can expose it with `#[pyfunction]` and use `wrap_function!` to get the corresponding `PyObject`. For dynamic functions, e.g. lambda and functions that were passed as arguments, you must put them in some kind of owned container, e.g. a box. (Long-Term a special container similar to wasm-bindgen's `Closure` should take care of that). You can than use a `#[pyclass]` struct with that container as field as a way to pass the function over the ffi-barrier. You can even make that class callable with `__call__` so it looks like a function in python code.
|
If you have a static function, you can expose it with `#[pyfunction]` and use `wrap_pyfunction!` to get the corresponding `PyObject`. For dynamic functions, e.g. lambda and functions that were passed as arguments, you must put them in some kind of owned container, e.g. a box. (Long-Term a special container similar to wasm-bindgen's `Closure` should take care of that). You can than use a `#[pyclass]` struct with that container as field as a way to pass the function over the ffi-barrier. You can even make that class callable with `__call__` so it looks like a function in python code.
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,8 @@ features = ["extension-module"]
|
||||||
```rust
|
```rust
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::wrap_pyfunction;
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
/// Formats the sum of two numbers as string
|
/// Formats the sum of two numbers as string
|
||||||
|
@ -61,7 +59,7 @@ fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
|
||||||
/// This module is a python module implemented in Rust.
|
/// This module is a python module implemented in Rust.
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
|
fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
m.add_wrapped(wrap_function!(sum_as_string))?;
|
m.add_wrapped(wrap_pyfunction!(sum_as_string))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -95,8 +93,6 @@ Example program displaying the value of `sys.version`:
|
||||||
```rust
|
```rust
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
|
|
||||||
|
|
|
@ -3,10 +3,7 @@
|
||||||
As shown in the Getting Started chapter, you can create a module as follows:
|
As shown in the Getting Started chapter, you can create a module as follows:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
#![feature(proc_macro)]
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
use pyo3::{PyResult, Python, PyModule};
|
|
||||||
|
|
||||||
// add bindings to the generated python module
|
// add bindings to the generated python module
|
||||||
// N.B: names: "librust2py" must be the name of the `.so` or `.pyd` file
|
// N.B: names: "librust2py" must be the name of the `.so` or `.pyd` file
|
||||||
|
@ -62,20 +59,20 @@ fn subfunction() -> String {
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn submodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
fn submodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||||
module.add_wrapped(wrap_function!(subfunction))?;
|
module.add_wrapped(wrap_pyfunction!(subfunction))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn supermodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
fn supermodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||||
module.add_wrapped(wrap_module!(submodule))?;
|
module.add_wrapped(wrap_pymodule!(submodule))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn nested_call() {
|
fn nested_call() {
|
||||||
let gil = GILGuard::acquire();
|
let gil = GILGuard::acquire();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let supermodule = wrap_module!(supermodule)(py);
|
let supermodule = wrap_pymodule!(supermodule)(py);
|
||||||
ctx.set_item("supermodule", supermodule);
|
ctx.set_item("supermodule", supermodule);
|
||||||
|
|
||||||
py.run("assert supermodule.submodule.subfuntion() == 'Subfunction'", None, Some(&ctx)).unwrap();
|
py.run("assert supermodule.submodule.subfuntion() == 'Subfunction'", None, Some(&ctx)).unwrap();
|
||||||
|
|
|
@ -27,8 +27,6 @@ py_class!(class MyClass |py| {
|
||||||
```rust
|
```rust
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::PyRawObject;
|
use pyo3::PyRawObject;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3-derive-backend"
|
name = "pyo3-derive-backend"
|
||||||
version = "0.6.0-alpha.1"
|
version = "0.6.0-alpha.2"
|
||||||
description = "Code generation for PyO3 package"
|
description = "Code generation for PyO3 package"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
@ -8,6 +8,7 @@ homepage = "https://github.com/pyo3/pyo3"
|
||||||
repository = "https://github.com/pyo3/pyo3"
|
repository = "https://github.com/pyo3/pyo3"
|
||||||
categories = ["api-bindings", "development-tools::ffi"]
|
categories = ["api-bindings", "development-tools::ffi"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quote = "0.6.9"
|
quote = "0.6.9"
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
|
use quote::quote;
|
||||||
use syn;
|
use syn;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -179,12 +181,12 @@ pub fn parse_arguments(items: &[syn::NestedMeta]) -> Vec<Argument> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
use args::{parse_arguments, Argument};
|
use crate::args::{parse_arguments, Argument};
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use syn;
|
use syn;
|
||||||
|
|
||||||
fn items(s: TokenStream) -> Vec<syn::NestedMeta> {
|
fn items(s: TokenStream) -> Vec<syn::NestedMeta> {
|
||||||
let dummy: syn::ItemFn = parse_quote! {#s fn dummy() {}};
|
let dummy: syn::ItemFn = syn::parse_quote! {#s fn dummy() {}};
|
||||||
match dummy.attrs[0].interpret_meta() {
|
match dummy.attrs[0].interpret_meta() {
|
||||||
Some(syn::Meta::List(syn::MetaList { nested, .. })) => {
|
Some(syn::Meta::List(syn::MetaList { nested, .. })) => {
|
||||||
nested.iter().map(Clone::clone).collect()
|
nested.iter().map(Clone::clone).collect()
|
||||||
|
@ -208,9 +210,9 @@ mod test {
|
||||||
let args = parse_arguments(&items(quote! {#[args(test1, test2, test3="None")]}));
|
let args = parse_arguments(&items(quote! {#[args(test1, test2, test3="None")]}));
|
||||||
assert!(
|
assert!(
|
||||||
args == vec![
|
args == vec![
|
||||||
Argument::Arg(parse_quote! {test1}, None),
|
Argument::Arg(syn::parse_quote! {test1}, None),
|
||||||
Argument::Arg(parse_quote! {test2}, None),
|
Argument::Arg(syn::parse_quote! {test2}, None),
|
||||||
Argument::Arg(parse_quote! {test3}, Some("None".to_owned())),
|
Argument::Arg(syn::parse_quote! {test3}, Some("None".to_owned())),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -222,10 +224,10 @@ mod test {
|
||||||
));
|
));
|
||||||
assert!(
|
assert!(
|
||||||
args == vec![
|
args == vec![
|
||||||
Argument::Arg(parse_quote! {test1}, None),
|
Argument::Arg(syn::parse_quote! {test1}, None),
|
||||||
Argument::Arg(parse_quote! {test2}, Some("None".to_owned())),
|
Argument::Arg(syn::parse_quote! {test2}, Some("None".to_owned())),
|
||||||
Argument::VarArgsSeparator,
|
Argument::VarArgsSeparator,
|
||||||
Argument::Kwarg(parse_quote! {test3}, "None".to_owned()),
|
Argument::Kwarg(syn::parse_quote! {test3}, "None".to_owned()),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -237,11 +239,11 @@ mod test {
|
||||||
));
|
));
|
||||||
assert!(
|
assert!(
|
||||||
args == vec![
|
args == vec![
|
||||||
Argument::Arg(parse_quote! {test1}, None),
|
Argument::Arg(syn::parse_quote! {test1}, None),
|
||||||
Argument::Arg(parse_quote! {test2}, Some("None".to_owned())),
|
Argument::Arg(syn::parse_quote! {test2}, Some("None".to_owned())),
|
||||||
Argument::VarArgs(parse_quote! {args}),
|
Argument::VarArgs(syn::parse_quote! {args}),
|
||||||
Argument::Kwarg(parse_quote! {test3}, "None".to_owned()),
|
Argument::Kwarg(syn::parse_quote! {test3}, "None".to_owned()),
|
||||||
Argument::KeywordArgs(parse_quote! {kwargs}),
|
Argument::KeywordArgs(syn::parse_quote! {kwargs}),
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
use func::MethodProto;
|
use crate::func::MethodProto;
|
||||||
|
|
||||||
pub struct Proto {
|
pub struct Proto {
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
use crate::utils::print_err;
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
use quote::quote;
|
||||||
use syn;
|
use syn;
|
||||||
use utils::print_err;
|
|
||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// Add lifetime support for args with Rptr
|
// Add lifetime support for args with Rptr
|
||||||
|
@ -87,7 +88,7 @@ pub fn impl_method_proto(
|
||||||
let p: syn::Path = syn::parse_str(proto).unwrap();
|
let p: syn::Path = syn::parse_str(proto).unwrap();
|
||||||
let (ty, succ) = get_res_success(ty);
|
let (ty, succ) = get_res_success(ty);
|
||||||
|
|
||||||
let tmp: syn::ItemFn = parse_quote! {
|
let tmp: syn::ItemFn = syn::parse_quote! {
|
||||||
fn test(&self) -> <#cls as #p<'p>>::Result {}
|
fn test(&self) -> <#cls as #p<'p>>::Result {}
|
||||||
};
|
};
|
||||||
sig.decl.output = tmp.decl.output;
|
sig.decl.output = tmp.decl.output;
|
||||||
|
@ -124,11 +125,11 @@ pub fn impl_method_proto(
|
||||||
let arg_ty = get_arg_ty(sig, 1);
|
let arg_ty = get_arg_ty(sig, 1);
|
||||||
let (ty, succ) = get_res_success(ty);
|
let (ty, succ) = get_res_success(ty);
|
||||||
|
|
||||||
let tmp = extract_decl(parse_quote! {
|
let tmp = extract_decl(syn::parse_quote! {
|
||||||
fn test(&self,arg: <#cls as #p<'p>>::#arg_name)-> <#cls as #p<'p>>::Result {}
|
fn test(&self,arg: <#cls as #p<'p>>::#arg_name)-> <#cls as #p<'p>>::Result {}
|
||||||
});
|
});
|
||||||
|
|
||||||
let tmp2 = extract_decl(parse_quote! {
|
let tmp2 = extract_decl(syn::parse_quote! {
|
||||||
fn test( &self, arg: Option<<#cls as #p<'p>>::#arg_name>) -> <#cls as #p<'p>>::Result {}
|
fn test( &self, arg: Option<<#cls as #p<'p>>::#arg_name>) -> <#cls as #p<'p>>::Result {}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -171,11 +172,11 @@ pub fn impl_method_proto(
|
||||||
let (ty, succ) = get_res_success(ty);
|
let (ty, succ) = get_res_success(ty);
|
||||||
|
|
||||||
// rewrite ty
|
// rewrite ty
|
||||||
let tmp = extract_decl(parse_quote! {fn test(
|
let tmp = extract_decl(syn::parse_quote! {fn test(
|
||||||
arg1: <#cls as #p<'p>>::#arg1_name,
|
arg1: <#cls as #p<'p>>::#arg1_name,
|
||||||
arg2: <#cls as #p<'p>>::#arg2_name)
|
arg2: <#cls as #p<'p>>::#arg2_name)
|
||||||
-> <#cls as #p<'p>>::Result {}});
|
-> <#cls as #p<'p>>::Result {}});
|
||||||
let tmp2 = extract_decl(parse_quote! {fn test(
|
let tmp2 = extract_decl(syn::parse_quote! {fn test(
|
||||||
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
|
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
|
||||||
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
|
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
|
||||||
-> <#cls as #p<'p>>::Result {}});
|
-> <#cls as #p<'p>>::Result {}});
|
||||||
|
@ -220,12 +221,12 @@ pub fn impl_method_proto(
|
||||||
let (ty, succ) = get_res_success(ty);
|
let (ty, succ) = get_res_success(ty);
|
||||||
|
|
||||||
// rewrite ty
|
// rewrite ty
|
||||||
let tmp = extract_decl(parse_quote! {fn test(
|
let tmp = extract_decl(syn::parse_quote! {fn test(
|
||||||
&self,
|
&self,
|
||||||
arg1: <#cls as #p<'p>>::#arg1_name,
|
arg1: <#cls as #p<'p>>::#arg1_name,
|
||||||
arg2: <#cls as #p<'p>>::#arg2_name)
|
arg2: <#cls as #p<'p>>::#arg2_name)
|
||||||
-> <#cls as #p<'p>>::Result {}});
|
-> <#cls as #p<'p>>::Result {}});
|
||||||
let tmp2 = extract_decl(parse_quote! {fn test(
|
let tmp2 = extract_decl(syn::parse_quote! {fn test(
|
||||||
&self,
|
&self,
|
||||||
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
|
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
|
||||||
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
|
arg2: Option<<#cls as #p<'p>>::#arg2_name>)
|
||||||
|
@ -275,12 +276,12 @@ pub fn impl_method_proto(
|
||||||
let (ty, succ) = get_res_success(ty);
|
let (ty, succ) = get_res_success(ty);
|
||||||
|
|
||||||
// rewrite ty
|
// rewrite ty
|
||||||
let tmp = extract_decl(parse_quote! {fn test(
|
let tmp = extract_decl(syn::parse_quote! {fn test(
|
||||||
arg1: <#cls as #p<'p>>::#arg1_name,
|
arg1: <#cls as #p<'p>>::#arg1_name,
|
||||||
arg2: <#cls as #p<'p>>::#arg2_name,
|
arg2: <#cls as #p<'p>>::#arg2_name,
|
||||||
arg3: <#cls as #p<'p>>::#arg3_name)
|
arg3: <#cls as #p<'p>>::#arg3_name)
|
||||||
-> <#cls as #p<'p>>::Result {}});
|
-> <#cls as #p<'p>>::Result {}});
|
||||||
let tmp2 = extract_decl(parse_quote! {fn test(
|
let tmp2 = extract_decl(syn::parse_quote! {fn test(
|
||||||
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
|
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
|
||||||
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
|
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
|
||||||
arg3: Option<<#cls as #p<'p>>::#arg3_name>)
|
arg3: Option<<#cls as #p<'p>>::#arg3_name>)
|
||||||
|
@ -331,13 +332,13 @@ pub fn impl_method_proto(
|
||||||
let (ty, succ) = get_res_success(ty);
|
let (ty, succ) = get_res_success(ty);
|
||||||
|
|
||||||
// rewrite ty
|
// rewrite ty
|
||||||
let tmp = extract_decl(parse_quote! {fn test(
|
let tmp = extract_decl(syn::parse_quote! {fn test(
|
||||||
&self,
|
&self,
|
||||||
arg1: <#cls as #p<'p>>::#arg1_name,
|
arg1: <#cls as #p<'p>>::#arg1_name,
|
||||||
arg2: <#cls as #p<'p>>::#arg2_name,
|
arg2: <#cls as #p<'p>>::#arg2_name,
|
||||||
arg3: <#cls as #p<'p>>::#arg3_name)
|
arg3: <#cls as #p<'p>>::#arg3_name)
|
||||||
-> <#cls as #p<'p>>::Result {}});
|
-> <#cls as #p<'p>>::Result {}});
|
||||||
let tmp2 = extract_decl(parse_quote! {fn test(
|
let tmp2 = extract_decl(syn::parse_quote! {fn test(
|
||||||
&self,
|
&self,
|
||||||
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
|
arg1: Option<<#cls as #p<'p>>::#arg1_name>,
|
||||||
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
|
arg2: Option<<#cls as #p<'p>>::#arg2_name>,
|
||||||
|
@ -395,7 +396,7 @@ fn get_arg_ty(sig: &syn::MethodSig, idx: usize) -> syn::Type {
|
||||||
|
|
||||||
// Add a lifetime if there is none
|
// Add a lifetime if there is none
|
||||||
if let syn::Type::Reference(ref mut r) = ty {
|
if let syn::Type::Reference(ref mut r) = ty {
|
||||||
r.lifetime.get_or_insert(parse_quote! {'p});
|
r.lifetime.get_or_insert(syn::parse_quote! {'p});
|
||||||
}
|
}
|
||||||
|
|
||||||
ty
|
ty
|
||||||
|
@ -492,7 +493,7 @@ fn modify_arg_ty(sig: &mut syn::MethodSig, idx: usize, decl1: &syn::FnDecl, decl
|
||||||
|
|
||||||
fn modify_self_ty(sig: &mut syn::MethodSig) {
|
fn modify_self_ty(sig: &mut syn::MethodSig) {
|
||||||
if let syn::FnArg::SelfRef(ref mut r) = sig.decl.inputs[0] {
|
if let syn::FnArg::SelfRef(ref mut r) = sig.decl.inputs[0] {
|
||||||
r.lifetime = Some(parse_quote! {'p});
|
r.lifetime = Some(syn::parse_quote! {'p});
|
||||||
} else {
|
} else {
|
||||||
panic!("not supported")
|
panic!("not supported")
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,13 +3,6 @@
|
||||||
|
|
||||||
#![recursion_limit = "1024"]
|
#![recursion_limit = "1024"]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate quote;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate syn;
|
|
||||||
extern crate proc_macro;
|
|
||||||
extern crate proc_macro2;
|
|
||||||
|
|
||||||
pub mod args;
|
pub mod args;
|
||||||
pub mod defs;
|
pub mod defs;
|
||||||
pub mod func;
|
pub mod func;
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
use syn;
|
use crate::args::{parse_arguments, Argument};
|
||||||
|
|
||||||
use args::{parse_arguments, Argument};
|
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
|
use quote::quote;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
|
use syn;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
pub struct FnArg<'a> {
|
pub struct FnArg<'a> {
|
||||||
|
@ -39,7 +39,7 @@ pub struct FnSpec<'a> {
|
||||||
|
|
||||||
pub fn get_return_info(output: &syn::ReturnType) -> syn::Type {
|
pub fn get_return_info(output: &syn::ReturnType) -> syn::Type {
|
||||||
match output {
|
match output {
|
||||||
syn::ReturnType::Default => syn::Type::Infer(parse_quote! {_}),
|
syn::ReturnType::Default => syn::Type::Infer(syn::parse_quote! {_}),
|
||||||
syn::ReturnType::Type(_, ref ty) => *ty.clone(),
|
syn::ReturnType::Type(_, ref ty) => *ty.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
//! Code generation for the function that initializes a python module and adds classes and function.
|
//! Code generation for the function that initializes a python module and adds classes and function.
|
||||||
|
|
||||||
use args;
|
use crate::args;
|
||||||
use method;
|
use crate::method;
|
||||||
use py_method;
|
use crate::py_method;
|
||||||
use syn;
|
use crate::utils;
|
||||||
use utils;
|
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
use quote::quote;
|
||||||
|
use syn;
|
||||||
|
|
||||||
/// 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
|
||||||
|
@ -48,7 +48,7 @@ pub fn process_functions_in_module(func: &mut syn::ItemFn) {
|
||||||
{
|
{
|
||||||
let function_to_python = add_fn_to_module(func, &python_name, pyfn_attrs);
|
let function_to_python = add_fn_to_module(func, &python_name, pyfn_attrs);
|
||||||
let function_wrapper_ident = function_wrapper_ident(&func.ident);
|
let function_wrapper_ident = function_wrapper_ident(&func.ident);
|
||||||
let item: syn::ItemFn = parse_quote! {
|
let item: syn::ItemFn = syn::parse_quote! {
|
||||||
fn block_wrapper() {
|
fn block_wrapper() {
|
||||||
#function_to_python
|
#function_to_python
|
||||||
#module_name.add_wrapped(&#function_wrapper_ident)?;
|
#module_name.add_wrapped(&#function_wrapper_ident)?;
|
||||||
|
@ -145,7 +145,7 @@ fn extract_pyfn_attrs(
|
||||||
|
|
||||||
/// Coordinates the naming of a the add-function-to-python-module function
|
/// Coordinates the naming of a the add-function-to-python-module function
|
||||||
fn function_wrapper_ident(name: &syn::Ident) -> syn::Ident {
|
fn function_wrapper_ident(name: &syn::Ident) -> syn::Ident {
|
||||||
// Make sure this ident matches the one of wrap_function
|
// Make sure this ident matches the one of wrap_pyfunction
|
||||||
// The trim_start_matches("r#") is for https://github.com/dtolnay/syn/issues/478
|
// The trim_start_matches("r#") is for https://github.com/dtolnay/syn/issues/478
|
||||||
syn::Ident::new(
|
syn::Ident::new(
|
||||||
&format!(
|
&format!(
|
||||||
|
@ -214,7 +214,7 @@ pub fn add_fn_to_module(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate static function wrapper (PyCFunction, PyCFunctionWithKeywords)
|
/// Generate static function wrapper (PyCFunction, PyCFunctionWithKeywords)
|
||||||
fn function_c_wrapper(name: &syn::Ident, spec: &method::FnSpec) -> TokenStream {
|
fn function_c_wrapper(name: &syn::Ident, spec: &method::FnSpec<'_>) -> TokenStream {
|
||||||
let names: Vec<syn::Ident> = spec
|
let names: Vec<syn::Ident> = spec
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
use method::{FnArg, FnSpec, FnType};
|
use crate::method::{FnArg, FnSpec, FnType};
|
||||||
|
use crate::py_method::{
|
||||||
|
impl_py_getter_def, impl_py_setter_def, impl_wrap_getter, impl_wrap_setter,
|
||||||
|
};
|
||||||
|
use crate::utils;
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use py_method::{impl_py_getter_def, impl_py_setter_def, impl_wrap_getter, impl_wrap_setter};
|
use quote::quote;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use syn;
|
use syn;
|
||||||
use utils;
|
|
||||||
|
|
||||||
pub fn build_py_class(class: &mut syn::ItemStruct, attr: &Vec<syn::Expr>) -> TokenStream {
|
pub fn build_py_class(class: &mut syn::ItemStruct, attr: &Vec<syn::Expr>) -> TokenStream {
|
||||||
let (params, flags, base) = parse_attribute(attr);
|
let (params, flags, base) = parse_attribute(attr);
|
||||||
|
@ -115,9 +118,9 @@ fn impl_class(
|
||||||
let mut has_dict = false;
|
let mut has_dict = false;
|
||||||
for f in flags.iter() {
|
for f in flags.iter() {
|
||||||
if let syn::Expr::Path(ref epath) = f {
|
if let syn::Expr::Path(ref epath) = f {
|
||||||
if epath.path == parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_WEAKREF} {
|
if epath.path == syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_WEAKREF} {
|
||||||
has_weakref = true;
|
has_weakref = true;
|
||||||
} else if epath.path == parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_DICT} {
|
} else if epath.path == syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_DICT} {
|
||||||
has_dict = true;
|
has_dict = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,7 +268,7 @@ fn impl_descriptors(cls: &syn::Type, descriptors: Vec<(syn::Field, Vec<FnType>)>
|
||||||
py: true,
|
py: true,
|
||||||
reference: false,
|
reference: false,
|
||||||
}],
|
}],
|
||||||
output: parse_quote!(PyResult<()>),
|
output: syn::parse_quote!(PyResult<()>),
|
||||||
};
|
};
|
||||||
impl_py_setter_def(
|
impl_py_setter_def(
|
||||||
&name,
|
&name,
|
||||||
|
@ -305,8 +308,8 @@ fn parse_attribute(
|
||||||
let mut params = HashMap::new();
|
let mut params = HashMap::new();
|
||||||
// We need the 0 as value for the constant we're later building using quote for when there
|
// We need the 0 as value for the constant we're later building using quote for when there
|
||||||
// are no other flags
|
// are no other flags
|
||||||
let mut flags = vec![parse_quote! {0}];
|
let mut flags = vec![syn::parse_quote! {0}];
|
||||||
let mut base: syn::TypePath = parse_quote! {::pyo3::types::PyObjectRef};
|
let mut base: syn::TypePath = syn::parse_quote! {::pyo3::types::PyObjectRef};
|
||||||
|
|
||||||
for expr in args.iter() {
|
for expr in args.iter() {
|
||||||
match expr {
|
match expr {
|
||||||
|
@ -315,16 +318,16 @@ fn parse_attribute(
|
||||||
let flag = exp.path.segments.first().unwrap().value().ident.to_string();
|
let flag = exp.path.segments.first().unwrap().value().ident.to_string();
|
||||||
let path = match flag.as_str() {
|
let path = match flag.as_str() {
|
||||||
"gc" => {
|
"gc" => {
|
||||||
parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_GC}
|
syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_GC}
|
||||||
}
|
}
|
||||||
"weakref" => {
|
"weakref" => {
|
||||||
parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_WEAKREF}
|
syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_WEAKREF}
|
||||||
}
|
}
|
||||||
"subclass" => {
|
"subclass" => {
|
||||||
parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_BASETYPE}
|
syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_BASETYPE}
|
||||||
}
|
}
|
||||||
"dict" => {
|
"dict" => {
|
||||||
parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_DICT}
|
syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_DICT}
|
||||||
}
|
}
|
||||||
param => panic!("Unsupported parameter: {}", param),
|
param => panic!("Unsupported parameter: {}", param),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
|
use crate::py_method;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use py_method;
|
use quote::quote;
|
||||||
use syn;
|
use syn;
|
||||||
|
|
||||||
pub fn build_py_methods(ast: &mut syn::ItemImpl) -> TokenStream {
|
pub fn build_py_methods(ast: &mut syn::ItemImpl) -> TokenStream {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
use method::{FnArg, FnSpec, FnType};
|
use crate::method::{FnArg, FnSpec, FnType};
|
||||||
|
use crate::utils;
|
||||||
|
use proc_macro2::{Span, TokenStream};
|
||||||
|
use quote::quote;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn;
|
use syn;
|
||||||
|
|
||||||
use proc_macro2::{Span, TokenStream};
|
|
||||||
use utils;
|
|
||||||
|
|
||||||
pub fn gen_py_method<'a>(
|
pub fn gen_py_method<'a>(
|
||||||
cls: &syn::Type,
|
cls: &syn::Type,
|
||||||
name: &syn::Ident,
|
name: &syn::Ident,
|
||||||
|
@ -42,7 +42,7 @@ fn check_generic(name: &syn::Ident, sig: &syn::MethodSig) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn body_to_result(body: &TokenStream, spec: &FnSpec) -> TokenStream {
|
pub fn body_to_result(body: &TokenStream, spec: &FnSpec<'_>) -> TokenStream {
|
||||||
let output = &spec.output;
|
let output = &spec.output;
|
||||||
quote! {
|
quote! {
|
||||||
let _result: ::pyo3::PyResult<<#output as ::pyo3::ReturnTypeIntoPyResult>::Inner> = {
|
let _result: ::pyo3::PyResult<<#output as ::pyo3::ReturnTypeIntoPyResult>::Inner> = {
|
||||||
|
@ -52,7 +52,12 @@ pub fn body_to_result(body: &TokenStream, spec: &FnSpec) -> TokenStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate function wrapper (PyCFunction, PyCFunctionWithKeywords)
|
/// Generate function wrapper (PyCFunction, PyCFunctionWithKeywords)
|
||||||
pub fn impl_wrap(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec, noargs: bool) -> TokenStream {
|
pub fn impl_wrap(
|
||||||
|
cls: &syn::Type,
|
||||||
|
name: &syn::Ident,
|
||||||
|
spec: &FnSpec<'_>,
|
||||||
|
noargs: bool,
|
||||||
|
) -> TokenStream {
|
||||||
let body = impl_call(cls, name, &spec);
|
let body = impl_call(cls, name, &spec);
|
||||||
|
|
||||||
if spec.args.is_empty() && noargs {
|
if spec.args.is_empty() && noargs {
|
||||||
|
@ -100,7 +105,7 @@ pub fn impl_wrap(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec, noargs: bool
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate function wrapper for protocol method (PyCFunction, PyCFunctionWithKeywords)
|
/// Generate function wrapper for protocol method (PyCFunction, PyCFunctionWithKeywords)
|
||||||
pub fn impl_proto_wrap(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
|
pub fn impl_proto_wrap(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>) -> TokenStream {
|
||||||
let cb = impl_call(cls, name, &spec);
|
let cb = impl_call(cls, name, &spec);
|
||||||
let body = impl_arg_params(&spec, cb);
|
let body = impl_arg_params(&spec, cb);
|
||||||
|
|
||||||
|
@ -128,7 +133,7 @@ pub fn impl_proto_wrap(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> Tok
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
|
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
|
||||||
pub fn impl_wrap_new(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
|
pub fn impl_wrap_new(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>) -> TokenStream {
|
||||||
let names: Vec<syn::Ident> = spec
|
let names: Vec<syn::Ident> = spec
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -185,11 +190,11 @@ pub fn impl_wrap_new(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> Token
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate function wrapper for ffi::initproc
|
/// Generate function wrapper for ffi::initproc
|
||||||
fn impl_wrap_init(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
|
fn impl_wrap_init(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>) -> TokenStream {
|
||||||
let cb = impl_call(cls, name, &spec);
|
let cb = impl_call(cls, name, &spec);
|
||||||
let output = &spec.output;
|
let output = &spec.output;
|
||||||
let result_empty: syn::Type = parse_quote!(PyResult<()>);
|
let result_empty: syn::Type = syn::parse_quote!(PyResult<()>);
|
||||||
let empty: syn::Type = parse_quote!(());
|
let empty: syn::Type = syn::parse_quote!(());
|
||||||
if output != &result_empty || output != &empty {
|
if output != &result_empty || output != &empty {
|
||||||
panic!("Constructor must return PyResult<()> or a ()");
|
panic!("Constructor must return PyResult<()> or a ()");
|
||||||
}
|
}
|
||||||
|
@ -202,7 +207,7 @@ fn impl_wrap_init(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStr
|
||||||
unsafe extern "C" fn __wrap(
|
unsafe extern "C" fn __wrap(
|
||||||
_slf: *mut ::pyo3::ffi::PyObject,
|
_slf: *mut ::pyo3::ffi::PyObject,
|
||||||
_args: *mut ::pyo3::ffi::PyObject,
|
_args: *mut ::pyo3::ffi::PyObject,
|
||||||
_kwargs: *mut ::pyo3::ffi::PyObject) -> ::pyo3::libc::c_int
|
_kwargs: *mut ::pyo3::ffi::PyObject) -> libc::c_int
|
||||||
{
|
{
|
||||||
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
|
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
|
||||||
let _pool = ::pyo3::GILPool::new();
|
let _pool = ::pyo3::GILPool::new();
|
||||||
|
@ -224,7 +229,7 @@ fn impl_wrap_init(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStr
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
|
/// Generate class method wrapper (PyCFunction, PyCFunctionWithKeywords)
|
||||||
pub fn impl_wrap_class(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
|
pub fn impl_wrap_class(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>) -> TokenStream {
|
||||||
let names: Vec<syn::Ident> = spec
|
let names: Vec<syn::Ident> = spec
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -266,7 +271,7 @@ pub fn impl_wrap_class(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> Tok
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate static method wrapper (PyCFunction, PyCFunctionWithKeywords)
|
/// Generate static method wrapper (PyCFunction, PyCFunctionWithKeywords)
|
||||||
pub fn impl_wrap_static(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
|
pub fn impl_wrap_static(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>) -> TokenStream {
|
||||||
let names: Vec<syn::Ident> = spec
|
let names: Vec<syn::Ident> = spec
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -332,7 +337,11 @@ pub(crate) fn impl_wrap_getter(cls: &syn::Type, name: &syn::Ident) -> TokenStrea
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate functiona wrapper (PyCFunction, PyCFunctionWithKeywords)
|
/// Generate functiona wrapper (PyCFunction, PyCFunctionWithKeywords)
|
||||||
pub(crate) fn impl_wrap_setter(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec) -> TokenStream {
|
pub(crate) fn impl_wrap_setter(
|
||||||
|
cls: &syn::Type,
|
||||||
|
name: &syn::Ident,
|
||||||
|
spec: &FnSpec<'_>,
|
||||||
|
) -> TokenStream {
|
||||||
if spec.args.len() < 1 {
|
if spec.args.len() < 1 {
|
||||||
println!(
|
println!(
|
||||||
"Not enough arguments for setter {}::{}",
|
"Not enough arguments for setter {}::{}",
|
||||||
|
@ -346,7 +355,7 @@ pub(crate) fn impl_wrap_setter(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
unsafe extern "C" fn __wrap(
|
unsafe extern "C" fn __wrap(
|
||||||
_slf: *mut ::pyo3::ffi::PyObject,
|
_slf: *mut ::pyo3::ffi::PyObject,
|
||||||
_value: *mut ::pyo3::ffi::PyObject, _: *mut ::std::os::raw::c_void) -> ::pyo3::libc::c_int
|
_value: *mut ::pyo3::ffi::PyObject, _: *mut ::std::os::raw::c_void) -> libc::c_int
|
||||||
{
|
{
|
||||||
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
|
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
|
||||||
let _pool = ::pyo3::GILPool::new();
|
let _pool = ::pyo3::GILPool::new();
|
||||||
|
@ -369,7 +378,7 @@ pub(crate) fn impl_wrap_setter(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_call(_cls: &syn::Type, fname: &syn::Ident, spec: &FnSpec) -> TokenStream {
|
fn impl_call(_cls: &syn::Type, fname: &syn::Ident, spec: &FnSpec<'_>) -> TokenStream {
|
||||||
let names: Vec<syn::Ident> = spec
|
let names: Vec<syn::Ident> = spec
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -387,8 +396,8 @@ fn impl_call(_cls: &syn::Type, fname: &syn::Ident, spec: &FnSpec) -> TokenStream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn impl_arg_params(spec: &FnSpec, body: TokenStream) -> TokenStream {
|
pub fn impl_arg_params(spec: &FnSpec<'_>, body: TokenStream) -> TokenStream {
|
||||||
let args: Vec<FnArg> = spec
|
let args: Vec<FnArg<'_>> = spec
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|item| !item.py)
|
.filter(|item| !item.py)
|
||||||
|
@ -474,7 +483,12 @@ pub fn impl_arg_params(spec: &FnSpec, body: TokenStream) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &TokenStream, idx: usize) -> TokenStream {
|
fn impl_arg_param(
|
||||||
|
arg: &FnArg<'_>,
|
||||||
|
spec: &FnSpec<'_>,
|
||||||
|
body: &TokenStream,
|
||||||
|
idx: usize,
|
||||||
|
) -> TokenStream {
|
||||||
if arg.py {
|
if arg.py {
|
||||||
return body.clone();
|
return body.clone();
|
||||||
}
|
}
|
||||||
|
@ -562,7 +576,7 @@ fn impl_arg_param(arg: &FnArg, spec: &FnSpec, body: &TokenStream, idx: usize) ->
|
||||||
pub fn impl_py_method_def(
|
pub fn impl_py_method_def(
|
||||||
name: &syn::Ident,
|
name: &syn::Ident,
|
||||||
doc: syn::Lit,
|
doc: syn::Lit,
|
||||||
spec: &FnSpec,
|
spec: &FnSpec<'_>,
|
||||||
wrapper: &TokenStream,
|
wrapper: &TokenStream,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
if spec.args.is_empty() {
|
if spec.args.is_empty() {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
use defs;
|
use crate::defs;
|
||||||
use func::impl_method_proto;
|
use crate::func::impl_method_proto;
|
||||||
use method::FnSpec;
|
use crate::method::FnSpec;
|
||||||
|
use crate::py_method;
|
||||||
use proc_macro2::TokenStream;
|
use proc_macro2::TokenStream;
|
||||||
use py_method;
|
use quote::quote;
|
||||||
use quote::ToTokens;
|
use quote::ToTokens;
|
||||||
use syn;
|
use syn;
|
||||||
|
|
||||||
|
@ -32,9 +33,9 @@ pub fn build_py_proto(ast: &mut syn::ItemImpl) -> TokenStream {
|
||||||
|
|
||||||
// attach lifetime
|
// attach lifetime
|
||||||
let mut seg = path.segments.pop().unwrap().into_value();
|
let mut seg = path.segments.pop().unwrap().into_value();
|
||||||
seg.arguments = syn::PathArguments::AngleBracketed(parse_quote! {<'p>});
|
seg.arguments = syn::PathArguments::AngleBracketed(syn::parse_quote! {<'p>});
|
||||||
path.segments.push(seg);
|
path.segments.push(seg);
|
||||||
ast.generics.params = parse_quote! {'p};
|
ast.generics.params = syn::parse_quote! {'p};
|
||||||
|
|
||||||
tokens
|
tokens
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "pyo3cls"
|
name = "pyo3cls"
|
||||||
version = "0.6.0-alpha.1"
|
version = "0.6.0-alpha.2"
|
||||||
description = "Proc macros for PyO3 package"
|
description = "Proc macros for PyO3 package"
|
||||||
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
|
||||||
keywords = ["pyo3", "python", "cpython", "ffi"]
|
keywords = ["pyo3", "python", "cpython", "ffi"]
|
||||||
|
@ -8,6 +8,7 @@ homepage = "https://github.com/pyo3/pyo3"
|
||||||
repository = "https://github.com/pyo3/pyo3"
|
repository = "https://github.com/pyo3/pyo3"
|
||||||
categories = ["api-bindings", "development-tools::ffi"]
|
categories = ["api-bindings", "development-tools::ffi"]
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
@ -16,4 +17,4 @@ proc-macro = true
|
||||||
quote= "0.6.9"
|
quote= "0.6.9"
|
||||||
proc-macro2 = "0.4.20"
|
proc-macro2 = "0.4.20"
|
||||||
syn = { version = "0.15.15", features = ["full", "extra-traits"] }
|
syn = { version = "0.15.15", features = ["full", "extra-traits"] }
|
||||||
pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.6.0-alpha.1" }
|
pyo3-derive-backend = { path = "../pyo3-derive-backend", version = "=0.6.0-alpha.2" }
|
||||||
|
|
|
@ -2,26 +2,18 @@
|
||||||
//! This crate declares only the proc macro attributes, as a crate defining proc macro attributes
|
//! This crate declares only the proc macro attributes, as a crate defining proc macro attributes
|
||||||
//! must not contain any other public items.
|
//! must not contain any other public items.
|
||||||
|
|
||||||
#![recursion_limit = "1024"]
|
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
extern crate proc_macro2;
|
use proc_macro::TokenStream;
|
||||||
extern crate pyo3_derive_backend;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate quote;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate syn;
|
|
||||||
|
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
use pyo3_derive_backend::*;
|
use pyo3_derive_backend::{module, py_class, py_impl, py_proto, utils};
|
||||||
|
use quote::quote;
|
||||||
|
use syn;
|
||||||
use syn::parse::Parser;
|
use syn::parse::Parser;
|
||||||
use syn::punctuated::Punctuated;
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::Token;
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn pymodule2(
|
pub fn pymodule2(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
attr: proc_macro::TokenStream,
|
|
||||||
input: proc_macro::TokenStream,
|
|
||||||
) -> proc_macro::TokenStream {
|
|
||||||
// Parse the token stream into a syntax tree
|
// Parse the token stream into a syntax tree
|
||||||
let mut ast: syn::ItemFn = syn::parse(input).expect("#[pymodule] must be used on a function");
|
let mut ast: syn::ItemFn = syn::parse(input).expect("#[pymodule] must be used on a function");
|
||||||
|
|
||||||
|
@ -46,10 +38,7 @@ pub fn pymodule2(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn pymodule3(
|
pub fn pymodule3(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
attr: proc_macro::TokenStream,
|
|
||||||
input: proc_macro::TokenStream,
|
|
||||||
) -> proc_macro::TokenStream {
|
|
||||||
// Parse the token stream into a syntax tree
|
// Parse the token stream into a syntax tree
|
||||||
let mut ast: syn::ItemFn = syn::parse(input).expect("#[pymodule] must be used on a `fn` block");
|
let mut ast: syn::ItemFn = syn::parse(input).expect("#[pymodule] must be used on a `fn` block");
|
||||||
|
|
||||||
|
@ -74,10 +63,7 @@ pub fn pymodule3(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn pyproto(
|
pub fn pyproto(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
_: proc_macro::TokenStream,
|
|
||||||
input: proc_macro::TokenStream,
|
|
||||||
) -> proc_macro::TokenStream {
|
|
||||||
// Parse the token stream into a syntax tree
|
// Parse the token stream into a syntax tree
|
||||||
let mut ast: syn::ItemImpl =
|
let mut ast: syn::ItemImpl =
|
||||||
syn::parse(input).expect("#[pyproto] must be used on an `impl` block");
|
syn::parse(input).expect("#[pyproto] must be used on an `impl` block");
|
||||||
|
@ -93,10 +79,7 @@ pub fn pyproto(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn pyclass(
|
pub fn pyclass(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
attr: proc_macro::TokenStream,
|
|
||||||
input: proc_macro::TokenStream,
|
|
||||||
) -> proc_macro::TokenStream {
|
|
||||||
// Parse the token stream into a syntax tree
|
// Parse the token stream into a syntax tree
|
||||||
let mut ast: syn::ItemStruct =
|
let mut ast: syn::ItemStruct =
|
||||||
syn::parse(input).expect("#[pyclass] must be used on a `struct`");
|
syn::parse(input).expect("#[pyclass] must be used on a `struct`");
|
||||||
|
@ -121,10 +104,7 @@ pub fn pyclass(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn pymethods(
|
pub fn pymethods(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
_: proc_macro::TokenStream,
|
|
||||||
input: proc_macro::TokenStream,
|
|
||||||
) -> proc_macro::TokenStream {
|
|
||||||
// Parse the token stream into a syntax tree
|
// Parse the token stream into a syntax tree
|
||||||
let mut ast: syn::ItemImpl =
|
let mut ast: syn::ItemImpl =
|
||||||
syn::parse(input.clone()).expect("#[pymethods] must be used on an `impl` block");
|
syn::parse(input.clone()).expect("#[pymethods] must be used on an `impl` block");
|
||||||
|
@ -140,10 +120,7 @@ pub fn pymethods(
|
||||||
}
|
}
|
||||||
|
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn pyfunction(
|
pub fn pyfunction(_: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
_: proc_macro::TokenStream,
|
|
||||||
input: proc_macro::TokenStream,
|
|
||||||
) -> proc_macro::TokenStream {
|
|
||||||
let mut ast: syn::ItemFn = syn::parse(input).expect("#[function] must be used on a `fn` block");
|
let mut ast: syn::ItemFn = syn::parse(input).expect("#[function] must be used on a `fn` block");
|
||||||
|
|
||||||
// Workaround for https://github.com/dtolnay/syn/issues/478
|
// Workaround for https://github.com/dtolnay/syn/issues/478
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
nightly-2019-01-12
|
nightly
|
|
@ -663,7 +663,6 @@ mod test {
|
||||||
use super::PyBuffer;
|
use super::PyBuffer;
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use crate::python::Python;
|
use crate::python::Python;
|
||||||
use std;
|
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use crate::objectprotocol::ObjectProtocol;
|
use crate::objectprotocol::ObjectProtocol;
|
||||||
|
|
|
@ -160,7 +160,7 @@ macro_rules! py_binary_self_func {
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
e.restore(py);
|
e.restore(py);
|
||||||
$crate::std::ptr::null_mut()
|
std::ptr::null_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,7 @@ macro_rules! py_ternary_self_func {
|
||||||
Ok(_) => slf,
|
Ok(_) => slf,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
e.restore(py);
|
e.restore(py);
|
||||||
$crate::std::ptr::null_mut()
|
std::ptr::null_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,7 +317,7 @@ macro_rules! py_func_set {
|
||||||
slf: *mut $crate::ffi::PyObject,
|
slf: *mut $crate::ffi::PyObject,
|
||||||
name: *mut $crate::ffi::PyObject,
|
name: *mut $crate::ffi::PyObject,
|
||||||
value: *mut $crate::ffi::PyObject,
|
value: *mut $crate::ffi::PyObject,
|
||||||
) -> $crate::libc::c_int
|
) -> libc::c_int
|
||||||
where
|
where
|
||||||
T: for<'p> $trait_name<'p>,
|
T: for<'p> $trait_name<'p>,
|
||||||
{
|
{
|
||||||
|
@ -365,7 +365,7 @@ macro_rules! py_func_del {
|
||||||
slf: *mut $crate::ffi::PyObject,
|
slf: *mut $crate::ffi::PyObject,
|
||||||
name: *mut $crate::ffi::PyObject,
|
name: *mut $crate::ffi::PyObject,
|
||||||
value: *mut $crate::ffi::PyObject,
|
value: *mut $crate::ffi::PyObject,
|
||||||
) -> $crate::libc::c_int
|
) -> libc::c_int
|
||||||
where
|
where
|
||||||
U: for<'p> $trait_name<'p>,
|
U: for<'p> $trait_name<'p>,
|
||||||
{
|
{
|
||||||
|
@ -407,7 +407,7 @@ macro_rules! py_func_set_del {
|
||||||
slf: *mut $crate::ffi::PyObject,
|
slf: *mut $crate::ffi::PyObject,
|
||||||
name: *mut $crate::ffi::PyObject,
|
name: *mut $crate::ffi::PyObject,
|
||||||
value: *mut $crate::ffi::PyObject,
|
value: *mut $crate::ffi::PyObject,
|
||||||
) -> $crate::libc::c_int
|
) -> libc::c_int
|
||||||
where
|
where
|
||||||
T: for<'p> $trait1<'p> + for<'p> $trait2<'p>,
|
T: for<'p> $trait1<'p> + for<'p> $trait2<'p>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use std;
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
|
|
||||||
/// `PyMethodDefType` represents different types of python callable objects.
|
/// `PyMethodDefType` represents different types of python callable objects.
|
||||||
|
|
|
@ -8,7 +8,6 @@ use crate::python::{IntoPyPointer, Python, ToPyPointer};
|
||||||
use crate::typeob::PyTypeObject;
|
use crate::typeob::PyTypeObject;
|
||||||
use crate::types::{exceptions, PyObjectRef, PyType};
|
use crate::types::{exceptions, PyObjectRef, PyType};
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
use std;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
use std;
|
|
||||||
use std::mem;
|
|
||||||
use std::ptr::NonNull;
|
|
||||||
|
|
||||||
use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject};
|
use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject};
|
||||||
use crate::err::{PyErr, PyResult};
|
use crate::err::{PyErr, PyResult};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
|
@ -15,6 +11,8 @@ use crate::pythonrun;
|
||||||
use crate::typeob::PyTypeCreate;
|
use crate::typeob::PyTypeCreate;
|
||||||
use crate::typeob::{PyTypeInfo, PyTypeObject};
|
use crate::typeob::{PyTypeInfo, PyTypeObject};
|
||||||
use crate::types::PyObjectRef;
|
use crate::types::PyObjectRef;
|
||||||
|
use std::mem;
|
||||||
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
/// Any instance that is managed Python can have access to `gil`.
|
/// Any instance that is managed Python can have access to `gil`.
|
||||||
///
|
///
|
||||||
|
@ -234,7 +232,7 @@ impl<T: PyTypeInfo + PyNativeType> AsPyRefDispatch<T> for Py<T> {
|
||||||
unsafe { &*(self as *const instance::Py<T> as *const T) }
|
unsafe { &*(self as *const instance::Py<T> as *const T) }
|
||||||
}
|
}
|
||||||
fn as_mut_dispatch(&mut self, _py: Python) -> &mut T {
|
fn as_mut_dispatch(&mut self, _py: Python) -> &mut T {
|
||||||
unsafe { &mut *(self as *const _ as *mut T) }
|
unsafe { &mut *(self as *mut _ as *mut T) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
168
src/lib.rs
168
src/lib.rs
|
@ -2,7 +2,10 @@
|
||||||
|
|
||||||
//! Rust bindings to the Python interpreter.
|
//! Rust bindings to the Python interpreter.
|
||||||
//!
|
//!
|
||||||
|
//! Look at [the guide](https://pyo3.rs/) for a detailed introduction.
|
||||||
|
//!
|
||||||
//! # Ownership and Lifetimes
|
//! # Ownership and Lifetimes
|
||||||
|
//!
|
||||||
//! In Python, all objects are implicitly reference counted.
|
//! In Python, all objects are implicitly reference counted.
|
||||||
//! In rust, we will use the `PyObject` type to represent a reference to a Python object.
|
//! In rust, we will use the `PyObject` type to represent a reference to a Python object.
|
||||||
//!
|
//!
|
||||||
|
@ -28,10 +31,77 @@
|
||||||
//!
|
//!
|
||||||
//! # Example
|
//! # Example
|
||||||
//!
|
//!
|
||||||
|
//! ## Using rust from python
|
||||||
|
//!
|
||||||
|
//! Pyo3 can be used to generate a native python module.
|
||||||
|
//!
|
||||||
|
//! **`Cargo.toml`**
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [package]
|
||||||
|
//! name = "string-sum"
|
||||||
|
//! version = "0.1.0"
|
||||||
|
//! edition = "2018"
|
||||||
|
//!
|
||||||
|
//! [lib]
|
||||||
|
//! name = "string_sum"
|
||||||
|
//! crate-type = ["cdylib"]
|
||||||
|
//!
|
||||||
|
//! [dependencies.pyo3]
|
||||||
|
//! version = "0.6.0-alpha.2"
|
||||||
|
//! features = ["extension-module"]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! **`src/lib.rs`**
|
||||||
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! #![feature(specialization)]
|
//! #![feature(specialization)]
|
||||||
//!
|
//!
|
||||||
//! extern crate pyo3;
|
//! use pyo3::prelude::*;
|
||||||
|
//! use pyo3::wrap_pyfunction;
|
||||||
|
//!
|
||||||
|
//! #[pyfunction]
|
||||||
|
//! /// Formats the sum of two numbers as string
|
||||||
|
//! fn sum_as_string(a: usize, b: usize) -> PyResult<String> {
|
||||||
|
//! Ok((a + b).to_string())
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! /// This module is a python module implemented in Rust.
|
||||||
|
//! #[pymodule]
|
||||||
|
//! fn string_sum(py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
//! m.add_wrapped(wrap_pyfunction!(sum_as_string))?;
|
||||||
|
//!
|
||||||
|
//! Ok(())
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! On windows and linux, you can build normally with `cargo build --release`. On macOS, you need to set additional linker arguments. One option is to compile with `cargo rustc --release -- -C link-arg=-undefined -C link-arg=dynamic_lookup`, the other is to create a `.cargo/config` with the following content:
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [target.x86_64-apple-darwin]
|
||||||
|
//! rustflags = [
|
||||||
|
//! "-C", "link-arg=-undefined",
|
||||||
|
//! "-C", "link-arg=dynamic_lookup",
|
||||||
|
//! ]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! For developing, you can copy and rename the shared library from the target folder: On macOS, rename `libstring_sum.dylib` to `string_sum.so`, on windows `libstring_sum.dll` to `string_sum.pyd` and on linux `libstring_sum.so` to `string_sum.so`. Then open a python shell in the same folder and you'll be able to `import string_sum`.
|
||||||
|
//!
|
||||||
|
//! To build, test and publish your crate as python module, you can use [pyo3-pack](https://github.com/PyO3/pyo3-pack) or [setuptools-rust](https://github.com/PyO3/setuptools-rust). You can find an example for setuptools-rust in [examples/word-count](examples/word-count), while pyo3-pack should work on your crate without any configuration.
|
||||||
|
//!
|
||||||
|
//! ## Using python from rust
|
||||||
|
//!
|
||||||
|
//! Add `pyo3` this to your `Cargo.toml`:
|
||||||
|
//!
|
||||||
|
//! ```toml
|
||||||
|
//! [dependencies]
|
||||||
|
//! pyo3 = "0.6.0-alpha.2"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Example program displaying the value of `sys.version`:
|
||||||
|
//!
|
||||||
|
//! ```rust
|
||||||
|
//! #![feature(specialization)]
|
||||||
//!
|
//!
|
||||||
//! use pyo3::prelude::*;
|
//! use pyo3::prelude::*;
|
||||||
//! use pyo3::types::PyDict;
|
//! use pyo3::types::PyDict;
|
||||||
|
@ -51,91 +121,6 @@
|
||||||
//! Ok(())
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
|
||||||
//! # Python extension
|
|
||||||
//!
|
|
||||||
//! To allow Python to load the rust code as a Python extension
|
|
||||||
//! module, you need an initialization function with `Fn(Python, &PyModule) -> PyResult<()>`
|
|
||||||
//! that is annotates with `#[pymodule]`. By default the function name will become the module name,
|
|
||||||
//! but you can override that with `#[pymodule(name)]`.
|
|
||||||
//!
|
|
||||||
//! To creates a Python callable object that invokes a Rust function, specify rust
|
|
||||||
//! function and decorate it with `#[pyfn()]` attribute. `pyfn()` accepts three parameters.
|
|
||||||
//!
|
|
||||||
//! 1. `m`: The module name.
|
|
||||||
//! 2. name of function visible to Python code.
|
|
||||||
//! 3. comma separated arguments, i.e. param="None", "*", param3="55"
|
|
||||||
//!
|
|
||||||
//!
|
|
||||||
//! # Example
|
|
||||||
//!
|
|
||||||
//! ```rust
|
|
||||||
//! #![feature(specialization)]
|
|
||||||
//!
|
|
||||||
//! extern crate pyo3;
|
|
||||||
//! use pyo3::prelude::*;
|
|
||||||
//!
|
|
||||||
//! // Add bindings to the generated python module
|
|
||||||
//! // N.B: names: "librust2py" must be the name of the `.so` or `.pyd` file
|
|
||||||
//! /// This module is implemented in Rust.
|
|
||||||
//! #[pymodule]
|
|
||||||
//! fn rust2py(py: Python, m: &PyModule) -> PyResult<()> {
|
|
||||||
//!
|
|
||||||
//! #[pyfn(m, "sum_as_string")]
|
|
||||||
//! // ``#[pyfn()]` converts the arguments from Python objects to Rust values
|
|
||||||
//! // and the Rust return value back into a Python object.
|
|
||||||
//! fn sum_as_string_py(a:i64, b:i64) -> PyResult<String> {
|
|
||||||
//! let out = sum_as_string(a, b);
|
|
||||||
//! Ok(out)
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! Ok(())
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // The logic can be implemented as a normal rust function
|
|
||||||
//! fn sum_as_string(a:i64, b:i64) -> String {
|
|
||||||
//! format!("{}", a + b).to_string()
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! # fn main() {}
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! In your `Cargo.toml`, use the `extension-module` feature for the `pyo3` dependency:
|
|
||||||
//!
|
|
||||||
//! ```cargo
|
|
||||||
//! [dependencies.pyo3]
|
|
||||||
//! version = "*"
|
|
||||||
//! features = ["extension-module"]
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! On windows and linux, you can build normally with `cargo build --release`. On Mac Os, you need to set additional linker arguments. One option is to compile with `cargo rustc --release -- -C link-arg=-undefined -C link-arg=dynamic_lookup`, the other is to create a `.cargo/config` with the following content:
|
|
||||||
//!
|
|
||||||
//! ```toml
|
|
||||||
//! [target.x86_64-apple-darwin]
|
|
||||||
//! rustflags = [
|
|
||||||
//! "-C", "link-arg=-undefined",
|
|
||||||
//! "-C", "link-arg=dynamic_lookup",
|
|
||||||
//! ]
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! Also on macOS, you will need to rename the output from \*.dylib to \*.so. On Windows, you will need to rename the output from \*.dll to \*.pyd.
|
|
||||||
//!
|
|
||||||
//! [`setuptools-rust`](https://github.com/PyO3/setuptools-rust) can be used to generate a python package and includes the commands above by default. See [examples/word-count](examples/word-count) and the associated setup.py.
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate assert_approx_eq;
|
|
||||||
#[cfg(test)]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate indoc;
|
|
||||||
// We need those types in the macro exports
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub extern crate libc;
|
|
||||||
// We need that reexport for wrap_function
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub extern crate mashup;
|
|
||||||
extern crate pyo3cls;
|
|
||||||
extern crate spin;
|
|
||||||
|
|
||||||
pub use crate::class::*;
|
pub use crate::class::*;
|
||||||
pub use crate::conversion::{
|
pub use crate::conversion::{
|
||||||
|
@ -152,6 +137,13 @@ pub use crate::pythonrun::{init_once, prepare_freethreaded_python, GILGuard, GIL
|
||||||
pub use crate::typeob::{PyObjectAlloc, PyRawObject, PyTypeInfo};
|
pub use crate::typeob::{PyObjectAlloc, PyRawObject, PyTypeInfo};
|
||||||
pub use crate::types::exceptions;
|
pub use crate::types::exceptions;
|
||||||
|
|
||||||
|
// We need those types in the macro exports
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use libc;
|
||||||
|
// We need that reexport for wrap_function
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub use mashup;
|
||||||
|
|
||||||
/// Rust FFI declarations for Python
|
/// Rust FFI declarations for Python
|
||||||
pub mod ffi;
|
pub mod ffi;
|
||||||
|
|
||||||
|
@ -203,7 +195,7 @@ pub mod proc_macro {
|
||||||
///
|
///
|
||||||
/// Use this together with `#[pyfunction]` and [types::PyModule::add_wrapped].
|
/// Use this together with `#[pyfunction]` and [types::PyModule::add_wrapped].
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! wrap_function {
|
macro_rules! wrap_pyfunction {
|
||||||
($function_name:ident) => {{
|
($function_name:ident) => {{
|
||||||
// Get the mashup macro and its helpers into scope
|
// Get the mashup macro and its helpers into scope
|
||||||
use $crate::mashup::*;
|
use $crate::mashup::*;
|
||||||
|
@ -224,7 +216,7 @@ macro_rules! wrap_function {
|
||||||
/// Use this together with `#[pymodule]` and [types::PyModule::add_wrapped].
|
/// Use this together with `#[pymodule]` and [types::PyModule::add_wrapped].
|
||||||
#[cfg(Py_3)]
|
#[cfg(Py_3)]
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! wrap_module {
|
macro_rules! wrap_pymodule {
|
||||||
($module_name:ident) => {{
|
($module_name:ident) => {{
|
||||||
use $crate::mashup::*;
|
use $crate::mashup::*;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
use std;
|
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
use crate::conversion::{
|
use crate::conversion::{
|
||||||
|
@ -18,7 +17,7 @@ use crate::types::{PyDict, PyObjectRef, PyTuple};
|
||||||
/// The python object's lifetime is managed by python's garbage
|
/// The python object's lifetime is managed by python's garbage
|
||||||
/// collector.
|
/// collector.
|
||||||
///
|
///
|
||||||
/// Technically, it is a safe wrapper around the unsafe `*mut ffi::PyObject` pointer.
|
/// Technically, it is a safe wrapper around `NonNull<ffi::PyObject>`.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct PyObject(NonNull<ffi::PyObject>);
|
pub struct PyObject(NonNull<ffi::PyObject>);
|
||||||
|
@ -258,11 +257,11 @@ impl PyObject {
|
||||||
impl AsPyRef<PyObjectRef> for PyObject {
|
impl AsPyRef<PyObjectRef> for PyObject {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_ref(&self, _py: Python) -> &PyObjectRef {
|
fn as_ref(&self, _py: Python) -> &PyObjectRef {
|
||||||
unsafe { &*(self as *const _ as *mut PyObjectRef) }
|
unsafe { &*(self as *const _ as *const PyObjectRef) }
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_mut(&mut self, _py: Python) -> &mut PyObjectRef {
|
fn as_mut(&mut self, _py: Python) -> &mut PyObjectRef {
|
||||||
unsafe { &mut *(self as *const _ as *mut PyObjectRef) }
|
unsafe { &mut *(self as *mut _ as *mut PyObjectRef) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ use crate::object::PyObject;
|
||||||
use crate::python::{IntoPyPointer, Python, ToPyPointer};
|
use crate::python::{IntoPyPointer, Python, ToPyPointer};
|
||||||
use crate::typeob::PyTypeInfo;
|
use crate::typeob::PyTypeInfo;
|
||||||
use crate::types::{PyDict, PyIterator, PyObjectRef, PyString, PyTuple, PyType};
|
use crate::types::{PyDict, PyIterator, PyObjectRef, PyString, PyTuple, PyType};
|
||||||
use std;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,6 @@ pub use crate::pythonrun::GILGuard;
|
||||||
pub use crate::types::PyModule;
|
pub use crate::types::PyModule;
|
||||||
// This is required for the constructor
|
// This is required for the constructor
|
||||||
pub use crate::PyRawObject;
|
pub use crate::PyRawObject;
|
||||||
|
|
||||||
pub use pyo3cls::{pyclass, pyfunction, pymethods, pyproto};
|
pub use pyo3cls::{pyclass, pyfunction, pymethods, pyproto};
|
||||||
|
|
||||||
#[cfg(Py_3)]
|
#[cfg(Py_3)]
|
||||||
|
|
|
@ -11,7 +11,6 @@ use crate::pythonrun::{self, GILGuard};
|
||||||
use crate::typeob::PyTypeCreate;
|
use crate::typeob::PyTypeCreate;
|
||||||
use crate::typeob::{PyTypeInfo, PyTypeObject};
|
use crate::typeob::{PyTypeInfo, PyTypeObject};
|
||||||
use crate::types::{PyDict, PyModule, PyObjectRef, PyType};
|
use crate::types::{PyDict, PyModule, PyObjectRef, PyType};
|
||||||
use std;
|
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::os::raw::c_int;
|
use std::os::raw::c_int;
|
||||||
|
@ -293,6 +292,7 @@ impl<'p> Python<'p> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::cast_ref_to_mut)] // FIXME
|
||||||
unsafe fn unchecked_mut_downcast<T: PyTypeInfo>(self, ob: &PyObjectRef) -> &'p mut T {
|
unsafe fn unchecked_mut_downcast<T: PyTypeInfo>(self, ob: &PyObjectRef) -> &'p mut T {
|
||||||
if T::OFFSET == 0 {
|
if T::OFFSET == 0 {
|
||||||
&mut *(ob as *const _ as *mut T)
|
&mut *(ob as *const _ as *mut T)
|
||||||
|
@ -307,10 +307,7 @@ impl<'p> Python<'p> {
|
||||||
where
|
where
|
||||||
T: PyTypeInfo,
|
T: PyTypeInfo,
|
||||||
{
|
{
|
||||||
let p;
|
let p = unsafe { pythonrun::register_owned(self, obj.into_nonnull()) };
|
||||||
unsafe {
|
|
||||||
p = pythonrun::register_owned(self, obj.into_nonnull());
|
|
||||||
}
|
|
||||||
<T as PyTryFrom>::try_from(p)
|
<T as PyTryFrom>::try_from(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,6 @@
|
||||||
|
|
||||||
//! Python type object information
|
//! Python type object information
|
||||||
|
|
||||||
use std;
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::os::raw::c_void;
|
|
||||||
|
|
||||||
use crate::class::methods::PyMethodDefType;
|
use crate::class::methods::PyMethodDefType;
|
||||||
use crate::err::{PyErr, PyResult};
|
use crate::err::{PyErr, PyResult};
|
||||||
use crate::instance::{Py, PyObjectWithGIL};
|
use crate::instance::{Py, PyObjectWithGIL};
|
||||||
|
@ -15,6 +10,9 @@ use crate::python::{IntoPyPointer, Python};
|
||||||
use crate::types::PyObjectRef;
|
use crate::types::PyObjectRef;
|
||||||
use crate::types::PyType;
|
use crate::types::PyType;
|
||||||
use crate::{class, ffi, pythonrun};
|
use crate::{class, ffi, pythonrun};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::ffi::CString;
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
|
||||||
/// Python type information.
|
/// Python type information.
|
||||||
pub trait PyTypeInfo {
|
pub trait PyTypeInfo {
|
||||||
|
|
|
@ -116,13 +116,13 @@ impl<'py> Neg for &'py PyComplex {
|
||||||
|
|
||||||
#[cfg(feature = "num-complex")]
|
#[cfg(feature = "num-complex")]
|
||||||
mod complex_conversion {
|
mod complex_conversion {
|
||||||
extern crate num_complex;
|
|
||||||
use self::num_complex::Complex;
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use conversion::{FromPyObject, IntoPyObject, ToPyObject};
|
use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject};
|
||||||
use err::PyErr;
|
use crate::err::PyErr;
|
||||||
use types::PyObjectRef;
|
use crate::types::PyObjectRef;
|
||||||
use PyResult;
|
use crate::PyResult;
|
||||||
|
use num_complex::Complex;
|
||||||
|
|
||||||
impl PyComplex {
|
impl PyComplex {
|
||||||
/// Creates a new Python `PyComplex` object from num_complex::Complex.
|
/// Creates a new Python `PyComplex` object from num_complex::Complex.
|
||||||
pub fn from_complex<'py, F: Into<c_double>>(
|
pub fn from_complex<'py, F: Into<c_double>>(
|
||||||
|
@ -153,6 +153,7 @@ mod complex_conversion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(any(not(Py_LIMITED_API), not(Py_3)))]
|
#[cfg(any(not(Py_LIMITED_API), not(Py_3)))]
|
||||||
|
#[allow(clippy::float_cmp)] // The comparison is for an error value
|
||||||
impl<'source> FromPyObject<'source> for Complex<$float> {
|
impl<'source> FromPyObject<'source> for Complex<$float> {
|
||||||
fn extract(obj: &'source PyObjectRef) -> PyResult<Complex<$float>> {
|
fn extract(obj: &'source PyObjectRef) -> PyResult<Complex<$float>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -166,6 +167,7 @@ mod complex_conversion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(all(Py_LIMITED_API, Py_3))]
|
#[cfg(all(Py_LIMITED_API, Py_3))]
|
||||||
|
#[allow(clippy::float_cmp)] // The comparison is for an error value
|
||||||
impl<'source> FromPyObject<'source> for Complex<$float> {
|
impl<'source> FromPyObject<'source> for Complex<$float> {
|
||||||
fn extract(obj: &'source PyObjectRef) -> PyResult<Complex<$float>> {
|
fn extract(obj: &'source PyObjectRef) -> PyResult<Complex<$float>> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -214,6 +216,8 @@ mod complex_conversion {
|
||||||
mod test {
|
mod test {
|
||||||
use super::PyComplex;
|
use super::PyComplex;
|
||||||
use crate::python::Python;
|
use crate::python::Python;
|
||||||
|
use assert_approx_eq::assert_approx_eq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_from_double() {
|
fn test_from_double() {
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
|
|
|
@ -7,7 +7,6 @@ use crate::instance::PyObjectWithGIL;
|
||||||
use crate::object::PyObject;
|
use crate::object::PyObject;
|
||||||
use crate::python::{IntoPyPointer, Python, ToPyPointer};
|
use crate::python::{IntoPyPointer, Python, ToPyPointer};
|
||||||
use crate::types::{PyList, PyObjectRef};
|
use crate::types::{PyList, PyObjectRef};
|
||||||
use std;
|
|
||||||
use std::{cmp, collections, hash, mem};
|
use std::{cmp, collections, hash, mem};
|
||||||
|
|
||||||
/// Represents a Python `dict`.
|
/// Represents a Python `dict`.
|
||||||
|
|
|
@ -44,6 +44,7 @@ macro_rules! impl_exception_boilerplate {
|
||||||
/// Defines rust type for exception defined in Python code.
|
/// Defines rust type for exception defined in Python code.
|
||||||
///
|
///
|
||||||
/// # Syntax
|
/// # Syntax
|
||||||
|
///
|
||||||
/// `import_exception!(module, MyError)`
|
/// `import_exception!(module, MyError)`
|
||||||
///
|
///
|
||||||
/// * `module` is the name of the containing module.
|
/// * `module` is the name of the containing module.
|
||||||
|
@ -51,11 +52,10 @@ macro_rules! impl_exception_boilerplate {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
///extern crate pyo3;
|
|
||||||
///
|
|
||||||
/// use pyo3::import_exception;
|
/// use pyo3::import_exception;
|
||||||
/// use pyo3::types::PyDict;
|
/// use pyo3::types::PyDict;
|
||||||
/// use pyo3::Python;
|
/// use pyo3::Python;
|
||||||
|
///
|
||||||
/// import_exception!(socket, gaierror);
|
/// import_exception!(socket, gaierror);
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
|
@ -142,10 +142,8 @@ macro_rules! import_exception_type_object {
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
/// ```
|
/// ```
|
||||||
/// #[macro_use]
|
|
||||||
/// extern crate pyo3;
|
|
||||||
///
|
|
||||||
/// use pyo3::prelude::*;
|
/// use pyo3::prelude::*;
|
||||||
|
/// use pyo3::create_exception;
|
||||||
/// use pyo3::types::PyDict;
|
/// use pyo3::types::PyDict;
|
||||||
/// use pyo3::exceptions::Exception;
|
/// use pyo3::exceptions::Exception;
|
||||||
///
|
///
|
||||||
|
@ -360,6 +358,7 @@ impl UnicodeDecodeError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::range_plus_one)] // False positive, ..= returns the wrong type
|
||||||
pub fn new_utf8<'p>(
|
pub fn new_utf8<'p>(
|
||||||
py: Python<'p>,
|
py: Python<'p>,
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
|
|
|
@ -83,6 +83,8 @@ impl<'p> Drop for PyIterator<'p> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use indoc::indoc;
|
||||||
|
|
||||||
use crate::conversion::{PyTryFrom, ToPyObject};
|
use crate::conversion::{PyTryFrom, ToPyObject};
|
||||||
use crate::instance::AsPyRef;
|
use crate::instance::AsPyRef;
|
||||||
use crate::objectprotocol::ObjectProtocol;
|
use crate::objectprotocol::ObjectProtocol;
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
//
|
//
|
||||||
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
||||||
|
|
||||||
use std;
|
|
||||||
|
|
||||||
use crate::conversion::{IntoPyObject, ToBorrowedObject, ToPyObject};
|
use crate::conversion::{IntoPyObject, ToBorrowedObject, ToPyObject};
|
||||||
use crate::err::{self, PyResult};
|
use crate::err::{self, PyResult};
|
||||||
use crate::ffi::{self, Py_ssize_t};
|
use crate::ffi::{self, Py_ssize_t};
|
||||||
|
|
|
@ -171,18 +171,18 @@ impl PyModule {
|
||||||
|
|
||||||
/// Adds a function or a (sub)module to a module, using the functions __name__ as name.
|
/// Adds a function or a (sub)module to a module, using the functions __name__ as name.
|
||||||
///
|
///
|
||||||
/// Use this together with the`#[pyfunction]` and [wrap_function!] or `#[pymodule]` and
|
/// Use this together with the`#[pyfunction]` and [wrap_pyfunction!] or `#[pymodule]` and
|
||||||
/// [wrap_module!].
|
/// [wrap_pymodule!].
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// m.add_wrapped(wrap_function!(double));
|
/// m.add_wrapped(wrap_pyfunction!(double));
|
||||||
/// m.add_wrapped(wrap_module!(utils));
|
/// m.add_wrapped(wrap_pymodule!(utils));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// You can also add a function with a custom name using [add](PyModule::add):
|
/// You can also add a function with a custom name using [add](PyModule::add):
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// m.add("also_double", wrap_function!(double)(py));
|
/// m.add("also_double", wrap_pyfunction!(double)(py));
|
||||||
/// ```
|
/// ```
|
||||||
pub fn add_wrapped(&self, wrapper: &Fn(Python) -> PyObject) -> PyResult<()> {
|
pub fn add_wrapped(&self, wrapper: &Fn(Python) -> PyObject) -> PyResult<()> {
|
||||||
let function = wrapper(self.py());
|
let function = wrapper(self.py());
|
||||||
|
|
|
@ -2,18 +2,15 @@
|
||||||
//
|
//
|
||||||
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
||||||
|
|
||||||
use std::os::raw::{c_long, c_uchar};
|
|
||||||
|
|
||||||
extern crate num_traits;
|
|
||||||
use self::num_traits::cast::cast;
|
|
||||||
|
|
||||||
use super::num_common::{err_if_invalid_value, IS_LITTLE_ENDIAN};
|
use super::num_common::{err_if_invalid_value, IS_LITTLE_ENDIAN};
|
||||||
use conversion::{FromPyObject, IntoPyObject, ToPyObject};
|
use conversion::{FromPyObject, IntoPyObject, ToPyObject};
|
||||||
use err::{PyErr, PyResult};
|
use err::{PyErr, PyResult};
|
||||||
use ffi;
|
use ffi;
|
||||||
use instance::{Py, PyObjectWithGIL};
|
use instance::{Py, PyObjectWithGIL};
|
||||||
|
use num_traits::cast::cast;
|
||||||
use object::PyObject;
|
use object::PyObject;
|
||||||
use python::{IntoPyPointer, Python, ToPyPointer};
|
use python::{IntoPyPointer, Python, ToPyPointer};
|
||||||
|
use std::os::raw::{c_long, c_uchar};
|
||||||
use types::{exceptions, PyObjectRef};
|
use types::{exceptions, PyObjectRef};
|
||||||
|
|
||||||
/// Represents a Python `int` object.
|
/// Represents a Python `int` object.
|
||||||
|
|
|
@ -2,9 +2,6 @@
|
||||||
//
|
//
|
||||||
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
||||||
|
|
||||||
extern crate num_traits;
|
|
||||||
|
|
||||||
use self::num_traits::cast::cast;
|
|
||||||
use super::num_common::{err_if_invalid_value, IS_LITTLE_ENDIAN};
|
use super::num_common::{err_if_invalid_value, IS_LITTLE_ENDIAN};
|
||||||
use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject};
|
use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject};
|
||||||
use crate::err::{PyErr, PyResult};
|
use crate::err::{PyErr, PyResult};
|
||||||
|
@ -13,6 +10,7 @@ use crate::instance::PyObjectWithGIL;
|
||||||
use crate::object::PyObject;
|
use crate::object::PyObject;
|
||||||
use crate::python::{Python, ToPyPointer};
|
use crate::python::{Python, ToPyPointer};
|
||||||
use crate::types::{exceptions, PyObjectRef};
|
use crate::types::{exceptions, PyObjectRef};
|
||||||
|
use num_traits::cast::cast;
|
||||||
use std::i64;
|
use std::i64;
|
||||||
use std::os::raw::{c_long, c_uchar};
|
use std::os::raw::{c_long, c_uchar};
|
||||||
|
|
||||||
|
|
|
@ -105,8 +105,6 @@ pub(super) const IS_LITTLE_ENDIAN: c_int = 0;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std;
|
|
||||||
|
|
||||||
use crate::conversion::ToPyObject;
|
use crate::conversion::ToPyObject;
|
||||||
use crate::python::Python;
|
use crate::python::Python;
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
// Copyright (c) 2017-present PyO3 Project and Contributors
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
||||||
|
|
||||||
use std;
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
use std::{mem, str};
|
|
||||||
|
|
||||||
use crate::err::{PyErr, PyResult};
|
use crate::err::{PyErr, PyResult};
|
||||||
use crate::ffi;
|
use crate::ffi;
|
||||||
use crate::instance::{Py, PyObjectWithGIL};
|
use crate::instance::{Py, PyObjectWithGIL};
|
||||||
|
@ -12,6 +7,9 @@ use crate::object::PyObject;
|
||||||
use crate::python::{Python, ToPyPointer};
|
use crate::python::{Python, ToPyPointer};
|
||||||
use crate::types::exceptions;
|
use crate::types::exceptions;
|
||||||
use crate::types::PyObjectRef;
|
use crate::types::PyObjectRef;
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
use std::{mem, str};
|
||||||
|
|
||||||
/// Represents a Python `string`.
|
/// Represents a Python `string`.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
|
|
@ -2,11 +2,6 @@
|
||||||
//
|
//
|
||||||
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
||||||
|
|
||||||
use std;
|
|
||||||
use std::borrow::Cow;
|
|
||||||
use std::os::raw::c_char;
|
|
||||||
use std::str;
|
|
||||||
|
|
||||||
use err::{PyErr, PyResult};
|
use err::{PyErr, PyResult};
|
||||||
use ffi;
|
use ffi;
|
||||||
use instance::{Py, PyObjectWithGIL};
|
use instance::{Py, PyObjectWithGIL};
|
||||||
|
@ -14,6 +9,9 @@ use object::PyObject;
|
||||||
use objectprotocol::ObjectProtocol;
|
use objectprotocol::ObjectProtocol;
|
||||||
use python::IntoPyPointer;
|
use python::IntoPyPointer;
|
||||||
use python::{Python, ToPyPointer};
|
use python::{Python, ToPyPointer};
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::os::raw::c_char;
|
||||||
|
use std::str;
|
||||||
use types::exceptions;
|
use types::exceptions;
|
||||||
|
|
||||||
use super::PyObjectRef;
|
use super::PyObjectRef;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::class::*;
|
use pyo3::class::*;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyObjectRef;
|
use pyo3::types::PyObjectRef;
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use std::os::raw::{c_int, c_void};
|
|
||||||
use std::ptr;
|
|
||||||
|
|
||||||
use pyo3::class::PyBufferProtocol;
|
use pyo3::class::PyBufferProtocol;
|
||||||
use pyo3::exceptions::BufferError;
|
use pyo3::exceptions::BufferError;
|
||||||
use pyo3::ffi;
|
use pyo3::ffi;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
|
use std::os::raw::{c_int, c_void};
|
||||||
|
use std::ptr;
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
struct TestClass {
|
struct TestClass {
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::PyRawObject;
|
use pyo3::PyRawObject;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(concat_idents)]
|
#![feature(concat_idents)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::ffi::*;
|
use pyo3::ffi::*;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::{PyDate, PyDateTime, PyDict, PyObjectRef, PyTime};
|
use pyo3::types::{PyDate, PyDateTime, PyDict, PyObjectRef, PyTime};
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
extern crate pyo3;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::types::IntoPyDict;
|
||||||
use pyo3::{prelude::*, types::IntoPyDict};
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iter_dict_nosegv() {
|
fn iter_dict_nosegv() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
extern crate docmatic;
|
use docmatic;
|
||||||
|
|
||||||
use std::default::Default;
|
use std::default::Default;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use std::{isize, iter};
|
use std::{isize, iter};
|
||||||
|
|
||||||
use pyo3::class::{
|
use pyo3::class::{
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use pyo3::class::PyGCProtocol;
|
use pyo3::class::PyGCProtocol;
|
||||||
use pyo3::class::PyTraverseError;
|
use pyo3::class::PyTraverseError;
|
||||||
use pyo3::class::PyVisit;
|
use pyo3::class::PyVisit;
|
||||||
|
@ -15,6 +9,9 @@ use pyo3::python::ToPyPointer;
|
||||||
use pyo3::types::PyObjectRef;
|
use pyo3::types::PyObjectRef;
|
||||||
use pyo3::types::PyTuple;
|
use pyo3::types::PyTuple;
|
||||||
use pyo3::PyRawObject;
|
use pyo3::PyRawObject;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use std::isize;
|
use std::isize;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
use std::isize;
|
use std::isize;
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::{PyDict, PyString, PyTuple, PyType};
|
use pyo3::types::{PyDict, PyString, PyTuple, PyType};
|
||||||
use pyo3::PyRawObject;
|
use pyo3::PyRawObject;
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
use pyo3::{wrap_pyfunction, wrap_pymodule};
|
||||||
|
|
||||||
#[cfg(Py_3)]
|
#[cfg(Py_3)]
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
|
@ -47,8 +45,8 @@ fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
|
||||||
|
|
||||||
m.add("foo", "bar").unwrap();
|
m.add("foo", "bar").unwrap();
|
||||||
|
|
||||||
m.add_wrapped(wrap_function!(double)).unwrap();
|
m.add_wrapped(wrap_pyfunction!(double)).unwrap();
|
||||||
m.add("also_double", wrap_function!(double)(py)).unwrap();
|
m.add("also_double", wrap_pyfunction!(double)(py)).unwrap();
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -62,7 +60,7 @@ fn test_module_with_functions() {
|
||||||
let d = PyDict::new(py);
|
let d = PyDict::new(py);
|
||||||
d.set_item(
|
d.set_item(
|
||||||
"module_with_functions",
|
"module_with_functions",
|
||||||
wrap_module!(module_with_functions)(py),
|
wrap_pymodule!(module_with_functions)(py),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
@ -141,7 +139,7 @@ fn r#move() -> usize {
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
#[cfg(Py_3)]
|
#[cfg(Py_3)]
|
||||||
fn raw_ident_module(_py: Python, module: &PyModule) -> PyResult<()> {
|
fn raw_ident_module(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||||
module.add_wrapped(wrap_function!(r#move))
|
module.add_wrapped(wrap_pyfunction!(r#move))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -150,7 +148,7 @@ fn test_raw_idents() {
|
||||||
let gil = Python::acquire_gil();
|
let gil = Python::acquire_gil();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
|
|
||||||
let module = wrap_module!(raw_ident_module)(py);
|
let module = wrap_pymodule!(raw_ident_module)(py);
|
||||||
|
|
||||||
py_assert!(py, module, "module.move() == 42");
|
py_assert!(py, module, "module.move() == 42");
|
||||||
}
|
}
|
||||||
|
@ -164,7 +162,7 @@ fn subfunction() -> String {
|
||||||
#[cfg(Py_3)]
|
#[cfg(Py_3)]
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn submodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
fn submodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||||
module.add_wrapped(wrap_function!(subfunction))?;
|
module.add_wrapped(wrap_pyfunction!(subfunction))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,8 +175,8 @@ fn superfunction() -> String {
|
||||||
#[cfg(Py_3)]
|
#[cfg(Py_3)]
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn supermodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
fn supermodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||||
module.add_wrapped(wrap_function!(superfunction))?;
|
module.add_wrapped(wrap_pyfunction!(superfunction))?;
|
||||||
module.add_wrapped(wrap_module!(submodule))?;
|
module.add_wrapped(wrap_pymodule!(submodule))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +185,7 @@ fn supermodule(_py: Python, module: &PyModule) -> PyResult<()> {
|
||||||
fn test_module_nesting() {
|
fn test_module_nesting() {
|
||||||
let gil = GILGuard::acquire();
|
let gil = GILGuard::acquire();
|
||||||
let py = gil.python();
|
let py = gil.python();
|
||||||
let supermodule = wrap_module!(supermodule)(py);
|
let supermodule = wrap_pymodule!(supermodule)(py);
|
||||||
|
|
||||||
py_assert!(
|
py_assert!(
|
||||||
py,
|
py,
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
#![feature(custom_attribute)]
|
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::{PyDict, PyTuple};
|
use pyo3::types::{PyDict, PyTuple};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
#![feature(specialization)]
|
#![feature(specialization)]
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate pyo3;
|
|
||||||
|
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
|
use pyo3::wrap_pyfunction;
|
||||||
use std::isize;
|
use std::isize;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
@ -63,6 +61,6 @@ fn return_custom_class() {
|
||||||
assert_eq!(get_zero().unwrap().value, 0);
|
assert_eq!(get_zero().unwrap().value, 0);
|
||||||
|
|
||||||
// Using from python
|
// Using from python
|
||||||
let get_zero = wrap_function!(get_zero)(py);
|
let get_zero = wrap_pyfunction!(get_zero)(py);
|
||||||
py_assert!(py, get_zero, "get_zero().value == 0");
|
py_assert!(py, get_zero, "get_zero().value == 0");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue