From c54dd443e6fe5871ef0aa6b67e365ab3afcb527a Mon Sep 17 00:00:00 2001 From: Fantix King Date: Sat, 8 Dec 2018 10:17:10 +0800 Subject: [PATCH 1/4] Fixes #402, fix custom JSON/JSONB type support. --- gino/dialects/asyncpg.py | 13 +++++++++++++ gino/dialects/base.py | 10 ---------- tests/test_json.py | 15 ++++++++++++++- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/gino/dialects/asyncpg.py b/gino/dialects/asyncpg.py index 70e1a256..97b53fac 100644 --- a/gino/dialects/asyncpg.py +++ b/gino/dialects/asyncpg.py @@ -21,6 +21,9 @@ from . import base +JSON_COLTYPE = 114 +JSONB_COLTYPE = 3802 + class AsyncpgDBAPI(base.BaseDBAPI): Error = asyncpg.PostgresError, asyncpg.InterfaceError @@ -283,6 +286,15 @@ async def _on_metadata_drop_async(self, target, bind, checkfirst=False, await self.drop_async(bind=bind, checkfirst=checkfirst) +class GinoNullType(sqltypes.NullType): + def result_processor(self, dialect, coltype): + if coltype == JSON_COLTYPE: + return JSON().result_processor(dialect, coltype) + if coltype == JSONB_COLTYPE: + return JSONB().result_processor(dialect, coltype) + return super().result_processor(dialect, coltype) + + # noinspection PyAbstractClass class AsyncpgDialect(PGDialect, base.AsyncDialectMixin): driver = 'asyncpg' @@ -299,6 +311,7 @@ class AsyncpgDialect(PGDialect, base.AsyncDialectMixin): { ENUM: AsyncEnum, sqltypes.Enum: AsyncEnum, + sqltypes.NullType: GinoNullType, } ) diff --git a/gino/dialects/base.py b/gino/dialects/base.py index 3a941643..18ae9e67 100644 --- a/gino/dialects/base.py +++ b/gino/dialects/base.py @@ -2,15 +2,12 @@ import weakref from sqlalchemy import util -from sqlalchemy.dialects.postgresql import JSON, JSONB # noinspection PyProtectedMember from ..engine import _SAConnection, _SAEngine, _DBAPIConnection from ..loader import Loader DEFAULT = object() -JSON_COLTYPE = 114 -JSONB_COLTYPE = 3802 class BaseDBAPI: @@ -375,13 +372,6 @@ def _init_statement_prepared(cls, dialect, connection, dbapi_connection, self.cursor = self.create_cursor() return self - def get_result_processor(self, type_, colname, coltype): - if coltype == JSON_COLTYPE: - return JSON().result_processor(self.dialect, coltype) - if coltype == JSONB_COLTYPE: - return JSONB().result_processor(self.dialect, coltype) - return super().get_result_processor(type_, colname, coltype) - class AsyncDialectMixin: cursor_cls = DBAPICursor diff --git a/tests/test_json.py b/tests/test_json.py index b4d58c1b..0e1e423f 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -175,13 +175,21 @@ class Test(db.Model): age = db.IntegerProperty(default=18) -async def test_t291(bind): +async def test_t291_t402(bind): from gino.dialects.asyncpg import JSON, JSONB + class CustomJSONB(db.TypeDecorator): + impl = JSONB + + def process_result_value(self, *_): + return 123 + class PropsTest(db.Model): __tablename__ = 'props_test_291' profile = db.Column(JSONB(), nullable=False, server_default='{}') profile1 = db.Column(JSON(), nullable=False, server_default='{}') + profile2 = db.Column(CustomJSONB(), + nullable=False, server_default='{}') bool = db.BooleanProperty() bool1 = db.BooleanProperty(column_name='profile1') @@ -196,5 +204,10 @@ class PropsTest(db.Model): assert isinstance(profile, dict) profile1 = await bind.scalar('SELECT profile1 FROM props_test_291') assert isinstance(profile1, dict) + profile2 = await bind.scalar('SELECT profile2 FROM props_test_291') + assert isinstance(profile2, dict) + custom_profile2 = await bind.scalar(PropsTest.select('profile2')) + assert isinstance(custom_profile2, int) + assert custom_profile2 == 123 finally: await PropsTest.gino.drop() From 3cc1ecb46a4f352ca09746e12625a7ae21e609d9 Mon Sep 17 00:00:00 2001 From: Fantix King Date: Sat, 8 Dec 2018 15:10:17 +0800 Subject: [PATCH 2/4] Prepare 0.7.7 --- HISTORY.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index 5c0c3991..59f55dc0 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -7,6 +7,11 @@ GINO 0.7 This is also version 1.0 beta 3. +0.7.7 (2018-12-08) +^^^^^^^^^^^^^^^^^^ + +* Backported fix for custom JSON/JSONB type support (#402 #403) + 0.7.6 (2018-08-26) ^^^^^^^^^^^^^^^^^^ From b829ce8ccf5049e7f989b473f150ec3b6ae1b593 Mon Sep 17 00:00:00 2001 From: Fantix King Date: Sat, 8 Dec 2018 15:10:52 +0800 Subject: [PATCH 3/4] =?UTF-8?q?Bump=20version:=200.7.6=20=E2=86=92=200.7.7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gino/__init__.py | 2 +- setup.cfg | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gino/__init__.py b/gino/__init__.py index 252e575f..995ec7f9 100644 --- a/gino/__init__.py +++ b/gino/__init__.py @@ -11,4 +11,4 @@ def create_engine(*args, **kwargs): return create_engine(*args, **kwargs) -__version__ = '0.7.6' +__version__ = '0.7.7' diff --git a/setup.cfg b/setup.cfg index 906a7033..ea1eb563 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.7.6 +current_version = 0.7.7 commit = True tag = True diff --git a/setup.py b/setup.py index 91486fdf..90b8a9e2 100644 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ def req_file(filename): setup( name='gino', - version='0.7.6', + version='0.7.7', description="GINO Is Not ORM - " "a Python asyncio ORM on SQLAlchemy core.", long_description=readme + '\n\n' + history, From 80a4cba6e9a10185b8a78eb4c24b60fe33de4bba Mon Sep 17 00:00:00 2001 From: Tony Wang Date: Thu, 25 Oct 2018 01:02:27 +0800 Subject: [PATCH 4/4] fix false warning by flake8 3.6.0 pycodestyle which is contained in flake8 3.6.0 has an issue with syntax `await (await async_func())`. The issue was filed as https://github.com/PyCQA/pycodestyle/issues/811 --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index 7dd1598b..5a58e831 100644 --- a/tox.ini +++ b/tox.ini @@ -9,7 +9,7 @@ python = [testenv:flake8] basepython=python -deps=flake8 +deps=flake8==3.5.0 commands=flake8 gino [testenv]