From: Mike Bayer Date: Wed, 7 Apr 2010 20:07:55 +0000 (-0400) Subject: - Repaired missing import in psycopg2._PGNumeric type when X-Git-Tag: rel_0_6_0~27^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3351b65df94324b2baba87da303c9db3454653d6;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Repaired missing import in psycopg2._PGNumeric type when unknown numeric is received. - psycopg2/pg8000 dialects now aware of REAL[], FLOAT[], DOUBLE_PRECISION[], NUMERIC[] return types without raising an exception. - introducing testing.provide_metadata for all these stupid little create/drop tests --- diff --git a/CHANGES b/CHANGES index c556ce6c6d..f027db6475 100644 --- a/CHANGES +++ b/CHANGES @@ -109,6 +109,13 @@ CHANGES has been changed. Thanks to Kumar McMillan for the patch. [ticket:1071] + - Repaired missing import in psycopg2._PGNumeric type when + unknown numeric is received. + + - psycopg2/pg8000 dialects now aware of REAL[], FLOAT[], + DOUBLE_PRECISION[], NUMERIC[] return types without + raising an exception. + - oracle - Now using cx_oracle output converters so that the DBAPI returns natively the kinds of values we prefer: diff --git a/lib/sqlalchemy/dialects/postgresql/pg8000.py b/lib/sqlalchemy/dialects/postgresql/pg8000.py index a620daac6a..c822e37a57 100644 --- a/lib/sqlalchemy/dialects/postgresql/pg8000.py +++ b/lib/sqlalchemy/dialects/postgresql/pg8000.py @@ -31,18 +31,18 @@ from sqlalchemy.dialects.postgresql.base import PGDialect, \ class _PGNumeric(sqltypes.Numeric): def result_processor(self, dialect, coltype): if self.asdecimal: - if coltype in (700, 701): + if coltype in (700, 701, 1021, 1022): return processors.to_decimal_processor_factory(decimal.Decimal) - elif coltype == 1700: + elif coltype in (1700, 1231): # pg8000 returns Decimal natively for 1700 return None else: raise exc.InvalidRequestError("Unknown PG numeric type: %d" % coltype) else: - if coltype in (700, 701): + if coltype in (700, 701, 1021, 1022): # pg8000 returns float natively for 701 return None - elif coltype == 1700: + elif coltype in (1700, 1231): return processors.to_float else: raise exc.InvalidRequestError("Unknown PG numeric type: %d" % coltype) diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index f21c9a5589..45d1bf29e5 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -60,7 +60,7 @@ import re import decimal import logging -from sqlalchemy import util +from sqlalchemy import util, exc from sqlalchemy import processors from sqlalchemy.engine import base, default from sqlalchemy.sql import expression @@ -80,18 +80,18 @@ class _PGNumeric(sqltypes.Numeric): def result_processor(self, dialect, coltype): if self.asdecimal: - if coltype in (700, 701): + if coltype in (700, 701, 1021, 1022): return processors.to_decimal_processor_factory(decimal.Decimal) - elif coltype == 1700: + elif coltype in (1700, 1231): # pg8000 returns Decimal natively for 1700 return None else: raise exc.InvalidRequestError("Unknown PG numeric type: %d" % coltype) else: - if coltype in (700, 701): + if coltype in (700, 701, 1021, 1022): # pg8000 returns float natively for 701 return None - elif coltype == 1700: + elif coltype in (1700, 1231): return processors.to_float else: raise exc.InvalidRequestError("Unknown PG numeric type: %d" % coltype) diff --git a/lib/sqlalchemy/test/testing.py b/lib/sqlalchemy/test/testing.py index 771b8c90fb..70ddc7ba20 100644 --- a/lib/sqlalchemy/test/testing.py +++ b/lib/sqlalchemy/test/testing.py @@ -546,6 +546,23 @@ def fixture(table, columns, *rows): for column_values in rows]) table.append_ddl_listener('after-create', onload) +def provide_metadata(fn): + """Provides a bound MetaData object for a single test, + drops it afterwards.""" + def maybe(*args, **kw): + metadata = schema.MetaData(db) + context = dict(fn.func_globals) + context['metadata'] = metadata + # jython bug #1034 + rebound = types.FunctionType( + fn.func_code, context, fn.func_name, fn.func_defaults, + fn.func_closure) + try: + return rebound(*args, **kw) + finally: + metadata.drop_all() + return function_named(maybe, fn.__name__) + def resolve_artifact_names(fn): """Decorator, augment function globals with tables and classes. diff --git a/test/dialect/test_postgresql.py b/test/dialect/test_postgresql.py index fbe62cdec8..bcf8ac9562 100644 --- a/test/dialect/test_postgresql.py +++ b/test/dialect/test_postgresql.py @@ -228,7 +228,21 @@ class FloatCoercionTest(TablesTest, AssertsExecutionResults): ).scalar() eq_(round_decimal(ret, 9), result) - + @testing.provide_metadata + def test_arrays(self): + t1 = Table('t', metadata, + Column('x', postgresql.ARRAY(Float)), + Column('y', postgresql.ARRAY(postgresql.REAL)), + Column('z', postgresql.ARRAY(postgresql.DOUBLE_PRECISION)), + Column('q', postgresql.ARRAY(Numeric)) + ) + metadata.create_all() + t1.insert().execute(x=[5], y=[5], z=[6], q=[6.4]) + row = t1.select().execute().first() + eq_( + row, + ([5], [5], [6], [decimal.Decimal("6.4")]) + ) class EnumTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL): __only_on__ = 'postgresql' @@ -1311,8 +1325,17 @@ class MiscTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL): else: exception_cls = eng.dialect.dbapi.ProgrammingError assert_raises(exception_cls, eng.execute, "show transaction isolation level") - - + + @testing.only_on('postgresql+psycopg2', + "this assertion isn't used on others, " + "except pg8000 which circumvents it") + def test_numeric_raise(self): + stmt = text("select 'hi' as hi", typemap={'hi':Numeric}) + assert_raises( + exc.InvalidRequestError, + testing.db.execute, stmt + ) + class TimezoneTest(TestBase): """Test timezone-aware datetimes.