-
Notifications
You must be signed in to change notification settings - Fork 5
/
usersettings.py
106 lines (94 loc) · 4.17 KB
/
usersettings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/usr/bin/python
"""
Provide interface for persistent portable editable user settings
"""
import os
try:
import ConfigParser
except ImportError:
import configparser as ConfigParser
import ast
import appdirs
class Settings(dict):
""" Provide interface for portable persistent user editable settings """
app_id = None
settings_directory = None
settings_file = None
_settings_types = {}
_settings_defaults = {}
def __init__(self, app_id):
"""
Create the settings object, using the specified app id (a reversed rfc
1034 identifier, e.g. com.example.apps.thisapp
"""
self.app_id = app_id
self.settings_directory = appdirs.user_data_dir(
app_id, appauthor=app_id, roaming=True
)
self.settings_file = os.path.join(self.settings_directory, "settings.cfg")
super(Settings, self).__init__()
def add_setting(self, setting_name, setting_type=str, default=None):
""" Define a settings option (and default value) """
self._settings_types[setting_name] = setting_type
self._settings_defaults[setting_name] = default
def load_settings(self):
""" Set default values and parse stored settings file """
# Set the defaults
for key, value in self._settings_defaults.items():
if key not in self._settings_types:
self._settings_types[key] = str
super(Settings, self).__setitem__(key, value)
# Load the stored values
parser = ConfigParser.RawConfigParser()
try:
with open(self.settings_file, "r") as settings_fp:
parser.readfp(settings_fp)
for key, value in parser.items("settings"):
if key not in self._settings_types:
self._settings_types[key] = str
adjusted_value = value
# There are some special helper functions in ConfigParser
# for ints, floats, and booleans.
if issubclass(self._settings_types[key], bool):
# This needs to appear before int
adjusted_value = parser.getboolean("settings", key)
elif issubclass(self._settings_types[key], int):
adjusted_value = parser.getint("settings", key)
elif issubclass(self._settings_types[key], float):
adjusted_value = parser.getfloat("settings", key)
elif issubclass(self._settings_types[key], (dict, list, set)):
adjusted_value = self._settings_types[key](
ast.literal_eval(value)
)
else:
adjusted_value = self._settings_types[key](value)
super(Settings, self).__setitem__(key, adjusted_value)
except IOError:
# No config file exists, or it is invalid
pass
def save_settings(self):
""" Write the settings data to disk """
if not os.path.exists(self.settings_directory):
os.makedirs(self.settings_directory, 0o755)
parser = ConfigParser.RawConfigParser()
parser.add_section("settings")
for key, value in self.items():
parser.set("settings", key, value)
with open(self.settings_file, "w") as settings_fp:
parser.write(settings_fp)
def __getattr__(self, setting_name):
""" Provide attribute-based access to stored config data """
try:
return super(Settings, self).__getitem__(setting_name)
except KeyError:
raise AttributeError
def __setattr__(self, setting_name, setting_value):
""" Provide attribute-based access to stored config data """
if setting_name in self._settings_defaults:
# This value will go to the internal dict
try:
return super(Settings, self).__setitem__(setting_name, setting_value)
except KeyError:
raise AttributeError
# This value will be an attribute of self
return super(Settings, self).__setattr__(setting_name, setting_value)