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

Revision 756, 8.1 KB checked in by aspidites, 8 years ago (diff)

Patch by Aspidites:

+ maps load properly once again
+ obsoleted get/set methods in settings.py

  • pc speed is no longer set, so walk speed is unbearably slow
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        return self.__dict__[option]
81
82    def options(self):
83        """ Returns a dictionary of existing options """
84        options = self.__dict__
85        # get rid of properties that aren't actually options
86        if options.has_key('name'):
87            options.pop('name')
88
89        return options.keys()
90
91#TODO: remember config filenames/paths
92#TODO: remove hard-coded settings filename/path
93class Settings(object):
94    """ An object that represents a settings file, its sectons,
95        and the options defined within those sections.
96    """
97    def __init__(self, *filenames):
98        """ initializes a new settings object.
99
100            @param filenames: Either a string representing a filename or a list
101                of such strings. If a single string is given, settings
102                sections and options are simply read from it. If a list is given,
103                each file is parsed sequentially with the next file's options
104                taking precedence over the previous one's. Consider:
105                    files = ['foo.cfg' ,'bar.cfg']
106                    config = Config(files)
107                First, foo.cfg is read, then, if similar options in bar.cfg exist,
108                they overwrite the ones previously set by foo.cfg.
109            @type filenames: either a string or list
110            @ivar config_file: Python object representing the settings
111                file. Its purpose is to preserve the order of each section and
112                its options on read and write.
113            @type config_file: list
114        """
115
116        self.config_file = ''
117
118        if hasattr(filenames, 'split'):
119            self.read(filenames)
120        else:
121            for filename in filenames:
122                self.read(filename)
123
124    def __getattr__(self, name):
125        """ Returns a Section object to be used for assignment, creating one
126            if it doesn't exist.
127
128            @param name: name of section to be retrieved
129            @type name: string
130        """
131        if name in ['get', 'set']:
132            raise AttributeError("{0} is not a valid method. Please consult "
133                                 "Settings' documentation for a list of "
134                                 " available methods.".format(name))
135        else:
136            if not self.__dict__.has_key(name):
137                setattr(self, name, Section(name))
138
139        return getattr(self, name)
140
141    def read(self, filename):
142        """ Reads a settings file and populates the settings object
143            with its sections and options.
144
145            @param filename: name of file to be parsed.
146            @type filename: string
147        """
148        section = None
149        try:
150            self.config_file = open(filename, 'r').readlines()
151        except IOError:
152            pass
153
154        for line in self.config_file:
155            if line.startswith('#') or line.strip() == '':
156                continue
157            elif line.startswith('[') and line.endswith(']\n'):
158                getattr(self, line[1:-2])
159                section = line[1:-2]
160            else:
161                option, value = [item.strip()
162                                 for item in line.split('=', 1)]
163
164                setattr(getattr(self, section), option, value)
165
166    def write(self, filename):
167        """ Writes a settings file based on the settings object's
168            sections and options
169
170            @param filename: name of file to save to
171            @type filename: string
172        """
173        for section in self.sections():
174            if '[{0}]\n'.format(section) not in self.config_file:
175                self.config_file.append('\n[{0}]\n'.format(section))
176                for option, value in getattr(self, section).options().iteritems():
177                    template = '{0} = {1}\n'.format(option, value)
178                    self.config_file.append(template)
179            else:
180                start_of_section = (self.config_file
181                                        .index('[{0}]\n'.format(section)) + 1)
182                for option, value in getattr(self, 
183                                             section).options().iteritems():
184
185                    if hasattr(value, 'sort'):
186                        value = '[{0}]'.format(', '.join(value))
187
188                    new_option = False
189                    template = '{0} = {1}\n'.format(option, value)
190                    for index, line in enumerate(self.config_file[:]):
191                        if option in line:
192                            new_option = False
193                            self.config_file[index] = template
194                            break
195                        else:
196                            new_option = True
197                    if new_option:
198                        self.config_file.insert(start_of_section, template)
199
200        with open(filename, 'w') as out_stream:
201            for line in self.config_file:
202                out_stream.write(line)
203
204    def sections(self):
205        """ Returns a list of existing sections"""
206        sections = self.__dict__.keys()
207        sections.pop(sections.index('config_file'))
208        return sections
Note: See TracBrowser for help on using the repository browser.