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; extern crate pyo3;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py::modinit; use pyo3::pymodinit;
// 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
/// This module is implemented in Rust. /// This module is implemented in Rust.
#[modinit(rust2py)] #[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> { fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "sum_as_string")] #[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 { fn sum_as_string(a:i64, b:i64) -> String {
format!("{}", a + b).to_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: 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; extern crate rayon;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py::{class, methods, modinit}; use pyo3::{pyclass, pymethods, pymodinit};
use rayon::prelude::*; use rayon::prelude::*;
use std::fs::File; use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
#[class(dict)] #[pyclass(dict)]
struct WordCounter { struct WordCounter {
path: String, path: String,
token: PyToken, token: PyToken,
} }
#[methods] #[pymethods]
impl WordCounter { impl WordCounter {
#[new] #[new]
fn __new__(obj: &PyRawObject, path: String) -> PyResult<()> { 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() lines.par_lines().map(|line| wc_line(line, search)).sum()
} }
#[modinit(_word_count)] #[pymodinit(_word_count)]
fn init_mod(_py: Python, m: &PyModule) -> PyResult<()> { fn init_mod(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<WordCounter>()?; m.add_class::<WordCounter>()?;

View File

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

View File

@ -1,122 +1,87 @@
# Python Class # 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 ## 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 ```rust
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
use pyo3::py::class; use pyo3::pyclass;
#[class] #[pyclass]
struct MyClass { struct MyClass {
num: i32, num: i32,
debug: bool, 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 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.
impl PyTypeInfo for MyClass { ... }
impl PyTypeObject for MyClass { ... }
impl PyObjectWithToken for MyClass { ... }
impl ToPyObject for MyClass { ... }
impl IntoPyObject for MyClass { ... }
impl ToPyPointer for MyClass { ... }
```
Following implementations `PyObjectWithToken`, `ToPyObject`, `IntoPyObject`, `ToPyPointer` ## Customizing the class
are generated only if struct contains `PyToken` attribute.
`PyToken` instance available only in `py.init` method. The `#[pyclass]` macro accepts following parameters:
TODO - continue * `name=XXX` - Set the class name shown in python code. By default struct name is used as a class name.
## 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.
* `freelist=XXX` - `freelist` parameter add support of free allocation list to custom class. * `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, 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. 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 * `gc` - Classes with the `gc` parameter
participate in python garbage collector. If custom class contains references to other participate in python garbage collector. If a custom class contains references to other
python object that can be collector `PyGCProtocol` trait has to be implemented. python object that can be collected, the `PyGCProtocol` trait has to be implemented.
* `weakref` - adds support for python weak references * `weakref` - adds support for python weak references
* `base=BaseType` - use custom base class. BaseType is type which is * `base=BaseType` - use a custom base class. The base BaseType must implement `PyTypeInfo`.
implements `PyTypeInfo` trait. * `subclass` - Allows Python classes to inherit from this class
* `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. (Incomplete, see [#123](https://github.com/PyO3/pyo3/issues/123))
* `dict` - adds `__dict__` support, the instances of this type have a dictionary containing instance variables.
## Constructor ## Constructor
By default it is not possible to create instance of custom class from python code. By default it is not possible to create an instance of a custom class from python code.
To declare constructor, you need to define class method and annotate it with `#[new]` To declare a constructor, you need to define a class method and annotate it with `#[new]`
attribute. Only python `__new__` method can be specified, `__init__` is not available. attribute. Only the python `__new__` method can be specified, `__init__` is not available.
```rust ```rust
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# #
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::class; use pyo3::{pyclass, pymethods};
#
# #[class]
# struct MyClass {
# num: i32,
# debug: bool,
# token: PyToken,
# }
#
use pyo3::py::methods;
#[methods] #[pyclass]
struct MyClass {
num: i32,
token: PyToken,
}
#[pymethods]
impl MyClass { impl MyClass {
#[new] #[new]
fn __new__(obj: &PyRawObject, num: Option<i32>) -> PyResult<()> { fn __new__(obj: &PyRawObject, num: i32) -> PyResult<()> {
obj.init(|token| { obj.init(|token| {
MyClass { MyClass {
num: num.unwrap_or(10), num,
debug: false, token
token: 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 * If no method marked with `#[new]` is declared, object instances can only be created
from Rust, but not from Python. from Rust, but not from Python.
* The first parameter is the raw object, custom `new` method must initialize object * The first parameter is the raw object and the custom `new` method must initialize the object
with value of struct using `init` method. Type of the object may be the type object of 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. a derived class declared in Python.
* The first parameter implicitly has type `&PyRawObject`. * The first parameter implicitly has type `&PyRawObject`.
* For details on `parameter-list`, see the documentation of `Method arguments` section. * 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`. * The return type must be `PyResult<T>` for some `T` that implements `IntoPyObject`. Usually, `T` will be `MyType`.
Usually, `T` will be `MyType`.
## Inheritance ## Inheritance
@ -130,15 +95,15 @@ with value of custom class struct. Subclass must call parent's `__new__` method.
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #
#[class] #[pyclass]
struct BaseClass { struct BaseClass {
val1: usize, val1: usize,
token: PyToken, token: PyToken,
} }
#[methods] #[pymethods]
impl BaseClass { impl BaseClass {
#[new] #[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> { fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -150,13 +115,13 @@ impl BaseClass {
} }
} }
#[class(base=BaseClass)] #[pyclass(base=BaseClass)]
struct SubClass { struct SubClass {
val2: usize, val2: usize,
token: PyToken, token: PyToken,
} }
#[methods] #[pymethods]
impl SubClass { impl SubClass {
#[new] #[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> { fn __new__(obj: &PyRawObject) -> PyResult<()> {
@ -177,21 +142,21 @@ base class.
## Object properties ## Object properties
Descriptor methods can be defined in 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. attributes. i.e.
```rust ```rust
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #[class] # #[pyclass]
# struct MyClass { # struct MyClass {
# num: i32, # num: i32,
# token: PyToken, # token: PyToken,
# } # }
# #
#[methods] #[pymethods]
impl MyClass { impl MyClass {
#[getter] #[getter]
@ -212,14 +177,14 @@ rust's special keywords like `type`.
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #[class] # #[pyclass]
# struct MyClass { # struct MyClass {
# num: i32, # num: i32,
# token: PyToken, # token: PyToken,
# } # }
# #
#[methods] #[pymethods]
impl MyClass { impl MyClass {
#[getter] #[getter]
@ -244,14 +209,14 @@ If parameter is specified, it is used and property name. i.e.
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #[class] # #[pyclass]
# struct MyClass { # struct MyClass {
# num: i32, # num: i32,
# token: PyToken, # token: PyToken,
# } # }
# #
#[methods] #[pymethods]
impl MyClass { impl MyClass {
#[getter(number)] #[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)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
#[class] #[pyclass]
struct MyClass { struct MyClass {
#[prop(get, set)] #[prop(get, set)]
num: i32 num: i32
@ -288,7 +253,7 @@ Then it is available from Python code as `self.num`.
## Instance methods ## Instance methods
To define python compatible method, `impl` block for struct has to be annotated 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, wrappers for all functions in this block with some variations, like descriptors,
class method static methods, etc. class method static methods, etc.
@ -296,14 +261,14 @@ class method static methods, etc.
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #[class] # #[pyclass]
# struct MyClass { # struct MyClass {
# num: i32, # num: i32,
# token: PyToken, # token: PyToken,
# } # }
# #
#[methods] #[pymethods]
impl MyClass { impl MyClass {
fn method1(&self) -> PyResult<i32> { fn method1(&self) -> PyResult<i32> {
@ -327,15 +292,15 @@ get injected by method wrapper. i.e
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #[class] # #[pyclass]
# struct MyClass { # struct MyClass {
# num: i32, # num: i32,
# debug: bool, # debug: bool,
# token: PyToken, # token: PyToken,
# } # }
#[methods] #[pymethods]
impl MyClass { impl MyClass {
fn method2(&self, py: Python) -> PyResult<i32> { fn method2(&self, py: Python) -> PyResult<i32> {
Ok(10) Ok(10)
@ -354,15 +319,15 @@ with`#[classmethod]` attribute.
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #[class] # #[pyclass]
# struct MyClass { # struct MyClass {
# num: i32, # num: i32,
# debug: bool, # debug: bool,
# token: PyToken, # token: PyToken,
# } # }
#[methods] #[pymethods]
impl MyClass { impl MyClass {
#[classmethod] #[classmethod]
fn cls_method(cls: &PyType) -> PyResult<i32> { fn cls_method(cls: &PyType) -> PyResult<i32> {
@ -389,15 +354,15 @@ for some `T` that implements `IntoPyObject`.
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #[class] # #[pyclass]
# struct MyClass { # struct MyClass {
# num: i32, # num: i32,
# debug: bool, # debug: bool,
# token: PyToken, # token: PyToken,
# } # }
#[methods] #[pymethods]
impl MyClass { impl MyClass {
#[staticmethod] #[staticmethod]
fn static_method(param1: i32, param2: &str) -> PyResult<i32> { 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)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #[class] # #[pyclass]
# struct MyClass { # struct MyClass {
# num: i32, # num: i32,
# debug: bool, # debug: bool,
# token: PyToken, # token: PyToken,
# } # }
#[methods] #[pymethods]
impl MyClass { impl MyClass {
#[call] #[call]
#[args(args="*")] #[args(args="*")]
@ -461,15 +426,15 @@ Example:
# #![feature(proc_macro, specialization)] # #![feature(proc_macro, specialization)]
# extern crate pyo3; # extern crate pyo3;
# use pyo3::prelude::*; # use pyo3::prelude::*;
# use pyo3::py::*; # use pyo3::{pyclass, pymethods};
# #[class] # #[pyclass]
# struct MyClass { # struct MyClass {
# num: i32, # num: i32,
# debug: bool, # debug: bool,
# token: PyToken, # token: PyToken,
# } # }
# #
#[methods] #[pymethods]
impl MyClass { impl MyClass {
#[args(arg1=true, args="*", arg2=10, kwargs="**")] #[args(arg1=true, args="*", arg2=10, kwargs="**")]
fn method(&self, arg1: bool, args: &PyTuple, arg2: i32, kwargs: Option<&PyDict>) -> PyResult<i32> { 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 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 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 for your struct. Important note, each protocol implementation block has to be annotated
with `#[proto]` attribute. with `#[pyproto]` attribute.
### Basic object customization ### Basic object customization
@ -566,15 +531,15 @@ Example:
extern crate pyo3; extern crate pyo3;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py::{class, proto}; use pyo3::{pyclass, pyproto};
#[class] #[pyclass]
struct ClassWithGCSupport { struct ClassWithGCSupport {
obj: Option<PyObject>, obj: Option<PyObject>,
token: PyToken, token: PyToken,
} }
#[proto] #[pyproto]
impl PyGCProtocol for ClassWithGCSupport { impl PyGCProtocol for ClassWithGCSupport {
fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> { fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> {
if let Some(ref obj) = self.obj { 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. 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. collector, and it is possible to track them with `gc` module methods.
### Iterator Types ### 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. Returning `Ok(None)` from `__next__` indicates that that there are no further items.
Example: Example:
```rust ```rust
#![feature(proc_macro, specialization)] #![feature(proc_macro, specialization)]
extern crate pyo3; extern crate pyo3;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py::*; use pyo3::{pyclass, pyproto};
#[class] #[pyclass]
struct MyIterator { struct MyIterator {
iter: Box<Iterator<Item=PyObject> + Send>, iter: Box<Iterator<Item=PyObject> + Send>,
token: PyToken, token: PyToken,
} }
#[proto] #[pyproto]
impl PyIterProtocol for MyIterator { impl PyIterProtocol for MyIterator {
fn __iter__(&mut self) -> PyResult<PyObject> { fn __iter__(&mut self) -> PyResult<PyObject> {
@ -632,5 +598,4 @@ impl PyIterProtocol for MyIterator {
Ok(self.iter.next()) Ok(self.iter.next())
} }
} }
# fn main() {}
``` ```

View File

@ -1,9 +1,9 @@
# Debugging # 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 ```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.) (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`: You can also debug classic `!`-macros by adding -Z trace-macros`:
```bash ```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)] #![feature(proc_macro)]
extern crate pyo3; extern crate pyo3;
use pyo3::{py, PyResult, Python, PyModule}; use pyo3::prelude::*;
use pyo3::py::modint; use pyo3::pymodinit;
#[modinit(rust2py)] #[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> { fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
// Note that the `#[pyfn()]` annotation automatically converts the arguments from // Note that the `#[pyfn()]` annotation automatically converts the arguments from
@ -38,17 +38,16 @@ as third.
#[macro_use] #[macro_use]
extern crate pyo3; extern crate pyo3;
use pyo3::{py, PyResult, Python, PyModule}; use pyo3::prelude::*;
use pyo3::py::function as pyfunction; use pyo3::{pyfunction, pymodinit};
use pyo3::py::modint;
#[pyfunction] #[pyfunction]
fn double(x: usize) -> usize { fn double(x: usize) -> usize {
x * 2 x * 2
} }
#[modinit(module_with_functions)] #[pymodinit(module_with_functions)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> { fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_function!(double)).unwrap(); 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)] #![feature(proc_macro)]
extern crate pyo3; 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 // 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
/// This module is implemented in Rust. /// This module is implemented in Rust.
#[modinit(rust2py)] #[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> { fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
// pyo3 aware function. All of our python interface could be declared in a separate module. // 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() {} # 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. 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; extern crate pyo3;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py::modint; use pyo3::pymodinit;
// 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
/// This module is implemented in Rust. /// This module is implemented in Rust.
#[modinit(rust2py)] #[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> { fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "sum_as_string")] #[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: `Python::allow_threads` method to enable true parallelism:
```rust,ignore ```rust,ignore
#[modinit(_word_count)] #[pymodinit(_word_count)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> { fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "search")] #[pyfn(m, "search")]

View File

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

View File

@ -1,6 +1,6 @@
[package] [package]
name = "pyo3-derive-backend" name = "pyo3-derive-backend"
version = "0.2.5" version = "0.3.0"
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"]

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) { pub fn process_functions_in_module(func: &mut syn::ItemFn) {
let mut stmts: Vec<syn::Stmt> = Vec::new(); 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 { } 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) 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 { pub fn build_py_methods(ast: &mut syn::ItemImpl) -> TokenStream {
if ast.trait_.is_some() { 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 { } else {
impl_methods(&ast.self_ty, &mut ast.items) 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), "PyBufferProtocol" => impl_proto_impl(ty, items, &defs::BUFFER),
"PyGCProtocol" => impl_proto_impl(ty, items, &defs::GC), "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(); return TokenStream::new();
} }
} }
} else { } else {
panic!("#[proto] can only be used with protocol trait implementations") panic!("#[pyproto] can only be used with protocol trait implementations")
}; };
// attach lifetime // attach lifetime
@ -42,7 +42,7 @@ pub fn build_py_proto(ast: &mut syn::ItemImpl) -> TokenStream {
tokens tokens
} else { } 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, input: proc_macro::TokenStream,
) -> 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("#[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 // Extract the mod name
let modname: syn::Ident = syn::parse(attr).expect("could not parse module 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, input: proc_macro::TokenStream,
) -> 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("#[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 // Extract the mod name
let modname: syn::Ident = syn::parse(attr).expect("could not parse module name"); let modname: syn::Ident = syn::parse(attr).expect("could not parse module name");
@ -65,13 +65,13 @@ pub fn mod3init(
} }
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn proto( pub fn pyproto(
_: proc_macro::TokenStream, _: proc_macro::TokenStream,
input: proc_macro::TokenStream, input: proc_macro::TokenStream,
) -> 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("#[proto] must be used on an `impl` block"); syn::parse(input).expect("#[pyproto] must be used on an `impl` block");
// Build the output // Build the output
let expanded = py_proto::build_py_proto(&mut ast); let expanded = py_proto::build_py_proto(&mut ast);
@ -83,12 +83,12 @@ pub fn proto(
} }
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn class( pub fn pyclass(
attr: proc_macro::TokenStream, attr: proc_macro::TokenStream,
input: proc_macro::TokenStream, input: proc_macro::TokenStream,
) -> 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 = 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 // Parse the macro arguments into a list of expressions
let args: Vec<syn::Expr> = { let args: Vec<syn::Expr> = {
@ -110,13 +110,13 @@ pub fn class(
} }
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn methods( pub fn pymethods(
_: proc_macro::TokenStream, _: proc_macro::TokenStream,
input: proc_macro::TokenStream, input: proc_macro::TokenStream,
) -> 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("#[methods] must be used on an `impl` block"); syn::parse(input.clone()).expect("#[pymethods] must be used on an `impl` block");
// Build the output // Build the output
let expanded = py_impl::build_py_methods(&mut ast); let expanded = py_impl::build_py_methods(&mut ast);
@ -128,7 +128,7 @@ pub fn methods(
} }
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn function( pub fn pyfunction(
_: proc_macro::TokenStream, _: proc_macro::TokenStream,
input: proc_macro::TokenStream, input: proc_macro::TokenStream,
) -> proc_macro::TokenStream { ) -> proc_macro::TokenStream {

View File

@ -8,7 +8,7 @@ use ffi;
static NO_PY_METHODS: &'static [PyMethodDefType] = &[]; static NO_PY_METHODS: &'static [PyMethodDefType] = &[];
/// `PyMethodDefType` represents different types of python callable objects. /// `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)] #[derive(Debug)]
pub enum PyMethodDefType { pub enum PyMethodDefType {
/// Represents class `__new__` method /// Represents class `__new__` method

View File

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

View File

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

View File

@ -169,7 +169,7 @@ impl PyModule {
/// Adds a function to a module, using the functions __name__ as name. /// 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 /// ```rust,ignore
/// m.add_function(wrap_function!(double)); /// 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): /// 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_function!(double)(py));
/// ``` /// ```
pub fn add_function(&self, wrapper: &Fn(Python) -> PyObject) -> PyResult<()> { pub fn add_function(&self, wrapper: &Fn(Python) -> PyObject) -> PyResult<()> {
let function = wrapper(self.py()); let function = wrapper(self.py());

View File

@ -10,7 +10,6 @@
//! use pyo3::prelude::*; //! use pyo3::prelude::*;
//! ``` //! ```
pub use super::py;
pub use class::*; pub use class::*;
pub use objects::*; pub use objects::*;
pub use objectprotocol::ObjectProtocol; 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 /// thread (the thread which originally initialized Python) also initializes
/// threading. /// threading.
/// ///
/// When writing an extension module, the `#[modinit(..)]` macro /// When writing an extension module, the `#[pymodinit(..)]` macro
/// will ensure that Python threading is initialized. /// will ensure that Python threading is initialized.
/// ///
pub fn prepare_freethreaded_python() { 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: /// Example of custom class implementation with `__new__` method:
/// ```rust,ignore /// ```rust,ignore
/// use pyo3::py::class; /// use pyo3::{pyclass, pymethods};
/// use pyo3::py::methods;
/// ///
/// #[class] /// #[pyclass]
/// struct MyClass { /// struct MyClass {
/// token: PyToken /// token: PyToken
/// } /// }
/// ///
/// #[methods] /// #[pymethods]
/// impl MyClass { /// impl MyClass {
/// #[new] /// #[new]
/// fn __new__(obj: &PyRawObject) -> PyResult<()> { /// 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> { pub trait PyObjectAlloc<T> {
/// Allocates a new object (usually by calling ty->tp_alloc), /// Allocates a new object (usually by calling ty->tp_alloc),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,22 +4,22 @@
extern crate pyo3; extern crate pyo3;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py::{class, function, modinit}; use pyo3::{pyclass, pyfunction, pymodinit};
#[class] #[pyclass]
struct EmptyClass {} struct EmptyClass {}
fn sum_as_string(a: i64, b: i64) -> String { fn sum_as_string(a: i64, b: i64) -> String {
format!("{}", a + b).to_string() format!("{}", a + b).to_string()
} }
#[function] #[pyfunction]
fn double(x: usize) -> usize { fn double(x: usize) -> usize {
x * 2 x * 2
} }
/// This module is implemented in Rust. /// This module is implemented in Rust.
#[modinit(module_with_functions)] #[pymodinit(module_with_functions)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> { fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "sum_as_string")] #[pyfn(m, "sum_as_string")]
fn sum_as_string_py(_py: Python, a: i64, b: i64) -> PyResult<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 pyo3::prelude::*;
use std::isize; use std::isize;
use pyo3::py::class; use pyo3::pyclass;
use pyo3::py::methods; use pyo3::pymethods;
#[macro_use] #[macro_use]
mod common; mod common;
#[class] #[pyclass]
struct MutRefArg { struct MutRefArg {
n: i32, n: i32,
token: PyToken, token: PyToken,
} }
#[methods] #[pymethods]
impl MutRefArg { impl MutRefArg {
fn get(&self) -> PyResult<i32> { fn get(&self) -> PyResult<i32> {
Ok(self.n) Ok(self.n)