reportlab/lib/attrmap.py
author rgbecker
Sat, 23 Mar 2002 16:47:27 +0000
changeset 1549 df0706b21a94
parent 948 2531b35adf85
child 1559 2bb75ab0d0aa
permissions -rw-r--r--
Fixed to work with 2.2
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
     1
#copyright ReportLab Inc. 2000
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
     2
#see license.txt for license details
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
     3
#history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/reportlab/lib/attrmap.py?cvsroot=reportlab
1549
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
     4
#$Header: /tmp/reportlab/reportlab/lib/attrmap.py,v 1.3 2002/03/23 16:47:27 rgbecker Exp $
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
     5
from UserDict import UserDict
1549
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
     6
from reportlab.lib.validators import isAnything, _SequenceTypes
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
     7
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
     8
class CallableValue:
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
     9
	'''a class to allow callable initial values'''
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    10
	def __init__(self,func,*args,**kw):
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    11
		#assert iscallable(func)
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    12
		self.func = func
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    13
		self.args = args
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    14
		self.kw = kw
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    15
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    16
	def __call__(self):
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    17
		return apply(self.func,self.args,self.kw)
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    18
		
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    19
class AttrMapValue:
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    20
	'''Simple multi-value holder for attribute maps'''
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    21
	def __init__(self,validate=None,desc=None,initial=None, **kw):
948
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    22
		self.validate = validate or isAnything
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    23
		self.desc = desc
1549
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    24
		self.initial = initial
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    25
		for k,v in kw.items():
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    26
			setattr(self,k,v)
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    27
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    28
	def __getattr__(self,name):
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    29
		#hack to allow callable initial values
1549
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    30
		if name=='initial':
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    31
			if isinstance(self._initial,CallableValue): return self._initial()
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    32
			return self._initial
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    33
		elif name=='hidden':
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    34
			return 0
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    35
		raise AttributeError, name
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    36
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    37
class AttrMap(UserDict):
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    38
	def __init__(self,BASE=None,UNWANTED=[],**kw):
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    39
		if BASE:
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    40
			if isinstance(BASE,AttrMap):
948
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    41
				data = BASE.data						#they used BASECLASS._attrMap
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    42
			elif hasattr(BASE,'_attrMap'):
948
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    43
				data = getattr(BASE._attrMap,'data',{})	#they gave us the BASECLASS
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    44
			else:
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    45
				raise ValueError, 'BASE=%s has wrong kind of value' % str(BASE)
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    46
		else:
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    47
			data = {}
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    48
948
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    49
		UserDict.__init__(self,data)
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    50
		self.remove(UNWANTED)
948
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    51
		self.data.update(kw)
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    52
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    53
	def update(self,kw):
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    54
		if isinstance(kw,AttrMap): kw = kw.data
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    55
		self.data.update(kw)
946
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    56
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    57
	def remove(self,unwanted):
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    58
		for k in unwanted:
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    59
			try:
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    60
				del self[k]
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    61
			except KeyError:
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    62
				pass
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    63
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    64
	def clone(self,UNWANTED=[],**kw):
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    65
		c = AttrMap(BASE=self,UNWANTED=UNWANTED)
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    66
		c.update(kw)
0bda695b09ce Initial version
rgbecker
parents:
diff changeset
    67
		return c
948
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    68
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    69
def validateSetattr(obj,name,value):
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    70
	'''validate setattr(obj,name,value)'''
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    71
	map = obj._attrMap
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    72
	if map and name[0]!= '_':
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    73
		try:
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    74
			validate = map[name].validate
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    75
			if not validate(value):
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    76
				raise AttributeError, "Illegal assignment of '%s' to '%s' in class %s" % (value, name, obj.__class__.__name__)
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    77
		except KeyError:
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    78
			raise AttributeError, "Illegal attribute '%s' in class %s" % (name, obj.__class__.__name__)
2531b35adf85 New AttrMap emplacement
rgbecker
parents: 946
diff changeset
    79
	obj.__dict__[name] = value
1549
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    80
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    81
def _privateAttrMap(obj,ret=0):
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    82
	'''clone obj._attrMap if required'''
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    83
	A = obj._attrMap
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    84
	oA = getattr(obj.__class__,'_attrMap',None)
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    85
	if ret:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    86
		if oA is A:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    87
			return A.clone(), oA
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    88
		else:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    89
			return A, None
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    90
	else:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    91
		if oA is A:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    92
			obj._attrMap = A.clone()
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    93
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    94
def _findObjectAndAttr(src, P):
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    95
	'''Locate the object src.P for P a string, return parent and name of attribute
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    96
	'''
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    97
	P = string.split(P, '.')
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    98
	if len(P) == 0:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
    99
		return None, None
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   100
	else:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   101
		for p in P[0:-1]:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   102
			src = getattr(src, p)
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   103
		return src, P[-1]
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   104
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   105
def addProxyAttribute(src,name=None,dst=None):
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   106
	'''
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   107
	Add a proxy attribute 'name' to src with targets dst
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   108
	'''
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   109
	#sanity
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   110
	assert hasattr(src,'_attrMap'), 'src object has no _attrMap'
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   111
	A, oA = _privateAttrMap(src,1)
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   112
	assert name and name in A.keys(), 'invalid proxy attribute name %s' % repr(name)
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   113
	if type(dst) not in _SequenceTypes: dst = dst,
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   114
	D = []
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   115
	DV = []
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   116
	for d in dst:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   117
		if type(d) in _SequenceTypes:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   118
			d, e = d[0], d[1:]
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   119
		obj, attr = _findObjectAndAttr(src,d)
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   120
		if obj:
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   121
			dA = getattr(obj,'_attrMap',None)
df0706b21a94 Fixed to work with 2.2
rgbecker
parents: 948
diff changeset
   122
			assert dA and attr in dA.keys(), 'target attribute %s not in _attrMap' % d