diff options
| author | James Aylett <james@tartarus.org> | 2016-02-09 15:00:14 +0000 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2016-02-23 18:51:43 -0500 |
| commit | 1ff6e37de46f0cbf271a287a0ca67678e741a90a (patch) | |
| tree | 00db8ec13fb90be9ffecdbf5442a14bc91487dff /django | |
| parent | eda306f1cec20d490d5dc798ddaa8e8e8d13f26e (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.py | 7 | ||||
| -rw-r--r-- | django/core/files/storage.py | 124 |
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) |
