Contact: fumanchu@aminus.org

Log in as guest/dejavu to create tickets

I think I've seen this ORM somewhere before...

Changeset 172

Show
Ignore:
Timestamp:
02/27/06 23:48:09
Author:
fumanchu
Message:

Fix for #45 (memorize fails on unicode inside tuple).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/storage/db.py

    r171 r172  
    1414assume no limit, although you may choose whatever default size you wish 
    1515(255 is common for strings). 
     16 
     17ENCODING ISSUES 
     18=============== 
     19All SQL sent to the database must be strings, not unicode. You can set the 
     20encoding of the Adapters (I may add a more centralized encoding context in 
     21the future). We must use encoded strings so that we can mix encodings 
     22within the same string; for example, we might have a DB which understands 
     23utf8, but a pickle value which will be encoded in raw-unicode-escape inline 
     24with that. All values, therefore, must be coerced before we try to join 
     25them into an SQL statement string. 
     26 
    1627""" 
    1728 
     
    106117    def coerce_float(self, cls, key): 
    107118        prop = getattr(cls, key) 
    108         bytes = int(prop.hints.get(u'bytes', '8')) 
     119        bytes = int(prop.hints.get('bytes', '8')) 
    109120        if bytes < 5: 
    110121            # In MySQL, REAL is still probably 8 bytes. Meh. 
    111             return u"REAL" 
     122            return "REAL" 
    112123        else: 
    113124            # Python floats are implemented using C doubles; 
    114125            # actual precision depends on platform. PostgreSQL 
    115126            # DOUBLE is 8 bytes (15 decimal-digit precision). 
    116             return u"DOUBLE PRECISION" 
     127            return "DOUBLE PRECISION" 
    117128     
    118129    def coerce_str(self, cls, key): 
    119130        # The bytes hint shall not reflect the usual 4-byte base for varchar. 
    120131        prop = getattr(cls, key) 
    121         bytes = int(prop.hints.get(u'bytes', '0')) 
     132        bytes = int(prop.hints.get('bytes', '0')) 
    122133        if bytes: 
    123             return u"VARCHAR(%s)" % bytes 
     134            return "VARCHAR(%s)" % bytes 
    124135        else: 
    125136            # TEXT is not an SQL standard, but it's common. 
    126             return u"TEXT" 
     137            return "TEXT" 
    127138     
    128139    def coerce_dict(self, cls, key): 
     
    135146        return self.coerce_str(cls, key) 
    136147     
    137     def coerce_bool(self, cls, key): return u"BOOLEAN" 
    138      
    139     def coerce_datetime_datetime(self, cls, key): return u"TIMESTAMP" 
    140     def coerce_datetime_date(self, cls, key): return u"DATE" 
    141     def coerce_datetime_time(self, cls, key): return u"TIME" 
     148    def coerce_bool(self, cls, key): return "BOOLEAN" 
     149     
     150    def coerce_datetime_datetime(self, cls, key): return "TIMESTAMP" 
     151    def coerce_datetime_date(self, cls, key): return "DATE" 
     152    def coerce_datetime_time(self, cls, key): return "TIME" 
    142153     
    143154    # I was seriously disinterested in writing a parser for interval. 
     
    158169            precision = self.numeric_max_precision 
    159170        # Assume most people use decimal for money; default scale = 2. 
    160         scale = int(prop.hints.get(u'scale', 2)) 
    161         return u"NUMERIC(%s, %s)" % (precision, scale) 
     171        scale = int(prop.hints.get('scale', 2)) 
     172        return "NUMERIC(%s, %s)" % (precision, scale) 
    162173     
    163174    def coerce_decimal(self, cls, key): 
     
    171182            precision = self.numeric_max_precision 
    172183        # Assume most people use decimal for money; default scale = 2. 
    173         scale = int(prop.hints.get(u'scale', 2)) 
    174         return u"NUMERIC(%s, %s)" % (precision, scale) 
     184        scale = int(prop.hints.get('scale', 2)) 
     185        return "NUMERIC(%s, %s)" % (precision, scale) 
    175186     
    176187    def coerce_long(self, cls, key): 
    177188        prop = getattr(cls, key) 
    178         bytes = int(prop.hints.get(u'bytes', 0)) 
     189        bytes = int(prop.hints.get('bytes', 0)) 
    179190        if bytes <= 4: 
    180191            return self.coerce_int(cls, key) 
     
    194205    def coerce_int(self, cls, key): 
    195206        prop = getattr(cls, key) 
    196         bytes = int(prop.hints.get(u'bytes', '4')) 
     207        bytes = int(prop.hints.get('bytes', '4')) 
    197208        if bytes == 1: 
    198209            return "BOOLEAN" 
     
    202213##            return "MEDIUMINT" 
    203214        else: 
    204             return u"INTEGER" 
     215            return "INTEGER" 
    205216 
    206217 
     
    211222    """ 
    212223     
     224    # You should REALLY check into your DB's encoding and override this. 
     225    encoding = 'utf8' 
     226     
    213227    # Notice these are ordered pairs. Escape \ before introducing new ones. 
     228    # Values in these two lists should be strings encoded with self.encoding. 
    214229    escapes = [("'", "''"), ("\\", r"\\")] 
    215230    like_escapes = [("%", r"\%"), ("_", r"\_")] 
     
    223238    def escape_like(self, value): 
    224239        """Prepare a string value for use in a LIKE comparison.""" 
     240        if not isinstance(value, str): 
     241            value = value.encode(self.encoding) 
    225242        # Notice we strip leading and trailing quote-marks. 
    226243        value = value.strip("'\"") 
     
    235252     
    236253    def tostr(self, value): 
    237         return str(value) 
     254        if isinstance(value, basestring): 
     255            return value.encode(self.encoding) 
     256        else: 
     257            return str(value) 
    238258     
    239259    def coerce_NoneType(self, value): 
     
    249269    # and comparisons will still work! 
    250270    def coerce_datetime_datetime(self, value): 
    251         return (u"'%04d-%02d-%02d %02d:%02d:%02d'" % 
     271        return ("'%04d-%02d-%02d %02d:%02d:%02d'" % 
    252272                (value.year, value.month, value.day, 
    253273                 value.hour, value.minute, value.second)) 
    254274     
    255275    def coerce_datetime_date(self, value): 
    256         return u"'%04d-%02d-%02d'" % (value.year, value.month, value.day) 
     276        return "'%04d-%02d-%02d'" % (value.year, value.month, value.day) 
    257277     
    258278    def coerce_datetime_time(self, value): 
    259         return u"'%02d:%02d:%02d'" % (value.hour, value.minute, value.second) 
     279        return "'%02d:%02d:%02d'" % (value.hour, value.minute, value.second) 
    260280     
    261281    def coerce_datetime_timedelta(self, value): 
     
    267287     
    268288    def do_pickle(self, value): 
    269         return self.coerce_str(pickle.dumps(value)) 
     289        # Note: dumps with protocol 0 uses the 'raw-unicode-escape' 
     290        # encoding, and we take pains not to re-encode it with 
     291        # self.encoding. 
     292        value = pickle.dumps(value) 
     293        return self.coerce_str(value, skip_encoding=True) 
    270294     
    271295    coerce_dict = do_pickle 
     
    279303    coerce_long = tostr 
    280304     
    281     def coerce_str(self, value): 
     305    def coerce_str(self, value, skip_encoding=False): 
     306        if not skip_encoding and not isinstance(value, str): 
     307            value = value.encode(self.encoding) 
    282308        for pat, repl in self.escapes: 
    283309            value = value.replace(pat, repl) 
     
    300326    This base class is designed to work out-of-the-box with PostgreSQL 8. 
    301327    """ 
     328     
     329    # You should REALLY check into your DB's encoding and override this. 
     330    encoding = 'utf8' 
    302331     
    303332    def coerce(self, value, coltype, valuetype=None): 
     
    323352    def do_pickle(self, value, coltype): 
    324353        # Coerce to str for pickle.loads restriction. 
     354        if isinstance(value, unicode): 
     355            value = value.encode(self.encoding) 
    325356        value = str(value) 
    326357        return pickle.loads(value) 
     
    369400     
    370401    def coerce_str(self, value, coltype): 
    371         return str(value) 
     402        if isinstance(value, basestring): 
     403            return value.encode(self.encoding) 
     404        else: 
     405            return str(value) 
    372406     
    373407    coerce_tuple = do_pickle 
    374408     
    375409    def coerce_unicode(self, value, coltype): 
    376         # You should REALLY check into your DB's encoding and override this. 
    377         return unicode(value, "utf8") 
     410        if isinstance(value, unicode): 
     411            return value 
     412        else: 
     413            return unicode(value, self.encoding) 
    378414 
    379415 
    380416# -------------------------- SQL DECOMPILATION -------------------------- # 
    381417 
    382 class ConstWrapper(unicode): 
     418class ConstWrapper(str): 
    383419    """Wraps a constant for use in SQLDecompiler's stack. 
    384420     
     
    388424    """ 
    389425    def __new__(self, basevalue, coerced_value): 
    390         newobj = unicode.__new__(ConstWrapper, coerced_value) 
     426        newobj = str.__new__(ConstWrapper, coerced_value) 
    391427        newobj.basevalue = basevalue 
    392428        return newobj 
    393      
    394     def __str__(self): 
    395         return str(self) 
    396      
    397     def __unicode__(self): 
    398         return self 
    399      
    400     def __repr__(self): 
    401         return self 
    402429 
    403430 
     
    774801            return adapter_class 
    775802         
    776         adapter = get_adapter_option(u'Type Adapter') 
     803        adapter = get_adapter_option('Type Adapter') 
    777804        if adapter: self.typeAdapter = adapter 
    778         adapter = get_adapter_option(u'To Adapter') 
     805        adapter = get_adapter_option('To Adapter') 
    779806        if adapter: self.toAdapter = adapter 
    780         adapter = get_adapter_option(u'From Adapter') 
     807        adapter = get_adapter_option('From Adapter') 
    781808        if adapter: self.fromAdapter = adapter 
    782809         
    783         self.pool_size = int(allOptions.get(u'Pool Size', '10')) 
     810        self.pool_size = int(allOptions.get('Pool Size', '10')) 
    784811         
    785812        self.refs = {} 
     
    791818        self.threaded = True 
    792819         
    793         self.prefix = allOptions.get(u'Prefix', u"djv") 
     820        self.prefix = allOptions.get('Prefix', "djv") 
    794821        self.reserve_lock = threading.Lock() 
    795822         
    796823        ec = {} 
    797         for prop in allOptions.get(u'Expanded Columns', '').split(","): 
     824        for prop in allOptions.get('Expanded Columns', '').split(","): 
    798825            if prop: 
    799826                cls, type = [x.strip() for x in prop.split(":", 1)] 
     
    924951            fields = [self.column_name(clsname, x) for x in fields] 
    925952            if distinct: 
    926                 sql = u'SELECT DISTINCT %s FROM %s' 
     953                sql = 'SELECT DISTINCT %s FROM %s' 
    927954            else: 
    928                 sql = u'SELECT %s FROM %s' 
    929             sql = sql % (u', '.join(fields), tablename) 
    930         else: 
    931             sql = u'SELECT * FROM %s' % tablename 
     955                sql = 'SELECT %s FROM %s' 
     956            sql = sql % (', '.join(fields), tablename) 
     957        else: 
     958            sql = 'SELECT * FROM %s' % tablename 
    932959         
    933960        w, i = self.where((clsname,), expr) 
    934961        if len(w) > 0: 
    935             w = u" WHERE " + w 
    936         else: 
    937             w = u"" 
     962            w = " WHERE " + w 
     963        else: 
     964            w = "" 
    938965        sql += w + ";" 
    939966        return sql, i 
     
    947974        if conn is None: 
    948975            conn = self.connection() 
     976        if isinstance(query, unicode): 
     977            query = query.encode(self.toAdapter.encoding) 
    949978        self.arena.log(query, LOGSQL) 
    950         return conn.query(query.encode('utf8')
     979        return conn.query(query
    951980     
    952981    def fetch(self, query, conn=None): 
     
    10141043                id_fields = [self.column_name(clsname, prop.key) 
    10151044                             for prop in cls.identifiers] 
    1016                 data, cols = self.fetch(u'SELECT %s FROM %s;' % 
     1045                data, cols = self.fetch('SELECT %s FROM %s;' % 
    10171046                                        (', '.join(id_fields), tablename)) 
    10181047                if data: 
     
    10451074                    values.append(val) 
    10461075             
    1047             fields = u", ".join(fields) 
    1048             values = u", ".join(values) 
     1076            fields = ", ".join(fields) 
     1077            try: 
     1078                values = ", ".join(values) 
     1079            except UnicodeDecodeError: 
     1080                print values 
     1081                raise 
    10491082            self.execute('INSERT INTO %s (%s) VALUES (%s);' % 
    1050                          (tablename, fields, values)) 
     1083                         (str(tablename), fields, values)) 
    10511084            unit.cleanse() 
    10521085        finally: 
     
    10821115            if parms: 
    10831116                sql = ('UPDATE %s SET %s WHERE %s;' % 
    1084                        (self.table_name(clsname), u", ".join(parms), 
     1117                       (self.table_name(clsname), ", ".join(parms), 
    10851118                        self.id_clause(unit))) 
    10861119                self.execute(sql) 
     
    10951128        # Just drop the old table and start with a new one. 
    10961129        try: 
    1097             self.execute(u"DROP TABLE %s;" % table) 
     1130            self.execute("DROP TABLE %s;" % table) 
    10981131        except: 
    10991132            pass 
     
    11061139        else: 
    11071140            ftype = getattr(self.typeAdapter, "coerce_" + subtype)(unitcls, key) 
    1108             self.execute(u"CREATE TABLE %s (EXPVAL %s);" % (table, ftype)) 
     1141            self.execute("CREATE TABLE %s (EXPVAL %s);" % (table, ftype)) 
    11091142             
    11101143            for v in val: 
    1111                 self.execute(u"INSERT INTO %s (EXPVAL) VALUES ('%s');" 
     1144                self.execute("INSERT INTO %s (EXPVAL) VALUES ('%s');" 
    11121145                             % (table, self.toAdapter.coerce(v))) 
    11131146     
     
    11181151        table = self.table_name("_%s_%s_%s" % (unitcls.__name__, id, key)) 
    11191152        try: 
    1120             data, col_defs = self.fetch(u"SELECT EXPVAL FROM %s" % table) 
     1153            data, col_defs = self.fetch("SELECT EXPVAL FROM %s" % table) 
    11211154        except: 
    11221155            values = None 
     
    11381171        else: 
    11391172            star = "" 
    1140         self.execute(u'DELETE%s FROM %s WHERE %s;' % 
     1173        self.execute('DELETE%s FROM %s WHERE %s;' % 
    11411174                     (star, self.table_name(unit.__class__.__name__), 
    11421175                      self.id_clause(unit))) 
     
    12841317         
    12851318        statement = ("SELECT %s FROM %s WHERE %s" % 
    1286                      (u', '.join(colnames), joins, w)) 
     1319                     (', '.join(colnames), joins, w)) 
    12871320        return statement, imp, cols 
    12881321     
     
    13461379        fields = [] 
    13471380        for key in cls.properties(): 
    1348             fields.append(u'%s %s' % (self.column_name(clsname, key), 
     1381            fields.append('%s %s' % (self.column_name(clsname, key), 
    13491382                                      typename(cls, key))) 
    1350         self.execute(u'CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 
     1383        self.execute('CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 
    13511384         
    13521385        for index in cls.indices(): 
    13531386            i = self.table_name("i" + clsname + index) 
    1354             self.execute(u'CREATE INDEX %s ON %s (%s);' % 
     1387            self.execute('CREATE INDEX %s ON %s (%s);' % 
    13551388                         (i, tablename, self.column_name(clsname, index))) 
    13561389     
     
    13661399     
    13671400    def drop_storage(self, cls): 
    1368         self.execute(u'DROP TABLE %s;' % self.table_name(cls.__name__)) 
     1401        self.execute('DROP TABLE %s;' % self.table_name(cls.__name__)) 
    13691402     
    13701403    def add_property(self, cls, name): 
  • trunk/storage/storeado.py

    r171 r172  
    8686class AdapterFromADO(db.AdapterFromDB): 
    8787    """Coerce incoming values from ADO to Dejavu datatypes.""" 
     88     
     89    encoding = 'ISO-8859-1' 
    8890     
    8991    def coerce_datetime_datetime(self, value, coltype): 
     
    150152        if isinstance(value, (basestring, buffer)): 
    151153            try: 
    152                 return unicode(value, "ISO-8859-1"
     154                return unicode(value, self.encoding
    153155            except UnicodeError: 
    154156                raise StandardError(type(value)) 
     
    338340        if conn is None: 
    339341            conn = self.connection() 
     342        if isinstance(query, unicode): 
     343            query = query.encode(self.toAdapter.encoding) 
    340344        self.arena.log(query, dejavu.LOGSQL) 
    341345        try: 
     
    431435class AdapterToADOSQL_SQLServer(db.AdapterToSQL): 
    432436     
     437    encoding = 'ISO-8859-1' 
     438     
    433439    escapes = [("'", "''")] 
    434440    like_escapes = [("%", "[%]"), ("_", "[_]")] 
     
    450456    numeric_max_precision = 38 
    451457     
    452     def coerce_bool(self, cls, key): return u"BIT" 
     458    def coerce_bool(self, cls, key): 
     459        return "BIT" 
    453460     
    454461    def coerce_datetime_datetime(self, cls, key): 
    455         return u"DATETIME" 
     462        return "DATETIME" 
    456463     
    457464    def coerce_datetime_date(self, cls, key): 
    458         return u"DATETIME" 
     465        return "DATETIME" 
    459466     
    460467    def coerce_datetime_time(self, cls, key): 
    461         return u"DATETIME" 
     468        return "DATETIME" 
    462469     
    463470    def coerce_str(self, cls, key): 
    464471        # The bytes hint does not reflect the usual 4-byte base for varchar. 
    465472        prop = getattr(cls, key) 
    466         bytes = int(prop.hints.get(u'bytes', '0')) 
     473        bytes = int(prop.hints.get('bytes', '0')) 
    467474        if bytes == 0: 
    468475            # Okay, what the @#$%& is wrong with Redmond??!?! We can't even 
     
    480487        # might exceed the max size (8060) for a record. We could calc the 
    481488        # total requested record size, and adjust accordingly. Meh. 
    482         return u"VARCHAR(%s)" % bytes 
     489        return "VARCHAR(%s)" % bytes 
    483490 
    484491 
     
    491498        db.StorageManagerDB.__init__(self, name, arena, allOptions) 
    492499         
    493         self.connstring = allOptions[u'Connect'] 
     500        self.connstring = allOptions['Connect'] 
    494501        atoms = self.connatoms() 
    495         self.dbname = atoms[u'INITIAL CATALOG'] 
     502        self.dbname = atoms['INITIAL CATALOG'] 
    496503     
    497504    def create_database(self): 
     
    554561    numeric_max_precision = 15 
    555562     
    556     def coerce_bool(self, cls, key): return u"BIT" 
    557      
    558     def coerce_datetime_datetime(self, cls, key): return u"DATETIME" 
    559     def coerce_datetime_date(self, cls, key): return u"DATETIME" 
    560     def coerce_datetime_time(self, cls, key): return u"DATETIME" 
     563    def coerce_bool(self, cls, key): return "BIT" 
     564     
     565    def coerce_datetime_datetime(self, cls, key): return "DATETIME" 
     566    def coerce_datetime_date(self, cls, key): return "DATETIME" 
     567    def coerce_datetime_time(self, cls, key): return "DATETIME" 
    561568     
    562569    def numeric_type(self, cls, key, precision, scale): 
     
    600607            precision = decimal.getcontext().prec 
    601608        # Assume most people use decimal for money; default scale = 2. 
    602         scale = int(prop.hints.get(u'scale', 2)) 
     609        scale = int(prop.hints.get('scale', 2)) 
    603610        return self.numeric_type(cls, key, precision, scale) 
    604611     
     
    609616            precision = self.numeric_max_precision 
    610617        # Assume most people use decimal for money; default scale = 2. 
    611         scale = int(prop.hints.get(u'scale', 2)) 
     618        scale = int(prop.hints.get('scale', 2)) 
    612619        return self.numeric_type(cls, key, precision, scale) 
    613620     
    614621    def coerce_int(self, cls, key): 
    615622        prop = getattr(cls, key) 
    616         bytes = int(prop.hints.get(u'bytes', '4')) 
     623        bytes = int(prop.hints.get('bytes', '4')) 
    617624        if bytes == 1: 
    618625            return "BIT" 
    619626        else: 
    620             return u"INTEGER" 
     627            return "INTEGER" 
    621628     
    622629    def coerce_long(self, cls, key): 
    623630        prop = getattr(cls, key) 
    624         bytes = int(prop.hints.get(u'bytes', 0)) 
     631        bytes = int(prop.hints.get('bytes', 0)) 
    625632        return self.numeric_type(cls, key, precision, 0) 
    626633     
     
    628635        # The bytes hint shall not reflect the usual 4-byte base for varchar. 
    629636        prop = getattr(cls, key) 
    630         bytes = int(prop.hints.get(u'bytes', '0')) 
     637        bytes = int(prop.hints.get('bytes', '0')) 
    631638        if bytes and bytes <= 255: 
    632639            # 255 chars is the upper limit for TEXT / VARCHAR in MS Access. 
    633             return u"VARCHAR(%s)" % bytes 
     640            return "VARCHAR(%s)" % bytes 
    634641        else: 
    635642            # MEMO is 1 GB max when set programatically (only 64K when set 
     
    641648                                  % (cls.__name__, key), 
    642649                                  dejavu.StorageWarning) 
    643             return u"MEMO" 
     650            return "MEMO" 
    644651 
    645652 
     
    647654    """Coerce Expression constants to ADO SQL.""" 
    648655     
     656    encoding = 'ISO-8859-1' 
     657     
    649658    escapes = [("'", "''")] 
    650659    like_escapes = [("%", "[%]"), ("_", "[_]")] 
    651660     
    652661    def coerce_datetime_datetime(self, value): 
    653         return (u'#%s/%s/%s %02d:%02d:%02d#' % 
     662        return ('#%s/%s/%s %02d:%02d:%02d#' % 
    654663                (value.month, value.day, value.year, 
    655664                 value.hour, value.minute, value.second)) 
    656665     
    657666    def coerce_datetime_date(self, value): 
    658         return u'#%s/%s/%s#' % (value.month, value.day, value.year) 
     667        return '#%s/%s/%s#' % (value.month, value.day, value.year) 
    659668     
    660669    def coerce_datetime_time(self, value): 
    661         return u'#%02d:%02d:%02d#' % (value.hour, value.minute, value.second) 
     670        return '#%02d:%02d:%02d#' % (value.hour, value.minute, value.second) 
    662671 
    663672 
     
    674683        db.StorageManagerDB.__init__(self, name, arena, allOptions) 
    675684         
    676         self.connstring = allOptions[u'Connect'] 
     685        self.connstring = allOptions['Connect'] 
    677686        atoms = self.connatoms() 
    678         self.dbname = (atoms.get(u'DATA SOURCE') or 
    679                        atoms.get(u'DATA SOURCE NAME') or 
    680                        atoms.get(u'DBQ')) 
     687        self.dbname = (atoms.get('DATA SOURCE') or 
     688                       atoms.get('DATA SOURCE NAME') or 
     689                       atoms.get('DBQ')) 
    681690        # MS Access can't use a pool, because there doesn't seem 
    682691        # to be a commit timeout. 
  • trunk/storage/storemysql.py

    r171 r172  
    2929    bool_false = "0" 
    3030     
    31     def coerce_str(self, value): 
     31    def coerce_str(self, value, skip_encoding=False): 
     32        if not skip_encoding and not isinstance(value, str): 
     33            value = value.encode(self.encoding) 
    3234        return "'" + _mysql.escape_string(value) + "'" 
    3335     
     
    4648            value = (value == '1') 
    4749        return bool(value) 
    48      
    49     def coerce_unicode(self, value, coltype): 
    50         return unicode(value, "utf-8") 
    5150 
    5251 
     
    9392    def coerce_str(self, cls, key): 
    9493        prop = getattr(cls, key) 
    95         bytes = int(prop.hints.get(u'bytes', '0')) 
     94        bytes = int(prop.hints.get('bytes', '0')) 
    9695        if bytes: 
    9796            # MySQL VARBINARY/BLOBs will do case-sensitive comparisons. 
    9897            # They also won't truncate trailing spaces like VARCHAR does. 
    9998            if bytes <= 255: 
    100                 return u"VARBINARY(%s)" % bytes 
     99                return "VARBINARY(%s)" % bytes 
    101100            elif bytes < 2 ** 16: 
    102101                return "BLOB" 
    103102            elif bytes < 2 ** 24: 
    104103                return "MEDIUMBLOB" 
    105         return u"LONGBLOB" 
     104        return "LONGBLOB" 
    106105     
    107106    def coerce_bool(self, cls, key): 
    108107        # We could use BOOLEAN, but it wasn't introduced until 4.1.0. 
    109         return u"BOOL" 
     108        return "BOOL" 
    110109     
    111110    def coerce_datetime_datetime(self, cls, key): 
    112         return u"DATETIME" 
     111        return "DATETIME" 
    113112 
    114113 
     
    188187    def destroy(self, unit): 
    189188        """destroy(unit). Delete the unit.""" 
    190         self.execute(u'DELETE FROM %s WHERE %s;' % 
     189        self.execute('DELETE FROM %s WHERE %s;' % 
    191190                     (self.table_name(unit.__class__.__name__), 
    192191                      self.id_clause(unit))) 
     
    220219        fields = [] 
    221220        for key in cls.properties(): 
    222             fields.append(u'%s %s' % (self.column_name(clsname, key), 
     221            fields.append('%s %s' % (self.column_name(clsname, key), 
    223222                                      coerce(cls, key))) 
    224         self.execute(u'CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 
     223        self.execute('CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 
    225224         
    226225        for index in cls.indices(): 
     
    231230                # MySQL won't allow indexes on a BLOB field 
    232231                # without a specific length. 
    233                 self.execute(u'CREATE INDEX %s ON %s (%s(%s));' % 
     232                self.execute('CREATE INDEX %s ON %s (%s(%s));' % 
    234233                             (i, tablename, 
    235234                              self.column_name(clsname, index), 255)) 
    236235            else: 
    237                 self.execute(u'CREATE INDEX %s ON %s (%s);' % 
     236                self.execute('CREATE INDEX %s ON %s (%s);' % 
    238237                             (i, tablename, 
    239238                              self.column_name(clsname, index))) 
  • trunk/storage/storepypgsql.py

    r171 r172  
    5050         
    5151        # connstring = (host=h port=p dbname=d user=u password=p options=o tty=t) 
    52         self.connstring = allOptions[u'Connect'] 
     52        self.connstring = allOptions['Connect'] 
    5353        atoms = self.connstring.split(" ") 
    5454        for atom in atoms: 
     
    112112    def has_storage(self, cls): 
    113113        # For some odd reason, libpq errors if you try to filter by tablename. 
    114         sql = u"SELECT tablename FROM pg_tables" 
     114        sql = "SELECT tablename FROM pg_tables" 
    115115        data, cols = self.fetch(sql) 
    116116        return [self.table_name(cls.__name__, quoted=False)] in data 
  • trunk/storage/storesqlite.py

    r171 r172  
    143143        db.StorageManagerDB.__init__(self, name, arena, allOptions) 
    144144         
    145         dbfile = allOptions.get(u'Database', '') 
     145        dbfile = allOptions.get('Database', '') 
    146146        if not os.path.isabs(dbfile): 
    147147            dbfile = os.path.join(os.getcwd(), dbfile) 
    148148        self.database = dbfile 
    149149         
    150         self.mode = int(allOptions.get(u'Mode', '0755'), 8) 
     150        self.mode = int(allOptions.get('Mode', '0755'), 8) 
    151151     
    152152    def sql_name(self, name, quoted=True): 
     
    179179            if conn is None: 
    180180                conn = self.connection() 
     181            if isinstance(query, unicode): 
     182                query = query.encode(self.toAdapter.encoding) 
    181183            self.arena.log(query, dejavu.LOGSQL) 
    182             return conn.execute(query.encode('utf8')
     184            return conn.execute(query
    183185            #           ^^^^^^^ 
    184186        except Exception, x: 
     
    259261        fields = [self.column_name(clsname, key) for key in cls.properties()] 
    260262         
    261         self.execute(u'CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 
     263        self.execute('CREATE TABLE %s (%s);' % (tablename, ", ".join(fields))) 
    262264        for index in cls.indices(): 
    263265            i = self.table_name("i" + clsname + index) 
    264             self.execute(u'CREATE INDEX %s ON %s (%s);' % 
     266            self.execute('CREATE INDEX %s ON %s (%s);' % 
    265267                         (i, tablename, self.column_name(clsname, index))) 
    266268     
  • trunk/test/zoo_fixture.py

    r171 r172  
    105105    Animals = UnitProperty(list) 
    106106    PettingAllowed = UnitProperty(bool) 
     107    Creators = UnitProperty(tuple) 
     108     
    107109    if decimal: 
    108110        Acreage = UnitProperty(decimal.Decimal) 
     
    222224                     PettingAllowed = True, 
    223225                     Acreage = "3.21", 
     226                     # See ticket #45 
     227                     Creators = (u'Richard F\xfcrst', u'Sonja Martin'), 
    224228                     ) 
    225229        box.memorize(pe) 
     
    744748    """Dejavu logger (writes to error.log).""" 
    745749    if flag & arena.logflags: 
    746         s = "%s %s" % (datetime.datetime.now().isoformat(), 
    747                        message.encode('utf8')) 
     750        if isinstance(message, unicode): 
     751            message = message.encode('utf8') 
     752        s = "%s %s" % (datetime.datetime.now().isoformat(), message) 
    748753        fname = os.path.join(os.path.dirname(__file__), "djvtest.log") 
    749754        f = open(fname, 'ab')