mirror of
https://github.com/Farama-Foundation/Gymnasium.git
synced 2025-08-26 16:27:11 +00:00
56 lines
1.9 KiB
Python
56 lines
1.9 KiB
Python
# Based on http://stackoverflow.com/questions/2333872/atomic-writing-to-file-with-python
|
|
|
|
import os
|
|
from contextlib import contextmanager
|
|
|
|
# We would ideally atomically replace any existing file with the new
|
|
# version. However, on Windows there's no Python-only solution prior
|
|
# to Python 3.3. (This library includes a C extension to do so:
|
|
# https://pypi.python.org/pypi/pyosreplace/0.1.)
|
|
#
|
|
# Correspondingly, we make a best effort, but on Python < 3.3 use a
|
|
# replace method which could result in the file temporarily
|
|
# disappearing.
|
|
import sys
|
|
if sys.version_info >= (3, 3):
|
|
# Python 3.3 and up have a native `replace` method
|
|
from os import replace
|
|
elif sys.platform.startswith("win"):
|
|
def replace(src, dst):
|
|
# TODO: on Windows, this will raise if the file is in use,
|
|
# which is possible. We'll need to make this more robust over
|
|
# time.
|
|
try:
|
|
os.remove(dst)
|
|
except OSError:
|
|
pass
|
|
os.rename(src, dst)
|
|
else:
|
|
# POSIX rename() is always atomic
|
|
from os import rename as replace
|
|
|
|
@contextmanager
|
|
def atomic_write(filepath, binary=False, fsync=False):
|
|
""" Writeable file object that atomically updates a file (using a temporary file). In some cases (namely Python < 3.3 on Windows), this could result in an existing file being temporarily unlinked.
|
|
|
|
:param filepath: the file path to be opened
|
|
:param binary: whether to open the file in a binary mode instead of textual
|
|
:param fsync: whether to force write the file to disk
|
|
"""
|
|
|
|
tmppath = filepath + '~'
|
|
while os.path.isfile(tmppath):
|
|
tmppath += '~'
|
|
try:
|
|
with open(tmppath, 'wb' if binary else 'w') as file:
|
|
yield file
|
|
if fsync:
|
|
file.flush()
|
|
os.fsync(file.fileno())
|
|
replace(tmppath, filepath)
|
|
finally:
|
|
try:
|
|
os.remove(tmppath)
|
|
except (IOError, OSError):
|
|
pass
|