Initial revision
This commit is contained in:
1
intern/python/modules/vrml/utils/__init__.py
Normal file
1
intern/python/modules/vrml/utils/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""utilities"""
|
169
intern/python/modules/vrml/utils/collapse.py
Normal file
169
intern/python/modules/vrml/utils/collapse.py
Normal 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]
|
||||
|
37
intern/python/modules/vrml/utils/err.py
Normal file
37
intern/python/modules/vrml/utils/err.py
Normal 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)
|
||||
|
225
intern/python/modules/vrml/utils/namespace.py
Normal file
225
intern/python/modules/vrml/utils/namespace.py
Normal 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
|
||||
|
||||
|
50
intern/python/modules/vrml/utils/typeclasses.py
Normal file
50
intern/python/modules/vrml/utils/typeclasses.py
Normal 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()
|
Reference in New Issue
Block a user