@@ -165,32 +165,34 @@ def safe_markdown(value: Any) -> str:
165
165
_PRECOMPILED_TOKEN_PATTERN = re .compile (r"{{ .+? }}|{% .+? %}" )
166
166
167
167
168
- def _find_next_extends (template : str ) :
168
+ def _find_next_extends (template : bytes ) -> "re.Match[bytes]" :
169
169
return _PRECOMPILED_EXTENDS_PATTERN .search (template )
170
170
171
171
172
- def _find_next_block (template : str ) :
172
+ def _find_next_block (template : bytes ) -> "re.Match[bytes]" :
173
173
return _PRECOMPILED_BLOCK_PATTERN .search (template )
174
174
175
175
176
- def _find_next_include (template : str ) :
176
+ def _find_next_include (template : bytes ) -> "re.Match[bytes]" :
177
177
return _PRECOMPILED_INCLUDE_PATTERN .search (template )
178
178
179
179
180
- def _find_named_endblock (template : str , name : str ):
181
- return re .search (r"{% endblock " + name + r" %}" , template )
180
+ def _find_named_endblock (template : bytes , name : bytes ) -> "re.Match[bytes]" :
181
+ return re .search (
182
+ r"{% endblock " .encode ("utf-8" ) + name + r" %}" .encode ("utf-8" ), template
183
+ )
182
184
183
185
184
- def _exists_and_is_file (path : str ):
186
+ def _exists_and_is_file (path : str ) -> bool :
185
187
try :
186
188
return (os .stat (path )[0 ] & 0b_11110000_00000000 ) == 0b_10000000_00000000
187
189
except OSError :
188
190
return False
189
191
190
192
191
- def _resolve_includes (template : str ) :
193
+ def _resolve_includes (template : bytes ) -> bytes :
192
194
while (include_match := _find_next_include (template )) is not None :
193
- template_path = include_match .group (0 )[12 :- 4 ]
195
+ template_path = include_match .group (0 )[12 :- 4 ]. decode ( "utf-8" )
194
196
195
197
# TODO: Restrict include to specific directory
196
198
@@ -201,19 +203,19 @@ def _resolve_includes(template: str):
201
203
with open (template_path , "rt" , encoding = "utf-8" ) as template_file :
202
204
template = (
203
205
template [: include_match .start ()]
204
- + template_file .read ()
206
+ + template_file .read (). encode ( "utf-8" )
205
207
+ template [include_match .end () :]
206
208
)
207
209
return template
208
210
209
211
210
- def _check_for_unsupported_nested_blocks (template : str ):
212
+ def _check_for_unsupported_nested_blocks (template : bytes ):
211
213
if _find_next_block (template ) is not None :
212
214
raise ValueError ("Nested blocks are not supported" )
213
215
214
216
215
- def _resolve_includes_blocks_and_extends (template : str ) :
216
- block_replacements : "dict[str, str ]" = {}
217
+ def _resolve_includes_blocks_and_extends (template : bytes ) -> bytes :
218
+ block_replacements : "dict[bytes, bytes ]" = {}
217
219
218
220
# Processing nested child templates
219
221
while (extends_match := _find_next_extends (template )) is not None :
@@ -223,7 +225,7 @@ def _resolve_includes_blocks_and_extends(template: str):
223
225
with open (
224
226
extended_template_name , "rt" , encoding = "utf-8"
225
227
) as extended_template_file :
226
- extended_template = extended_template_file .read ()
228
+ extended_template = extended_template_file .read (). encode ( "utf-8" )
227
229
228
230
# Removed the extend tag
229
231
template = template [extends_match .end () :]
@@ -240,18 +242,13 @@ def _resolve_includes_blocks_and_extends(template: str):
240
242
if endblock_match is None :
241
243
raise ValueError (r"Missing {% endblock %} for block: " + block_name )
242
244
243
- # Workaround for bug in re module https://github.com/adafruit/circuitpython/issues/6860
244
- block_content = template .encode ("utf-8" )[
245
- block_match .end () : endblock_match .start ()
246
- ].decode ("utf-8" )
247
- # TODO: Uncomment when bug is fixed
248
- # block_content = template[block_match.end() : endblock_match.start()]
245
+ block_content = template [block_match .end () : endblock_match .start ()]
249
246
250
247
_check_for_unsupported_nested_blocks (block_content )
251
248
252
249
if block_name in block_replacements :
253
250
block_replacements [block_name ] = block_replacements [block_name ].replace (
254
- r"{{ block.super }}" , block_content
251
+ r"{{ block.super }}" . encode ( "utf-8" ) , block_content
255
252
)
256
253
else :
257
254
block_replacements .setdefault (block_name , block_content )
@@ -268,14 +265,16 @@ def _resolve_includes_blocks_and_extends(template: str):
268
265
return _replace_blocks_with_replacements (template , block_replacements )
269
266
270
267
271
- def _replace_blocks_with_replacements (template : str , replacements : "dict[str, str]" ):
268
+ def _replace_blocks_with_replacements (
269
+ template : bytes , replacements : "dict[bytes, bytes]"
270
+ ) -> bytes :
272
271
# Replace blocks in top-level template
273
272
while (block_match := _find_next_block (template )) is not None :
274
273
block_name = block_match .group (0 )[9 :- 3 ]
275
274
276
275
# Self-closing block tag without default content
277
276
if (endblock_match := _find_named_endblock (template , block_name )) is None :
278
- replacement = replacements .get (block_name , "" )
277
+ replacement = replacements .get (block_name , "" . encode ( "utf-8" ) )
279
278
280
279
template = (
281
280
template [: block_match .start ()]
@@ -300,7 +299,7 @@ def _replace_blocks_with_replacements(template: str, replacements: "dict[str, st
300
299
# Replace default content with replacement
301
300
else :
302
301
replacement = replacements [block_name ].replace (
303
- r"{{ block.super }}" , block_content
302
+ r"{{ block.super }}" . encode ( "utf-8" ) , block_content
304
303
)
305
304
306
305
template = (
@@ -312,15 +311,15 @@ def _replace_blocks_with_replacements(template: str, replacements: "dict[str, st
312
311
return template
313
312
314
313
315
- def _find_next_hash_comment (template : str ) :
314
+ def _find_next_hash_comment (template : bytes ) -> "re.Match[bytes]" :
316
315
return _PRECOMPILED_HASH_COMMENT_PATTERN .search (template )
317
316
318
317
319
- def _find_next_block_comment (template : str ) :
318
+ def _find_next_block_comment (template : bytes ) -> "re.Match[bytes]" :
320
319
return _PRECOMPILED_BLOCK_COMMENT_PATTERN .search (template )
321
320
322
321
323
- def _remove_comments (template : str ) :
322
+ def _remove_comments (template : bytes ) -> bytes :
324
323
# Remove hash comments: {# ... #}
325
324
while (comment_match := _find_next_hash_comment (template )) is not None :
326
325
template = template [: comment_match .start ()] + template [comment_match .end () :]
@@ -332,7 +331,7 @@ def _remove_comments(template: str):
332
331
return template
333
332
334
333
335
- def _find_next_token (template : str ) :
334
+ def _find_next_token (template : bytes ) -> "re.Match[bytes]" :
336
335
return _PRECOMPILED_TOKEN_PATTERN .search (template )
337
336
338
337
@@ -344,6 +343,10 @@ def _create_template_function( # pylint: disable=,too-many-locals,too-many-bran
344
343
context_name : str = "context" ,
345
344
dry_run : bool = False ,
346
345
) -> "Generator[str] | str" :
346
+ # Workaround for bug in re module https://github.com/adafruit/circuitpython/issues/6860
347
+ # TODO: Remove .encode() and .decode() when bug is fixed
348
+ template : bytes = template .encode ("utf-8" )
349
+
347
350
# Resolve includes, blocks and extends
348
351
template = _resolve_includes_blocks_and_extends (template )
349
352
@@ -360,10 +363,10 @@ def _create_template_function( # pylint: disable=,too-many-locals,too-many-bran
360
363
361
364
# Resolve tokens
362
365
while (token_match := _find_next_token (template )) is not None :
363
- token = token_match .group (0 )
366
+ token : str = token_match .group (0 ). decode ( "utf-8" )
364
367
365
368
# Add the text before the token
366
- if text_before_token := template [: token_match .start ()]:
369
+ if text_before_token := template [: token_match .start ()]. decode ( "utf-8" ) :
367
370
function_string += (
368
371
indent * indentation_level + f"yield { repr (text_before_token )} \n "
369
372
)
@@ -452,9 +455,11 @@ def _create_template_function( # pylint: disable=,too-many-locals,too-many-bran
452
455
# Continue with the rest of the template
453
456
template = template [token_match .end () :]
454
457
455
- # Add the text after the last token (if any) and return
458
+ # Add the text after the last token (if any)
456
459
if template :
457
- function_string += indent * indentation_level + f"yield { repr (template )} \n "
460
+ function_string += (
461
+ indent * indentation_level + f"yield { repr (template .decode ('utf-8' ))} \n " #
462
+ )
458
463
459
464
# If dry run, return the template function string
460
465
if dry_run :
0 commit comments