From 921c10309a68b698cf2a381048ad8d3299c0099f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 30 Mar 2020 07:45:11 +0000 Subject: [PATCH 1/5] Bump urllib3 from 1.24.2 to 1.24.3 Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.24.2 to 1.24.3. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/master/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/1.24.2...1.24.3) Signed-off-by: dependabot-preview[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index be3f3714..c47eb81e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,7 @@ pytz==2018.9 # via -r requirements.in pyyaml==5.2 # via -r requirements.in requests==2.21.0 # via -r requirements.in six==1.10.0 # via cryptography, protobuf, pyopenssl -urllib3==1.24.2 # via -r requirements.in, requests +urllib3==1.24.3 # via -r requirements.in, requests wheel==0.24.0 # via -r requirements.in wrapt==1.11.2 # via deprecated From 780b69eca3852f933c3f4747d0e3a0f0338ef27a Mon Sep 17 00:00:00 2001 From: echarrod Date: Mon, 30 Mar 2020 09:11:31 +0100 Subject: [PATCH 2/5] Update requrements.in to specify urllib3>=1.24.3 --- requirements.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.in b/requirements.in index 6c920272..8ce2e47e 100644 --- a/requirements.in +++ b/requirements.in @@ -9,7 +9,7 @@ pyopenssl==18.0.0 PyYAML==5.2 # PyYAML 5.3 does not support Python 3.4 pytz==2018.9 requests>=2.20.0 -urllib3>=1.24.2 +urllib3>=1.24.3 deprecated==1.2.6 wheel==0.24.0 iso8601==0.1.12 From 626762b7e84df192a71d8d237ad45dc14f627d1a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 4 Jun 2020 07:19:47 +0000 Subject: [PATCH 3/5] Bump pytz from 2018.9 to 2020.1 Bumps [pytz](https://github.com/stub42/pytz) from 2018.9 to 2020.1. - [Release notes](https://github.com/stub42/pytz/releases) - [Commits](https://github.com/stub42/pytz/compare/release_2018.9...release_2020.1) Signed-off-by: dependabot-preview[bot] --- requirements.in | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.in b/requirements.in index 8ce2e47e..c50857ae 100644 --- a/requirements.in +++ b/requirements.in @@ -7,7 +7,7 @@ pbr==1.10.0 protobuf==3.11.3 pyopenssl==18.0.0 PyYAML==5.2 # PyYAML 5.3 does not support Python 3.4 -pytz==2018.9 +pytz==2020.1 requests>=2.20.0 urllib3>=1.24.3 deprecated==1.2.6 diff --git a/requirements.txt b/requirements.txt index c47eb81e..09e1e8e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -18,7 +18,7 @@ pbr==1.10.0 # via -r requirements.in protobuf==3.11.3 # via -r requirements.in pycparser==2.18 # via cffi pyopenssl==18.0.0 # via -r requirements.in -pytz==2018.9 # via -r requirements.in +pytz==2020.1 # via -r requirements.in pyyaml==5.2 # via -r requirements.in requests==2.21.0 # via -r requirements.in six==1.10.0 # via cryptography, protobuf, pyopenssl From 6034b6ce4548623b0be122f01556528f7a2fbb04 Mon Sep 17 00:00:00 2001 From: echarrod Date: Mon, 8 Jun 2020 14:06:54 +0100 Subject: [PATCH 4/5] SDK-1589: Update cffi package --- requirements.in | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.in b/requirements.in index c50857ae..d0afce0e 100644 --- a/requirements.in +++ b/requirements.in @@ -1,6 +1,6 @@ asn1==2.2.0 cryptography>=2.8.0 -cffi>=1.13.0 +cffi>=1.14.0 future==0.18.2 itsdangerous==0.24 pbr==1.10.0 diff --git a/requirements.txt b/requirements.txt index 09e1e8e2..08bea14c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ # asn1==2.2.0 # via -r requirements.in certifi==2018.11.29 # via requests -cffi==1.13.0 # via -r requirements.in, cryptography +cffi==1.14.0 # via -r requirements.in, cryptography chardet==3.0.4 # via requests cryptography==2.8 # via -r requirements.in, pyopenssl deprecated==1.2.6 # via -r requirements.in From 5be163298a1b2a3baed44699d0b9fbcee35d60ce Mon Sep 17 00:00:00 2001 From: echarrod Date: Mon, 8 Jun 2020 14:10:13 +0100 Subject: [PATCH 5/5] SDK-1589: Update Attibute Issuance Expiry Date format to be milliseconds, not microseconds; update version --- sonar-project.properties | 2 +- .../third_party_attribute_extension.py | 31 ++++++- .../test_third_party_attribute_extension.py | 85 ++++++++++++++++++- yoti_python_sdk/version.py | 2 +- 4 files changed, 111 insertions(+), 9 deletions(-) diff --git a/sonar-project.properties b/sonar-project.properties index 4869bb67..491aea13 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,7 +2,7 @@ sonar.host.url = https://sonarcloud.io sonar.organization = getyoti sonar.projectKey = getyoti:python sonar.projectName = Python SDK -sonar.projectVersion = 2.12.0 +sonar.projectVersion = 2.12.1 sonar.exclusions = yoti_python_sdk/tests/**,examples/**,yoti_python_sdk/protobuf/**/* sonar.python.pylint.reportPath = coverage.out diff --git a/yoti_python_sdk/dynamic_sharing_service/extension/third_party_attribute_extension.py b/yoti_python_sdk/dynamic_sharing_service/extension/third_party_attribute_extension.py index 6299f05f..64ec5551 100644 --- a/yoti_python_sdk/dynamic_sharing_service/extension/third_party_attribute_extension.py +++ b/yoti_python_sdk/dynamic_sharing_service/extension/third_party_attribute_extension.py @@ -1,23 +1,46 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals + import copy +import pytz + class ThirdPartyAttributeExtension(object): THIRDPARTY_ATTRIBUTE = "THIRD_PARTY_ATTRIBUTE" def __init__(self): - self.__extension = {} - self.__extension["type"] = self.THIRDPARTY_ATTRIBUTE - self.__extension["content"] = {"expiry_date": None, "definitions": []} + self.__extension = { + "type": self.THIRDPARTY_ATTRIBUTE, + "content": {"expiry_date": None, "definitions": []}, + } def with_expiry_date(self, expiry_date): - self.__extension["content"]["expiry_date"] = expiry_date.isoformat() + """ + :param expiry_date: Expiry date for the attribute. If no timezone info is provided, UTC will be used. + :type expiry_date: datetime + """ + if expiry_date.tzinfo is None: + expiry_date = expiry_date.replace(tzinfo=pytz.UTC) + + utc_time = expiry_date.astimezone(pytz.utc) + rfc_3339_milliseconds = utc_time.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + self.__extension["content"]["expiry_date"] = rfc_3339_milliseconds + "Z" return self def with_definitions(self, *names): + """ + :param names: attribute definitions + :type names: str or list[str] + """ self.__extension["content"]["definitions"].extend([{"name": s} for s in names]) return self def build(self): + """ + Builds the object + + :return: the third party attribute + :rtype: ThirdPartyAttributeExtension + """ return copy.deepcopy(self.__extension) diff --git a/yoti_python_sdk/tests/dynamic_sharing_service/extension/test_third_party_attribute_extension.py b/yoti_python_sdk/tests/dynamic_sharing_service/extension/test_third_party_attribute_extension.py index 088a47ae..7c7a57ae 100644 --- a/yoti_python_sdk/tests/dynamic_sharing_service/extension/test_third_party_attribute_extension.py +++ b/yoti_python_sdk/tests/dynamic_sharing_service/extension/test_third_party_attribute_extension.py @@ -2,6 +2,10 @@ from __future__ import unicode_literals from datetime import datetime + +import pytest +import pytz + from yoti_python_sdk.dynamic_sharing_service.extension.third_party_attribute_extension import ( ThirdPartyAttributeExtension, ) @@ -19,7 +23,7 @@ def test_should_create_extension(): ) assert extension["type"] == ThirdPartyAttributeExtension.THIRDPARTY_ATTRIBUTE - assert extension["content"]["expiry_date"] == "2019-10-30T12:10:09.458000" + assert extension["content"]["expiry_date"] == "2019-10-30T12:10:09.458Z" assert extension["content"]["definitions"][0]["name"] == DEFINITION @@ -38,7 +42,7 @@ def test_with_definition_should_add_to_list(): ) assert extension["type"] == ThirdPartyAttributeExtension.THIRDPARTY_ATTRIBUTE - assert extension["content"]["expiry_date"] == "2019-10-30T12:10:09.458000" + assert extension["content"]["expiry_date"] == "2019-10-30T12:10:09.458Z" assert extension["content"]["definitions"][0]["name"] == DEFINITION1 assert extension["content"]["definitions"][1]["name"] == DEFINITION2 @@ -58,7 +62,82 @@ def test_with_definition_should_add_multiple(): ) assert extension["type"] == ThirdPartyAttributeExtension.THIRDPARTY_ATTRIBUTE - assert extension["content"]["expiry_date"] == "2019-10-30T12:10:09.458000" + assert extension["content"]["expiry_date"] == "2019-10-30T12:10:09.458Z" assert extension["content"]["definitions"][0]["name"] == DEFINITION1 assert extension["content"]["definitions"][1]["name"] == DEFINITION2 + + +@pytest.mark.parametrize( + "expiry_date, expected_value", + [ + ( + datetime(2051, 1, 13, 19, 50, 53, 1, tzinfo=pytz.utc), + "2051-01-13T19:50:53.000Z", + ), + ( + datetime(2026, 2, 2, 22, 4, 5, 123, tzinfo=pytz.utc), + "2026-02-02T22:04:05.000Z", + ), + ( + datetime(2051, 4, 13, 19, 50, 53, 999, tzinfo=pytz.utc), + "2051-04-13T19:50:53.000Z", + ), + ( + datetime(2026, 1, 31, 22, 4, 5, 1232, tzinfo=pytz.utc), + "2026-01-31T22:04:05.001Z", + ), + ( + datetime(2026, 1, 31, 22, 4, 5, 17777, tzinfo=pytz.utc), + "2026-01-31T22:04:05.017Z", + ), + ( + datetime(2019, 10, 30, 12, 10, 9, int(458e3), tzinfo=pytz.utc), + "2019-10-30T12:10:09.458Z", + ), + ( + datetime(2026, 1, 2, 22, 4, 5, 123456, tzinfo=pytz.utc), + "2026-01-02T22:04:05.123Z", + ), + ], +) +def test_should_format_utc_expiry_dates_correctly(expiry_date, expected_value): + DEFINITION = "some_value" + + extension = ( + ThirdPartyAttributeExtension() + .with_expiry_date(expiry_date) + .with_definitions(DEFINITION) + .build() + ) + + assert extension["content"]["expiry_date"] == expected_value + + +@pytest.mark.parametrize( + "expiry_date, tz_name", + [ + (datetime(2030, 6, 6, 8, 0, 0, 0), "US/Eastern",), + (datetime(2030, 6, 6, 15, 0, 0, 0), "Europe/Moscow",), + (datetime(2030, 6, 6, 7, 0, 0, 0), "America/Jamaica",), + (datetime(2030, 6, 6, 23, 0, 0, 0), "Etc/GMT-11"), + (datetime(2030, 6, 6, 7, 0, 0, 0), "Etc/GMT+5"), + # In order to conform with the POSIX style, those zones beginning + # with "Etc/GMT" have their sign reversed from what most people expect. In this style, zones west of GMT have + # a positive sign and those east have a negative sign. + ], +) +def test_should_format_localized_expiry_dates(expiry_date, tz_name): + DEFINITION = "some_value" + + tz = pytz.timezone(tz_name) + localized_expiry_date = tz.localize(expiry_date) + + extension = ( + ThirdPartyAttributeExtension() + .with_expiry_date(localized_expiry_date) + .with_definitions(DEFINITION) + .build() + ) + + assert extension["content"]["expiry_date"] == "2030-06-06T12:00:00.000Z" diff --git a/yoti_python_sdk/version.py b/yoti_python_sdk/version.py index 3c62c652..ad24c607 100644 --- a/yoti_python_sdk/version.py +++ b/yoti_python_sdk/version.py @@ -1,2 +1,2 @@ # -*- coding: utf-8 -*- -__version__ = "2.12.0" +__version__ = "2.12.1"