Atomically save prefs.yaml to prevent file corruption

This adds a dependency on the atomicwrites package. Note that it was
already a transitive dev-dependency, but is now a direct dependency as
well.

On Linux, atomicwrites fsyncs the directory after saving. This is
unnecessary for consistency after a system crash, and slows down program
shutdown slightly. But I'm too lazy to vendor or rewrite the library to
not fsync the directory.
pull/377/head
nyanpasu64 2021-06-13 20:39:57 -07:00
rodzic 9b97221001
commit 50349d6eac
4 zmienionych plików z 10 dodań i 10 usunięć

Wyświetl plik

@ -19,6 +19,7 @@ from typing import (
Any, Any,
TextIO, TextIO,
Union, Union,
IO,
) )
import attr import attr
@ -64,10 +65,6 @@ class MyYAML(YAML):
with stream.open("w", encoding="utf-8") as f: with stream.open("w", encoding="utf-8") as f:
self.dump_without_corrupting(data, f, **kwargs) self.dump_without_corrupting(data, f, **kwargs)
elif isinstance(stream, TextIO):
# Nobody actually calls dump(..., open()). This branch is never taken.
self.dump_without_corrupting(data, stream, **kwargs)
elif stream is None: elif stream is None:
# Possibly only called in unit tests, not in production. # Possibly only called in unit tests, not in production.
stream = StringIO() stream = StringIO()
@ -75,9 +72,8 @@ class MyYAML(YAML):
return stream.getvalue() return stream.getvalue()
else: else:
raise TypeError( # with atomic_write(...) as f: dump(..., f)
f"stream must be {{Path, TextIO=open(), None}}, but is {type(stream)}" self.dump_without_corrupting(data, stream, **kwargs)
)
def dump_without_corrupting(self, *args, **kwargs): def dump_without_corrupting(self, *args, **kwargs):
YAML.dump(self, *args, **kwargs) YAML.dump(self, *args, **kwargs)

Wyświetl plik

@ -1,5 +1,7 @@
from typing import * from typing import *
from atomicwrites import atomic_write
from corrscope.config import DumpableAttrs, yaml from corrscope.config import DumpableAttrs, yaml
from corrscope.settings import paths from corrscope.settings import paths
@ -50,4 +52,5 @@ def load_prefs() -> GlobalPrefs:
def dump_prefs(pref: GlobalPrefs) -> None: def dump_prefs(pref: GlobalPrefs) -> None:
yaml.dump(pref, _PREF_PATH) with atomic_write(_PREF_PATH, overwrite=True) as f:
yaml.dump(pref, f)

4
poetry.lock wygenerowano
Wyświetl plik

@ -18,7 +18,7 @@ python-versions = "*"
name = "atomicwrites" name = "atomicwrites"
version = "1.4.0" version = "1.4.0"
description = "Atomic file writes." description = "Atomic file writes."
category = "dev" category = "main"
optional = false optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
@ -609,7 +609,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pyt
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.6.2" python-versions = "^3.6.2"
content-hash = "7e4bd31660cb4764c68a7f51487837972530c1426c7902c04ca760d5ef278fa5" content-hash = "bb03d24e8ec7fcbf38ca0726736a7cdcd3e3f38a2ad281f522e3aedce1540bfb"
[metadata.files] [metadata.files]
altgraph = [ altgraph = [

Wyświetl plik

@ -27,6 +27,7 @@ matplotlib = "^3.1"
attrs = "^21.2.0" attrs = "^21.2.0"
PyQt5 = "^5.15.4" PyQt5 = "^5.15.4"
appdirs = "^1.4.4" appdirs = "^1.4.4"
atomicwrites = "^1.4.0"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
pytest = "^6.2.4" pytest = "^6.2.4"