From bed76729a297f75fd74574eefc1801b60c00e789 Mon Sep 17 00:00:00 2001 From: Konsta Vesterinen Date: Mon, 9 Nov 2015 17:06:14 +0200 Subject: [PATCH] Fix non ascii string handling with composite types, refs #170 --- CHANGES.rst | 6 ++++++ sqlalchemy_utils/__init__.py | 2 +- sqlalchemy_utils/types/pg_composite.py | 14 ++++++++++++-- tests/types/test_composite.py | 13 +++++++++++++ 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index a4e0122..d45432f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,6 +4,12 @@ Changelog Here you can see the full list of changes between each SQLAlchemy-Utils release. +0.31.3 (2015-11-09) +^^^^^^^^^^^^^^^^^^^ + +- Fixed non-ascii string handling in composite types (#170) + + 0.31.2 (2015-10-30) ^^^^^^^^^^^^^^^^^^^ diff --git a/sqlalchemy_utils/__init__.py b/sqlalchemy_utils/__init__.py index cab47cc..ed56e95 100644 --- a/sqlalchemy_utils/__init__.py +++ b/sqlalchemy_utils/__init__.py @@ -93,4 +93,4 @@ from .types import ( # noqa WeekDaysType ) -__version__ = '0.31.2' +__version__ = '0.31.3' diff --git a/sqlalchemy_utils/types/pg_composite.py b/sqlalchemy_utils/types/pg_composite.py index 255e0d8..b195f3a 100644 --- a/sqlalchemy_utils/types/pg_composite.py +++ b/sqlalchemy_utils/types/pg_composite.py @@ -95,6 +95,7 @@ http://schinckel.net/2014/09/24/using-postgres-composite-types-in-django/ """ from collections import namedtuple +import six import sqlalchemy as sa from sqlalchemy.dialects.postgresql import ARRAY from sqlalchemy.dialects.postgresql.psycopg2 import PGDialect_psycopg2 @@ -259,7 +260,7 @@ def register_psycopg2_composite(dbapi_connection, composite): ) def adapt_composite(value): - values = [ + adapted = [ adapt( getattr(value, column.name) if not isinstance(column.type, TypeDecorator) @@ -267,10 +268,19 @@ def register_psycopg2_composite(dbapi_connection, composite): getattr(value, column.name), PGDialect_psycopg2() ) - ).getquoted().decode('utf-8') + ) for column in composite.columns ] + for value in adapted: + if hasattr(value, 'prepare'): + value.prepare(dbapi_connection) + values = [ + value.getquoted().decode(dbapi_connection.encoding) + if six.PY3 + else value.getquoted() + for value in adapted + ] return AsIs("(%s)::%s" % (', '.join(values), composite.name)) register_adapter(composite.type_cls, adapt_composite) diff --git a/tests/types/test_composite.py b/tests/types/test_composite.py index d748606..f5f7fba 100644 --- a/tests/types/test_composite.py +++ b/tests/types/test_composite.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- import sqlalchemy as sa from pytest import mark from sqlalchemy import create_engine @@ -50,6 +51,18 @@ class TestCompositeTypeWithRegularTypes(TestCase): assert account.balance.currency == 'USD' assert account.balance.amount == 15 + def test_non_ascii_chars(self): + account = self.Account( + balance=(u'ääöö', 15) + ) + + self.session.add(account) + self.session.commit() + + account = self.session.query(self.Account).first() + assert account.balance.currency == u'ääöö' + assert account.balance.amount == 15 + @mark.skipif('i18n.babel is None') class TestCompositeTypeWithTypeDecorators(TestCase):