Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some api improvements #367

Merged
merged 3 commits into from
Feb 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ examples/*/py*
*.egg-info
extensions/stamps/
pip-wheel-metadata
valgrind-python.supp
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* Added a `wrap_pymodule!` macro similar to the existing `wrap_pyfunction!` macro. Only available on python 3
* Added support for cross compiling (e.g. to arm v7) by mtp401 in [#327](https://github.com/PyO3/pyo3/pull/327). See the "Cross Compiling" section in the "Building and Distribution" chapter of the guide for more details.
* The `PyRef` and `PyRefMut` types, which allow to differentiate between an instance of a rust struct on the rust heap and an instance that is embedded inside a python object. By kngwyu in [#335](https://github.com/PyO3/pyo3/pull/335)
* Added `FromPy<T>` and `IntoPy<T>` which are equivalent to `From<T>` and `Into<T>` except that they require a gil token.
* Added `ManagedPyRef`, which should eventually replace `ToBorrowedObject`.

### Changed

Expand All @@ -27,14 +29,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
* `#[pyfunction]` now supports the same arguments as `#[pyfn()]`
* Some macros now emit proper spanned errors instead of panics.
* Migrated to the 2018 edition
* Replace `IntoPyTuple` with `IntoPy<Py<PyTuple>>`. Eventually `IntoPy<T>` should replace `ToPyObject` and be itself implemented through `FromPy<T>`
* `crate::types::exceptions` moved to `crate::exceptions`
* Replace `IntoPyTuple` with `IntoPy<Py<PyTuple>>`.
* `IntoPyPointer` and `ToPyPointer` moved into the crate root.
* `class::CompareOp` moved into `class::basic::CompareOp`
* PyTypeObject is now a direct subtrait PyTypeCreate, removing the old cyclical implementation in [#350](https://github.com/PyO3/pyo3/pull/350)
* Add `PyList::{sort, reverse}` by chr1sj0nes in [#357](https://github.com/PyO3/pyo3/pull/357) and [#358](https://github.com/PyO3/pyo3/pull/358)
* Renamed the `typeob` module to `type_object`

### Removed

* `PyToken` was removed due to unsoundness (See [#94](https://github.com/PyO3/pyo3/issues/94)).
* Removed the unnecessary type parameter from `PyObjectAlloc`
* `NoArgs`. Just use an empty tuple
* `PyObjectWithGIL`. `PyNativeType` is sufficient now that PyToken is removed.

### Fixed

Expand Down
4 changes: 2 additions & 2 deletions examples/rustapi_module/src/datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,8 @@ pub struct TzClass {}
#[pymethods]
impl TzClass {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
Ok(obj.init(TzClass {}))
fn new(obj: &PyRawObject) {
obj.init(TzClass {})
}

fn utcoffset(&self, py: Python<'_>, _dt: &PyDateTime) -> PyResult<Py<PyDelta>> {
Expand Down
4 changes: 2 additions & 2 deletions examples/rustapi_module/src/dict_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub struct DictSize {
#[pymethods]
impl DictSize {
#[new]
fn __new__(obj: &PyRawObject, expected: u32) -> PyResult<()> {
Ok(obj.init(DictSize { expected }))
fn new(obj: &PyRawObject, expected: u32) {
obj.init(DictSize { expected })
}

fn iter_dict(&mut self, _py: Python<'_>, dict: &PyDict) -> PyResult<u32> {
Expand Down
6 changes: 3 additions & 3 deletions examples/rustapi_module/src/othermod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ pub struct ModClass {
#[pymethods]
impl ModClass {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
Ok(obj.init(ModClass {
fn new(obj: &PyRawObject) {
obj.init(ModClass {
_somefield: String::from("contents"),
}))
})
}

fn noop(&self, x: usize) -> usize {
Expand Down
4 changes: 2 additions & 2 deletions examples/rustapi_module/src/subclassing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ pub struct Subclassable {}
#[pymethods]
impl Subclassable {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
Ok(obj.init(Subclassable {}))
fn new(obj: &PyRawObject) {
obj.init(Subclassable {});
}
}

Expand Down
6 changes: 3 additions & 3 deletions examples/word-count/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ struct WordCounter {
#[pymethods]
impl WordCounter {
#[new]
fn new(obj: &PyRawObject, path: String) -> PyResult<()> {
Ok(obj.init(WordCounter {
fn new(obj: &PyRawObject, path: String) {
obj.init(WordCounter {
path: PathBuf::from(path),
}))
});
}

/// Searches for the word, parallelized by rayon
Expand Down
12 changes: 6 additions & 6 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,12 @@ struct MyClass {
impl MyClass {

#[new]
fn __new__(obj: &PyRawObject, num: i32) -> PyResult<()> {
fn new(obj: &PyRawObject, num: i32) {
obj.init({
MyClass {
num,
}
})
});
}
}
```
Expand Down Expand Up @@ -158,8 +158,8 @@ struct BaseClass {
#[pymethods]
impl BaseClass {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
Ok(obj.init(BaseClass{ val1: 10 }))
fn new(obj: &PyRawObject) {
obj.init(BaseClass{ val1: 10 });
}

pub fn method(&self) -> PyResult<()> {
Expand All @@ -175,9 +175,9 @@ struct SubClass {
#[pymethods]
impl SubClass {
#[new]
fn __new__(obj: &PyRawObject) -> PyResult<()> {
fn new(obj: &PyRawObject) {
obj.init(SubClass{ val2: 10 });
BaseClass::__new__(obj)
BaseClass::new(obj);
}

fn method2(&self) -> PyResult<()> {
Expand Down
8 changes: 4 additions & 4 deletions guide/src/conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ provides two methods:
* `call` - call callable python object.
* `call_method` - call specific method on the object.

Both methods accept `args` and `kwargs` arguments. The `NoArgs` object represents an empty tuple object.
Both methods accept `args` and `kwargs` arguments.

```rust
use pyo3::prelude::*;
Expand Down Expand Up @@ -87,16 +87,16 @@ fn main() {
// call object with PyDict
let kwargs = PyDict::new(py);
kwargs.set_item(key1, val1);
obj.call(py, NoArgs, Some(kwargs));
obj.call(py, (), Some(kwargs));

// pass arguments as Vec
let kwargs = vec![(key1, val1), (key2, val2)];
obj.call(py, NoArgs, Some(kwargs.into_py_dict(py)));
obj.call(py, (), Some(kwargs.into_py_dict(py)));

// pass arguments as HashMap
let mut kwargs = HashMap::<&str, i32>::new();
kwargs.insert(key1, 1);
obj.call(py, NoArgs, Some(kwargs.into_py_dict(py)));
obj.call(py, (), Some(kwargs.into_py_dict(py)));
}
```

Expand Down
11 changes: 11 additions & 0 deletions guide/src/debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,14 @@ cargo rustc --profile=check -- -Z unstable-options --pretty=expanded -Z trace-ma

See [cargo expand](https://github.com/dtolnay/cargo-expand) for a more elaborate version of those commands.

## Running with Valgrind

Valgrind is a tool to detect memory managment bugs such as memory leaks.

You first need to installa debug build of python, otherwise valgrind won't produce usable results. In ubuntu there's e.g. a `python3-dbg` package.

Activate an environment with the debug interpreter and recompile. If you're on linux, use `ldd` with the name of you're binary and check that you're linking e.g. `libpython3.6dm.so.1.0` instead of `libpython3.6m.so.1.0`.

[Download the suppressions file for cpython](https://raw.githubusercontent.com/python/cpython/master/Misc/valgrind-python.supp).

Run valgrind with `valgrind --suppressions=valgrind-python.supp ./my-command --with-options`
4 changes: 2 additions & 2 deletions guide/src/exception.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ To check the type of an exception, you can simply do:
# fn main() {
# let gil = Python::acquire_gil();
# let py = gil.python();
# let err = exceptions::TypeError::py_err(NoArgs);
# let err = exceptions::TypeError::py_err(());
err.is_instance::<exceptions::TypeError>(py);
# }
```
Expand All @@ -112,7 +112,7 @@ The vast majority of operations in this library will return [`PyResult<T>`](http
This is an alias for the type `Result<T, PyErr>`.

A [`PyErr`](https://docs.rs/pyo3/0.2.7/struct.PyErr.html) represents a Python exception.
Errors within the `PyO3` library are also exposed as Python exceptions.
Errors within the `Pyo3` library are also exposed as Python exceptions.

PyO3 library handles python exception in two stages. During first stage `PyErr` instance get
created. At this stage python GIL is not required. During second stage, actual python
Expand Down
2 changes: 1 addition & 1 deletion guide/src/function.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Currently, there are no conversions between `Fn`s in rust and callables in pytho

### Calling a python function in rust

You can use `ObjectProtocol::is_callable` to check if you got a callable, which is true for functions (including lambdas), methods and objects with a `__call__` method. You can call the object with `ObjectProtocol::call` with the args as first parameter and the kwargs (or `NoArgs`) as second parameter. There are also `ObjectProtocol::call0` with no args and `ObjectProtocol::call1` with only the args.
You can use `ObjectProtocol::is_callable` to check if you got a callable, which is true for functions (including lambdas), methods and objects with a `__call__` method. You can call the object with `ObjectProtocol::call` with the args as first parameter and the kwargs (or `None`) as second parameter. There are also `ObjectProtocol::call0` with no args and `ObjectProtocol::call1` with only the args.

### Calling rust `Fn`s in python

Expand Down
4 changes: 2 additions & 2 deletions guide/src/rust-cpython.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ struct MyClass {
#[pymethods]
impl MyClass {
#[new]
fn __new__(obj: &PyRawObject, num: u32) -> PyResult<()> {
fn new(obj: &PyRawObject, num: u32) {
obj.init({
MyClass {
num,
}
})
});
}

fn half(&self) -> PyResult<u32> {
Expand Down
20 changes: 10 additions & 10 deletions pyo3-derive-backend/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,16 @@ impl PyClassArgs {
let flag = exp.path.segments.first().unwrap().value().ident.to_string();
let path = match flag.as_str() {
"gc" => {
parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_GC}
parse_quote! {::pyo3::type_object::PY_TYPE_FLAG_GC}
}
"weakref" => {
parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_WEAKREF}
parse_quote! {::pyo3::type_object::PY_TYPE_FLAG_WEAKREF}
}
"subclass" => {
parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_BASETYPE}
parse_quote! {::pyo3::type_object::PY_TYPE_FLAG_BASETYPE}
}
"dict" => {
parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_DICT}
parse_quote! {::pyo3::type_object::PY_TYPE_FLAG_DICT}
}
_ => {
return Err(syn::Error::new_spanned(
Expand Down Expand Up @@ -250,7 +250,7 @@ fn impl_class(
FREELIST = Box::into_raw(Box::new(
::pyo3::freelist::FreeList::with_capacity(#freelist)));

<#cls as ::pyo3::typeob::PyTypeObject>::init_type();
<#cls as ::pyo3::type_object::PyTypeObject>::init_type();
}
&mut *FREELIST
}
Expand All @@ -259,7 +259,7 @@ fn impl_class(
}
} else {
quote! {
impl ::pyo3::typeob::PyObjectAlloc for #cls {}
impl ::pyo3::type_object::PyObjectAlloc for #cls {}
}
}
};
Expand All @@ -280,9 +280,9 @@ fn impl_class(
let mut has_dict = false;
for f in attr.flags.iter() {
if let syn::Expr::Path(ref epath) = f {
if epath.path == parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_WEAKREF} {
if epath.path == parse_quote! {::pyo3::type_object::PY_TYPE_FLAG_WEAKREF} {
has_weakref = true;
} else if epath.path == parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_DICT} {
} else if epath.path == parse_quote! {::pyo3::type_object::PY_TYPE_FLAG_DICT} {
has_dict = true;
}
}
Expand All @@ -304,7 +304,7 @@ fn impl_class(
let flags = &attr.flags;

quote! {
impl ::pyo3::typeob::PyTypeInfo for #cls {
impl ::pyo3::type_object::PyTypeInfo for #cls {
type Type = #cls;
type BaseType = #base;

Expand All @@ -319,7 +319,7 @@ fn impl_class(
const OFFSET: isize = {
// round base_size up to next multiple of align
(
(<#base as ::pyo3::typeob::PyTypeInfo>::SIZE +
(<#base as ::pyo3::type_object::PyTypeInfo>::SIZE +
::std::mem::align_of::<#cls>() - 1) /
::std::mem::align_of::<#cls>() * ::std::mem::align_of::<#cls>()
) as isize
Expand Down
10 changes: 5 additions & 5 deletions pyo3-derive-backend/src/pymethod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub fn impl_wrap(
let _slf = _py.mut_from_borrowed_ptr::<#cls>(_slf);

let _result = {
::pyo3::IntoPyResult::into_py_result(#body)
::pyo3::derive_utils::IntoPyResult::into_py_result(#body)
};

::pyo3::callback::cb_convert(
Expand Down Expand Up @@ -136,12 +136,12 @@ pub fn impl_wrap_new(cls: &syn::Type, name: &syn::Ident, spec: &FnSpec<'_>) -> T
_args: *mut ::pyo3::ffi::PyObject,
_kwargs: *mut ::pyo3::ffi::PyObject) -> *mut ::pyo3::ffi::PyObject
{
use ::pyo3::typeob::PyTypeInfo;
use ::pyo3::type_object::PyTypeInfo;

const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#name),"()");
let _pool = ::pyo3::GILPool::new();
let _py = ::pyo3::Python::assume_gil_acquired();
match ::pyo3::typeob::PyRawObject::new(_py, #cls::type_object(), _cls) {
match ::pyo3::type_object::PyRawObject::new(_py, #cls::type_object(), _cls) {
Ok(_obj) => {
let _args = _py.from_borrowed_ptr::<::pyo3::types::PyTuple>(_args);
let _kwargs: Option<&::pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
Expand Down Expand Up @@ -355,7 +355,7 @@ pub fn impl_arg_params(spec: &FnSpec<'_>, body: TokenStream) -> TokenStream {
if spec.args.is_empty() {
return quote! {
let _result = {
::pyo3::IntoPyResult::into_py_result(#body)
::pyo3::derive_utils::IntoPyResult::into_py_result(#body)
};
};
}
Expand Down Expand Up @@ -415,7 +415,7 @@ pub fn impl_arg_params(spec: &FnSpec<'_>, body: TokenStream) -> TokenStream {

#(#param_conversion)*

::pyo3::IntoPyResult::into_py_result(#body)
::pyo3::derive_utils::IntoPyResult::into_py_result(#body)
})();
}
}
Expand Down
1 change: 1 addition & 0 deletions pyo3-derive-backend/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) 2017-present PyO3 Project and Contributors

use proc_macro2::TokenStream;
use syn;

pub fn print_err(msg: String, t: TokenStream) {
println!("Error: {} in '{}'", msg, t.to_string());
Expand Down
5 changes: 3 additions & 2 deletions src/buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@
use crate::err::{self, PyResult};
use crate::exceptions;
use crate::ffi;
use crate::python::{Python, ToPyPointer};
use crate::types::PyObjectRef;
use crate::Python;
use crate::ToPyPointer;
use libc;
use std::ffi::CStr;
use std::os::raw;
Expand Down Expand Up @@ -661,7 +662,7 @@ impl_element!(f64, Float);
mod test {
use super::PyBuffer;
use crate::ffi;
use crate::python::Python;
use crate::Python;

#[allow(unused_imports)]
use crate::objectprotocol::ObjectProtocol;
Expand Down
6 changes: 3 additions & 3 deletions src/callback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

//! Utilities for a Python callable object that invokes a Rust function.

use crate::conversion::IntoPyObject;
use crate::err::PyResult;
use crate::exceptions::OverflowError;
use crate::ffi::{self, Py_hash_t};
use crate::python::{IntoPyPointer, Python};
use crate::types::exceptions::OverflowError;
use crate::Python;
use crate::{IntoPyObject, IntoPyPointer};
use std::os::raw::c_int;
use std::{isize, ptr};

Expand Down
Loading