Does UnicodeText even converts to unicode?

Issue #2216 resolved
Former user created an issue

When you use the UnicodeText type it does not perform any convertions to unicode. As a result you can not save an object that was subclassed from unicode.

For example:

engine = create_engine('postgresql://localhost/bungeni-test', echo=True)

metadata = MetaData()
metadata.bind = engine

test_table = Table('test123', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', UnicodeText),
)

class TestObject(object):
    pass

    def __str__(self):
        return self.name

mapper(TestObject, test_table)
Session = sessionmaker()
Session.configure(bind=engine)
session = Session()

class UnicodeSubType(unicode):

    _bad_attribute = None

    def __new__(cls, ustr, bad_attribute=None):
        self = unicode.__new__(cls, ustr)
        self._bad_attribute = bad_attribute
        return self

ob = TestObject()
ob.name = UnicodeSubType("TestObject Text")
session.add(ob)
session.flush()

Will raise an error (ProgrammingError) can't adapt type 'UnicodeSubType'

Adding a test script to recreate.

Comments (3)

  1. Mike Bayer repo owner

    The script runs fully for me against a PG database, psycopg2 2.2.4, as indicated below.

    psycopg2 accepts Python unicode literals directly, so SQLAlchemy has no need to process incoming Python unicode binds when used with this backend (and note that a unicode subclass is still isinstance(x, unicode)). If a particular version here is not accepting your subclass, you can set convert_unicode='force' on the UnicodeText type, which will encode it to a string with utf-8 or whatever engine.encoding is set to, though its likely best to just upgrade your psycopg2.

    classics-MacBook-Pro:sqlalchemy classic$ python test.py
    2011-07-12 10:29:20,107 INFO sqlalchemy.engine.base.Engine select version()
    2011-07-12 10:29:20,107 INFO sqlalchemy.engine.base.Engine {}
    2011-07-12 10:29:20,109 INFO sqlalchemy.engine.base.Engine select current_schema()
    2011-07-12 10:29:20,109 INFO sqlalchemy.engine.base.Engine {}
    2011-07-12 10:29:20,111 INFO sqlalchemy.engine.base.Engine select relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where n.nspname=current_schema() and lower(relname)=%(name)s
    2011-07-12 10:29:20,111 INFO sqlalchemy.engine.base.Engine {'name': u'test123'}
    2011-07-12 10:29:20,115 INFO sqlalchemy.engine.base.Engine 
    DROP TABLE test123
    2011-07-12 10:29:20,115 INFO sqlalchemy.engine.base.Engine {}
    2011-07-12 10:29:20,118 INFO sqlalchemy.engine.base.Engine COMMIT
    2011-07-12 10:29:20,120 INFO sqlalchemy.engine.base.Engine select relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where n.nspname=current_schema() and lower(relname)=%(name)s
    2011-07-12 10:29:20,120 INFO sqlalchemy.engine.base.Engine {'name': u'test123'}
    2011-07-12 10:29:20,122 INFO sqlalchemy.engine.base.Engine 
    CREATE TABLE test123 (
        id SERIAL NOT NULL, 
        name TEXT, 
        PRIMARY KEY (id)
    )
    
    
    2011-07-12 10:29:20,122 INFO sqlalchemy.engine.base.Engine {}
    2011-07-12 10:29:20,129 INFO sqlalchemy.engine.base.Engine COMMIT
    2011-07-12 10:29:20,131 INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
    /Users/classic/dev/sqlalchemy/lib/sqlalchemy/engine/default.py:460: SAWarning: Unicode type received non-unicode bind param value.
      processors[key](key)(compiled_params[key](key))
    2011-07-12 10:29:20,132 INFO sqlalchemy.engine.base.Engine INSERT INTO test123 (name) VALUES (%(name)s) RETURNING test123.id
    2011-07-12 10:29:20,132 INFO sqlalchemy.engine.base.Engine {'name': 'TestObject Text'}
    2011-07-12 10:29:20,134 INFO sqlalchemy.engine.base.Engine SELECT test123.id AS test123_id, test123.name AS test123_name 
    FROM test123
    2011-07-12 10:29:20,134 INFO sqlalchemy.engine.base.Engine {}
    [object at 0x128b590>](<__main__.TestObject)
    2011-07-12 10:29:20,135 INFO sqlalchemy.engine.base.Engine SELECT test123.id AS test123_id, test123.name AS test123_name 
    FROM test123 
     LIMIT %(param_1)s OFFSET %(param_2)s
    2011-07-12 10:29:20,135 INFO sqlalchemy.engine.base.Engine {'param_1': 1, 'param_2': 0}
    <type 'str'>
    2011-07-12 10:29:20,136 INFO sqlalchemy.engine.base.Engine INSERT INTO test123 (name) VALUES (%(name)s) RETURNING test123.id
    2011-07-12 10:29:20,136 INFO sqlalchemy.engine.base.Engine {'name': u'TestObject Text'}
    2011-07-12 10:29:20,137 INFO sqlalchemy.engine.base.Engine SELECT test123.id AS test123_id, test123.name AS test123_name 
    FROM test123
    2011-07-12 10:29:20,137 INFO sqlalchemy.engine.base.Engine {}
    [object at 0x13154f0>, <__main__.TestObject object at 0x128b670>](<__main__.TestObject)
    2011-07-12 10:29:20,138 INFO sqlalchemy.engine.base.Engine SELECT test123.id AS test123_id, test123.name AS test123_name 
    FROM test123 
     LIMIT %(param_1)s OFFSET %(param_2)s
    2011-07-12 10:29:20,138 INFO sqlalchemy.engine.base.Engine {'param_1': 1, 'param_2': 0}
    <type 'unicode'>
    classics-MacBook-Pro:sqlalchemy classic$
    
  2. Former user Account Deleted

    yes the problem was in psycopg 2.2.0 (You have 2.4.2, because there is no 2.2.4 package.). It was fixed starting with 2.3.0

  3. Log in to comment