Add `py` prefix to the proc macros and move them into the root module

This is important because `proc_macro_path_invoc` isn't going to be stabilized soon.
This commit is contained in:
konstin 2018-07-08 23:33:48 +02:00
parent 562d417517
commit 4013d40897
34 changed files with 282 additions and 330 deletions

View File

@ -74,12 +74,12 @@ features = ["extension-module"]
extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::modinit;
use pyo3::pymodinit;
// 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.
#[modinit(rust2py)]
#[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "sum_as_string")]
@ -97,7 +97,6 @@ fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
fn sum_as_string(a:i64, b:i64) -> String {
format!("{}", a + b).to_string()
}
```
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:

View File

@ -6,18 +6,18 @@ extern crate pyo3;
extern crate rayon;
use pyo3::prelude::*;
use pyo3::py::{class, methods, modinit};
use pyo3::{pyclass, pymethods, pymodinit};
use rayon::prelude::*;
use std::fs::File;
use std::io::prelude::*;
#[class(dict)]
#[pyclass(dict)]
struct WordCounter {
path: String,
token: PyToken,
}
#[methods]
#[pymethods]
impl WordCounter {
#[new]
fn __new__(obj: &PyRawObject, path: String) -> PyResult<()> {
@ -79,7 +79,7 @@ fn wc_parallel(lines: &str, search: &str) -> i32 {
lines.par_lines().map(|line| wc_line(line, search)).sum()
}
#[modinit(_word_count)]
#[pymodinit(_word_count)]
fn init_mod(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<WordCounter>()?;

View File

@ -10,7 +10,7 @@ use std::io::prelude::*;
use pyo3::prelude::*;
use rayon::prelude::*;
use pyo3::py::modinit;
use pyo3::pymodinit;
fn matches(word: &str, search: &str) -> bool {
let mut search = search.chars();
@ -50,7 +50,7 @@ fn wc_parallel(lines: &str, search: &str) -> i32 {
lines.par_lines().map(|line| wc_line(line, search)).sum()
}
#[modinit(_word_count)]
#[pymodinit(_word_count)]
fn init_mod(_py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "search")]
fn search(py: Python, path: String, search: String) -> PyResult<i32> {

View File

@ -1,122 +1,87 @@
# Python Class
Python class generation is powered by unstable [Procedural Macros](https://doc.rust-lang.org/book/first-edition/procedural-macros.html) and
[Specialization](https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md) and [Const fn](https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md)
features, so you need to turn on `proc_macro` and `specialization` features:
```rust
#![feature(proc_macro, specialization)]
extern crate pyo3;
```
## Define new class
To define python custom class, rust struct needs to be annotated with `#[class]` attribute.
To define python custom class, rust struct needs to be annotated with `#[pyclass]` attribute.
```rust
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
use pyo3::py::class;
use pyo3::pyclass;
#[class]
#[pyclass]
struct MyClass {
num: i32,
debug: bool,
token: PyToken,
}
```
The above example generates the following implementations for `MyClass` struct
The above example generates implementations for `PyTypeInfo` and `PyTypeObject` for `MyClass`.
```rust,ignore
impl PyTypeInfo for MyClass { ... }
impl PyTypeObject for MyClass { ... }
impl PyObjectWithToken for MyClass { ... }
impl ToPyObject for MyClass { ... }
impl IntoPyObject for MyClass { ... }
impl ToPyPointer for MyClass { ... }
```
If the class has a `PyToken` attribute, implementations for `PyObjectWithToken`, `ToPyObject`, `IntoPyObject` and `ToPyPointer` are also generated. You can only get a `PyToken` instance through the `__new__` method.
Following implementations `PyObjectWithToken`, `ToPyObject`, `IntoPyObject`, `ToPyPointer`
are generated only if struct contains `PyToken` attribute.
## Customizing the class
`PyToken` instance available only in `py.init` method.
The `#[pyclass]` macro accepts following parameters:
TODO - continue
## The `#[class]` macro
Python class generation is powered by [Procedural Macros](https://doc.rust-lang.org/book/first-edition/procedural-macros.html).
To define python custom class, rust struct needs to be annotated with `#[class]` attribute.
`class` macro accepts following parameters:
* `name=XXX` - customize class name visible to python code. By default struct name is used as
a class name.
* `name=XXX` - Set the class name shown in python code. By default struct name is used as a class name.
* `freelist=XXX` - `freelist` parameter add support of free allocation list to custom class.
The performance improvement applies to types that are often created and deleted in a row,
so that they can benefit from a freelist. `XXX` is a number of items for free list.
* `gc` - adds support for python garbage collector. classes that build with `gc` parameter
participate in python garbage collector. If custom class contains references to other
python object that can be collector `PyGCProtocol` trait has to be implemented.
* `gc` - Classes with the `gc` parameter
participate in python garbage collector. If a custom class contains references to other
python object that can be collected, the `PyGCProtocol` trait has to be implemented.
* `weakref` - adds support for python weak references
* `base=BaseType` - use custom base class. BaseType is type which is
implements `PyTypeInfo` trait.
* `subclass` - adds subclass support so that Python classes can inherit from this class
* `dict` - adds `__dict__` support, the instances of this type have a dictionary containing instance variables.
* `base=BaseType` - use a custom base class. The base BaseType must implement `PyTypeInfo`.
* `subclass` - Allows Python classes to inherit from this class
* `dict` - adds `__dict__` support, the instances of this type have a dictionary containing instance variables. (Incomplete, see [#123](https://github.com/PyO3/pyo3/issues/123))
## Constructor
By default it is not possible to create instance of custom class from python code.
To declare constructor, you need to define class method and annotate it with `#[new]`
attribute. Only python `__new__` method can be specified, `__init__` is not available.
By default it is not possible to create an instance of a custom class from python code.
To declare a constructor, you need to define a class method and annotate it with `#[new]`
attribute. Only the python `__new__` method can be specified, `__init__` is not available.
```rust
# #![feature(proc_macro, specialization)]
#
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::class;
#
# #[class]
# struct MyClass {
# num: i32,
# debug: bool,
# token: PyToken,
# }
#
use pyo3::py::methods;
use pyo3::{pyclass, pymethods};
#[methods]
#[pyclass]
struct MyClass {
num: i32,
token: PyToken,
}
#[pymethods]
impl MyClass {
#[new]
fn __new__(obj: &PyRawObject, num: Option<i32>) -> PyResult<()> {
fn __new__(obj: &PyRawObject, num: i32) -> PyResult<()> {
obj.init(|token| {
MyClass {
num: num.unwrap_or(10),
debug: false,
token: token
num,
token
}
})
}
}
```
Some rules of `new` method
Rules for the `new` method:
* If no method marked with `#[new]` is declared, object instances can only be created
from Rust, but not from Python.
* The first parameter is the raw object, custom `new` method must initialize object
with value of struct using `init` method. Type of the object may be the type object of
* The first parameter is the raw object and the custom `new` method must initialize the object
with an instance of the struct using `init` method. The type of the object may be the type object of
a derived class declared in Python.
* The first parameter implicitly has type `&PyRawObject`.
* For details on `parameter-list`, see the documentation of `Method arguments` section.
* The return type must be `PyResult<T>` for some `T` that implements `IntoPyObject`.
Usually, `T` will be `MyType`.
* The return type must be `PyResult<T>` for some `T` that implements `IntoPyObject`. Usually, `T` will be `MyType`.
## Inheritance
@ -130,15 +95,15 @@ with value of custom class struct. Subclass must call parent's `__new__` method.
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# use pyo3::{pyclass, pymethods};
#
#[class]
#[pyclass]
struct BaseClass {
val1: usize,
token: PyToken,
}
#[methods]
#[pymethods]
impl BaseClass {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -150,13 +115,13 @@ impl BaseClass {
}
}
#[class(base=BaseClass)]
#[pyclass(base=BaseClass)]
struct SubClass {
val2: usize,
token: PyToken,
}
#[methods]
#[pymethods]
impl SubClass {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -177,21 +142,21 @@ base class.
## Object properties
Descriptor methods can be defined in
`#[methods]` `impl` block only and has to be annotated with `#[getter]` or `[setter]`
`#[pymethods]` `impl` block only and has to be annotated with `#[getter]` or `[setter]`
attributes. i.e.
```rust
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# #[class]
# use pyo3::{pyclass, pymethods};
# #[pyclass]
# struct MyClass {
# num: i32,
# token: PyToken,
# }
#
#[methods]
#[pymethods]
impl MyClass {
#[getter]
@ -212,14 +177,14 @@ rust's special keywords like `type`.
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# #[class]
# use pyo3::{pyclass, pymethods};
# #[pyclass]
# struct MyClass {
# num: i32,
# token: PyToken,
# }
#
#[methods]
#[pymethods]
impl MyClass {
#[getter]
@ -244,14 +209,14 @@ If parameter is specified, it is used and property name. i.e.
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# #[class]
# use pyo3::{pyclass, pymethods};
# #[pyclass]
# struct MyClass {
# num: i32,
# token: PyToken,
# }
#
#[methods]
#[pymethods]
impl MyClass {
#[getter(number)]
@ -275,8 +240,8 @@ For simple cases you can also define getters and setters in your Rust struct fie
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
#[class]
# use pyo3::{pyclass, pymethods};
#[pyclass]
struct MyClass {
#[prop(get, set)]
num: i32
@ -288,7 +253,7 @@ Then it is available from Python code as `self.num`.
## Instance methods
To define python compatible method, `impl` block for struct has to be annotated
with `#[methods]` attribute. `pyo3` library generates python compatible
with `#[pymethods]` attribute. `pyo3` library generates python compatible
wrappers for all functions in this block with some variations, like descriptors,
class method static methods, etc.
@ -296,14 +261,14 @@ class method static methods, etc.
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# #[class]
# use pyo3::{pyclass, pymethods};
# #[pyclass]
# struct MyClass {
# num: i32,
# token: PyToken,
# }
#
#[methods]
#[pymethods]
impl MyClass {
fn method1(&self) -> PyResult<i32> {
@ -327,15 +292,15 @@ get injected by method wrapper. i.e
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# #[class]
# use pyo3::{pyclass, pymethods};
# #[pyclass]
# struct MyClass {
# num: i32,
# debug: bool,
# token: PyToken,
# }
#[methods]
#[pymethods]
impl MyClass {
fn method2(&self, py: Python) -> PyResult<i32> {
Ok(10)
@ -354,15 +319,15 @@ with`#[classmethod]` attribute.
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# #[class]
# use pyo3::{pyclass, pymethods};
# #[pyclass]
# struct MyClass {
# num: i32,
# debug: bool,
# token: PyToken,
# }
#[methods]
#[pymethods]
impl MyClass {
#[classmethod]
fn cls_method(cls: &PyType) -> PyResult<i32> {
@ -389,15 +354,15 @@ for some `T` that implements `IntoPyObject`.
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# #[class]
# use pyo3::{pyclass, pymethods};
# #[pyclass]
# struct MyClass {
# num: i32,
# debug: bool,
# token: PyToken,
# }
#[methods]
#[pymethods]
impl MyClass {
#[staticmethod]
fn static_method(param1: i32, param2: &str) -> PyResult<i32> {
@ -415,15 +380,15 @@ with `#[call]` attribute. Arguments of the method are specified same as for inst
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# #[class]
# use pyo3::{pyclass, pymethods};
# #[pyclass]
# struct MyClass {
# num: i32,
# debug: bool,
# token: PyToken,
# }
#[methods]
#[pymethods]
impl MyClass {
#[call]
#[args(args="*")]
@ -461,15 +426,15 @@ Example:
# #![feature(proc_macro, specialization)]
# extern crate pyo3;
# use pyo3::prelude::*;
# use pyo3::py::*;
# #[class]
# use pyo3::{pyclass, pymethods};
# #[pyclass]
# struct MyClass {
# num: i32,
# debug: bool,
# token: PyToken,
# }
#
#[methods]
#[pymethods]
impl MyClass {
#[args(arg1=true, args="*", arg2=10, kwargs="**")]
fn method(&self, arg1: bool, args: &PyTuple, arg2: i32, kwargs: Option<&PyDict>) -> PyResult<i32> {
@ -485,7 +450,7 @@ Python object model defines several protocols for different object behavior,
like sequence, mapping or number protocols. pyo3 library defines separate trait for each
of them. To provide specific python object behavior you need to implement specific trait
for your struct. Important note, each protocol implementation block has to be annotated
with `#[proto]` attribute.
with `#[pyproto]` attribute.
### Basic object customization
@ -566,15 +531,15 @@ Example:
extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::{class, proto};
use pyo3::{pyclass, pyproto};
#[class]
#[pyclass]
struct ClassWithGCSupport {
obj: Option<PyObject>,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyGCProtocol for ClassWithGCSupport {
fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> {
if let Some(ref obj) = self.obj {
@ -592,10 +557,10 @@ impl PyGCProtocol for ClassWithGCSupport {
}
```
Special protocol trait implementation has to be annotated with `#[proto]` attribute.
Special protocol trait implementation has to be annotated with `#[pyproto]` attribute.
It is also possible to enable gc for custom class using `gc` parameter for `class` annotation.
i.e. `#[class(gc)]`. In that case instances of custom class participate in python garbage
i.e. `#[pyclass(gc)]`. In that case instances of custom class participate in python garbage
collector, and it is possible to track them with `gc` module methods.
### Iterator Types
@ -609,20 +574,21 @@ It includes two methods `__iter__` and `__next__`:
Returning `Ok(None)` from `__next__` indicates that that there are no further items.
Example:
```rust
#![feature(proc_macro, specialization)]
extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::*;
use pyo3::{pyclass, pyproto};
#[class]
#[pyclass]
struct MyIterator {
iter: Box<Iterator<Item=PyObject> + Send>,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyIterProtocol for MyIterator {
fn __iter__(&mut self) -> PyResult<PyObject> {
@ -632,5 +598,4 @@ impl PyIterProtocol for MyIterator {
Ok(self.iter.next())
}
}
# fn main() {}
```

View File

@ -1,9 +1,9 @@
# Debugging
Pyo3's attributes, `#[class]`, `#[modinit]`, etc. are [procedural macros](https://doc.rust-lang.org/unstable-book/language-features/proc-macro.html), which means that rewrite the source of the annotated item. You can view the generated source with the following command, which also expands a few other things:
Pyo3's attributes, `#[pyclass]`, `#[pymodinit]`, etc. are [procedural macros](https://doc.rust-lang.org/unstable-book/language-features/proc-macro.html), which means that rewrite the source of the annotated item. You can view the generated source with the following command, which also expands a few other things:
```bash
cargo rustc -- -Z unstable-options --pretty=expanded > expanded.rs; rustfmt expanded.rs
cargo rustc --profile=check -- -Z unstable-options --pretty=expanded > expanded.rs; rustfmt expanded.rs
```
(You might need to install [rustfmt](https://github.com/rust-lang-nursery/rustfmt) if you don't already have it.)
@ -11,5 +11,7 @@ cargo rustc -- -Z unstable-options --pretty=expanded > expanded.rs; rustfmt expa
You can also debug classic `!`-macros by adding -Z trace-macros`:
```bash
cargo rustc -- -Z unstable-options --pretty=expanded -Z trace-macros > expanded.rs; rustfmt expanded.rs
cargo rustc --profile=check -- -Z unstable-options --pretty=expanded -Z trace-macros > expanded.rs; rustfmt expanded.rs
```
See [cargo expand](https://github.com/dtolnay/cargo-expand) for a more elaborate version of those commands.

View File

@ -9,10 +9,10 @@ One way is defining the function in the module definition.
#![feature(proc_macro)]
extern crate pyo3;
use pyo3::{py, PyResult, Python, PyModule};
use pyo3::py::modint;
use pyo3::prelude::*;
use pyo3::pymodinit;
#[modinit(rust2py)]
#[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
// Note that the `#[pyfn()]` annotation automatically converts the arguments from
@ -38,17 +38,16 @@ as third.
#[macro_use]
extern crate pyo3;
use pyo3::{py, PyResult, Python, PyModule};
use pyo3::prelude::*;
use pyo3::py::function as pyfunction;
use pyo3::py::modint;
use pyo3::{pyfunction, pymodinit};
#[pyfunction]
fn double(x: usize) -> usize {
x * 2
}
#[modinit(module_with_functions)]
#[pymodinit(module_with_functions)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_function!(double)).unwrap();

View File

@ -6,14 +6,14 @@ As shown in the Getting Started chapter, you can create a module as follows:
#![feature(proc_macro)]
extern crate pyo3;
use pyo3::{py, PyResult, Python, PyModule};
use pyo3::{PyResult, Python, PyModule};
use pyo3::py::modint;
use pyo3::pymodinit;
// 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.
#[modinit(rust2py)]
#[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
// pyo3 aware function. All of our python interface could be declared in a separate module.
@ -36,7 +36,7 @@ fn sum_as_string(a:i64, b:i64) -> String {
# fn main() {}
```
The `modinit` procedural macro attribute takes care of exporting the initialization function of your module to Python. It takes one argument as the name of your module, it must be the name of the `.so` or `.pyd` file.
The `#[pymodinit}` procedural macro attribute takes care of exporting the initialization function of your module to Python. It takes one argument as the name of your module, it must be the name of the `.so` or `.pyd` file.
The [Rust doc comments](https://doc.rust-lang.org/stable/book/first-edition/comments.html) of the module initialization function will be applied automatically as the Python doc string of your module.

View File

@ -64,12 +64,12 @@ features = ["extension-module"]
extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::modint;
use pyo3::pymodinit;
// 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.
#[modinit(rust2py)]
#[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "sum_as_string")]

View File

@ -28,7 +28,7 @@ Then in the Python bridge, we have a function `search` exposed to Python runtime
`Python::allow_threads` method to enable true parallelism:
```rust,ignore
#[modinit(_word_count)]
#[pymodinit(_word_count)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "search")]

View File

@ -30,14 +30,14 @@ py_class!(class MyClass |py| {
extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::{class, methods};
use pyo3::{pyclass, pymethods};
#[class]
#[pyclass]
struct MyClass {
num: u32,
}
#[methods]
#[pymethods]
impl MyClass {
#[new]
fn __new__(obj: &PyRawObject, num: u32) -> PyResult<()> {

View File

@ -1,6 +1,6 @@
[package]
name = "pyo3-derive-backend"
version = "0.2.5"
version = "0.3.0"
description = "Code generation for PyO3 package"
authors = ["PyO3 Project and Contributors <https://github.com/PyO3>"]
keywords = ["pyo3", "python", "cpython", "ffi"]

View File

@ -92,7 +92,7 @@ pub fn py2_init(fnname: &syn::Ident, name: &syn::Ident, doc: syn::Lit) -> TokenS
}
}
/// Finds and takes care of the #[pyfn(...)] in #[modinit(...)]
/// Finds and takes care of the #[pyfn(...)] in #[pymodinit(...)]
pub fn process_functions_in_module(func: &mut syn::ItemFn) {
let mut stmts: Vec<syn::Stmt> = Vec::new();

View File

@ -29,7 +29,7 @@ pub fn build_py_class(class: &mut syn::ItemStruct, attr: &Vec<syn::Expr>) -> Tok
}
}
} else {
panic!("#[class] can only be used with C-style structs")
panic!("#[pyclass] can only be used with C-style structs")
}
impl_class(&class.ident, &base, token, doc, params, flags, descriptors)

View File

@ -7,7 +7,7 @@ use py_method;
pub fn build_py_methods(ast: &mut syn::ItemImpl) -> TokenStream {
if ast.trait_.is_some() {
panic!("#[methods] can not be used only with trait impl block");
panic!("#[pymethods] can not be used only with trait impl block");
} else {
impl_methods(&ast.self_ty, &mut ast.items)
}

View File

@ -26,12 +26,12 @@ pub fn build_py_proto(ast: &mut syn::ItemImpl) -> TokenStream {
"PyBufferProtocol" => impl_proto_impl(ty, items, &defs::BUFFER),
"PyGCProtocol" => impl_proto_impl(ty, items, &defs::GC),
_ => {
warn!("#[proto] can not be used with this block");
warn!("#[pyproto] can not be used with this block");
return TokenStream::new();
}
}
} else {
panic!("#[proto] can only be used with protocol trait implementations")
panic!("#[pyproto] can only be used with protocol trait implementations")
};
// attach lifetime
@ -42,7 +42,7 @@ pub fn build_py_proto(ast: &mut syn::ItemImpl) -> TokenStream {
tokens
} else {
panic!("#[proto] can only be used with protocol trait implementations")
panic!("#[pyproto] can only be used with protocol trait implementations")
}
}

View File

@ -24,7 +24,7 @@ pub fn mod2init(
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
// Parse the token stream into a syntax tree
let mut ast: syn::ItemFn = syn::parse(input).expect("#[modinit] must be used on a function");
let mut ast: syn::ItemFn = syn::parse(input).expect("#[pymodinit] must be used on a function");
// Extract the mod name
let modname: syn::Ident = syn::parse(attr).expect("could not parse module name");
@ -47,7 +47,7 @@ pub fn mod3init(
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
// Parse the token stream into a syntax tree
let mut ast: syn::ItemFn = syn::parse(input).expect("#[modinit] must be used on a `fn` block");
let mut ast: syn::ItemFn = syn::parse(input).expect("#[pymodinit] must be used on a `fn` block");
// Extract the mod name
let modname: syn::Ident = syn::parse(attr).expect("could not parse module name");
@ -65,13 +65,13 @@ pub fn mod3init(
}
#[proc_macro_attribute]
pub fn proto(
pub fn pyproto(
_: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
// Parse the token stream into a syntax tree
let mut ast: syn::ItemImpl =
syn::parse(input).expect("#[proto] must be used on an `impl` block");
syn::parse(input).expect("#[pyproto] must be used on an `impl` block");
// Build the output
let expanded = py_proto::build_py_proto(&mut ast);
@ -83,12 +83,12 @@ pub fn proto(
}
#[proc_macro_attribute]
pub fn class(
pub fn pyclass(
attr: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
// Parse the token stream into a syntax tree
let mut ast: syn::ItemStruct = syn::parse(input).expect("#[class] must be used on a `struct`");
let mut ast: syn::ItemStruct = syn::parse(input).expect("#[pyclass] must be used on a `struct`");
// Parse the macro arguments into a list of expressions
let args: Vec<syn::Expr> = {
@ -110,13 +110,13 @@ pub fn class(
}
#[proc_macro_attribute]
pub fn methods(
pub fn pymethods(
_: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
// Parse the token stream into a syntax tree
let mut ast: syn::ItemImpl =
syn::parse(input.clone()).expect("#[methods] must be used on an `impl` block");
syn::parse(input.clone()).expect("#[pymethods] must be used on an `impl` block");
// Build the output
let expanded = py_impl::build_py_methods(&mut ast);
@ -128,7 +128,7 @@ pub fn methods(
}
#[proc_macro_attribute]
pub fn function(
pub fn pyfunction(
_: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {

View File

@ -8,7 +8,7 @@ use ffi;
static NO_PY_METHODS: &'static [PyMethodDefType] = &[];
/// `PyMethodDefType` represents different types of python callable objects.
/// It is used by `#[methods]` and `#[proto]` annotations.
/// It is used by `#[pymethods]` and `#[pyproto]` annotations.
#[derive(Debug)]
pub enum PyMethodDefType {
/// Represents class `__new__` method

View File

@ -32,6 +32,7 @@ pub use self::methods::{PyMethodDef, PyMethodDefType, PyMethodType,
use ffi;
/// Operators for the __richcmp__ method
#[derive(Debug)]
pub enum CompareOp {
Lt = ffi::Py_LT as isize,

View File

@ -29,22 +29,21 @@
//! # Example
//!
//! ```rust
//! #![feature(proc_macro, specialization)]
//!
//! extern crate pyo3;
//!
//! use pyo3::{Python, PyDict, PyResult, ObjectProtocol};
//! use pyo3::prelude::*;
//!
//! fn main() {
//! fn main() -> PyResult<()> {
//! let gil = Python::acquire_gil();
//! hello(gil.python()).unwrap();
//! }
//!
//! fn hello(py: Python) -> PyResult<()> {
//! let py = gil.python();
//! let sys = py.import("sys")?;
//! let version: String = sys.get("version")?.extract()?;
//!
//! let locals = PyDict::new(py);
//! locals.set_item("os", py.import("os")?)?;
//! let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(locals))?.extract()?;
//! let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract()?;
//!
//! println!("Hello {}, I'm Python {}", user, version);
//! Ok(())
@ -54,10 +53,10 @@
//! # Python extension
//!
//! To allow Python to load the rust code as a Python extension
//! module, you need provide initialization function and annotate it with `#[modinit(name)]`.
//! module, you need provide initialization function and annotate it with `#[pymodinit(name)]`.
//! `pymodinit` expands to an `extern "C"` function.
//!
//! Macro syntax: `#[modinit(name)]`
//! Macro syntax: `#[pymodinit(name)]`
//!
//! 1. `name`: The module name as a Rust identifier
//! 2. Decorate init function `Fn(Python, &PyModule) -> PyResult<()>`.
@ -80,28 +79,30 @@
//! extern crate pyo3;
//! use pyo3::prelude::*;
//!
//! use pyo3::py::modinit;
//! use pyo3::pymodinit;
//!
//! // add bindings to the generated python module
//! // N.B: names: "libhello" must be the name of the `.so` or `.pyd` file
//! // 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.
//! #[pymodinit(rust2py)]
//! fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
//!
//! /// Module documentation string
//! #[modinit(hello)]
//! fn init_module(py: Python, m: &PyModule) -> PyResult<()> {
//!
//! // pyo3 aware function. All of our python interface could be declared
//! // in a separate module.
//! // Note that the `#[pyfn()]` annotation automatically converts the arguments from
//! // Python objects to Rust values; and the Rust return value back into a Python object.
//! #[pyfn(m, "run_rust_func")]
//! fn run(name: &PyString) -> PyResult<()> {
//! println!("Rust says: Hello {} of Python!", name);
//! Ok(())
//! #[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() {}
//! ```
//!
@ -113,29 +114,19 @@
//! features = ["extension-module"]
//! ```
//!
//! The full example project can be found at:
//! <https://github.com/PyO3/setuptools-rust/tree/master/example/>
//! 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:
//!
//! Rust will compile the code into a file named `libhello.so`, but we have to
//! rename the file in order to use it with Python:
//!
//! ```bash
//! cp ./target/debug/libhello.so ./hello.so
//! ```toml
//! [target.x86_64-apple-darwin]
//! rustflags = [
//! "-C", "link-arg=-undefined",
//! "-C", "link-arg=dynamic_lookup",
//! ]
//! ```
//!
//! (Note: on macOS you will have to rename `libhello.dynlib` to `libhello.so`.
//! To build on macOS, use `-C link-arg=-undefined -C link-arg=dynamic_lookup`
//! is required to build the library.
//! `setuptools-rust` includes this by default.
//! See [examples/word-count](https://github.com/PyO3/pyo3/tree/master/examples/word-count).)
//! 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.
//!
//! The extension module can then be imported into Python:
//!
//! ```python,ignore
//! >>> import hello
//! >>> hello.run_rust_func("test")
//! Rust says: Hello Python!
//! ```
//! [`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.
extern crate libc;
extern crate spin;
@ -172,16 +163,13 @@ pub use conversion::{FromPyObject, PyTryFrom, PyTryInto,
pub mod class;
pub use class::*;
/// Procedural macros
pub mod py {
pub use pyo3cls::{proto, class, methods, function};
pub use pyo3cls::{pyproto, pyclass, pymethods, pyfunction};
#[cfg(Py_3)]
pub use pyo3cls::mod3init as modinit;
#[cfg(Py_3)]
pub use pyo3cls::mod3init as pymodinit;
#[cfg(not(Py_3))]
pub use pyo3cls::mod2init as modinit;
}
#[cfg(not(Py_3))]
pub use pyo3cls::mod2init as pymodinit;
/// Constructs a `&'static CStr` literal.
macro_rules! cstr {

View File

@ -169,7 +169,7 @@ impl PyModule {
/// Adds a function to a module, using the functions __name__ as name.
///
/// Use this together with the`#[function]` and [wrap_function!] macro.
/// Use this together with the`#[pyfunction]` and [wrap_function!] macro.
///
/// ```rust,ignore
/// m.add_function(wrap_function!(double));
@ -178,7 +178,7 @@ impl PyModule {
/// You can also add a function with a custom name using [add](PyModule::add):
///
/// ```rust,ignore
/// m.add("also_double", wrap_function!(double)(py));
/// m.add("also_double", wrap_function!(double)(py));
/// ```
pub fn add_function(&self, wrapper: &Fn(Python) -> PyObject) -> PyResult<()> {
let function = wrapper(self.py());

View File

@ -10,7 +10,6 @@
//! use pyo3::prelude::*;
//! ```
pub use super::py;
pub use class::*;
pub use objects::*;
pub use objectprotocol::ObjectProtocol;

View File

@ -27,7 +27,7 @@ static START_PYO3: sync::Once = sync::ONCE_INIT;
/// thread (the thread which originally initialized Python) also initializes
/// threading.
///
/// When writing an extension module, the `#[modinit(..)]` macro
/// When writing an extension module, the `#[pymodinit(..)]` macro
/// will ensure that Python threading is initialized.
///
pub fn prepare_freethreaded_python() {

View File

@ -103,15 +103,14 @@ impl<'a, T: ?Sized> PyTypeInfo for &'a T where T: PyTypeInfo {
///
/// Example of custom class implementation with `__new__` method:
/// ```rust,ignore
/// use pyo3::py::class;
/// use pyo3::py::methods;
/// use pyo3::{pyclass, pymethods};
///
/// #[class]
/// #[pyclass]
/// struct MyClass {
/// token: PyToken
/// }
///
/// #[methods]
/// #[pymethods]
/// impl MyClass {
/// #[new]
/// fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -212,7 +211,7 @@ impl PyObjectWithToken for PyRawObject {
}
}
/// A Python object allocator that is usable as a base type for #[class]
/// A Python object allocator that is usable as a base type for #[pyclass]
pub trait PyObjectAlloc<T> {
/// Allocates a new object (usually by calling ty->tp_alloc),

View File

@ -3,17 +3,17 @@
extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::{class, proto};
use pyo3::{pyclass, pyproto};
#[macro_use]
mod common;
#[class]
#[pyclass]
struct UnaryArithmetic {
token: PyToken,
}
#[proto]
#[pyproto]
impl PyNumberProtocol for UnaryArithmetic {
fn __neg__(&self) -> PyResult<&'static str> {
Ok("neg")
@ -44,32 +44,32 @@ fn unary_arithmetic() {
py_run!(py, c, "assert ~c == 'invert'");
}
#[class]
#[pyclass]
struct BinaryArithmetic {
token: PyToken,
}
#[proto]
#[pyproto]
impl PyObjectProtocol for BinaryArithmetic {
fn __repr__(&self) -> PyResult<&'static str> {
Ok("BA")
}
}
#[class]
#[pyclass]
struct InPlaceOperations {
value: u32,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyObjectProtocol for InPlaceOperations {
fn __repr__(&self) -> PyResult<String> {
Ok(format!("IPO({:?})", self.value))
}
}
#[proto]
#[pyproto]
impl PyNumberProtocol for InPlaceOperations {
fn __iadd__(&mut self, other: u32) -> PyResult<()> {
self.value += other;
@ -132,7 +132,7 @@ fn inplace_operations() {
init(12, "d = c; c ^= 5; assert repr(c) == repr(d) == 'IPO(9)'");
}
#[proto]
#[pyproto]
impl PyNumberProtocol for BinaryArithmetic {
fn __add__(lhs: &PyObjectRef, rhs: &PyObjectRef) -> PyResult<String> {
Ok(format!("{:?} + {:?}", lhs, rhs))
@ -193,12 +193,12 @@ fn binary_arithmetic() {
py_run!(py, c, "assert 1 | c == '1 | BA'");
}
#[class]
#[pyclass]
struct RichComparisons {
token: PyToken,
}
#[proto]
#[pyproto]
impl PyObjectProtocol for RichComparisons {
fn __repr__(&self) -> PyResult<&'static str> {
Ok("RC")
@ -216,12 +216,12 @@ impl PyObjectProtocol for RichComparisons {
}
}
#[class]
#[pyclass]
struct RichComparisons2 {
py: PyToken,
}
#[proto]
#[pyproto]
impl PyObjectProtocol for RichComparisons2 {
fn __repr__(&self) -> PyResult<&'static str> {
Ok("RC2")

View File

@ -8,16 +8,16 @@ use std::ptr;
use pyo3::ffi;
use pyo3::prelude::*;
use pyo3::py::class;
use pyo3::py::proto;
use pyo3::pyclass;
use pyo3::pyproto;
#[class]
#[pyclass]
struct TestClass {
vec: Vec<u8>,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyBufferProtocol for TestClass {
fn bf_getbuffer(&self, view: *mut ffi::Py_buffer, flags: c_int) -> PyResult<()> {
if view.is_null() {

View File

@ -4,12 +4,12 @@ extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::class;
use pyo3::pyclass;
#[macro_use]
mod common;
#[class]
#[pyclass]
struct EmptyClass {}
#[test]
@ -27,7 +27,7 @@ fn empty_class() {
///Line2
/// Line3
// this is not doc string
#[class]
#[pyclass]
struct ClassWithDocs {}
#[test]
@ -44,7 +44,7 @@ fn class_with_docstr() {
}
}
#[class(name=CustomName)]
#[pyclass(name=CustomName)]
struct EmptyClass2 {}
#[test]
@ -55,7 +55,7 @@ fn custom_class_name() {
py_assert!(py, typeobj, "typeobj.__name__ == 'CustomName'");
}
#[class]
#[pyclass]
struct EmptyClassInModule {}
#[test]

View File

@ -4,15 +4,15 @@ extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::class;
use pyo3::py::methods;
use pyo3::pyclass;
use pyo3::pymethods;
#[class]
#[pyclass]
struct EmptyClassWithNew {
token: PyToken,
}
#[methods]
#[pymethods]
impl EmptyClassWithNew {
#[__new__]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -34,13 +34,13 @@ fn empty_class_with_new() {
);
}
#[class]
#[pyclass]
struct NewWithOneArg {
_data: i32,
token: PyToken,
}
#[methods]
#[pymethods]
impl NewWithOneArg {
#[new]
fn __new__(obj: &PyRawObject, arg: i32) -> PyResult<()> {
@ -61,7 +61,7 @@ fn new_with_one_arg() {
assert_eq!(obj._data, 42);
}
#[class]
#[pyclass]
struct NewWithTwoArgs {
_data1: i32,
_data2: i32,
@ -69,7 +69,7 @@ struct NewWithTwoArgs {
token: PyToken,
}
#[methods]
#[pymethods]
impl NewWithTwoArgs {
#[new]
fn __new__(obj: &PyRawObject, arg1: i32, arg2: i32) -> PyResult<()> {

View File

@ -6,20 +6,20 @@ use pyo3::ffi;
use pyo3::prelude::*;
use std::{isize, iter};
use pyo3::py::class;
use pyo3::py::methods;
use pyo3::py::proto;
use pyo3::pyclass;
use pyo3::pymethods;
use pyo3::pyproto;
#[macro_use]
mod common;
#[class]
#[pyclass]
pub struct Len {
l: usize,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyMappingProtocol for Len {
fn __len__(&self) -> PyResult<usize> {
Ok(self.l)
@ -45,13 +45,13 @@ fn len() {
py_expect_exception!(py, inst, "len(inst)", OverflowError);
}
#[class]
#[pyclass]
struct Iterator {
iter: Box<iter::Iterator<Item = i32> + Send>,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyIterProtocol for Iterator {
fn __iter__(&mut self) -> PyResult<Py<Iterator>> {
Ok(self.into())
@ -75,12 +75,12 @@ fn iterator() {
py_assert!(py, inst, "list(inst) == [5, 6, 7]");
}
#[class]
#[pyclass]
struct StringMethods {
token: PyToken,
}
#[proto]
#[pyproto]
impl<'p> PyObjectProtocol<'p> for StringMethods {
fn __str__(&self) -> PyResult<&'static str> {
Ok("str")
@ -129,13 +129,13 @@ fn string_methods() {
py_assert!(py, obj, "'{0:x}'.format(obj) == 'format(x)'");
}
#[class]
#[pyclass]
struct Comparisons {
val: i32,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyObjectProtocol for Comparisons {
fn __hash__(&self) -> PyResult<isize> {
Ok(self.val as isize)
@ -162,12 +162,12 @@ fn comparisons() {
py_assert!(py, zero, "not zero");
}
#[class]
#[pyclass]
struct Sequence {
token: PyToken,
}
#[proto]
#[pyproto]
impl PySequenceProtocol for Sequence {
fn __len__(&self) -> PyResult<usize> {
Ok(5)
@ -191,12 +191,12 @@ fn sequence() {
py_expect_exception!(py, c, "c['abc']", TypeError);
}
#[class]
#[pyclass]
struct Callable {
token: PyToken,
}
#[methods]
#[pymethods]
impl Callable {
#[__call__]
fn __call__(&self, arg: i32) -> PyResult<i32> {
@ -217,14 +217,14 @@ fn callable() {
py_assert!(py, nc, "not callable(nc)");
}
#[class]
#[pyclass]
struct SetItem {
key: i32,
val: i32,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyMappingProtocol<'a> for SetItem {
fn __setitem__(&mut self, key: i32, val: i32) -> PyResult<()> {
self.key = key;
@ -250,13 +250,13 @@ fn setitem() {
py_expect_exception!(py, c, "del c[1]", NotImplementedError);
}
#[class]
#[pyclass]
struct DelItem {
key: i32,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyMappingProtocol<'a> for DelItem {
fn __delitem__(&mut self, key: i32) -> PyResult<()> {
self.key = key;
@ -275,13 +275,13 @@ fn delitem() {
py_expect_exception!(py, c, "c[1] = 2", NotImplementedError);
}
#[class]
#[pyclass]
struct SetDelItem {
val: Option<i32>,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyMappingProtocol for SetDelItem {
fn __setitem__(&mut self, _key: i32, val: i32) -> PyResult<()> {
self.val = Some(val);
@ -310,12 +310,12 @@ fn setdelitem() {
assert_eq!(c.val, None);
}
#[class]
#[pyclass]
struct Reversed {
token: PyToken,
}
#[proto]
#[pyproto]
impl PyMappingProtocol for Reversed {
fn __reversed__(&self) -> PyResult<&'static str> {
Ok("I am reversed")
@ -331,12 +331,12 @@ fn reversed() {
py_run!(py, c, "assert reversed(c) == 'I am reversed'");
}
#[class]
#[pyclass]
struct Contains {
token: PyToken,
}
#[proto]
#[pyproto]
impl PySequenceProtocol for Contains {
fn __contains__(&self, item: i32) -> PyResult<bool> {
Ok(item >= 0)
@ -354,13 +354,13 @@ fn contains() {
py_expect_exception!(py, c, "assert 'wrong type' not in c", TypeError);
}
#[class]
#[pyclass]
struct ContextManager {
exit_called: bool,
token: PyToken,
}
#[proto]
#[pyproto]
impl<'p> PyContextProtocol<'p> for ContextManager {
fn __enter__(&mut self) -> PyResult<i32> {
Ok(42)
@ -421,12 +421,12 @@ fn test_basics() {
assert_eq!(5, indices.slicelength);
}
#[class]
#[pyclass]
struct Test {
token: PyToken,
}
#[proto]
#[pyproto]
impl<'p> PyMappingProtocol<'p> for Test {
fn __getitem__(&self, idx: &PyObjectRef) -> PyResult<PyObject> {
if let Ok(slice) = idx.cast_as::<PySlice>() {
@ -457,7 +457,7 @@ fn test_cls_impl() {
.unwrap();
}
#[class(dict)]
#[pyclass(dict)]
struct DunderDictSupport {
token: PyToken,
}
@ -477,7 +477,7 @@ fn dunder_dict_support() {
);
}
#[class(weakref, dict)]
#[pyclass(weakref, dict)]
struct WeakRefDunderDictSupport {
token: PyToken,
}

View File

@ -8,14 +8,14 @@ use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use pyo3::py::class;
use pyo3::py::methods;
use pyo3::py::proto;
use pyo3::pyclass;
use pyo3::pymethods;
use pyo3::pyproto;
#[macro_use]
mod common;
#[class(freelist = 2)]
#[pyclass(freelist = 2)]
struct ClassWithFreelist {
token: PyToken,
}
@ -55,7 +55,7 @@ impl Drop for TestDropCall {
}
#[allow(dead_code)]
#[class]
#[pyclass]
struct DataIsDropped {
member1: TestDropCall,
member2: TestDropCall,
@ -89,7 +89,7 @@ fn data_is_dropped() {
assert!(drop_called2.load(Ordering::Relaxed));
}
#[class]
#[pyclass]
struct ClassWithDrop {
token: PyToken,
}
@ -136,14 +136,14 @@ fn create_pointers_in_drop() {
}
#[allow(dead_code)]
#[class]
#[pyclass]
struct GCIntegration {
self_ref: RefCell<PyObject>,
dropped: TestDropCall,
token: PyToken,
}
#[proto]
#[pyproto]
impl PyGCProtocol for GCIntegration {
fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> {
visit.call(&*self.self_ref.borrow())
@ -178,7 +178,7 @@ fn gc_integration() {
assert!(drop_called.load(Ordering::Relaxed));
}
#[class(gc)]
#[pyclass(gc)]
struct GCIntegration2 {
token: PyToken,
}
@ -190,7 +190,7 @@ fn gc_integration2() {
py_run!(py, inst, "import gc; assert inst in gc.get_objects()");
}
#[class(weakref)]
#[pyclass(weakref)]
struct WeakRefSupport {
token: PyToken,
}
@ -206,13 +206,13 @@ fn weakref_support() {
);
}
#[class]
#[pyclass]
struct BaseClassWithDrop {
token: PyToken,
data: Option<Arc<AtomicBool>>,
}
#[methods]
#[pymethods]
impl BaseClassWithDrop {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -231,13 +231,13 @@ impl Drop for BaseClassWithDrop {
}
}
#[class(base=BaseClassWithDrop)]
#[pyclass(base=BaseClassWithDrop)]
struct SubClassWithDrop {
token: PyToken,
data: Option<Arc<AtomicBool>>,
}
#[methods]
#[pymethods]
impl SubClassWithDrop {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {

View File

@ -5,19 +5,19 @@ extern crate pyo3;
use pyo3::prelude::*;
use std::isize;
use pyo3::py::class;
use pyo3::py::methods;
use pyo3::pyclass;
use pyo3::pymethods;
#[macro_use]
mod common;
#[class]
#[pyclass]
struct ClassWithProperties {
num: i32,
token: PyToken,
}
#[methods]
#[pymethods]
impl ClassWithProperties {
fn get_num(&self) -> PyResult<i32> {
Ok(self.num)
@ -50,7 +50,7 @@ fn class_with_properties() {
py_run!(py, inst, "assert inst.get_num() == inst.DATA");
}
#[class]
#[pyclass]
struct GetterSetter {
token: PyToken,
#[prop(get, set)]
@ -59,7 +59,7 @@ struct GetterSetter {
text: String,
}
#[methods]
#[pymethods]
impl GetterSetter {
fn get_num2(&self) -> PyResult<i32> {
Ok(self.num)

View File

@ -5,18 +5,18 @@ extern crate pyo3;
use pyo3::prelude::*;
use std::isize;
use pyo3::py::{class, methods};
use pyo3::{pyclass, pymethods};
#[macro_use]
mod common;
#[class]
#[pyclass]
struct BaseClass {
#[prop(get)]
val1: usize,
}
#[class(subclass)]
#[pyclass(subclass)]
struct SubclassAble {}
#[test]
@ -35,7 +35,7 @@ fn subclass() {
.unwrap();
}
#[methods]
#[pymethods]
impl BaseClass {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -43,13 +43,13 @@ impl BaseClass {
}
}
#[class(base=BaseClass)]
#[pyclass(base=BaseClass)]
struct SubClass {
#[prop(get)]
val2: usize,
}
#[methods]
#[pymethods]
impl SubClass {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {

View File

@ -4,19 +4,19 @@ extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::class;
use pyo3::py::methods;
use pyo3::pyclass;
use pyo3::pymethods;
#[macro_use]
mod common;
#[class]
#[pyclass]
struct InstanceMethod {
member: i32,
token: PyToken,
}
#[methods]
#[pymethods]
impl InstanceMethod {
/// Test method
fn method(&self) -> PyResult<i32> {
@ -42,13 +42,13 @@ fn instance_method() {
.unwrap();
}
#[class]
#[pyclass]
struct InstanceMethodWithArgs {
member: i32,
token: PyToken,
}
#[methods]
#[pymethods]
impl InstanceMethodWithArgs {
fn method(&self, multiplier: i32) -> PyResult<i32> {
Ok(self.member * multiplier)
@ -74,12 +74,12 @@ fn instance_method_with_args() {
.unwrap();
}
#[class]
#[pyclass]
struct ClassMethod {
token: PyToken,
}
#[methods]
#[pymethods]
impl ClassMethod {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -111,12 +111,12 @@ fn class_method() {
).unwrap();
}
#[class]
#[pyclass]
struct ClassMethodWithArgs {
token: PyToken,
}
#[methods]
#[pymethods]
impl ClassMethodWithArgs {
#[classmethod]
fn method(cls: &PyType, input: &PyString) -> PyResult<String> {
@ -139,12 +139,12 @@ fn class_method_with_args() {
).unwrap();
}
#[class]
#[pyclass]
struct StaticMethod {
token: PyToken,
}
#[methods]
#[pymethods]
impl StaticMethod {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -177,12 +177,12 @@ fn static_method() {
).unwrap();
}
#[class]
#[pyclass]
struct StaticMethodWithArgs {
token: PyToken,
}
#[methods]
#[pymethods]
impl StaticMethodWithArgs {
#[staticmethod]
fn method(_py: Python, input: i32) -> PyResult<String> {
@ -204,12 +204,12 @@ fn static_method_with_args() {
.unwrap();
}
#[class]
#[pyclass]
struct MethArgs {
token: PyToken,
}
#[methods]
#[pymethods]
impl MethArgs {
#[args(test)]
fn get_optional(&self, test: Option<i32>) -> PyResult<i32> {

View File

@ -4,22 +4,22 @@
extern crate pyo3;
use pyo3::prelude::*;
use pyo3::py::{class, function, modinit};
use pyo3::{pyclass, pyfunction, pymodinit};
#[class]
#[pyclass]
struct EmptyClass {}
fn sum_as_string(a: i64, b: i64) -> String {
format!("{}", a + b).to_string()
}
#[function]
#[pyfunction]
fn double(x: usize) -> usize {
x * 2
}
/// This module is implemented in Rust.
#[modinit(module_with_functions)]
#[pymodinit(module_with_functions)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "sum_as_string")]
fn sum_as_string_py(_py: Python, a: i64, b: i64) -> PyResult<String> {

View File

@ -5,19 +5,19 @@ extern crate pyo3;
use pyo3::prelude::*;
use std::isize;
use pyo3::py::class;
use pyo3::py::methods;
use pyo3::pyclass;
use pyo3::pymethods;
#[macro_use]
mod common;
#[class]
#[pyclass]
struct MutRefArg {
n: i32,
token: PyToken,
}
#[methods]
#[pymethods]
impl MutRefArg {
fn get(&self) -> PyResult<i32> {
Ok(self.n)