Many small improvements
This commit is contained in:
parent
55d0917419
commit
d0ed68414a
|
@ -4,7 +4,9 @@ language: python
|
|||
|
||||
cache:
|
||||
pip: true
|
||||
cargo: true
|
||||
directories:
|
||||
- $HOME/.cargo
|
||||
- $TRAVIS_BUILD_DIR/target
|
||||
|
||||
matrix:
|
||||
include:
|
||||
|
|
14
Cargo.toml
14
Cargo.toml
|
@ -15,22 +15,22 @@ build = "build.rs"
|
|||
|
||||
[badges]
|
||||
travis-ci = { repository = "PyO3/pyo3", branch = "master" }
|
||||
appveyor = { repository = "PyO3/pyo3" }
|
||||
appveyor = { repository = "fafhrd91/pyo3" }
|
||||
codecov = { repository = "PyO3/pyo3", branch = "master", service = "github" }
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2"
|
||||
spin = "0.4.6"
|
||||
num-traits = "0.2"
|
||||
libc = "0.2.42"
|
||||
spin = "0.4.8"
|
||||
num-traits = "0.2.5"
|
||||
pyo3cls = { path = "pyo3cls", version = "0.4.0" }
|
||||
mashup = "0.1.5"
|
||||
|
||||
[dev-dependencies]
|
||||
docmatic = "^0.1.2"
|
||||
docmatic = "0.1.2"
|
||||
|
||||
[build-dependencies]
|
||||
regex = "1.0"
|
||||
version_check = "0.1.3"
|
||||
regex = "1.0.2"
|
||||
version_check = "0.1.4"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# PyO3
|
||||
|
||||
[![Build Status](https://travis-ci.org/PyO3/pyo3.svg?branch=master)](https://travis-ci.org/PyO3/pyo3)
|
||||
[![Build Status](https://ci.appveyor.com/api/projects/status/github/PyO3/pyo3?branch=master&svg=true)](https://ci.appveyor.com/project/fafhrd91/pyo3)
|
||||
[![Build Status](https://ci.appveyor.com/api/projects/status/github/fafhrd91/pyo3?branch=master&svg=true)](https://ci.appveyor.com/project/fafhrd91/pyo3)
|
||||
[![codecov](https://codecov.io/gh/PyO3/pyo3/branch/master/graph/badge.svg)](https://codecov.io/gh/PyO3/pyo3)
|
||||
[![crates.io](http://meritbadge.herokuapp.com/pyo3)](https://crates.io/crates/pyo3)
|
||||
[![Join the dev chat](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/PyO3/Lobby)
|
||||
|
|
20
build.rs
20
build.rs
|
@ -6,6 +6,7 @@ use std::collections::HashMap;
|
|||
use std::env;
|
||||
use std::fmt;
|
||||
use std::process::Command;
|
||||
use std::process::Stdio;
|
||||
use version_check::{is_min_date, is_min_version, supports_features};
|
||||
|
||||
// Specifies the minimum nightly version needed to compile pyo3.
|
||||
|
@ -172,12 +173,12 @@ fn cfg_line_for_var(key: &str, val: &str) -> Option<String> {
|
|||
fn run_python_script(interpreter: &str, script: &str) -> Result<String, String> {
|
||||
let out = Command::new(interpreter)
|
||||
.args(&["-c", script])
|
||||
.stderr(Stdio::inherit())
|
||||
.output()
|
||||
.map_err(|e| format!("failed to run python interpreter:\n\n{}", e))?;
|
||||
|
||||
if !out.status.success() {
|
||||
let stderr = String::from_utf8(out.stderr).unwrap();
|
||||
return Err(format!("python script failed with stderr:\n\n{}", stderr));
|
||||
return Err(format!("python script failed"));
|
||||
}
|
||||
|
||||
Ok(String::from_utf8(out.stdout).unwrap())
|
||||
|
@ -306,11 +307,16 @@ fn find_interpreter_and_get_config(
|
|||
|
||||
/// Extract compilation vars from the specified interpreter.
|
||||
fn get_config_from_interpreter(interpreter: &str) -> Result<(PythonVersion, Vec<String>), String> {
|
||||
let script = "import sys; import sysconfig; print(sys.version_info[0:2]); \
|
||||
print(sysconfig.get_config_var('LIBDIR')); \
|
||||
print(sysconfig.get_config_var('Py_ENABLE_SHARED')); \
|
||||
print(sysconfig.get_config_var('LDVERSION') or sysconfig.get_config_var('py_version_short')); \
|
||||
print(sys.exec_prefix);";
|
||||
let script = r#"
|
||||
import sys
|
||||
import sysconfig
|
||||
|
||||
print(sys.version_info[0:2])
|
||||
print(sysconfig.get_config_var('LIBDIR'))
|
||||
print(sysconfig.get_config_var('Py_ENABLE_SHARED'))
|
||||
print(sysconfig.get_config_var('LDVERSION') or sysconfig.get_config_var('py_version_short'))
|
||||
print(sys.exec_prefix)
|
||||
"#;
|
||||
let out = run_python_script(interpreter, script)?;
|
||||
let lines: Vec<String> = out.lines().map(|line| line.to_owned()).collect();
|
||||
let interpreter_version = get_interpreter_version(&lines[0])?;
|
||||
|
|
|
@ -38,13 +38,7 @@ fi
|
|||
### Setup python linker flags ##################################################
|
||||
|
||||
PYTHON_LIB=$(python -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")
|
||||
LIBRARY_PATH="$LIBRARY_PATH:$PYTHON_LIB"
|
||||
|
||||
# delete any possible empty components
|
||||
# https://github.com/google/pulldown-cmark/issues/122#issuecomment-364948741
|
||||
LIBRARY_PATH=$(echo ${LIBRARY_PATH} | sed -E -e 's/^:*//' -e 's/:*$//' -e 's/:+/:/g')
|
||||
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PYTHON_LIB:$HOME/rust/lib"
|
||||
|
||||
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$LIBRARY_PATH:$HOME/rust/lib"
|
||||
|
||||
python -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))"
|
||||
echo ${LD_LIBRARY_PATH}
|
|
@ -4,7 +4,7 @@ name = "word-count"
|
|||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
rayon = "1.0"
|
||||
rayon = "1.0.2"
|
||||
pyo3 = { path = "../..", features = ["extension-module"] }
|
||||
|
||||
[lib]
|
||||
|
|
2
examples/word-count/pyproject.toml
Normal file
2
examples/word-count/pyproject.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[build-system]
|
||||
requires = ["setuptools", "wheel", "setuptools-rust"]
|
|
@ -25,8 +25,7 @@ class PyTest(TestCommand):
|
|||
import subprocess
|
||||
import sys
|
||||
|
||||
errno = subprocess.call([sys.executable, "-m", "pytest", "tests"])
|
||||
raise SystemExit(errno)
|
||||
subprocess.check_call([sys.executable, "-m", "pytest", "tests"])
|
||||
|
||||
|
||||
setup_requires = ["setuptools-rust>=0.10.1", "wheel"]
|
||||
|
|
|
@ -54,3 +54,16 @@ fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
|
|||
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
## Closures
|
||||
|
||||
Currently, there are no conversions between `Fn`s in rust and callables in python. This would definitely be possible and very useful, so contributions are welcome. In the meantime, you can do the following:
|
||||
|
||||
### 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 paramter. There are also `ObjectProtocol::call0` with no args and `ObjectProtocol::call1` with only the args.
|
||||
|
||||
### Calling rust `Fn`s in python
|
||||
|
||||
If you have a static function, you can expose it with `#[pyfunction]` and use `wrap_function!` to get the corresponding `PyObject`. For dynamic functions, e.g. lambda and functions that were passed as arguments, you must put them in some kind of owned container, e.g. a box. (Long-Term a special container similar to wasm-bindgen's `Closure` should take care of that). You can than use a `#[pyclass]` struct with that container as field as a way to pass the function over the ffi-barrier. You can even make that class callable with `__call__` so it looks like a function in python code.
|
||||
|
||||
|
|
|
@ -11,13 +11,13 @@ categories = ["api-bindings", "development-tools::ffi"]
|
|||
license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
log="0.4"
|
||||
quote="0.6"
|
||||
log= "0.4.3"
|
||||
quote= "0.6.4"
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = "0.4.9"
|
||||
features = ["nightly"]
|
||||
|
||||
[dependencies.syn]
|
||||
version="0.14"
|
||||
version= "0.14.5"
|
||||
features=["full", "parsing", "printing", "extra-traits"]
|
||||
|
|
|
@ -61,7 +61,7 @@ pub fn py2_init(fnname: &syn::Ident, name: &syn::Ident, doc: syn::Lit) -> TokenS
|
|||
|
||||
quote! {
|
||||
#[no_mangle]
|
||||
#[allow(non_snake_case, unused_imports)]
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe extern "C" fn #cb_name() {
|
||||
// initialize python
|
||||
::pyo3::init_once();
|
||||
|
@ -281,7 +281,6 @@ fn function_c_wrapper(name: &syn::Ident, spec: &method::FnSpec) -> TokenStream {
|
|||
let body_to_result = py_method::body_to_result(&body, spec);
|
||||
|
||||
quote! {
|
||||
#[allow(unused_variables, unused_imports)]
|
||||
unsafe extern "C" fn __wrap(
|
||||
_slf: *mut ::pyo3::ffi::PyObject,
|
||||
_args: *mut ::pyo3::ffi::PyObject,
|
||||
|
|
|
@ -14,10 +14,10 @@ license = "Apache-2.0"
|
|||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote="0.6"
|
||||
quote= "0.6.4"
|
||||
|
||||
[dependencies.syn]
|
||||
version="0.14"
|
||||
version= "0.14.5"
|
||||
features=["full", "parsing", "printing", "extra-traits"]
|
||||
|
||||
[dependencies.pyo3-derive-backend]
|
||||
|
|
|
@ -98,20 +98,20 @@ mod tupleobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3
|
|||
mod enumobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod methodobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod moduleobject;
|
||||
mod setobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod setobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
// mod funcobject; TODO excluded by PEP-384
|
||||
// mod classobject; TODO excluded by PEP-384
|
||||
mod fileobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod pycapsule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod sliceobject;
|
||||
mod traceback; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod traceback; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
// mod cellobject; TODO excluded by PEP-384
|
||||
mod descrobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod genobject; // TODO excluded by PEP-384
|
||||
mod iterobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod structseq;
|
||||
mod warnings; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod weakrefobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod weakrefobject; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
// mod namespaceobject; TODO
|
||||
|
||||
mod codecs; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
|
@ -131,7 +131,7 @@ mod import;
|
|||
mod intrcheck; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
#[cfg(Py_3_6)]
|
||||
mod osmodule;
|
||||
mod sysmodule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5 // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
mod sysmodule; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
|
||||
mod bltinmodule;
|
||||
mod objectabstract; // TODO supports PEP-384 only; needs adjustment for Python 3.3 and 3.5
|
||||
|
|
|
@ -14,7 +14,6 @@ use python::{IntoPyDictPointer, IntoPyPointer, Python, ToPyPointer};
|
|||
use typeob::PyTypeInfo;
|
||||
|
||||
/// Python object model helper methods
|
||||
|
||||
pub trait ObjectProtocol {
|
||||
/// Determines whether this object has the given attribute.
|
||||
/// This is equivalent to the Python expression 'hasattr(self, attr_name)'.
|
||||
|
@ -517,14 +516,14 @@ where
|
|||
FromPyObject::extract(self.into())
|
||||
}
|
||||
|
||||
fn get_refcnt(&self) -> isize {
|
||||
unsafe { ffi::Py_REFCNT(self.as_ptr()) }
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)] // the Python keyword starts with uppercase
|
||||
fn None(&self) -> PyObject {
|
||||
unsafe { PyObject::from_borrowed_ptr(self.py(), ffi::Py_None()) }
|
||||
}
|
||||
|
||||
fn get_refcnt(&self) -> isize {
|
||||
unsafe { ffi::Py_REFCNT(self.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
//
|
||||
// based on Daniel Grunwald's https://github.com/dgrunwald/rust-cpython
|
||||
|
||||
use std;
|
||||
use std::ffi::CString;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_int;
|
||||
|
||||
use conversion::PyTryFrom;
|
||||
use err::{PyDowncastError, PyErr, PyResult};
|
||||
use ffi;
|
||||
|
@ -14,6 +9,10 @@ use instance::{AsPyRef, Py, PyToken};
|
|||
use object::PyObject;
|
||||
use objects::{PyDict, PyModule, PyObjectRef, PyType};
|
||||
use pythonrun::{self, GILGuard};
|
||||
use std;
|
||||
use std::ffi::CString;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::raw::c_int;
|
||||
use typeob::{PyObjectAlloc, PyTypeInfo, PyTypeObject};
|
||||
|
||||
/// Marker type that indicates that the GIL is currently held.
|
||||
|
@ -294,10 +293,11 @@ impl<'p> Python<'p> {
|
|||
where
|
||||
T: PyTypeInfo,
|
||||
{
|
||||
let p;
|
||||
unsafe {
|
||||
let p = pythonrun::register_owned(self, obj.into_ptr());
|
||||
<T as PyTryFrom>::try_from(p)
|
||||
p = pythonrun::register_owned(self, obj.into_ptr());
|
||||
}
|
||||
<T as PyTryFrom>::try_from(p)
|
||||
}
|
||||
|
||||
/// Register object in release pool, and do unchecked downcast to specific type.
|
||||
|
@ -463,7 +463,6 @@ impl<'p> Python<'p> {
|
|||
/// Release `ffi::PyObject` pointer.
|
||||
/// Undefined behavior if the pointer is invalid.
|
||||
#[inline]
|
||||
|
||||
pub fn xdecref(self, ptr: *mut ffi::PyObject) {
|
||||
if !ptr.is_null() {
|
||||
unsafe { ffi::Py_DECREF(ptr) };
|
||||
|
|
Loading…
Reference in a new issue