I am writing a Model to read, write and store settings. I think my code is pretty good, but I am not 100% sure. Any advice on how I could possibly improve it is welcome.
import ntpath
import yaml
class Settings:
def __init__(self, paths=None, default_path=None):
"""Load, write and store settings
This model manages setting files (YAML).
Keyword Arguments:
paths {list or None} -- list of full or relative
paths with filenames (default: {None})
default_path {str or None} -- path to user settings, read last
and default for writing
(default: {None})
"""
paths = paths or []
# Make sure paths are unique and sorted by file name
self.paths = sorted(set(paths), key=lambda p: ntpath.basename(p))
# Remove default_path from paths (look at next comment)
try:
self.paths.remove(default_path)
except ValueError:
pass
# Readd default_path at the end to make sure it's loaded last
if default_path is not None:
self.paths.append(default_path)
# Set remaining attributes
self.default_path = default_path
self.settings = {}
# Load files
self.reload()
def reload(self):
"""Reload files into buffer
Reloads the files specified in self.paths
and writes them into the buffer.
"""
# Clear settings to ensure no unwanted leftovers
self.settings.clear()
# Load every path (sorted by filename, self.default_path last)
for path in self.paths:
with open(path, 'r') as f:
content = f.read()
self.settings.update(yaml.load(content) or {})
def write(self, key, value, path=None):
"""Write into file
Writes key and value into the file specified
by path (or self.default_path if None)
Arguments:
key {immutable} -- key to use (valid YAML key)
value {ANY} -- value to save
Keyword Arguments:
path {str} -- path to save file (default: {None})
"""
path = path or self.default_path
assert path is not None
with open(path, 'r') as f:
settings = yaml.load(f.read()) or {}
settings[key] = value
self.settings[key] = value
with open(path, 'w') as f:
f.write(yaml.dump(settings, default_flow_style=False))
2 Answers 2
One thing I found so far is to either rename the attribute "settings" to "buffer" (or something similar), or to make Settings inherit from dict (or better from collections.MutableMapping as suggested here). Doing something like this is awkward:
settings_instance.settings['test_key']
The module should import os.path
instead of ntpath
.
os.path
is the cross-platform equivalent of ntpath
, it automatically picks the appropriate path module for the OS your code is running on. So it will use ntpath
behind the scenes when running on Windows, but you will also be able to use the code on more operating systems than just Windows. (See the note at https://docs.python.org/3/library/os.path.html)
-
\$\begingroup\$ Thank you, I did it that way initially but changed it after reading the accepted answer to this post: stackoverflow.com/questions/8384737/…; Seems as he was wrong? \$\endgroup\$Matthias Schreiber– Matthias Schreiber2016年06月03日 11:33:54 +00:00Commented Jun 3, 2016 at 11:33
-
\$\begingroup\$ @Matthias: That post is dealing with Windows paths specifically. If you must deal with Windows paths, use
ntpath
; if you are dealing with whatever paths are used by the OS your program is run on, useos.path
. You shouldn't be dealing with only Windows paths because you try to open the files. On Linux, you can't open Windows files. Therefore, you should be usingos.path
\$\endgroup\$zondo– zondo2016年06月03日 13:13:39 +00:00Commented Jun 3, 2016 at 13:13