summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
authorJames Aylett <james@tartarus.org>2016-02-09 15:00:14 +0000
committerTim Graham <timograham@gmail.com>2016-02-23 18:51:43 -0500
commit1ff6e37de46f0cbf271a287a0ca67678e741a90a (patch)
tree00db8ec13fb90be9ffecdbf5442a14bc91487dff /django
parenteda306f1cec20d490d5dc798ddaa8e8e8d13f26e (diff)
Fixed #23832 -- Added timezone aware Storage API.
New Storage.get_{accessed,created,modified}_time() methods convert the naive time from now-deprecated {accessed,created_modified}_time() methods into aware objects in UTC if USE_TZ=True.
Diffstat (limited to 'django')
-rw-r--r--django/contrib/staticfiles/management/commands/collectstatic.py7
-rw-r--r--django/core/files/storage.py124
2 files changed, 124 insertions, 7 deletions
diff --git a/django/contrib/staticfiles/management/commands/collectstatic.py b/django/contrib/staticfiles/management/commands/collectstatic.py
index 4d6df282c3..60c4e7cd6d 100644
--- a/django/contrib/staticfiles/management/commands/collectstatic.py
+++ b/django/contrib/staticfiles/management/commands/collectstatic.py
@@ -237,15 +237,14 @@ class Command(BaseCommand):
if self.storage.exists(prefixed_path):
try:
# When was the target file modified last time?
- target_last_modified = \
- self.storage.modified_time(prefixed_path)
+ target_last_modified = self.storage.get_modified_time(prefixed_path)
except (OSError, NotImplementedError, AttributeError):
- # The storage doesn't support ``modified_time`` or failed
+ # The storage doesn't support get_modified_time() or failed
pass
else:
try:
# When was the source file modified last time?
- source_last_modified = source_storage.modified_time(path)
+ source_last_modified = source_storage.get_modified_time(path)
except (OSError, NotImplementedError, AttributeError):
pass
else:
diff --git a/django/core/files/storage.py b/django/core/files/storage.py
index 208884e1cf..d8423f0600 100644
--- a/django/core/files/storage.py
+++ b/django/core/files/storage.py
@@ -1,5 +1,6 @@
import errno
import os
+import warnings
from datetime import datetime
from django.conf import settings
@@ -7,9 +8,11 @@ from django.core.exceptions import SuspiciousFileOperation
from django.core.files import File, locks
from django.core.files.move import file_move_safe
from django.core.signals import setting_changed
+from django.utils import timezone
from django.utils._os import abspathu, safe_join
from django.utils.crypto import get_random_string
from django.utils.deconstruct import deconstructible
+from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.encoding import filepath_to_uri, force_text
from django.utils.functional import LazyObject, cached_property
from django.utils.module_loading import import_string
@@ -140,24 +143,101 @@ class Storage(object):
def accessed_time(self, name):
"""
Returns the last accessed time (as datetime object) of the file
- specified by name.
+ specified by name. Deprecated: use get_accessed_time() instead.
"""
+ warnings.warn(
+ 'Storage.accessed_time() is deprecated in favor of get_accessed_time().',
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
raise NotImplementedError('subclasses of Storage must provide an accessed_time() method')
def created_time(self, name):
"""
Returns the creation time (as datetime object) of the file
- specified by name.
+ specified by name. Deprecated: use get_created_time() instead.
"""
+ warnings.warn(
+ 'Storage.created_time() is deprecated in favor of get_created_time().',
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
raise NotImplementedError('subclasses of Storage must provide a created_time() method')
def modified_time(self, name):
"""
Returns the last modified time (as datetime object) of the file
- specified by name.
+ specified by name. Deprecated: use get_modified_time() instead.
"""
+ warnings.warn(
+ 'Storage.modified_time() is deprecated in favor of get_modified_time().',
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
raise NotImplementedError('subclasses of Storage must provide a modified_time() method')
+ def get_accessed_time(self, name):
+ """
+ Return the last accessed time (as a datetime) of the file specified by
+ name. The datetime will be timezone-aware if USE_TZ=True.
+ """
+ # At the end of the deprecation:
+ # raise NotImplementedError('subclasses of Storage must provide a get_accessed_time() method')
+ warnings.warn(
+ 'Storage.accessed_time() is deprecated. '
+ 'Storage backends should implement get_accessed_time().',
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
+ dt = self.accessed_time(name)
+ return _possibly_make_aware(dt)
+
+ def get_created_time(self, name):
+ """
+ Return the creation time (as a datetime) of the file specified by name.
+ The datetime will be timezone-aware if USE_TZ=True.
+ """
+ # At the end of the deprecation:
+ # raise NotImplementedError('subclasses of Storage must provide a get_created_time() method')
+ warnings.warn(
+ 'Storage.created_time() is deprecated. '
+ 'Storage backends should implement get_created_time().',
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
+ dt = self.created_time(name)
+ return _possibly_make_aware(dt)
+
+ def get_modified_time(self, name):
+ """
+ Return the last modified time (as a datetime) of the file specified by
+ name. The datetime will be timezone-aware if USE_TZ=True.
+ """
+ # At the end of the deprecation:
+ # raise NotImplementedError('subclasses of Storage must provide a get_modified_time() method')
+ warnings.warn(
+ 'Storage.modified_time() is deprecated. '
+ 'Storage backends should implement get_modified_time().',
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
+ dt = self.modified_time(name)
+ return _possibly_make_aware(dt)
+
+
+def _possibly_make_aware(dt):
+ """
+ Convert a datetime object in the local timezone to aware
+ in UTC, if USE_TZ is True.
+ """
+ # This function is only needed to help with the deprecations above and can
+ # be removed in Django 2.0, RemovedInDjango20Warning.
+ if settings.USE_TZ:
+ tz = timezone.get_default_timezone()
+ return timezone.make_aware(dt, tz).astimezone(timezone.utc)
+ else:
+ return dt
+
@deconstructible
class FileSystemStorage(Storage):
@@ -328,14 +408,52 @@ class FileSystemStorage(Storage):
return urljoin(self.base_url, filepath_to_uri(name))
def accessed_time(self, name):
+ warnings.warn(
+ 'FileSystemStorage.accessed_time() is deprecated in favor of '
+ 'get_accessed_time().',
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
return datetime.fromtimestamp(os.path.getatime(self.path(name)))
def created_time(self, name):
+ warnings.warn(
+ 'FileSystemStorage.created_time() is deprecated in favor of '
+ 'get_created_time().',
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
return datetime.fromtimestamp(os.path.getctime(self.path(name)))
def modified_time(self, name):
+ warnings.warn(
+ 'FileSystemStorage.modified_time() is deprecated in favor of '
+ 'get_modified_time().',
+ RemovedInDjango20Warning,
+ stacklevel=2,
+ )
return datetime.fromtimestamp(os.path.getmtime(self.path(name)))
+ def _datetime_from_timestamp(self, ts):
+ """
+ If timezone support is enabled, make an aware datetime object in UTC;
+ otherwise make a naive one in the local timezone.
+ """
+ if settings.USE_TZ:
+ # Safe to use .replace() because UTC doesn't have DST
+ return datetime.utcfromtimestamp(ts).replace(tzinfo=timezone.utc)
+ else:
+ return datetime.fromtimestamp(ts)
+
+ def get_accessed_time(self, name):
+ return self._datetime_from_timestamp(os.path.getatime(self.path(name)))
+
+ def get_created_time(self, name):
+ return self._datetime_from_timestamp(os.path.getctime(self.path(name)))
+
+ def get_modified_time(self, name):
+ return self._datetime_from_timestamp(os.path.getmtime(self.path(name)))
+
def get_storage_class(import_path=None):
return import_string(import_path or settings.DEFAULT_FILE_STORAGE)