From 6b79d2ea7951abc2bb6083b541db0fbf71590dd3 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 22 Nov 2013 20:04:19 -0500 Subject: - The precision used when coercing a returned floating point value to Python ``Decimal`` via string is now configurable. The flag ``decimal_return_scale`` is now supported by all :class:`.Numeric` and :class:`.Float` types, which will ensure this many digits are taken from the native floating point value when it is converted to string. If not present, the type will make use of the value of ``.scale``, if the type supports this setting and it is non-None. Otherwise the original default length of 10 is used. [ticket:2867] --- lib/sqlalchemy/dialects/postgresql/psycopg2.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/sqlalchemy/dialects/postgresql/psycopg2.py') diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index 02eda094e..9995a1f5a 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -191,7 +191,8 @@ class _PGNumeric(sqltypes.Numeric): def result_processor(self, dialect, coltype): if self.asdecimal: if coltype in _FLOAT_TYPES: - return processors.to_decimal_processor_factory(decimal.Decimal) + return processors.to_decimal_processor_factory( + decimal.Decimal, self.decimal_return_scale) elif coltype in _DECIMAL_TYPES or coltype in _INT_TYPES: # pg8000 returns Decimal natively for 1700 return None -- cgit v1.2.1 From 4acfce6c4c1da91901921ddfae7a682771817945 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sat, 23 Nov 2013 17:19:43 -0500 Subject: - evaulate decimal_return_scale statelessly. Don't re-assign to self.decimal_return_scale so that __repr__() is maintained (for alembic tests) --- lib/sqlalchemy/dialects/postgresql/psycopg2.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/sqlalchemy/dialects/postgresql/psycopg2.py') diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index 9995a1f5a..d7ce6eb90 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -192,7 +192,8 @@ class _PGNumeric(sqltypes.Numeric): if self.asdecimal: if coltype in _FLOAT_TYPES: return processors.to_decimal_processor_factory( - decimal.Decimal, self.decimal_return_scale) + decimal.Decimal, + self._effective_decimal_return_scale) elif coltype in _DECIMAL_TYPES or coltype in _INT_TYPES: # pg8000 returns Decimal natively for 1700 return None -- cgit v1.2.1 From f285b3536fe01f21409e201fbeeac559ab423a9d Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 10 Dec 2013 10:01:51 -0500 Subject: sqlalchemy/dialects/postgresql/pgjson: - Fixed reference to HSTORE - Corrected spelling of SQLAlchemy sqlalchemy/dialects/postgresql/psycopg2: - Added psycopg2 specific wrapper type for JSON which uses inherent json deserialization facilities - Added code to detect and utilize the JSON wrapper if psycopg2 >= 2.5 test/dialect/postgresql/test_types: - removed reference to use_native_hstore --- lib/sqlalchemy/dialects/postgresql/psycopg2.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'lib/sqlalchemy/dialects/postgresql/psycopg2.py') diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index d7ce6eb90..1f4078500 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -168,6 +168,8 @@ from __future__ import absolute_import import re import logging +import psycopg2.extensions as ext + from ... import util, exc import decimal from ... import processors @@ -179,6 +181,7 @@ from .base import PGDialect, PGCompiler, \ ENUM, ARRAY, _DECIMAL_TYPES, _FLOAT_TYPES,\ _INT_TYPES from .hstore import HSTORE +from .pgjson import JSON logger = logging.getLogger('sqlalchemy.dialects.postgresql') @@ -243,6 +246,17 @@ class _PGHStore(HSTORE): else: return super(_PGHStore, self).result_processor(dialect, coltype) + +class _PGJSON(JSON): + # I've omitted the bind processor here because the method of serializing + # involves registering specific types to auto-serialize, and the adapter + # just a thin wrapper over json.dumps. + def result_processor(self, dialect, coltype): + if dialect._has_native_json: + return None + else: + return super(_PGJSON, self).result_processor(dialect, coltype) + # When we're handed literal SQL, ensure it's a SELECT-query. Since # 8.3, combining cursors and "FOR UPDATE" has been fine. SERVER_SIDE_CURSOR_RE = re.compile( @@ -327,6 +341,7 @@ class PGDialect_psycopg2(PGDialect): psycopg2_version = (0, 0) _has_native_hstore = False + _has_native_json = False colspecs = util.update_copy( PGDialect.colspecs, @@ -336,6 +351,7 @@ class PGDialect_psycopg2(PGDialect): sqltypes.Enum: _PGEnum, # needs force_unicode ARRAY: _PGArray, # needs force_unicode HSTORE: _PGHStore, + JSON: _PGJSON } ) @@ -363,6 +379,7 @@ class PGDialect_psycopg2(PGDialect): self._has_native_hstore = self.use_native_hstore and \ self._hstore_oids(connection.connection) \ is not None + self._has_native_json = self.psycopg2_version >= (2, 5) @classmethod def dbapi(cls): -- cgit v1.2.1 From 059039e0f7eaeeaf7ab49181a99a5edeb67d9f28 Mon Sep 17 00:00:00 2001 From: nathan Date: Tue, 10 Dec 2013 10:09:15 -0500 Subject: sqlalchemy/dialects/postgresql/psycopg2: - Removed unneeded import of psycopg2.extensions --- lib/sqlalchemy/dialects/postgresql/psycopg2.py | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib/sqlalchemy/dialects/postgresql/psycopg2.py') diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index 1f4078500..0dbdfe8fb 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -168,8 +168,6 @@ from __future__ import absolute_import import re import logging -import psycopg2.extensions as ext - from ... import util, exc import decimal from ... import processors -- cgit v1.2.1 From b2223ab14988317f86fcbb6271a8b853b2924bae Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 15 Dec 2013 21:23:01 -0500 Subject: - add "force_nocheck" as a way to turn on unicode=force without even doing the isinstance() check - currently used only by psycopg2 + native enum + py2k. - didn't realize psycopg2 had UNICODEARRAY extension all this time; replace _PGArray with just using UNICODEARRAY instead. - replace unnecessary/inconsistent __import__ in _isolation_lookup. --- lib/sqlalchemy/dialects/postgresql/psycopg2.py | 28 +++++++++----------------- 1 file changed, 9 insertions(+), 19 deletions(-) (limited to 'lib/sqlalchemy/dialects/postgresql/psycopg2.py') diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index d7ce6eb90..c3c749523 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -212,23 +212,13 @@ class _PGNumeric(sqltypes.Numeric): class _PGEnum(ENUM): - def __init__(self, *arg, **kw): - super(_PGEnum, self).__init__(*arg, **kw) - if util.py2k: - if self.convert_unicode: - self.convert_unicode = "force" - - -class _PGArray(ARRAY): - def __init__(self, *arg, **kw): - super(_PGArray, self).__init__(*arg, **kw) - if util.py2k: - # FIXME: this check won't work for setups that - # have convert_unicode only on their create_engine(). - if isinstance(self.item_type, sqltypes.String) and \ - self.item_type.convert_unicode: - self.item_type.convert_unicode = "force" - + def result_processor(self, dialect, coltype): + if util.py2k and self.convert_unicode is True: + # we can't easily use PG's extensions here because + # the OID is on the fly, and we need to give it a python + # function anyway - not really worth it. + self.convert_unicode = "force_nocheck" + return super(_PGEnum, self).result_processor(dialect, coltype) class _PGHStore(HSTORE): def bind_processor(self, dialect): @@ -334,7 +324,6 @@ class PGDialect_psycopg2(PGDialect): sqltypes.Numeric: _PGNumeric, ENUM: _PGEnum, # needs force_unicode sqltypes.Enum: _PGEnum, # needs force_unicode - ARRAY: _PGArray, # needs force_unicode HSTORE: _PGHStore, } ) @@ -371,7 +360,7 @@ class PGDialect_psycopg2(PGDialect): @util.memoized_property def _isolation_lookup(self): - extensions = __import__('psycopg2.extensions').extensions + from psycopg2 import extensions return { 'AUTOCOMMIT': extensions.ISOLATION_LEVEL_AUTOCOMMIT, 'READ COMMITTED': extensions.ISOLATION_LEVEL_READ_COMMITTED, @@ -409,6 +398,7 @@ class PGDialect_psycopg2(PGDialect): if self.dbapi and self.use_native_unicode: def on_connect(conn): extensions.register_type(extensions.UNICODE, conn) + extensions.register_type(extensions.UNICODEARRAY, conn) fns.append(on_connect) if self.dbapi and self.use_native_hstore: -- cgit v1.2.1 From 73013914e7eae2a0480492ece085b48c5938dd84 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 17 Dec 2013 15:13:39 -0500 Subject: - rework JSON expressions to be based off __getitem__ exclusively - add support for "standalone" JSON objects; this involves getting CAST to upgrade the given type of a bound parameter. should add a core-only test for this. - add tests for "standalone" json round trips both with and without unicode - add mechanism by which we remove psycopg2's "json" handler in order to get the effect of using our non-native result handlers --- lib/sqlalchemy/dialects/postgresql/psycopg2.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'lib/sqlalchemy/dialects/postgresql/psycopg2.py') diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index 4a9248e5f..ceb04b580 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -179,7 +179,7 @@ from .base import PGDialect, PGCompiler, \ ENUM, ARRAY, _DECIMAL_TYPES, _FLOAT_TYPES,\ _INT_TYPES from .hstore import HSTORE -from .pgjson import JSON +from .json import JSON logger = logging.getLogger('sqlalchemy.dialects.postgresql') @@ -236,9 +236,7 @@ class _PGHStore(HSTORE): class _PGJSON(JSON): - # I've omitted the bind processor here because the method of serializing - # involves registering specific types to auto-serialize, and the adapter - # just a thin wrapper over json.dumps. + def result_processor(self, dialect, coltype): if dialect._has_native_json: return None -- cgit v1.2.1 From fec03c88d659bf9a0b102dd328afac1ba3dc7f23 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 17 Dec 2013 17:46:09 -0500 Subject: - make the json serializer and deserializer per-dialect, so that we are compatible with psycopg2's per-connection/cursor approach. add round trip tests for both native and non-native. --- lib/sqlalchemy/dialects/postgresql/psycopg2.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib/sqlalchemy/dialects/postgresql/psycopg2.py') diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index ceb04b580..f5da8a711 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -428,6 +428,11 @@ class PGDialect_psycopg2(PGDialect): array_oid=array_oid) fns.append(on_connect) + if self.dbapi and self._json_deserializer: + def on_connect(conn): + extras.register_default_json(conn, loads=self._json_deserializer) + fns.append(on_connect) + if fns: def on_connect(conn): for fn in fns: -- cgit v1.2.1 From f89d4d216bd7605c920b7b8a10ecde6bfea2238c Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 5 Jan 2014 16:57:05 -0500 Subject: - happy new year --- lib/sqlalchemy/dialects/postgresql/psycopg2.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/sqlalchemy/dialects/postgresql/psycopg2.py') diff --git a/lib/sqlalchemy/dialects/postgresql/psycopg2.py b/lib/sqlalchemy/dialects/postgresql/psycopg2.py index f5da8a711..e9f64f829 100644 --- a/lib/sqlalchemy/dialects/postgresql/psycopg2.py +++ b/lib/sqlalchemy/dialects/postgresql/psycopg2.py @@ -1,5 +1,5 @@ # postgresql/psycopg2.py -# Copyright (C) 2005-2013 the SQLAlchemy authors and contributors +# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors # # This module is part of SQLAlchemy and is released under # the MIT License: http://www.opensource.org/licenses/mit-license.php -- cgit v1.2.1