Initial revision

This commit is contained in:
Hans Lambermont
2002-10-12 11:37:38 +00:00
commit 12315f4d0e
1699 changed files with 444708 additions and 0 deletions

View File

@@ -0,0 +1 @@
"""utilities"""

View File

@@ -0,0 +1,169 @@
'''
Destructive Functions for "collapsing" Sequences into single levels
>>> from mcf.utils import collapse
>>> collapse.test([[[1],[2,3]],[[]],[4],5,[6]])
[1, 2, 3, 4, 5, 6] # note that is the same root list
>>> collapse.collapse2([[[1],[2,3]],[[]],(4,()),(5,),[6]])
[1, 2, 3, 4, 5, 6] # note is the same root list
'''
import copy, types, sys
from types import ListType, TupleType # this now only supports the obsolete stuff...
def hyperCollapse( inlist, allowedmap, type=type, list=list, itype=types.InstanceType, maxint= sys.maxint):
'''
Destructively flatten a mixed hierarchy to a single level.
Non-recursive, many speedups and obfuscations by Tim Peters :)
'''
try:
# for every possible index
for ind in xrange( maxint):
# while that index currently holds a list
expandable = 1
while expandable:
expandable = 0
if allowedmap.has_key( type(inlist[ind]) ):
# expand that list into the index (and subsequent indicies)
inlist[ind:ind+1] = list( inlist[ind])
expandable = 1
# alternately you could iterate through checking for isinstance on all possible
# classes, but that would be very slow
elif type( inlist[ind] ) is itype and allowedmap.has_key( inlist[ind].__class__ ):
# here figure out some way to generically expand that doesn't risk
# infinite loops...
templist = []
for x in inlist[ind]:
templist.append( x)
inlist[ind:ind+1] = templist
expandable = 1
except IndexError:
pass
return inlist
def collapse(inlist, type=type, ltype=types.ListType, maxint= sys.maxint):
'''
Destructively flatten a list hierarchy to a single level.
Non-recursive, and (as far as I can see, doesn't have any
glaring loopholes).
Further speedups and obfuscations by Tim Peters :)
'''
try:
# for every possible index
for ind in xrange( maxint):
# while that index currently holds a list
while type(inlist[ind]) is ltype:
# expand that list into the index (and subsequent indicies)
inlist[ind:ind+1] = inlist[ind]
#ind = ind+1
except IndexError:
pass
return inlist
def collapse_safe(inlist):
'''
As collapse, but works on a copy of the inlist
'''
return collapse( inlist[:] )
def collapse2(inlist, ltype=(types.ListType, types.TupleType), type=type, maxint= sys.maxint ):
'''
Destructively flatten a list hierarchy to a single level.
Will expand tuple children as well, but will fail if the
top level element is not a list.
Non-recursive, and (as far as I can see, doesn't have any
glaring loopholes).
'''
ind = 0
try:
while 1:
while type(inlist[ind]) in ltype:
try:
inlist[ind:ind+1] = inlist[ind]
except TypeError:
inlist[ind:ind+1] = list(inlist[ind])
ind = ind+1
except IndexError:
pass
return inlist
def collapse2_safe(inlist):
'''
As collapse2, but works on a copy of the inlist
'''
return collapse( list(inlist) )
def old_buggy_collapse(inlist):
'''Always return a one-level list of all the non-list elements in listin,
rewritten to be non-recursive 96-12-28 Note that the new versions work
on the original list, not a copy of the original.'''
if type(inlist)==TupleType:
inlist = list(inlist)
elif type(inlist)!=ListType:
return [inlist]
x = 0
while 1:
try:
y = inlist[x]
if type(y) == ListType:
ylen = len(y)
if ylen == 1:
inlist[x] = y[0]
if type(inlist[x]) == ListType:
x = x - 1 # need to collapse that list...
elif ylen == 0:
del(inlist[x])
x = x-1 # list has been shortened
else:
inlist[x:x+1]=y
x = x+1
except IndexError:
break
return inlist
def old_buggy_collapse2(inlist):
'''As collapse, but also collapse tuples, rewritten 96-12-28 to be non-recursive'''
if type(inlist)==TupleType:
inlist = list(inlist)
elif type(inlist)!=ListType:
return [inlist]
x = 0
while 1:
try:
y = inlist[x]
if type(y) in [ListType, TupleType]:
ylen = len(y)
if ylen == 1:
inlist[x] = y[0]
if type(inlist[x]) in [ListType,TupleType]:
x = x-1 #(to deal with that element)
elif ylen == 0:
del(inlist[x])
x = x-1 # list has been shortened, will raise exception with tuples...
else:
inlist[x:x+1]=list(y)
x = x+1
except IndexError:
break
return inlist
def oldest_buggy_collapse(listin):
'Always return a one-level list of all the non-list elements in listin'
if type(listin) == ListType:
return reduce(lambda x,y: x+y, map(collapse, listin), [])
else: return [listin]
def oldest_buggy_collapse2(seqin):
if type(seqin) in [ListType, TupleType]:
return reduce(lambda x,y: x+y, map(collapse2, seqin), [])
else:
return [seqin]

View File

@@ -0,0 +1,37 @@
'''
err.py Encapsulated writing to sys.stderr
The idea of this module is that, for a GUI system (or a more advanced UI),
you can just import a different err module (or object) and keep
your code the same. (For instance, you often want a status window
which flashes warnings and info, and have error messages pop up an
alert to get immediate attention.
'''
import sys
def err(message, Code=0):
'''
report an error, with an optional error code
'''
if Code:
sys.stderr.write('Error #%i: %s\n'%(Code,message))
else:
sys.stderr.write('Error: %s\n'%message)
def warn(message, Code=0):
'''
report a warning, with an optional error code
'''
if Code:
sys.stderr.write('Warning #%i: %s\n'%(Code,message))
else:
sys.stderr.write('Warning: %s\n'%message)
def info(message, Code=0):
'''
report information/status, with an optional error code
'''
if Code:
sys.stderr.write('Info #%i: %s\n'%(Code,message))
else:
sys.stderr.write('Info: %s\n'%message)

View File

@@ -0,0 +1,225 @@
'''
NameSpace v0.04:
A "NameSpace" is an object wrapper around a _base dictionary
which allows chaining searches for an 'attribute' within that
dictionary, or any other namespace which is defined as part
of the search path (depending on the downcascade variable, is
either the hier-parents or the hier-children).
You can assign attributes to the namespace normally, and read
them normally. (setattr, getattr, a.this = that, a.this)
I use namespaces for writing parsing systems, where I want to
differentiate between sources (have multiple sources that I can
swap into or out of the namespace), but want to be able to get
at them through a single interface. There is a test function
which gives you an idea how to use the system.
In general, call NameSpace(someobj), where someobj is a dictionary,
a module, or another NameSpace, and it will return a NameSpace which
wraps up the keys of someobj. To add a namespace to the NameSpace,
just call the append (or hier_addchild) method of the parent namespace
with the child as argument.
### NOTE: if you pass a module (or anything else with a dict attribute),
names which start with '__' will be removed. You can avoid this by
pre-copying the dict of the object and passing it as the arg to the
__init__ method.
### NOTE: to properly pickle and/or copy module-based namespaces you
will likely want to do: from mcf.utils import extpkl, copy_extend
### Changes:
97.05.04 -- Altered to use standard hierobj interface, cleaned up
interface by removing the "addparent" function, which is reachable
by simply appending to the __parent__ attribute, though normally
you would want to use the hier_addchild or append functions, since
they let both objects know about the addition (and therefor the
relationship will be restored if the objects are stored and unstored)
97.06.26 -- Altered the getattr function to reduce the number of
situations in which infinite lookup loops could be created
(unfortunately, the cost is rather high). Made the downcascade
variable harden (resolve) at init, instead of checking for every
lookup. (see next note)
97.08.29 -- Discovered some _very_ weird behaviour when storing
namespaces in mcf.store dbases. Resolved it by storing the
__namespace_cascade__ attribute as a normal attribute instead of
using the __unstore__ mechanism... There was really no need to
use the __unstore__, but figuring out how a functions saying
self.__dict__['__namespace_cascade__'] = something
print `self.__dict__['__namespace_cascade__']` can print nothing
is a bit beyond me. (without causing an exception, mind you)
97.11.15 Found yet more errors, decided to make two different
classes of namespace. Those based on modules now act similar
to dummy objects, that is, they let you modify the original
instead of keeping a copy of the original and modifying that.
98.03.15 -- Eliminated custom pickling methods as they are no longer
needed for use with Python 1.5final
98.03.15 -- Fixed bug in items, values, etceteras with module-type
base objects.
'''
import copy, types, string
from mcf.utils import hierobj
class NameSpace(hierobj.Hierobj):
'''
An hierarchic NameSpace, allows specification of upward or downward
chaining search for resolving names
'''
def __init__(self, val = None, parents=None, downcascade=1,children=[]):
'''
A NameSpace can be initialised with a dictionary, a dummied
dictionary, another namespace, or something which has a __dict__
attribute.
Note that downcascade is hardened (resolved) at init, not at
lookup time.
'''
hierobj.Hierobj.__init__(self, parents, children)
self.__dict__['__downcascade__'] = downcascade # boolean
if val is None:
self.__dict__['_base'] = {}
else:
if type( val ) == types.StringType:
# this is a reference to a module which has been pickled
val = __import__( val, {},{}, string.split( val, '.') )
try:
# See if val's a dummy-style object which has a _base
self.__dict__['_base']=copy.copy(val._base)
except (AttributeError,KeyError):
# not a dummy-style object... see if it has a dict attribute...
try:
if type(val) != types.ModuleType:
val = copy.copy(val.__dict__)
except (AttributeError, KeyError):
pass
# whatever val is now, it's going to become our _base...
self.__dict__['_base']=val
# harden (resolve) the reference to downcascade to speed attribute lookups
if downcascade: self.__dict__['__namespace_cascade__'] = self.__childlist__
else: self.__dict__['__namespace_cascade__'] = self.__parent__
def __setattr__(self, var, val):
'''
An attempt to set an attribute should place the attribute in the _base
dictionary through a setitem call.
'''
# Note that we use standard attribute access to allow ObStore loading if the
# ._base isn't yet available.
try:
self._base[var] = val
except TypeError:
setattr(self._base, var, val)
def __getattr__(self,var):
## print '__getattr__', var
return self.__safe_getattr__(var, {}) # the {} is a stopdict
def __safe_getattr__(self, var,stopdict):
'''
We have a lot to do in this function, if the attribute is an unloaded
but stored attribute, we need to load it. If it's not in the stored
attributes, then we need to load the _base, then see if it's in the
_base.
If it's not found by then, then we need to check our resource namespaces
and see if it's in them.
'''
# we don't have a __storedattr__ or it doesn't have this key...
if var != '_base':
try:
return self._base[var]
except (KeyError,TypeError), x:
try:
return getattr(self._base, var)
except AttributeError:
pass
try: # with pickle, it tries to get the __setstate__ before restoration is complete
for cas in self.__dict__['__namespace_cascade__']:
try:
stopdict[id(cas)] # if succeeds, we've already tried this child
# no need to do anything, if none of the children succeeds we will
# raise an AttributeError
except KeyError:
stopdict[id(cas)] = None
return cas.__safe_getattr__(var,stopdict)
except (KeyError,AttributeError):
pass
raise AttributeError, var
def items(self):
try:
return self._base.items()
except AttributeError:
pass
try:
return self._base.__dict__.items()
except AttributeError:
pass
def keys(self):
try:
return self._base.keys()
except AttributeError:
pass
try:
return self._base.__dict__.keys()
except AttributeError:
pass
def has_key( self, key ):
try:
return self._base.has_key( key)
except AttributeError:
pass
try:
return self._base.__dict__.has_key( key)
except AttributeError:
pass
def values(self):
try:
return self._base.values()
except AttributeError:
pass
try:
return self._base.__dict__.values()
except AttributeError:
pass
def __getinitargs__(self):
if type( self._base ) is types.ModuleType:
base = self._base.__name__
else:
base = self._base
return (base, self.__parent__, self.__downcascade__, self.__childlist__)
def __getstate__(self):
return None
def __setstate__(self,*args):
pass
def __deepcopy__(self, memo=None):
d = id(self)
if memo is None:
memo = {}
elif memo.has_key(d):
return memo[d]
if type(self._base) == types.ModuleType:
rest = tuple(map( copy.deepcopy, (self.__parent__, self.__downcascade__, self.__childlist__) ))
new = apply(self.__class__, (self._base,)+rest )
else:
new = tuple(map( copy.deepcopy, (self._base, self.__parent__, self.__downcascade__, self.__childlist__) ))
return new
## def __del__( self, id=id ):
## print 'del namespace', id( self )
def test():
import string
a = NameSpace(string)
del(string)
a.append(NameSpace({'a':23,'b':42}))
import math
a.append(NameSpace(math))
print 'The returned object should allow access to the attributes of the string,\nand math modules, and two simple variables "a" and "b" (== 23 and42 respectively)'
return a

View File

@@ -0,0 +1,50 @@
'''
Classes of Types
Often you want to be able to say:
if type(obj) in MutableTypes:
yada
This module is intended to make that easier.
Just import and use :)
'''
import types
MutableTypes = [ types.ListType, types.DictType, types.InstanceType ]
MutableSequenceTypes = [ types.ListType ]
SequenceTypes = [ types.ListType, types.StringType, types.TupleType ]
NumericTypes = [ types.IntType, types.FloatType, types.LongType, types.ComplexType ]
MappingTypes = [ types.DictType ]
def regarray():
if globals().has_key('array'):
return 1
try:
import array
SequenceTypes.append( array.ArrayType )
MutableTypes.append( array.ArrayType )
MutableSequenceTypes.append( array.ArrayType )
return 1
except ImportError:
return 0
def regnumpy():
'''
Call if you want to register numpy arrays
according to their types.
'''
if globals().has_key('Numeric'):
return 1
try:
import Numeric
SequenceTypes.append( Numeric.ArrayType )
MutableTypes.append( Numeric.ArrayType )
MutableSequenceTypes.append( Numeric.ArrayType )
return 1
except ImportError:
return 0
# for now, I'm going to always register these, if the module becomes part of the base distribution
# it might be better to leave it out so numpy isn't always getting loaded...
regarray()
regnumpy()