util: add new module for reading and writing toml
The toml module situation in Python is a bit of a mess. Different distro versions have different modules packaged or built-in, sometimes with different capabilities (no writing). Since we need to support reading and writing toml files both on the host (osbuild internals, sources, inputs) and in the build root (stages), let's centralise the import decision making in an internal utility module that covers all cases. Two of the modules we might import (tomli and tomllib) don't support writing, so we need to either import a separate module (tomli_w) or raise an exception when dump() is called without a write-capable module. The tomli and tomllib modules require files be opened in binary mode (not text) while the others require text mode. So we can't wrap the toml.load() and toml.dump() functions directly; the caller doesn't know which module it will be using. Let's keep track of the mode based on which import succeeded and have our functions open the files as needed. The wrapper functions are named load_from_file() and dump_to_file() to avoid confusion with the load() and dump() functions that take a file object. See also #1847
This commit is contained in:
parent
347c0dec4a
commit
94cdcecafb
1 changed files with 62 additions and 0 deletions
62
osbuild/util/toml.py
Normal file
62
osbuild/util/toml.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
"""
|
||||
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
|
||||
|
||||
# Different modules require different file mode (text vs binary)
|
||||
toml_modules = {
|
||||
"tomllib": "rb", # stdlib since 3.11 (read-only)
|
||||
"tomli": "rb", # EL9+
|
||||
"toml": "r", # older unmaintained lib, needed for backwards compatibility with existing EL9 and Fedora manifests
|
||||
"pytoml": "r", # deprecated, needed for backwards compatibility (EL8 manifests)
|
||||
}
|
||||
|
||||
|
||||
toml = None
|
||||
rmode: str = None
|
||||
for module, mode in toml_modules.items():
|
||||
try:
|
||||
toml = importlib.import_module(module)
|
||||
rmode = mode
|
||||
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": "wb", # EL9+
|
||||
"toml": "w", # older unmaintained lib, needed for backwards compatibility with existing EL9 and Fedora manifests
|
||||
"pytoml": "w", # deprecated, needed for backwards compatibility (EL8 manifests)
|
||||
}
|
||||
|
||||
|
||||
tomlw = None
|
||||
wmode: str = None
|
||||
for module, mode in tomlw_modules.items():
|
||||
try:
|
||||
tomlw = importlib.import_module(module)
|
||||
wmode = mode
|
||||
break
|
||||
except ModuleNotFoundError:
|
||||
# allow importing without write support
|
||||
pass
|
||||
|
||||
|
||||
def load_from_file(path):
|
||||
with open(path, rmode) as tomlfile:
|
||||
return toml.load(tomlfile)
|
||||
|
||||
|
||||
def dump_to_file(data, path, pre=None):
|
||||
if tomlw is None:
|
||||
raise RuntimeError("no toml module available with write support")
|
||||
|
||||
with open(path, wmode) as tomlfile:
|
||||
if pre:
|
||||
tomlfile.write(pre)
|
||||
|
||||
tomlw.dump(data, tomlfile)
|
||||
Loading…
Add table
Add a link
Reference in a new issue