Fix bug where finalized IPA object where trying to modify their member variables in Encoder methods.

This commit is contained in:
Pavel Zuna authored and Jason Gerard DeRose committed 2009-05-22 15:57:27 -06:00
1 parent 762d38a734
commit 9468c9fca8
1 file changed
+64 -76
+64 -76
View File
@@ -17,16 +17,12 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
""" """
This module provides the Encoder base class, that adds encoding/decoding Encoding capabilities.
capabilities to classes extending it. It also defines a set of decorators
designed to automagically encode method arguments and decode their return
values.
""" """
class Encoder(object): class EncoderSettings(object):
""" """
Base class implementing encoding python scalar types to strings Container for encoder settings.
and vise-versa.
""" """
encode_to = 'utf-8' encode_to = 'utf-8'
encode_none = False encode_none = False
@@ -46,9 +42,23 @@ class Encoder(object):
decode_dict_vals_table_keygen = staticmethod(lambda x: x) decode_dict_vals_table_keygen = staticmethod(lambda x: x)
decode_postprocessor = staticmethod(lambda x: x) decode_postprocessor = staticmethod(lambda x: x)
class Encoder(object):
"""
Base class implementing encoding of python scalar types to strings
and vise-versa.
"""
encoder_settings = EncoderSettings()
def __init__(self):
# each instance should have its own settings
self.encoder_settings = EncoderSettings()
def _decode_dict_val(self, key, val): def _decode_dict_val(self, key, val):
f = self.decode_dict_vals_table.get( f = self.encoder_settings.decode_dict_vals_table.get(
self.decode_dict_vals_table_keygen(key), self.decode self.encoder_settings.decode_dict_vals_table_keygen(key, val),
self.decode
) )
return f(val) return f(val)
@@ -61,38 +71,42 @@ class Encoder(object):
Returns an encoded copy of 'var'. Returns an encoded copy of 'var'.
""" """
if isinstance(var, basestring): if isinstance(var, basestring):
return self.encode_postprocessor(var.encode(self.encode_to)) return self.encoder_settings.encode_postprocessor(
var.encode(self.encoder_settings.encode_to)
)
elif isinstance(var, (bool, float, int, long)): elif isinstance(var, (bool, float, int, long)):
return self.encode_postprocessor(str(var).encode(self.encode_to)) return self.encoder_settings.encode_postprocessor(
str(var).encode(self.encoder_settings.encode_to)
)
elif isinstance(var, list): elif isinstance(var, list):
return [self.encode(m) for m in var] return [self.encode(m) for m in var]
elif isinstance(var, tuple): elif isinstance(var, tuple):
return tuple(self.encode(m) for m in var) return list(self.encode(m) for m in var)
elif isinstance(var, dict): elif isinstance(var, dict):
if self.encode_dict_keys: if self.encoder_settings.encode_dict_keys:
dct = dict() dct = dict()
if not self.encode_dict_keys_postprocess: if not self.encoder_settings.encode_dict_keys_postprocess:
tmp = self.encode_postprocessor tmp = self.encoder_settings.encode_postprocessor
self.encode_postprocessor = lambda x: x self.encoder_settings.encode_postprocessor = lambda x: x
for (k, v) in var.iteritems(): for (k, v) in var.iteritems():
dct[self.encode(k)] = v dct[self.encode(k)] = v
if not self.encode_dict_keys_postprocess: if not self.encoder_settings.encode_dict_keys_postprocess:
self.encode_postprocessor = tmp self.encoder_settings.encode_postprocessor = tmp
else: else:
dct = dict(var) dct = dict(var)
if self.encode_dict_vals: if self.encoder_settings.encode_dict_vals:
if not self.encode_dict_vals_postprocess: if not self.encoder_settings.encode_dict_vals_postprocess:
tmp = self.encode_postprocessor tmp = self.encoder_settings.encode_postprocessor
self.encode_postprocessor = lambda x: x self.encoder_settings.encode_postprocessor = lambda x: x
for (k, v) in dct.iteritems(): for (k, v) in dct.iteritems():
dct[k] = self.encode(v) dct[k] = self.encode(v)
if not self.encode_dict_vals_postprocess: if not self.encoder_settings.encode_dict_vals_postprocess:
self.encode_postprocessor = tmp self.encoder_settings.encode_postprocessor = tmp
return dct return dct
elif var is None: elif var is None:
if self.encode_none: if self.encoder_settings.encode_none:
return self.encode_postprocessor( return self.encoder_settings.encode_postprocessor(
str(var).encode(self.encode_to) str(var).encode(self.encoder_settings.encode_to)
) )
return None return None
raise TypeError('python built-in type expected, got \'%s\'', type(var)) raise TypeError('python built-in type expected, got \'%s\'', type(var))
@@ -109,38 +123,40 @@ class Encoder(object):
Returns a decoded copy of 'var'. Returns a decoded copy of 'var'.
""" """
if isinstance(var, basestring): if isinstance(var, basestring):
return self.decode_postprocessor(var.decode(self.decode_from)) return self.encoder_settings.decode_postprocessor(
var.decode(self.encoder_settings.decode_from)
)
elif isinstance(var, (bool, float, int, long)): elif isinstance(var, (bool, float, int, long)):
return self.decode_postprocessor(unicode(var)) return self.encoder_settings.decode_postprocessor(unicode(var))
elif isinstance(var, list): elif isinstance(var, list):
return [self.decode(m) for m in var] return [self.decode(m) for m in var]
elif isinstance(var, tuple): elif isinstance(var, tuple):
return tuple(self.decode(m) for m in var) return list(self.decode(m) for m in var)
elif isinstance(var, dict): elif isinstance(var, dict):
if self.decode_dict_keys: if self.encoder_settings.decode_dict_keys:
dct = dict() dct = dict()
if not self.decode_dict_keys_postprocess: if not self.encoder_settings.decode_dict_keys_postprocess:
tmp = self.decode_postprocessor tmp = self.encoder_settings.decode_postprocessor
self.decode_postprocessor = lambda x: x self.encoder_settings.decode_postprocessor = lambda x: x
for (k, v) in var.iteritems(): for (k, v) in var.iteritems():
dct[self.decode(k)] = v dct[self.decode(k)] = v
if not self.decode_dict_keys_postprocess: if not self.encoder_settings.decode_dict_keys_postprocess:
self.decode_postprocessor = tmp self.encoder_settings.decode_postprocessor = tmp
else: else:
dct = dict(var) dct = dict(var)
if self.decode_dict_vals: if self.encoder_settings.decode_dict_vals:
if not self.decode_dict_vals_postprocess: if not self.encoder_settings.decode_dict_vals_postprocess:
tmp = self.decode_postprocessor tmp = self.encoder_settings.decode_postprocessor
self.decode_postprocessor = lambda x: x self.encoder_settings.decode_postprocessor = lambda x: x
for (k, v) in dct.iteritems(): for (k, v) in dct.iteritems():
dct[k] = self._decode_dict_val(k, v) dct[k] = self._decode_dict_val(k, v)
if not self.decode_dict_vals_postprocess: if not self.encoder_settings.decode_dict_vals_postprocess:
self.decode_postprocessor = tmp self.encoder_settings.decode_postprocessor = tmp
return dct return dct
elif var is None: elif var is None:
if self.decode_none: if self.encoder_settings.decode_none:
return self.decode_postprocessor( return self.encoder_settings.decode_postprocessor(
str(var).decode(self.decode_from) str(var).decode(self.encoder_settings.decode_from)
) )
return None return None
raise TypeError('python built-in type expected, got \'%s\'', type(var)) raise TypeError('python built-in type expected, got \'%s\'', type(var))
@@ -148,22 +164,6 @@ class Encoder(object):
## ENCODER METHOD DECORATORS ## ENCODER METHOD DECORATORS
def encode_args(*outer_args): def encode_args(*outer_args):
"""
Encode arguments of the decorated method specified by their sequence
number or name for keyword arguments.
Example:
class some_class_that_needs_encoding_capabilities(Encoder):
...
@encode_args(1, 3, 'name'):
def some_method(
self, encode_this, dont_encode_this, encode_this_too, **kwargs
):
# if there's going to be a 'name' kwargs it will be encoded
...
This is an Encoder method decorator.
"""
def decorate(f): def decorate(f):
def new_f(*args, **kwargs): def new_f(*args, **kwargs):
assert isinstance(args[0], Encoder), \ assert isinstance(args[0], Encoder), \
@@ -171,8 +171,10 @@ def encode_args(*outer_args):
new_args = list(args) new_args = list(args)
for a in outer_args: for a in outer_args:
if isinstance(a, int): if isinstance(a, int):
if a < len(args):
new_args[a] = args[0].encode(args[a]) new_args[a] = args[0].encode(args[a])
elif isinstance(a, basestring) and a in kwargs: elif isinstance(a, basestring):
if a in kwargs:
kwargs[a] = args[0].encode(kwargs[a]) kwargs[a] = args[0].encode(kwargs[a])
else: else:
raise TypeError( raise TypeError(
@@ -185,20 +187,6 @@ def encode_args(*outer_args):
def decode_retval(): def decode_retval():
"""
Decode the return value of the decorated method.
Example:
class some_class_that_needs_encoding_capabilities(Encoder):
...
@decode_retval():
def some_method(self):
...
return this_will_be_decoded
...
This is an Encoder method decorator AND IT HAS TO BE CALLED (use "()")!
"""
def decorate(f): def decorate(f):
def new_f(*args, **kwargs): def new_f(*args, **kwargs):
assert isinstance(args[0], Encoder), \ assert isinstance(args[0], Encoder), \