From c9cfb713ce1488dc0c1cb87bcc050e3ac0de7bcb Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 26 Mar 2006 06:26:02 +0000 Subject: [PATCH] util: the __setitem__ method on historyarraylist was meaningless, surprising nobody noticed that. types: added PickleType, its slightly trickier than trivial, so OK now its standard. attributes: the level of pain if an AttributeError occurs inside a CallableProp, in combination with an object that implements __getattr__, is too deep for me to put the users through....so convert AttributeErrors to Assertions... engine: im not a fan of catching universal exceptions and squashing them --- lib/sqlalchemy/attributes.py | 15 ++++++++++++--- lib/sqlalchemy/engine.py | 8 ++++---- lib/sqlalchemy/mapping/mapper.py | 4 ---- lib/sqlalchemy/types.py | 24 ++++++++++++++++++++++-- lib/sqlalchemy/util.py | 2 +- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/lib/sqlalchemy/attributes.py b/lib/sqlalchemy/attributes.py index 997b2c8f82..cd01faddd7 100644 --- a/lib/sqlalchemy/attributes.py +++ b/lib/sqlalchemy/attributes.py @@ -214,7 +214,12 @@ class CallableProp(object): if passive: value = None else: - value = self.callable_() + try: + value = self.callable_() + except AttributeError, e: + # this catch/raise is because this call is frequently within an + # AttributeError-sensitive callstack + raise AssertionError("AttributeError caught in callable prop:" + str(e.args)) self.obj.__dict__[self.key] = value p = PropHistory(self.obj, self.key, **self.kwargs) @@ -223,11 +228,15 @@ class CallableProp(object): if passive: value = None else: - value = self.callable_() + try: + value = self.callable_() + except AttributeError, e: + # this catch/raise is because this call is frequently within an + # AttributeError-sensitive callstack + raise AssertionError("AttributeError caught in callable prop:" + str(e.args)) else: value = None p = self.manager.create_list(self.obj, self.key, value, readonly=self.live, **self.kwargs) - if not self.live and not passive: # set the new history list as the new attribute, discards ourself self.manager.attribute_history(self.obj)[self.key] = p diff --git a/lib/sqlalchemy/engine.py b/lib/sqlalchemy/engine.py index c804680e62..85005bb7d3 100644 --- a/lib/sqlalchemy/engine.py +++ b/lib/sqlalchemy/engine.py @@ -852,10 +852,10 @@ class RowProxy: def __getitem__(self, key): return self.__parent._get_col(self.__row, key) def __getattr__(self, name): - try: - return self.__parent._get_col(self.__row, name) - except: - raise AttributeError + #try: + return self.__parent._get_col(self.__row, name) + #except: + # raise AttributeError def items(self): return [(key, getattr(self, key)) for key in self.keys()] def keys(self): diff --git a/lib/sqlalchemy/mapping/mapper.py b/lib/sqlalchemy/mapping/mapper.py index 0d3cbb3006..32da013ac7 100644 --- a/lib/sqlalchemy/mapping/mapper.py +++ b/lib/sqlalchemy/mapping/mapper.py @@ -812,7 +812,6 @@ class Mapper(object): list. if the instance already exists in the given identity map, its not added. in either case, executes all the property loaders on the instance to also process extra information in the row.""" - # look in main identity map. if its there, we dont do anything to it, # including modifying any of its related items lists, as its already # been exposed to being modified by the application. @@ -830,7 +829,6 @@ class Mapper(object): if self.extension.append_result(self, row, imap, result, instance, isnew, populate_existing=populate_existing): if result is not None: result.append_nohistory(instance) - return instance # look in result-local identitymap for it. @@ -857,11 +855,9 @@ class Mapper(object): # instances from the row and possibly populate this item. if self.extension.populate_instance(self, instance, row, identitykey, imap, isnew): self.populate_instance(instance, row, identitykey, imap, isnew, translate=False) - if self.extension.append_result(self, row, imap, result, instance, isnew, populate_existing=populate_existing): if result is not None: result.append_nohistory(instance) - return instance def populate_instance(self, instance, row, identitykey, imap, isnew, translate=True): diff --git a/lib/sqlalchemy/types.py b/lib/sqlalchemy/types.py index 2aa67507d4..ecf791a378 100644 --- a/lib/sqlalchemy/types.py +++ b/lib/sqlalchemy/types.py @@ -7,12 +7,16 @@ __all__ = [ 'TypeEngine', 'TypeDecorator', 'NullTypeEngine', 'INT', 'CHAR', 'VARCHAR', 'TEXT', 'FLOAT', 'DECIMAL', 'TIMESTAMP', 'DATETIME', 'CLOB', 'BLOB', 'BOOLEAN', 'String', 'Integer', 'Smallinteger', - 'Numeric', 'Float', 'DateTime', 'Date', 'Time', 'Binary', 'Boolean', 'Unicode', 'NULLTYPE', + 'Numeric', 'Float', 'DateTime', 'Date', 'Time', 'Binary', 'Boolean', 'Unicode', 'PickleType', 'NULLTYPE', 'SMALLINT', 'DATE', 'TIME' ] import sqlalchemy.util as util - +try: + import cPickle as pickle +except: + import pickle + class TypeEngine(object): basetypes = [] def __init__(self, *args, **kwargs): @@ -142,6 +146,22 @@ class Binary(TypeEngine): def get_constructor_args(self): return {'length':self.length} +class PickleType(Binary): + def __init__(self, protocol=pickle.HIGHEST_PROTOCOL): + """allows the pickle protocol to be specified""" + self.protocol = protocol + def convert_result_value(self, value, engine): + if value is None: + return None + buf = Binary.convert_result_value(self, value, engine) + return pickle.loads(str(buf)) + def convert_bind_param(self, value, engine): + if value is None: + return None + return Binary.convert_bind_param(self, pickle.dumps(value, self.protocol), engine) + def get_constructor_args(self): + return {} + class Boolean(TypeEngine): pass diff --git a/lib/sqlalchemy/util.py b/lib/sqlalchemy/util.py index 85bbfdc5ac..44209b1049 100644 --- a/lib/sqlalchemy/util.py +++ b/lib/sqlalchemy/util.py @@ -397,7 +397,7 @@ class HistoryArraySet(UserList.UserList): def has_item(self, item): return self.records.has_key(item) def __setitem__(self, i, item): - if self._setrecord(a): + if self._setrecord(item): self.data[i] = item def __delitem__(self, i): self._delrecord(self.data[i]) -- 2.47.2