Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 61 additions & 0 deletions crates/derive-impl/src/class_docs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//! Attribute docs resolved while expanding `#[pyclass]`.

use alloc::collections::BTreeSet;

use proc_macro2::TokenStream;
use quote::quote;

/// Modules `get_qualified` consults for `module`.
fn module_aliases(module: &str) -> Vec<String> {
let mut aliases = vec![module.to_owned()];
if module == "os" || module == "_os" {
aliases.push("posix".to_owned());
aliases.push("nt".to_owned());
}
if let Some(rest) = module.strip_prefix('_')
&& !rest.is_empty()
{
aliases.push(rest.to_owned());
}
if !module.is_empty() && !module.starts_with('_') {
aliases.push(format!("_{module}"));
}
if module != "builtins" && !module.starts_with('_') {
aliases.push("builtins".to_owned());
}
aliases
}

/// `get_attr`, then `class_attr_doc` when that entry is missing or empty.
/// An explicit empty entry with no fallback is `Some("")`.
fn resolved_attr_doc(module_name: Option<&str>, class: &str, attr: &str) -> Option<&'static str> {
let module_key = module_name.unwrap_or("builtins");
let exact = rustpython_doc::get_attr(module_key, class, attr);
let qualified = rustpython_doc::class_attr_doc(module_name, class, attr);
match exact {
Some(doc) if !doc.is_empty() => Some(doc),
Some(_) => qualified.or(Some("")),
None => qualified,
}
}

pub(crate) fn attr_docs_tokens(module_name: Option<&str>, class: &str) -> TokenStream {
let module_key = module_name.unwrap_or("builtins");
let mut names = BTreeSet::new();
for module in module_aliases(module_key) {
let prefix = format!("{module}.{class}.");
for (key, _) in rustpython_doc::DB {
if let Some(attr) = key.strip_prefix(&prefix)
&& !attr.is_empty()
&& !attr.contains('.')
{
names.insert(attr);
}
}
}
let entries = names.into_iter().filter_map(|attr| {
let doc = resolved_attr_doc(module_name, class, attr)?;
Some(quote! { (#attr, #doc) })
});
quote! { &[#(#entries),*] }
}
2 changes: 2 additions & 0 deletions crates/derive-impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustPython/RustPython/main/logo.png")]
#![doc(html_root_url = "https://docs.rs/rustpython-derive/")]

extern crate alloc;
extern crate proc_macro;

#[macro_use]
mod error;
#[macro_use]
mod util;

mod class_docs;
mod compile_bytecode;
mod from_args;
mod pyclass;
Expand Down
19 changes: 6 additions & 13 deletions crates/derive-impl/src/pyclass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,22 +445,13 @@ fn attr_doc_expr(self_ty: Option<&syn::Type>, attr: &str, rust_doc: Option<Strin
};
quote! {
{
const MODULE: &str = match <#ty as ::rustpython_vm::class::PyClassDef>::MODULE_NAME {
Some(module) => module,
None => "builtins",
};
const CLASS: &str = <#ty as ::rustpython_vm::class::PyClassDef>::NAME;
const EXACT: Option<&str> = ::rustpython_vm::__exports::rustpython_doc::get_attr(MODULE, CLASS, #attr);
const QUALIFIED: Option<&str> = ::rustpython_vm::__exports::rustpython_doc::class_attr_doc(
<#ty as ::rustpython_vm::class::PyClassDef>::MODULE_NAME,
CLASS,
const FOUND: Option<&str> = ::rustpython_vm::class::attr_doc(
<#ty as ::rustpython_vm::class::PyClassDef>::ATTR_DOCS,
#attr,
);
const RUST_DOC: Option<&str> = #fallback;
if let Some(doc) = EXACT {
if doc.is_empty() { QUALIFIED } else { Some(doc) }
} else if QUALIFIED.is_some() {
QUALIFIED
if let Some(doc) = FOUND {
if doc.is_empty() { None } else { Some(doc) }
} else {
RUST_DOC
}
Expand Down Expand Up @@ -501,6 +492,7 @@ fn generate_class_def(
attrs: &[Attribute],
) -> Result<TokenStream> {
let module_key = module_name.unwrap_or("builtins");
let attr_docs = crate::class_docs::attr_docs_tokens(module_name, name);
let doc = rustpython_doc::get_qualified(module_key, name, None, true)
.filter(|doc| !doc.is_empty())
.map(str::to_owned)
Expand Down Expand Up @@ -614,6 +606,7 @@ fn generate_class_def(
const MODULE_NAME: Option<&'static str> = #module_name;
const TP_NAME: &'static str = #module_class_name;
const DOC: Option<&'static str> = #doc;
const ATTR_DOCS: &'static [(&'static str, &'static str)] = #attr_docs;
const BASICSIZE: usize = #basicsize;
const UNHASHABLE: bool = #unhashable;

Expand Down
2 changes: 2 additions & 0 deletions crates/derive-impl/src/pystructseq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ pub(crate) fn impl_pystruct_sequence(
Some(doc) => quote!(Some(#doc)),
None => quote!(None),
};
let attr_docs = crate::class_docs::attr_docs_tokens(module_name.as_deref(), &class_name);

let output = quote! {
// The Python type struct - newtype wrapping PyTuple
Expand All @@ -548,6 +549,7 @@ pub(crate) fn impl_pystruct_sequence(
const MODULE_NAME: Option<&'static str> = #module_name_tokens;
const TP_NAME: &'static str = #module_class_name;
const DOC: Option<&'static str> = #doc;
const ATTR_DOCS: &'static [(&'static str, &'static str)] = #attr_docs;
const BASICSIZE: usize = 0;
const UNHASHABLE: bool = false;

Expand Down
10 changes: 5 additions & 5 deletions crates/stdlib/src/binascii.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ mod decl {
struct A2bBase64Args {
#[pyarg(positional)]
data: ArgAsciiBuffer,
#[pyarg(named, default = false)]
#[pyarg(named, default)]
strict_mode: bool,
}

Expand All @@ -116,7 +116,7 @@ mod decl {
struct A2bQpArgs {
#[pyarg(any)]
data: ArgAsciiBuffer,
#[pyarg(any, default = false)]
#[pyarg(any, default)]
header: bool,
}

Expand All @@ -130,11 +130,11 @@ mod decl {
struct B2aQpArgs {
#[pyarg(any)]
data: ArgBytesLike,
#[pyarg(any, default = false)]
#[pyarg(any, default)]
quotetabs: bool,
#[pyarg(any, default = true)]
istext: bool,
#[pyarg(any, default = false)]
#[pyarg(any, default)]
header: bool,
}

Expand All @@ -157,7 +157,7 @@ mod decl {

#[derive(FromArgs)]
struct BacktickArg {
#[pyarg(named, default = false)]
#[pyarg(named, default)]
backtick: bool,
}

Expand Down
10 changes: 5 additions & 5 deletions crates/stdlib/src/blake2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ mod _blake2 {
fanout: i64,
#[pyarg(named, default = 1)]
depth: i64,
#[pyarg(named, default = 0)]
#[pyarg(named, default)]
leaf_size: i64,
#[pyarg(named, default = 0)]
#[pyarg(named, default)]
node_offset: i64,
#[pyarg(named, default = 0)]
#[pyarg(named, default)]
node_depth: i64,
#[pyarg(named, default = 0)]
#[pyarg(named, default)]
inner_size: i64,
#[pyarg(named, default = false)]
#[pyarg(named, default)]
last_node: bool,
#[pyarg(named, default = true)]
usedforsecurity: bool,
Expand Down
4 changes: 2 additions & 2 deletions crates/stdlib/src/elementtree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1368,9 +1368,9 @@ pub(crate) mod _elementtree {
comment_factory: Option<PyObjectRef>,
#[pyarg(named, default)]
pi_factory: Option<PyObjectRef>,
#[pyarg(named, default = false)]
#[pyarg(named, default)]
insert_comments: bool,
#[pyarg(named, default = false)]
#[pyarg(named, default)]
insert_pis: bool,
}

Expand Down
10 changes: 5 additions & 5 deletions crates/stdlib/src/faulthandler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -748,11 +748,11 @@ mod decl {
struct DumpTracebackLaterArgs {
#[pyarg(positional, error_msg = "timeout must be a number (int or float)")]
timeout: ArgIntoFloat,
#[pyarg(any, default = false)]
#[pyarg(any, default)]
repeat: bool,
#[pyarg(any, default)]
file: OptionalArg<PyObjectRef>,
#[pyarg(any, default = false)]
#[pyarg(any, default)]
exit: bool,
}

Expand Down Expand Up @@ -877,7 +877,7 @@ mod decl {
file: OptionalArg<PyObjectRef>,
#[pyarg(any, default = true)]
all_threads: bool,
#[pyarg(any, default = false)]
#[pyarg(any, default)]
chain: bool,
}

Expand Down Expand Up @@ -930,7 +930,7 @@ mod decl {
#[derive(FromArgs)]
#[allow(dead_code)]
struct SigsegvArgs {
#[pyarg(positional, default = false)]
#[pyarg(positional, default)]
release_gil: bool,
}

Expand Down Expand Up @@ -1027,7 +1027,7 @@ mod decl {
struct RaiseExceptionArgs {
#[pyarg(positional)]
code: u32,
#[pyarg(positional, default = 0)]
#[pyarg(positional, default)]
flags: u32,
}

Expand Down
2 changes: 1 addition & 1 deletion crates/stdlib/src/fcntl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ mod fcntl {
len: PyIntRef,
#[pyarg(positional, default = 0)]
start: PyIntRef,
#[pyarg(positional, default = 0)]
#[pyarg(positional, default)]
whence: i32,
}

Expand Down
4 changes: 2 additions & 2 deletions crates/stdlib/src/hashlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ pub(crate) mod _hashlib {
node_depth: OptionalArg<ArgPrimitiveIndex<i64>>,
#[pyarg(named, optional)]
inner_size: OptionalArg<ArgPrimitiveIndex<i64>>,
#[pyarg(named, default = false)]
#[pyarg(named, default)]
last_node: bool,
#[pyarg(named, default = true)]
usedforsecurity: bool,
Expand Down Expand Up @@ -1239,7 +1239,7 @@ pub(crate) mod _hashlib {
r: ArgPrimitiveIndex<i64>,
#[pyarg(named)]
p: ArgPrimitiveIndex<i64>,
#[pyarg(named, default = 0)]
#[pyarg(named, default)]
maxmem: i64,
#[pyarg(named, default = 64)]
dklen: i64,
Expand Down
8 changes: 4 additions & 4 deletions crates/stdlib/src/mmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ mod mmap {
prot: core::ffi::c_int,
#[pyarg(any, default = AccessMode::Default)]
access: AccessMode,
#[pyarg(any, default = 0)]
#[pyarg(any, default)]
offset: i64,
#[pyarg(named, default = true)]
trackfd: bool,
Expand All @@ -253,7 +253,7 @@ mod mmap {
tagname: Option<PyObjectRef>,
#[pyarg(any, default = AccessMode::Default)]
access: AccessMode,
#[pyarg(any, default = 0)]
#[pyarg(any, default)]
offset: i64,
}

Expand All @@ -280,13 +280,13 @@ mod mmap {
struct SeekArgs {
#[pyarg(positional)]
pos: isize,
#[pyarg(positional, default = 0)]
#[pyarg(positional, default)]
whence: core::ffi::c_int,
}

#[derive(FromArgs)]
pub(super) struct FlushOptions {
#[pyarg(positional, default = 0)]
#[pyarg(positional, default)]
offset: isize,
#[pyarg(positional, optional)]
size: Option<isize>,
Expand Down
2 changes: 1 addition & 1 deletion crates/stdlib/src/openssl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ mod _ssl {
#[derive(FromArgs)]
struct Txt2ObjArgs {
txt: PyStrRef,
#[pyarg(any, default = false)]
#[pyarg(any, default)]
name: bool,
}

Expand Down
2 changes: 1 addition & 1 deletion crates/stdlib/src/pystruct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pub(crate) mod _struct {
#[derive(FromArgs)]
struct UpdateFromArgs {
buffer: ArgBytesLike,
#[pyarg(any, default = 0)]
#[pyarg(any, default)]
offset: isize,
}

Expand Down
8 changes: 4 additions & 4 deletions crates/stdlib/src/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ mod decl {
pub(crate) struct EpollNewArgs {
#[pyarg(any, default = -1)]
sizehint: i32,
#[pyarg(any, default = 0)]
#[pyarg(any, default)]
flags: i32,
}

Expand Down Expand Up @@ -718,11 +718,11 @@ mod decl {
filter: i16,
#[pyarg(any, default = host_select::kqueue::DEFAULT_FLAGS)]
flags: u16,
#[pyarg(any, default = 0)]
#[pyarg(any, default)]
fflags: u32,
#[pyarg(any, default = 0)]
#[pyarg(any, default)]
data: isize,
#[pyarg(any, default = 0)]
#[pyarg(any, default)]
udata: usize,
}

Expand Down
6 changes: 3 additions & 3 deletions crates/stdlib/src/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2885,11 +2885,11 @@ mod _socket {

#[pyarg(any, default = c::AF_UNSPEC)]
family: i32,
#[pyarg(any, name = "type", default = 0)]
#[pyarg(any, name = "type", default)]
ty: i32,
#[pyarg(any, default = 0)]
#[pyarg(any, default)]
proto: i32,
#[pyarg(any, default = 0)]
#[pyarg(any, default)]
flags: i32,
}

Expand Down
Loading
Loading