@@ -379,12 +379,9 @@ fn is_wrapped_arg_ty(ty: &Type) -> bool {
379379 )
380380}
381381
382- /// Expression passed to `ToPyObject` for a literal Python default .
382+ /// Expression passed to `ToPyObject` for a string, bytes, int, float, or bool literal .
383383fn literal_object_expr ( expr : & Expr ) -> Option < TokenStream > {
384384 match expr {
385- Expr :: Path ( path) if path. qself . is_none ( ) && path. path . is_ident ( "None" ) => {
386- Some ( quote ! ( vm. ctx. none( ) ) )
387- }
388385 Expr :: Lit ( syn:: ExprLit { lit, .. } ) => match lit {
389386 Lit :: Str ( _) | Lit :: ByteStr ( _) | Lit :: Bool ( _) => Some ( expr. to_token_stream ( ) ) ,
390387 Lit :: Int ( _) => Some ( quote ! ( ( #expr as i128 ) ) ) ,
@@ -662,22 +659,26 @@ mod tests {
662659 use super :: * ;
663660
664661 #[ test]
665- fn none_object_default_is_lazy_and_typed ( ) {
666- let field: Field = parse_quote ! {
667- #[ pyarg( any, default = None ) ]
668- value: PyObjectRef
669- } ;
670- let tokens = generate_field ( ( 0 , & field) ) . unwrap ( ) . to_string ( ) ;
671- let fallback = tokens. find ( "unwrap_or_else" ) . unwrap ( ) ;
672- let none = tokens. find ( "vm . ctx . none ()" ) . unwrap ( ) ;
673- assert ! ( fallback < none) ;
674- assert ! ( tokens. contains( "TryFromObject > :: try_from_object" ) ) ;
675- let attr = ArgAttribute :: try_from ( & field) . unwrap ( ) ;
676- let repr = repr_path ( ) ;
677- assert_eq ! (
678- signature_default( & field, & attr) . unwrap( ) . to_string( ) ,
679- quote!( Some ( #repr:: None ) ) . to_string( )
680- ) ;
662+ fn option_none_default_keeps_rust_value_and_metadata ( ) {
663+ let types: [ Type ; 2 ] = [
664+ parse_quote ! ( Option <PyObjectRef >) ,
665+ parse_quote ! ( Option <PyStrRef >) ,
666+ ] ;
667+ for ty in types {
668+ let field: Field = parse_quote ! {
669+ #[ pyarg( any, default = None ) ]
670+ value: #ty
671+ } ;
672+ let tokens = generate_field ( ( 0 , & field) ) . unwrap ( ) . to_string ( ) ;
673+ assert ! ( tokens. contains( & quote!( unwrap_or_else( || None ) ) . to_string( ) ) ) ;
674+ assert ! ( !tokens. contains( "vm . ctx . none" ) ) ;
675+ let attr = ArgAttribute :: try_from ( & field) . unwrap ( ) ;
676+ let repr = repr_path ( ) ;
677+ assert_eq ! (
678+ signature_default( & field, & attr) . unwrap( ) . to_string( ) ,
679+ quote!( Some ( #repr:: None ) ) . to_string( )
680+ ) ;
681+ }
681682 }
682683
683684 #[ test]
@@ -699,12 +700,9 @@ mod tests {
699700 }
700701
701702 #[ test]
702- fn literal_object_defaults_preserve_conversion ( ) {
703+ fn none_is_not_a_python_object_literal ( ) {
703704 for expr in [ parse_quote ! ( None ) , parse_quote ! ( ( None ) ) ] {
704- assert_eq ! (
705- literal_object_expr( & expr) . unwrap( ) . to_string( ) ,
706- quote!( vm. ctx. none( ) ) . to_string( )
707- ) ;
705+ assert ! ( literal_object_expr( & expr) . is_none( ) ) ;
708706 }
709707 for expr in [
710708 parse_quote ! ( "text" ) ,
@@ -717,13 +715,11 @@ mod tests {
717715 ) ;
718716 }
719717 let field: Field = parse_quote ! {
720- #[ pyarg( any, default = None ) ]
718+ #[ pyarg( any, default = "text" ) ]
721719 value: PyStrRef
722720 } ;
723- // A typed object still validates the default through its converter;
724- // None must not be transmuted or treated as a missing sentinel.
725721 let tokens = generate_field ( ( 0 , & field) ) . unwrap ( ) . to_string ( ) ;
726722 assert ! ( tokens. contains( "< PyStrRef as :: rustpython_vm :: convert :: TryFromObject >" ) ) ;
727- assert ! ( tokens. contains( "vm . ctx . none () " ) ) ;
723+ assert ! ( ! tokens. contains( "vm . ctx . none" ) ) ;
728724 }
729725}
0 commit comments