1414# Authors:
1515# Tristan Van Berkom <tristan.vanberkom@codethink.co.uk>
1616
17+ import sys
1718import tempfile
1819from typing import Callable , Generator
1920import os
@@ -264,7 +265,9 @@ def foreach_parent(parent):
264265 # modify_element_function (Callable[[CommentedMap],None]): A function to modify a given CommentedMap
265266 #
266267 @contextmanager
267- def temporary_modified_element (self ,target :str ,modify_element_function :Callable [[CommentedMap ],None ]) -> Generator [None , None , None ]:
268+ def temporary_modified_element (
269+ self , target : str , modify_element_function : Callable [[CommentedMap ], None ]
270+ ) -> Generator [None , None , None ]:
268271
269272 _ , target_name , target_loader = self ._parse_name (target , MappingNode .from_dict ({}))
270273
@@ -273,16 +276,18 @@ def temporary_modified_element(self,target:str,modify_element_function:Callable[
273276
274277 modify_element_function (target_node )
275278
276- with tempfile .NamedTemporaryFile (
279+ # FIXME When 3.12 hits EOL, replace this with tempfile.NamedTemporaryFile itself.
280+ with _legacy_named_temporary_file_delete_on_close (
277281 delete_on_close = False , prefix = f"{ target_name .replace ('/' ,'_' )} _temp" , suffix = ".bst"
278282 ) as temp_target_file :
279283 _yaml .roundtrip_dump (target_node , temp_target_file )
280284 temp_target_file .close () # delete_on_close is false so this doesn't remove the file, but delete is True(default) so we delete the file when we leave the context manager.
281285 target_loader ._set_fullpath_override (target_name , temp_target_file .name )
282286
283- yield
284-
285- target_loader ._set_fullpath_override (target_name ,None )
287+ try :
288+ yield
289+ finally :
290+ target_loader ._set_fullpath_override (target_name , None )
286291
287292 ###########################################
288293 # Private Methods #
@@ -1141,3 +1146,30 @@ def _clean_caches(self):
11411146
11421147 self ._meta_elements = {}
11431148 self ._elements = {}
1149+
1150+
1151+ # _legacy_named_temporary_file_delete_on_close()
1152+ #
1153+ # Helper for python 3.10 and 3.11 support
1154+ #
1155+ # NamedTemporaryFile attribute `delete_on_close=False` was not added until 3.12
1156+ #
1157+ # FIXME: When 3.11 hits end of life remove this function.
1158+ #
1159+ @contextmanager
1160+ def _legacy_named_temporary_file_delete_on_close (delete_on_close = False , prefix = None , suffix = None ):
1161+
1162+ assert not delete_on_close , "Don't use this function unless you explicitly need delete_on_close set to false"
1163+ if sys .version_info >= (3 , 12 ):
1164+ # Use the `delete_on_close` attribute if it's available
1165+ yield tempfile .NamedTemporaryFile (delete_on_close = delete_on_close , prefix = prefix , suffix = suffix )
1166+ else :
1167+ # Otherwise implement it for ourselves.
1168+ file = tempfile .NamedTemporaryFile (prefix = prefix , suffix = suffix , delete = False )
1169+ try :
1170+ yield file
1171+ finally :
1172+ try :
1173+ os .unlink (file .name )
1174+ except OSError :
1175+ pass
0 commit comments