Hi, I am having a weird problem. I am dealing with some "legacy" database, so I subclass TypeDecorator to help clean things up a bit.
This worked fine in 0.3 but I am now trying to use 0.4 and things break in the strangest of way. When I run the file below, Python complains about AttributeError: 'String' object has no attribute 'padding' Now, "padding" is a parameter of the constructor of PaddedIntString. So it is not an attribute. If I make "padding" an attribute of PaddedIntString, the error dissappears. Am I doing something wrong or is this a feature of 0.4??? TIA François Here is a file that triggers the problem PaddedIntString allows me to use integer in Python but to have strings like "02","10" in the DB. ############ %< ################################## !/usr/bin/env python ########################################################################### # # ########################################################################### from sqlalchemy.types import TypeDecorator from sqlalchemy import * from sqlalchemy.orm import * class Enum(Unicode): """An Enum is simply a field where the value can only be chosen from a limited list of values""" def __init__(self, values): ''' construct an Enum type values : a list of values that are valid for this column ''' if values is None or len(values) is 0: raise exceptions.AssertionError('Enum requires a list of values') self.values = values # the length of the string/unicode column should be the longest string # in values super(Enum, self).__init__(max(map(len,values))) def convert_bind_param(self, value, engine): if value is None or value == '': value = None elif value not in self.values: raise exceptions.AssertionError('%s not in Enum.values' %value) return super(Enum, self).convert_bind_param(value, engine) def convert_result_value(self, value, engine): if value is not None and value not in self.values: raise exceptions.AssertionError('%s not in Enum.values' %value) return super(Enum, self).convert_result_value(value, engine) class CP874String(TypeDecorator): """A string type converted between unicode and cp874""" impl = String def convert_bind_param(self, value, engine): """Convert from unicode to cp874""" if value is None: return None return value.encode('cp874') def convert_result_value(self, value, engine): """Convert from cp874 to unicode""" #return unicode(value,"utf8") if value is None: return None return value.decode('cp874') class IntString(TypeDecorator): """A string type converted between unicode and integer""" impl = String def convert_bind_param(self, value, engine): """Convert from int to string""" if value is None: return None return str(value) def convert_result_value(self, value, engine): """Convert from string to int""" #return unicode(value,"utf8") if value is None: return None return int(value.strip()) class PaddedIntString(IntString): """A string type converted between unicode and integer""" def __init__(self, length=None, convert_unicode=False,padding='0'): if length is None: raise Exception("Use IntString instead") self.pat="%%%s%dd"%(padding,length) IntString.__init__(self,length,convert_unicode) def convert_bind_param(self, value, engine): """Convert from int to string""" if value is None: return None return self.pat%(value) def convert_result_value(self, value, engine): """Convert from string to int""" #return unicode(value,"utf8") if value is None: return None return int(value.strip()) class myBoolean(TypeDecorator): """A string type converted between unicode and integer""" impl = Integer def convert_bind_param(self, value, engine): """Convert from bool to int""" if value is None or not value: return 0 return 1 def convert_result_value(self, value, engine): """Convert from int to bool""" #return unicode(value,"utf8") if value is None or value==0 or value=='0': return False return True class StripString(TypeDecorator): """A string type stripping its content (mostly for fixed length stri)ngs""" impl = String def convert_bind_param(self, value, engine): """Idempotent""" return value def convert_result_value(self, value, engine): """Convert from DB value""" if value is None: return None return value.strip() class CodeString(TypeDecorator): """A string type with a natural sorting comparator Should we subclass StripString? """ impl = String def convert_bind_param(self, value, engine): """Idempotent""" return str(value) def convert_result_value(self, value, engine): """Convert from DB value""" if value is None: return None return NCString(value.strip()) _Metadata=MetaData() tblStore=Table("Store",_Metadata, Column("StoreNo",PaddedIntString(2), primary_key=True), Column("StoreEnglishName",StripString(50)), Column("StoreThaiName",CP874String(50)), Column("StoreType",String(2)), Column("StoreLocation",String(2)), Column("StoreStatus",String(1)), Column("Shop",Integer), Column("LastDate",DateTime), Column("LastUser",String(8))) tblStock=Table("Stkdetl",_Metadata, Column("DTL_STORE",PaddedIntString(2),ForeignKey("Store.StoreNo"),primary_key=True), Column("DTL_CODE",String(20),primary_key=True), Column("DTL_BAL_Q1",Integer,nullable=False), Column("DTL_ISS_Q1",Integer,nullable=False), Column("DTL_RCV_Q1",Integer,nullable=False), Column("DTL_BAL_TT",Integer,nullable=False), Column("DTL_MIN_PT",Integer), Column("DTL_MAX_PT",Integer), Column("DTL_LOC",String(8)), Column("DTL_DIST",String(6)), Column("DTL_ACCT",String(12)), Column("DTL_AC_DM",String(12))) class DBObject(object): """A simple class that let's render the info as a table""" def addStyle(self,prop,style): assert prop in self.__dict__ self.style[prop]=style def delStyle(self,prop): if prop in self.styles.keys(): del self.styles[prop] class StockItem(DBObject): """Info concerning the in-stock quantity for a given product""" def _Level(self): return int(self.Balance+self.Received-self.Issued) def _AvgCost(self): try: myval=self.Product.Master.AvgCost #row=myconn.execute(sel).fetchone() #return float(row[0]) except: return 0.0 if myval is None: return 0.0 return myval def _ItemCost(self): if self.Level==0: return self.AvgCost return self.TotalCost/self.Level Level=property(_Level) AvgCost=property(_AvgCost) ItemCost=property(_ItemCost) class Stock(DBObject): """One of our Real or virtual shops""" def __repr__(self): if self.id in self.FGStocks.keys(): return self.FGStocks[self.id] if self.id in self.VirtualStocks.keys(): return self.VirtualStocks[self.id] if self.id in self.OtherStocks.keys(): return self.OtherStocks[self.id] return "Unknown Stock %d"%(self.id) def _Unposted(self): return [ x for x in self.Inventory if x.Level!=x.Balance ] Unposted=property(_Unposted) StockItem.mapper["Primary"]=mapper(StockItem, tblStock, properties={ #'Product': relation(Product,backref="inStock", lazy=False), "Balance": tblStock.c.DTL_BAL_Q1, "Issued": tblStock.c.DTL_ISS_Q1, "Received": tblStock.c.DTL_RCV_Q1, "Minimum": tblStock.c.DTL_MIN_PT, "Maximum": tblStock.c.DTL_MAX_PT, "TotalCost": tblStock.c.DTL_BAL_TT, 'AccountNb': tblStock.c.DTL_AC_DM, } ) StockItem.stylesclass={"Level":"numval", "Balance":"numval", "Issued":"numval", "Received":"numval", "TotalCost":"numval", "AvgCost":"numval"} Stock.mapper["Primary"]=mapper(Stock, tblStore, properties={ 'Inventory':relation(StockItem,backref="Stock", lazy=True, cascade="all, delete-orphan"), 'id' : tblStore.c.StoreNo, } ) ############ %< ################################## --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalchemy@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en -~----------~----~----~----~------~----~------~--~---