@@ -46,25 +46,33 @@ pub type PyResult<T> = Result<T, PyErr>;
4646#[ derive( Debug ) ]
4747pub struct DowncastError < ' a , ' py > {
4848 from : Borrowed < ' a , ' py , PyAny > ,
49- to : Cow < ' static , str > ,
49+ to : TypeNameOrValue < ' py > ,
5050}
5151
5252impl < ' a , ' py > DowncastError < ' a , ' py > {
5353 /// Create a new `PyDowncastError` representing a failure to convert the object
5454 /// `from` into the type named in `to`.
5555 pub fn new ( from : & ' a Bound < ' py , PyAny > , to : impl Into < Cow < ' static , str > > ) -> Self {
56- DowncastError {
56+ Self {
5757 from : from. as_borrowed ( ) ,
58- to : to. into ( ) ,
58+ to : TypeNameOrValue :: Name ( to. into ( ) ) ,
5959 }
6060 }
61+
6162 pub ( crate ) fn new_from_borrowed (
6263 from : Borrowed < ' a , ' py , PyAny > ,
6364 to : impl Into < Cow < ' static , str > > ,
6465 ) -> Self {
65- DowncastError {
66+ Self {
67+ from,
68+ to : TypeNameOrValue :: Name ( to. into ( ) ) ,
69+ }
70+ }
71+
72+ pub ( crate ) fn new_from_type ( from : Borrowed < ' a , ' py , PyAny > , to : Bound < ' py , PyType > ) -> Self {
73+ Self {
6674 from,
67- to : to . into ( ) ,
75+ to : TypeNameOrValue :: Value ( to ) ,
6876 }
6977 }
7078}
@@ -73,16 +81,23 @@ impl<'a, 'py> DowncastError<'a, 'py> {
7381#[ derive( Debug ) ]
7482pub struct DowncastIntoError < ' py > {
7583 from : Bound < ' py , PyAny > ,
76- to : Cow < ' static , str > ,
84+ to : TypeNameOrValue < ' py > ,
7785}
7886
7987impl < ' py > DowncastIntoError < ' py > {
8088 /// Create a new `DowncastIntoError` representing a failure to convert the object
8189 /// `from` into the type named in `to`.
8290 pub fn new ( from : Bound < ' py , PyAny > , to : impl Into < Cow < ' static , str > > ) -> Self {
83- DowncastIntoError {
91+ Self {
8492 from,
85- to : to. into ( ) ,
93+ to : TypeNameOrValue :: Name ( to. into ( ) ) ,
94+ }
95+ }
96+
97+ pub ( crate ) fn new_from_type ( from : Bound < ' py , PyAny > , to : Bound < ' py , PyType > ) -> Self {
98+ Self {
99+ from,
100+ to : TypeNameOrValue :: Value ( to) ,
86101 }
87102 }
88103
@@ -95,6 +110,11 @@ impl<'py> DowncastIntoError<'py> {
95110 }
96111}
97112
113+ // Helper to store either a concrete type or a type name
114+ enum TypeNameOrValue < ' py > {
115+ Name ( Cow < ' static , str > ) ,
116+ Value ( Bound < ' py , PyType > ) ,
117+ }
98118/// Helper conversion trait that allows to use custom arguments for lazy exception construction.
99119pub trait PyErrArguments : Send + Sync {
100120 /// Arguments for exception
@@ -721,25 +741,33 @@ impl<'py> IntoPyObject<'py> for &PyErr {
721741
722742struct PyDowncastErrorArguments {
723743 from : Py < PyType > ,
724- to : Cow < ' static , str > ,
744+ to : OwnedTypeNameOrValue ,
725745}
726746
727747impl PyErrArguments for PyDowncastErrorArguments {
728748 fn arguments ( self , py : Python < ' _ > ) -> Py < PyAny > {
729- const FAILED_TO_EXTRACT : Cow < ' _ , str > = Cow :: Borrowed ( "<failed to extract type name>" ) ;
730749 let from = self . from . bind ( py) . qualname ( ) ;
731- let from = match & from {
732- Ok ( qn) => qn. to_cow ( ) . unwrap_or ( FAILED_TO_EXTRACT ) ,
733- Err ( _) => FAILED_TO_EXTRACT ,
750+ let from = from
751+ . as_ref ( )
752+ . map ( |name| name. to_string_lossy ( ) )
753+ . unwrap_or ( Cow :: Borrowed ( "<failed to extract type name>" ) ) ;
754+ let to = match self . to {
755+ OwnedTypeNameOrValue :: Name ( name) => TypeNameOrValue :: Name ( name) ,
756+ OwnedTypeNameOrValue :: Value ( t) => TypeNameOrValue :: Value ( t. into_bound ( py) ) ,
734757 } ;
735- format ! ( "'{}' object cannot be converted to '{}'" , from, self . to)
758+ format ! ( "'{}' object cannot be converted to '{}'" , from, to)
736759 . into_pyobject ( py)
737760 . unwrap ( )
738761 . into_any ( )
739762 . unbind ( )
740763 }
741764}
742765
766+ enum OwnedTypeNameOrValue {
767+ Name ( Cow < ' static , str > ) ,
768+ Value ( Py < PyType > ) ,
769+ }
770+
743771/// Python exceptions that can be converted to [`PyErr`].
744772///
745773/// This is used to implement [`From<Bound<'_, T>> for PyErr`].
@@ -763,7 +791,10 @@ impl std::convert::From<DowncastError<'_, '_>> for PyErr {
763791 fn from ( err : DowncastError < ' _ , ' _ > ) -> PyErr {
764792 let args = PyDowncastErrorArguments {
765793 from : err. from . get_type ( ) . into ( ) ,
766- to : err. to ,
794+ to : match err. to {
795+ TypeNameOrValue :: Name ( name) => OwnedTypeNameOrValue :: Name ( name) ,
796+ TypeNameOrValue :: Value ( t) => OwnedTypeNameOrValue :: Value ( t. into ( ) ) ,
797+ } ,
767798 } ;
768799
769800 exceptions:: PyTypeError :: new_err ( args)
@@ -783,7 +814,10 @@ impl std::convert::From<DowncastIntoError<'_>> for PyErr {
783814 fn from ( err : DowncastIntoError < ' _ > ) -> PyErr {
784815 let args = PyDowncastErrorArguments {
785816 from : err. from . get_type ( ) . into ( ) ,
786- to : err. to ,
817+ to : match err. to {
818+ TypeNameOrValue :: Name ( name) => OwnedTypeNameOrValue :: Name ( name) ,
819+ TypeNameOrValue :: Value ( t) => OwnedTypeNameOrValue :: Value ( t. into ( ) ) ,
820+ } ,
787821 } ;
788822
789823 exceptions:: PyTypeError :: new_err ( args)
@@ -801,7 +835,7 @@ impl std::fmt::Display for DowncastIntoError<'_> {
801835fn display_downcast_error (
802836 f : & mut std:: fmt:: Formatter < ' _ > ,
803837 from : & Bound < ' _ , PyAny > ,
804- to : & str ,
838+ to : & TypeNameOrValue < ' _ > ,
805839) -> std:: fmt:: Result {
806840 write ! (
807841 f,
@@ -811,6 +845,25 @@ fn display_downcast_error(
811845 )
812846}
813847
848+ impl std:: fmt:: Debug for TypeNameOrValue < ' _ > {
849+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
850+ std:: fmt:: Display :: fmt ( self , f)
851+ }
852+ }
853+
854+ impl std:: fmt:: Display for TypeNameOrValue < ' _ > {
855+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
856+ match self {
857+ Self :: Name ( name) => name. fmt ( f) ,
858+ Self :: Value ( t) => t
859+ . qualname ( )
860+ . map_err ( |_| std:: fmt:: Error ) ?
861+ . to_string_lossy ( )
862+ . fmt ( f) ,
863+ }
864+ }
865+ }
866+
814867#[ track_caller]
815868pub fn panic_after_error ( _py : Python < ' _ > ) -> ! {
816869 unsafe {
0 commit comments