#[pymodinit] now uses the function name as default module name

This commit is contained in:
konstin 2018-07-10 00:13:02 +02:00
parent c32dd1c120
commit fe931a594f
18 changed files with 64 additions and 42 deletions

View File

@ -5,6 +5,7 @@
* Upgraded to syn 0.14 which means much better error messages :tada:
* 128 bit integer support by [kngwyu](https://github.com/kngwyu) ([#137](https://github.com/PyO3/pyo3/pull/173))
* Added `py` prefixes to the proc macros and moved them into the root module. You should just use the plain proc macros, i.e. `#[pyclass]`, `#[pymethods]`, `#[pyproto]`, `#[pyfunction]` and `#[pymodinit]`. This is important because `proc_macro_path_invoc` isn't going to be stabilized soon.
* `#[pymodinit]` uses the function name as module name, unless the name is overrriden with `#[pymodinit(name)]`
* The guide is now properly versioned.
* A few internal macros became part of the public api ([#155](https://github.com/PyO3/pyo3/pull/155), [#186](https://github.com/PyO3/pyo3/pull/186))
* Always clone in getters. This allows using the get-annotation on all Clone-Types

View File

@ -79,8 +79,8 @@ use pyo3::pymodinit;
// Add bindings to the generated python module
// N.B: names: "librust2py" must be the name of the `.so` or `.pyd` file
/// This module is implemented in Rust.
#[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pymodinit]
fn rust2py(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "sum_as_string")]
// ``#[pyfn()]` converts the arguments from Python objects to Rust values

View File

@ -10,5 +10,5 @@ rayon = "0.8"
path = "../../"
[lib]
name = "word_count"
name = "word_count_cls"
crate-type = ["cdylib"]

View File

@ -44,7 +44,7 @@ setup(
'Operating System :: MacOS :: MacOS X',
],
packages=['word_count_cls'],
rust_extensions=[RustExtension('word_count_cls._word_count', 'Cargo.toml')],
rust_extensions=[RustExtension('word_count_cls.word_count_cls', 'Cargo.toml')],
install_requires=install_requires,
tests_require=tests_require,
setup_requires=setup_requires,

View File

@ -79,8 +79,8 @@ fn wc_parallel(lines: &str, search: &str) -> i32 {
lines.par_lines().map(|line| wc_line(line, search)).sum()
}
#[pymodinit(_word_count)]
fn init_mod(_py: Python, m: &PyModule) -> PyResult<()> {
#[pymodinit]
fn word_count(_py: Python, m: &PyModule) -> PyResult<()> {
m.add_class::<WordCounter>()?;
Ok(())

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from ._word_count import WordCounter
from .word_count_cls import WordCounter
__all__ = ['WordCounter', 'search_py']

View File

@ -44,7 +44,7 @@ setup(
'Operating System :: MacOS :: MacOS X',
],
packages=['word_count'],
rust_extensions=[RustExtension('word_count._word_count', 'Cargo.toml')],
rust_extensions=[RustExtension('word_count.word_count', 'Cargo.toml')],
install_requires=install_requires,
tests_require=tests_require,
setup_requires=setup_requires,

View File

@ -50,8 +50,8 @@ fn wc_parallel(lines: &str, search: &str) -> i32 {
lines.par_lines().map(|line| wc_line(line, search)).sum()
}
#[pymodinit(_word_count)]
fn init_mod(_py: Python, m: &PyModule) -> PyResult<()> {
#[pymodinit]
fn word_count(_py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "search")]
fn search(py: Python, path: String, search: String) -> PyResult<i32> {
let mut file = File::open(path)?;

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from ._word_count import search, search_sequential
from .word_count import search, search_sequential
__all__ = ['search', 'search_sequential', 'search_py']

View File

@ -12,8 +12,8 @@ extern crate pyo3;
use pyo3::prelude::*;
use pyo3::pymodinit;
#[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pymodinit]
fn rust2py(py: Python, m: &PyModule) -> PyResult<()> {
// Note that the `#[pyfn()]` annotation automatically converts the arguments from
// Python objects to Rust values; and the Rust return value back into a Python object.
@ -47,8 +47,8 @@ fn double(x: usize) -> usize {
x * 2
}
#[pymodinit(module_with_functions)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pymodinit]
fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
m.add_function(wrap_function!(double)).unwrap();
Ok(())

View File

@ -13,8 +13,8 @@ use pyo3::pymodinit;
// add bindings to the generated python module
// N.B: names: "librust2py" must be the name of the `.so` or `.pyd` file
/// This module is implemented in Rust.
#[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pymodinit]
fn rust2py(py: Python, m: &PyModule) -> PyResult<()> {
// pyo3 aware function. All of our python interface could be declared in a separate module.
// Note that the `#[pyfn()]` annotation automatically converts the arguments from

View File

@ -69,8 +69,8 @@ use pyo3::pymodinit;
// Add bindings to the generated python module
// N.B: names: "librust2py" must be the name of the `.so` or `.pyd` file
/// This module is implemented in Rust.
#[pymodinit(rust2py)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pymodinit]
fn rust2py(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "sum_as_string")]
// ``#[pyfn()]` converts the arguments from Python objects to Rust values

View File

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

View File

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

View File

@ -26,8 +26,12 @@ pub fn mod2init(
// Parse the token stream into a syntax tree
let mut ast: syn::ItemFn = syn::parse(input).expect("#[pymodinit] must be used on a function");
// Extract the mod name
let modname: syn::Ident = syn::parse(attr).expect("could not parse module name");
let modname: syn::Ident;
if attr.is_empty() {
modname = ast.ident.clone();
} else {
modname = syn::parse(attr).expect("could not parse module name");
}
// Process the functions within the module
module::process_functions_in_module(&mut ast);
@ -49,8 +53,12 @@ pub fn mod3init(
// Parse the token stream into a syntax tree
let mut ast: syn::ItemFn = syn::parse(input).expect("#[pymodinit] must be used on a `fn` block");
// Extract the mod name
let modname: syn::Ident = syn::parse(attr).expect("could not parse module name");
let modname: syn::Ident;
if attr.is_empty() {
modname = ast.ident.clone();
} else {
modname = syn::parse(attr).expect("could not parse module name");
}
// Process the functions within the module
module::process_functions_in_module(&mut ast);

View File

@ -53,15 +53,9 @@
//! # Python extension
//!
//! To allow Python to load the rust code as a Python extension
//! module, you need provide initialization function and annotate it with `#[pymodinit(name)]`.
//! `pymodinit` expands to an `extern "C"` function.
//!
//! Macro syntax: `#[pymodinit(name)]`
//!
//! 1. `name`: The module name as a Rust identifier
//! 2. Decorate init function `Fn(Python, &PyModule) -> PyResult<()>`.
//! This function will be called when the module is imported, and is responsible
//! for adding the module's members.
//! module, you need an initialization function with `Fn(Python, &PyModule) -> PyResult<()>`
//! that is annotates with `#[pymodinit]`. By default the function name will become the module name,
//! but you can override that with `#[pymodinit(name)]`.
//!
//! To creates a Python callable object that invokes a Rust function, specify rust
//! function and decorate it with `#[pyfn()]` attribute. `pyfn()` accepts three parameters.
@ -84,8 +78,8 @@
//! // Add bindings to the generated python module
//! // N.B: names: "librust2py" must be the name of the `.so` or `.pyd` file
//! /// This module is implemented in Rust.
//! #[pymodinit(rust2py)]
//! fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
//! #[pymodinit]
//! fn rust2py(py: Python, m: &PyModule) -> PyResult<()> {
//!
//! #[pyfn(m, "sum_as_string")]
//! // ``#[pyfn()]` converts the arguments from Python objects to Rust values

View File

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

View File

@ -19,8 +19,8 @@ fn double(x: usize) -> usize {
}
/// This module is implemented in Rust.
#[pymodinit(module_with_functions)]
fn init_mod(py: Python, m: &PyModule) -> PyResult<()> {
#[pymodinit]
fn module_with_functions(py: Python, m: &PyModule) -> PyResult<()> {
#[pyfn(m, "sum_as_string")]
fn sum_as_string_py(_py: Python, a: i64, b: i64) -> PyResult<String> {
let out = sum_as_string(a, b);
@ -64,6 +64,25 @@ fn test_module_with_functions() {
run("assert module_with_functions.also_double(3) == 6");
}
#[pymodinit(other_name)]
fn some_name(_: Python, _: &PyModule) -> PyResult<()> {
Ok(())
}
#[test]
#[cfg(Py_3)]
fn test_module_renaming() {
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();
py.run("assert different_name.__name__ == 'other_name'", None, Some(d)).unwrap();
}
#[test]
#[cfg(Py_3)]
fn test_module_from_code() {