From 4d5330088ff101c36fd8460dd72c7fd644938c7e Mon Sep 17 00:00:00 2001 From: Julien Danjou Date: Wed, 9 Dec 2015 20:34:16 +0000 Subject: [PATCH] Replace oslo_utils.timeutils This change introduces glance.common.timeutils that provides the timeutils previously consumed from oslo_utils. Oslo is deprecating some timeutils functionality which of Glance depends on. Suggested replacement (isoformat) would break glance APIs so it's cleaner to carry this functionality in Glance rather than re-invent the wheel. Co-Authored-By: Erno Kuvaja Co-Authored-By: Sabari Kumar Murugesan Change-Id: I91e1cc9a273249fd88749cecf21200f3f5e2bab1 --- glance/api/v1/images.py | 2 +- glance/api/v2/image_members.py | 2 +- glance/api/v2/images.py | 2 +- glance/api/v2/tasks.py | 2 +- glance/artifacts/domain/__init__.py | 3 +- glance/cmd/cache_manage.py | 2 +- glance/common/rpc.py | 2 +- glance/common/timeutils.py | 89 ++++++++ glance/common/wsme_utils.py | 3 +- glance/db/simple/api.py | 2 +- glance/db/sqlalchemy/api.py | 2 +- glance/db/sqlalchemy/artifacts.py | 2 +- glance/db/sqlalchemy/metadata.py | 2 +- .../versions/035_add_metadef_tables.py | 2 +- glance/db/sqlalchemy/models.py | 3 +- glance/db/sqlalchemy/models_artifacts.py | 2 +- glance/db/sqlalchemy/models_metadef.py | 2 +- glance/domain/__init__.py | 2 +- glance/notifier.py | 2 +- glance/registry/api/v1/images.py | 2 +- glance/tests/functional/db/base.py | 2 +- .../legacy_functional/test_v1_api.py | 2 +- glance/tests/integration/v2/test_tasks_api.py | 2 +- glance/tests/unit/common/test_timeutils.py | 209 ++++++++++++++++++ glance/tests/unit/test_auth.py | 2 +- glance/tests/unit/test_domain.py | 2 +- glance/tests/unit/test_migrations.py | 2 +- glance/tests/unit/test_notifier.py | 2 +- glance/tests/unit/v1/test_api.py | 2 +- glance/tests/unit/v1/test_registry_api.py | 2 +- glance/tests/unit/v1/test_registry_client.py | 2 +- glance/tests/unit/v2/test_registry_api.py | 2 +- glance/tests/unit/v2/test_registry_client.py | 2 +- glance/tests/unit/v2/test_tasks_resource.py | 2 +- glance/tests/utils.py | 2 +- requirements.txt | 4 + 36 files changed, 337 insertions(+), 34 deletions(-) create mode 100644 glance/common/timeutils.py create mode 100644 glance/tests/unit/common/test_timeutils.py diff --git a/glance/api/v1/images.py b/glance/api/v1/images.py index 9582c08a..d60f613d 100644 --- a/glance/api/v1/images.py +++ b/glance/api/v1/images.py @@ -45,12 +45,12 @@ from glance.api.v1 import upload_utils from glance.common import exception from glance.common import property_utils from glance.common import store_utils +from glance.common import timeutils from glance.common import utils from glance.common import wsgi from glance.i18n import _, _LE, _LI, _LW from glance import notifier import glance.registry.client.v1.api as registry -from oslo_utils import timeutils LOG = logging.getLogger(__name__) SUPPORTED_PARAMS = glance.api.v1.SUPPORTED_PARAMS diff --git a/glance/api/v2/image_members.py b/glance/api/v2/image_members.py index b9fc8a54..636c9f1f 100644 --- a/glance/api/v2/image_members.py +++ b/glance/api/v2/image_members.py @@ -19,12 +19,12 @@ import glance_store from oslo_log import log as logging from oslo_serialization import jsonutils from oslo_utils import encodeutils -from oslo_utils import timeutils import six import webob from glance.api import policy from glance.common import exception +from glance.common import timeutils from glance.common import utils from glance.common import wsgi import glance.db diff --git a/glance/api/v2/images.py b/glance/api/v2/images.py index bbf813b8..8c7cdd82 100644 --- a/glance/api/v2/images.py +++ b/glance/api/v2/images.py @@ -20,7 +20,6 @@ from oslo_config import cfg from oslo_log import log as logging from oslo_serialization import jsonutils as json from oslo_utils import encodeutils -from oslo_utils import timeutils import six import six.moves.urllib.parse as urlparse import webob.exc @@ -28,6 +27,7 @@ import webob.exc from glance.api import policy from glance.common import exception from glance.common import location_strategy +from glance.common import timeutils from glance.common import utils from glance.common import wsgi import glance.db diff --git a/glance/api/v2/tasks.py b/glance/api/v2/tasks.py index 6aa38a8c..afff3d97 100644 --- a/glance/api/v2/tasks.py +++ b/glance/api/v2/tasks.py @@ -21,7 +21,6 @@ from oslo_config import cfg from oslo_log import log as logging import oslo_serialization.jsonutils as json from oslo_utils import encodeutils -from oslo_utils import timeutils from oslo_utils import uuidutils import six import six.moves.urllib.parse as urlparse @@ -30,6 +29,7 @@ import webob.exc from glance.api import common from glance.api import policy from glance.common import exception +from glance.common import timeutils from glance.common import wsgi import glance.db import glance.gateway diff --git a/glance/artifacts/domain/__init__.py b/glance/artifacts/domain/__init__.py index 569b0be2..e2d1ac86 100644 --- a/glance/artifacts/domain/__init__.py +++ b/glance/artifacts/domain/__init__.py @@ -14,8 +14,7 @@ import uuid -from oslo_utils import timeutils - +from glance.common import timeutils from glance.i18n import _ diff --git a/glance/cmd/cache_manage.py b/glance/cmd/cache_manage.py index f91f84d2..8fff5d9f 100755 --- a/glance/cmd/cache_manage.py +++ b/glance/cmd/cache_manage.py @@ -27,8 +27,8 @@ import sys import time from oslo_utils import encodeutils -from oslo_utils import timeutils +from glance.common import timeutils from glance.common import utils from six.moves import input diff --git a/glance/common/rpc.py b/glance/common/rpc.py index 2c0c1607..f7490075 100644 --- a/glance/common/rpc.py +++ b/glance/common/rpc.py @@ -23,12 +23,12 @@ from oslo_config import cfg from oslo_log import log as logging from oslo_utils import encodeutils import oslo_utils.importutils as imp -from oslo_utils import timeutils import six from webob import exc from glance.common import client from glance.common import exception +from glance.common import timeutils from glance.common import wsgi from glance.i18n import _, _LE diff --git a/glance/common/timeutils.py b/glance/common/timeutils.py new file mode 100644 index 00000000..72b9788e --- /dev/null +++ b/glance/common/timeutils.py @@ -0,0 +1,89 @@ +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +""" +Time related utilities and helper functions. +""" + +import datetime + +import iso8601 +from monotonic import monotonic as now # noqa +import six + +# ISO 8601 extended time format with microseconds +_ISO8601_TIME_FORMAT_SUBSECOND = '%Y-%m-%dT%H:%M:%S.%f' +_ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' +PERFECT_TIME_FORMAT = _ISO8601_TIME_FORMAT_SUBSECOND + + +def isotime(at=None, subsecond=False): + """Stringify time in ISO 8601 format.""" + if not at: + at = utcnow() + st = at.strftime(_ISO8601_TIME_FORMAT + if not subsecond + else _ISO8601_TIME_FORMAT_SUBSECOND) + tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' + st += ('Z' if tz == 'UTC' else tz) + return st + + +def parse_isotime(timestr): + """Parse time from ISO 8601 format.""" + try: + return iso8601.parse_date(timestr) + except iso8601.ParseError as e: + raise ValueError(six.text_type(e)) + except TypeError as e: + raise ValueError(six.text_type(e)) + + +def utcnow(with_timezone=False): + """Overridable version of utils.utcnow that can return a TZ-aware datetime. + """ + if utcnow.override_time: + try: + return utcnow.override_time.pop(0) + except AttributeError: + return utcnow.override_time + if with_timezone: + return datetime.datetime.now(tz=iso8601.iso8601.UTC) + return datetime.datetime.utcnow() + + +def normalize_time(timestamp): + """Normalize time in arbitrary timezone to UTC naive object.""" + offset = timestamp.utcoffset() + if offset is None: + return timestamp + return timestamp.replace(tzinfo=None) - offset + + +def iso8601_from_timestamp(timestamp, microsecond=False): + """Returns an iso8601 formatted date from timestamp.""" + return isotime(datetime.datetime.utcfromtimestamp(timestamp), microsecond) + +utcnow.override_time = None + + +def delta_seconds(before, after): + """Return the difference between two timing objects. + + Compute the difference in seconds between two date, time, or + datetime objects (as a float, to microsecond resolution). + """ + delta = after - before + return datetime.timedelta.total_seconds(delta) diff --git a/glance/common/wsme_utils.py b/glance/common/wsme_utils.py index 82f4cbd0..27ad6688 100644 --- a/glance/common/wsme_utils.py +++ b/glance/common/wsme_utils.py @@ -14,9 +14,10 @@ from datetime import datetime -from oslo_utils import timeutils from wsme import types as wsme_types +from glance.common import timeutils + class WSMEModelTransformer(object): diff --git a/glance/db/simple/api.py b/glance/db/simple/api.py index 05b47d05..db4ebbba 100644 --- a/glance/db/simple/api.py +++ b/glance/db/simple/api.py @@ -20,10 +20,10 @@ from operator import itemgetter import uuid from oslo_log import log as logging -from oslo_utils import timeutils import six from glance.common import exception +from glance.common import timeutils from glance.common import utils from glance.i18n import _, _LI, _LW diff --git a/glance/db/sqlalchemy/api.py b/glance/db/sqlalchemy/api.py index b1e202c9..dde26fd7 100644 --- a/glance/db/sqlalchemy/api.py +++ b/glance/db/sqlalchemy/api.py @@ -27,7 +27,6 @@ from oslo_config import cfg from oslo_db import exception as db_exception from oslo_db.sqlalchemy import session from oslo_log import log as logging -from oslo_utils import timeutils import osprofiler.sqlalchemy from retrying import retry import six @@ -39,6 +38,7 @@ import sqlalchemy.sql as sa_sql from glance import artifacts as ga from glance.common import exception +from glance.common import timeutils from glance.common import utils from glance.db.sqlalchemy import artifacts from glance.db.sqlalchemy.metadef_api import (resource_type diff --git a/glance/db/sqlalchemy/artifacts.py b/glance/db/sqlalchemy/artifacts.py index 396cb7f7..11f4c624 100644 --- a/glance/db/sqlalchemy/artifacts.py +++ b/glance/db/sqlalchemy/artifacts.py @@ -19,7 +19,6 @@ import uuid from enum import Enum from oslo_config import cfg from oslo_db import exception as db_exc -from oslo_utils import timeutils import sqlalchemy from sqlalchemy import and_ from sqlalchemy import case @@ -30,6 +29,7 @@ from sqlalchemy.orm import joinedload import glance.artifacts as ga from glance.common import exception from glance.common import semver_db +from glance.common import timeutils from glance.db.sqlalchemy import models_artifacts as models from glance.i18n import _LE, _LW from oslo_log import log as os_logging diff --git a/glance/db/sqlalchemy/metadata.py b/glance/db/sqlalchemy/metadata.py index 65bbba09..6991e3c7 100644 --- a/glance/db/sqlalchemy/metadata.py +++ b/glance/db/sqlalchemy/metadata.py @@ -26,13 +26,13 @@ import re from oslo_config import cfg from oslo_log import log as logging from oslo_utils import encodeutils -from oslo_utils import timeutils import six import sqlalchemy from sqlalchemy import and_ from sqlalchemy.schema import MetaData from sqlalchemy.sql import select +from glance.common import timeutils from glance.i18n import _, _LE, _LI, _LW LOG = logging.getLogger(__name__) diff --git a/glance/db/sqlalchemy/migrate_repo/versions/035_add_metadef_tables.py b/glance/db/sqlalchemy/migrate_repo/versions/035_add_metadef_tables.py index 2674d1c5..47e1f321 100644 --- a/glance/db/sqlalchemy/migrate_repo/versions/035_add_metadef_tables.py +++ b/glance/db/sqlalchemy/migrate_repo/versions/035_add_metadef_tables.py @@ -12,11 +12,11 @@ # License for the specific language governing permissions and limitations # under the License. -from oslo_utils import timeutils import sqlalchemy from sqlalchemy.schema import ( Column, ForeignKey, Index, MetaData, Table, UniqueConstraint) # noqa +from glance.common import timeutils from glance.db.sqlalchemy.migrate_repo.schema import ( Boolean, DateTime, Integer, String, Text, create_tables, drop_tables) # noqa diff --git a/glance/db/sqlalchemy/models.py b/glance/db/sqlalchemy/models.py index 785b9844..1d3526fd 100644 --- a/glance/db/sqlalchemy/models.py +++ b/glance/db/sqlalchemy/models.py @@ -22,7 +22,6 @@ import uuid from oslo_db.sqlalchemy import models from oslo_serialization import jsonutils -from oslo_utils import timeutils from sqlalchemy import BigInteger from sqlalchemy import Boolean from sqlalchemy import Column @@ -39,6 +38,8 @@ from sqlalchemy import Text from sqlalchemy.types import TypeDecorator from sqlalchemy import UniqueConstraint +from glance.common import timeutils + BASE = declarative_base() diff --git a/glance/db/sqlalchemy/models_artifacts.py b/glance/db/sqlalchemy/models_artifacts.py index 40244708..4b1ed4b7 100644 --- a/glance/db/sqlalchemy/models_artifacts.py +++ b/glance/db/sqlalchemy/models_artifacts.py @@ -15,7 +15,6 @@ import uuid from oslo_db.sqlalchemy import models -from oslo_utils import timeutils from sqlalchemy import BigInteger from sqlalchemy import Boolean from sqlalchemy import Column @@ -33,6 +32,7 @@ from sqlalchemy import Text import glance.artifacts as ga from glance.common import semver_db +from glance.common import timeutils from oslo_log import log as os_logging BASE = declarative.declarative_base() diff --git a/glance/db/sqlalchemy/models_metadef.py b/glance/db/sqlalchemy/models_metadef.py index 70af7185..3d822c7c 100644 --- a/glance/db/sqlalchemy/models_metadef.py +++ b/glance/db/sqlalchemy/models_metadef.py @@ -17,7 +17,6 @@ SQLAlchemy models for glance metadata schema """ from oslo_db.sqlalchemy import models -from oslo_utils import timeutils from sqlalchemy import Boolean from sqlalchemy import Column from sqlalchemy import DateTime @@ -30,6 +29,7 @@ from sqlalchemy import String from sqlalchemy import Text from sqlalchemy import UniqueConstraint +from glance.common import timeutils from glance.db.sqlalchemy.models import JSONEncodedDict diff --git a/glance/domain/__init__.py b/glance/domain/__init__.py index e6fa28c6..ca3ecd80 100644 --- a/glance/domain/__init__.py +++ b/glance/domain/__init__.py @@ -22,10 +22,10 @@ from oslo_config import cfg from oslo_log import log as logging from oslo_utils import excutils from oslo_utils import importutils -from oslo_utils import timeutils import six from glance.common import exception +from glance.common import timeutils from glance.i18n import _, _LE, _LI, _LW LOG = logging.getLogger(__name__) diff --git a/glance/notifier.py b/glance/notifier.py index 2a8ce754..84a6b544 100644 --- a/glance/notifier.py +++ b/glance/notifier.py @@ -22,11 +22,11 @@ from oslo_log import log as logging import oslo_messaging from oslo_utils import encodeutils from oslo_utils import excutils -from oslo_utils import timeutils import six import webob from glance.common import exception +from glance.common import timeutils from glance.domain import proxy as domain_proxy from glance.i18n import _, _LE diff --git a/glance/registry/api/v1/images.py b/glance/registry/api/v1/images.py index 97e64c01..0c292254 100644 --- a/glance/registry/api/v1/images.py +++ b/glance/registry/api/v1/images.py @@ -21,11 +21,11 @@ from oslo_config import cfg from oslo_log import log as logging from oslo_utils import encodeutils from oslo_utils import strutils -from oslo_utils import timeutils from oslo_utils import uuidutils from webob import exc from glance.common import exception +from glance.common import timeutils from glance.common import utils from glance.common import wsgi import glance.db diff --git a/glance/tests/functional/db/base.py b/glance/tests/functional/db/base.py index 8b08da7d..04ee1a32 100644 --- a/glance/tests/functional/db/base.py +++ b/glance/tests/functional/db/base.py @@ -20,11 +20,11 @@ import datetime import uuid import mock -from oslo_utils import timeutils # NOTE(jokke): simplified transition to py3, behaves like py2 xrange from six.moves import range from glance.common import exception +from glance.common import timeutils from glance import context from glance.tests import functional import glance.tests.functional.db as db_tests diff --git a/glance/tests/integration/legacy_functional/test_v1_api.py b/glance/tests/integration/legacy_functional/test_v1_api.py index bf7486a1..6a551c87 100644 --- a/glance/tests/integration/legacy_functional/test_v1_api.py +++ b/glance/tests/integration/legacy_functional/test_v1_api.py @@ -16,10 +16,10 @@ import os import tempfile from oslo_serialization import jsonutils -from oslo_utils import timeutils from oslo_utils import units import testtools +from glance.common import timeutils from glance.tests.integration.legacy_functional import base from glance.tests.utils import minimal_headers diff --git a/glance/tests/integration/v2/test_tasks_api.py b/glance/tests/integration/v2/test_tasks_api.py index 13f5efad..3f71fcbc 100644 --- a/glance/tests/integration/v2/test_tasks_api.py +++ b/glance/tests/integration/v2/test_tasks_api.py @@ -16,9 +16,9 @@ import time from oslo_serialization import jsonutils as json -from oslo_utils import timeutils from glance.api.v2 import tasks +from glance.common import timeutils from glance.tests.integration.v2 import base TENANT1 = '6838eb7b-6ded-434a-882c-b344c77fe8df' diff --git a/glance/tests/unit/common/test_timeutils.py b/glance/tests/unit/common/test_timeutils.py new file mode 100644 index 00000000..fd8a6151 --- /dev/null +++ b/glance/tests/unit/common/test_timeutils.py @@ -0,0 +1,209 @@ +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import calendar +import datetime + +import iso8601 +import mock + +from glance.common import timeutils +from glance.tests import utils as test_utils + + +class TimeUtilsTest(test_utils.BaseTestCase): + + def setUp(self): + super(TimeUtilsTest, self).setUp() + self.skynet_self_aware_time_str = '1997-08-29T06:14:00Z' + self.skynet_self_aware_time_ms_str = '1997-08-29T06:14:00.000123Z' + self.skynet_self_aware_time = datetime.datetime(1997, 8, 29, 6, 14, 0) + self.skynet_self_aware_ms_time = datetime.datetime( + 1997, 8, 29, 6, 14, 0, 123) + self.one_minute_before = datetime.datetime(1997, 8, 29, 6, 13, 0) + self.one_minute_after = datetime.datetime(1997, 8, 29, 6, 15, 0) + self.skynet_self_aware_time_perfect_str = '1997-08-29T06:14:00.000000' + self.skynet_self_aware_time_perfect = datetime.datetime(1997, 8, 29, + 6, 14, 0) + + def test_isotime(self): + with mock.patch('datetime.datetime') as datetime_mock: + datetime_mock.utcnow.return_value = self.skynet_self_aware_time + dt = timeutils.isotime() + self.assertEqual(dt, self.skynet_self_aware_time_str) + + def test_isotimei_micro_second_precision(self): + with mock.patch('datetime.datetime') as datetime_mock: + datetime_mock.utcnow.return_value = self.skynet_self_aware_ms_time + dt = timeutils.isotime(subsecond=True) + self.assertEqual(dt, self.skynet_self_aware_time_ms_str) + + def test_parse_isotime(self): + expect = timeutils.parse_isotime(self.skynet_self_aware_time_str) + skynet_self_aware_time_utc = self.skynet_self_aware_time.replace( + tzinfo=iso8601.iso8601.UTC) + self.assertEqual(skynet_self_aware_time_utc, expect) + + def test_parse_isotime_micro_second_precision(self): + expect = timeutils.parse_isotime(self.skynet_self_aware_time_ms_str) + skynet_self_aware_time_ms_utc = self.skynet_self_aware_ms_time.replace( + tzinfo=iso8601.iso8601.UTC) + self.assertEqual(skynet_self_aware_time_ms_utc, expect) + + def test_utcnow(self): + with mock.patch('datetime.datetime') as datetime_mock: + datetime_mock.utcnow.return_value = self.skynet_self_aware_time + self.assertEqual(timeutils.utcnow(), self.skynet_self_aware_time) + + self.assertFalse(timeutils.utcnow() == self.skynet_self_aware_time) + self.assertTrue(timeutils.utcnow()) + + def test_delta_seconds(self): + before = timeutils.utcnow() + after = before + datetime.timedelta(days=7, seconds=59, + microseconds=123456) + self.assertAlmostEquals(604859.123456, + timeutils.delta_seconds(before, after)) + + def test_iso8601_from_timestamp(self): + utcnow = timeutils.utcnow() + iso = timeutils.isotime(utcnow) + ts = calendar.timegm(utcnow.timetuple()) + self.assertEqual(iso, timeutils.iso8601_from_timestamp(ts)) + + +class TestIso8601Time(test_utils.BaseTestCase): + + def _instaneous(self, timestamp, yr, mon, day, hr, minute, sec, micro): + self.assertEqual(timestamp.year, yr) + self.assertEqual(timestamp.month, mon) + self.assertEqual(timestamp.day, day) + self.assertEqual(timestamp.hour, hr) + self.assertEqual(timestamp.minute, minute) + self.assertEqual(timestamp.second, sec) + self.assertEqual(timestamp.microsecond, micro) + + def _do_test(self, time_str, yr, mon, day, hr, minute, sec, micro, shift): + DAY_SECONDS = 24 * 60 * 60 + timestamp = timeutils.parse_isotime(time_str) + self._instaneous(timestamp, yr, mon, day, hr, minute, sec, micro) + offset = timestamp.tzinfo.utcoffset(None) + self.assertEqual(offset.seconds + offset.days * DAY_SECONDS, shift) + + def test_zulu(self): + time_str = '2012-02-14T20:53:07Z' + self._do_test(time_str, 2012, 2, 14, 20, 53, 7, 0, 0) + + def test_zulu_micros(self): + time_str = '2012-02-14T20:53:07.123Z' + self._do_test(time_str, 2012, 2, 14, 20, 53, 7, 123000, 0) + + def test_offset_east(self): + time_str = '2012-02-14T20:53:07+04:30' + offset = 4.5 * 60 * 60 + self._do_test(time_str, 2012, 2, 14, 20, 53, 7, 0, offset) + + def test_offset_east_micros(self): + time_str = '2012-02-14T20:53:07.42+04:30' + offset = 4.5 * 60 * 60 + self._do_test(time_str, 2012, 2, 14, 20, 53, 7, 420000, offset) + + def test_offset_west(self): + time_str = '2012-02-14T20:53:07-05:30' + offset = -5.5 * 60 * 60 + self._do_test(time_str, 2012, 2, 14, 20, 53, 7, 0, offset) + + def test_offset_west_micros(self): + time_str = '2012-02-14T20:53:07.654321-05:30' + offset = -5.5 * 60 * 60 + self._do_test(time_str, 2012, 2, 14, 20, 53, 7, 654321, offset) + + def test_compare(self): + zulu = timeutils.parse_isotime('2012-02-14T20:53:07') + east = timeutils.parse_isotime('2012-02-14T20:53:07-01:00') + west = timeutils.parse_isotime('2012-02-14T20:53:07+01:00') + self.assertTrue(east > west) + self.assertTrue(east > zulu) + self.assertTrue(zulu > west) + + def test_compare_micros(self): + zulu = timeutils.parse_isotime('2012-02-14T20:53:07.6544') + east = timeutils.parse_isotime('2012-02-14T19:53:07.654321-01:00') + west = timeutils.parse_isotime('2012-02-14T21:53:07.655+01:00') + self.assertTrue(east < west) + self.assertTrue(east < zulu) + self.assertTrue(zulu < west) + + def test_zulu_roundtrip(self): + time_str = '2012-02-14T20:53:07Z' + zulu = timeutils.parse_isotime(time_str) + self.assertEqual(zulu.tzinfo, iso8601.iso8601.UTC) + self.assertEqual(timeutils.isotime(zulu), time_str) + + def test_east_roundtrip(self): + time_str = '2012-02-14T20:53:07-07:00' + east = timeutils.parse_isotime(time_str) + self.assertEqual(east.tzinfo.tzname(None), '-07:00') + self.assertEqual(timeutils.isotime(east), time_str) + + def test_west_roundtrip(self): + time_str = '2012-02-14T20:53:07+11:30' + west = timeutils.parse_isotime(time_str) + self.assertEqual(west.tzinfo.tzname(None), '+11:30') + self.assertEqual(timeutils.isotime(west), time_str) + + def test_now_roundtrip(self): + time_str = timeutils.isotime() + now = timeutils.parse_isotime(time_str) + self.assertEqual(now.tzinfo, iso8601.iso8601.UTC) + self.assertEqual(timeutils.isotime(now), time_str) + + def test_zulu_normalize(self): + time_str = '2012-02-14T20:53:07Z' + zulu = timeutils.parse_isotime(time_str) + normed = timeutils.normalize_time(zulu) + self._instaneous(normed, 2012, 2, 14, 20, 53, 7, 0) + + def test_east_normalize(self): + time_str = '2012-02-14T20:53:07-07:00' + east = timeutils.parse_isotime(time_str) + normed = timeutils.normalize_time(east) + self._instaneous(normed, 2012, 2, 15, 3, 53, 7, 0) + + def test_west_normalize(self): + time_str = '2012-02-14T20:53:07+21:00' + west = timeutils.parse_isotime(time_str) + normed = timeutils.normalize_time(west) + self._instaneous(normed, 2012, 2, 13, 23, 53, 7, 0) + + def test_normalize_aware_to_naive(self): + dt = datetime.datetime(2011, 2, 14, 20, 53, 7) + time_str = '2011-02-14T20:53:07+21:00' + aware = timeutils.parse_isotime(time_str) + naive = timeutils.normalize_time(aware) + self.assertTrue(naive < dt) + + def test_normalize_zulu_aware_to_naive(self): + dt = datetime.datetime(2011, 2, 14, 20, 53, 7) + time_str = '2011-02-14T19:53:07Z' + aware = timeutils.parse_isotime(time_str) + naive = timeutils.normalize_time(aware) + self.assertTrue(naive < dt) + + def test_normalize_naive(self): + dt = datetime.datetime(2011, 2, 14, 20, 53, 7) + dtn = datetime.datetime(2011, 2, 14, 19, 53, 7) + naive = timeutils.normalize_time(dtn) + self.assertTrue(naive < dt) diff --git a/glance/tests/unit/test_auth.py b/glance/tests/unit/test_auth.py index a9921c76..f67fb88c 100644 --- a/glance/tests/unit/test_auth.py +++ b/glance/tests/unit/test_auth.py @@ -15,13 +15,13 @@ # under the License. from oslo_serialization import jsonutils -from oslo_utils import timeutils from oslotest import moxstubout import webob from glance.api import authorization from glance.common import auth from glance.common import exception +from glance.common import timeutils import glance.domain from glance.tests.unit import utils as unittest_utils from glance.tests import utils diff --git a/glance/tests/unit/test_domain.py b/glance/tests/unit/test_domain.py index 02aa9b36..6f7fb466 100644 --- a/glance/tests/unit/test_domain.py +++ b/glance/tests/unit/test_domain.py @@ -20,13 +20,13 @@ import uuid import mock from oslo_config import cfg import oslo_utils.importutils -from oslo_utils import timeutils from glance.artifacts import domain as artifacts_domain import glance.async from glance.async import taskflow_executor from glance.common.artifacts import definitions from glance.common import exception +from glance.common import timeutils from glance import domain import glance.tests.utils as test_utils diff --git a/glance/tests/unit/test_migrations.py b/glance/tests/unit/test_migrations.py index 023913a7..d20241dc 100644 --- a/glance/tests/unit/test_migrations.py +++ b/glance/tests/unit/test_migrations.py @@ -37,7 +37,6 @@ from oslo_db.sqlalchemy import test_base from oslo_db.sqlalchemy import test_migrations from oslo_db.sqlalchemy import utils as db_utils from oslo_serialization import jsonutils -from oslo_utils import timeutils from oslo_utils import uuidutils # NOTE(jokke): simplified transition to py3, behaves like py2 xrange from six.moves import range @@ -46,6 +45,7 @@ from sqlalchemy import inspect from glance.common import crypt from glance.common import exception +from glance.common import timeutils from glance.db import migration from glance.db.sqlalchemy import migrate_repo from glance.db.sqlalchemy.migrate_repo.schema import from_migration_import diff --git a/glance/tests/unit/test_notifier.py b/glance/tests/unit/test_notifier.py index 7b68e976..b0a32a41 100644 --- a/glance/tests/unit/test_notifier.py +++ b/glance/tests/unit/test_notifier.py @@ -20,11 +20,11 @@ import glance_store import mock from oslo_config import cfg import oslo_messaging -from oslo_utils import timeutils import webob import glance.async from glance.common import exception +from glance.common import timeutils import glance.context from glance import notifier import glance.tests.unit.utils as unit_test_utils diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py index 8a54164d..1039abf6 100644 --- a/glance/tests/unit/v1/test_api.py +++ b/glance/tests/unit/v1/test_api.py @@ -26,7 +26,6 @@ import glance_store as store import mock from oslo_config import cfg from oslo_serialization import jsonutils -from oslo_utils import timeutils import routes import six import webob @@ -37,6 +36,7 @@ from glance.api.v1 import router from glance.api.v1 import upload_utils import glance.common.config from glance.common import exception +from glance.common import timeutils import glance.context from glance.db.sqlalchemy import api as db_api from glance.db.sqlalchemy import models as db_models diff --git a/glance/tests/unit/v1/test_registry_api.py b/glance/tests/unit/v1/test_registry_api.py index 6b242ceb..065143e8 100644 --- a/glance/tests/unit/v1/test_registry_api.py +++ b/glance/tests/unit/v1/test_registry_api.py @@ -21,7 +21,6 @@ import uuid import mock from oslo_config import cfg from oslo_serialization import jsonutils -from oslo_utils import timeutils import routes import six import webob @@ -29,6 +28,7 @@ import webob import glance.api.common import glance.common.config from glance.common import crypt +from glance.common import timeutils from glance import context from glance.db.sqlalchemy import api as db_api from glance.db.sqlalchemy import models as db_models diff --git a/glance/tests/unit/v1/test_registry_client.py b/glance/tests/unit/v1/test_registry_client.py index 019070db..424bd568 100644 --- a/glance/tests/unit/v1/test_registry_client.py +++ b/glance/tests/unit/v1/test_registry_client.py @@ -19,7 +19,6 @@ import os import uuid from mock import patch -from oslo_utils import timeutils from six.moves import reload_module import testtools @@ -27,6 +26,7 @@ from glance.api.v1.images import Controller as acontroller from glance.common import client as test_client from glance.common import config from glance.common import exception +from glance.common import timeutils from glance import context from glance.db.sqlalchemy import api as db_api from glance.registry.api.v1.images import Controller as rcontroller diff --git a/glance/tests/unit/v2/test_registry_api.py b/glance/tests/unit/v2/test_registry_api.py index 783842a7..6adf55fe 100644 --- a/glance/tests/unit/v2/test_registry_api.py +++ b/glance/tests/unit/v2/test_registry_api.py @@ -20,13 +20,13 @@ import uuid from oslo_config import cfg from oslo_serialization import jsonutils -from oslo_utils import timeutils import routes import six import webob import glance.api.common import glance.common.config +from glance.common import timeutils import glance.context from glance.db.sqlalchemy import api as db_api from glance.db.sqlalchemy import models as db_models diff --git a/glance/tests/unit/v2/test_registry_client.py b/glance/tests/unit/v2/test_registry_client.py index fc70f398..6bc99bf0 100644 --- a/glance/tests/unit/v2/test_registry_client.py +++ b/glance/tests/unit/v2/test_registry_client.py @@ -25,11 +25,11 @@ import os import uuid from mock import patch -from oslo_utils import timeutils from six.moves import reload_module from glance.common import config from glance.common import exception +from glance.common import timeutils from glance import context from glance.db.sqlalchemy import api as db_api from glance.i18n import _ diff --git a/glance/tests/unit/v2/test_tasks_resource.py b/glance/tests/unit/v2/test_tasks_resource.py index 6167d01d..8db70910 100644 --- a/glance/tests/unit/v2/test_tasks_resource.py +++ b/glance/tests/unit/v2/test_tasks_resource.py @@ -20,12 +20,12 @@ import uuid import mock from oslo_config import cfg from oslo_serialization import jsonutils -from oslo_utils import timeutils # NOTE(jokke): simplified transition to py3, behaves like py2 xrange from six.moves import range import webob import glance.api.v2.tasks +from glance.common import timeutils import glance.domain import glance.gateway from glance.tests.unit import base diff --git a/glance/tests/utils.py b/glance/tests/utils.py index ac56fb51..50247564 100644 --- a/glance/tests/utils.py +++ b/glance/tests/utils.py @@ -28,7 +28,6 @@ from oslo_config import cfg from oslo_config import fixture as cfg_fixture from oslo_log import log from oslo_serialization import jsonutils -from oslo_utils import timeutils from oslotest import moxstubout import six from six.moves import BaseHTTPServer @@ -38,6 +37,7 @@ import webob from glance.common import config from glance.common import exception from glance.common import property_utils +from glance.common import timeutils from glance.common import utils from glance.common import wsgi from glance import context diff --git a/requirements.txt b/requirements.txt index 0d805b60..75fbd094 100644 --- a/requirements.txt +++ b/requirements.txt @@ -54,3 +54,7 @@ semantic-version>=2.3.1 castellan>=0.3.1 # Apache-2.0 cryptography>=1.0 # Apache-2.0 + +# timeutils +iso8601>=0.1.9 +monotonic>=0.3 # Apache-2.0