Hello community,

here is the log from the commit of package python-SQLAlchemy-Utils for 
openSUSE:Factory checked in at 2020-05-11 13:43:51
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-SQLAlchemy-Utils (Old)
 and      /work/SRC/openSUSE:Factory/.python-SQLAlchemy-Utils.new.2738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-SQLAlchemy-Utils"

Mon May 11 13:43:51 2020 rev:26 rq:802548 version:0.36.5

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-SQLAlchemy-Utils/python-SQLAlchemy-Utils.changes
  2020-04-22 20:51:23.407204030 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-SQLAlchemy-Utils.new.2738/python-SQLAlchemy-Utils.changes
        2020-05-11 13:44:02.193461053 +0200
@@ -1,0 +2,17 @@
+Sat May  9 16:12:59 UTC 2020 - Arun Persaud <a...@gmx.de>
+
+- update to version 0.36.5:
+  * Added support for dictionary input in CompositeType (#435, pull
+    request courtesy of cozos)
+  * Added new EnrichedDateTime and EnrichedDate types (#403, pull
+    request courtesy of yk-lab)
+  * Using String instead of LargeBinary for impl of EncryptedType
+    (#426, pull request courtesy of aicioara)
+  * Added support for JSONType in EncryptedType (#439, pull request
+    courtesy of rushilsrivastava)
+
+- changes from version 0.36.4:
+  * Added jsonb_sql function (#377, pull request courtesy of getglad)
+  * Drop py27 support
+
+-------------------------------------------------------------------

Old:
----
  SQLAlchemy-Utils-0.36.3.tar.gz

New:
----
  SQLAlchemy-Utils-0.36.5.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-SQLAlchemy-Utils.spec ++++++
--- /var/tmp/diff_new_pack.Ltnzxv/_old  2020-05-11 13:44:03.449463717 +0200
+++ /var/tmp/diff_new_pack.Ltnzxv/_new  2020-05-11 13:44:03.453463726 +0200
@@ -17,9 +17,9 @@
 
 
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
-%bcond_without python2
+%define skip_python2 1
 Name:           python-SQLAlchemy-Utils
-Version:        0.36.3
+Version:        0.36.5
 Release:        0
 Summary:        Various utility functions for SQLAlchemy
 License:        BSD-3-Clause
@@ -57,14 +57,6 @@
 Recommends:     python-passlib >= 1.6
 Recommends:     python-phonenumbers >= 5.9.2
 BuildArch:      noarch
-%if %{with python2}
-BuildRequires:  python-enum34
-BuildRequires:  python-ipaddr
-%endif
-%ifpython2
-Requires:       python-enum34
-Requires:       python-ipaddr
-%endif
 %python_subpackages
 
 %description

++++++ SQLAlchemy-Utils-0.36.3.tar.gz -> SQLAlchemy-Utils-0.36.5.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SQLAlchemy-Utils-0.36.3/CHANGES.rst 
new/SQLAlchemy-Utils-0.36.5/CHANGES.rst
--- old/SQLAlchemy-Utils-0.36.3/CHANGES.rst     2020-03-18 10:26:44.000000000 
+0100
+++ new/SQLAlchemy-Utils-0.36.5/CHANGES.rst     2020-05-03 20:11:20.000000000 
+0200
@@ -4,13 +4,29 @@
 Here you can see the full list of changes between each SQLAlchemy-Utils 
release.
 
 
-0.36.3 (2019-03-18)
+0.36.5 (2020-05-03)
+^^^^^^^^^^^^^^^^^^^
+
+- Added support for dictionary input in CompositeType (#435, pull request 
courtesy of cozos)
+- Added new EnrichedDateTime and EnrichedDate types (#403, pull request 
courtesy of yk-lab)
+- Using String instead of LargeBinary for impl of EncryptedType (#426, pull 
request courtesy of aicioara)
+- Added support for JSONType in EncryptedType (#439, pull request courtesy of 
rushilsrivastava)
+
+
+0.36.4 (2020-04-30)
+^^^^^^^^^^^^^^^^^^^
+
+- Added jsonb_sql function (#377, pull request courtesy of getglad)
+- Drop py27 support
+
+
+0.36.3 (2020-03-18)
 ^^^^^^^^^^^^^^^^^^^
 
 - Added hash method for PhoneNumberType (#428, pull request courtesy of 
hanc1208)
 
 
-0.36.2 (2019-03-16)
+0.36.2 (2020-03-16)
 ^^^^^^^^^^^^^^^^^^^
 
 - Added repr for UUIDType (#424, pull request courtesy of ziima)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SQLAlchemy-Utils-0.36.3/PKG-INFO 
new/SQLAlchemy-Utils-0.36.5/PKG-INFO
--- old/SQLAlchemy-Utils-0.36.3/PKG-INFO        2020-03-18 10:27:45.000000000 
+0100
+++ new/SQLAlchemy-Utils-0.36.5/PKG-INFO        2020-05-03 20:21:42.000000000 
+0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: SQLAlchemy-Utils
-Version: 0.36.3
+Version: 0.36.5
 Summary: Various utility functions for SQLAlchemy.
 Home-page: https://github.com/kvesteri/sqlalchemy-utils
 Author: Konsta Vesterinen, Ryan Leckey, Janne Vanhala, Vesa Uimonen
@@ -18,8 +18,6 @@
 Classifier: License :: OSI Approved :: BSD License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
@@ -31,6 +29,7 @@
 Provides-Extra: anyjson
 Provides-Extra: babel
 Provides-Extra: arrow
+Provides-Extra: pendulum
 Provides-Extra: intervals
 Provides-Extra: phone
 Provides-Extra: password
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/SQLAlchemy_Utils.egg-info/PKG-INFO 
new/SQLAlchemy-Utils-0.36.5/SQLAlchemy_Utils.egg-info/PKG-INFO
--- old/SQLAlchemy-Utils-0.36.3/SQLAlchemy_Utils.egg-info/PKG-INFO      
2020-03-18 10:27:44.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/SQLAlchemy_Utils.egg-info/PKG-INFO      
2020-05-03 20:21:42.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: SQLAlchemy-Utils
-Version: 0.36.3
+Version: 0.36.5
 Summary: Various utility functions for SQLAlchemy.
 Home-page: https://github.com/kvesteri/sqlalchemy-utils
 Author: Konsta Vesterinen, Ryan Leckey, Janne Vanhala, Vesa Uimonen
@@ -18,8 +18,6 @@
 Classifier: License :: OSI Approved :: BSD License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.4
 Classifier: Programming Language :: Python :: 3.5
@@ -31,6 +29,7 @@
 Provides-Extra: anyjson
 Provides-Extra: babel
 Provides-Extra: arrow
+Provides-Extra: pendulum
 Provides-Extra: intervals
 Provides-Extra: phone
 Provides-Extra: password
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/SQLAlchemy_Utils.egg-info/SOURCES.txt 
new/SQLAlchemy-Utils-0.36.5/SQLAlchemy_Utils.egg-info/SOURCES.txt
--- old/SQLAlchemy-Utils-0.36.3/SQLAlchemy_Utils.egg-info/SOURCES.txt   
2020-03-18 10:27:44.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/SQLAlchemy_Utils.egg-info/SOURCES.txt   
2020-05-03 20:21:42.000000000 +0200
@@ -91,6 +91,12 @@
 sqlalchemy_utils/types/encrypted/__init__.py
 sqlalchemy_utils/types/encrypted/encrypted_type.py
 sqlalchemy_utils/types/encrypted/padding.py
+sqlalchemy_utils/types/enriched_datetime/__init__.py
+sqlalchemy_utils/types/enriched_datetime/arrow_datetime.py
+sqlalchemy_utils/types/enriched_datetime/enriched_date_type.py
+sqlalchemy_utils/types/enriched_datetime/enriched_datetime_type.py
+sqlalchemy_utils/types/enriched_datetime/pendulum_date.py
+sqlalchemy_utils/types/enriched_datetime/pendulum_datetime.py
 tests/.DS_Store
 tests/__init__.py
 tests/mixins.py
@@ -144,6 +150,7 @@
 tests/functions/test_identity.py
 tests/functions/test_is_loaded.py
 tests/functions/test_json_sql.py
+tests/functions/test_jsonb_sql.py
 tests/functions/test_make_order_by_deterministic.py
 tests/functions/test_merge_references.py
 tests/functions/test_naturally_equivalent.py
@@ -183,6 +190,9 @@
 tests/types/test_datetime_range.py
 tests/types/test_email.py
 tests/types/test_encrypted.py
+tests/types/test_enriched_date_pendulum.py
+tests/types/test_enriched_datetime_arrow.py
+tests/types/test_enriched_datetime_pendulum.py
 tests/types/test_int_range.py
 tests/types/test_ip_address.py
 tests/types/test_json.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/SQLAlchemy_Utils.egg-info/requires.txt 
new/SQLAlchemy-Utils-0.36.5/SQLAlchemy_Utils.egg-info/requires.txt
--- old/SQLAlchemy-Utils-0.36.3/SQLAlchemy_Utils.egg-info/requires.txt  
2020-03-18 10:27:44.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/SQLAlchemy_Utils.egg-info/requires.txt  
2020-05-03 20:21:42.000000000 +0200
@@ -26,6 +26,9 @@
 [password]
 passlib<2.0,>=1.6
 
+[pendulum]
+pendulum>=2.0.5
+
 [phone]
 phonenumbers>=5.9.2
 
@@ -53,6 +56,7 @@
 cryptography>=0.6
 intervals>=0.7.1
 passlib<2.0,>=1.6
+pendulum>=2.0.5
 phonenumbers>=5.9.2
 pytest>=2.7.1
 Pygments>=1.2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/docs/generic_relationship.rst 
new/SQLAlchemy-Utils-0.36.5/docs/generic_relationship.rst
--- old/SQLAlchemy-Utils-0.36.3/docs/generic_relationship.rst   2015-08-16 
10:02:59.000000000 +0200
+++ new/SQLAlchemy-Utils-0.36.5/docs/generic_relationship.rst   2020-05-03 
20:05:20.000000000 +0200
@@ -53,7 +53,7 @@
 
 ::
 
-    class Employee(self.Base):
+    class Employee(Base):
         __tablename__ = 'employee'
         id = sa.Column(sa.Integer, primary_key=True)
         name = sa.Column(sa.String(50))
@@ -74,7 +74,7 @@
             'polymorphic_identity': 'engineer'
         }
 
-    class Activity(self.Base):
+    class Activity(Base):
         __tablename__ = 'event'
         id = sa.Column(sa.Integer, primary_key=True)
 
@@ -116,15 +116,15 @@
 ::
 
 
-    class Building(self.Base):
+    class Building(Base):
         __tablename__ = 'building'
         id = sa.Column(sa.Integer, primary_key=True)
 
-    class User(self.Base):
+    class User(Base):
         __tablename__ = 'user'
         id = sa.Column(sa.Integer, primary_key=True)
 
-    class EventBase(self.Base):
+    class EventBase(Base):
         __abstract__ = True
 
         object_type = sa.Column(sa.Unicode(255))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SQLAlchemy-Utils-0.36.3/setup.py 
new/SQLAlchemy-Utils-0.36.5/setup.py
--- old/SQLAlchemy-Utils-0.36.3/setup.py        2019-08-20 14:11:55.000000000 
+0200
+++ new/SQLAlchemy-Utils-0.36.5/setup.py        2020-05-03 19:55:01.000000000 
+0200
@@ -42,6 +42,7 @@
     'anyjson': ['anyjson>=0.3.3'],
     'babel': ['Babel>=1.3'],
     'arrow': ['arrow>=0.3.4'],
+    'pendulum': ['pendulum>=2.0.5'],
     'intervals': ['intervals>=0.7.1'],
     'phone': ['phonenumbers>=5.9.2'],
     'password': ['passlib >= 1.6, < 2.0'],
@@ -87,8 +88,6 @@
         'License :: OSI Approved :: BSD License',
         'Operating System :: OS Independent',
         'Programming Language :: Python',
-        'Programming Language :: Python :: 2',
-        'Programming Language :: Python :: 2.7',
         'Programming Language :: Python :: 3',
         'Programming Language :: Python :: 3.4',
         'Programming Language :: Python :: 3.5',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/__init__.py 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/__init__.py
--- old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/__init__.py    2020-03-18 
10:26:59.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/__init__.py    2020-05-03 
19:57:02.000000000 +0200
@@ -36,6 +36,7 @@
     identity,
     is_loaded,
     json_sql,
+    jsonb_sql,
     merge_references,
     mock_engine,
     naturally_equivalent,
@@ -70,6 +71,8 @@
     DateTimeRangeType,
     EmailType,
     EncryptedType,
+    EnrichedDateTimeType,
+    EnrichedDateType,
     instrumented_list,
     InstrumentedList,
     Int8RangeType,
@@ -100,4 +103,4 @@
     refresh_materialized_view
 )
 
-__version__ = '0.36.3'
+__version__ = '0.36.5'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/functions/__init__.py 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/functions/__init__.py
--- old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/functions/__init__.py  
2019-12-08 18:38:14.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/functions/__init__.py  
2020-04-30 09:45:37.000000000 +0200
@@ -6,7 +6,8 @@
     has_index,
     has_unique_index,
     is_auto_assigned_date_column,
-    json_sql
+    json_sql,
+    jsonb_sql
 )
 from .foreign_keys import (  # noqa
     dependent_objects,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/functions/database.py 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/functions/database.py
--- old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/functions/database.py  
2019-12-08 18:38:14.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/functions/database.py  
2020-04-30 09:45:37.000000000 +0200
@@ -109,6 +109,78 @@
     return value
 
 
+def jsonb_sql(value, scalars_to_jsonb=True):
+    """
+    Convert python data structures to PostgreSQL specific SQLAlchemy JSONB
+    constructs. This function is extremly useful if you need to build
+    PostgreSQL JSONB on python side.
+
+    .. note::
+
+        This function needs PostgreSQL >= 9.4
+
+    Scalars are converted to to_jsonb SQLAlchemy function objects
+
+    ::
+
+        jsonb_sql(1)     # Equals SQL: to_jsonb(1)
+
+        jsonb_sql('a')   # to_jsonb('a')
+
+
+    Mappings are converted to jsonb_build_object constructs
+
+    ::
+
+        jsonb_sql({'a': 'c', '2': 5})  # jsonb_build_object('a', 'c', '2', 5)
+
+
+    Sequences (other than strings) converted to jsonb_build_array constructs
+
+    ::
+
+        jsonb_sql([1, 2, 3])  # jsonb_build_array(1, 2, 3)
+
+
+    You can also nest these data structures
+
+    ::
+
+        jsonb_sql({'a': [1, 2, 3]})
+        # jsonb_build_object('a', jsonb_build_array[1, 2, 3])
+
+
+    :param value:
+        value to be converted to SQLAlchemy PostgreSQL function constructs
+    :boolean jsonbb:
+        Flag to alternatively convert the return with a to_jsonb construct
+    """
+    scalar_convert = sa.text
+    if scalars_to_jsonb:
+        def scalar_convert(a):
+            return sa.func.to_jsonb(sa.text(a))
+
+    if isinstance(value, Mapping):
+        return sa.func.jsonb_build_object(
+            *(
+                jsonb_sql(v, scalars_to_jsonb=False)
+                for v in itertools.chain(*value.items())
+            )
+        )
+    elif isinstance(value, str):
+        return scalar_convert("'{0}'".format(value))
+    elif isinstance(value, Sequence):
+        return sa.func.jsonb_build_array(
+            *(
+                jsonb_sql(v, scalars_to_jsonb=False)
+                for v in value
+            )
+        )
+    elif isinstance(value, (int, float)):
+        return scalar_convert(str(value))
+    return value
+
+
 def has_index(column_or_constraint):
     """
     Return whether or not given column or the columns of given foreign key
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/__init__.py 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/__init__.py
--- old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/__init__.py      
2019-11-01 11:32:40.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/__init__.py      
2020-05-03 19:55:01.000000000 +0200
@@ -9,6 +9,7 @@
 from .currency import CurrencyType  # noqa
 from .email import EmailType  # noqa
 from .encrypted.encrypted_type import EncryptedType  # noqa
+from .enriched_datetime.enriched_date_type import EnrichedDateType  # noqa
 from .ip_address import IPAddressType  # noqa
 from .json import JSONType  # noqa
 from .locale import LocaleType  # noqa
@@ -39,6 +40,8 @@
 from .uuid import UUIDType  # noqa
 from .weekdays import WeekDaysType  # noqa
 
+from .enriched_datetime.enriched_datetime_type import EnrichedDateTimeType  # 
noqa isort:skip
+
 
 class InstrumentedList(_InstrumentedList):
     """Enhanced version of SQLAlchemy InstrumentedList. Provides some
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/arrow.py 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/arrow.py
--- old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/arrow.py 2019-08-20 
13:55:26.000000000 +0200
+++ new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/arrow.py 2020-05-03 
19:55:01.000000000 +0200
@@ -1,17 +1,8 @@
 from __future__ import absolute_import
 
-from datetime import datetime
-
-import six
-from sqlalchemy import types
-
 from ..exceptions import ImproperlyConfigured
-from .scalar_coercible import ScalarCoercible
-
-try:
-    from collections.abc import Iterable
-except ImportError:  # For python 2.7 support
-    from collections import Iterable
+from .enriched_datetime import ArrowDateTime
+from .enriched_datetime.enriched_datetime_type import EnrichedDateTimeType
 
 arrow = None
 try:
@@ -20,7 +11,7 @@
     pass
 
 
-class ArrowType(types.TypeDecorator, ScalarCoercible):
+class ArrowType(EnrichedDateTimeType):
     """
     ArrowType provides way of saving Arrow_ objects into database. It
     automatically changes Arrow_ objects to datetime objects on the way in and
@@ -58,41 +49,11 @@
         # 'an hour ago'
 
     """
-    impl = types.DateTime
-
     def __init__(self, *args, **kwargs):
         if not arrow:
             raise ImproperlyConfigured(
                 "'arrow' package is required to use 'ArrowType'"
             )
 
-        super(ArrowType, self).__init__(*args, **kwargs)
-
-    def process_bind_param(self, value, dialect):
-        if value:
-            utc_val = self._coerce(value).to('UTC')
-            return utc_val.datetime if self.impl.timezone else utc_val.naive
-        return value
-
-    def process_result_value(self, value, dialect):
-        if value:
-            return arrow.get(value)
-        return value
-
-    def process_literal_param(self, value, dialect):
-        return str(value)
-
-    def _coerce(self, value):
-        if value is None:
-            return None
-        elif isinstance(value, six.string_types):
-            value = arrow.get(value)
-        elif isinstance(value, Iterable):
-            value = arrow.get(*value)
-        elif isinstance(value, datetime):
-            value = arrow.get(value)
-        return value
-
-    @property
-    def python_type(self):
-        return self.impl.type.python_type
+        super(ArrowType, self).__init__(datetime_processor=ArrowDateTime,
+                                        *args, **kwargs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/encrypted/encrypted_type.py 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/encrypted/encrypted_type.py
--- 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/encrypted/encrypted_type.py  
    2018-04-29 09:09:37.000000000 +0200
+++ 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/encrypted/encrypted_type.py  
    2020-05-03 20:08:22.000000000 +0200
@@ -1,13 +1,15 @@
 # -*- coding: utf-8 -*-
 import base64
 import datetime
+import json
 import os
 
 import six
-from sqlalchemy.types import LargeBinary, String, TypeDecorator
+from sqlalchemy.types import String, TypeDecorator
 
 from sqlalchemy_utils.exceptions import ImproperlyConfigured
 from sqlalchemy_utils.types.encrypted.padding import PADDING_MECHANISM
+from sqlalchemy_utils.types.json import JSONType
 from sqlalchemy_utils.types.scalar_coercible import ScalarCoercible
 
 cryptography = None
@@ -110,7 +112,7 @@
         encryptor = self.cipher.encryptor()
         encrypted = encryptor.update(value) + encryptor.finalize()
         encrypted = base64.b64encode(encrypted)
-        return encrypted
+        return encrypted.decode('utf-8')
 
     def decrypt(self, value):
         if isinstance(value, six.text_type):
@@ -164,7 +166,7 @@
         encrypted = encryptor.update(value) + encryptor.finalize()
         assert len(encryptor.tag) == self.TAG_SIZE_BYTES
         encrypted = base64.b64encode(iv + encryptor.tag + encrypted)
-        return encrypted
+        return encrypted.decode('utf-8')
 
     def decrypt(self, value):
         if isinstance(value, six.text_type):
@@ -208,12 +210,12 @@
             value = str(value)
         value = value.encode()
         encrypted = self.fernet.encrypt(value)
-        return encrypted
+        return encrypted.decode('utf-8')
 
     def decrypt(self, value):
         if isinstance(value, six.text_type):
             value = str(value)
-        decrypted = self.fernet.decrypt(value)
+        decrypted = self.fernet.decrypt(value.encode())
         if not isinstance(decrypted, six.string_types):
             decrypted = decrypted.decode('utf-8')
         return decrypted
@@ -344,7 +346,7 @@
 
     """
 
-    impl = LargeBinary
+    impl = String
 
     def __init__(self, type_in=None, key=None,
                  engine=None, padding=None, **kwargs):
@@ -400,6 +402,9 @@
                 elif issubclass(type_, (datetime.date, datetime.time)):
                     value = value.isoformat()
 
+                elif issubclass(type_, JSONType):
+                    value = six.text_type(json.dumps(value))
+
             return self.engine.encrypt(value)
 
     def process_result_value(self, value, dialect):
@@ -428,6 +433,9 @@
                         decrypted_value, type_
                     )
 
+                elif issubclass(type_, JSONType):
+                    return json.loads(decrypted_value)
+
                 # Handle all others
                 return self.underlying_type.python_type(decrypted_value)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/__init__.py
 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/__init__.py
--- 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/__init__.py
    1970-01-01 01:00:00.000000000 +0100
+++ 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/__init__.py
    2020-05-03 19:55:01.000000000 +0200
@@ -0,0 +1,4 @@
+# Module for enriched date, datetime type
+from .arrow_datetime import ArrowDateTime  # noqa
+from .pendulum_date import PendulumDate  # noqa
+from .pendulum_datetime import PendulumDateTime  # noqa
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/arrow_datetime.py
 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/arrow_datetime.py
--- 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/arrow_datetime.py
      1970-01-01 01:00:00.000000000 +0100
+++ 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/arrow_datetime.py
      2020-05-03 19:55:01.000000000 +0200
@@ -0,0 +1,45 @@
+from datetime import datetime
+
+import six
+
+from ...exceptions import ImproperlyConfigured
+
+try:
+    from collections.abc import Iterable
+except ImportError:  # For python 2.7 support
+    from collections import Iterable
+
+arrow = None
+try:
+    import arrow
+except ImportError:
+    pass
+
+
+class ArrowDateTime(object):
+    def __init__(self):
+        if not arrow:
+            raise ImproperlyConfigured(
+                "'arrow' package is required to use 'ArrowDateTime'"
+            )
+
+    def _coerce(self, impl, value):
+        if isinstance(value, six.string_types):
+            value = arrow.get(value)
+        elif isinstance(value, Iterable):
+            value = arrow.get(*value)
+        elif isinstance(value, datetime):
+            value = arrow.get(value)
+        return value
+
+    def process_bind_param(self, impl, value, dialect):
+        if value:
+            utc_val = self._coerce(impl, value).to('UTC')
+            return utc_val.datetime\
+                if impl.timezone else utc_val.naive
+        return value
+
+    def process_result_value(self, impl, value, dialect):
+        if value:
+            return arrow.get(value)
+        return value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/enriched_date_type.py
 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/enriched_date_type.py
--- 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/enriched_date_type.py
  1970-01-01 01:00:00.000000000 +0100
+++ 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/enriched_date_type.py
  2020-05-03 19:55:01.000000000 +0200
@@ -0,0 +1,49 @@
+from sqlalchemy import types
+
+from ..scalar_coercible import ScalarCoercible
+from .pendulum_date import PendulumDate
+
+
+class EnrichedDateType(types.TypeDecorator, ScalarCoercible):
+    """
+    Supported for pendulum only.
+
+    Example::
+
+
+        from sqlalchemy_utils import EnrichedDateType
+        import pendulum
+
+
+        class User(Base):
+            __tablename__ = 'user'
+            id = sa.Column(sa.Integer, primary_key=True)
+            birthday = sa.Column(EnrichedDateType(type="pendulum"))
+
+
+        user = User()
+        user.birthday = pendulum.datetime(year=1995, month=7, day=11)
+        session.add(user)
+        session.commit()
+    """
+    impl = types.Date
+
+    def __init__(self, date_processor=PendulumDate, *args, **kwargs):
+        super(EnrichedDateType, self).__init__(*args, **kwargs)
+        self.date_object = date_processor()
+
+    def _coerce(self, value):
+        return self.date_object._coerce(self.impl, value)
+
+    def process_bind_param(self, value, dialect):
+        return self.date_object.process_bind_param(self.impl, value, dialect)
+
+    def process_result_value(self, value, dialect):
+        return self.date_object.process_result_value(self.impl, value, dialect)
+
+    def process_literal_param(self, value, dialect):
+        return str(value)
+
+    @property
+    def python_type(self):
+        return self.impl.type.python_type
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/enriched_datetime_type.py
 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/enriched_datetime_type.py
--- 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/enriched_datetime_type.py
      1970-01-01 01:00:00.000000000 +0100
+++ 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/enriched_datetime_type.py
      2020-05-03 19:55:01.000000000 +0200
@@ -0,0 +1,50 @@
+from sqlalchemy import types
+
+from ..scalar_coercible import ScalarCoercible
+from .pendulum_datetime import PendulumDateTime
+
+
+class EnrichedDateTimeType(types.TypeDecorator, ScalarCoercible):
+    """
+    Supported for arrow and pendulum.
+
+    Example::
+
+
+        from sqlalchemy_utils import EnrichedDateTimeType
+        import pendulum
+
+
+        class User(Base):
+            __tablename__ = 'user'
+            id = sa.Column(sa.Integer, primary_key=True)
+            created_at = sa.Column(EnrichedDateTimeType(type="pendulum"))
+            # created_at = sa.Column(EnrichedDateTimeType(type="arrow"))
+
+
+        user = User()
+        user.created_at = pendulum.now()
+        session.add(user)
+        session.commit()
+    """
+    impl = types.DateTime
+
+    def __init__(self, datetime_processor=PendulumDateTime, *args, **kwargs):
+        super(EnrichedDateTimeType, self).__init__(*args, **kwargs)
+        self.dt_object = datetime_processor()
+
+    def _coerce(self, value):
+        return self.dt_object._coerce(self.impl, value)
+
+    def process_bind_param(self, value, dialect):
+        return self.dt_object.process_bind_param(self.impl, value, dialect)
+
+    def process_result_value(self, value, dialect):
+        return self.dt_object.process_result_value(self.impl, value, dialect)
+
+    def process_literal_param(self, value, dialect):
+        return str(value)
+
+    @property
+    def python_type(self):
+        return self.impl.type.python_type
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/pendulum_date.py
 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/pendulum_date.py
--- 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/pendulum_date.py
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/pendulum_date.py
       2020-05-03 19:55:01.000000000 +0200
@@ -0,0 +1,32 @@
+from ...exceptions import ImproperlyConfigured
+from .pendulum_datetime import PendulumDateTime
+
+pendulum = None
+try:
+    import pendulum
+except ImportError:
+    pass
+
+
+class PendulumDate(PendulumDateTime):
+    def __init__(self):
+        if not pendulum:
+            raise ImproperlyConfigured(
+                "'pendulum' package is required to use 'PendulumDate'"
+            )
+
+    def _coerce(self, impl, value):
+        if value:
+            if not isinstance(value, pendulum.Date):
+                value = super(PendulumDate, self)._coerce(impl, value).date()
+        return value
+
+    def process_result_value(self, impl, value, dialect):
+        if value:
+            return pendulum.parse(value.isoformat()).date()
+        return value
+
+    def process_bind_param(self, impl, value, dialect):
+        if value:
+            return self._coerce(impl, value)
+        return value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/pendulum_datetime.py
 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/pendulum_datetime.py
--- 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/enriched_datetime/pendulum_datetime.py
   1970-01-01 01:00:00.000000000 +0100
+++ 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/enriched_datetime/pendulum_datetime.py
   2020-05-03 19:55:01.000000000 +0200
@@ -0,0 +1,46 @@
+from datetime import datetime
+
+import six
+
+from ...exceptions import ImproperlyConfigured
+
+pendulum = None
+try:
+    import pendulum
+except ImportError:
+    pass
+
+
+class PendulumDateTime(object):
+    def __init__(self):
+        if not pendulum:
+            raise ImproperlyConfigured(
+                "'pendulum' package is required to use 'PendulumDateTime'"
+            )
+
+    def _coerce(self, impl, value):
+        if value is not None:
+            if isinstance(value, pendulum.DateTime):
+                pass
+            elif isinstance(value, (int, float)):
+                value = pendulum.from_timestamp(value)
+            elif isinstance(value, six.string_types) and value.isdigit():
+                value = pendulum.from_timestamp(int(value))
+            elif isinstance(value, datetime):
+                value = pendulum.datetime(value.year,
+                                          value.month, value.day,
+                                          value.hour, value.minute,
+                                          value.second, value.microsecond)
+            else:
+                value = pendulum.parse(value)
+        return value
+
+    def process_bind_param(self, impl, value, dialect):
+        if value:
+            return self._coerce(impl, value).in_tz("UTC")
+        return value
+
+    def process_result_value(self, impl, value, dialect):
+        if value:
+            return pendulum.parse(value.isoformat())
+        return value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/pg_composite.py 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/pg_composite.py
--- old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/pg_composite.py  
2016-12-18 10:08:56.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/pg_composite.py  
2020-05-03 19:32:28.000000000 +0200
@@ -49,6 +49,22 @@
         )
 
 
+Creation
+~~~~~~~~
+When creating CompositeType, you can either pass in a tuple or a dictionary.
+
+::
+    account1 = Account()
+    account1.balance = ('USD', 15)
+
+    account2 = Account()
+    account2.balance = {'currency': 'USD', 'balance': 15}
+
+    session.add(account1)
+    session.add(account2)
+    session.commit()
+
+
 Accessing fields
 ^^^^^^^^^^^^^^^^
 
@@ -207,16 +223,23 @@
         def process(value):
             if value is None:
                 return None
+
             processed_value = []
             for i, column in enumerate(self.columns):
+                current_value = (
+                    value.get(column.name)
+                    if isinstance(value, dict)
+                    else value[i]
+                )
+
                 if isinstance(column.type, TypeDecorator):
                     processed_value.append(
                         column.type.process_bind_param(
-                            value[i], dialect
+                            current_value, dialect
                         )
                     )
                 else:
-                    processed_value.append(value[i])
+                    processed_value.append(current_value)
             return self.type_cls(*processed_value)
         return process
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/uuid.py 
new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/uuid.py
--- old/SQLAlchemy-Utils-0.36.3/sqlalchemy_utils/types/uuid.py  2020-03-16 
12:56:33.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/sqlalchemy_utils/types/uuid.py  2020-05-03 
19:55:01.000000000 +0200
@@ -28,7 +28,7 @@
 
     python_type = uuid.UUID
 
-    def __init__(self, binary=True, native=True):
+    def __init__(self, binary=True, native=True, **kwargs):
         """
         :param binary: Whether to use a BINARY(16) or CHAR(32) fallback.
         """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/tests/functions/test_jsonb_sql.py 
new/SQLAlchemy-Utils-0.36.5/tests/functions/test_jsonb_sql.py
--- old/SQLAlchemy-Utils-0.36.3/tests/functions/test_jsonb_sql.py       
1970-01-01 01:00:00.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/tests/functions/test_jsonb_sql.py       
2020-04-30 09:45:37.000000000 +0200
@@ -0,0 +1,32 @@
+import pytest
+import sqlalchemy as sa
+
+from sqlalchemy_utils import jsonb_sql
+
+
+@pytest.mark.usefixtures('postgresql_dsn')
+class TestJSONBSQL(object):
+
+    @pytest.mark.parametrize(
+        ('value', 'result'),
+        (
+            (1, 1),
+            (14.14, 14.14),
+            ({'a': 2, 'b': 'c'}, {'a': 2, 'b': 'c'}),
+            (
+                {'a': {'b': 'c'}},
+                {'a': {'b': 'c'}}
+            ),
+            ({}, {}),
+            ([1, 2], [1, 2]),
+            ([], []),
+            (
+                [sa.select([sa.text('1')]).label('alias')],
+                [1]
+            )
+        )
+    )
+    def test_compiled_scalars(self, connection, value, result):
+        assert result == (
+            connection.execute(sa.select([jsonb_sql(value)])).fetchone()[0]
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/SQLAlchemy-Utils-0.36.3/tests/types/test_arrow.py 
new/SQLAlchemy-Utils-0.36.5/tests/types/test_arrow.py
--- old/SQLAlchemy-Utils-0.36.3/tests/types/test_arrow.py       2019-11-01 
11:16:50.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/tests/types/test_arrow.py       2020-04-27 
12:45:14.000000000 +0200
@@ -63,7 +63,7 @@
     def test_literal_param(self, session, Article):
         clause = Article.created_at > '2015-01-01'
         compiled = str(clause.compile(compile_kwargs={"literal_binds": True}))
-        assert compiled == 'article.created_at > 2015-01-01'
+        assert compiled == "article.created_at > '2015-01-01'"
 
     @pytest.mark.usefixtures('postgresql_dsn')
     def test_timezone(self, session, Article):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/tests/types/test_composite.py 
new/SQLAlchemy-Utils-0.36.5/tests/types/test_composite.py
--- old/SQLAlchemy-Utils-0.36.3/tests/types/test_composite.py   2019-07-15 
14:44:13.000000000 +0200
+++ new/SQLAlchemy-Utils-0.36.5/tests/types/test_composite.py   2020-05-03 
19:32:28.000000000 +0200
@@ -66,6 +66,39 @@
         assert account.balance.currency == u'ääöö'
         assert account.balance.amount == 15
 
+    def test_dict_input(self, session, Account):
+        account = Account(
+            balance={'currency': 'USD', 'amount': 15}
+        )
+
+        session.add(account)
+        session.commit()
+
+        account = session.query(Account).first()
+        assert account.balance.currency == 'USD'
+        assert account.balance.amount == 15
+
+    def test_incomplete_dict(self, session, Account):
+        """
+        Postgres doesn't allow non-nullabe fields in Composite Types:
+
+        "no constraints (such as NOT NULL) can presently be included"
+        (https://www.postgresql.org/docs/10/rowtypes.html)
+
+        So this should be allowed.
+        """
+
+        account = Account(
+            balance={'amount': 15}
+        )
+
+        session.add(account)
+        session.commit()
+
+        account = session.query(Account).first()
+        assert account.balance.currency is None
+        assert account.balance.amount == 15
+
 
 @pytest.mark.skipif('i18n.babel is None')
 @pytest.mark.usefixtures('postgresql_dsn')
@@ -116,6 +149,18 @@
         assert account.balance.currency == Currency('USD')
         assert account.balance.amount == 15
 
+    def test_dict_input(self, session, Account):
+        account = Account(
+            balance={'currency': Currency('USD'), 'amount': 15}
+        )
+
+        session.add(account)
+        session.commit()
+
+        account = session.query(Account).first()
+        assert account.balance.currency == 'USD'
+        assert account.balance.amount == 15
+
 
 @pytest.mark.skipif('i18n.babel is None')
 @pytest.mark.usefixtures('postgresql_dsn')
@@ -154,6 +199,23 @@
             ]
         )
 
+        session.add(account)
+        session.commit()
+
+        account = session.query(Account).first()
+        assert account.balances[0].currency == Currency('USD')
+        assert account.balances[0].amount == 15
+        assert account.balances[1].currency == Currency('AUD')
+        assert account.balances[1].amount == 20
+
+    def test_dict_input(self, session, type_, Account):
+        account = Account(
+            balances=[
+                {'currency': Currency('USD'), 'amount': 15},
+                {'currency': Currency('AUD'), 'amount': 20}
+            ]
+        )
+
         session.add(account)
         session.commit()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/tests/types/test_encrypted.py 
new/SQLAlchemy-Utils-0.36.5/tests/types/test_encrypted.py
--- old/SQLAlchemy-Utils-0.36.3/tests/types/test_encrypted.py   2018-11-19 
08:53:23.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/tests/types/test_encrypted.py   2020-05-03 
20:08:22.000000000 +0200
@@ -4,6 +4,7 @@
 import sqlalchemy as sa
 
 from sqlalchemy_utils import ColorType, EncryptedType, PhoneNumberType
+from sqlalchemy_utils.types import JSONType
 from sqlalchemy_utils.types.encrypted.encrypted_type import (
     AesEngine,
     AesGcmEngine,
@@ -95,6 +96,13 @@
             padding_mechanism)
         )
 
+        json = sa.Column(EncryptedType(
+            JSONType,
+            test_key,
+            encryption_engine,
+            padding_mechanism)
+        )
+
     return User
 
 
@@ -124,6 +132,11 @@
 
 
 @pytest.fixture
+def user_json():
+    return {"key": "value"}
+
+
+@pytest.fixture
 def user_date():
     return date(2010, 10, 2)
 
@@ -170,6 +183,7 @@
     user_date,
     user_time,
     user_enum,
+    user_json,
     user_datetime,
     test_token,
     active,
@@ -183,6 +197,7 @@
     user.date = user_date
     user.time = user_time
     user.enum = user_enum
+    user.json = user_json
     user.datetime = user_datetime
     user.access_token = test_token
     user.is_active = active
@@ -278,6 +293,9 @@
     def test_enum(self, user, user_enum):
         assert user.enum == user_enum
 
+    def test_json(self, user, user_json):
+        assert user.json == user_json
+
     def test_lookup_key(self, session, Team):
         # Add teams
         self._team_key = 'one'
@@ -468,7 +486,7 @@
         # 3rd char will be IV. Modify it
         POS = 3
         encrypted = encrypted[:POS] + \
-            (b'A' if encrypted[POS] != b'A' else b'B') + \
+            ('A' if encrypted[POS] != 'A' else 'B') + \
             encrypted[POS + 1:]
         with pytest.raises(InvalidCiphertextError):
             self.engine.decrypt(encrypted)
@@ -479,7 +497,7 @@
         # 19th char will be tag. Modify it
         POS = 19
         encrypted = encrypted[:POS] + \
-            (b'A' if encrypted[POS] != b'A' else b'B') + \
+            ('A' if encrypted[POS] != 'A' else 'B') + \
             encrypted[POS + 1:]
         with pytest.raises(InvalidCiphertextError):
             self.engine.decrypt(encrypted)
@@ -490,7 +508,7 @@
         # 43rd char will be ciphertext. Modify it
         POS = 43
         encrypted = encrypted[:POS] + \
-            (b'A' if encrypted[POS] != b'A' else b'B') + \
+            ('A' if encrypted[POS] != 'A' else 'B') + \
             encrypted[POS + 1:]
         with pytest.raises(InvalidCiphertextError):
             self.engine.decrypt(encrypted)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/tests/types/test_enriched_date_pendulum.py 
new/SQLAlchemy-Utils-0.36.5/tests/types/test_enriched_date_pendulum.py
--- old/SQLAlchemy-Utils-0.36.3/tests/types/test_enriched_date_pendulum.py      
1970-01-01 01:00:00.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/tests/types/test_enriched_date_pendulum.py      
2020-05-03 20:15:41.000000000 +0200
@@ -0,0 +1,68 @@
+from __future__ import unicode_literals
+
+from datetime import date
+
+import pytest
+import sqlalchemy as sa
+
+from sqlalchemy_utils.types.enriched_datetime import (
+    enriched_date_type,
+    pendulum_date
+)
+
+
+@pytest.fixture
+def User(Base):
+    class User(Base):
+        __tablename__ = 'users'
+        id = sa.Column(sa.Integer, primary_key=True)
+        birthday = sa.Column(
+            enriched_date_type.EnrichedDateType(
+                date_processor=pendulum_date.PendulumDate
+            ))
+    return User
+
+
+@pytest.fixture
+def init_models(User):
+    pass
+
+
+@pytest.mark.skipif('pendulum_date.pendulum is None')
+class TestPendulumDateType(object):
+
+    def test_parameter_processing(self, session, User):
+        user = User(
+            birthday=pendulum_date.pendulum.date(1995, 7, 11)
+        )
+
+        session.add(user)
+        session.commit()
+
+        user = session.query(User).first()
+        assert isinstance(user.birthday, date)
+
+    def test_int_coercion(self, User):
+        user = User(
+            birthday=1367900664
+        )
+        assert user.birthday.year == 2013
+
+    def test_string_coercion(self, User):
+        user = User(
+            birthday='1367900664'
+        )
+        assert user.birthday.year == 2013
+
+    def test_utc(self, session, User):
+        time = pendulum_date.pendulum.now("UTC")
+        user = User(birthday=time)
+        session.add(user)
+        assert user.birthday == time
+        session.commit()
+        assert user.birthday == time.date()
+
+    def test_literal_param(self, session, User):
+        clause = User.birthday > '2015-01-01'
+        compiled = str(clause.compile(compile_kwargs={"literal_binds": True}))
+        assert compiled == "users.birthday > '2015-01-01'"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/tests/types/test_enriched_datetime_arrow.py 
new/SQLAlchemy-Utils-0.36.5/tests/types/test_enriched_datetime_arrow.py
--- old/SQLAlchemy-Utils-0.36.3/tests/types/test_enriched_datetime_arrow.py     
1970-01-01 01:00:00.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/tests/types/test_enriched_datetime_arrow.py     
2020-05-03 20:15:55.000000000 +0200
@@ -0,0 +1,91 @@
+from datetime import datetime
+
+import pytest
+import sqlalchemy as sa
+from dateutil import tz
+
+from sqlalchemy_utils.types.enriched_datetime import (
+    arrow_datetime,
+    enriched_datetime_type
+)
+
+
+@pytest.fixture
+def Article(Base):
+    class Article(Base):
+        __tablename__ = 'article'
+        id = sa.Column(sa.Integer, primary_key=True)
+        created_at = sa.Column(
+            enriched_datetime_type.EnrichedDateTimeType(
+                datetime_processor=arrow_datetime.ArrowDateTime
+            ))
+        published_at = sa.Column(
+            enriched_datetime_type.EnrichedDateTimeType(
+                datetime_processor=arrow_datetime.ArrowDateTime,
+                timezone=True
+            ))
+        published_at_dt = sa.Column(sa.DateTime(timezone=True))
+    return Article
+
+
+@pytest.fixture
+def init_models(Article):
+    pass
+
+
+@pytest.mark.skipif('arrow_datetime.arrow is None')
+class TestArrowDateTimeType(object):
+
+    def test_parameter_processing(self, session, Article):
+        article = Article(
+            created_at=arrow_datetime.arrow.get(datetime(2000, 11, 1))
+        )
+
+        session.add(article)
+        session.commit()
+
+        article = session.query(Article).first()
+        assert article.created_at.datetime
+
+    def test_string_coercion(self, Article):
+        article = Article(
+            created_at='2013-01-01'
+        )
+        assert article.created_at.year == 2013
+
+    def test_utc(self, session, Article):
+        time = arrow_datetime.arrow.utcnow()
+        article = Article(created_at=time)
+        session.add(article)
+        assert article.created_at == time
+        session.commit()
+        assert article.created_at == time
+
+    def test_other_tz(self, session, Article):
+        time = arrow_datetime.arrow.utcnow()
+        local = time.to('US/Pacific')
+        article = Article(created_at=local)
+        session.add(article)
+        assert article.created_at == time == local
+        session.commit()
+        assert article.created_at == time
+
+    def test_literal_param(self, session, Article):
+        clause = Article.created_at > '2015-01-01'
+        compiled = str(clause.compile(compile_kwargs={"literal_binds": True}))
+        assert compiled == "article.created_at > '2015-01-01'"
+
+    @pytest.mark.usefixtures('postgresql_dsn')
+    def test_timezone(self, session, Article):
+        timezone = tz.gettz('Europe/Stockholm')
+        dt = arrow_datetime.arrow.get(datetime(2015, 1, 1, 15, 30, 45),
+                                      timezone)
+        article = Article(published_at=dt, published_at_dt=dt.datetime)
+
+        session.add(article)
+        session.commit()
+        session.expunge_all()
+
+        item = session.query(Article).one()
+        assert item.published_at.datetime == item.published_at_dt
+        assert item.published_at.to(timezone) == dt
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/SQLAlchemy-Utils-0.36.3/tests/types/test_enriched_datetime_pendulum.py 
new/SQLAlchemy-Utils-0.36.5/tests/types/test_enriched_datetime_pendulum.py
--- old/SQLAlchemy-Utils-0.36.3/tests/types/test_enriched_datetime_pendulum.py  
1970-01-01 01:00:00.000000000 +0100
+++ new/SQLAlchemy-Utils-0.36.5/tests/types/test_enriched_datetime_pendulum.py  
2020-05-03 20:16:09.000000000 +0200
@@ -0,0 +1,83 @@
+from __future__ import unicode_literals
+
+from datetime import datetime
+
+import pytest
+import sqlalchemy as sa
+
+from sqlalchemy_utils.types.enriched_datetime import (
+    enriched_datetime_type,
+    pendulum_datetime
+)
+
+
+@pytest.fixture
+def User(Base):
+    class User(Base):
+        __tablename__ = 'users'
+        id = sa.Column(sa.Integer, primary_key=True)
+        created_at = sa.Column(
+            enriched_datetime_type.EnrichedDateTimeType(
+                datetime_processor=pendulum_datetime.PendulumDateTime,
+            ))
+    return User
+
+
+@pytest.fixture
+def init_models(User):
+    pass
+
+
+@pytest.mark.skipif('pendulum_datetime.pendulum is None')
+class TestPendulumDateTimeType(object):
+
+    def test_parameter_processing(self, session, User):
+        user = User(
+            created_at=pendulum_datetime.pendulum.datetime(1995, 7, 11)
+        )
+
+        session.add(user)
+        session.commit()
+
+        user = session.query(User).first()
+        assert isinstance(user.created_at, datetime)
+
+        def test_int_coercion(self, User):
+            user = User(
+                created_at=1367900664
+            )
+            assert user.created_at.year == 2013
+
+        def test_float_coercion(self, User):
+            user = User(
+                created_at=1367900664.0
+            )
+            assert user.created_at.year == 2013
+
+    def test_string_coercion(self, User):
+        user = User(
+            created_at='1367900664'
+        )
+        assert user.created_at.year == 2013
+
+    def test_utc(self, session, User):
+        time = pendulum_datetime.pendulum.now("UTC")
+        user = User(created_at=time)
+        session.add(user)
+        assert user.created_at == time
+        session.commit()
+        assert user.created_at == time
+
+    def test_other_tz(self, session, User):
+        time = pendulum_datetime.pendulum.now("UTC")
+        local = time.in_tz('Asia/Tokyo')
+        user = User(created_at=local)
+        session.add(user)
+        assert user.created_at == time == local
+        session.commit()
+        assert user.created_at == time
+
+    def test_literal_param(self, session, User):
+        clause = User.created_at > '2015-01-01'
+        compiled = str(clause.compile(compile_kwargs={"literal_binds": True}))
+        assert compiled == "users.created_at > '2015-01-01'"


Reply via email to