~jconti/recent-notifications/trunk

« back to all changes in this revision

Viewing changes to unity/Config.py

  • Committer: Jason Conti
  • Date: 2011-04-24 20:48:00 UTC
  • Revision ID: jason.conti@gmail.com-20110424204800-znrodggqqte9nvxb
Ported Config.py to the unity app, promoting it to a proper GObject in the process, so value changes are handled by signals instead of calling functions. Adding a basic set of tests for the new Config class. Adding __init__.py to unity to make it a proper module for testing (will need renaming later). Changed the edge radius to 5px for the message icon.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Config.py
 
3
February 13, 2011
 
4
updated: April 24, 2011
 
5
 
 
6
Reads and writes config files in a simple (key = value) or just (key) for boolean
 
7
properties, and notifies listeners when the values are changed.
 
8
"""
 
9
 
 
10
import errno
 
11
import logging
 
12
import os
 
13
 
 
14
from gi.repository import GObject
 
15
from threading import Lock
 
16
 
 
17
logger = logging.getLogger("Config")
 
18
 
 
19
class ConfigException(Exception):
 
20
  pass
 
21
 
 
22
class Config(GObject.GObject):
 
23
  """A config file"""
 
24
  __gsignals__ = {
 
25
      "value-changed": (GObject.SignalFlags.RUN_LAST, None, [str, str])
 
26
  }
 
27
  def __init__(self, path):
 
28
    GObject.GObject.__init__(self)
 
29
 
 
30
    self._path = os.path.expanduser(path)
 
31
    self._options = {}
 
32
    self._lock = Lock()
 
33
 
 
34
    self.load()
 
35
 
 
36
  def __contains__(self, key):
 
37
    """Returns true if this config has the given key."""
 
38
    return key in self._options
 
39
 
 
40
  def __iter__(self):
 
41
    """Returns an iterator over the keys of this Config object."""
 
42
    return iter(self._options)
 
43
 
 
44
  def load(self):
 
45
    """Loads a config file, if it exists."""
 
46
    try:
 
47
      f = open(self._path, "r")
 
48
    except:
 
49
      logger.warning("Failed to open config file: {0}".format(self._path))
 
50
      self._options = {}
 
51
      return
 
52
 
 
53
    try:
 
54
      line_number = 1
 
55
      for line in f:
 
56
        # Skip blank lines
 
57
        if line.strip() == "":
 
58
          continue
 
59
 
 
60
        item = line.split("=", 1)
 
61
        
 
62
        key = item[0].strip()
 
63
        if len(item) == 1:
 
64
          value = True
 
65
        else:
 
66
          value = item[1].strip()
 
67
 
 
68
        # Empty key
 
69
        if key == "":
 
70
          raise ConfigException("Empty key on line {0}: {1}".format(line_number, line.strip()))
 
71
 
 
72
        self._options[key] = value
 
73
        self.emit("value-changed", key, value)
 
74
        line_number += 1
 
75
    except:
 
76
      logger.exception("Error reading config file: {0}".format(self._path))
 
77
      self._options = {}
 
78
 
 
79
  def save(self):
 
80
    """Saves the config file, creating the destination directory if necessary."""
 
81
    # Create the destination directory
 
82
    dirname = os.path.dirname(self._path)
 
83
    try:
 
84
      os.makedirs(dirname, 0700)
 
85
    except os.error as e:
 
86
      if e.errno != errno.EEXIST:
 
87
        logger.error("Failed to create directory: {0}".format(dirname))
 
88
        return
 
89
 
 
90
    with open(self._path, "w") as f:
 
91
      for key, value in self._options.items():
 
92
        f.write("{0} = {1}\n".format(key, value))
 
93
 
 
94
  def get(self, key, default = ""):
 
95
    """Returns the value of the given key, or the default value."""
 
96
    if key in self._options:
 
97
      return self._options[key]
 
98
    else:
 
99
      return default
 
100
 
 
101
  def get_bool(self, key, default = False):
 
102
    """Returns the value of the given key as a boolean, or the default value if it fails
 
103
    to convert or does not exist."""
 
104
    if key not in self._options:
 
105
      return default
 
106
    value = self._options[key]
 
107
    if value == True or value == "True":
 
108
      return True
 
109
    elif value == False or value == "False":
 
110
      return False
 
111
    else:
 
112
      return default
 
113
 
 
114
  def get_int(self, key, default = 0):
 
115
    """Returns this value of the given key as an int, or the default value if it fails to
 
116
    convert or does not exist."""
 
117
    if key not in self._options:
 
118
      return default
 
119
    value = self._options[key]
 
120
    try:
 
121
      return int(value)
 
122
    except:
 
123
      return default
 
124
 
 
125
  def set(self, key, value):
 
126
    """Sets the value for the given key, saves the config file and notifies any
 
127
    listeners that the value has changed."""
 
128
    if not (isinstance(key, str) or isinstance(key, unicode)):
 
129
      raise ConfigException("Trying to set a non-string key: {0} = {1}".format(key, value))
 
130
 
 
131
    key = key.strip()
 
132
    if key == "":
 
133
      raise ConfigException("Trying to set empty key to value: {0}".format(value))
 
134
 
 
135
    with self._lock:
 
136
      self._options[key] = value
 
137
      self.save()
 
138
    self.emit("value-changed", key, value)
 
139
 
 
140
  def set_if_unset(self, key, value):
 
141
    """Calls set(key, value) only if the key does not exist in this config."""
 
142
    if key not in self._options:
 
143
      self.set(key, value)
 
144