initial add of pycecil
This commit is contained in:
commit
d0b8fdecba
9 changed files with 519 additions and 0 deletions
2
.hgignore
Normal file
2
.hgignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
syntax: glob
|
||||
*.pyc
|
4
buildnum
Normal file
4
buildnum
Normal file
|
@ -0,0 +1,4 @@
|
|||
(S'1.0.0-build'
|
||||
p1
|
||||
I10
|
||||
t.
|
11
cecil/__init__.py
Normal file
11
cecil/__init__.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
|
||||
__doc__ = """
|
||||
Cecil's Python Modules
|
||||
|
||||
Full of awesome little tools that do magic and stuff.
|
||||
""".lstrip()
|
||||
|
||||
__all__ = ["core"]
|
||||
|
||||
import preconfig
|
||||
|
8
cecil/core/__init__.py
Normal file
8
cecil/core/__init__.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
__doc__ = """
|
||||
Core modules from Cecil's library
|
||||
""".lstrip()
|
||||
|
||||
__all__ = ["objproxy", "config"]
|
||||
|
||||
import objproxy, config
|
119
cecil/core/config.py
Normal file
119
cecil/core/config.py
Normal file
|
@ -0,0 +1,119 @@
|
|||
import os, sys
|
||||
import inifile
|
||||
import objproxy
|
||||
from cecil import preconfig
|
||||
|
||||
|
||||
config = objproxy.Proxy({})
|
||||
paths = []
|
||||
filenames = []
|
||||
|
||||
def init(appname=None):
|
||||
global paths, filenames
|
||||
paths = []
|
||||
filenames = []
|
||||
if appname != None:
|
||||
if os.name == 'posix':
|
||||
if 'HOME' in os.environ:
|
||||
paths.append(os.path.join(os.environ['HOME'], appname))
|
||||
paths.append(os.path.join('/etc', appname))
|
||||
filenames.extend([x % (appname) for x in ('%s.conf', '%s.ini', '%s.cfg', '%s.cnf')])
|
||||
|
||||
elif os.name == 'nt':
|
||||
if 'APPDATA' in os.environ:
|
||||
paths.append(os.path.join(os.environ['APPDATA'], appname))
|
||||
if 'LOCALAPPDATA' in os.environ:
|
||||
paths.append(os.path.join(os.environ['LOCALAPPDATA'], appname))
|
||||
filenames.extend([x % (appname) for x in ('%s.ini', '%s.conf', '%s.cfg', '%s.cnf')])
|
||||
|
||||
|
||||
if os.name == 'posix':
|
||||
if 'HOME' in os.environ:
|
||||
paths.append(os.environ['HOME'])
|
||||
paths.append('/etc')
|
||||
|
||||
try:
|
||||
paths.append(os.path.abspath(os.path.dirname(__file__)))
|
||||
except:
|
||||
pass
|
||||
|
||||
if os.name == 'nt':
|
||||
if 'USERPROFILE' in os.environ:
|
||||
paths.append(os.environ['USERPROFILE'])
|
||||
if 'WINDIR' in os.environ:
|
||||
paths.append(os.environ['WINDIR'])
|
||||
if 'SYSTEMDRIVE' in os.environ:
|
||||
paths.append('%s\\' % (os.environ['SYSTEMDRIVE']),)
|
||||
|
||||
try:
|
||||
paths.append(os.path.abspath(os.path.split(os.path.dirname(__file__))[0]))
|
||||
paths.append(os.path.abspath(os.path.dirname(sys.argv[0])))
|
||||
except:
|
||||
pass
|
||||
|
||||
if os.name == 'posix':
|
||||
filenames.extend(['settings.conf', 'settings.ini', 'settings.cfg', 'settings.cnf'])
|
||||
else:
|
||||
filenames.extend(['settings.ini', 'settings.conf', 'settings.cfg', 'settings.cnf'])
|
||||
|
||||
load_config()
|
||||
|
||||
def locate_config(paths, filenames):
|
||||
fd = None
|
||||
for p in paths:
|
||||
for f in filenames:
|
||||
fp = os.path.join(p, f)
|
||||
if os.path.exists(fp):
|
||||
try:
|
||||
fd = inifile.inifile(fp)
|
||||
except None:
|
||||
fd = None
|
||||
return fd
|
||||
|
||||
def load_config(fname=None):
|
||||
global paths, filenames
|
||||
if fname != None:
|
||||
fp, fn = os.path.split(fname)
|
||||
else:
|
||||
fp, fn = None, None
|
||||
|
||||
if fp:
|
||||
pp = [fp]
|
||||
else:
|
||||
pp = paths[:]
|
||||
|
||||
if fn:
|
||||
ff = [fn]
|
||||
else:
|
||||
ff = filenames[:]
|
||||
|
||||
fd = locate_config(pp, ff)
|
||||
if fd != None:
|
||||
config._setobj(fd)
|
||||
|
||||
def save_config(original_name=True, make_path=True):
|
||||
if original_name:
|
||||
fp = config.fname
|
||||
else:
|
||||
saved = False
|
||||
for f in filenames:
|
||||
for p in paths:
|
||||
if make_path:
|
||||
try:
|
||||
os.makedirs(p)
|
||||
except OSError:
|
||||
pass
|
||||
if os.path.exists(p):
|
||||
fp = os.path.join(p, f)
|
||||
config.fname = fp
|
||||
try:
|
||||
config.write()
|
||||
except OSError:
|
||||
continue
|
||||
saved = True
|
||||
break
|
||||
if not saved:
|
||||
raise OSError, "No writable path to save configuration"
|
||||
|
||||
if preconfig.load_config:
|
||||
init(preconfig.appname)
|
226
cecil/core/inifile.py
Normal file
226
cecil/core/inifile.py
Normal file
|
@ -0,0 +1,226 @@
|
|||
# ini reader/writer
|
||||
__doc__ = """
|
||||
reads and writes config files using the microsoft windows 'ini' format.
|
||||
(author's note: I don't think there IS any official 'ini' format. Some
|
||||
artistic licence may have been used)
|
||||
|
||||
Provides class 'inifile', which is a dict-like object that can be read
|
||||
from a file or written out to a file (or both!)
|
||||
"""
|
||||
|
||||
__license__ = """
|
||||
Copyright (c) 2006-2007 Bradley Lawrence <bradley@eltanin.net>
|
||||
|
||||
This is licensed under the Modified BSD License, as follows:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
"""
|
||||
|
||||
|
||||
def sanitize_for_subst(key):
|
||||
"""
|
||||
replaces open and close brackets with tokens, to ensure the brackets
|
||||
do not interfere with the %(dict_key)s string formatting syntax.
|
||||
|
||||
'=' is used as a token delimiter because we know an equals can never
|
||||
appear in a keyname, since it is interpreted by this reader as the
|
||||
end of the key and the start of the value.
|
||||
"""
|
||||
return key.replace('(', '=o=').replace(')', '=c=')
|
||||
|
||||
|
||||
|
||||
|
||||
class inifilesec(dict):
|
||||
def __init__(self, name, owner):
|
||||
self.owner = owner
|
||||
self.name = name
|
||||
self.verbatim_hdr = "[%(sec_title)s]\n"
|
||||
self.verbatim = ["%(=new_data=)s"]
|
||||
self.verbatim_ftr = "\n"
|
||||
self.verbatim_fields = []
|
||||
self.new_fields = []
|
||||
self.initializing = True
|
||||
|
||||
def __getitem__(self, key):
|
||||
lk = key.lower()
|
||||
if lk in self:
|
||||
return dict.__getitem__(self, key.lower())
|
||||
else:
|
||||
raise KeyError, "Section '%s' has no key '%s'" % (self.name, key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if not self.has_key(key.lower()):
|
||||
if self.initializing:
|
||||
self.verbatim_fields += [key]
|
||||
else:
|
||||
self.new_fields += [key]
|
||||
dict.__setitem__(self, key.lower(), value)
|
||||
|
||||
def __delitem__(self, key):
|
||||
dict.__delitem__(self, key.lower())
|
||||
|
||||
|
||||
|
||||
class inifile(dict):
|
||||
def __init__(self, fname, path=None, autoread=True):
|
||||
dict.__init__(self)
|
||||
|
||||
self.fname = fname
|
||||
self.cur_section = None
|
||||
self.verbatim_hdr = []
|
||||
self.section_order = []
|
||||
if autoread:
|
||||
self.read()
|
||||
|
||||
def set_section(self, section):
|
||||
self.cur_section = section.lower()
|
||||
|
||||
def unset_section(self):
|
||||
self.cur_section = None
|
||||
|
||||
def get_current_file(self):
|
||||
return
|
||||
|
||||
def read(self):
|
||||
fd = file(self.fname, 'r')
|
||||
|
||||
act_section = 'default'
|
||||
section_init = False
|
||||
for line in fd:
|
||||
verbatimline = line
|
||||
keyvalue_line = False
|
||||
line = line.lstrip()
|
||||
if not line:
|
||||
# blank line, ignore
|
||||
pass
|
||||
elif line[0] == ';':
|
||||
# comment! ignore
|
||||
pass
|
||||
elif line[0] == '[':
|
||||
# section header
|
||||
line = line.rstrip()
|
||||
if line[-1] == ']':
|
||||
act_section = line[1:-1]
|
||||
section_init = True
|
||||
if not self.has_key(act_section.lower()):
|
||||
"add specified section"
|
||||
actsec = inifilesec(act_section, self)
|
||||
dict.__setitem__(self, act_section.lower(), actsec)
|
||||
#self[act_section.lower()] = actsec
|
||||
actsec.verbatim_hdr = verbatimline
|
||||
actsec.verbatim_ftr = ""
|
||||
verbatimline = None
|
||||
self.section_order += [act_section]
|
||||
else:
|
||||
# garbage line, don't understand it
|
||||
pass
|
||||
else:
|
||||
peq = line.find('=')
|
||||
if peq == -1:
|
||||
# garbage line, don't understand it
|
||||
pass
|
||||
else:
|
||||
k = line[:peq]
|
||||
v = line[peq+1:].rstrip('\n\r')
|
||||
if not self.has_key(act_section.lower()):
|
||||
"add default section"
|
||||
assert not section_init
|
||||
|
||||
actsec = inifilesec('default', self)
|
||||
self[act_section.lower()] = actsec
|
||||
|
||||
|
||||
self[act_section.lower()][k] = v
|
||||
verbatimline = "".join([k, '=%(', sanitize_for_subst(k.lower()), ')s\n'])
|
||||
keyvalue_line = True
|
||||
|
||||
if verbatimline:
|
||||
if section_init or keyvalue_line:
|
||||
"keyvalue lines always go under the default section, regardless of initialized state"
|
||||
actsec = self[act_section.lower()]
|
||||
actsec.verbatim += [verbatimline]
|
||||
else:
|
||||
self.verbatim_hdr += [verbatimline]
|
||||
|
||||
|
||||
if section_init:
|
||||
actsec = self[act_section.lower()]
|
||||
actsec.verbatim += ["\n"]
|
||||
else:
|
||||
self.verbatim_hdr += ["\n"]
|
||||
|
||||
if self.has_key('default'):
|
||||
"has a default section. make sure it's added to the section_order"
|
||||
try:
|
||||
self.section_order.index('default')
|
||||
except:
|
||||
self.section_order += ['default']
|
||||
|
||||
for secdict in self.values():
|
||||
secdict.initializing = False
|
||||
|
||||
def write(self):
|
||||
fd = file(self.fname, 'w')
|
||||
first = True
|
||||
|
||||
fd.write("".join(self.verbatim_hdr))
|
||||
|
||||
for sec in self.section_order:
|
||||
secdict = self[sec.lower()]
|
||||
|
||||
new_lines = []
|
||||
for k in secdict.new_fields:
|
||||
new_lines += ["%s=%s\n" % (k, secdict[k])]
|
||||
new_lines = "".join(new_lines)
|
||||
verbatim_dict = {'=new_data=': new_lines}
|
||||
for k in secdict.verbatim_fields:
|
||||
verbatim_dict[sanitize_for_subst(k.lower())] = secdict[k]
|
||||
|
||||
fd.write(secdict.verbatim_hdr % {'sec_title': secdict.name})
|
||||
fd.write("".join(secdict.verbatim) % verbatim_dict)
|
||||
fd.write(secdict.verbatim_ftr)
|
||||
|
||||
def add_section(self, key):
|
||||
if not self.has_key(key):
|
||||
self[key.lower()] = inifilesec(key, self)
|
||||
self.section_order += [key]
|
||||
|
||||
|
||||
def __getitem__(self, key):
|
||||
if type(key) != str:
|
||||
raise TypeError, "Ini files can only contain string keys"
|
||||
|
||||
if self.cur_section != None:
|
||||
if dict.__getitem__(self, self.cur_section).has_key(key.lower()):
|
||||
return dict.__getitem__(self, self.cur_section)[key.lower()]
|
||||
else:
|
||||
raise KeyError, "Section '%s' does not contain a key named '%s'" % (self.cur_section, key)
|
||||
else:
|
||||
#if not self.has_key(key.lower()):
|
||||
# self[key.lower()] = inifilesec(key, self)
|
||||
return dict.__getitem__(self, key.lower())
|
||||
def __setitem__(self, key, value):
|
||||
if self.cur_section != None:
|
||||
if not self.has_key(self.cur_section):
|
||||
raise KeyError, "Section '%s' does not exist" % (self.cur_section)
|
||||
self[self.cur_section][key.lower()] = value
|
||||
else:
|
||||
raise ValueError, "Cannot set the value of a section header"
|
||||
|
99
cecil/core/objproxy.py
Normal file
99
cecil/core/objproxy.py
Normal file
|
@ -0,0 +1,99 @@
|
|||
|
||||
## {{{ http://code.activestate.com/recipes/496741/ (r1)
|
||||
class Proxy(object):
|
||||
__slots__ = ["_obj", "__weakref__"]
|
||||
_local = {
|
||||
'_setobj':1,
|
||||
'_getobj':1
|
||||
}
|
||||
def __init__(self, obj):
|
||||
object.__setattr__(self, "_obj", obj)
|
||||
|
||||
#
|
||||
# proxying (special cases)
|
||||
#
|
||||
def __getattribute__(self, name):
|
||||
if name in Proxy._local:
|
||||
return object.__getattribute__(self, name)
|
||||
return getattr(object.__getattribute__(self, "_obj"), name)
|
||||
def __delattr__(self, name):
|
||||
delattr(object.__getattribute__(self, "_obj"), name)
|
||||
def __setattr__(self, name, value):
|
||||
setattr(object.__getattribute__(self, "_obj"), name, value)
|
||||
|
||||
def __nonzero__(self):
|
||||
return bool(object.__getattribute__(self, "_obj"))
|
||||
def __str__(self):
|
||||
return str(object.__getattribute__(self, "_obj"))
|
||||
def __repr__(self):
|
||||
return repr(object.__getattribute__(self, "_obj"))
|
||||
def __call__(self, *args, **kwargs):
|
||||
return object.__getattribute__(self, "_obj")(*args, **kwargs)
|
||||
|
||||
def _setobj(self, newobj):
|
||||
newclass = Proxy._get_proxy(newobj)
|
||||
object.__setattr__(self, "_obj", newobj)
|
||||
object.__setattr__(self, "__class__", newclass)
|
||||
|
||||
def _getobj(self):
|
||||
return object.__getattribute__(self, "_obj")
|
||||
|
||||
#
|
||||
# factories
|
||||
#
|
||||
_special_names = [
|
||||
'__abs__', '__add__', '__and__', '__call__', '__cmp__', '__coerce__',
|
||||
'__contains__', '__delitem__', '__delslice__', '__div__', '__divmod__',
|
||||
'__eq__', '__float__', '__floordiv__', '__ge__', '__getitem__',
|
||||
'__getslice__', '__gt__', '__hash__', '__hex__', '__iadd__', '__iand__',
|
||||
'__idiv__', '__idivmod__', '__ifloordiv__', '__ilshift__', '__imod__',
|
||||
'__imul__', '__int__', '__invert__', '__ior__', '__ipow__', '__irshift__',
|
||||
'__isub__', '__iter__', '__itruediv__', '__ixor__', '__le__', '__len__',
|
||||
'__long__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__',
|
||||
'__neg__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__',
|
||||
'__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__',
|
||||
'__repr__', '__reversed__', '__rfloorfiv__', '__rlshift__', '__rmod__',
|
||||
'__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__',
|
||||
'__rtruediv__', '__rxor__', '__setitem__', '__setslice__', '__sub__',
|
||||
'__truediv__', '__xor__', 'next'
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def _get_proxy(cls, obj):
|
||||
try:
|
||||
cache = cls.__dict__["_class_proxy_cache"]
|
||||
except KeyError:
|
||||
cls._class_proxy_cache = cache = {}
|
||||
try:
|
||||
theclass = cache[obj.__class__]
|
||||
except KeyError:
|
||||
cache[obj.__class__] = theclass = cls._create_class_proxy(obj.__class__)
|
||||
return theclass
|
||||
|
||||
@classmethod
|
||||
def _create_class_proxy(cls, theclass):
|
||||
"""creates a proxy for the given class"""
|
||||
|
||||
def make_method(name):
|
||||
def method(self, *args, **kw):
|
||||
return getattr(object.__getattribute__(self, "_obj"), name)(*args, **kw)
|
||||
return method
|
||||
|
||||
namespace = {}
|
||||
for name in cls._special_names:
|
||||
if hasattr(theclass, name) and not hasattr(cls, name):
|
||||
namespace[name] = make_method(name)
|
||||
return type("%s(%s)" % (cls.__name__, theclass.__name__), (cls,), namespace)
|
||||
|
||||
def __new__(cls, obj, *args, **kwargs):
|
||||
"""
|
||||
creates an proxy instance referencing `obj`. (obj, *args, **kwargs) are
|
||||
passed to this class' __init__, so deriving classes can define an
|
||||
__init__ method of their own.
|
||||
note: _class_proxy_cache is unique per deriving class (each deriving
|
||||
class must hold its own cache)
|
||||
"""
|
||||
theclass = cls._get_proxy(obj)
|
||||
ins = object.__new__(theclass)
|
||||
#theclass.__init__(ins, obj, *args, **kwargs)
|
||||
return ins
|
5
cecil/preconfig.py
Normal file
5
cecil/preconfig.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
|
||||
load_config = True
|
||||
appname = None
|
||||
db_pool_class = None
|
||||
|
45
setup.py
Executable file
45
setup.py
Executable file
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/python
|
||||
from distutils.core import setup
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import distutils.sysconfig
|
||||
try:
|
||||
from cPickle import load, dump
|
||||
except ImportError:
|
||||
from pickle import load, dump
|
||||
|
||||
packages=['cecil', 'cecil.core']
|
||||
|
||||
if sys.argv[1] == 'clean':
|
||||
for dir in packages:
|
||||
dir_to_remove = os.path.join(distutils.sysconfig.get_python_lib(), dir)
|
||||
assert len(dir_to_remove) > (len(distutils.sysconfig.get_python_lib()) + 1)
|
||||
shutil.rmtree(dir_to_remove)
|
||||
else:
|
||||
majorversion = '1.0.0-build'
|
||||
buildnumber = 0
|
||||
if os.path.exists('buildnum'):
|
||||
fd = open('buildnum', 'rb')
|
||||
try:
|
||||
vinfo = load(fd)
|
||||
mv, bn = vinfo
|
||||
if mv == majorversion:
|
||||
buildnumber = bn
|
||||
except:
|
||||
pass
|
||||
fd.close()
|
||||
buildnumber += 1
|
||||
fd = open('buildnum', 'wb')
|
||||
dump((majorversion, buildnumber), fd)
|
||||
fd.close()
|
||||
|
||||
ver = '%s%d' % (majorversion, buildnumber)
|
||||
print "Building version %s" % (ver,)
|
||||
setup(
|
||||
name='pycecil',
|
||||
version=ver,
|
||||
packages=packages
|
||||
)
|
||||
if os.path.exists('setup.py'):
|
||||
shutil.rmtree("build")
|
Loading…
Add table
Reference in a new issue