Skip to content

Commit

Permalink
macros: support #[pyo3(name = "...")]
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Apr 19, 2021
1 parent d153bca commit 3a4e8d0
Show file tree
Hide file tree
Showing 31 changed files with 1,018 additions and 688 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Add FFI definition `Py_IS_TYPE`. [#1429](https://github.com/PyO3/pyo3/pull/1429)
- Add FFI definition `_Py_InitializeMain`. [#1473](https://github.com/PyO3/pyo3/pull/1473)
- Add tuple and unit struct support for `#[pyclass]` macro. [#1504](https://github.com/PyO3/pyo3/pull/1504)
- Add `#[pyo3(name = "...")]` syntax for setting Python names. [#1567](https://github.com/PyO3/pyo3/pull/1567)

### Changed
- Change `PyTimeAcces::get_fold()` to return a `bool` instead of a `u8`. [#1397](https://github.com/PyO3/pyo3/pull/1397)
Expand All @@ -29,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Deprecate `PyModule` methods `call`, `call0`, `call1` and `get`. [#1492](https://github.com/PyO3/pyo3/pull/1492)
- Add length information to `PyBufferError`s raised from `PyBuffer::copy_to_slice` and `PyBuffer::copy_from_slice`. [#1534](https://github.com/PyO3/pyo3/pull/1534)
- Automatically provide `-undefined` and `dynamic_lookup` linker arguments on macOS with `extension-module` feature. [#1539](https://github.com/PyO3/pyo3/pull/1539)
- Deprecate `#[name = "..."]` attributes in favor of `#[pyo3(name = "...")]`. [#1567](https://github.com/PyO3/pyo3/pull/1567)

### Removed
- Remove deprecated exception names `BaseException` etc. [#1426](https://github.com/PyO3/pyo3/pull/1426)
Expand Down
2 changes: 1 addition & 1 deletion guide/src/trait_bounds.md
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ pub fn solve<T: Model>(model: &mut T) {
}

#[pyfunction]
#[name = "solve"]
#[pyo3(name = "solve")]
pub fn solve_wrapper(model: &mut UserModel) {
solve(model);
}
Expand Down
96 changes: 96 additions & 0 deletions pyo3-macros-backend/src/attributes.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
spanned::Spanned,
token::Comma,
Attribute, ExprPath, Ident, LitStr, Result, Token,
};

pub mod kw {
syn::custom_keyword!(annotation);
syn::custom_keyword!(attribute);
syn::custom_keyword!(from_py_with);
syn::custom_keyword!(item);
syn::custom_keyword!(pass_module);
syn::custom_keyword!(name);
syn::custom_keyword!(signature);
syn::custom_keyword!(transparent);
}

#[derive(Clone, Debug, PartialEq)]
pub struct FromPyWithAttribute(pub ExprPath);

impl Parse for FromPyWithAttribute {
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)
}
}

#[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)
}
}

pub fn get_pyo3_attribute<T: Parse>(attr: &syn::Attribute) -> Result<Option<Punctuated<T, Comma>>> {
if attribute_ident_is(attr, "pyo3") {
attr.parse_args_with(Punctuated::parse_terminated).map(Some)
} else {
Ok(None)
}
}

pub fn attribute_ident_is(attr: &syn::Attribute, name: &str) -> bool {
if let Some(path_segment) = attr.path.segments.last() {
attr.path.segments.len() == 1 && path_segment.ident == name
} else {
false
}
}

/// Takes attributes from an attribute vector.
///
/// For each attribute in `attrs`, `extractor` is called. If `extractor` returns `Ok(true)`, then
/// the attribute will be removed from the vector.
///
/// This is similar to `Vec::retain` except the closure is fallible and the condition is reversed.
/// (In `retain`, returning `true` keeps the element, here it removes it.)
pub fn take_attributes(
attrs: &mut Vec<Attribute>,
mut extractor: impl FnMut(&Attribute) -> Result<bool>,
) -> Result<()> {
*attrs = attrs
.drain(..)
.filter_map(|attr| {
extractor(&attr)
.map(move |attribute_handled| if attribute_handled { None } else { Some(attr) })
.transpose()
})
.collect::<Result<_>>()?;
Ok(())
}

pub fn get_deprecated_name_attribute(attr: &syn::Attribute) -> syn::Result<Option<NameAttribute>> {
match attr.parse_meta() {
Ok(syn::Meta::NameValue(syn::MetaNameValue {
path,
lit: syn::Lit::Str(s),
..
})) if path.is_ident("name") => {
let mut ident: syn::Ident = s.parse()?;
// This span is the whole attribute span, which is nicer for reporting errors.
ident.set_span(attr.span());
Ok(Some(NameAttribute(ident)))
}
_ => Ok(None),
}
}
22 changes: 0 additions & 22 deletions pyo3-macros-backend/src/attrs.rs

This file was deleted.

Loading

0 comments on commit 3a4e8d0

Please sign in to comment.