Skip to content

Commit 34ad77f

Browse files
committed
Better default value
1 parent 7603b89 commit 34ad77f

File tree

4 files changed

+81
-62
lines changed

4 files changed

+81
-62
lines changed

pyo3-macros-backend/src/introspection.rs

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use crate::pyfunction::FunctionSignature;
1313
use crate::utils::PyO3CratePath;
1414
use proc_macro2::{Span, TokenStream};
1515
use quote::{format_ident, quote, ToTokens};
16+
use std::borrow::Cow;
1617
use std::collections::hash_map::DefaultHasher;
1718
use std::collections::HashMap;
1819
use std::hash::{Hash, Hasher};
@@ -30,9 +31,9 @@ pub fn module_introspection_code<'a>(
3031
) -> TokenStream {
3132
IntrospectionNode::Map(
3233
[
33-
("type", IntrospectionNode::String("module")),
34+
("type", IntrospectionNode::String("module".into())),
3435
("id", IntrospectionNode::IntrospectionId(None)),
35-
("name", IntrospectionNode::String(name)),
36+
("name", IntrospectionNode::String(name.into())),
3637
(
3738
"members",
3839
IntrospectionNode::List(
@@ -62,9 +63,9 @@ pub fn class_introspection_code(
6263
) -> TokenStream {
6364
IntrospectionNode::Map(
6465
[
65-
("type", IntrospectionNode::String("class")),
66+
("type", IntrospectionNode::String("class".into())),
6667
("id", IntrospectionNode::IntrospectionId(Some(ident))),
67-
("name", IntrospectionNode::String(name)),
68+
("name", IntrospectionNode::String(name.into())),
6869
]
6970
.into(),
7071
)
@@ -79,9 +80,9 @@ pub fn function_introspection_code(
7980
) -> TokenStream {
8081
IntrospectionNode::Map(
8182
[
82-
("type", IntrospectionNode::String("function")),
83+
("type", IntrospectionNode::String("function".into())),
8384
("id", IntrospectionNode::IntrospectionId(Some(ident))),
84-
("name", IntrospectionNode::String(name)),
85+
("name", IntrospectionNode::String(name.into())),
8586
("arguments", arguments_introspection_data(signature)),
8687
]
8788
.into(),
@@ -125,8 +126,8 @@ fn arguments_introspection_data<'a>(signature: &'a FunctionSignature<'a>) -> Int
125126
if let Some(param) = &signature.python_signature.varargs {
126127
arguments.push(IntrospectionNode::Map(
127128
[
128-
("name", IntrospectionNode::String(param)),
129-
("kind", IntrospectionNode::String("VAR_POSITIONAL")),
129+
("name", IntrospectionNode::String(param.into())),
130+
("kind", IntrospectionNode::String("VAR_POSITIONAL".into())),
130131
]
131132
.into(),
132133
));
@@ -144,8 +145,8 @@ fn arguments_introspection_data<'a>(signature: &'a FunctionSignature<'a>) -> Int
144145
if let Some(param) = &signature.python_signature.kwargs {
145146
arguments.push(IntrospectionNode::Map(
146147
[
147-
("name", IntrospectionNode::String(param)),
148-
("kind", IntrospectionNode::String("VAR_KEYWORD")),
148+
("name", IntrospectionNode::String(param.into())),
149+
("kind", IntrospectionNode::String("VAR_KEYWORD".into())),
149150
]
150151
.into(),
151152
));
@@ -160,19 +161,21 @@ fn argument_introspection_data<'a>(
160161
desc: &'a RegularArg<'_>,
161162
) -> IntrospectionNode<'a> {
162163
let mut params: HashMap<_, _> = [
163-
("name", IntrospectionNode::String(name)),
164-
("kind", IntrospectionNode::String(kind)),
164+
("name", IntrospectionNode::String(name.into())),
165+
("kind", IntrospectionNode::String(kind.into())),
165166
]
166167
.into();
167168
if desc.default_value.is_some() {
168-
// TODO: generate a nice default values for literals (None, false, 0, ""...)
169-
params.insert("default_value", IntrospectionNode::String("..."));
169+
params.insert(
170+
"default_value",
171+
IntrospectionNode::String(desc.default_value().into()),
172+
);
170173
}
171174
IntrospectionNode::Map(params)
172175
}
173176

174177
enum IntrospectionNode<'a> {
175-
String(&'a str),
178+
String(Cow<'a, str>),
176179
IntrospectionId(Option<&'a Ident>),
177180
Map(HashMap<&'static str, IntrospectionNode<'a>>),
178181
List(Vec<IntrospectionNode<'a>>),
@@ -198,7 +201,7 @@ impl IntrospectionNode<'_> {
198201
fn add_to_serialization(self, content: &mut ConcatenationBuilder) {
199202
match self {
200203
Self::String(string) => {
201-
content.push_str_to_escape(string);
204+
content.push_str_to_escape(&string);
202205
}
203206
Self::IntrospectionId(ident) => {
204207
content.push_str("\"");

pyo3-macros-backend/src/method.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,52 @@ pub struct RegularArg<'a> {
2727
pub option_wrapped_type: Option<&'a syn::Type>,
2828
}
2929

30+
impl RegularArg<'_> {
31+
pub fn default_value(&self) -> String {
32+
if let Self {
33+
default_value: Some(arg_default),
34+
..
35+
} = self
36+
{
37+
match arg_default {
38+
// literal values
39+
syn::Expr::Lit(syn::ExprLit { lit, .. }) => match lit {
40+
syn::Lit::Str(s) => s.token().to_string(),
41+
syn::Lit::Char(c) => c.token().to_string(),
42+
syn::Lit::Int(i) => i.base10_digits().to_string(),
43+
syn::Lit::Float(f) => f.base10_digits().to_string(),
44+
syn::Lit::Bool(b) => {
45+
if b.value() {
46+
"True".to_string()
47+
} else {
48+
"False".to_string()
49+
}
50+
}
51+
_ => "...".to_string(),
52+
},
53+
// None
54+
syn::Expr::Path(syn::ExprPath { qself, path, .. })
55+
if qself.is_none() && path.is_ident("None") =>
56+
{
57+
"None".to_string()
58+
}
59+
// others, unsupported yet so defaults to `...`
60+
_ => "...".to_string(),
61+
}
62+
} else if let RegularArg {
63+
option_wrapped_type: Some(..),
64+
..
65+
} = self
66+
{
67+
// functions without a `#[pyo3(signature = (...))]` option
68+
// will treat trailing `Option<T>` arguments as having a default of `None`
69+
"None".to_string()
70+
} else {
71+
"...".to_string()
72+
}
73+
}
74+
}
75+
3076
/// Pythons *args argument
3177
#[derive(Clone, Debug)]
3278
pub struct VarargsArg<'a> {
@@ -177,6 +223,14 @@ impl<'a> FnArg<'a> {
177223
}
178224
}
179225
}
226+
227+
pub fn default_value(&self) -> String {
228+
if let Self::Regular(args) = self {
229+
args.default_value()
230+
} else {
231+
"...".to_string()
232+
}
233+
}
180234
}
181235

182236
fn handle_argument_error(pat: &syn::Pat) -> syn::Error {

pyo3-macros-backend/src/pyfunction/signature.rs

Lines changed: 3 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -491,49 +491,11 @@ impl<'a> FunctionSignature<'a> {
491491
}
492492

493493
fn default_value_for_parameter(&self, parameter: &str) -> String {
494-
let mut default = "...".to_string();
495494
if let Some(fn_arg) = self.arguments.iter().find(|arg| arg.name() == parameter) {
496-
if let FnArg::Regular(RegularArg {
497-
default_value: Some(arg_default),
498-
..
499-
}) = fn_arg
500-
{
501-
match arg_default {
502-
// literal values
503-
syn::Expr::Lit(syn::ExprLit { lit, .. }) => match lit {
504-
syn::Lit::Str(s) => default = s.token().to_string(),
505-
syn::Lit::Char(c) => default = c.token().to_string(),
506-
syn::Lit::Int(i) => default = i.base10_digits().to_string(),
507-
syn::Lit::Float(f) => default = f.base10_digits().to_string(),
508-
syn::Lit::Bool(b) => {
509-
default = if b.value() {
510-
"True".to_string()
511-
} else {
512-
"False".to_string()
513-
}
514-
}
515-
_ => {}
516-
},
517-
// None
518-
syn::Expr::Path(syn::ExprPath {
519-
qself: None, path, ..
520-
}) if path.is_ident("None") => {
521-
default = "None".to_string();
522-
}
523-
// others, unsupported yet so defaults to `...`
524-
_ => {}
525-
}
526-
} else if let FnArg::Regular(RegularArg {
527-
option_wrapped_type: Some(..),
528-
..
529-
}) = fn_arg
530-
{
531-
// functions without a `#[pyo3(signature = (...))]` option
532-
// will treat trailing `Option<T>` arguments as having a default of `None`
533-
default = "None".to_string();
534-
}
495+
fn_arg.default_value()
496+
} else {
497+
"...".to_string()
535498
}
536-
default
537499
}
538500

539501
pub fn text_signature(&self, self_argument: Option<&str>) -> String {

pytests/stubs/pyfunctions.pyi

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
def args_kwargs(*args, **kwargs): ...
22
def none(): ...
33
def positional_only(a, /, b): ...
4-
def simple(a, b=..., *, c=...): ...
5-
def simple_args(a, b=..., *args, c=...): ...
6-
def simple_args_kwargs(a, b=..., *args, c=..., **kwargs): ...
7-
def simple_kwargs(a, b=..., c=..., **kwargs): ...
8-
def with_typed_args(a=..., b=..., c=..., d=...): ...
4+
def simple(a, b=None, *, c=None): ...
5+
def simple_args(a, b=None, *args, c=None): ...
6+
def simple_args_kwargs(a, b=None, *args, c=None, **kwargs): ...
7+
def simple_kwargs(a, b=None, c=None, **kwargs): ...
8+
def with_typed_args(a=False, b=0, c=0.0, d=""): ...

0 commit comments

Comments
 (0)