Commits

Éric Araujo committed b1a8afc

* Change datetime imports to make mocking easier.
* Use identity comparison instead of equality for types.

Comments (0)

Files changed (2)

dynamodb_mapper/model.py

 """
 from __future__ import absolute_import
 
-import datetime
+import json
 import logging
 import threading
+from datetime import datetime, timedelta, tzinfo
 
 import boto
 from boto.dynamodb.item import Item
 from boto.exception import DynamoDBResponseError
-import json
 
 
 log = logging.getLogger(__name__)
 _JSON_TYPES = frozenset([list, dict])
 
 
-class UTC(datetime.tzinfo):
+class UTC(tzinfo):
     """UTC timezone"""
     def utcoffset(self, dt):
-        return datetime.timedelta(0)
+        return timedelta(0)
 
     def tzname(self, dt):
         return "UTC"
 
     def dst(self, dt):
-        return datetime.timedelta(0)
+        return timedelta(0)
 
 
 utc_tz = UTC()
     if schema_type in _JSON_TYPES:
         return u""
 
-    if schema_type == datetime.datetime:
+    if schema_type is datetime:
         return u""
 
     # Regular string/number
       - For strings, it's an empty string.
       - For numbers, it's zero.
     """
-    if schema_type == datetime.datetime:
+    if schema_type is datetime:
         # Beginning of the UNIX epoch
-        return datetime.datetime(1970, 1, 1, 0, 0, 0, tzinfo=utc_tz)
+        return datetime(1970, 1, 1, 0, 0, 0, tzinfo=utc_tz)
 
     return schema_type()
 
         # json serialization hooks for json_* data types.
         return json.dumps(value, sort_keys=True)
 
-    if isinstance(value, datetime.datetime):
+    if isinstance(value, datetime):
         # datetime instances are stored as UTC in the DB itself.
         # (that way, they become sortable)
         # datetime objects without tzinfo are not supported.
     # This means a missing attribute for a _JSON_TYPES object is valid,
     # and results in an empty sequence. Is that a bad thing?
     if value is None:
-        if schema_type == datetime.datetime:
+        if schema_type is datetime:
             # Default value for unsupplied datetimes:
             # the beginning of the UNIX epoch.
-            return datetime.datetime.now(tz=utc_tz)
+            return datetime.now(tz=utc_tz)
         # Empty sets/strings are represented as missing attributes
         return schema_type()
 
     if schema_type in _JSON_TYPES:
         return schema_type(json.loads(value))
 
-    if schema_type == datetime.datetime:
+    if schema_type is datetime:
         # Parse TZ-aware isoformat
 
         # strptime doesn't support timezone parsing (%z flag), so we're forcing
         # TODO Handle arbitrary timezones (with manual parsing).
         if value.endswith('Z'):
             value = value[:-2] + '+00:00'
-        return datetime.datetime.strptime(
+        return datetime.strptime(
             value, "%Y-%m-%dT%H:%M:%S.%f+00:00").replace(tzinfo=utc_tz)
 
     return schema_type(value)
 
         hash_key_type = cls.__schema__[hash_key_name]
 
-        if hash_key_type == autoincrement_int:
+        if hash_key_type is autoincrement_int:
             if range_key_name:
                 raise SchemaError(
                     "Class defines both a range key and an autoincrement_int hash key",
         table = conn.create_table(cls.__table__, schema, read_units, write_units)
         table.refresh(wait_for_active=wait_for_active)
 
-        if hash_key_type == autoincrement_int:
+        if hash_key_type is autoincrement_int:
             self._create_autoincrement_magic_item(table)
 
         return table
             value = getattr(self, name)
             if isinstance(value, (set, frozenset)):
                 out[name] = sorted(value)
-            elif isinstance(value, datetime.datetime):
+            elif isinstance(value, datetime):
                 # Using strftime instead of str or isoformat to get the right
                 # separator ('T') and time offset notation (with ':')
                 out[name] = value.astimezone(utc_tz).isoformat()
         item_data = self.to_db_dict()
         item = Item(table, attrs=item_data)
 
-        if schema[hash_key] == autoincrement_int and item_data[hash_key] == 0:
+        if schema[hash_key] is autoincrement_int and item_data[hash_key] == 0:
             # We're inserting a new item in an autoincrementing table.
             self._save_autoincrement_hash_key(item)
             # Update the primary key so that it reflects what it was saved as.

dynamodb_mapper/tests/test_model.py

 
     @mock.patch("dynamodb_mapper.model.datetime")
     def test_dynamodb_to_python_default(self, m_datetime):
-        # There's some fairly ugly mock/datetime juggling in that test, because
-        # datetime is written in C, so I can't simply overwrite its attributes
-        # or those of its members:
-        # the entire module must be mocked, and precise bits un-mocked as
-        # required. Joy.
-        m_datetime.timedelta = datetime.timedelta
-        m_now = datetime.datetime.now(tz=utc_tz)
-        m_datetime.datetime.now.return_value = m_now
+        m_datetime.now.return_value = now = datetime.datetime.now(tz=utc_tz)
         self.assertEquals(
-            m_now,
-            _dynamodb_to_python(m_datetime.datetime, None))
+            now,
+            _dynamodb_to_python(m_datetime, None))
 
     def test_dynamodb_to_python_datetime_notz(self):
         # Timezone info is mandatory