@@ -2,11 +2,12 @@ use std::collections::HashMap;
2
2
use std:: path:: { Path , PathBuf } ;
3
3
4
4
use encoding_rs:: Encoding ;
5
+ use pyo3:: exceptions:: PyUnicodeError ;
5
6
use pyo3:: prelude:: * ;
6
7
7
8
use crate :: template:: django_rusty_templates:: Template ;
8
9
9
- #[ derive( Clone ) ]
10
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
10
11
pub struct LoaderError {
11
12
pub tried : Vec < ( String , String ) > ,
12
13
}
@@ -30,7 +31,11 @@ impl FileSystemLoader {
30
31
}
31
32
}
32
33
33
- fn get_template ( & self , template_name : & str ) -> Result < PyResult < Template > , LoaderError > {
34
+ fn get_template (
35
+ & self ,
36
+ py : Python < ' _ > ,
37
+ template_name : & str ,
38
+ ) -> Result < PyResult < Template > , LoaderError > {
34
39
let mut tried = Vec :: new ( ) ;
35
40
for template_dir in & self . dirs {
36
41
let path = match safe_join ( template_dir, template_name) {
@@ -47,7 +52,13 @@ impl FileSystemLoader {
47
52
continue ;
48
53
}
49
54
} ;
50
- let ( contents, _, _) = self . encoding . decode ( & bytes) ;
55
+ let ( contents, encoding, malformed) = self . encoding . decode ( & bytes) ;
56
+ if malformed {
57
+ return Ok ( Err ( PyUnicodeError :: new_err ( format ! (
58
+ "Could not open {path:?} with {} encoding." ,
59
+ encoding. name( )
60
+ ) ) ) ) ;
61
+ }
51
62
return Ok ( Template :: new ( & contents, path) ) ;
52
63
}
53
64
Err ( LoaderError { tried } )
@@ -57,7 +68,11 @@ impl FileSystemLoader {
57
68
pub struct AppDirsLoader { }
58
69
59
70
impl AppDirsLoader {
60
- fn get_template ( & self , template_name : & str ) -> Result < PyResult < Template > , LoaderError > {
71
+ fn get_template (
72
+ & self ,
73
+ py : Python < ' _ > ,
74
+ template_name : & str ,
75
+ ) -> Result < PyResult < Template > , LoaderError > {
61
76
todo ! ( )
62
77
}
63
78
}
@@ -75,14 +90,18 @@ impl CachedLoader {
75
90
}
76
91
}
77
92
78
- fn get_template ( & mut self , template_name : & str ) -> Result < PyResult < Template > , LoaderError > {
93
+ fn get_template (
94
+ & mut self ,
95
+ py : Python < ' _ > ,
96
+ template_name : & str ,
97
+ ) -> Result < PyResult < Template > , LoaderError > {
79
98
match self . cache . get ( template_name) {
80
99
Some ( Ok ( template) ) => Ok ( Ok ( template. clone ( ) ) ) ,
81
100
Some ( Err ( e) ) => Err ( e. clone ( ) ) ,
82
101
None => {
83
102
let mut tried = Vec :: new ( ) ;
84
103
for loader in & mut self . loaders {
85
- match loader. get_template ( template_name) {
104
+ match loader. get_template ( py , template_name) {
86
105
Ok ( Ok ( template) ) => {
87
106
self . cache
88
107
. insert ( template_name. to_string ( ) , Ok ( template. clone ( ) ) ) ;
@@ -101,15 +120,23 @@ impl CachedLoader {
101
120
pub struct LocMemLoader { }
102
121
103
122
impl LocMemLoader {
104
- fn get_template ( & self , template_name : & str ) -> Result < PyResult < Template > , LoaderError > {
123
+ fn get_template (
124
+ & self ,
125
+ py : Python < ' _ > ,
126
+ template_name : & str ,
127
+ ) -> Result < PyResult < Template > , LoaderError > {
105
128
todo ! ( )
106
129
}
107
130
}
108
131
109
132
pub struct ExternalLoader { }
110
133
111
134
impl ExternalLoader {
112
- fn get_template ( & self , template_name : & str ) -> Result < PyResult < Template > , LoaderError > {
135
+ fn get_template (
136
+ & self ,
137
+ py : Python < ' _ > ,
138
+ template_name : & str ,
139
+ ) -> Result < PyResult < Template > , LoaderError > {
113
140
todo ! ( )
114
141
}
115
142
}
@@ -123,13 +150,75 @@ pub enum Loader {
123
150
}
124
151
125
152
impl Loader {
126
- pub fn get_template ( & mut self , template_name : & str ) -> Result < PyResult < Template > , LoaderError > {
153
+ pub fn get_template (
154
+ & mut self ,
155
+ py : Python < ' _ > ,
156
+ template_name : & str ,
157
+ ) -> Result < PyResult < Template > , LoaderError > {
127
158
match self {
128
- Self :: FileSystem ( loader) => loader. get_template ( template_name) ,
129
- Self :: AppDirs ( loader) => loader. get_template ( template_name) ,
130
- Self :: Cached ( loader) => loader. get_template ( template_name) ,
131
- Self :: LocMem ( loader) => loader. get_template ( template_name) ,
132
- Self :: External ( loader) => loader. get_template ( template_name) ,
159
+ Self :: FileSystem ( loader) => loader. get_template ( py , template_name) ,
160
+ Self :: AppDirs ( loader) => loader. get_template ( py , template_name) ,
161
+ Self :: Cached ( loader) => loader. get_template ( py , template_name) ,
162
+ Self :: LocMem ( loader) => loader. get_template ( py , template_name) ,
163
+ Self :: External ( loader) => loader. get_template ( py , template_name) ,
133
164
}
134
165
}
135
166
}
167
+
168
+ #[ cfg( test) ]
169
+ mod tests {
170
+ use super :: * ;
171
+
172
+ #[ test]
173
+ fn test_filesystem_loader ( ) {
174
+ pyo3:: prepare_freethreaded_python ( ) ;
175
+
176
+ Python :: with_gil ( |py| {
177
+ let loader =
178
+ FileSystemLoader :: new ( vec ! [ "tests/templates" . to_string( ) ] , encoding_rs:: UTF_8 ) ;
179
+ let template = loader. get_template ( py, "basic.txt" ) . unwrap ( ) . unwrap ( ) ;
180
+
181
+ assert_eq ! (
182
+ template. filename. unwrap( ) ,
183
+ PathBuf :: from( "tests/templates/basic.txt" )
184
+ ) ;
185
+ } )
186
+ }
187
+
188
+ #[ test]
189
+ fn test_filesystem_loader_missing_template ( ) {
190
+ pyo3:: prepare_freethreaded_python ( ) ;
191
+
192
+ Python :: with_gil ( |py| {
193
+ let loader =
194
+ FileSystemLoader :: new ( vec ! [ "tests/templates" . to_string( ) ] , encoding_rs:: UTF_8 ) ;
195
+ let error = loader. get_template ( py, "missing.txt" ) . unwrap_err ( ) ;
196
+
197
+ assert_eq ! (
198
+ error,
199
+ LoaderError {
200
+ tried: vec![ (
201
+ "tests/templates/missing.txt" . to_string( ) ,
202
+ "Source does not exist" . to_string( ) ,
203
+ ) ] ,
204
+ } ,
205
+ ) ;
206
+ } )
207
+ }
208
+
209
+ #[ test]
210
+ fn test_filesystem_loader_invalid_encoding ( ) {
211
+ pyo3:: prepare_freethreaded_python ( ) ;
212
+
213
+ Python :: with_gil ( |py| {
214
+ let loader =
215
+ FileSystemLoader :: new ( vec ! [ "tests/templates" . to_string( ) ] , encoding_rs:: UTF_8 ) ;
216
+ let error = loader. get_template ( py, "invalid.txt" ) . unwrap ( ) . unwrap_err ( ) ;
217
+
218
+ assert_eq ! (
219
+ error. to_string( ) ,
220
+ "UnicodeError: Could not open \" tests/templates/invalid.txt\" with UTF-8 encoding."
221
+ ) ;
222
+ } )
223
+ }
224
+ }
0 commit comments