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
-~----------~----~----~----~------~----~------~--~---

Reply via email to