debian-forge/osbuild/util/toml.py
2024-08-21 19:26:31 +02:00

78 lines
2.3 KiB
Python

"""
Utility functions for reading and writing toml files.
Handles module imports for all supported versions (in a build root or on a host).
"""
import importlib
from types import ModuleType
from typing import Optional
# Different modules require different file mode (text vs binary)
_toml_modules = {
"tomllib": {"mode": "rb"}, # stdlib since 3.11 (read-only)
"tomli": {"mode": "rb"}, # EL9+
"toml": {"mode": "r", "encoding": "utf-8"}, # older unmaintained lib, needed for backwards compatibility
"pytoml": {"mode": "r", "encoding": "utf-8"}, # deprecated, needed for backwards compatibility (EL8 manifests)
}
_toml: Optional[ModuleType] = None
_rargs: dict = {}
for module, args in _toml_modules.items():
try:
_toml = importlib.import_module(module)
_rargs = args
break
except ModuleNotFoundError:
pass
else:
raise ModuleNotFoundError("No toml module found: " + ", ".join(_toml_modules))
# Different modules require different file mode (text vs binary)
_tomlw_modules = {
"tomli_w": {"mode": "wb"}, # EL9+
"toml": {"mode": "w", "encoding": "utf-8"}, # older unmaintained lib, needed for backwards compatibility
"pytoml": {"mode": "w", "encoding": "utf-8"}, # deprecated, needed for backwards compatibility (EL8 manifests)
}
_tomlw: Optional[ModuleType] = None
_wargs: dict = {}
for module, args in _tomlw_modules.items():
try:
_tomlw = importlib.import_module(module)
_wargs = args
break
except ModuleNotFoundError:
# allow importing without write support
pass
def load_from_file(path):
if _toml is None:
raise RuntimeError("no toml module available")
with open(path, **_rargs) as tomlfile: # pylint: disable=unspecified-encoding
return _toml.load(tomlfile)
def dump_to_file(data, path, header=""):
if _tomlw is None:
raise RuntimeError("no toml module available with write support")
with open(path, **_wargs) as tomlfile: # pylint: disable=unspecified-encoding
if header:
_write_comment(tomlfile, header)
_tomlw.dump(data, tomlfile)
def _write_comment(f, comment: list):
if not comment:
return
data = "\n".join(map(lambda c: f"# {c}", comment)) + "\n\n"
if "b" in f.mode:
f.write(data.encode())
else:
f.write(data)