source: branches/active/character_customization/game/parpg/settings.py @ 747

Revision 747, 8.9 KB checked in by aspidites, 8 years ago (diff)

Patch by Aspidites:

  • started integrating settings.py into current modules.
Line 
1#   This file is part of PARPG.
2#
3#   PARPG is free software: you can redistribute it and/or modify
4#   it under the terms of the GNU General Public License as published by
5#   the Free Software Foundation, either version 3 of the License, or
6#   (at your option) any later version.
7#
8#   PARPG is distributed in the hope that it will be useful,
9#   but WITHOUT ANY WARRANTY; without even the implied warranty of
10#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11#   GNU General Public License for more details.
12#
13#   You should have received a copy of the GNU General Public License
14#   along with PARPG.  If not, see <http://www.gnu.org/licenses/>.
15
16""" Provides a class used for reading and writing various configurable options
17    throughout the game
18
19    This class produces an INI formated settings file as opposed to an XML
20    formatted one. The reason that python's built-in ConfigurationParser isn't
21    sufficient is because comments aren't preserved when writing a settings
22    file, the order in which the options are written isn't preserved, and the
23    interface used with this class is arguably more convenient that
24    ConfigParser's.
25"""
26
27import os
28
29class Section(object):
30    """ An object that represents a section in a settings file.
31
32        Options can be added to a section by simply assigning a value to an
33            attribute:
34                section.foo = baz
35            would produce:
36                [section]
37                foo = baz
38            in the settings file. Options that do not exist on assignment
39            are created dynamcially.
40    """
41    def __init__(self, name):
42        """ Initialize a new section.
43
44            @param name: name of the section. In the INI file, sections are surrounded
45                by brackets ([name])
46            @type name: string
47        """
48        self.name = name
49
50    def __setattr__(self, option, value):
51        """ Assign a value to an option, converting types when appropriate.
52
53            @param option: name of the option to assign a value to.
54            @type option: string
55            @param value: value to be assigned to the option.
56            @type value: int, float, string, boolean, or list
57        """
58        value = str(value)
59        if value.startswith('[') and value.endswith(']'):
60            value = [item.strip() for item in value[1:-1].split(',')]
61        elif value.lower() == 'true':
62            value = True
63        elif value.lower() == 'false':
64            value = False
65        elif value.isdigit():
66            value = int(value)
67        else:
68            try:
69                value = float(value)
70            except ValueError:
71                # leave as string
72                pass
73
74        self.__dict__[option] = value
75
76    def __getattr__(self, option):
77        """ Retrieve the value of the requested option
78            @param option: name of the option whose value is being requested
79        """
80        try:
81            return self.__dict__[option]
82        except KeyError:
83            return None
84
85    def options(self):
86        """ Returns a dictionary of existing options """
87        options = self.__dict__
88        # get rid of properties that aren't actually options
89        if options.has_key('name'):
90            options.pop('name')
91
92        return options.keys()
93
94#TODO: remember config filenames/paths
95#TODO: remove hard-coded settings filename/path
96class Settings(object):
97    """ An object that represents a settings file, its sectons,
98        and the options defined within those sections.
99    """
100    def __init__(self, *filenames):
101        """ initializes a new settings object.
102
103            @param filenames: Either a string representing a filename or a list
104                of such strings. If a single string is given, settings
105                sections and options are simply read from it. If a list is given,
106                each file is parsed sequentially with the next file's options
107                taking precedence over the previous one's. Consider:
108                    files = ['foo.cfg' ,'bar.cfg']
109                    config = Config(files)
110                First, foo.cfg is read, then, if similar options in bar.cfg exist,
111                they overwrite the ones previously set by foo.cfg.
112            @type filenames: either a string or list
113            @ivar config_file: Python object representing the settings
114                file. Its purpose is to preserve the order of each section and
115                its options on read and write.
116            @type config_file: list
117        """
118
119        self.config_file = ''
120
121        if hasattr(filenames, 'split'):
122            self.read(filenames)
123        else:
124            for filename in filenames:
125                self.read(filename)
126
127    def __getattr__(self, name):
128        """ Returns a Section object to be used for assignment, creating one
129            if it doesn't exist.
130
131            @param name: name of section to be retrieved
132            @type name: string
133        """
134        if not self.__dict__.has_key(name):
135            setattr(self, name, Section(name))
136
137        return getattr(self, name)
138
139    def read(self, filename):
140        """ Reads a settings file and populates the settings object
141            with its sections and options.
142
143            @param filename: name of file to be parsed.
144            @type filename: string
145        """
146        section = None
147        try:
148            self.config_file = open(filename, 'r').readlines()
149        except IOError:
150            pass
151
152        for line in self.config_file:
153            if line.startswith('#') or line.strip() == '':
154                continue
155            elif line.startswith('[') and line.endswith(']\n'):
156                getattr(self, line[1:-2])
157                section = line[1:-2]
158            else:
159                option, value = [item.strip()
160                                 for item in line.split('=', 1)]
161
162                setattr(getattr(self, section), option, value)
163
164    def write(self, filename):
165        """ Writes a settings file based on the settings object's
166            sections and options
167
168            @param filename: name of file to save to
169            @type filename: string
170        """
171        for section in self.sections():
172            if '[{0}]\n'.format(section) not in self.config_file:
173                self.config_file.append('\n[{0}]\n'.format(section))
174                for option, value in getattr(self, section).options().iteritems():
175                    template = '{0} = {1}\n'.format(option, value)
176                    self.config_file.append(template)
177            else:
178                start_of_section = (self.config_file
179                                        .index('[{0}]\n'.format(section)) + 1)
180                for option, value in getattr(self, 
181                                             section).options().iteritems():
182
183                    if hasattr(value, 'sort'):
184                        value = '[{0}]'.format(', '.join(value))
185
186                    new_option = False
187                    template = '{0} = {1}\n'.format(option, value)
188                    for index, line in enumerate(self.config_file[:]):
189                        if option in line:
190                            new_option = False
191                            self.config_file[index] = template
192                            break
193                        else:
194                            new_option = True
195                    if new_option:
196                        self.config_file.insert(start_of_section, template)
197
198        with open(filename, 'w') as out_stream:
199            for line in self.config_file:
200                out_stream.write(line)
201
202    def sections(self):
203        """ Returns a list of existing sections"""
204        sections = self.__dict__.keys()
205        sections.pop(sections.index('config_file'))
206        return sections
207
208    # backward compatibility methods
209    def get(self, section, option, default=None):
210        """ Returns the value of the requested option located in the
211            requested section.
212
213            This method is provided strictly for backwards                   
214            compatibility be deprecated in future versions.
215 
216            @param section: the section in which the option is located in
217            @type section: string
218            @param option: the option being requested
219            @type section: string
220            @param default: the default value to return if a section's option
221                is not defined
222            @type section: any valid object
223        """
224        value = getattr(getattr(self, section), option)
225        if value is None and default is not None:
226            return default
227        else:
228            return value
229
230    def getScreenWidth(self):
231        return self.FIFE.ScreenWidth
232
233    def getScreenHeight(self):
234        return self.FIFE.ScreenHeight
Note: See TracBrowser for help on using the repository browser.