Skip to content

Commit

Permalink
Merge branch 'main' into export-conf
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashley Anderson committed Mar 22, 2022
2 parents 4a62a62 + 87c79c0 commit 272d2bc
Show file tree
Hide file tree
Showing 44 changed files with 985 additions and 561 deletions.
8 changes: 1 addition & 7 deletions .cargo/config
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
[alias]
xtask = "run --package xtask --"
pyo3_doc = "doc --lib --no-default-features --features=full --no-deps --workspace --open --exclude pyo3-macros --exclude pyo3-macros-backend"
pyo3_doc_scrape = "doc --lib --no-default-features --features=full --no-deps --workspace --open --exclude pyo3-macros --exclude pyo3-macros-backend -Z unstable-options -Z rustdoc-scrape-examples=examples"
pyo3_doc_internal = "doc --lib --no-default-features --features=full --no-deps --workspace --open --document-private-items -Z unstable-options -Z rustdoc-scrape-examples=examples"

[build]
rustdocflags = ["--cfg", "docsrs"]

[target.'cfg(feature = "cargo-clippy")']
rustflags = [
Expand All @@ -21,4 +15,4 @@ rustflags = [
"-Dclippy::todo",
"-Dclippy::unnecessary_wraps",
"-Dclippy::useless_transmute",
]
]
9 changes: 3 additions & 6 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ Please consider adding the following to your pull request:
- docs to all new functions and / or detail in the guide
- tests for all new or changed functions

Be aware the CI pipeline will check your pull request for the following. This is done using `nox` (you can install with `pip install nox`):
- Rust tests (`cargo test` or `nox -s test-rust`)
- Examples (`nox -s test-py`)
- Rust lints (`nox -s clippy`)
- Rust formatting (`nox -s fmt-rust`)
- Python formatting (`nox -s fmt-py`)
PyO3's CI pipeline will check your pull request. To run its tests
locally, you can run ```cargo xtask ci```. See its documentation
[here](https://github.com/PyO3/pyo3/tree/main/xtask#readme).
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,13 @@ jobs:
- if: matrix.msrv == 'MSRV'
name: Prepare minimal package versions (MSRV only)
run: |
set -x
cargo update -p indexmap --precise 1.6.2
cargo update -p hashbrown:0.12.0 --precise 0.9.1
PROJECTS=("." "examples/decorator" "examples/maturin-starter" "examples/setuptools-rust-starter" "examples/word-count")
for PROJ in ${PROJECTS[@]}; do
cargo update --manifest-path "$PROJ/Cargo.toml" -p parking_lot --precise 0.11.0
done
- name: Build docs
run: cargo doc --no-deps --no-default-features --features "full ${{ matrix.extra_features }}"
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/guide.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
mkdir target
mkdir -p gh-pages-build/internal
echo "<div class='internal-banner' style='position:fixed; z-index: 99999; color:red;border:3px solid red;margin-left: auto; margin-right: auto; width: 430px;left:0;right: 0;'><div style='display: flex; align-items: center; justify-content: center;'> ⚠️ Internal Docs ⚠️ Not Public API 👉 <a href='https://pyo3.rs/main/doc/pyo3/index.html' style='color:red;text-decoration:underline;'>Official Docs Here</a></div></div>" > target/banner.html
cargo +nightly pyo3_doc_internal
cargo xtask doc --internal
cp -r target/doc gh-pages-build/internal
env:
RUSTDOCFLAGS: "--cfg docsrs --Z unstable-options --document-hidden-items --html-before-content target/banner.html"
Expand All @@ -71,7 +71,7 @@ jobs:
# This adds the docs to gh-pages-build/doc
- name: Build the doc
run: |
cargo +nightly pyo3_doc_scrape
cargo xtask doc
cp -r target/doc gh-pages-build/doc
echo "<meta http-equiv=refresh content=0;url=pyo3/index.html>" > gh-pages-build/doc/index.html
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ guide/book/
extensions/stamps/
pip-wheel-metadata
valgrind-python.supp
*.pyd
14 changes: 13 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow dependent crates to access config values from `pyo3-build-config` via cargo link dep env vars. [#2092](https://github.com/PyO3/pyo3/pull/2092)
- Added methods on `InterpreterConfig` to run Python scripts using the configured executable. [#2092](https://github.com/PyO3/pyo3/pull/2092)

### Changed

- Allow `#[pyo3(crate = "...", text_signature = "...")]` options to be used directly in `#[pyclass(crate = "...", text_signature = "...")]`. [#2234](https://github.com/PyO3/pyo3/pull/2234)

### Fixed

- Considered `PYTHONFRAMEWORK` when cross compiling in order that on macos cross compiling against a [Framework bundle](https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html) is considered shared. [#2233](https://github.com/PyO3/pyo3/pull/2233)

- Panic during compilation when `PYO3_CROSS_LIB_DIR` is set for some host/target combinations. [#2232](https://github.com/PyO3/pyo3/pull/2232)
- Correct dependency version for `syn` to require correct minimal patch version 1.0.56. [#2240](https://github.com/PyO3/pyo3/pull/2240)

### Added

- Added `as_bytes` on `Py<PyBytes>`. [#2235](https://github.com/PyO3/pyo3/pull/2235)

### Packaging

- Extend `parking_lot` dependency supported versions to include 0.12. [#2239](https://github.com/PyO3/pyo3/pull/2239)

## [0.16.2] - 2022-03-15

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ edition = "2018"
[dependencies]
cfg-if = "1.0"
libc = "0.2.62"
parking_lot = "0.11.0"
parking_lot = ">= 0.11, < 0.13"

# ffi bindings to the python interpreter, split into a seperate crate so they can be used independently
pyo3-ffi = { path = "pyo3-ffi", version = "=0.16.2" }
Expand Down
6 changes: 5 additions & 1 deletion Contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ There are some specific areas of focus where help is currently needed for the do
- Not all APIs had docs or examples when they were made. The goal is to have documentation on all PyO3 APIs ([#306](https://github.com/PyO3/pyo3/issues/306)). If you see an API lacking a doc, please write one and open a PR!

You can build the docs (including all features) with
```cargo +nightly pyo3_doc_scrape```
```cargo xtask doc --open```

#### Doctests

Expand Down Expand Up @@ -87,6 +87,10 @@ Tests run with all supported Python versions with the latest stable Rust compile

If you are adding a new feature, you should add it to the `full` feature in our *Cargo.toml** so that it is tested in CI.

You can run these tests yourself with
```cargo xtask ci```
See [it's documentation](https://github.com/PyO3/pyo3/tree/main/xtask#readme)for more commands you can run.

## Python and Rust version support policy

PyO3 aims to keep sufficient compatibility to make packaging Python extensions built with PyO3 feasible on most common package managers.
Expand Down
31 changes: 12 additions & 19 deletions guide/src/class.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,22 +195,16 @@ Python::with_gil(|py|{

## Customizing the class

The `#[pyclass]` macro accepts the following parameters:

* `name="XXX"` - Set the class name shown in Python code. By default, the struct name is used as the class name.
* `freelist=XXX` - The `freelist` parameter adds support of free allocation list to custom class.
The performance improvement applies to types that are often created and deleted in a row,
so that they can benefit from a freelist. `XXX` is a number of items for the free list.
* `gc` - Classes with the `gc` parameter participate in Python garbage collection.
If a custom class contains references to other Python objects that can be collected, the [`PyGCProtocol`]({{#PYO3_DOCS_URL}}/pyo3/class/gc/trait.PyGCProtocol.html) trait has to be implemented.
* `weakref` - Adds support for Python weak references.
* `extends=BaseType` - Use a custom base class. The base `BaseType` must implement `PyTypeInfo`. `enum` pyclasses can't use a custom base class.
* `subclass` - Allows Python classes to inherit from this class. `enum` pyclasses can't be inherited from.
* `dict` - Adds `__dict__` support, so that the instances of this type have a dictionary containing arbitrary instance variables.
* `unsendable` - Making it safe to expose `!Send` structs to Python, where all object can be accessed
by multiple threads. A class marked with `unsendable` panics when accessed by another thread.
* `module="XXX"` - Set the name of the module the class will be shown as defined in. If not given, the class
will be a virtual member of the `builtins` module.
{{#include ../../pyo3-macros/docs/pyclass_parameters.md}}

[params-1]: {{#PYO3_DOCS_URL}}/pyo3/prelude/struct.PyAny.html
[params-2]: https://en.wikipedia.org/wiki/Free_list
[params-3]: https://doc.rust-lang.org/stable/std/marker/trait.Send.html
[params-4]: https://doc.rust-lang.org/stable/std/rc/struct.Rc.html
[params-5]: https://doc.rust-lang.org/stable/std/sync/struct.Rc.html
[params-6]: https://docs.python.org/3/library/weakref.html

These parameters are covered in various sections of this guide.

### Return type

Expand Down Expand Up @@ -716,16 +710,15 @@ num=-1

## Making class method signatures available to Python

The [`#[pyo3(text_signature = "...")]`](./function.md#text_signature) option for `#[pyfunction]` also works for classes and methods:
The [`text_signature = "..."`](./function.md#text_signature) option for `#[pyfunction]` also works for classes and methods:

```rust
# #![allow(dead_code)]
use pyo3::prelude::*;
use pyo3::types::PyType;

// it works even if the item is not documented:
#[pyclass]
#[pyo3(text_signature = "(c, d, /)")]
#[pyclass(text_signature = "(c, d, /)")]
struct MyClass {}

#[pymethods]
Expand Down
2 changes: 1 addition & 1 deletion guide/src/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ For a detailed list of all changes, see the [CHANGELOG](changelog.md).

PyO3 0.16 has increased minimum Rust version to 1.48 and minimum Python version to 3.7. This enables use of newer language features (enabling some of the other additions in 0.16) and simplifies maintenance of the project.

### `#[pyproto]` has been deprecated
### `#[pyproto]` has been deprecated

In PyO3 0.15, the `#[pymethods]` attribute macro gained support for implementing "magic methods" such as `__str__` (aka "dunder" methods). This implementation was not quite finalized at the time, with a few edge cases to be decided upon. The existing `#[pyproto]` attribute macro was left untouched, because it covered these edge cases.

Expand Down
2 changes: 1 addition & 1 deletion pyo3-macros-backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ proc-macro2 = { version = "1", default-features = false }
pyo3-build-config = { path = "../pyo3-build-config", version = "0.16.2", features = ["resolve-config"] }

[dependencies.syn]
version = "1"
version = "1.0.56"
default-features = false
features = ["derive", "parsing", "printing", "clone-impls", "full", "extra-traits"]

Expand Down
98 changes: 64 additions & 34 deletions pyo3-macros-backend/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -1,78 +1,108 @@
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
token::Comma,
Attribute, ExprPath, Ident, LitStr, Path, Result, Token,
Attribute, Expr, ExprPath, Ident, LitStr, Path, Result, Token,
};

pub mod kw {
syn::custom_keyword!(annotation);
syn::custom_keyword!(attribute);
syn::custom_keyword!(dict);
syn::custom_keyword!(extends);
syn::custom_keyword!(freelist);
syn::custom_keyword!(from_py_with);
syn::custom_keyword!(gc);
syn::custom_keyword!(get);
syn::custom_keyword!(item);
syn::custom_keyword!(pass_module);
syn::custom_keyword!(module);
syn::custom_keyword!(name);
syn::custom_keyword!(pass_module);
syn::custom_keyword!(set);
syn::custom_keyword!(signature);
syn::custom_keyword!(subclass);
syn::custom_keyword!(text_signature);
syn::custom_keyword!(transparent);
syn::custom_keyword!(unsendable);
syn::custom_keyword!(weakref);
}

#[derive(Clone, Debug)]
pub struct KeywordAttribute<K, V> {
pub kw: K,
pub value: V,
}

/// A helper type which parses the inner type via a literal string
/// e.g. LitStrValue<Path> -> parses "some::path" in quotes.
#[derive(Clone, Debug, PartialEq)]
pub struct FromPyWithAttribute(pub ExprPath);
pub struct LitStrValue<T>(pub T);

impl Parse for FromPyWithAttribute {
impl<T: Parse> Parse for LitStrValue<T> {
fn parse(input: ParseStream) -> Result<Self> {
let _: kw::from_py_with = input.parse()?;
let _: Token![=] = input.parse()?;
let string_literal: LitStr = input.parse()?;
string_literal.parse().map(FromPyWithAttribute)
let lit_str: LitStr = input.parse()?;
lit_str.parse().map(LitStrValue)
}
}

#[derive(Clone, Debug, PartialEq)]
pub struct NameAttribute(pub Ident);

impl Parse for NameAttribute {
fn parse(input: ParseStream) -> Result<Self> {
let _: kw::name = input.parse()?;
let _: Token![=] = input.parse()?;
let string_literal: LitStr = input.parse()?;
string_literal.parse().map(NameAttribute)
impl<T: ToTokens> ToTokens for LitStrValue<T> {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.0.to_tokens(tokens)
}
}

/// For specifying the path to the pyo3 crate.
/// A helper type which parses a name via a literal string
#[derive(Clone, Debug, PartialEq)]
pub struct CrateAttribute(pub Path);
pub struct NameLitStr(pub Ident);

impl Parse for CrateAttribute {
impl Parse for NameLitStr {
fn parse(input: ParseStream) -> Result<Self> {
let _: Token![crate] = input.parse()?;
let _: Token![=] = input.parse()?;
let string_literal: LitStr = input.parse()?;
string_literal.parse().map(CrateAttribute)
if let Ok(ident) = string_literal.parse() {
Ok(NameLitStr(ident))
} else {
bail_spanned!(string_literal.span() => "expected a single identifier in double quotes")
}
}
}

#[derive(Clone, Debug, PartialEq)]
pub struct TextSignatureAttribute {
pub kw: kw::text_signature,
pub eq_token: Token![=],
pub lit: LitStr,
impl ToTokens for NameLitStr {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.0.to_tokens(tokens)
}
}

impl Parse for TextSignatureAttribute {
pub type ExtendsAttribute = KeywordAttribute<kw::extends, Path>;
pub type FreelistAttribute = KeywordAttribute<kw::freelist, Box<Expr>>;
pub type ModuleAttribute = KeywordAttribute<kw::module, LitStr>;
pub type NameAttribute = KeywordAttribute<kw::name, NameLitStr>;
pub type TextSignatureAttribute = KeywordAttribute<kw::text_signature, LitStr>;

impl<K: Parse + std::fmt::Debug, V: Parse> Parse for KeywordAttribute<K, V> {
fn parse(input: ParseStream) -> Result<Self> {
Ok(TextSignatureAttribute {
kw: input.parse()?,
eq_token: input.parse()?,
lit: input.parse()?,
})
let kw: K = input.parse()?;
let _: Token![=] = input.parse()?;
let value = input.parse()?;
Ok(KeywordAttribute { kw, value })
}
}

impl<K: ToTokens, V: ToTokens> ToTokens for KeywordAttribute<K, V> {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.kw.to_tokens(tokens);
Token![=](self.kw.span()).to_tokens(tokens);
self.value.to_tokens(tokens);
}
}

pub type FromPyWithAttribute = KeywordAttribute<kw::from_py_with, LitStrValue<ExprPath>>;

/// For specifying the path to the pyo3 crate.
pub type CrateAttribute = KeywordAttribute<Token![crate], LitStrValue<Path>>;

pub fn get_pyo3_options<T: Parse>(attr: &syn::Attribute) -> Result<Option<Punctuated<T, Comma>>> {
if is_attribute_ident(attr, "pyo3") {
attr.parse_args_with(Punctuated::parse_terminated).map(Some)
Expand Down
10 changes: 7 additions & 3 deletions pyo3-macros-backend/src/frompyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,9 @@ impl<'a> Container<'a> {
None => quote!(
obj.get_item(#index)?.extract()
),
Some(FromPyWithAttribute(expr_path)) => quote! (
Some(FromPyWithAttribute {
value: expr_path, ..
}) => quote! (
#expr_path(obj.get_item(#index)?)
),
};
Expand Down Expand Up @@ -308,7 +310,9 @@ impl<'a> Container<'a> {
new_err.set_cause(py, ::std::option::Option::Some(inner));
new_err
})?),
Some(FromPyWithAttribute(expr_path)) => quote! (
Some(FromPyWithAttribute {
value: expr_path, ..
}) => quote! (
#expr_path(#get_field).map_err(|inner| {
let py = _pyo3::PyNativeType::py(obj);
let new_err = _pyo3::exceptions::PyTypeError::new_err(#conversion_error_msg);
Expand Down Expand Up @@ -388,7 +392,7 @@ impl ContainerOptions {
ContainerPyO3Attribute::Crate(path) => {
ensure_spanned!(
options.krate.is_none(),
path.0.span() => "`crate` may only be provided once"
path.span() => "`crate` may only be provided once"
);
options.krate = Some(path);
}
Expand Down
4 changes: 2 additions & 2 deletions pyo3-macros-backend/src/konst.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub struct ConstSpec {
impl ConstSpec {
pub fn python_name(&self) -> Cow<Ident> {
if let Some(name) = &self.attributes.name {
Cow::Borrowed(&name.0)
Cow::Borrowed(&name.value.0)
} else {
Cow::Owned(self.rust_ident.unraw())
}
Expand Down Expand Up @@ -89,7 +89,7 @@ impl ConstAttributes {
fn set_name(&mut self, name: NameAttribute) -> Result<()> {
ensure_spanned!(
self.name.is_none(),
name.0.span() => "`name` may only be specified once"
name.span() => "`name` may only be specified once"
);
self.name = Some(name);
Ok(())
Expand Down

0 comments on commit 272d2bc

Please sign in to comment.