@@ -13,8 +13,11 @@ use std::{
1313 fmt:: { Display , Formatter } ,
1414} ;
1515use pyo3:: {
16- exceptions:: { PyFileNotFoundError , PyPermissionError } ,
17- intern, prelude:: * , sync:: PyOnceLock ,
16+ exceptions:: { PyFileNotFoundError , PyValueError , PyPermissionError } ,
17+ intern,
18+ prelude:: * ,
19+ types:: PyDict ,
20+ sync:: PyOnceLock ,
1821} ;
1922
2023pub mod colors;
@@ -35,6 +38,8 @@ pub enum Error {
3538 FileNotFoundError ,
3639 /// Permission denied to access or create the filesystem path.
3740 PermissionError ,
41+ /// Indicate that the argument is an inappropriate value.
42+ ValueError ( String ) ,
3843 /// Other Python errors.
3944 Python ( PyErr ) ,
4045}
@@ -53,6 +58,8 @@ If you use Anaconda, see https://github.com/PyO3/pyo3/issues/1554"),
5358 Error :: PermissionError =>
5459 write ! ( f, "Permission denied to access or create the \
5560 filesystem path") ,
61+ Error :: ValueError ( msg) =>
62+ write ! ( f, "ValueError: {}" , msg) ,
5663 Error :: Python ( e) =>
5764 write ! ( f, "Python error: {}" , e) ,
5865 }
@@ -61,7 +68,8 @@ If you use Anaconda, see https://github.com/PyO3/pyo3/issues/1554"),
6168
6269impl std:: error:: Error for Error { }
6370
64- /// Conversion from `PyErr` to `Error` (requires the Python handle).
71+ /// Conversion from `PyErr` to `Error`.
72+ // It requires the Python handle, so the `Into` trait cannot be used.
6573trait IntoError {
6674 type T ;
6775 fn into_error ( self , py : Python < ' _ > ) -> Result < Self :: T , Error > ;
@@ -76,6 +84,9 @@ impl<T> IntoError for Result<T, PyErr> {
7684 Error :: FileNotFoundError
7785 } else if e. is_instance_of :: < PyPermissionError > ( py) {
7886 Error :: PermissionError
87+ } else if e. is_instance_of :: < PyValueError > ( py) {
88+ let msg = e. value ( py) . str ( ) . unwrap ( ) ;
89+ Error :: ValueError ( msg. to_string_lossy ( ) . into_owned ( ) )
7990 } else {
8091 Error :: Python ( e)
8192 }
@@ -99,38 +110,76 @@ impl From<&ImportError> for Error {
99110/// in [`rcsetup`].
100111#[ derive( Debug ) ]
101112pub struct RcParams {
102- dict : Py < PyAny > ,
113+ rc : Py < PyDict > ,
103114}
104115
116+ pub trait RcParamsValue {
117+ fn into_py < ' py > ( & self , py : Python < ' py > ) -> impl IntoPyObject < ' py > ;
118+ }
119+
120+ impl RcParamsValue for & str {
121+ fn into_py < ' py > ( & self , _py : Python < ' py > ) -> impl IntoPyObject < ' py > {
122+ self
123+ }
124+ }
125+
126+ impl RcParamsValue for usize {
127+ fn into_py < ' py > ( & self , _py : Python < ' py > ) -> impl IntoPyObject < ' py > {
128+ self
129+ }
130+ }
131+
132+ impl RcParamsValue for f64 {
133+ fn into_py < ' py > ( & self , _py : Python < ' py > ) -> impl IntoPyObject < ' py > {
134+ self
135+ }
136+ }
137+
138+ // TODO: Make more types implement `RcParamsValue`.
139+
105140impl RcParams {
141+ pub fn get ( & self , key : & str ) -> Option < Py < PyAny > > {
142+ Python :: attach ( |py| {
143+ self . rc . bind ( py) . get_item ( key)
144+ . unwrap ( )
145+ . map ( |o| o. unbind ( ) )
146+ } )
147+ }
148+
149+ pub fn set < ' py > ( & self , key : & str , value : impl RcParamsValue ) -> Result < ( ) , Error > {
150+ Python :: attach ( |py| -> Result < _ , Error > {
151+ self . rc . bind ( py) . set_item ( key, value. into_py ( py) )
152+ . into_error ( py)
153+ } )
154+ }
155+
106156 /// Return the subset of the `self` dictionary whose keys match
107157 /// ([`using
108158 /// re.search()`](https://docs.python.org/3/library/re.html#re.search)) the
109159 /// given pattern.
110160 pub fn find_all ( & self , pat : & str ) -> Vec < String > {
111161 Python :: attach ( |py| {
112- self . dict . bind ( py)
162+ self . rc . bind ( py)
113163 . call_method1 ( intern ! ( py, "find_all" ) , ( pat, ) ) . unwrap ( )
114164 . cast ( ) . unwrap ( )
115165 . extract ( ) . unwrap ( )
116166 } )
117167 }
118168}
119169
120- pub fn rcsetup ( ) {
121- todo ! ( )
122- }
123-
124- #[ derive( Debug ) ]
125- pub struct RcParamsRef < ' a > {
126- dict : & ' a Bound < ' a , PyAny > ,
127- }
128-
129- fn rc_params ( py : Python < ' _ > ) -> RcParamsRef < ' _ > {
130- static RCPARAMS : PyOnceLock < Py < PyAny > > = PyOnceLock :: new ( ) ;
131- let dict = RCPARAMS . import ( py, "matplotlib" , "rcParams" )
132- . expect ( "Cannot find matplotlib.rcParams" ) ;
133- RcParamsRef { dict }
170+ pub fn rc_params ( ) -> & ' static RcParams {
171+ static RCPARAMS : PyOnceLock < RcParams > = PyOnceLock :: new ( ) ;
172+ Python :: attach ( |py| {
173+ RCPARAMS . get_or_init ( py, || {
174+ let rc = py. import ( "matplotlib" )
175+ . expect ( "Cannot find matplotlib" )
176+ . getattr ( "rcParams" )
177+ . expect ( "Cannot find matplotlib.rcParams" )
178+ . cast_into :: < PyDict > ( ) . unwrap ( ) ;
179+ RcParams { rc : rc. unbind ( ) }
180+ } ) ;
181+ RCPARAMS . get ( py) . unwrap ( )
182+ } )
134183}
135184
136185
0 commit comments