Version 2 (modified by 18 years ago) ( diff ) | ,
---|
{{{ --------------------------------(((((((((((ARE YOU READY ))))))))))-------------------------------------- # Programmer: limodou # E-mail: limodou@… # # Copyleft 2006 limodou # # Distributed under the terms of the GPL (GNU Public License) # # NewEdit is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # version 0.1 # This program is used for parsing settings.py. So it has many limits. # It has some features: # * Remaining comments in settings, including comments in tuple. And if the # comments in tuple data type, they should be nearby the first '(' or the # last ')', other comments will be lost. # * You can delete a key, but when you save the settings, the key will be # comment but not be really delete # * You can also get a comment key, and if you set a new value to it, # the key will be uncomment. Or you can also remove the key object's delete flag # to uncomment the key, just like: # # obj = ini.get_obj('KEY') # obj.delete = False # * If the value is value, DjangoIni will read it as list, so you can deal with # the key as a list. But when it's saved, it'll be automaticaly converted to tuple, # just keeping the same type in settings.py # * The instance of DjangoIni acts as a dict object, so you can do like: # from DjangoIni import DjangoIni # ini = DjangoIni('settings.py') # iniKEY if a key has been delete, so it'll complain a KeyError Exception # ini.get('KEY', defaultvalue) if a key has been delete, it'll also can be returned # ini.keys() omit the key deleted # ini.has_key('KEY') omit the key deleted # ini.get_obj('KEY') can also get a delete obj # ini.save(filename or fileobj) saving the result to file #
import codec import copy import re import os import sys
r_line = re.compile(r'(\w+)\s+=\s*([#]+)')
class DeleteException(Exception):pass
class Node:
def init(self, parent, key, old_value, lines, span=None, new=False, delete=False):
self.parent = parent self.key = key self.value = copy.deepcopy(old_value) self.old_value = copy.deepcopy(old_value) self.lines = lines self.delete = delete self.new = new self.span = span
def render(self):
if self.lines[0] == -1: #new
if isinstance(self.value, (tuple, list)):
line = [] line.append('%s = (') for i in self.value:
line.append(' '*4 + repr(i) + ',')
line.append(')')
else:
line = % (self.key, self.value)
else:
if len(self.lines) == 1:
line = self.parent.get_lines(self.lines[0]) b, e = self.span line = % (self.key, self.value) + line[e:]
else:
b, e = self.lines line = [self.parent.get_lines(b)] has_more = False for j in self.parent.get_lines(b+1, e-1):
if j.strip().startswith('#'):
line.append(j)
else:
has_more = True break
for i in self.value:
line.append(' '*4 + repr(i) + ',')
line.append(')')
if has_more:
lines = self.parent.get_lines(b+1, e-1) lines.reverse() for j in lines:
if j.strip().startswith('#'):
line.insert(len(line)-1, j)
else:
break
if self.delete:
if self.new:
return None
else:
return ['#'+x for x in line]
return line
class DjangoIni(object):
def init(self, filename=, encoding='utf-8'):
self._items = {} self._orders = {} self._id = 0 self._max_id = 99999 self._lines = [] self.filename = filename self.read(self.filename)
def _add_order(self, key):
self._id += 1 self._orders[key] = self._id
def _add_max_order(self, key):
self._max_id += 1 self._orders[key] = self._max_id
def read(self, filename, encoding='utf-8'):
if not filename:
return
dir = os.path.dirname(filename) sys.path.insert(0, dir) mod = import(os.path.splitext(os.path.basename(filename))[0]) sys.path.pop(0) f = codecs.open(filename, encoding=encoding) i = 0 for line in f:
line = line.rstrip() self._lines.append(line) #saving all lines if line.startswith('#'):
deleteflag = True line = line[1:]
else:
deleteflag = False
b = r_line.search(line) if b:
self._lines[-1] = line key, value = b.groups() lines = [i] x, y = b.span(2) if deleteflag:
x = x + 1
value = value.strip() obj = Node(self, key, value, lines, span=(0, x+len(value)), delete=deleteflag) self._items[key] = obj self._add_order(key) if value == '(':
s = ( while 1:
line = f.next().rstrip() if line.startswith('#') and deleteflag:
line = line[1:]
self._lines.append(line) i += 1 if line != ')':
t = line.lstrip() if not t.startswith('#'):
s.append(line)
else:
obj.old_value = s obj.value = [x.strip()[:-1] for x in s if not x.strip().startswith('#')] lines.append(i+1) s.append(')') value = .join(s) break
else:
if value and value[0] in ("'", '"'):
ch = value[0] pp = [ch] line_iter = iter(line[x+1:]) for j in line_iter:
if j == '
':pp.append(j) j = line_iter.next() pp.append(j)
elif j == ch:
pp.append(j) break
else:
pp.append(j)
value = .join(pp) obj.span = (0, x + len(value))
if hasattr(mod, key):
obj.value = getattr(mod, key)
else:
obj.value = eval(value)
if isinstance(obj.value, tuple):
obj.value = list(obj.value)
i += 1
def get_lines(self, start, end=-1):
if end <= start:
return self._lines[start]
else:
return self._lines[start:end]
def out(self):
a = [(value, key) for key, value in self._orders.items()] a.sort() for i, key in a:
print key, self._items[key].value, self._items[key].lines
def setitem(self, name, value):
obj = self._items.get(name, None) if not obj:
obj = Node(self, name, value, [-1], new=True) self._items[name] = obj self._add_max_order(name)
else:
if obj.delete:
obj.delete = False
obj.value = value
def getitem(self, name):
obj = self._items.get(name, None) if obj:
if obj.delete:
raise DeleteException, 'The value has been deleted!'
else:
return obj.value
else:
raise KeyError, name
def delitem(self, name):
"""set an item's delete flag, so the result will be commented in .py file""" obj = self._items.get(name, None) if obj:
obj.delete = True
else:
raise KeyError, name
def get(self, name, defaultvalue):
"""Get an item, but also can get deleted item""" obj = self._items.get(name, None) if obj:
return obj.value
else:
return defaultvalue
def get_obj(self, name):
"""Get an item, but also can get deleted item""" obj = self._items.get(name, None) if obj:
return obj
else:
raise KeyError, name
def keys(self):
return self._items.keys()
def values(self):
return [obj.value for obj in self.items.values()]
def has_key(self, name):
return self._items.has_key(name)
def save(self, filename=None, encoding='utf-8'):
if not filename:
filename = self.filename
a = [(value, key) for key, value in self._orders.items()] a.sort()
k = 0 s = [] last = [] for i, key in a:
obj = self._items[key] b = obj.lines[0] while k < b:
s.append(self.get_lines(k)) k += 1
if len(obj.lines) == 1:
b = obj.lines[0] if b == -1:
last.extend(obj.render())
else:
s.extend(obj.render()) k = b + 1
else:
b, e = obj.lines s.extend(obj.render()) k = e
s.extend(last)
if isinstance(filename, (str, unicode)):
f = codecs.open(filename, 'w', encoding) f.write('\n'.join(s)) f.close()
else:
filename.write('\n'.join(s))
if name == 'main':
ini = DjangoIni('settings.py') print ini.keys() print iniLANGUAGE_CODE iniADMINS.append(('limodou', 'limodou@…')) iniDATABASE_ENGINE = iniDEBUG = False iniNEW = 'This is test'
# ini.save('t.py')
print '-----------------------------------------------' ini.save(sys.stdout)
}}}