From ad590bd158194f84cb2cf08a18748edad6d42329 Mon Sep 17 00:00:00 2001 From: konstin Date: Sat, 23 Feb 2019 18:01:22 +0100 Subject: [PATCH] Some api improvements --- .gitignore | 1 + CHANGELOG.md | 10 +- guide/src/conversions.md | 8 +- guide/src/debugging.md | 11 ++ guide/src/exception.md | 4 +- guide/src/function.md | 2 +- pyo3-derive-backend/src/pyclass.rs | 20 ++-- pyo3-derive-backend/src/pymethod.rs | 10 +- pyo3-derive-backend/src/utils.rs | 1 + src/buffer.rs | 5 +- src/callback.rs | 6 +- src/class/basic.rs | 22 +++- src/class/buffer.rs | 2 +- src/class/context.rs | 2 +- src/class/descr.rs | 4 +- src/class/gc.rs | 5 +- src/class/iter.rs | 7 +- src/class/mapping.rs | 8 +- src/class/mod.rs | 17 +-- src/class/number.rs | 2 +- src/class/pyasync.rs | 7 +- src/class/sequence.rs | 9 +- src/conversion.rs | 136 ++++++++++++++++------ src/derive_utils.rs | 29 ++++- src/err.rs | 14 ++- src/{types => }/exceptions.rs | 18 +-- src/ffi3/mod.rs | 61 +++++----- src/freelist.rs | 4 +- src/{pythonrun.rs => gil.rs} | 34 +++--- src/instance.rs | 174 ++++++++++++++++++++++++---- src/lib.rs | 33 ++---- src/noargs.rs | 50 -------- src/object.rs | 31 ++--- src/objectprotocol.rs | 25 ++-- src/prelude.rs | 7 +- src/python.rs | 124 +++----------------- src/{typeob.rs => type_object.rs} | 13 ++- src/types/boolobject.rs | 9 +- src/types/bytearray.rs | 7 +- src/types/complex.rs | 9 +- src/types/datetime.rs | 5 +- src/types/dict.rs | 12 +- src/types/floatob.rs | 11 +- src/types/iterator.rs | 11 +- src/types/list.rs | 16 +-- src/types/mod.rs | 25 ++-- src/types/module.rs | 22 ++-- src/types/num2.rs | 15 ++- src/types/num3.rs | 16 +-- src/types/num_common.rs | 8 +- src/types/sequence.rs | 11 +- src/types/set.rs | 11 +- src/types/slice.rs | 6 +- src/types/string.rs | 11 +- src/types/string2.rs | 11 +- src/types/stringutils.rs | 6 +- src/types/tuple.rs | 37 ++---- src/types/typeobject.rs | 7 +- tests/test_arithmetics.rs | 1 + tests/test_class_basics.rs | 2 +- tests/test_class_new.rs | 2 +- tests/test_dunder.rs | 4 +- tests/test_gc.rs | 6 +- tests/test_inheritance.rs | 2 +- tests/test_module.rs | 8 +- 65 files changed, 654 insertions(+), 553 deletions(-) rename src/{types => }/exceptions.rs (96%) rename src/{pythonrun.rs => gil.rs} (94%) delete mode 100644 src/noargs.rs rename src/{typeob.rs => type_object.rs} (98%) diff --git a/.gitignore b/.gitignore index 2e3bc7bb..939ff4ed 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ examples/*/py* *.egg-info extensions/stamps/ pip-wheel-metadata +valgrind-python.supp diff --git a/CHANGELOG.md b/CHANGELOG.md index ef639b9e..9268f240 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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` and `IntoPy` which are equivalent to `From` and `Into` except that they require a gil token. + * Added `ManagedPyRef`, which should eventually replace `ToBorrowedObject`. ### Changed @@ -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>`. Eventually `IntoPy` should replace `ToPyObject` and be itself implemented through `FromPy` + * `crate::types::exceptions` moved to `crate::exceptions` + * Replace `IntoPyTuple` with `IntoPy>`. + * `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 diff --git a/guide/src/conversions.md b/guide/src/conversions.md index f8f816da..a8b34568 100644 --- a/guide/src/conversions.md +++ b/guide/src/conversions.md @@ -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::*; @@ -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))); } ``` diff --git a/guide/src/debugging.md b/guide/src/debugging.md index 0d458203..b268a155 100644 --- a/guide/src/debugging.md +++ b/guide/src/debugging.md @@ -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` diff --git a/guide/src/exception.md b/guide/src/exception.md index 7f1ffb7a..b262e457 100644 --- a/guide/src/exception.md +++ b/guide/src/exception.md @@ -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::(py); # } ``` @@ -112,7 +112,7 @@ The vast majority of operations in this library will return [`PyResult`](http This is an alias for the type `Result`. 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 diff --git a/guide/src/function.md b/guide/src/function.md index 0e9a9436..ccf7d3c0 100644 --- a/guide/src/function.md +++ b/guide/src/function.md @@ -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 diff --git a/pyo3-derive-backend/src/pyclass.rs b/pyo3-derive-backend/src/pyclass.rs index 043c5faf..f11d44bf 100644 --- a/pyo3-derive-backend/src/pyclass.rs +++ b/pyo3-derive-backend/src/pyclass.rs @@ -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( @@ -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 } @@ -259,7 +259,7 @@ fn impl_class( } } else { quote! { - impl ::pyo3::typeob::PyObjectAlloc for #cls {} + impl ::pyo3::type_object::PyObjectAlloc for #cls {} } } }; @@ -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; } } @@ -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; @@ -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 diff --git a/pyo3-derive-backend/src/pymethod.rs b/pyo3-derive-backend/src/pymethod.rs index b79f7a3b..76bd4eec 100644 --- a/pyo3-derive-backend/src/pymethod.rs +++ b/pyo3-derive-backend/src/pymethod.rs @@ -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( @@ -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); @@ -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) }; }; } @@ -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) })(); } } diff --git a/pyo3-derive-backend/src/utils.rs b/pyo3-derive-backend/src/utils.rs index 4e329918..3c49efe7 100644 --- a/pyo3-derive-backend/src/utils.rs +++ b/pyo3-derive-backend/src/utils.rs @@ -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()); diff --git a/src/buffer.rs b/src/buffer.rs index 4ab6a8ad..90dcefd0 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -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; @@ -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; diff --git a/src/callback.rs b/src/callback.rs index 5626ebbc..d091a973 100644 --- a/src/callback.rs +++ b/src/callback.rs @@ -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}; diff --git a/src/class/basic.rs b/src/class/basic.rs index 2e3989cb..95208d64 100644 --- a/src/class/basic.rs +++ b/src/class/basic.rs @@ -10,17 +10,29 @@ use crate::callback::{BoolCallbackConverter, HashConverter, PyObjectCallbackConverter}; use crate::class::methods::PyMethodDef; -use crate::conversion::{FromPyObject, IntoPyObject}; use crate::err::{PyErr, PyResult}; +use crate::exceptions; use crate::ffi; use crate::objectprotocol::ObjectProtocol; -use crate::python::{IntoPyPointer, Python}; -use crate::typeob::PyTypeInfo; -use crate::types::{exceptions, PyObjectRef}; -use crate::CompareOp; +use crate::type_object::PyTypeInfo; +use crate::types::PyObjectRef; +use crate::IntoPyPointer; +use crate::Python; +use crate::{FromPyObject, IntoPyObject}; use std::os::raw::c_int; use std::ptr; +/// Operators for the __richcmp__ method +#[derive(Debug)] +pub enum CompareOp { + Lt = ffi::Py_LT as isize, + Le = ffi::Py_LE as isize, + Eq = ffi::Py_EQ as isize, + Ne = ffi::Py_NE as isize, + Gt = ffi::Py_GT as isize, + Ge = ffi::Py_GE as isize, +} + /// Basic python class customization #[allow(unused_variables)] pub trait PyObjectProtocol<'p>: PyTypeInfo { diff --git a/src/class/buffer.rs b/src/class/buffer.rs index c78bfbf8..000b434d 100644 --- a/src/class/buffer.rs +++ b/src/class/buffer.rs @@ -7,7 +7,7 @@ use crate::callback::UnitCallbackConverter; use crate::err::PyResult; use crate::ffi; -use crate::typeob::PyTypeInfo; +use crate::type_object::PyTypeInfo; use std::os::raw::c_int; /// Buffer protocol interface diff --git a/src/class/context.rs b/src/class/context.rs index 7ab59a79..705a9e08 100644 --- a/src/class/context.rs +++ b/src/class/context.rs @@ -6,7 +6,7 @@ use crate::class::methods::PyMethodDef; use crate::err::PyResult; -use crate::typeob::PyTypeInfo; +use crate::type_object::PyTypeInfo; /// Context manager interface #[allow(unused_variables)] diff --git a/src/class/descr.rs b/src/class/descr.rs index cc1bb29d..c7ceff36 100644 --- a/src/class/descr.rs +++ b/src/class/descr.rs @@ -7,11 +7,11 @@ use crate::callback::{PyObjectCallbackConverter, UnitCallbackConverter}; use crate::class::methods::PyMethodDef; -use crate::conversion::{FromPyObject, IntoPyObject}; use crate::err::PyResult; use crate::ffi; -use crate::typeob::PyTypeInfo; +use crate::type_object::PyTypeInfo; use crate::types::{PyObjectRef, PyType}; +use crate::{FromPyObject, IntoPyObject}; use std::os::raw::c_int; /// Descriptor interface diff --git a/src/class/gc.rs b/src/class/gc.rs index a8e3e442..9ddec65f 100644 --- a/src/class/gc.rs +++ b/src/class/gc.rs @@ -4,8 +4,9 @@ //! use crate::ffi; -use crate::python::{Python, ToPyPointer}; -use crate::typeob::PyTypeInfo; +use crate::type_object::PyTypeInfo; +use crate::Python; +use crate::ToPyPointer; use std::os::raw::{c_int, c_void}; #[repr(transparent)] diff --git a/src/class/iter.rs b/src/class/iter.rs index 5498137c..1d235d7f 100644 --- a/src/class/iter.rs +++ b/src/class/iter.rs @@ -3,12 +3,13 @@ //! Trait and support implementation for implementing iterators use crate::callback::{CallbackConverter, PyObjectCallbackConverter}; -use crate::conversion::IntoPyObject; use crate::err::PyResult; use crate::ffi; use crate::instance::PyRefMut; -use crate::python::{IntoPyPointer, Python}; -use crate::typeob::PyTypeInfo; +use crate::type_object::PyTypeInfo; +use crate::IntoPyObject; +use crate::IntoPyPointer; +use crate::Python; use std::ptr; /// Python Iterator Interface. diff --git a/src/class/mapping.rs b/src/class/mapping.rs index 0a4b045b..048b24a5 100644 --- a/src/class/mapping.rs +++ b/src/class/mapping.rs @@ -5,12 +5,12 @@ use crate::callback::{LenResultConverter, PyObjectCallbackConverter}; use crate::class::methods::PyMethodDef; -use crate::conversion::{FromPyObject, IntoPyObject}; use crate::err::{PyErr, PyResult}; +use crate::exceptions; use crate::ffi; -use crate::python::Python; -use crate::typeob::PyTypeInfo; -use crate::types::exceptions; +use crate::type_object::PyTypeInfo; +use crate::Python; +use crate::{FromPyObject, IntoPyObject}; /// Mapping interface #[allow(unused_variables)] diff --git a/src/class/mod.rs b/src/class/mod.rs index f49d4d13..46114023 100644 --- a/src/class/mod.rs +++ b/src/class/mod.rs @@ -21,23 +21,10 @@ pub use self::basic::PyObjectProtocol; pub use self::buffer::PyBufferProtocol; pub use self::context::PyContextProtocol; pub use self::descr::PyDescrProtocol; +pub use self::gc::{PyGCProtocol, PyTraverseError, PyVisit}; pub use self::iter::PyIterProtocol; pub use self::mapping::PyMappingProtocol; +pub use self::methods::{PyGetterDef, PyMethodDef, PyMethodDefType, PyMethodType, PySetterDef}; pub use self::number::PyNumberProtocol; pub use self::pyasync::PyAsyncProtocol; pub use self::sequence::PySequenceProtocol; - -pub use self::gc::{PyGCProtocol, PyTraverseError, PyVisit}; -pub use self::methods::{PyGetterDef, PyMethodDef, PyMethodDefType, PyMethodType, PySetterDef}; -use crate::ffi; - -/// Operators for the __richcmp__ method -#[derive(Debug)] -pub enum CompareOp { - Lt = ffi::Py_LT as isize, - Le = ffi::Py_LE as isize, - Eq = ffi::Py_EQ as isize, - Ne = ffi::Py_NE as isize, - Gt = ffi::Py_GT as isize, - Ge = ffi::Py_GE as isize, -} diff --git a/src/class/number.rs b/src/class/number.rs index 1488e930..9acfdcf0 100644 --- a/src/class/number.rs +++ b/src/class/number.rs @@ -8,7 +8,7 @@ use crate::class::basic::PyObjectProtocolImpl; use crate::class::methods::PyMethodDef; use crate::err::PyResult; use crate::ffi; -use crate::typeob::PyTypeInfo; +use crate::type_object::PyTypeInfo; use crate::{FromPyObject, IntoPyObject}; /// Number interface diff --git a/src/class/pyasync.rs b/src/class/pyasync.rs index 53e64722..e43d08e2 100644 --- a/src/class/pyasync.rs +++ b/src/class/pyasync.rs @@ -12,7 +12,7 @@ use crate::callback::PyObjectCallbackConverter; use crate::class::methods::PyMethodDef; use crate::err::PyResult; use crate::ffi; -use crate::typeob::PyTypeInfo; +use crate::type_object::PyTypeInfo; /// Python Async/Await support interface. /// @@ -190,9 +190,10 @@ impl<'p, T> PyAsyncAnextProtocolImpl for T where T: PyAsyncProtocol<'p> {} mod anext { use super::{PyAsyncAnextProtocol, PyAsyncAnextProtocolImpl}; use crate::callback::CallbackConverter; - use crate::conversion::IntoPyObject; use crate::ffi; - use crate::python::{IntoPyPointer, Python}; + use crate::IntoPyObject; + use crate::IntoPyPointer; + use crate::Python; use std::ptr; pub struct IterANextResultConverter; diff --git a/src/class/sequence.rs b/src/class/sequence.rs index b6509ea6..d959bb4e 100644 --- a/src/class/sequence.rs +++ b/src/class/sequence.rs @@ -4,13 +4,14 @@ //! Trait and support implementation for implementing sequence use crate::callback::{BoolCallbackConverter, LenResultConverter, PyObjectCallbackConverter}; -use crate::conversion::{FromPyObject, IntoPyObject}; use crate::err::{PyErr, PyResult}; +use crate::exceptions; use crate::ffi; use crate::objectprotocol::ObjectProtocol; -use crate::python::Python; -use crate::typeob::PyTypeInfo; -use crate::types::{exceptions, PyObjectRef}; +use crate::type_object::PyTypeInfo; +use crate::types::PyObjectRef; +use crate::Python; +use crate::{FromPyObject, IntoPyObject}; use std::os::raw::c_int; /// Sequece interface diff --git a/src/conversion.rs b/src/conversion.rs index a91e0e66..fc3d9bd8 100644 --- a/src/conversion.rs +++ b/src/conversion.rs @@ -1,13 +1,73 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -//! This module contains some conversion traits +//! Conversions between various states of rust and python types and their wrappers. use crate::err::{PyDowncastError, PyResult}; use crate::ffi; use crate::object::PyObject; -use crate::python::{IntoPyPointer, Python, ToPyPointer}; -use crate::typeob::PyTypeInfo; +use crate::type_object::PyTypeInfo; use crate::types::PyObjectRef; +use crate::types::PyTuple; +use crate::Py; +use crate::Python; + +/// This trait allows retrieving the underlying FFI pointer from Python objects. +/// +/// This trait is implemented for types that internally wrap a pointer to a python object. +pub trait ToPyPointer { + /// Retrieves the underlying FFI pointer (as a borrowed pointer). + fn as_ptr(&self) -> *mut ffi::PyObject; +} + +/// This trait allows retrieving the underlying FFI pointer from Python objects. +pub trait IntoPyPointer { + /// Retrieves the underlying FFI pointer. Whether pointer owned or borrowed + /// depends on implementation. + fn into_ptr(self) -> *mut ffi::PyObject; +} + +/// Convert `None` into a null pointer. +impl ToPyPointer for Option +where + T: ToPyPointer, +{ + #[inline] + fn as_ptr(&self) -> *mut ffi::PyObject { + match *self { + Some(ref t) => t.as_ptr(), + None => std::ptr::null_mut(), + } + } +} + +/// Convert `None` into a null pointer. +impl IntoPyPointer for Option +where + T: IntoPyPointer, +{ + #[inline] + fn into_ptr(self) -> *mut ffi::PyObject { + match self { + Some(t) => t.into_ptr(), + None => std::ptr::null_mut(), + } + } +} + +impl<'a, T> IntoPyPointer for &'a T +where + T: ToPyPointer, +{ + fn into_ptr(self) -> *mut ffi::PyObject { + let ptr = self.as_ptr(); + if !ptr.is_null() { + unsafe { + ffi::Py_INCREF(ptr); + } + } + ptr + } +} /// Conversion trait that allows various objects to be converted into `PyObject` pub trait ToPyObject { @@ -18,7 +78,9 @@ pub trait ToPyObject { /// This trait has two implementations: The slow one is implemented for /// all [ToPyObject] and creates a new object using [ToPyObject::to_object], /// while the fast one is only implemented for ToPyPointer (we know -/// that every ToPyObject is also ToPyObject) and uses [ToPyPointer::as_ptr()] +/// that every ToPyPointer is also ToPyObject) and uses [ToPyPointer::as_ptr()] +/// +/// This trait should eventually be replaced with [ManagedPyRef](crate::ManagedPyRef). pub trait ToBorrowedObject: ToPyObject { /// Converts self into a Python object and calls the specified closure /// on the native FFI pointer underlying the Python object. @@ -52,12 +114,35 @@ where } } -/// Similar to [std::convert::Into], just that it requires a gil token and there's -/// currently no corresponding [std::convert::From] part. +/// Similar to [std::convert::From], just that it requires a gil token. +pub trait FromPy: Sized { + /// Performs the conversion. + fn from_py(_: T, py: Python) -> Self; +} + +/// Similar to [std::convert::Into], just that it requires a gil token. pub trait IntoPy: Sized { + /// Performs the conversion. fn into_py(self, py: Python) -> T; } +// From implies Into +impl IntoPy for T +where + U: FromPy, +{ + fn into_py(self, py: Python) -> U { + U::from_py(self, py) + } +} + +// From (and thus Into) is reflexive +impl FromPy for T { + fn from_py(t: T, _: Python) -> T { + t + } +} + /// Conversion trait that allows various objects to be converted into `PyObject` /// by consuming original object. pub trait IntoPyObject { @@ -202,20 +287,17 @@ where /// Trait implemented by Python object types that allow a checked downcast. /// This trait is similar to `std::convert::TryInto` pub trait PyTryInto: Sized { - /// The type returned in the event of a conversion error. - type Error; - /// Cast from PyObject to a concrete Python object type. - fn try_into(&self) -> Result<&T, Self::Error>; + fn try_into(&self) -> Result<&T, PyDowncastError>; /// Cast from PyObject to a concrete Python object type. With exact type check. - fn try_into_exact(&self) -> Result<&T, Self::Error>; + fn try_into_exact(&self) -> Result<&T, PyDowncastError>; /// Cast from PyObject to a concrete Python object type. - fn try_into_mut(&self) -> Result<&mut T, Self::Error>; + fn try_into_mut(&self) -> Result<&mut T, PyDowncastError>; /// Cast from PyObject to a concrete Python object type. With exact type check. - fn try_into_mut_exact(&self) -> Result<&mut T, Self::Error>; + fn try_into_mut_exact(&self) -> Result<&mut T, PyDowncastError>; } /// Trait implemented by Python object types that allow a checked downcast. @@ -250,8 +332,6 @@ impl PyTryInto for PyObjectRef where U: for<'v> PyTryFrom<'v>, { - type Error = PyDowncastError; - fn try_into(&self) -> Result<&U, PyDowncastError> { U::try_from(self) } @@ -339,34 +419,20 @@ where } } -#[doc(hidden)] -/// This trait wraps a T: IntoPyObject into PyResult while PyResult remains PyResult. -/// -/// This is necessary because proc macros run before typechecking and can't decide -/// whether a return type is a (possibly aliased) PyResult or not. It is also quite handy because -/// the codegen is currently built on the assumption that all functions return a PyResult. -pub trait IntoPyResult { - fn into_py_result(self) -> PyResult; -} - -impl IntoPyResult for T { - fn into_py_result(self) -> PyResult { - Ok(self) - } -} - -impl IntoPyResult for PyResult { - fn into_py_result(self) -> PyResult { - self +/// Converts `()` to an empty Python tuple. +impl FromPy<()> for Py { + fn from_py(_: (), py: Python) -> Py { + PyTuple::empty(py) } } #[cfg(test)] mod test { - use super::PyTryFrom; use crate::types::PyList; use crate::Python; + use super::PyTryFrom; + #[test] fn test_try_from_unchecked() { let gil = Python::acquire_gil(); diff --git a/src/derive_utils.rs b/src/derive_utils.rs index 627294a3..9647b3fc 100644 --- a/src/derive_utils.rs +++ b/src/derive_utils.rs @@ -4,15 +4,14 @@ //! Functionality for the code generated by the derive backend -use crate::conversion::PyTryFrom; use crate::err::PyResult; use crate::exceptions::TypeError; use crate::ffi; use crate::init_once; -use crate::types::PyModule; -use crate::types::{PyDict, PyObjectRef, PyString, PyTuple}; +use crate::types::{PyDict, PyModule, PyObjectRef, PyString, PyTuple}; use crate::GILPool; use crate::Python; +use crate::{IntoPyObject, PyTryFrom}; use std::ptr; /// Description of a python parameter; used for `parse_args()`. @@ -111,14 +110,13 @@ pub fn parse_fn_args<'p>( } #[cfg(Py_3)] -#[doc(hidden)] /// Builds a module (or null) from a user given initializer. Used for `#[pymodule]`. pub unsafe fn make_module( name: &str, doc: &str, initializer: impl Fn(Python, &PyModule) -> PyResult<()>, ) -> *mut ffi::PyObject { - use crate::python::IntoPyPointer; + use crate::IntoPyPointer; init_once(); @@ -196,3 +194,24 @@ pub unsafe fn make_module( e.restore(py) } } + +/// This trait wraps a T: IntoPyObject into PyResult while PyResult remains PyResult. +/// +/// This is necessary because proc macros run before typechecking and can't decide +/// whether a return type is a (possibly aliased) PyResult or not. It is also quite handy because +/// the codegen is currently built on the assumption that all functions return a PyResult. +pub trait IntoPyResult { + fn into_py_result(self) -> PyResult; +} + +impl IntoPyResult for T { + fn into_py_result(self) -> PyResult { + Ok(self) + } +} + +impl IntoPyResult for PyResult { + fn into_py_result(self) -> PyResult { + self + } +} diff --git a/src/err.rs b/src/err.rs index d00810c9..25552f0b 100644 --- a/src/err.rs +++ b/src/err.rs @@ -1,12 +1,15 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::conversion::{IntoPyObject, ToBorrowedObject, ToPyObject}; +use crate::exceptions; use crate::ffi; use crate::instance::Py; use crate::object::PyObject; -use crate::python::{IntoPyPointer, Python, ToPyPointer}; -use crate::typeob::PyTypeObject; -use crate::types::{exceptions, PyObjectRef, PyType}; +use crate::type_object::PyTypeObject; +use crate::types::{PyObjectRef, PyType}; +use crate::IntoPyPointer; +use crate::Python; +use crate::ToPyPointer; +use crate::{IntoPyObject, ToBorrowedObject, ToPyObject}; use libc::c_int; use std::error::Error; use std::ffi::CString; @@ -54,7 +57,6 @@ impl PyErr { /// Creates a new PyErr of type `T`. /// /// `value` can be: - /// * `NoArgs`: the exception instance will be created using python `T()` /// * a tuple: the exception instance will be created using python `T(*tuple)` /// * any other value: the exception instance will be created using python `T(value)` /// @@ -521,7 +523,7 @@ pub fn error_on_minusone(py: Python, result: c_int) -> PyResult<()> { #[cfg(test)] mod tests { - use crate::types::exceptions; + use crate::exceptions; use crate::{PyErr, Python}; #[test] diff --git a/src/types/exceptions.rs b/src/exceptions.rs similarity index 96% rename from src/types/exceptions.rs rename to src/exceptions.rs index 5592f474..e10d7ff4 100644 --- a/src/types/exceptions.rs +++ b/src/exceptions.rs @@ -1,13 +1,13 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -//! This module contains the standard python exception types. +//! Exception types defined by python. -use crate::conversion::ToPyObject; use crate::err::{PyErr, PyResult}; use crate::ffi; -use crate::python::{Python, ToPyPointer}; -use crate::typeob::PyTypeObject; +use crate::type_object::PyTypeObject; use crate::types::{PyObjectRef, PyTuple}; +use crate::Python; +use crate::{ToPyObject, ToPyPointer}; use std::ffi::CStr; use std::os::raw::c_char; use std::{self, ops}; @@ -84,12 +84,12 @@ macro_rules! import_exception { }; } -/// `impl $crate::typeob::PyTypeObject for $name` where `$name` is an exception defined in python +/// `impl $crate::type_object::PyTypeObject for $name` where `$name` is an exception defined in python /// code. #[macro_export] macro_rules! import_exception_type_object { ($module: expr, $name: ident) => { - impl $crate::typeob::PyTypeObject for $name { + impl $crate::type_object::PyTypeObject for $name { fn init_type() -> std::ptr::NonNull<$crate::ffi::PyTypeObject> { // We can't use lazy_static here because raw pointers aren't Send static TYPE_OBJECT_ONCE: ::std::sync::Once = ::std::sync::Once::new(); @@ -170,12 +170,12 @@ macro_rules! create_exception { }; } -/// `impl $crate::typeob::PyTypeObject for $name` where `$name` is an exception newly defined in +/// `impl $crate::type_object::PyTypeObject for $name` where `$name` is an exception newly defined in /// rust code. #[macro_export] macro_rules! create_exception_type_object { ($module: ident, $name: ident, $base: ty) => { - impl $crate::typeob::PyTypeObject for $name { + impl $crate::type_object::PyTypeObject for $name { fn init_type() -> std::ptr::NonNull<$crate::ffi::PyTypeObject> { // We can't use lazy_static here because raw pointers aren't Send static TYPE_OBJECT_ONCE: ::std::sync::Once = ::std::sync::Once::new(); @@ -379,8 +379,8 @@ pub mod socket { #[cfg(test)] mod test { + use crate::exceptions::Exception; use crate::objectprotocol::ObjectProtocol; - use crate::types::exceptions::Exception; use crate::types::PyDict; use crate::{PyErr, Python}; diff --git a/src/ffi3/mod.rs b/src/ffi3/mod.rs index 9d5a350e..b3d537fe 100644 --- a/src/ffi3/mod.rs +++ b/src/ffi3/mod.rs @@ -3,68 +3,59 @@ #![cfg_attr(Py_LIMITED_API, allow(unused_imports))] #![cfg_attr(feature="cargo-clippy", allow(clippy::inline_always))] -pub use self::pymem::*; -pub use self::pyport::*; - -pub use self::object::*; -pub use self::objimpl::*; -pub use self::pyhash::*; -pub use self::typeslots::*; - -pub use self::pydebug::*; - +pub use self::bltinmodule::*; pub use self::boolobject::*; pub use self::bytearrayobject::*; pub use self::bytesobject::*; +pub use self::ceval::*; +pub use self::code::*; +pub use self::codecs::*; +pub use self::compile::*; pub use self::complexobject::*; pub use self::descrobject::*; pub use self::dictobject::*; pub use self::enumobject::*; +pub use self::eval::*; pub use self::fileobject::*; pub use self::floatobject::*; +pub use self::frameobject::PyFrameObject; pub use self::genobject::*; +pub use self::import::*; +pub use self::intrcheck::*; pub use self::iterobject::*; pub use self::listobject::*; pub use self::longobject::*; pub use self::memoryobject::*; pub use self::methodobject::*; +pub use self::modsupport::*; pub use self::moduleobject::*; +pub use self::object::*; +pub use self::objectabstract::*; +pub use self::objimpl::*; +#[cfg(Py_3_6)] +pub use self::osmodule::*; +pub use self::pyarena::*; pub use self::pycapsule::*; +pub use self::pydebug::*; +pub use self::pyerrors::*; +pub use self::pyhash::*; +pub use self::pymem::*; +pub use self::pyport::*; +pub use self::pystate::*; +pub use self::pystrtod::*; +pub use self::pythonrun::*; pub use self::rangeobject::*; pub use self::setobject::*; pub use self::sliceobject::*; pub use self::structseq::*; +pub use self::sysmodule::*; pub use self::traceback::*; pub use self::tupleobject::*; +pub use self::typeslots::*; pub use self::unicodeobject::*; pub use self::warnings::*; pub use self::weakrefobject::*; -pub use self::codecs::*; -pub use self::pyerrors::*; - -pub use self::pystate::*; - -pub use self::ceval::*; -pub use self::import::*; -pub use self::intrcheck::*; -pub use self::modsupport::*; -#[cfg(Py_3_6)] -pub use self::osmodule::*; -pub use self::pyarena::*; -pub use self::pythonrun::*; -pub use self::sysmodule::*; - -pub use self::bltinmodule::*; -pub use self::objectabstract::*; - -pub use self::code::*; -pub use self::compile::*; -pub use self::eval::*; - -pub use self::frameobject::PyFrameObject; -pub use self::pystrtod::*; - mod pyport; // mod pymacro; contains nothing of interest for Rust // mod pyatomic; contains nothing of interest for Rust diff --git a/src/freelist.rs b/src/freelist.rs index bff7286b..1c9ae975 100644 --- a/src/freelist.rs +++ b/src/freelist.rs @@ -3,8 +3,8 @@ //! Free allocation list use crate::ffi; -use crate::python::Python; -use crate::typeob::{pytype_drop, PyObjectAlloc, PyTypeInfo}; +use crate::type_object::{pytype_drop, PyObjectAlloc, PyTypeInfo}; +use crate::Python; use std::mem; use std::os::raw::c_void; diff --git a/src/pythonrun.rs b/src/gil.rs similarity index 94% rename from src/pythonrun.rs rename to src/gil.rs index 88a2c602..7175d5a4 100644 --- a/src/pythonrun.rs +++ b/src/gil.rs @@ -1,7 +1,10 @@ // Copyright (c) 2017-present PyO3 Project and Contributors + +//! Interaction with python's global interpreter lock + use crate::ffi; -use crate::python::Python; use crate::types::PyObjectRef; +use crate::Python; use spin; use std::ptr::NonNull; use std::{any, marker, rc, sync}; @@ -325,10 +328,11 @@ mod array_list { #[cfg(test)] mod test { use super::{GILPool, NonNull, ReleasePool, POOL}; - use crate::conversion::ToPyObject; use crate::object::PyObject; - use crate::python::{Python, ToPyPointer}; - use crate::{ffi, pythonrun}; + use crate::Python; + use crate::ToPyObject; + use crate::ToPyPointer; + use crate::{ffi, gil}; fn get_object() -> PyObject { // Convenience function for getting a single unique object @@ -342,7 +346,7 @@ mod test { #[test] fn test_owned() { - pythonrun::init_once(); + gil::init_once(); unsafe { let p: &'static mut ReleasePool = &mut *POOL; @@ -355,7 +359,7 @@ mod test { empty = ffi::PyTuple_New(0); cnt = ffi::Py_REFCNT(empty) - 1; - let _ = pythonrun::register_owned(py, NonNull::new(empty).unwrap()); + let _ = gil::register_owned(py, NonNull::new(empty).unwrap()); assert_eq!(p.owned.len(), 1); } @@ -369,7 +373,7 @@ mod test { #[test] fn test_owned_nested() { - pythonrun::init_once(); + gil::init_once(); let gil = Python::acquire_gil(); let py = gil.python(); @@ -386,14 +390,14 @@ mod test { empty = ffi::PyTuple_New(0); cnt = ffi::Py_REFCNT(empty) - 1; - let _ = pythonrun::register_owned(py, NonNull::new(empty).unwrap()); + let _ = gil::register_owned(py, NonNull::new(empty).unwrap()); assert_eq!(p.owned.len(), 1); { let _pool = GILPool::new(); let empty = ffi::PyTuple_New(0); - let _ = pythonrun::register_owned(py, NonNull::new(empty).unwrap()); + let _ = gil::register_owned(py, NonNull::new(empty).unwrap()); assert_eq!(p.owned.len(), 2); } assert_eq!(p.owned.len(), 1); @@ -407,7 +411,7 @@ mod test { #[test] fn test_borrowed() { - pythonrun::init_once(); + gil::init_once(); unsafe { let p: &'static mut ReleasePool = &mut *POOL; @@ -421,7 +425,7 @@ mod test { assert_eq!(p.borrowed.len(), 0); cnt = ffi::Py_REFCNT(obj_ptr); - pythonrun::register_borrowed(py, NonNull::new(obj_ptr).unwrap()); + gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap()); assert_eq!(p.borrowed.len(), 1); assert_eq!(ffi::Py_REFCNT(obj_ptr), cnt); @@ -436,7 +440,7 @@ mod test { #[test] fn test_borrowed_nested() { - pythonrun::init_once(); + gil::init_once(); unsafe { let p: &'static mut ReleasePool = &mut *POOL; @@ -450,7 +454,7 @@ mod test { assert_eq!(p.borrowed.len(), 0); cnt = ffi::Py_REFCNT(obj_ptr); - pythonrun::register_borrowed(py, NonNull::new(obj_ptr).unwrap()); + gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap()); assert_eq!(p.borrowed.len(), 1); assert_eq!(ffi::Py_REFCNT(obj_ptr), cnt); @@ -458,7 +462,7 @@ mod test { { let _pool = GILPool::new(); assert_eq!(p.borrowed.len(), 1); - pythonrun::register_borrowed(py, NonNull::new(obj_ptr).unwrap()); + gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap()); assert_eq!(p.borrowed.len(), 2); } @@ -475,7 +479,7 @@ mod test { #[test] fn test_pyobject_drop() { - pythonrun::init_once(); + gil::init_once(); unsafe { let p: &'static mut ReleasePool = &mut *POOL; diff --git a/src/instance.rs b/src/instance.rs index 83c474d7..9f949d02 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -1,32 +1,31 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject}; use crate::err::{PyErr, PyResult}; use crate::ffi; +use crate::gil; use crate::instance; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; -use crate::python::{IntoPyPointer, Python, ToPyPointer}; -use crate::pythonrun; -use crate::typeob::PyTypeCreate; -use crate::typeob::{PyTypeInfo, PyTypeObject}; +use crate::type_object::PyTypeCreate; +use crate::type_object::{PyTypeInfo, PyTypeObject}; use crate::types::PyObjectRef; +use crate::IntoPyPointer; +use crate::Python; +use crate::ToPyPointer; +use crate::{FromPyObject, IntoPyObject, ToPyObject}; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::ptr::NonNull; use std::rc::Rc; -/// Any instance that is managed Python can have access to `gil`. +/// Types that are built into the python interpreter. /// -/// Originally, this was given to all classes with a `PyToken` field, but since `PyToken` was -/// removed this is only given to native types. -pub trait PyObjectWithGIL: Sized { +/// pyo3 is designed in a way that that all references to those types are bound to the GIL, +/// which is why you can get a token from all references of those types. +pub trait PyNativeType: Sized { fn py(&self) -> Python; } -#[doc(hidden)] -pub trait PyNativeType: PyObjectWithGIL {} - /// A special reference of type `T`. `PyRef` refers a instance of T, which exists in the Python /// heap as a part of a Python object. /// @@ -267,21 +266,19 @@ unsafe impl Send for Py {} unsafe impl Sync for Py {} -impl Py -where - T: PyTypeCreate + PyTypeObject, -{ +impl Py { /// Create new instance of T and move it under python management - pub fn new(py: Python, value: T) -> PyResult> { + pub fn new(py: Python, value: T) -> PyResult> + where + T: PyTypeCreate, + { let ob = T::create(py)?; ob.init(value); let ob = unsafe { Py::from_owned_ptr(ob.into_ptr()) }; Ok(ob) } -} -impl Py { /// Creates a `Py` instance for the given FFI pointer. /// This moves ownership over the pointer into the `Py`. /// Undefined behavior if the pointer is NULL or invalid. @@ -440,7 +437,7 @@ impl PartialEq for Py { impl Drop for Py { fn drop(&mut self) { unsafe { - pythonrun::register_pointer(self.0); + gil::register_pointer(self.0); } } } @@ -501,3 +498,140 @@ where } } } + +/// Reference to a converted [ToPyObject]. +/// +/// Many methods want to take anything that can be converted into a python object. This type +/// takes care of both types types that are already python object (i.e. implement +/// [ToPyPointer]) and those that don't (i.e. [ToPyObject] types). +/// For the [ToPyPointer] types, we just use the borrowed pointer, which is a lot faster +/// and simpler than creating a new extra object. The remaning [ToPyObject] types are +/// converted to python objects, the owned pointer is stored and decref'd on drop. +/// +/// # Example +/// +/// ``` +/// use pyo3::ffi; +/// use pyo3::{ToPyObject, ToPyPointer, PyNativeType, ManagedPyRef}; +/// use pyo3::types::{PyDict, PyObjectRef}; +/// +/// pub fn get_dict_item<'p>(dict: &'p PyDict, key: &impl ToPyObject) -> Option<&'p PyObjectRef> { +/// let key = ManagedPyRef::from_to_pyobject(dict.py(), key); +/// unsafe { +/// dict.py().from_borrowed_ptr_or_opt(ffi::PyDict_GetItem(dict.as_ptr(), key.as_ptr())) +/// } +/// } +/// ``` +#[repr(transparent)] +pub struct ManagedPyRef<'p, T: ToPyObject + ?Sized> { + data: *mut ffi::PyObject, + data_type: PhantomData, + _py: Python<'p>, +} + +/// This should eventually be replaced with a generic `IntoPy` trait impl by figuring +/// out the correct lifetime annotation to make the compiler happy +impl<'p, T: ToPyObject> ManagedPyRef<'p, T> { + pub fn from_to_pyobject(py: Python<'p>, to_pyobject: &T) -> Self { + to_pyobject.to_managed_py_ref(py) + } +} + +impl<'p, T: ToPyObject> ToPyPointer for ManagedPyRef<'p, T> { + fn as_ptr(&self) -> *mut ffi::PyObject { + self.data + } +} + +/// Helper trait to choose the right implementation for [BorrowedPyRef] +pub trait ManagedPyRefDispatch: ToPyObject { + /// Optionally converts into a python object and stores the pointer to the python heap. + /// + /// Contains the case 1 impl (with to_object) to avoid a specialization error + fn to_managed_py_ref<'p>(&self, py: Python<'p>) -> ManagedPyRef<'p, Self> { + ManagedPyRef { + data: self.to_object(py).into_ptr(), + data_type: PhantomData, + _py: py, + } + } + + /// Dispatch over a xdecref and a noop drop impl + /// + /// Contains the case 1 impl (decref) to avoid a specialization error + fn drop_impl(borrowed: &mut ManagedPyRef) { + unsafe { ffi::Py_DECREF(borrowed.data) }; + } +} + +/// Case 1: It's a rust object which still needs to be converted to a python object. +/// This means we're storing the owned pointer that into_ptr() has given us +/// and therefore need to xdecref when we're done. +/// +/// Note that the actual implementations are part of the trait declaration to avoid +/// a specialization error +impl ManagedPyRefDispatch for T {} + +/// Case 2: It's an object on the python heap, we're just storing a borrowed pointer. +/// The object we're getting is an owned pointer, it might have it's own drop impl. +impl ManagedPyRefDispatch for T { + /// Use ToPyPointer to copy the pointer and store it as borrowed pointer + fn to_managed_py_ref<'p>(&self, py: Python<'p>) -> ManagedPyRef<'p, Self> { + ManagedPyRef { + data: self.as_ptr(), + data_type: PhantomData, + _py: py, + } + } + + /// We have a borrowed pointer, so nothing to do here + fn drop_impl(_: &mut ManagedPyRef) {} +} + +impl<'p, T: ToPyObject + ?Sized> Drop for ManagedPyRef<'p, T> { + /// Uses the internal [ManagedPyRefDispatch] trait to get the right drop impl without causing + /// a specialization error + fn drop(&mut self) { + ManagedPyRefDispatch::drop_impl(self); + } +} + +#[cfg(test)] +mod test { + use crate::ffi; + use crate::types::PyDict; + use crate::{ManagedPyRef, Python, ToPyPointer}; + + #[test] + fn borrowed_py_ref_with_to_pointer() { + let gil = Python::acquire_gil(); + let py = gil.python(); + let native = PyDict::new(py); + let ref_count = unsafe { ffi::Py_REFCNT(native.as_ptr()) }; + let borrowed = ManagedPyRef::from_to_pyobject(py, native); + assert_eq!(native.as_ptr(), borrowed.data); + assert_eq!(ref_count, unsafe { ffi::Py_REFCNT(borrowed.data) }); + drop(borrowed); + assert_eq!(ref_count, unsafe { ffi::Py_REFCNT(native.as_ptr()) }); + } + + #[test] + fn borrowed_py_ref_with_to_object() { + let gil = Python::acquire_gil(); + let py = gil.python(); + let convertible = (1, 2, 3); + let borrowed = ManagedPyRef::from_to_pyobject(py, &convertible); + let ptr = borrowed.data; + // The refcountwould become 0 after dropping, which means the gc can free the pointer + // and getting the refcount would be UB. This incref ensures that it remains 1 + unsafe { + ffi::Py_INCREF(ptr); + } + assert_eq!(2, unsafe { ffi::Py_REFCNT(ptr) }); + drop(borrowed); + assert_eq!(1, unsafe { ffi::Py_REFCNT(ptr) }); + unsafe { + ffi::Py_DECREF(ptr); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 0a6e8d1e..579f2842 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,29 +118,18 @@ //! } //! ``` -//pub extern crate libc; -//pub extern crate mashup; -//extern crate pyo3cls; -//extern crate num_traits; -//extern crate spin; -//extern crate indoc; -//#[macro_use] -//extern crate assert_approx_eq; - pub use crate::class::*; pub use crate::conversion::{ - FromPyObject, IntoPy, IntoPyObject, IntoPyResult, PyTryFrom, PyTryInto, ToBorrowedObject, - ToPyObject, + FromPy, FromPyObject, IntoPy, IntoPyObject, IntoPyPointer, PyTryFrom, PyTryInto, + ToBorrowedObject, ToPyObject, ToPyPointer, }; pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult}; -pub use crate::instance::{AsPyRef, Py, PyNativeType, PyObjectWithGIL, PyRef, PyRefMut}; -pub use crate::noargs::NoArgs; +pub use crate::gil::{init_once, GILGuard, GILPool}; +pub use crate::instance::{AsPyRef, ManagedPyRef, Py, PyNativeType, PyRef, PyRefMut}; pub use crate::object::PyObject; pub use crate::objectprotocol::ObjectProtocol; -pub use crate::python::{IntoPyPointer, Python, ToPyPointer}; -pub use crate::pythonrun::{init_once, prepare_freethreaded_python, GILGuard, GILPool}; -pub use crate::typeob::{PyObjectAlloc, PyRawObject, PyTypeInfo}; -pub use crate::types::exceptions; +pub use crate::python::{prepare_freethreaded_python, Python}; +pub use crate::type_object::{PyObjectAlloc, PyRawObject, PyTypeInfo}; // We need that reexport for wrap_function #[doc(hidden)] @@ -149,7 +138,7 @@ pub use mashup; #[doc(hidden)] pub use inventory; -/// Rust FFI declarations for Python +/// Raw ffi declarations for the c interface of python pub mod ffi; #[cfg(not(Py_3))] @@ -175,15 +164,15 @@ mod conversion; #[doc(hidden)] pub mod derive_utils; mod err; +pub mod exceptions; pub mod freelist; +mod gil; mod instance; -mod noargs; mod object; mod objectprotocol; pub mod prelude; -pub mod python; -mod pythonrun; -pub mod typeob; +mod python; +pub mod type_object; pub mod types; /// The proc macros, which are also part of the prelude diff --git a/src/noargs.rs b/src/noargs.rs deleted file mode 100644 index 73b4e6aa..00000000 --- a/src/noargs.rs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2017-present PyO3 Project and Contributors - -use crate::conversion::{IntoPy, IntoPyObject, ToPyObject}; -use crate::instance::Py; -use crate::object::PyObject; -use crate::python::Python; -use crate::types::PyTuple; - -/// An empty struct that represents the empty argument list. -/// Corresponds to the empty tuple `()` in Python. -/// -/// # Example -/// ``` -/// # use pyo3::prelude::*; -/// -/// let gil = Python::acquire_gil(); -/// let py = gil.python(); -/// let os = py.import("os").unwrap(); -/// let pid = os.call("get_pid", NoArgs, None); -/// ``` -#[derive(Copy, Clone, Debug)] -pub struct NoArgs; - -/// Converts `NoArgs` to an empty Python tuple. -impl IntoPy> for NoArgs { - fn into_py(self, py: Python) -> Py { - PyTuple::empty(py) - } -} - -/// Converts `()` to an empty Python tuple. -impl IntoPy> for () { - fn into_py(self, py: Python) -> Py { - PyTuple::empty(py) - } -} - -/// Converts `NoArgs` to an empty Python tuple. -impl ToPyObject for NoArgs { - fn to_object(&self, py: Python) -> PyObject { - PyTuple::empty(py).into() - } -} - -/// Converts `NoArgs` to an empty Python tuple. -impl IntoPyObject for NoArgs { - fn into_object(self, py: Python) -> PyObject { - PyTuple::empty(py).into() - } -} diff --git a/src/object.rs b/src/object.rs index e5c5a1b5..b85d32b2 100644 --- a/src/object.rs +++ b/src/object.rs @@ -1,15 +1,16 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::conversion::{ - FromPyObject, IntoPy, IntoPyObject, PyTryFrom, ToBorrowedObject, ToPyObject, -}; use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::ffi; -use crate::instance::{AsPyRef, PyObjectWithGIL, PyRef, PyRefMut}; -use crate::python::{IntoPyPointer, Python, ToPyPointer}; -use crate::pythonrun; +use crate::gil; +use crate::instance::{AsPyRef, PyNativeType, PyRef, PyRefMut}; use crate::types::{PyDict, PyObjectRef, PyTuple}; use crate::Py; +use crate::Python; +use crate::ToPyPointer; +use crate::{ + FromPyObject, IntoPy, IntoPyObject, IntoPyPointer, PyTryFrom, ToBorrowedObject, ToPyObject, +}; use std::ptr::NonNull; /// A python object @@ -202,7 +203,7 @@ impl PyObject { /// Calls the object without arguments. /// This is equivalent to the Python expression: 'self()' pub fn call0(&self, py: Python) -> PyResult { - self.call(py, PyTuple::empty(py), None) + self.call(py, (), None) } /// Calls the object. @@ -238,7 +239,7 @@ impl PyObject { /// Calls a method on the object. /// This is equivalent to the Python expression: 'self.name()' pub fn call_method0(&self, py: Python, name: &str) -> PyResult { - self.call_method(py, name, PyTuple::empty(py), None) + self.call_method(py, name, (), None) } /// Calls a method on the object. @@ -279,14 +280,6 @@ impl ToPyPointer for PyObject { } } -impl<'a> ToPyPointer for &'a PyObject { - /// Gets the underlying FFI pointer, returns a borrowed pointer. - #[inline] - fn as_ptr(&self) -> *mut ffi::PyObject { - self.0.as_ptr() - } -} - impl IntoPyPointer for PyObject { /// Gets the underlying FFI pointer, returns a owned pointer. #[inline] @@ -325,16 +318,16 @@ impl<'a> FromPyObject<'a> for PyObject { impl Drop for PyObject { fn drop(&mut self) { unsafe { - pythonrun::register_pointer(self.0); + gil::register_pointer(self.0); } } } #[cfg(test)] mod test { - use super::PyObject; - use crate::python::Python; use crate::types::PyDict; + use crate::PyObject; + use crate::Python; #[test] fn test_call_for_non_existing_method() { diff --git a/src/objectprotocol.rs b/src/objectprotocol.rs index a8241414..cb17ee57 100644 --- a/src/objectprotocol.rs +++ b/src/objectprotocol.rs @@ -1,15 +1,18 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::conversion::{FromPyObject, IntoPy, PyTryFrom, ToBorrowedObject, ToPyObject}; +use crate::class::basic::CompareOp; use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::exceptions::TypeError; use crate::ffi; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; -use crate::python::{IntoPyPointer, Python, ToPyPointer}; -use crate::typeob::PyTypeInfo; +use crate::type_object::PyTypeInfo; use crate::types::{PyDict, PyIterator, PyObjectRef, PyString, PyTuple, PyType}; +use crate::IntoPyPointer; use crate::Py; +use crate::Python; +use crate::ToPyPointer; +use crate::{FromPyObject, IntoPy, PyTryFrom, ToBorrowedObject, ToPyObject}; use std::cmp::Ordering; use std::os::raw::c_int; @@ -68,7 +71,7 @@ pub trait ObjectProtocol { /// * CompareOp::Le: `self <= other` /// * CompareOp::Gt: `self > other` /// * CompareOp::Ge: `self >= other` - fn rich_compare(&self, other: O, compare_op: crate::CompareOp) -> PyResult + fn rich_compare(&self, other: O, compare_op: CompareOp) -> PyResult where O: ToPyObject; @@ -208,7 +211,7 @@ pub trait ObjectProtocol { impl ObjectProtocol for T where - T: PyObjectWithGIL + ToPyPointer, + T: PyNativeType + ToPyPointer, { fn hasattr(&self, attr_name: N) -> PyResult where @@ -290,7 +293,7 @@ where }) } - fn rich_compare(&self, other: O, compare_op: crate::CompareOp) -> PyResult + fn rich_compare(&self, other: O, compare_op: CompareOp) -> PyResult where O: ToPyObject, { @@ -341,7 +344,7 @@ where } fn call0(&self) -> PyResult<&PyObjectRef> { - self.call(PyTuple::empty(self.py()), None) + self.call((), None) } fn call1(&self, args: impl IntoPy>) -> PyResult<&PyObjectRef> { @@ -372,7 +375,7 @@ where } fn call_method0(&self, name: &str) -> PyResult<&PyObjectRef> { - self.call_method(name, PyTuple::empty(self.py()), None) + self.call_method(name, (), None) } fn call_method1(&self, name: &str, args: impl IntoPy>) -> PyResult<&PyObjectRef> { @@ -497,10 +500,10 @@ where #[cfg(test)] mod test { use super::*; - use crate::conversion::{PyTryFrom, ToPyObject}; use crate::instance::AsPyRef; - use crate::python::Python; use crate::types::{IntoPyDict, PyString}; + use crate::Python; + use crate::{PyTryFrom, ToPyObject}; #[test] fn test_debug_string() { diff --git a/src/prelude.rs b/src/prelude.rs index 812c0ae3..c1cb589e 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -10,14 +10,15 @@ //! use pyo3::prelude::*; //! ``` -pub use crate::conversion::{FromPyObject, IntoPyObject, PyTryFrom, PyTryInto, ToPyObject}; pub use crate::err::{PyErr, PyResult}; +pub use crate::gil::GILGuard; pub use crate::instance::{AsPyRef, Py, PyRef, PyRefMut}; -pub use crate::noargs::NoArgs; pub use crate::object::PyObject; pub use crate::objectprotocol::ObjectProtocol; pub use crate::python::Python; -pub use crate::pythonrun::GILGuard; +pub use crate::{ + FromPy, FromPyObject, IntoPy, IntoPyObject, IntoPyPointer, PyTryFrom, PyTryInto, ToPyObject, +}; // This is only part of the prelude because we need it for the pymodule function pub use crate::types::PyModule; // This is required for the constructor diff --git a/src/python.rs b/src/python.rs index 14d789f4..54f0c685 100644 --- a/src/python.rs +++ b/src/python.rs @@ -2,20 +2,22 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython -use crate::conversion::PyTryFrom; use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::ffi; -use crate::instance::{AsPyRef, Py, PyRef, PyRefMut}; +use crate::gil::{self, GILGuard}; +use crate::instance::AsPyRef; use crate::object::PyObject; -use crate::pythonrun::{self, GILGuard}; -use crate::typeob::PyTypeCreate; -use crate::typeob::{PyTypeInfo, PyTypeObject}; +use crate::type_object::{PyTypeInfo, PyTypeObject}; use crate::types::{PyDict, PyModule, PyObjectRef, PyType}; +use crate::ToPyPointer; +use crate::{IntoPyPointer, PyTryFrom}; use std::ffi::CString; use std::marker::PhantomData; use std::os::raw::c_int; use std::ptr::NonNull; +pub use gil::prepare_freethreaded_python; + /// Marker type that indicates that the GIL is currently held. /// /// The 'Python' struct is a zero-size marker struct that is required for most Python operations. @@ -48,62 +50,6 @@ use std::ptr::NonNull; #[derive(Copy, Clone)] pub struct Python<'p>(PhantomData<&'p GILGuard>); -/// This trait allows retrieving the underlying FFI pointer from Python objects. -pub trait ToPyPointer { - /// Retrieves the underlying FFI pointer (as a borrowed pointer). - fn as_ptr(&self) -> *mut ffi::PyObject; -} - -/// This trait allows retrieving the underlying FFI pointer from Python objects. -pub trait IntoPyPointer { - /// Retrieves the underlying FFI pointer. Whether pointer owned or borrowed - /// depends on implementation. - fn into_ptr(self) -> *mut ffi::PyObject; -} - -/// Convert `None` into a null pointer. -impl ToPyPointer for Option -where - T: ToPyPointer, -{ - #[inline] - fn as_ptr(&self) -> *mut ffi::PyObject { - match *self { - Some(ref t) => t.as_ptr(), - None => std::ptr::null_mut(), - } - } -} - -/// Convert `None` into a null pointer. -impl IntoPyPointer for Option -where - T: IntoPyPointer, -{ - #[inline] - fn into_ptr(self) -> *mut ffi::PyObject { - match self { - Some(t) => t.into_ptr(), - None => std::ptr::null_mut(), - } - } -} - -impl<'a, T> IntoPyPointer for &'a T -where - T: ToPyPointer, -{ - fn into_ptr(self) -> *mut ffi::PyObject { - let ptr = self.as_ptr(); - if !ptr.is_null() { - unsafe { - ffi::Py_INCREF(ptr); - } - } - ptr - } -} - impl<'p> Python<'p> { /// Retrieve Python instance under the assumption that the GIL is already acquired at this point, /// and stays acquired for the lifetime `'p`. @@ -246,38 +192,6 @@ impl<'p> Python<'p> { } } -impl<'p> Python<'p> { - /// Create new instance of `T` and move it under python management. - /// Returns `Py`. - #[inline] - pub fn init(self, value: T) -> PyResult> - where - T: PyTypeCreate, - { - Py::new(self, value) - } - - /// Create new instance of `T` and move it under python management. - /// Created object get registered in release pool. Returns references to `T` - #[inline] - pub fn init_ref(self, value: T) -> PyResult> - where - T: PyTypeCreate, - { - PyRef::new(self, value) - } - - /// Create new instance of `T` and move it under python management. - /// Created object get registered in release pool. Returns mutable references to `T` - #[inline] - pub fn init_mut(self, value: T) -> PyResult> - where - T: PyTypeCreate, - { - PyRefMut::new(self, value) - } -} - impl<'p> Python<'p> { unsafe fn unchecked_downcast(self, ob: &PyObjectRef) -> &'p T { if T::OFFSET == 0 { @@ -303,7 +217,7 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - let p = unsafe { pythonrun::register_owned(self, obj.into_nonnull()) }; + let p = unsafe { gil::register_owned(self, obj.into_nonnull()) }; ::try_from(p) } @@ -312,14 +226,14 @@ impl<'p> Python<'p> { where T: PyTypeInfo, { - let p = pythonrun::register_owned(self, obj.into_nonnull()); + let p = gil::register_owned(self, obj.into_nonnull()); self.unchecked_downcast(p) } /// Register `ffi::PyObject` pointer in release pool pub unsafe fn from_borrowed_ptr_to_obj(self, ptr: *mut ffi::PyObject) -> &'p PyObjectRef { match NonNull::new(ptr) { - Some(p) => pythonrun::register_borrowed(self, p), + Some(p) => gil::register_borrowed(self, p), None => crate::err::panic_after_error(), } } @@ -333,7 +247,7 @@ impl<'p> Python<'p> { { match NonNull::new(ptr) { Some(p) => { - let p = pythonrun::register_owned(self, p); + let p = gil::register_owned(self, p); self.unchecked_downcast(p) } None => crate::err::panic_after_error(), @@ -348,7 +262,7 @@ impl<'p> Python<'p> { { match NonNull::new(ptr) { Some(p) => { - let p = pythonrun::register_owned(self, p); + let p = gil::register_owned(self, p); self.unchecked_mut_downcast(p) } None => crate::err::panic_after_error(), @@ -364,7 +278,7 @@ impl<'p> Python<'p> { { match NonNull::new(ptr) { Some(p) => { - let p = pythonrun::register_owned(self, p); + let p = gil::register_owned(self, p); Ok(self.unchecked_downcast(p)) } None => Err(PyErr::fetch(self)), @@ -379,7 +293,7 @@ impl<'p> Python<'p> { T: PyTypeInfo, { NonNull::new(ptr).map(|p| { - let p = pythonrun::register_owned(self, p); + let p = gil::register_owned(self, p); self.unchecked_downcast(p) }) } @@ -393,7 +307,7 @@ impl<'p> Python<'p> { { match NonNull::new(ptr) { Some(p) => { - let p = pythonrun::register_borrowed(self, p); + let p = gil::register_borrowed(self, p); self.unchecked_downcast(p) } None => crate::err::panic_after_error(), @@ -409,7 +323,7 @@ impl<'p> Python<'p> { { match NonNull::new(ptr) { Some(p) => { - let p = pythonrun::register_borrowed(self, p); + let p = gil::register_borrowed(self, p); self.unchecked_mut_downcast(p) } None => crate::err::panic_after_error(), @@ -425,7 +339,7 @@ impl<'p> Python<'p> { { match NonNull::new(ptr) { Some(p) => { - let p = pythonrun::register_borrowed(self, p); + let p = gil::register_borrowed(self, p); Ok(self.unchecked_downcast(p)) } None => Err(PyErr::fetch(self)), @@ -440,7 +354,7 @@ impl<'p> Python<'p> { T: PyTypeInfo, { NonNull::new(ptr).map(|p| { - let p = pythonrun::register_borrowed(self, p); + let p = gil::register_borrowed(self, p); self.unchecked_downcast(p) }) } @@ -449,7 +363,7 @@ impl<'p> Python<'p> { /// Pass value ownership to `Python` object and get reference back. /// Value get cleaned up on the GIL release. pub fn register_any(self, ob: T) -> &'p T { - unsafe { pythonrun::register_any(ob) } + unsafe { gil::register_any(ob) } } /// Release PyObject reference. diff --git a/src/typeob.rs b/src/type_object.rs similarity index 98% rename from src/typeob.rs rename to src/type_object.rs index 93c23578..6893c937 100644 --- a/src/typeob.rs +++ b/src/type_object.rs @@ -4,12 +4,13 @@ use crate::class::methods::PyMethodDefType; use crate::err::{PyErr, PyResult}; -use crate::instance::{Py, PyObjectWithGIL}; -use crate::python::ToPyPointer; -use crate::python::{IntoPyPointer, Python}; +use crate::instance::{Py, PyNativeType}; use crate::types::PyObjectRef; use crate::types::PyType; -use crate::{class, ffi, pythonrun}; +use crate::IntoPyPointer; +use crate::Python; +use crate::ToPyPointer; +use crate::{class, ffi, gil}; use class::methods::PyMethodsProtocol; use std::collections::HashMap; use std::ffi::CString; @@ -171,7 +172,7 @@ impl IntoPyPointer for PyRawObject { } } -impl PyObjectWithGIL for PyRawObject { +impl PyNativeType for PyRawObject { #[inline] fn py(&self) -> Python { unsafe { Python::assume_gil_acquired() } @@ -430,7 +431,7 @@ unsafe extern "C" fn tp_dealloc_callback(obj: *mut ffi::PyObject) where T: PyObjectAlloc, { - let _pool = pythonrun::GILPool::new_no_pointers(); + let _pool = gil::GILPool::new_no_pointers(); let py = Python::assume_gil_acquired(); ::dealloc(py, obj) } diff --git a/src/types/boolobject.rs b/src/types/boolobject.rs index a3587ed1..1d391141 100644 --- a/src/types/boolobject.rs +++ b/src/types/boolobject.rs @@ -1,11 +1,12 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::conversion::{IntoPyObject, PyTryFrom, ToPyObject}; use crate::ffi; use crate::object::PyObject; -use crate::python::{Python, ToPyPointer}; use crate::types::PyObjectRef; use crate::FromPyObject; use crate::PyResult; +use crate::Python; +use crate::ToPyPointer; +use crate::{IntoPyObject, PyTryFrom, ToPyObject}; /// Represents a Python `bool`. #[repr(transparent)] @@ -62,10 +63,10 @@ impl<'source> FromPyObject<'source> for bool { #[cfg(test)] mod test { - use crate::conversion::ToPyObject; use crate::objectprotocol::ObjectProtocol; - use crate::python::Python; use crate::types::{PyBool, PyObjectRef}; + use crate::Python; + use crate::ToPyObject; #[test] fn test_true() { diff --git a/src/types/bytearray.rs b/src/types/bytearray.rs index 4fe1280f..438f2091 100644 --- a/src/types/bytearray.rs +++ b/src/types/bytearray.rs @@ -2,9 +2,10 @@ use crate::err::{PyErr, PyResult}; use crate::ffi; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; -use crate::python::{Python, ToPyPointer}; +use crate::Python; +use crate::ToPyPointer; use std::os::raw::c_char; use std::slice; @@ -72,8 +73,8 @@ impl PyByteArray { mod test { use crate::exceptions; use crate::object::PyObject; - use crate::python::Python; use crate::types::PyByteArray; + use crate::Python; #[test] fn test_bytearray() { diff --git a/src/types/complex.rs b/src/types/complex.rs index 0ce80b45..68fc65c1 100644 --- a/src/types/complex.rs +++ b/src/types/complex.rs @@ -1,7 +1,8 @@ use crate::ffi; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; -use crate::python::{Python, ToPyPointer}; +use crate::Python; +use crate::ToPyPointer; #[cfg(any(not(Py_LIMITED_API), not(Py_3)))] use std::ops::*; use std::os::raw::c_double; @@ -117,10 +118,10 @@ impl<'py> Neg for &'py PyComplex { #[cfg(feature = "num-complex")] mod complex_conversion { use super::*; - use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject}; use crate::err::PyErr; use crate::types::PyObjectRef; use crate::PyResult; + use crate::{FromPyObject, IntoPyObject, ToPyObject}; use num_complex::Complex; impl PyComplex { @@ -215,7 +216,7 @@ mod complex_conversion { #[cfg(test)] mod test { use super::PyComplex; - use crate::python::Python; + use crate::Python; use assert_approx_eq::assert_approx_eq; #[test] diff --git a/src/types/datetime.rs b/src/types/datetime.rs index e9828336..ec70b9d8 100644 --- a/src/types/datetime.rs +++ b/src/types/datetime.rs @@ -5,7 +5,6 @@ #![allow(clippy::too_many_arguments)] -use crate::conversion::ToPyObject; use crate::err::PyResult; use crate::ffi; use crate::ffi::PyDateTimeAPI; @@ -26,8 +25,10 @@ use crate::ffi::{ }; use crate::instance::Py; use crate::object::PyObject; -use crate::python::{Python, ToPyPointer}; use crate::types::PyTuple; +use crate::Python; +use crate::ToPyObject; +use crate::ToPyPointer; use std::os::raw::c_int; use std::ptr; diff --git a/src/types/dict.rs b/src/types/dict.rs index aa63f918..02217ee1 100644 --- a/src/types/dict.rs +++ b/src/types/dict.rs @@ -1,12 +1,14 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::conversion::{IntoPyObject, ToBorrowedObject, ToPyObject}; use crate::err::{self, PyErr, PyResult}; use crate::ffi; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; -use crate::python::{IntoPyPointer, Python, ToPyPointer}; use crate::types::{PyList, PyObjectRef}; +use crate::IntoPyPointer; +use crate::Python; +use crate::ToPyPointer; +use crate::{IntoPyObject, ToBorrowedObject, ToPyObject}; use std::{cmp, collections, hash, mem}; /// Represents a Python `dict`. @@ -300,12 +302,12 @@ where #[cfg(test)] mod test { - use crate::conversion::{IntoPyObject, PyTryFrom, ToPyObject}; use crate::instance::AsPyRef; - use crate::python::Python; use crate::types::dict::IntoPyDict; use crate::types::{PyDict, PyList, PyTuple}; use crate::ObjectProtocol; + use crate::Python; + use crate::{IntoPyObject, PyTryFrom, ToPyObject}; use std::collections::{BTreeMap, HashMap}; #[test] diff --git a/src/types/floatob.rs b/src/types/floatob.rs index fd3e7309..7d57902d 100644 --- a/src/types/floatob.rs +++ b/src/types/floatob.rs @@ -2,16 +2,17 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython -use crate::conversion::{IntoPyObject, ToPyObject}; use crate::err::PyErr; use crate::ffi; -use crate::instance::{Py, PyObjectWithGIL}; +use crate::instance::{Py, PyNativeType}; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; -use crate::python::{Python, ToPyPointer}; use crate::types::PyObjectRef; use crate::FromPyObject; use crate::PyResult; +use crate::Python; +use crate::ToPyPointer; +use crate::{IntoPyObject, ToPyObject}; use std::os::raw::c_double; /// Represents a Python `float` object. @@ -83,8 +84,8 @@ impl<'source> FromPyObject<'source> for f32 { #[cfg(test)] mod test { - use crate::conversion::ToPyObject; - use crate::python::Python; + use crate::Python; + use crate::ToPyObject; macro_rules! num_to_py_object_and_back ( ($func_name:ident, $t1:ty, $t2:ty) => ( diff --git a/src/types/iterator.rs b/src/types/iterator.rs index 919af21b..b8895f17 100644 --- a/src/types/iterator.rs +++ b/src/types/iterator.rs @@ -4,9 +4,10 @@ use crate::err::{PyDowncastError, PyErr, PyResult}; use crate::ffi; -use crate::instance::PyObjectWithGIL; -use crate::python::{Python, ToPyPointer}; +use crate::instance::PyNativeType; use crate::types::PyObjectRef; +use crate::Python; +use crate::ToPyPointer; /// A python iterator object. /// @@ -83,13 +84,13 @@ impl<'p> Drop for PyIterator<'p> { #[cfg(test)] mod tests { - use crate::conversion::ToPyObject; + use crate::gil::GILPool; use crate::instance::AsPyRef; use crate::objectprotocol::ObjectProtocol; - use crate::python::Python; - use crate::pythonrun::GILPool; use crate::types::{PyDict, PyList}; use crate::GILGuard; + use crate::Python; + use crate::ToPyObject; use indoc::indoc; #[test] diff --git a/src/types/list.rs b/src/types/list.rs index 1e684165..b57d115d 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -2,13 +2,15 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython -use crate::conversion::{IntoPyObject, ToBorrowedObject, ToPyObject}; use crate::err::{self, PyResult}; use crate::ffi::{self, Py_ssize_t}; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; -use crate::python::{IntoPyPointer, Python, ToPyPointer}; use crate::types::PyObjectRef; +use crate::IntoPyPointer; +use crate::Python; +use crate::ToPyPointer; +use crate::{IntoPyObject, ToBorrowedObject, ToPyObject}; /// Represents a Python `list`. #[repr(transparent)] @@ -166,7 +168,7 @@ impl ToPyObject for [T] where T: ToPyObject, { - fn to_object<'p>(&self, py: Python<'p>) -> PyObject { + fn to_object(&self, py: Python<'_>) -> PyObject { unsafe { let ptr = ffi::PyList_New(self.len() as Py_ssize_t); for (i, e) in self.iter().enumerate() { @@ -182,7 +184,7 @@ impl ToPyObject for Vec where T: ToPyObject, { - fn to_object<'p>(&self, py: Python<'p>) -> PyObject { + fn to_object(&self, py: Python<'_>) -> PyObject { self.as_slice().to_object(py) } } @@ -205,11 +207,11 @@ where #[cfg(test)] mod test { - use crate::conversion::{PyTryFrom, ToPyObject}; use crate::instance::AsPyRef; use crate::objectprotocol::ObjectProtocol; - use crate::python::Python; use crate::types::PyList; + use crate::Python; + use crate::{PyTryFrom, ToPyObject}; #[test] fn test_new() { diff --git a/src/types/mod.rs b/src/types/mod.rs index cf8b685f..8e839251 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -30,7 +30,6 @@ pub use self::string2::{PyBytes, PyString, PyUnicode}; pub use self::tuple::PyTuple; pub use self::typeobject::PyType; use crate::ffi; -use crate::python::ToPyPointer; use crate::PyObject; /// Implements a typesafe conversions throught [FromPyObject], given a typecheck function as second @@ -58,8 +57,6 @@ macro_rules! pyobject_downcast ( #[macro_export] macro_rules! pyobject_native_type_named ( ($name: ty $(,$type_param: ident)*) => { - impl<$($type_param,)*> $crate::PyNativeType for $name {} - impl<$($type_param,)*> ::std::convert::AsRef<$crate::types::PyObjectRef> for $name { #[inline] fn as_ref(&self) -> &$crate::types::PyObjectRef { @@ -67,14 +64,13 @@ macro_rules! pyobject_native_type_named ( } } - impl<$($type_param,)*> $crate::PyObjectWithGIL for $name { - #[inline] + impl<$($type_param,)*> $crate::PyNativeType for $name { fn py(&self) -> $crate::Python { unsafe { $crate::Python::assume_gil_acquired() } } } - impl<$($type_param,)*> $crate::python::ToPyPointer for $name { + impl<$($type_param,)*> $crate::ToPyPointer for $name { /// Gets the underlying FFI pointer, returns a borrowed pointer. #[inline] fn as_ptr(&self) -> *mut $crate::ffi::PyObject { @@ -85,6 +81,8 @@ macro_rules! pyobject_native_type_named ( impl<$($type_param,)*> PartialEq for $name { #[inline] fn eq(&self, o: &$name) -> bool { + use $crate::ToPyPointer; + self.as_ptr() == o.as_ptr() } } @@ -108,7 +106,7 @@ macro_rules! pyobject_native_type ( #[macro_export] macro_rules! pyobject_native_type_convert( ($name: ty, $typeobject: expr, $checkfunction: path $(,$type_param: ident)*) => { - impl<$($type_param,)*> $crate::typeob::PyTypeInfo for $name { + impl<$($type_param,)*> $crate::type_object::PyTypeInfo for $name { type Type = (); type BaseType = $crate::types::PyObjectRef; @@ -121,18 +119,20 @@ macro_rules! pyobject_native_type_convert( &mut $typeobject } + #[allow(unused_unsafe)] fn is_instance(ptr: &$crate::types::PyObjectRef) -> bool { - #[allow(unused_unsafe)] + use $crate::ToPyPointer; + unsafe { $checkfunction(ptr.as_ptr()) > 0 } } } - impl<$($type_param,)*> $crate::typeob::PyObjectAlloc for $name {} + impl<$($type_param,)*> $crate::type_object::PyObjectAlloc for $name {} - impl<$($type_param,)*> $crate::typeob::PyTypeObject for $name { + impl<$($type_param,)*> $crate::type_object::PyTypeObject for $name { fn init_type() -> std::ptr::NonNull<$crate::ffi::PyTypeObject> { unsafe { - std::ptr::NonNull::new_unchecked(::type_object() as *mut _) + std::ptr::NonNull::new_unchecked(::type_object() as *mut _) } } } @@ -141,6 +141,8 @@ macro_rules! pyobject_native_type_convert( { #[inline] fn to_object(&self, py: $crate::Python) -> $crate::PyObject { + use $crate::ToPyPointer; + unsafe {$crate::PyObject::from_borrowed_ptr(py, self.0.as_ptr())} } } @@ -178,7 +180,6 @@ mod bytearray; mod complex; mod datetime; mod dict; -pub mod exceptions; mod floatob; mod iterator; mod list; diff --git a/src/types/module.rs b/src/types/module.rs index f93b4870..8974b62c 100644 --- a/src/types/module.rs +++ b/src/types/module.rs @@ -2,18 +2,21 @@ // // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython -use crate::conversion::{IntoPy, ToPyObject}; use crate::err::{PyErr, PyResult}; +use crate::exceptions; use crate::ffi; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; -use crate::python::{Python, ToPyPointer}; -use crate::typeob::PyTypeCreate; -use crate::typeob::PyTypeObject; +use crate::type_object::PyTypeCreate; +use crate::type_object::PyTypeObject; use crate::types::PyTuple; -use crate::types::{exceptions, PyDict, PyObjectRef}; +use crate::types::{PyDict, PyObjectRef}; +use crate::IntoPy; use crate::Py; +use crate::Python; +use crate::ToPyObject; +use crate::ToPyPointer; use std::ffi::{CStr, CString}; use std::os::raw::c_char; use std::str; @@ -64,7 +67,7 @@ impl PyModule { return Err(PyErr::fetch(py)); } - <&PyModule as crate::conversion::FromPyObject>::extract(py.from_owned_ptr_or_err(mptr)?) + <&PyModule as crate::FromPyObject>::extract(py.from_owned_ptr_or_err(mptr)?) } } @@ -124,10 +127,7 @@ impl PyModule { /// Calls a function in the module. /// This is equivalent to the Python expression: `getattr(module, name)(*args)` - pub fn call1(&self, name: &str, args: A) -> PyResult<&PyObjectRef> - where - A: IntoPy>, - { + pub fn call1(&self, name: &str, args: impl IntoPy>) -> PyResult<&PyObjectRef> { self.getattr(name)?.call1(args) } diff --git a/src/types/num2.rs b/src/types/num2.rs index b6775d0e..10fd80d8 100644 --- a/src/types/num2.rs +++ b/src/types/num2.rs @@ -3,13 +3,16 @@ // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython use super::num_common::{err_if_invalid_value, IS_LITTLE_ENDIAN}; -use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject}; use crate::err::{PyErr, PyResult}; +use crate::exceptions; use crate::ffi; -use crate::instance::{Py, PyObjectWithGIL}; +use crate::instance::{Py, PyNativeType}; use crate::object::PyObject; -use crate::python::{IntoPyPointer, Python, ToPyPointer}; -use crate::types::{exceptions, PyObjectRef}; +use crate::types::PyObjectRef; +use crate::IntoPyPointer; +use crate::Python; +use crate::ToPyPointer; +use crate::{FromPyObject, IntoPyObject, ToPyObject}; use num_traits::cast::cast; use std::os::raw::{c_long, c_uchar}; @@ -177,8 +180,8 @@ int_convert_bignum!(u128, 16, IS_LITTLE_ENDIAN, 0); #[cfg(test)] mod test { - use crate::conversion::ToPyObject; - use crate::python::Python; + use crate::Python; + use crate::ToPyObject; macro_rules! num_to_py_object_and_back ( ($func_name:ident, $t1:ty, $t2:ty) => ( diff --git a/src/types/num3.rs b/src/types/num3.rs index 766da083..27c6dd0a 100644 --- a/src/types/num3.rs +++ b/src/types/num3.rs @@ -3,13 +3,15 @@ // based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython use super::num_common::{err_if_invalid_value, IS_LITTLE_ENDIAN}; -use crate::conversion::{FromPyObject, IntoPyObject, ToPyObject}; use crate::err::{PyErr, PyResult}; +use crate::exceptions; use crate::ffi; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; -use crate::python::{Python, ToPyPointer}; -use crate::types::{exceptions, PyObjectRef}; +use crate::types::PyObjectRef; +use crate::Python; +use crate::ToPyPointer; +use crate::{FromPyObject, IntoPyObject, ToPyObject}; use num_traits::cast::cast; use std::i64; use std::os::raw::{c_long, c_uchar}; @@ -146,9 +148,9 @@ mod test { macro_rules! test_common ( ($test_mod_name:ident, $t:ty) => ( mod $test_mod_name { - use crate::types::exceptions; - use crate::conversion::ToPyObject; - use crate::python::Python; + use crate::exceptions; + use crate::ToPyObject; + use crate::Python; #[test] fn from_py_string_type_error() { diff --git a/src/types/num_common.rs b/src/types/num_common.rs index 653c409a..76921c70 100644 --- a/src/types/num_common.rs +++ b/src/types/num_common.rs @@ -1,7 +1,7 @@ //! common macros for num2.rs and num3.rs use crate::err::{PyErr, PyResult}; -use crate::python::Python; +use crate::Python; use std::os::raw::c_int; pub(super) fn err_if_invalid_value( @@ -104,8 +104,8 @@ pub(super) const IS_LITTLE_ENDIAN: c_int = 0; #[cfg(test)] mod test { - use crate::conversion::ToPyObject; - use crate::python::Python; + use crate::Python; + use crate::ToPyObject; #[test] fn test_u32_max() { @@ -188,9 +188,9 @@ mod test { #[test] #[cfg(not(Py_LIMITED_API))] fn test_u128_overflow() { + use crate::exceptions; use crate::ffi; use crate::object::PyObject; - use crate::types::exceptions; use std::os::raw::c_uchar; let gil = Python::acquire_gil(); let py = gil.python(); diff --git a/src/types/sequence.rs b/src/types/sequence.rs index 7cadfa7b..3e24bf99 100644 --- a/src/types/sequence.rs +++ b/src/types/sequence.rs @@ -1,14 +1,14 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::buffer; -use crate::conversion::{FromPyObject, PyTryFrom, ToBorrowedObject}; use crate::err::{self, PyDowncastError, PyErr, PyResult}; use crate::ffi::{self, Py_ssize_t}; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; -use crate::python::ToPyPointer; use crate::types::{PyList, PyObjectRef, PyTuple}; +use crate::ToPyPointer; +use crate::{FromPyObject, PyTryFrom, ToBorrowedObject}; /// Represents a reference to a python object supporting the sequence protocol. #[repr(transparent)] @@ -327,12 +327,13 @@ impl<'v> PyTryFrom<'v> for PySequence { #[cfg(test)] mod test { - use crate::conversion::{PyTryFrom, ToPyObject}; use crate::instance::AsPyRef; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; - use crate::python::{Python, ToPyPointer}; use crate::types::PySequence; + use crate::Python; + use crate::ToPyPointer; + use crate::{PyTryFrom, ToPyObject}; fn get_object() -> PyObject { // Convenience function for getting a single unique object diff --git a/src/types/set.rs b/src/types/set.rs index 899e963c..c59e0a2a 100644 --- a/src/types/set.rs +++ b/src/types/set.rs @@ -1,12 +1,13 @@ // Copyright (c) 2017-present PyO3 Project and Contributors // -use crate::conversion::{ToBorrowedObject, ToPyObject}; use crate::err::{self, PyErr, PyResult}; use crate::ffi; -use crate::instance::{AsPyRef, Py, PyObjectWithGIL}; +use crate::instance::{AsPyRef, Py, PyNativeType}; use crate::object::PyObject; -use crate::python::{Python, ToPyPointer}; +use crate::Python; +use crate::ToPyPointer; +use crate::{ToBorrowedObject, ToPyObject}; use std::{collections, hash}; /// Represents a Python `set` @@ -160,10 +161,10 @@ impl PyFrozenSet { #[cfg(test)] mod test { use super::{PyFrozenSet, PySet}; - use crate::conversion::{PyTryFrom, ToPyObject}; use crate::instance::AsPyRef; use crate::objectprotocol::ObjectProtocol; - use crate::python::Python; + use crate::Python; + use crate::{PyTryFrom, ToPyObject}; use std::collections::HashSet; #[test] diff --git a/src/types/slice.rs b/src/types/slice.rs index d02ffef5..98c27056 100644 --- a/src/types/slice.rs +++ b/src/types/slice.rs @@ -1,11 +1,11 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use crate::conversion::ToPyObject; use crate::err::{PyErr, PyResult}; use crate::ffi::{self, Py_ssize_t}; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; -use crate::python::{Python, ToPyPointer}; +use crate::Python; +use crate::{ToPyObject, ToPyPointer}; use std::os::raw::c_long; /// Represents a Python `slice`. diff --git a/src/types/string.rs b/src/types/string.rs index 5a8b7663..75c65800 100644 --- a/src/types/string.rs +++ b/src/types/string.rs @@ -1,12 +1,13 @@ // Copyright (c) 2017-present PyO3 Project and Contributors use crate::err::{PyErr, PyResult}; +use crate::exceptions; use crate::ffi; -use crate::instance::{Py, PyObjectWithGIL}; +use crate::instance::{Py, PyNativeType}; use crate::object::PyObject; -use crate::python::{Python, ToPyPointer}; -use crate::types::exceptions; use crate::types::PyObjectRef; +use crate::Python; +use crate::ToPyPointer; use std::borrow::Cow; use std::os::raw::c_char; use std::{mem, str}; @@ -119,10 +120,10 @@ impl PyBytes { #[cfg(test)] mod test { use super::PyString; - use crate::conversion::{FromPyObject, PyTryFrom, ToPyObject}; use crate::instance::AsPyRef; use crate::object::PyObject; - use crate::python::Python; + use crate::Python; + use crate::{FromPyObject, PyTryFrom, ToPyObject}; use std::borrow::Cow; #[test] diff --git a/src/types/string2.rs b/src/types/string2.rs index ac8e9bfc..aecc7bdd 100644 --- a/src/types/string2.rs +++ b/src/types/string2.rs @@ -4,13 +4,14 @@ use super::PyObjectRef; use crate::err::{PyErr, PyResult}; +use crate::exceptions; use crate::ffi; -use crate::instance::{Py, PyObjectWithGIL}; +use crate::instance::{Py, PyNativeType}; use crate::object::PyObject; use crate::objectprotocol::ObjectProtocol; use crate::python::IntoPyPointer; -use crate::python::{Python, ToPyPointer}; -use crate::types::exceptions; +use crate::Python; +use crate::ToPyPointer; use std::borrow::Cow; use std::os::raw::c_char; use std::str; @@ -204,10 +205,10 @@ impl std::convert::From> for Py { #[cfg(test)] mod test { use super::PyString; - use crate::conversion::{FromPyObject, PyTryFrom, ToPyObject}; use crate::instance::AsPyRef; use crate::object::PyObject; - use crate::python::Python; + use crate::Python; + use crate::{FromPyObject, PyTryFrom, ToPyObject}; use std::borrow::Cow; #[test] diff --git a/src/types/stringutils.rs b/src/types/stringutils.rs index 0f3ce9af..0837eee1 100644 --- a/src/types/stringutils.rs +++ b/src/types/stringutils.rs @@ -1,10 +1,10 @@ -use crate::conversion::{IntoPyObject, PyTryFrom, ToPyObject}; use crate::err::PyResult; -use crate::instance::PyObjectWithGIL; +use crate::instance::PyNativeType; use crate::object::PyObject; -use crate::python::Python; use crate::types::{PyObjectRef, PyString}; use crate::FromPyObject; +use crate::Python; +use crate::{IntoPyObject, PyTryFrom, ToPyObject}; use std::borrow::Cow; /// Converts Rust `str` to Python object. diff --git a/src/types/tuple.rs b/src/types/tuple.rs index eaa40a7a..ac5629d9 100644 --- a/src/types/tuple.rs +++ b/src/types/tuple.rs @@ -1,13 +1,16 @@ // Copyright (c) 2017-present PyO3 Project and Contributors -use super::exceptions; -use crate::conversion::{FromPyObject, IntoPy, IntoPyObject, PyTryFrom, ToPyObject}; +use crate::conversion::FromPy; use crate::err::{PyErr, PyResult}; +use crate::exceptions; use crate::ffi::{self, Py_ssize_t}; -use crate::instance::{AsPyRef, Py, PyObjectWithGIL}; +use crate::instance::{AsPyRef, Py, PyNativeType}; use crate::object::PyObject; -use crate::python::{IntoPyPointer, Python, ToPyPointer}; use crate::types::PyObjectRef; +use crate::IntoPyPointer; +use crate::Python; +use crate::ToPyPointer; +use crate::{FromPyObject, IntoPy, IntoPyObject, PyTryFrom, ToPyObject}; use std::slice; /// Represents a Python `tuple` object. @@ -131,25 +134,9 @@ impl<'a> IntoIterator for &'a PyTuple { } } -impl<'a> IntoPy> for &'a PyTuple { - fn into_py(self, _py: Python) -> Py { - unsafe { Py::from_borrowed_ptr(self.as_ptr()) } - } -} - -impl IntoPy> for Py { - fn into_py(self, _py: Python) -> Py { - self - } -} - -impl<'a> IntoPy> for &'a str { - fn into_py(self, py: Python) -> Py { - unsafe { - let ptr = ffi::PyTuple_New(1); - ffi::PyTuple_SetItem(ptr, 0, self.into_object(py).into_ptr()); - Py::from_owned_ptr_or_panic(ptr) - } +impl<'a> FromPy<&'a PyTuple> for Py { + fn from_py(tuple: &'a PyTuple, _py: Python) -> Py { + unsafe { Py::from_borrowed_ptr(tuple.as_ptr()) } } } @@ -265,12 +252,12 @@ tuple_conversion!( #[cfg(test)] mod test { - use crate::conversion::{PyTryFrom, ToPyObject}; use crate::instance::AsPyRef; use crate::objectprotocol::ObjectProtocol; - use crate::python::Python; use crate::types::PyObjectRef; use crate::types::PyTuple; + use crate::Python; + use crate::{PyTryFrom, ToPyObject}; use std::collections::HashSet; #[test] diff --git a/src/types/typeobject.rs b/src/types/typeobject.rs index 272d9373..38a83f0e 100644 --- a/src/types/typeobject.rs +++ b/src/types/typeobject.rs @@ -4,10 +4,11 @@ use crate::err::{PyErr, PyResult}; use crate::ffi; -use crate::instance::{Py, PyObjectWithGIL}; +use crate::instance::{Py, PyNativeType}; use crate::object::PyObject; -use crate::python::{Python, ToPyPointer}; -use crate::typeob::{PyTypeInfo, PyTypeObject}; +use crate::type_object::{PyTypeInfo, PyTypeObject}; +use crate::Python; +use crate::ToPyPointer; use std::borrow::Cow; use std::ffi::CStr; diff --git a/tests/test_arithmetics.rs b/tests/test_arithmetics.rs index f043e107..1f5afe9c 100644 --- a/tests/test_arithmetics.rs +++ b/tests/test_arithmetics.rs @@ -1,3 +1,4 @@ +use pyo3::class::basic::CompareOp; use pyo3::class::*; use pyo3::prelude::*; use pyo3::types::PyObjectRef; diff --git a/tests/test_class_basics.rs b/tests/test_class_basics.rs index a1f24eca..7431406e 100644 --- a/tests/test_class_basics.rs +++ b/tests/test_class_basics.rs @@ -12,7 +12,7 @@ fn empty_class() { let py = gil.python(); let typeobj = py.get_type::(); // By default, don't allow creating instances from python. - assert!(typeobj.call(NoArgs, None).is_err()); + assert!(typeobj.call((), None).is_err()); py_assert!(py, typeobj, "typeobj.__name__ == 'EmptyClass'"); } diff --git a/tests/test_class_new.rs b/tests/test_class_new.rs index 1fa5074d..11b51bf3 100644 --- a/tests/test_class_new.rs +++ b/tests/test_class_new.rs @@ -18,7 +18,7 @@ fn empty_class_with_new() { let py = gil.python(); let typeobj = py.get_type::(); assert!(typeobj - .call(NoArgs, None) + .call((), None) .unwrap() .cast_as::() .is_ok()); diff --git a/tests/test_dunder.rs b/tests/test_dunder.rs index 83ab1057..2d822014 100644 --- a/tests/test_dunder.rs +++ b/tests/test_dunder.rs @@ -6,8 +6,8 @@ use pyo3::class::{ use pyo3::exceptions::{IndexError, ValueError}; use pyo3::ffi; use pyo3::prelude::*; -use pyo3::python::ToPyPointer; use pyo3::types::{PyBytes, PyDict, PyObjectRef, PySlice, PyString, PyType}; +use pyo3::ToPyPointer; use std::{isize, iter}; #[macro_use] @@ -176,7 +176,7 @@ impl PySequenceProtocol for Sequence { fn __getitem__(&self, key: isize) -> PyResult { if key == 5 { - return Err(PyErr::new::(NoArgs)); + return Err(PyErr::new::(())); } Ok(key) } diff --git a/tests/test_gc.rs b/tests/test_gc.rs index 5106b07e..49804ec4 100644 --- a/tests/test_gc.rs +++ b/tests/test_gc.rs @@ -3,10 +3,10 @@ use pyo3::class::PyTraverseError; use pyo3::class::PyVisit; use pyo3::ffi; use pyo3::prelude::*; -use pyo3::python::ToPyPointer; use pyo3::types::PyObjectRef; use pyo3::types::PyTuple; use pyo3::PyRawObject; +use pyo3::ToPyPointer; use std::cell::RefCell; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; @@ -100,7 +100,7 @@ impl Drop for ClassWithDrop { } } -// Test behavior of pythonrun::register_pointers + typeob::dealloc +// Test behavior of pythonrun::register_pointers + type_object::dealloc #[test] fn create_pointers_in_drop() { let _gil = Python::acquire_gil(); @@ -258,7 +258,7 @@ fn inheritance_with_new_methods_with_drop() { let py = gil.python(); let _typebase = py.get_type::(); let typeobj = py.get_type::(); - let inst = typeobj.call(NoArgs, None).unwrap(); + let inst = typeobj.call((), None).unwrap(); let obj = SubClassWithDrop::try_from_mut(inst).unwrap(); obj.data = Some(Arc::clone(&drop_called1)); diff --git a/tests/test_inheritance.rs b/tests/test_inheritance.rs index 8780a178..07c6e3aa 100644 --- a/tests/test_inheritance.rs +++ b/tests/test_inheritance.rs @@ -60,6 +60,6 @@ fn inheritance_with_new_methods() { let py = gil.python(); let _typebase = py.get_type::(); let typeobj = py.get_type::(); - let inst = typeobj.call(NoArgs, None).unwrap(); + let inst = typeobj.call((), None).unwrap(); py_run!(py, inst, "assert inst.val1 == 10; assert inst.val2 == 5"); } diff --git a/tests/test_module.rs b/tests/test_module.rs index 6dfce243..85dd19e0 100644 --- a/tests/test_module.rs +++ b/tests/test_module.rs @@ -86,14 +86,14 @@ fn some_name(_: Python, _: &PyModule) -> PyResult<()> { #[test] #[cfg(Py_3)] fn test_module_renaming() { + use pyo3::wrap_pymodule; + let gil = Python::acquire_gil(); let py = gil.python(); let d = PyDict::new(py); - d.set_item("different_name", unsafe { - PyObject::from_owned_ptr(py, PyInit_other_name()) - }) - .unwrap(); + d.set_item("different_name", wrap_pymodule!(other_name)(py)) + .unwrap(); py.run( "assert different_name.__name__ == 'other_name'",