From 6e8e7f5099413931e09596206419a1440b3cb91b Mon Sep 17 00:00:00 2001 From: Sara Safavi Date: Tue, 30 Apr 2019 15:28:36 -0500 Subject: [PATCH 1/3] let date_range filter handle dates given with and without timezones --- planet/api/filters.py | 13 ++++++++++--- tests/test_filters.py | 27 +++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 tests/test_filters.py diff --git a/planet/api/filters.py b/planet/api/filters.py index 60abaabb9..baa07d9e9 100644 --- a/planet/api/filters.py +++ b/planet/api/filters.py @@ -100,8 +100,10 @@ def not_filter(*predicates): def date_range(field_name, **kwargs): '''Build a DateRangeFilter. - Predicate arguments accept a value str that in ISO-8601 format or a value - that has a `isoformat` callable that returns an ISO-8601 str. + Predicate arguments accept a str that is ISO-8601 format or a value + that has an `isoformat` callable that returns an ISO-8601 compliant str. + + If no timezone is provided, UTC is assumed for RFC 3339 compatability. :raises: ValueError if predicate value does not parse @@ -116,7 +118,12 @@ def date_range(field_name, **kwargs): dt = strp_lenient(str(v)) if dt is None: raise ValueError("unable to use provided time: " + str(v)) - kwargs[k] = dt.isoformat() + 'Z' + iso_date = dt.isoformat() + if not dt.tzinfo: + # assume UTC for datetimes without an explicit timezone + # necessary for RFC 3339 vs ISO 8601 compatability + iso_date += 'Z' + kwargs[k] = iso_date return _filter('DateRangeFilter', config=kwargs, field_name=field_name) diff --git a/tests/test_filters.py b/tests/test_filters.py new file mode 100644 index 000000000..ccbcd7dd6 --- /dev/null +++ b/tests/test_filters.py @@ -0,0 +1,27 @@ +import pytest +from pytz import timezone +from datetime import datetime +from planet.api import filters + + +@pytest.mark.parametrize('dt, expected', [ + (datetime(1900, 1, 1, tzinfo=timezone("US/Central")), + {'field_name': 'acquired', + 'type': 'DateRangeFilter', + 'config': {'gte': '1900-01-01T00:00:00-05:51'}}), + + (datetime(1999, 12, 31), + {'field_name': 'acquired', + 'type': 'DateRangeFilter', + 'config': {'gte': '1999-12-31T00:00:00Z'}}), + + ("2018-01-01", + {'field_name': 'acquired', + 'type': 'DateRangeFilter', + 'config': {'gte': '2018-01-01T00:00:00Z'}}), +]) +def test_date_range(dt, expected): + fieldname = "acquired" + arg = "gte" + + assert filters.date_range(fieldname, **{arg: dt}) == expected From 50c842e0adfbbcf3945398e217c30c641aa64f44 Mon Sep 17 00:00:00 2001 From: Sara Safavi Date: Tue, 30 Apr 2019 15:30:19 -0500 Subject: [PATCH 2/3] mimetypes.guess_extension() returns either .tif or .tiff - test accordingly prior to Python 3.6, the order of extensions returned is nondeterministic, at Python 3.6+ ".tif" is always returned first. Until we drop Python 2.7 support, we need to account for all cases in our tests. --- tests/test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_utils.py b/tests/test_utils.py index 00b440571..53dafbc81 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -148,7 +148,7 @@ def test_get_filename_from_url(url, expected): @pytest.mark.parametrize('content_type,check', [ (None, lambda x: re.match(r'^planet-[a-z0-9]{8}$', x, re.I) is not None), - ('image/tiff', lambda x: x.endswith('.tif')), + ('image/tiff', lambda x: x.endswith(('.tif', '.tiff'))), ]) def test_get_random_filename(content_type, check): assert check(utils.get_random_filename(content_type)) From fe3a43b823551f3246af0c44b5ed9187aa0e65f5 Mon Sep 17 00:00:00 2001 From: Sara Safavi Date: Tue, 30 Apr 2019 15:31:17 -0500 Subject: [PATCH 3/3] update tox config: remove obsolete Python3 versions and allow pytest args --- tox.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tox.ini b/tox.ini index a410f231e..ab3b9d2b6 100644 --- a/tox.ini +++ b/tox.ini @@ -4,10 +4,10 @@ # and then run "tox" from this directory. [tox] -envlist = py27, py34, py35, py36, py37 +envlist = py27, py36, py37 [testenv] deps = pytest commands = pip install -e .[dev] - pytest + pytest {posargs}