Changes between Initial Version and Version 1 of PythonScriptForParsingSettings


Ignore:
Timestamp:
Jan 27, 2006, 2:11:05 AM (18 years ago)
Author:
limodou@…
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • PythonScriptForParsingSettings

    v1 v1  
     1{{{
     2#   Programmer: limodou
     3#   E-mail:     limodou@gmail.com
     4#
     5#   Copyleft 2006 limodou
     6#
     7#   Distributed under the terms of the GPL (GNU Public License)
     8#
     9#   NewEdit is free software; you can redistribute it and/or modify
     10#   it under the terms of the GNU General Public License as published by
     11#   the Free Software Foundation; either version 2 of the License, or
     12#   (at your option) any later version.
     13#
     14#   This program is distributed in the hope that it will be useful,
     15#   but WITHOUT ANY WARRANTY; without even the implied warranty of
     16#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17#   GNU General Public License for more details.
     18#
     19#   You should have received a copy of the GNU General Public License
     20#   along with this program; if not, write to the Free Software
     21#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     22#
     23#   version 0.1
     24#   This program is used for parsing settings.py. So it has many limits.
     25#   It has some features:
     26#    *  Remaining comments in settings, including comments in tuple. And if the
     27#       comments in tuple data type, they should be nearby the first '(' or the
     28#       last ')', other comments will be lost.
     29#    *  You can delete a key, but when you save the settings, the key will be
     30#       comment but not be really delete
     31#    *  You can also get a comment key, and if you set a new value to it,
     32#       the key will be uncomment. Or you can also remove the key object's delete flag
     33#       to uncomment the key, just like:
     34#       
     35#       obj = ini.get_obj('KEY')
     36#       obj.delete = False
     37#    *  If the value is value, DjangoIni will read it as list, so you can deal with
     38#       the key as a list. But when it's saved, it'll be automaticaly converted to tuple,
     39#       just keeping the same type in settings.py
     40#    *  The instance of DjangoIni acts as a dict object, so you can do like:
     41#       from DjangoIni import DjangoIni
     42#       ini = DjangoIni('settings.py')
     43#       ini['KEY']              if a key has been delete, so it'll complain a KeyError Exception
     44#       ini.get('KEY', defaultvalue)    if a key has been delete, it'll also can be returned
     45#       ini.keys()              omit the key deleted
     46#       ini.has_key('KEY')      omit the key deleted
     47#       ini.get_obj('KEY')      can also get a delete obj
     48#       ini.save(filename or fileobj)   saving the result to file
     49#
     50
     51import codecs
     52import copy
     53import re
     54import os
     55import sys
     56
     57r_line = re.compile(r'(\w+)\s+=\s*([^#]+)')
     58
     59class DeleteException(Exception):pass
     60
     61class Node:
     62    def __init__(self, parent, key, old_value, lines, span=None, new=False, delete=False):
     63        self.parent = parent
     64        self.key = key
     65        self.value = copy.deepcopy(old_value)
     66        self.old_value = copy.deepcopy(old_value)
     67        self.lines = lines
     68        self.delete = delete
     69        self.new = new
     70        self.span = span
     71
     72    def render(self):
     73        if self.lines[0] == -1:     #new
     74            if isinstance(self.value, (tuple, list)):
     75                line = []
     76                line.append('%s = (')
     77                for i in self.value:
     78                    line.append(' '*4 + repr(i) + ',')
     79                line.append(')')
     80            else:
     81                line = ['%s = %r' % (self.key, self.value)]
     82        else:
     83            if len(self.lines) == 1:
     84                line = self.parent.get_lines(self.lines[0])
     85                b, e = self.span
     86                line = ["%s = %r" % (self.key, self.value) + line[e:]]
     87            else:
     88                b, e = self.lines
     89                line = [self.parent.get_lines(b)]
     90                has_more = False
     91                for j in self.parent.get_lines(b+1, e-1):
     92                    if j.strip().startswith('#'):
     93                        line.append(j)
     94                    else:
     95                        has_more = True
     96                        break
     97                for i in self.value:
     98                    line.append(' '*4 + repr(i) + ',')
     99                line.append(')')
     100               
     101                if has_more:
     102                    lines = self.parent.get_lines(b+1, e-1)
     103                    lines.reverse()
     104                    for j in lines:
     105                        if j.strip().startswith('#'):
     106                            line.insert(len(line)-1, j)
     107                        else:
     108                            break
     109               
     110        if self.delete:
     111            if self.new:
     112                return None
     113            else:
     114                return ['#'+x for x in line]
     115        return line
     116       
     117class DjangoIni(object):
     118    def __init__(self, filename='', encoding='utf-8'):
     119        self._items = {}
     120        self._orders = {}
     121        self._id = 0
     122        self._max_id = 99999
     123        self._lines = []
     124        self.filename = filename
     125        self.read(self.filename)
     126       
     127    def _add_order(self, key):
     128        self._id += 1
     129        self._orders[key] = self._id
     130   
     131    def _add_max_order(self, key):
     132        self._max_id += 1
     133        self._orders[key] = self._max_id
     134
     135    def read(self, filename, encoding='utf-8'):
     136        if not filename:
     137            return
     138       
     139        dir = os.path.dirname(filename)
     140        sys.path.insert(0, dir)
     141        mod = __import__(os.path.splitext(os.path.basename(filename))[0])
     142        sys.path.pop(0)
     143        f = codecs.open(filename, encoding=encoding)
     144        i = 0
     145        for line in f:
     146            line = line.rstrip()
     147            self._lines.append(line)    #saving all lines
     148            if line.startswith('#'):
     149                deleteflag = True
     150                line = line[1:]
     151            else:
     152                deleteflag = False
     153            b = r_line.search(line)
     154            if b:
     155                self._lines[-1] = line
     156                key, value = b.groups()
     157                lines = [i]
     158                x, y = b.span(2)
     159                if deleteflag:
     160                    x = x + 1
     161                value = value.strip()
     162                obj = Node(self, key, value, lines, span=(0, x+len(value)), delete=deleteflag)
     163                self._items[key] = obj
     164                self._add_order(key)
     165                if value == '(':
     166                    s = ['(']
     167                    while 1:
     168                        line = f.next().rstrip()
     169                        if line.startswith('#') and deleteflag:
     170                            line = line[1:]
     171                        self._lines.append(line)
     172                        i += 1
     173                        if line != ')':
     174                            t = line.lstrip()
     175                            if not t.startswith('#'):
     176                                s.append(line)
     177                        else:
     178                            obj.old_value = s
     179                            obj.value = [x.strip()[:-1] for x in s if not x.strip().startswith('#')]
     180                            lines.append(i+1)
     181                            s.append(')')
     182                            value = ''.join(s)
     183                            break
     184                else:
     185                    if value and value[0] in ("'", '"'):
     186                        ch = value[0]
     187                        pp = [ch]
     188                        line_iter = iter(line[x+1:])
     189                        for j in line_iter:
     190                            if j == '\\':
     191                                pp.append(j)
     192                                j = line_iter.next()
     193                                pp.append(j)
     194                            elif j == ch:
     195                                pp.append(j)
     196                                break
     197                            else:
     198                                pp.append(j)
     199                        value = ''.join(pp)
     200                        obj.span = (0, x + len(value))
     201                           
     202                if hasattr(mod, key):
     203                    obj.value = getattr(mod, key)
     204                else:
     205                    obj.value = eval(value)
     206                if isinstance(obj.value, tuple):
     207                    obj.value = list(obj.value)
     208            i += 1
     209           
     210    def get_lines(self, start, end=-1):
     211        if end <= start:
     212            return self._lines[start]
     213        else:
     214            return self._lines[start:end]
     215                       
     216    def out(self):
     217        a = [(value, key) for key, value in self._orders.items()]
     218        a.sort()
     219        for i, key in a:
     220            print key, self._items[key].value, self._items[key].lines
     221           
     222    def __setitem__(self, name, value):
     223        obj = self._items.get(name, None)
     224        if not obj:
     225            obj = Node(self, name, value, [-1], new=True)
     226            self._items[name] = obj
     227            self._add_max_order(name)
     228        else:
     229            if obj.delete:
     230                obj.delete = False   
     231            obj.value = value
     232           
     233    def __getitem__(self, name):
     234        obj = self._items.get(name, None)
     235        if obj:
     236            if obj.delete:
     237                raise DeleteException, 'The value has been deleted!'
     238            else:
     239                return obj.value
     240        else:
     241            raise KeyError, name
     242       
     243    def __delitem__(self, name):
     244        """set an item's delete flag, so the result will be commented in .py file"""
     245        obj = self._items.get(name, None)
     246        if obj:
     247            obj.delete = True
     248        else:
     249            raise KeyError, name
     250       
     251    def get(self, name, defaultvalue):
     252        """Get an item, but also can get deleted item"""
     253        obj = self._items.get(name, None)
     254        if obj:
     255            return obj.value
     256        else:
     257            return defaultvalue
     258       
     259    def get_obj(self, name):
     260        """Get an item, but also can get deleted item"""
     261        obj = self._items.get(name, None)
     262        if obj:
     263            return obj
     264        else:
     265            raise KeyError, name
     266       
     267    def keys(self):
     268        return self._items.keys()
     269   
     270    def values(self):
     271        return [obj.value for obj in self.items.values()]
     272   
     273    def has_key(self, name):
     274        return self._items.has_key(name)
     275   
     276    def save(self, filename=None, encoding='utf-8'):
     277        if not filename:
     278            filename = self.filename
     279        a = [(value, key) for key, value in self._orders.items()]
     280        a.sort()
     281
     282        k = 0
     283        s = []
     284        last = []
     285        for i, key in a:
     286            obj = self._items[key]
     287            b = obj.lines[0]
     288            while k < b:
     289                s.append(self.get_lines(k))
     290                k += 1
     291            if len(obj.lines) == 1:
     292                b = obj.lines[0]
     293                if b == -1:
     294                    last.extend(obj.render())
     295                else:
     296                    s.extend(obj.render())
     297                    k = b + 1
     298            else:
     299                b, e = obj.lines
     300                s.extend(obj.render())
     301                k = e
     302        s.extend(last)
     303
     304        if isinstance(filename, (str, unicode)):
     305            f = codecs.open(filename, 'w', encoding)
     306            f.write('\n'.join(s))
     307            f.close()
     308        else:
     309            filename.write('\n'.join(s))
     310           
     311if __name__ == '__main__':
     312    ini = DjangoIni('settings.py')
     313    print ini.keys()
     314    print ini['LANGUAGE_CODE']
     315    ini['ADMINS'].append(('limodou', 'limodou@gmail.com'))
     316    ini['DATABASE_ENGINE'] = ''
     317    ini['DEBUG'] = False
     318    ini['NEW'] = 'This is test'
     319#    ini.save('t.py')
     320    print '-----------------------------------------------'
     321    ini.save(sys.stdout)
     322}}}
Back to Top