diff --git a/.travis.yml b/.travis.yml index 0518b2e9..e06ef78b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,6 +40,8 @@ after_success: if [[ "$TRAVIS_OS_NAME" == "linux" && "$TRAVIS_PULL_REQUEST" = "false" && "$TRAVIS_BRANCH" == "master" && "$TRAVIS_PYTHON_VERSION" == "3.6" ]]; then cargo doc --no-deps && echo "" > target/doc/index.html && + cargo install mdbook && + cd guide && mdbook build -d ../target/doc/guide && cd .. && git clone https://github.com/davisp/ghp-import.git && ./ghp-import/ghp_import.py -n -p -f -m "Documentation upload" -r https://"$GH_TOKEN"@github.com/"$TRAVIS_REPO_SLUG.git" target/doc && echo "Uploaded documentation" diff --git a/guide/.gitignore b/guide/.gitignore new file mode 100644 index 00000000..7585238e --- /dev/null +++ b/guide/.gitignore @@ -0,0 +1 @@ +book diff --git a/guide/book.toml b/guide/book.toml new file mode 100644 index 00000000..4f0c4ac3 --- /dev/null +++ b/guide/book.toml @@ -0,0 +1,3 @@ +title = "PyO3 user guide" +description = "PyO3 user guide" +author = "PyO3 Project and Contributors" diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md new file mode 100644 index 00000000..f3100a60 --- /dev/null +++ b/guide/src/SUMMARY.md @@ -0,0 +1,13 @@ +# Summary + +[Overview](./overview.md) + +[Getting Started](./getting_started.md) + +- [Type Conversions](./conversions.md) +- [Python Exception](./exception.md) +- [Python Module](./module.md) +- [Python Function](./function.md) +- [Python Class](./class.md) +- [Parallelism](./parallelism.md) +- [Distribution](./distribution.md) diff --git a/guide/src/class.md b/guide/src/class.md new file mode 100644 index 00000000..97dedb35 --- /dev/null +++ b/guide/src/class.md @@ -0,0 +1,3 @@ +# Python Class + +TODO diff --git a/guide/src/conversions.md b/guide/src/conversions.md new file mode 100644 index 00000000..d39c56a2 --- /dev/null +++ b/guide/src/conversions.md @@ -0,0 +1,17 @@ +# Type Conversions + +`PyO3` provides some handy traits to convert between Python types and Rust types. + +## `ToPyObject` and `IntoPyObject` trait + +`ToPyObject` trait is a conversion trait that allows various objects to be converted into `PyObject`. + +TODO + +## `IntoPyTuple` trait + +TODO + +## `FromPyObject` and `RefFromPyObject` trait + +TODO diff --git a/guide/src/distribution.md b/guide/src/distribution.md new file mode 100644 index 00000000..7034ef97 --- /dev/null +++ b/guide/src/distribution.md @@ -0,0 +1,13 @@ +# Distribution + +## `setuptools-rust` integration + +TODO + +## Source distribution + +TODO + +## Binary wheel distribution + +TODO diff --git a/guide/src/exception.md b/guide/src/exception.md new file mode 100644 index 00000000..d6e653c4 --- /dev/null +++ b/guide/src/exception.md @@ -0,0 +1,41 @@ +# Python Exception + +## Define a new exception + +You can use the `py_exception!` macro to define a new excetpion type: + +```rust +py_exception!(module, MyError); +``` + +* `module` is the name of the containing module. +* `MyError` is the name of the new exception type. + +For example: + +```rust +#[macro_use] extern crate pyo3; + +use pyo3::{Python, PyDict}; + +py_exception!(mymodule, CustomError); + +fn main() { +let gil = Python::acquire_gil(); + let py = gil.python(); + let ctx = PyDict::new(py); + + ctx.set_item(py, "CustomError", py.get_type::()).unwrap(); + + py.run("assert str(CustomError) == \"\"", None, Some(&ctx)).unwrap(); + py.run("assert CustomError('oops').args == ('oops',)", None, Some(&ctx)).unwrap(); +} +``` + +## Raise an exception + +TODO + +## Check exception type + +TODO diff --git a/guide/src/function.md b/guide/src/function.md new file mode 100644 index 00000000..14918c99 --- /dev/null +++ b/guide/src/function.md @@ -0,0 +1,3 @@ +# Python Function + +TODO diff --git a/guide/src/getting_started.md b/guide/src/getting_started.md new file mode 100644 index 00000000..832e8e53 --- /dev/null +++ b/guide/src/getting_started.md @@ -0,0 +1,17 @@ +# Getting Started + +In this tutorial, we will walk through the steps of building a simple Python extension called `TODO`. + +## Install Rust + +Before we begin, we need to install Rust using the [rustup](https://www.rustup.rs/) installer: + +```bash +curl https://sh.rustup.rs -sSf | sh +``` + +If you already have rustup installed, run this command to ensure you have the latest version of Rust: + +```bash +rustup update +``` diff --git a/guide/src/module.md b/guide/src/module.md new file mode 100644 index 00000000..15faaa91 --- /dev/null +++ b/guide/src/module.md @@ -0,0 +1,3 @@ +# Python Module + +TODO diff --git a/guide/src/overview.md b/guide/src/overview.md new file mode 100644 index 00000000..d9607376 --- /dev/null +++ b/guide/src/overview.md @@ -0,0 +1,104 @@ +# Overview + +[![Build Status](https://travis-ci.org/PyO3/PyO3.svg?branch=master)](https://travis-ci.org/PyO3/PyO3) +[![Latest Version](https://img.shields.io/crates/v/pyo3.svg)](https://crates.io/crates/pyo3) +[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](http://pyo3.github.io/PyO3/pyo3/) + +PyO3 is a [Rust](http://www.rust-lang.org/) bindings for the [Python](https://www.python.org/) interpreter. + +Supported Python versions: + +* Python2.7, Python 3.5 and up + +Supported Rust version: + +* Rust 1.17.0-nightly or later +* On Windows, we require rustc 1.17.0-nightly + +## Usage + +To use `pyo3`, add this to your `Cargo.toml`: + +```toml +[dependencies] +pyo3 = "0.1" +``` + +Example program displaying the value of `sys.version`: + +```rust +extern crate pyo3; + +use pyo3::{Python, PyDict, PyResult}; + +fn main() { + let gil = Python::acquire_gil(); + hello(gil.python()).unwrap(); +} + +fn hello(py: Python) -> PyResult<()> { + let sys = py.import("sys")?; + let version: String = sys.get("version")?.extract(py)?; + + let locals = PyDict::new(py); + locals.set_item("os", py.import("os")?)?; + let user: String = py.eval("os.getenv('USER') or os.getenv('USERNAME')", None, Some(&locals))?.extract(py)?; + + println!("Hello {}, I'm Python {}", user, version); + Ok(()) +} +``` + +Example library with python bindings: + +The following two files will build with `cargo build`, and will generate a python-compatible library. +On Mac OS, you will need to rename the output from \*.dylib to \*.so. +On Windows, you will need to rename the output from \*.dll to \*.pyd. + +**`Cargo.toml`:** + +```toml +[lib] +name = "rust2py" +crate-type = ["cdylib"] + +[dependencies.pyo3] +version = "0.1" +features = ["extension-module"] +``` + +**`src/lib.rs`** + +```rust +#![feature(proc_macro)] + +extern crate pyo3; +use pyo3::{py, PyResult, Python, PyModule}; + +// add bindings to the generated python module +// N.B: names: "librust2py" must be the name of the `.so` or `.pyd` file +#[py::modinit(rust2py)] +fn init_mod(py: Python, m: &PyModule) -> PyResult<()> { + m.add(py, "__doc__", "This module is implemented in Rust.")?; + + #[pyfn(m, "sum_as_string")] + // 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 + // Python objects to Rust values; and the Rust return value back into a Python object. + fn sum_as_string_py(_: Python, a:i64, b:i64) -> PyResult { + let out = sum_as_string(a, b); + Ok(out) + } + + Ok(()) +} + +// logic implemented as a normal rust function +fn sum_as_string(a:i64, b:i64) -> String { + format!("{}", a + b).to_string() +} + +# fn main() {} +``` + +For `setup.py` integration, see [setuptools-rust](https://github.com/PyO3/setuptools-rust) diff --git a/guide/src/parallelism.md b/guide/src/parallelism.md new file mode 100644 index 00000000..ee3df3b4 --- /dev/null +++ b/guide/src/parallelism.md @@ -0,0 +1,3 @@ +# Parallelism + +TODO