Jannis Leidel avatar Jannis Leidel committed c7ebf4e

Added a custom datetime.datetime subclass to act as a compatibility layer between South and Django 1.4s timezone aware datetime objects.

Comments (0)

Files changed (8)

         'south.tests.otherfakeapp.migrations',
         'south.tests.deps_c.migrations',
         'south.tests.deps_b.migrations'
+        'south.utils',
     ],
 )

south/creator/actions.py

 """
 
 import sys
-import datetime
 
 from django.db.models.fields.related import RECURSIVE_RELATIONSHIP_CONSTANT
 from django.db.models.fields import FieldDoesNotExist, NOT_PROVIDED, CharField, TextField
 
 from south import modelsinspector
 from south.creator.freezer import remove_useless_attributes, model_key
+from south.utils import datetime_utils
 
 class Action(object):
     """
                 sys.exit(1)
             else:
                 try:
-                    result = eval(code, {}, {"datetime": datetime})
+                    result = eval(code, {}, {"datetime": datetime_utils})
                 except (SyntaxError, NameError), e:
                     print " ! Invalid input: %s" % e
                 else:

south/migration/base.py

 from south import exceptions
 from south.migration.utils import depends, dfs, flatten, get_app_label
 from south.orm import FakeORM
-from south.utils import memoize, ask_for_it_by_name
+from south.utils import memoize, ask_for_it_by_name, datetime_utils
 from south.migration.utils import app_label_to_app_module
 
 
                 raise exceptions.BrokenMigration(self, sys.exc_info())
         # Override some imports
         migration._ = lambda x: x  # Fake i18n
-        migration.datetime = datetime
+        migration.datetime = datetime_utils
         return migration
     migration = memoize(migration)
 

south/migration/migrators.py

     def record(migration, database):
         # Record us as having done this
         record = MigrationHistory.for_migration(migration, database)
-        record.applied = datetime.datetime.utcnow()
+        try:
+            from django.utils.timezone import now
+            record.applied = now()
+        except ImportError:
+            record.applied = datetime.datetime.utcnow()
         if database != DEFAULT_DB_ALIAS:
             record.save(using=database)
         else:
 """
 
 import inspect
-import datetime
 
 from django.db import models
 from django.db.models.loading import cache
 from django.core.exceptions import ImproperlyConfigured
 
 from south.db import db
-from south.utils import ask_for_it_by_name
+from south.utils import ask_for_it_by_name, datetime_utils
 from south.hacks import hacks
 from south.exceptions import UnfreezeMeLater, ORMBaseNotIncluded, ImpossibleORMUnfreeze
 
         fake_locals['_'] = lambda x: x
         
         # Datetime; there should be no datetime direct accesses
-        fake_locals['datetime'] = datetime
+        fake_locals['datetime'] = datetime_utils
         
         # Now, go through the requested imports and import them.
         for name, value in extra_imports.items():

south/utils.py

-"""
-Generally helpful utility functions.
-"""
-
-
-def _ask_for_it_by_name(name):
-    "Returns an object referenced by absolute path."
-    bits = name.split(".")
-
-    ## what if there is no absolute reference?
-    if len(bits)>1:
-        modulename = ".".join(bits[:-1])
-    else:
-        modulename=bits[0]
-        
-    module = __import__(modulename, {}, {}, bits[-1])
-    
-    if len(bits) == 1:
-        return module
-    else:
-        return getattr(module, bits[-1])
-
-
-def ask_for_it_by_name(name): 
-    "Returns an object referenced by absolute path. (Memoised outer wrapper)"
-    if name not in ask_for_it_by_name.cache: 
-        ask_for_it_by_name.cache[name] = _ask_for_it_by_name(name) 
-    return ask_for_it_by_name.cache[name] 
-ask_for_it_by_name.cache = {} 
-
-
-def get_attribute(item, attribute):
-    """
-    Like getattr, but recursive (i.e. you can ask for 'foo.bar.yay'.)
-    """
-    value = item
-    for part in attribute.split("."):
-        value = getattr(value, part)
-    return value
-
-def auto_through(field):
-    "Returns if the M2M class passed in has an autogenerated through table or not."
-    return (
-        # Django 1.0/1.1
-        (not field.rel.through)
-        or
-        # Django 1.2+
-        getattr(getattr(field.rel.through, "_meta", None), "auto_created", False)
-    )
-
-def auto_model(model):
-    "Returns if the given model was automatically generated."
-    return getattr(model._meta, "auto_created", False)
-
-def memoize(function):
-    "Standard memoization decorator."
-    name = function.__name__
-    _name = '_' + name
-    
-    def method(self):
-        if not hasattr(self, _name):
-            value = function(self)
-            setattr(self, _name, value)
-        return getattr(self, _name)
-    
-    def invalidate():
-        if hasattr(method, _name):
-            delattr(method, _name)
-        
-    method.__name__ = function.__name__
-    method.__doc__ = function.__doc__
-    method._invalidate = invalidate
-    return method

south/utils/__init__.py

+"""
+Generally helpful utility functions.
+"""
+
+
+def _ask_for_it_by_name(name):
+    "Returns an object referenced by absolute path."
+    bits = name.split(".")
+
+    ## what if there is no absolute reference?
+    if len(bits)>1:
+        modulename = ".".join(bits[:-1])
+    else:
+        modulename=bits[0]
+
+    module = __import__(modulename, {}, {}, bits[-1])
+
+    if len(bits) == 1:
+        return module
+    else:
+        return getattr(module, bits[-1])
+
+
+def ask_for_it_by_name(name):
+    "Returns an object referenced by absolute path. (Memoised outer wrapper)"
+    if name not in ask_for_it_by_name.cache:
+        ask_for_it_by_name.cache[name] = _ask_for_it_by_name(name)
+    return ask_for_it_by_name.cache[name]
+ask_for_it_by_name.cache = {}
+
+
+def get_attribute(item, attribute):
+    """
+    Like getattr, but recursive (i.e. you can ask for 'foo.bar.yay'.)
+    """
+    value = item
+    for part in attribute.split("."):
+        value = getattr(value, part)
+    return value
+
+def auto_through(field):
+    "Returns if the M2M class passed in has an autogenerated through table or not."
+    return (
+        # Django 1.0/1.1
+        (not field.rel.through)
+        or
+        # Django 1.2+
+        getattr(getattr(field.rel.through, "_meta", None), "auto_created", False)
+    )
+
+def auto_model(model):
+    "Returns if the given model was automatically generated."
+    return getattr(model._meta, "auto_created", False)
+
+def memoize(function):
+    "Standard memoization decorator."
+    name = function.__name__
+    _name = '_' + name
+
+    def method(self):
+        if not hasattr(self, _name):
+            value = function(self)
+            setattr(self, _name, value)
+        return getattr(self, _name)
+
+    def invalidate():
+        if hasattr(method, _name):
+            delattr(method, _name)
+
+    method.__name__ = function.__name__
+    method.__doc__ = function.__doc__
+    method._invalidate = invalidate
+    return method

south/utils/datetime_utils.py

+from datetime import *
+
+import django
+from django.conf import settings
+
+if django.VERSION[:2] >= (1, 4) and getattr(settings, 'USE_TZ', False):
+    from django.utils import timezone
+    from datetime import datetime as _datetime
+
+    class datetime(_datetime):
+        """
+        A custom datetime.datetime class which acts as a compatibility
+        layer between South and Django 1.4's timezone aware datetime
+        instances.
+
+        It basically adds the default timezone (as configured in Django's
+        settings) automatically if no tzinfo is given.
+        """
+        def __new__(cls, year, month, day,
+                    hour=0, minute=0, second=0, microsecond=0, tzinfo=None):
+
+            dt = _datetime(year, month, day,
+                           hour, minute, second, microsecond,
+                           tzinfo=tzinfo)
+            if tzinfo is None:
+                default_timezone = timezone.get_default_timezone()
+                dt = timezone.make_aware(dt, default_timezone)
+            return dt
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.