commit
519fd6188a
|
@ -58,7 +58,7 @@ jobs:
|
|||
platform: { os: "windows-latest" }
|
||||
include:
|
||||
# Test minimal supported Rust version
|
||||
- rust: 1.39.0
|
||||
- rust: 1.45.0
|
||||
python-version: 3.9
|
||||
platform: { os: "ubuntu-latest", python-architecture: "x64", rust-target: "x86_64-unknown-linux-gnu" }
|
||||
msrv: "MSRV"
|
||||
|
|
|
@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
## [Unreleased]
|
||||
### Packaging
|
||||
- Drop support for Python 3.5 (as it is now end-of-life). [#1250](https://github.com/PyO3/pyo3/pull/1250)
|
||||
- Bump minimum supported Rust version to 1.45. [#1272](https://github.com/PyO3/pyo3/pull/1272)
|
||||
- Bump indoc dependency to 1.0. [#1272](https://github.com/PyO3/pyo3/pull/1272)
|
||||
- Bump paste dependency to 1.0. [#1272](https://github.com/PyO3/pyo3/pull/1272)
|
||||
|
||||
### Added
|
||||
- Add support for building for CPython limited API. This required a few minor changes to runtime behaviour of of pyo3 `#[pyclass]` types. See the migration guide for full details. [#1152](https://github.com/PyO3/pyo3/pull/1152)
|
||||
|
|
|
@ -16,13 +16,13 @@ edition = "2018"
|
|||
|
||||
[dependencies]
|
||||
ctor = { version = "0.1", optional = true }
|
||||
indoc = { version = "0.3.4", optional = true }
|
||||
indoc = { version = "1.0.3", optional = true }
|
||||
inventory = { version = "0.1.4", optional = true }
|
||||
libc = "0.2.62"
|
||||
parking_lot = "0.11.0"
|
||||
num-bigint = { version = "0.3", optional = true }
|
||||
num-complex = { version = "0.3", optional = true }
|
||||
paste = { version = "0.1.6", optional = true }
|
||||
paste = { version = "1.0.3", optional = true }
|
||||
pyo3cls = { path = "pyo3cls", version = "=0.12.3", optional = true }
|
||||
unindent = { version = "0.1.4", optional = true }
|
||||
hashbrown = { version = "0.9", optional = true }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[![Actions Status](https://github.com/PyO3/pyo3/workflows/Test/badge.svg)](https://github.com/PyO3/pyo3/actions)
|
||||
[![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)
|
||||
[![minimum rustc 1.39](https://img.shields.io/badge/rustc-1.39+-blue.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
|
||||
[![minimum rustc 1.45](https://img.shields.io/badge/rustc-1.45+-blue.svg)](https://rust-lang.github.io/rfcs/2495-min-rust-version.html)
|
||||
[![Join the dev chat](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/PyO3/Lobby)
|
||||
|
||||
[Rust](http://www.rust-lang.org/) bindings for [Python](https://www.python.org/). This includes running and interacting with Python code from a Rust binary, as well as writing native Python modules.
|
||||
|
@ -18,7 +18,7 @@ A comparison with rust-cpython can be found [in the guide](https://pyo3.rs/maste
|
|||
|
||||
## Usage
|
||||
|
||||
PyO3 supports Python 3.6 and up. The minimum required Rust version is 1.39.0.
|
||||
PyO3 supports Python 3.6 and up. The minimum required Rust version is 1.45.0.
|
||||
|
||||
Building with PyPy is also possible (via cpyext) for Python 3.6, targeted PyPy version is 7.3+.
|
||||
Please refer to the [pypy section in the guide](https://pyo3.rs/master/pypy.html).
|
||||
|
|
14
build.rs
14
build.rs
|
@ -341,16 +341,16 @@ fn find_sysconfigdata(cross: &CrossCompileConfig) -> Result<PathBuf> {
|
|||
/// recursive search for _sysconfigdata, returns all possibilities of sysconfigdata paths
|
||||
fn search_lib_dir(path: impl AsRef<Path>, cross: &CrossCompileConfig) -> Vec<PathBuf> {
|
||||
let mut sysconfig_paths = vec![];
|
||||
let version_pat = if let Some(ref v) = cross.version {
|
||||
let version_pat = if let Some(v) = &cross.version {
|
||||
format!("python{}", v)
|
||||
} else {
|
||||
"python3.".into()
|
||||
};
|
||||
for f in fs::read_dir(path).expect("Path does not exist") {
|
||||
let sysc = match f {
|
||||
Ok(ref f) if starts_with(f, "_sysconfigdata") && ends_with(f, "py") => vec![f.path()],
|
||||
Ok(ref f) if starts_with(f, "build") => search_lib_dir(f.path(), cross),
|
||||
Ok(ref f) if starts_with(f, "lib.") => {
|
||||
let sysc = match &f {
|
||||
Ok(f) if starts_with(f, "_sysconfigdata") && ends_with(f, "py") => vec![f.path()],
|
||||
Ok(f) if starts_with(f, "build") => search_lib_dir(f.path(), cross),
|
||||
Ok(f) if starts_with(f, "lib.") => {
|
||||
let name = f.file_name();
|
||||
// check if right target os
|
||||
if !name.to_string_lossy().contains(if cross.os == "android" {
|
||||
|
@ -366,7 +366,7 @@ fn search_lib_dir(path: impl AsRef<Path>, cross: &CrossCompileConfig) -> Vec<Pat
|
|||
}
|
||||
search_lib_dir(f.path(), cross)
|
||||
}
|
||||
Ok(ref f) if starts_with(f, &version_pat) => search_lib_dir(f.path(), cross),
|
||||
Ok(f) if starts_with(f, &version_pat) => search_lib_dir(f.path(), cross),
|
||||
_ => continue,
|
||||
};
|
||||
sysconfig_paths.extend(sysc);
|
||||
|
@ -569,7 +569,7 @@ fn run_python_script(interpreter: &Path, script: &str) -> Result<String> {
|
|||
);
|
||||
}
|
||||
}
|
||||
Ok(ref ok) if !ok.status.success() => bail!("Python script failed: {}"),
|
||||
Ok(ok) if !ok.status.success() => bail!("Python script failed: {}"),
|
||||
Ok(ok) => Ok(String::from_utf8(ok.stdout)?),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ struct ClassWithGCSupport {
|
|||
#[pyproto]
|
||||
impl PyGCProtocol for ClassWithGCSupport {
|
||||
fn __traverse__(&self, visit: PyVisit) -> Result<(), PyTraverseError> {
|
||||
if let Some(ref obj) = self.obj {
|
||||
if let Some(obj) = &self.obj {
|
||||
visit.call(obj)?
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -137,13 +137,10 @@ impl<'a> Container<'a> {
|
|||
}
|
||||
let style = match (fields, transparent) {
|
||||
(Fields::Unnamed(_), true) => ContainerType::TupleNewtype,
|
||||
(Fields::Unnamed(unnamed), false) => {
|
||||
if unnamed.unnamed.len() == 1 {
|
||||
ContainerType::TupleNewtype
|
||||
} else {
|
||||
ContainerType::Tuple(unnamed.unnamed.len())
|
||||
}
|
||||
}
|
||||
(Fields::Unnamed(unnamed), false) => match unnamed.unnamed.len() {
|
||||
1 => ContainerType::TupleNewtype,
|
||||
len => ContainerType::Tuple(len),
|
||||
},
|
||||
(Fields::Named(named), true) => {
|
||||
let field = named
|
||||
.named
|
||||
|
@ -457,14 +454,15 @@ fn get_pyo3_meta_list(attrs: &[Attribute]) -> Result<MetaList> {
|
|||
}
|
||||
|
||||
fn verify_and_get_lifetime(generics: &syn::Generics) -> Result<Option<&syn::LifetimeDef>> {
|
||||
let lifetimes = generics.lifetimes().collect::<Vec<_>>();
|
||||
if lifetimes.len() > 1 {
|
||||
let mut lifetimes = generics.lifetimes();
|
||||
let lifetime = lifetimes.next();
|
||||
if lifetimes.next().is_some() {
|
||||
return Err(spanned_err(
|
||||
&generics,
|
||||
"FromPyObject can be derived with at most one lifetime parameter.",
|
||||
));
|
||||
}
|
||||
Ok(lifetimes.into_iter().next())
|
||||
Ok(lifetime)
|
||||
}
|
||||
|
||||
/// Derive FromPyObject for enums and structs.
|
||||
|
|
|
@ -100,7 +100,7 @@ pub struct FnSpec<'a> {
|
|||
pub fn get_return_info(output: &syn::ReturnType) -> syn::Type {
|
||||
match output {
|
||||
syn::ReturnType::Default => syn::Type::Infer(syn::parse_quote! {_}),
|
||||
syn::ReturnType::Type(_, ref ty) => *ty.clone(),
|
||||
syn::ReturnType::Type(_, ty) => *ty.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ pub fn parse_method_receiver(arg: &syn::FnArg) -> syn::Result<SelfType> {
|
|||
syn::FnArg::Receiver(recv) => Ok(SelfType::Receiver {
|
||||
mutable: recv.mutability.is_some(),
|
||||
}),
|
||||
syn::FnArg::Typed(syn::PatType { ref ty, .. }) => Ok(SelfType::TryFromPyCell(ty.span())),
|
||||
syn::FnArg::Typed(syn::PatType { ty, .. }) => Ok(SelfType::TryFromPyCell(ty.span())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,14 +198,12 @@ impl<'a> FnSpec<'a> {
|
|||
"Unexpected receiver for method",
|
||||
));
|
||||
}
|
||||
syn::FnArg::Typed(syn::PatType {
|
||||
ref pat, ref ty, ..
|
||||
}) => {
|
||||
let (ident, by_ref, mutability) = match **pat {
|
||||
syn::FnArg::Typed(syn::PatType { pat, ty, .. }) => {
|
||||
let (ident, by_ref, mutability) = match &**pat {
|
||||
syn::Pat::Ident(syn::PatIdent {
|
||||
ref ident,
|
||||
ref by_ref,
|
||||
ref mutability,
|
||||
ident,
|
||||
by_ref,
|
||||
mutability,
|
||||
..
|
||||
}) => (ident, by_ref, mutability),
|
||||
_ => {
|
||||
|
@ -267,7 +265,7 @@ impl<'a> FnSpec<'a> {
|
|||
|
||||
pub fn is_args(&self, name: &syn::Ident) -> bool {
|
||||
for s in self.attrs.iter() {
|
||||
if let Argument::VarArgs(ref path) = s {
|
||||
if let Argument::VarArgs(path) = s {
|
||||
return path.is_ident(name);
|
||||
}
|
||||
}
|
||||
|
@ -276,7 +274,7 @@ impl<'a> FnSpec<'a> {
|
|||
|
||||
pub fn is_kwargs(&self, name: &syn::Ident) -> bool {
|
||||
for s in self.attrs.iter() {
|
||||
if let Argument::KeywordArgs(ref path) = s {
|
||||
if let Argument::KeywordArgs(path) = s {
|
||||
return path.is_ident(name);
|
||||
}
|
||||
}
|
||||
|
@ -285,10 +283,10 @@ impl<'a> FnSpec<'a> {
|
|||
|
||||
pub fn default_value(&self, name: &syn::Ident) -> Option<TokenStream> {
|
||||
for s in self.attrs.iter() {
|
||||
match *s {
|
||||
Argument::Arg(ref path, ref opt) | Argument::Kwarg(ref path, ref opt) => {
|
||||
match s {
|
||||
Argument::Arg(path, opt) | Argument::Kwarg(path, opt) => {
|
||||
if path.is_ident(name) {
|
||||
if let Some(ref val) = opt {
|
||||
if let Some(val) = opt {
|
||||
let i: syn::Expr = syn::parse_str(&val).unwrap();
|
||||
return Some(i.into_token_stream());
|
||||
}
|
||||
|
@ -302,7 +300,7 @@ impl<'a> FnSpec<'a> {
|
|||
|
||||
pub fn is_kw_only(&self, name: &syn::Ident) -> bool {
|
||||
for s in self.attrs.iter() {
|
||||
if let Argument::Kwarg(ref path, _) = s {
|
||||
if let Argument::Kwarg(path, _) = s {
|
||||
if path.is_ident(name) {
|
||||
return true;
|
||||
}
|
||||
|
@ -341,7 +339,7 @@ fn parse_method_attributes(
|
|||
|
||||
for attr in attrs.iter() {
|
||||
match attr.parse_meta()? {
|
||||
syn::Meta::Path(ref name) => {
|
||||
syn::Meta::Path(name) => {
|
||||
if name.is_ident("new") || name.is_ident("__new__") {
|
||||
set_ty!(MethodTypeAttribute::New, name);
|
||||
} else if name.is_ident("init") || name.is_ident("__init__") {
|
||||
|
@ -373,11 +371,7 @@ fn parse_method_attributes(
|
|||
new_attrs.push(attr.clone())
|
||||
}
|
||||
}
|
||||
syn::Meta::List(syn::MetaList {
|
||||
ref path,
|
||||
ref nested,
|
||||
..
|
||||
}) => {
|
||||
syn::Meta::List(syn::MetaList { path, nested, .. }) => {
|
||||
if path.is_ident("new") {
|
||||
set_ty!(MethodTypeAttribute::New, path);
|
||||
} else if path.is_ident("init") {
|
||||
|
@ -408,11 +402,11 @@ fn parse_method_attributes(
|
|||
};
|
||||
|
||||
property_name = match nested.first().unwrap() {
|
||||
syn::NestedMeta::Meta(syn::Meta::Path(ref w)) if w.segments.len() == 1 => {
|
||||
syn::NestedMeta::Meta(syn::Meta::Path(w)) if w.segments.len() == 1 => {
|
||||
Some(w.segments[0].ident.clone())
|
||||
}
|
||||
syn::NestedMeta::Lit(ref lit) => match *lit {
|
||||
syn::Lit::Str(ref s) => Some(s.parse()?),
|
||||
syn::NestedMeta::Lit(lit) => match lit {
|
||||
syn::Lit::Str(s) => Some(s.parse()?),
|
||||
_ => {
|
||||
return Err(syn::Error::new_spanned(
|
||||
lit,
|
||||
|
@ -428,7 +422,7 @@ fn parse_method_attributes(
|
|||
}
|
||||
};
|
||||
} else if path.is_ident("args") {
|
||||
let attrs = PyFunctionAttr::from_meta(nested)?;
|
||||
let attrs = PyFunctionAttr::from_meta(&nested)?;
|
||||
args.extend(attrs.arguments)
|
||||
} else {
|
||||
new_attrs.push(attr.clone())
|
||||
|
|
|
@ -35,7 +35,7 @@ pub fn process_functions_in_module(func: &mut syn::ItemFn) -> syn::Result<()> {
|
|||
let mut stmts: Vec<syn::Stmt> = Vec::new();
|
||||
|
||||
for stmt in func.block.stmts.iter_mut() {
|
||||
if let syn::Stmt::Item(syn::Item::Fn(ref mut func)) = stmt {
|
||||
if let syn::Stmt::Item(syn::Item::Fn(func)) = stmt {
|
||||
if let Some((module_name, python_name, pyfn_attrs)) =
|
||||
extract_pyfn_attrs(&mut func.attrs)?
|
||||
{
|
||||
|
@ -59,8 +59,8 @@ pub fn process_functions_in_module(func: &mut syn::ItemFn) -> syn::Result<()> {
|
|||
|
||||
/// Transforms a rust fn arg parsed with syn into a method::FnArg
|
||||
fn wrap_fn_argument<'a>(cap: &'a syn::PatType) -> syn::Result<method::FnArg<'a>> {
|
||||
let (mutability, by_ref, ident) = match *cap.pat {
|
||||
syn::Pat::Ident(ref patid) => (&patid.mutability, &patid.by_ref, &patid.ident),
|
||||
let (mutability, by_ref, ident) = match &*cap.pat {
|
||||
syn::Pat::Ident(patid) => (&patid.mutability, &patid.by_ref, &patid.ident),
|
||||
_ => return Err(syn::Error::new_spanned(&cap.pat, "Unsupported argument")),
|
||||
};
|
||||
|
||||
|
@ -85,12 +85,12 @@ fn extract_pyfn_attrs(
|
|||
|
||||
for attr in attrs.iter() {
|
||||
match attr.parse_meta() {
|
||||
Ok(syn::Meta::List(ref list)) if list.path.is_ident("pyfn") => {
|
||||
Ok(syn::Meta::List(list)) if list.path.is_ident("pyfn") => {
|
||||
let meta: Vec<_> = list.nested.iter().cloned().collect();
|
||||
if meta.len() >= 2 {
|
||||
// read module name
|
||||
match meta[0] {
|
||||
syn::NestedMeta::Meta(syn::Meta::Path(ref path)) => {
|
||||
match &meta[0] {
|
||||
syn::NestedMeta::Meta(syn::Meta::Path(path)) => {
|
||||
modname = Some(path.clone())
|
||||
}
|
||||
_ => {
|
||||
|
@ -101,8 +101,8 @@ fn extract_pyfn_attrs(
|
|||
}
|
||||
}
|
||||
// read Python function name
|
||||
match meta[1] {
|
||||
syn::NestedMeta::Lit(syn::Lit::Str(ref lits)) => {
|
||||
match &meta[1] {
|
||||
syn::NestedMeta::Lit(syn::Lit::Str(lits)) => {
|
||||
fnname = Some(syn::Ident::new(&lits.value(), lits.span()));
|
||||
}
|
||||
_ => {
|
||||
|
@ -157,7 +157,7 @@ pub fn add_fn_to_module(
|
|||
"Unexpected receiver for #[pyfn]",
|
||||
))
|
||||
}
|
||||
syn::FnArg::Typed(ref cap) => {
|
||||
syn::FnArg::Typed(cap) => {
|
||||
if pyfn_attrs.pass_module && i == 0 {
|
||||
if let syn::Type::Reference(tyref) = cap.ty.as_ref() {
|
||||
if let syn::Type::Path(typath) = tyref.elem.as_ref() {
|
||||
|
|
|
@ -56,8 +56,8 @@ impl PyClassArgs {
|
|||
/// either a single word or an assignment expression
|
||||
fn add_expr(&mut self, expr: &Expr) -> syn::parse::Result<()> {
|
||||
match expr {
|
||||
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => self.add_path(exp),
|
||||
syn::Expr::Assign(ref assign) => self.add_assign(assign),
|
||||
syn::Expr::Path(exp) if exp.path.segments.len() == 1 => self.add_path(exp),
|
||||
syn::Expr::Assign(assign) => self.add_assign(assign),
|
||||
_ => Err(syn::Error::new_spanned(expr, "Failed to parse arguments")),
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ pub fn build_py_class(class: &mut syn::ItemStruct, attr: &PyClassArgs) -> syn::R
|
|||
let mut descriptors = Vec::new();
|
||||
|
||||
check_generics(class)?;
|
||||
if let syn::Fields::Named(ref mut fields) = class.fields {
|
||||
if let syn::Fields::Named(fields) = &mut class.fields {
|
||||
for field in fields.named.iter_mut() {
|
||||
let field_descs = parse_descriptors(field)?;
|
||||
if !field_descs.is_empty() {
|
||||
|
@ -178,10 +178,10 @@ fn parse_descriptors(item: &mut syn::Field) -> syn::Result<Vec<FnType>> {
|
|||
let mut descs = Vec::new();
|
||||
let mut new_attrs = Vec::new();
|
||||
for attr in item.attrs.iter() {
|
||||
if let Ok(syn::Meta::List(ref list)) = attr.parse_meta() {
|
||||
if let Ok(syn::Meta::List(list)) = attr.parse_meta() {
|
||||
if list.path.is_ident("pyo3") {
|
||||
for meta in list.nested.iter() {
|
||||
if let syn::NestedMeta::Meta(ref metaitem) = meta {
|
||||
if let syn::NestedMeta::Meta(metaitem) = meta {
|
||||
if metaitem.path().is_ident("get") {
|
||||
descs.push(FnType::Getter(SelfType::Receiver { mutable: false }));
|
||||
} else if metaitem.path().is_ident("set") {
|
||||
|
@ -318,7 +318,7 @@ fn impl_class(
|
|||
let mut has_dict = false;
|
||||
let mut has_gc = false;
|
||||
for f in attr.flags.iter() {
|
||||
if let syn::Expr::Path(ref epath) = f {
|
||||
if let syn::Expr::Path(epath) = f {
|
||||
if epath.path == parse_quote! { pyo3::type_flags::WEAKREF } {
|
||||
has_weakref = true;
|
||||
} else if epath.path == parse_quote! { pyo3::type_flags::DICT } {
|
||||
|
@ -469,7 +469,7 @@ fn impl_descriptors(
|
|||
) -> syn::Result<TokenStream> {
|
||||
let py_methods: Vec<TokenStream> = descriptors
|
||||
.iter()
|
||||
.flat_map(|&(ref field, ref fns)| {
|
||||
.flat_map(|(field, fns)| {
|
||||
fns.iter()
|
||||
.map(|desc| {
|
||||
let name = field.ident.as_ref().unwrap().unraw();
|
||||
|
|
|
@ -46,17 +46,17 @@ impl PyFunctionAttr {
|
|||
|
||||
pub fn add_item(&mut self, item: &NestedMeta) -> syn::Result<()> {
|
||||
match item {
|
||||
NestedMeta::Meta(syn::Meta::Path(ref ident)) if ident.is_ident("pass_module") => {
|
||||
NestedMeta::Meta(syn::Meta::Path(ident)) if ident.is_ident("pass_module") => {
|
||||
self.pass_module = true;
|
||||
}
|
||||
NestedMeta::Meta(syn::Meta::Path(ref ident)) => self.add_work(item, ident)?,
|
||||
NestedMeta::Meta(syn::Meta::NameValue(ref nv)) => {
|
||||
NestedMeta::Meta(syn::Meta::Path(ident)) => self.add_work(item, ident)?,
|
||||
NestedMeta::Meta(syn::Meta::NameValue(nv)) => {
|
||||
self.add_name_value(item, nv)?;
|
||||
}
|
||||
NestedMeta::Lit(ref lit) => {
|
||||
NestedMeta::Lit(lit) => {
|
||||
self.add_literal(item, lit)?;
|
||||
}
|
||||
NestedMeta::Meta(syn::Meta::List(ref list)) => {
|
||||
NestedMeta::Meta(syn::Meta::List(list)) => {
|
||||
return Err(syn::Error::new_spanned(
|
||||
list,
|
||||
"List is not supported as argument",
|
||||
|
@ -68,7 +68,7 @@ impl PyFunctionAttr {
|
|||
|
||||
fn add_literal(&mut self, item: &NestedMeta, lit: &syn::Lit) -> syn::Result<()> {
|
||||
match lit {
|
||||
syn::Lit::Str(ref lits) if lits.value() == "*" => {
|
||||
syn::Lit::Str(lits) if lits.value() == "*" => {
|
||||
// "*"
|
||||
self.vararg_is_ok(item)?;
|
||||
self.has_varargs = true;
|
||||
|
@ -137,8 +137,8 @@ impl PyFunctionAttr {
|
|||
}
|
||||
|
||||
fn add_name_value(&mut self, item: &NestedMeta, nv: &syn::MetaNameValue) -> syn::Result<()> {
|
||||
match nv.lit {
|
||||
syn::Lit::Str(ref litstr) => {
|
||||
match &nv.lit {
|
||||
syn::Lit::Str(litstr) => {
|
||||
if litstr.value() == "*" {
|
||||
// args="*"
|
||||
self.vararg_is_ok(item)?;
|
||||
|
@ -153,10 +153,10 @@ impl PyFunctionAttr {
|
|||
self.add_nv_common(item, &nv.path, litstr.value())?;
|
||||
}
|
||||
}
|
||||
syn::Lit::Int(ref litint) => {
|
||||
syn::Lit::Int(litint) => {
|
||||
self.add_nv_common(item, &nv.path, format!("{}", litint))?;
|
||||
}
|
||||
syn::Lit::Bool(ref litb) => {
|
||||
syn::Lit::Bool(litb) => {
|
||||
self.add_nv_common(item, &nv.path, format!("{}", litb.value))?;
|
||||
}
|
||||
_ => {
|
||||
|
@ -175,32 +175,29 @@ pub fn parse_name_attribute(attrs: &mut Vec<syn::Attribute>) -> syn::Result<Opti
|
|||
|
||||
// Using retain will extract all name attributes from the attribute list
|
||||
attrs.retain(|attr| match attr.parse_meta() {
|
||||
Ok(syn::Meta::NameValue(ref nv)) if nv.path.is_ident("name") => {
|
||||
name_attrs.push((nv.lit.clone(), attr.span()));
|
||||
Ok(syn::Meta::NameValue(nv)) if nv.path.is_ident("name") => {
|
||||
name_attrs.push((nv.lit, attr.span()));
|
||||
false
|
||||
}
|
||||
_ => true,
|
||||
});
|
||||
|
||||
if 1 < name_attrs.len() {
|
||||
return Err(syn::Error::new(
|
||||
name_attrs[0].1,
|
||||
"#[name] can not be specified multiple times",
|
||||
));
|
||||
}
|
||||
|
||||
match name_attrs.get(0) {
|
||||
Some((syn::Lit::Str(s), span)) => {
|
||||
match name_attrs.as_slice() {
|
||||
[] => Ok(None),
|
||||
[(syn::Lit::Str(s), span)] => {
|
||||
let mut ident: syn::Ident = s.parse()?;
|
||||
// This span is the whole attribute span, which is nicer for reporting errors.
|
||||
ident.set_span(*span);
|
||||
Ok(Some(ident))
|
||||
}
|
||||
Some((_, span)) => Err(syn::Error::new(
|
||||
[(_, span)] => Err(syn::Error::new(
|
||||
*span,
|
||||
"Expected string literal for #[name] argument",
|
||||
)),
|
||||
None => Ok(None),
|
||||
[_first_attr, second_attr, ..] => Err(syn::Error::new(
|
||||
second_attr.1,
|
||||
"#[name] can not be specified multiple times",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ use proc_macro2::TokenStream;
|
|||
use quote::quote;
|
||||
|
||||
pub fn build_py_methods(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
|
||||
if let Some((_, ref path, _)) = ast.trait_ {
|
||||
if let Some((_, path, _)) = &ast.trait_ {
|
||||
Err(syn::Error::new_spanned(
|
||||
path,
|
||||
"#[pymethods] cannot be used on trait impl blocks",
|
||||
|
|
|
@ -505,11 +505,10 @@ fn impl_arg_param(
|
|||
// Get Option<&T> from Option<PyRef<T>>
|
||||
(
|
||||
quote! { Option<<#tref as pyo3::derive_utils::ExtractExt>::Target> },
|
||||
// To support Rustc 1.39.0, we don't use as_deref here...
|
||||
if mut_.is_some() {
|
||||
quote! { _tmp.as_mut().map(std::ops::DerefMut::deref_mut) }
|
||||
quote! { _tmp.as_deref_mut() }
|
||||
} else {
|
||||
quote! { _tmp.as_ref().map(std::ops::Deref::deref) }
|
||||
quote! { _tmp.as_deref() }
|
||||
},
|
||||
)
|
||||
} else {
|
||||
|
@ -554,7 +553,7 @@ fn impl_arg_param(
|
|||
fn replace_self(tref: &mut syn::TypeReference, self_path: &syn::Path) {
|
||||
match &mut *tref.elem {
|
||||
syn::Type::Reference(tref_inner) => replace_self(tref_inner, self_path),
|
||||
syn::Type::Path(ref mut tpath) => {
|
||||
syn::Type::Path(tpath) => {
|
||||
if let Some(ident) = tpath.path.get_ident() {
|
||||
if ident == "Self" {
|
||||
tpath.path = self_path.to_owned();
|
||||
|
@ -712,13 +711,8 @@ pub(crate) fn impl_py_getter_def(
|
|||
|
||||
/// Split an argument of pyo3::Python from the front of the arg list, if present
|
||||
fn split_off_python_arg<'a>(args: &'a [FnArg<'a>]) -> (Option<&FnArg>, &[FnArg]) {
|
||||
if args
|
||||
.get(0)
|
||||
.map(|py| utils::is_python(&py.ty))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
(Some(&args[0]), &args[1..])
|
||||
} else {
|
||||
(None, args)
|
||||
match args {
|
||||
[py, args @ ..] if utils::is_python(&py.ty) => (Some(py), args),
|
||||
args => (None, args),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ use quote::ToTokens;
|
|||
use std::collections::HashSet;
|
||||
|
||||
pub fn build_py_proto(ast: &mut syn::ItemImpl) -> syn::Result<TokenStream> {
|
||||
if let Some((_, ref mut path, _)) = ast.trait_ {
|
||||
let proto = if let Some(ref mut segment) = path.segments.last() {
|
||||
if let Some((_, path, _)) = &mut ast.trait_ {
|
||||
let proto = if let Some(segment) = path.segments.last() {
|
||||
match segment.ident.to_string().as_str() {
|
||||
"PyObjectProtocol" => &defs::OBJECT,
|
||||
"PyAsyncProtocol" => &defs::ASYNC,
|
||||
|
@ -64,7 +64,7 @@ fn impl_proto_impl(
|
|||
let mut method_names = HashSet::new();
|
||||
|
||||
for iimpl in impls.iter_mut() {
|
||||
if let syn::ImplItem::Method(ref mut met) = iimpl {
|
||||
if let syn::ImplItem::Method(met) = iimpl {
|
||||
// impl Py~Protocol<'p> { type = ... }
|
||||
if let Some(m) = proto.get_proto(&met.sig.ident) {
|
||||
impl_method_proto(ty, &mut met.sig, m)?.to_tokens(&mut trait_impls);
|
||||
|
|
|
@ -10,7 +10,7 @@ pub fn print_err(msg: String, t: TokenStream) {
|
|||
/// Check if the given type `ty` is `pyo3::Python`.
|
||||
pub fn is_python(ty: &syn::Type) -> bool {
|
||||
match ty {
|
||||
syn::Type::Path(ref typath) => typath
|
||||
syn::Type::Path(typath) => typath
|
||||
.path
|
||||
.segments
|
||||
.last()
|
||||
|
@ -125,9 +125,9 @@ pub fn get_doc(
|
|||
let mut first = true;
|
||||
|
||||
for attr in attrs.iter() {
|
||||
if let Ok(syn::Meta::NameValue(ref metanv)) = attr.parse_meta() {
|
||||
if let Ok(syn::Meta::NameValue(metanv)) = attr.parse_meta() {
|
||||
if metanv.path.is_ident("doc") {
|
||||
if let syn::Lit::Str(ref litstr) = metanv.lit {
|
||||
if let syn::Lit::Str(litstr) = metanv.lit {
|
||||
if first {
|
||||
first = false;
|
||||
span = litstr.span();
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
//! This crate declares only the proc macro attributes, as a crate defining proc macro attributes
|
||||
//! must not contain any other public items.
|
||||
|
||||
extern crate proc_macro;
|
||||
use proc_macro::TokenStream;
|
||||
use pyo3_derive_backend::{
|
||||
build_derive_from_pyobject, build_py_class, build_py_function, build_py_methods,
|
||||
|
|
|
@ -46,17 +46,12 @@ pub enum ElementType {
|
|||
|
||||
impl ElementType {
|
||||
pub fn from_format(format: &CStr) -> ElementType {
|
||||
let slice = format.to_bytes();
|
||||
if slice.len() == 1 {
|
||||
native_element_type_from_type_char(slice[0])
|
||||
} else if slice.len() == 2 {
|
||||
match slice[0] {
|
||||
b'@' => native_element_type_from_type_char(slice[1]),
|
||||
b'=' | b'<' | b'>' | b'!' => standard_element_type_from_type_char(slice[1]),
|
||||
_ => ElementType::Unknown,
|
||||
match format.to_bytes() {
|
||||
[char] | [b'@', char] => native_element_type_from_type_char(*char),
|
||||
[modifier, char] if matches!(modifier, b'=' | b'<' | b'>' | b'!') => {
|
||||
standard_element_type_from_type_char(*char)
|
||||
}
|
||||
} else {
|
||||
ElementType::Unknown
|
||||
_ => ElementType::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -322,7 +322,7 @@ pub unsafe fn PyTZInfo_CheckExact(op: *mut PyObject) -> c_int {
|
|||
/// Accessor functions
|
||||
#[cfg(not(PyPy))]
|
||||
macro_rules! _access_field {
|
||||
($obj:expr, $type: ident, $field:tt) => {
|
||||
($obj:expr, $type: ident, $field:ident) => {
|
||||
(*($obj as *mut $type)).$field
|
||||
};
|
||||
}
|
||||
|
@ -504,7 +504,7 @@ pub unsafe fn PyDateTime_TIME_GET_TZINFO(o: *mut PyObject) -> *mut PyObject {
|
|||
// Accessor functions for PyDateTime_Delta
|
||||
#[cfg(not(PyPy))]
|
||||
macro_rules! _access_delta_field {
|
||||
($obj:expr, $field:tt) => {
|
||||
($obj:expr, $field:ident) => {
|
||||
_access_field!($obj, PyDateTime_Delta, $field)
|
||||
};
|
||||
}
|
||||
|
|
10
src/lib.rs
10
src/lib.rs
|
@ -211,7 +211,7 @@ pub mod proc_macro {
|
|||
#[macro_export]
|
||||
macro_rules! wrap_pyfunction {
|
||||
($function_name: ident) => {{
|
||||
&pyo3::paste::expr! { [<__pyo3_get_function_ $function_name>] }
|
||||
&pyo3::paste::paste! { [<__pyo3_get_function_ $function_name>] }
|
||||
}};
|
||||
|
||||
($function_name: ident, $arg: expr) => {
|
||||
|
@ -244,7 +244,7 @@ macro_rules! wrap_pyfunction {
|
|||
#[macro_export]
|
||||
macro_rules! raw_pycfunction {
|
||||
($function_name: ident) => {{
|
||||
pyo3::paste::expr! { [<__pyo3_raw_ $function_name>] }
|
||||
pyo3::paste::paste! { [<__pyo3_raw_ $function_name>] }
|
||||
}};
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,7 @@ macro_rules! raw_pycfunction {
|
|||
#[macro_export]
|
||||
macro_rules! wrap_pymodule {
|
||||
($module_name:ident) => {{
|
||||
pyo3::paste::expr! {
|
||||
pyo3::paste::paste! {
|
||||
&|py| unsafe { pyo3::PyObject::from_owned_ptr(py, [<PyInit_ $module_name>]()) }
|
||||
}
|
||||
}};
|
||||
|
@ -349,9 +349,9 @@ macro_rules! py_run_impl {
|
|||
#[doc(hidden)]
|
||||
pub mod doc_test {
|
||||
macro_rules! doc_comment {
|
||||
($x:expr, $($tt:tt)*) => {
|
||||
($x:expr, $module:item) => {
|
||||
#[doc = $x]
|
||||
$($tt)*
|
||||
$module
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -317,18 +317,18 @@ fn py_class_method_defs<T: PyMethods>() -> (
|
|||
let mut new = fallback_new();
|
||||
|
||||
for def in T::py_methods() {
|
||||
match *def {
|
||||
PyMethodDefType::New(ref def) => {
|
||||
match def {
|
||||
PyMethodDefType::New(def) => {
|
||||
new = def.get_new_func();
|
||||
debug_assert!(new.is_some());
|
||||
}
|
||||
PyMethodDefType::Call(ref def) => {
|
||||
PyMethodDefType::Call(def) => {
|
||||
call = def.get_cfunction_with_keywords();
|
||||
debug_assert!(call.is_some());
|
||||
}
|
||||
PyMethodDefType::Method(ref def)
|
||||
| PyMethodDefType::Class(ref def)
|
||||
| PyMethodDefType::Static(ref def) => {
|
||||
PyMethodDefType::Method(def)
|
||||
| PyMethodDefType::Class(def)
|
||||
| PyMethodDefType::Static(def) => {
|
||||
defs.push(def.as_method_def());
|
||||
}
|
||||
_ => (),
|
||||
|
@ -346,15 +346,15 @@ fn py_class_properties<T: PyClass>() -> Vec<ffi::PyGetSetDef> {
|
|||
let mut defs = std::collections::HashMap::new();
|
||||
|
||||
for def in T::py_methods() {
|
||||
match *def {
|
||||
PyMethodDefType::Getter(ref getter) => {
|
||||
match def {
|
||||
PyMethodDefType::Getter(getter) => {
|
||||
if !defs.contains_key(getter.name) {
|
||||
let _ = defs.insert(getter.name.to_owned(), ffi::PyGetSetDef_INIT);
|
||||
}
|
||||
let def = defs.get_mut(getter.name).expect("Failed to call get_mut");
|
||||
getter.copy_to(def);
|
||||
}
|
||||
PyMethodDefType::Setter(ref setter) => {
|
||||
PyMethodDefType::Setter(setter) => {
|
||||
if !defs.contains_key(setter.name) {
|
||||
let _ = defs.insert(setter.name.to_owned(), ffi::PyGetSetDef_INIT);
|
||||
}
|
||||
|
|
|
@ -8,18 +8,11 @@ fn test_compile_errors() {
|
|||
t.compile_fail("tests/ui/invalid_pyclass_args.rs");
|
||||
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
|
||||
t.compile_fail("tests/ui/reject_generics.rs");
|
||||
t.compile_fail("tests/ui/static_ref.rs");
|
||||
t.compile_fail("tests/ui/wrong_aspyref_lifetimes.rs");
|
||||
|
||||
tests_rust_1_43(&t);
|
||||
tests_rust_1_46(&t);
|
||||
|
||||
#[rustversion::since(1.43)]
|
||||
fn tests_rust_1_43(t: &trybuild::TestCases) {
|
||||
t.compile_fail("tests/ui/static_ref.rs");
|
||||
}
|
||||
#[rustversion::before(1.43)]
|
||||
fn tests_rust_1_43(_t: &trybuild::TestCases) {}
|
||||
|
||||
#[rustversion::since(1.46)]
|
||||
fn tests_rust_1_46(t: &trybuild::TestCases) {
|
||||
t.compile_fail("tests/ui/invalid_frompy_derive.rs");
|
||||
|
|
|
@ -36,7 +36,7 @@ macro_rules! assert_check_exact {
|
|||
unsafe {
|
||||
use pyo3::{AsPyPointer, ffi::*};
|
||||
assert!($check_func(($obj).as_ptr()) != 0);
|
||||
assert!(pyo3::paste::expr!([<$check_func Exact>])(($obj).as_ptr()) != 0);
|
||||
assert!(pyo3::paste::paste!([<$check_func Exact>])(($obj).as_ptr()) != 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ macro_rules! assert_check_only {
|
|||
unsafe {
|
||||
use pyo3::{AsPyPointer, ffi::*};
|
||||
assert!($check_func(($obj).as_ptr()) != 0);
|
||||
assert!(pyo3::paste::expr!([<$check_func Exact>])(($obj).as_ptr()) == 0);
|
||||
assert!(pyo3::paste::paste!([<$check_func Exact>])(($obj).as_ptr()) == 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ impl BaseClassWithDrop {
|
|||
|
||||
impl Drop for BaseClassWithDrop {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ref mut data) = self.data {
|
||||
if let Some(data) = &self.data {
|
||||
data.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ impl SubClassWithDrop {
|
|||
|
||||
impl Drop for SubClassWithDrop {
|
||||
fn drop(&mut self) {
|
||||
if let Some(ref mut data) = self.data {
|
||||
if let Some(data) = &self.data {
|
||||
data.store(true, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ impl PySequenceProtocol for ByteSequence {
|
|||
|
||||
fn __contains__(&self, other: &PyAny) -> bool {
|
||||
match u8::extract(other) {
|
||||
Ok(ref x) => self.elements.contains(x),
|
||||
Ok(x) => self.elements.contains(&x),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@ error: name not allowed with this method type
|
|||
| ^
|
||||
|
||||
error: #[name] can not be specified multiple times
|
||||
--> $DIR/invalid_pymethod_names.rs:17:5
|
||||
--> $DIR/invalid_pymethod_names.rs:18:5
|
||||
|
|
||||
17 | #[name = "foo"]
|
||||
18 | #[name = "bar"]
|
||||
| ^
|
||||
|
||||
error: name not allowed with this method type
|
||||
|
|
Loading…
Reference in New Issue