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 <[email protected]>
+
+- 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
+
+
[email protected]('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"}
+
+
[email protected]
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
+)
+
+
[email protected]
+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
+
+
[email protected]
+def init_models(User):
+ pass
+
+
[email protected]('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
+)
+
+
[email protected]
+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
+
+
[email protected]
+def init_models(Article):
+ pass
+
+
[email protected]('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
+)
+
+
[email protected]
+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
+
+
[email protected]
+def init_models(User):
+ pass
+
+
[email protected]('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'"