Commits

Roger Boardman committed 560a05e Draft Merge

Merged david/django-storages into default

Comments (0)

Files changed (7)

 3e8e477cf67db87f3ac796e9743b81b71867fd0d 1.1.4
 ae4dad30b2f6b4edc328cc0f9cf25b888e090f7d 1.1.5
 082f958b38117b2f043a5e85aaaad97157480048 1.1.6
+c32a25c5ed5da39a9f6866336f6cccad0343b659 1.1.7
+d26425cbfcb1f31b4e9259a09456c6a004f73c2d 1.1.8
 django-storages change log
 ==========================
 
+1.1.8 (2013-03-31)
+******************
+
+* Fixes `#156`_ regarding date parsing, ValueError when running collectstatic
+* Proper handling of boto dev version parsing
+* Made SFTP URLs accessible, now uses settings.MEDIA_URL instead of sftp://
+
+.. _#156: https://bitbucket.org/david/django-storages/issue/156/s3boto-backend-valueerror-time-data-thu-07
+
+1.1.7 (2013-03-20)
+******************
+
+* Listing of huge buckets on S3 is now prevented by using the prefix argument to boto's list() method
+* Initial support for Windows Azure Storage
+* Switched to useing boto's parse_ts date parser getting last modified info when using S3boto backend
+* Fixed key handling in S3boto and Google Storage backends
+* Account for lack of multipart upload in Google Storage backend
+* Fixed seek() issue when using AWS_IS_GZIPPED by darkness51 with pull-request `#50`_
+* Improvements to S3BotoStorage and GSBotoStorage
+
+.. _#50: https://bitbucket.org/david/django-storages/pull-request/50/
+
 1.1.6 (2013-01-06)
 ******************
 

storages/__init__.py

-__version__ = '1.1.6'
+__version__ = '1.1.8'

storages/backends/s3boto.py

 import os
 import mimetypes
 from gzip import GzipFile
+import datetime
 
 try:
     from cStringIO import StringIO
 
 from storages.utils import setting
 
-boto_version_info = tuple([int(i) for i in boto_version.split('.')])
+boto_version_info = tuple([int(i) for i in boto_version.split('-')[0].split('.')])
 
 if boto_version_info[:2] < (2, 4):
     raise ImproperlyConfigured("The installed Boto library must be 2.4 or "
                                "higher.\nSee https://github.com/boto/boto")
 
 
+def parse_ts_extended(ts):
+    RFC1123 = '%a, %d %b %Y %H:%M:%S %Z'
+    rv = None
+    try:
+        rv = parse_ts(ts)
+    except ValueError:
+        rv = datetime.datetime.strptime(ts, RFC1123)
+    return rv
+
+
 def safe_join(base, *paths):
     """
     A version of django.utils._os.safe_join for S3 paths.
         'application/x-javascript',
     ))
     url_protocol = setting('AWS_S3_URL_PROTOCOL', 'http:')
+    host = setting('AWS_S3_HOST', S3Connection.DefaultHost)
+    use_ssl = setting('AWS_S3_USE_SSL', True)
+    port = setting('AWS_S3_PORT', None)
 
     def __init__(self, acl=None, bucket=None, **settings):
         # check if some of the settings we've provided as class attributes
         # need to be overwritten with values passed in here
         for name, value in settings.items():
-            if name in self.__dict__:
+            if hasattr(self, name):
                 setattr(self, name, value)
 
         # For backward-compatibility of old differing parameter names
     def connection(self):
         if self._connection is None:
             self._connection = self.connection_class(
-                self.access_key, self.secret_key,
-                calling_format=self.calling_format)
+                self.access_key,
+                self.secret_key,
+                is_secure=self.use_ssl,
+                calling_format=self.calling_format,
+                host=self.host,
+                port=self.port,
+            )
         return self._connection
 
     @property
         if entry is None:
             entry = self.bucket.get_key(self._encode_name(name))
         # Parse the last_modified string to a local datetime object.
-        return parse_ts(entry.last_modified)
+        return parse_ts_extended(entry.last_modified)
 
     def url(self, name):
         name = self._normalize_name(self._clean_name(name))

storages/backends/sftpstorage.py

 # set "~/.ssh/known_hosts" will be used
 
 
+import getpass
 import os
-import stat
 import paramiko
 import posixpath
-import getpass
+import stat
+import urlparse
 from datetime import datetime
+
 from django.conf import settings
+from django.core.files.base import File
 from django.core.files.storage import Storage
-from django.core.files.base import File
+
 try:
     from cStringIO import StringIO
 except ImportError:
-    from StringIO import StringIO
+    from StringIO import StringIO  # noqa
+
 
 class SFTPStorage(Storage):
 
         self._known_host_file = getattr(settings, 'SFTP_KNOWN_HOST_FILE', None)
 
         self._root_path = settings.SFTP_STORAGE_ROOT
+        self._base_url = settings.MEDIA_URL
 
         # for now it's all posix paths.  Maybe someday we'll support figuring
         # out if the remote host is windows.
         return datetime.fromtimestamp(utime)
 
     def url(self, name):
-        remote_path = self._remote_path(name)
-        return 'sftp://%s/%s' % (self._host, remote_path)
+        if self._base_url is None:
+            raise ValueError("This file is not accessible via a URL.")
+        return urlparse.urljoin(self._base_url, name).replace('\\', '/')
+
 
 class SFTPStorageFile(File):
     def __init__(self, name, storage, mode):

storages/tests/s3boto.py

 import mock
 from uuid import uuid4
 from urllib2 import urlopen
+import datetime
 
 from django.test import TestCase
 from django.core.files.base import ContentFile
 from storages.backends import s3boto
 
 __all__ = (
+    'ParseTsExtendedCase',
     'SafeJoinTest',
     'S3BotoStorageTests',
     #'S3BotoStorageFileTests',
 )
 
+class ParseTsExtendedCase(TestCase):
+    def test_normal(self):
+        value = s3boto.parse_ts_extended("Wed, 13 Mar 2013 12:45:49 GMT")
+        self.assertEquals(value, datetime.datetime(2013, 3, 13, 12, 45, 49))
+
 class S3BotoTestCase(TestCase):
     @mock.patch('storages.backends.s3boto.S3Connection')
     def setUp(self, S3Connection):
 # content of: tox.ini , put in same dir as setup.py
 [tox]
-envlist = django11,django12,django13,django14
+envlist = dev,django11,django12,django13,django14
 
 [base]
 deps =
 [testenv]
 commands=python setup.py test
 
+[testenv:dev]
+deps=
+    mock==1.0.1
+    -egit://github.com/boto/boto.git@develop#egg=boto
+    -egit://github.com/django/django.git#egg=django
+
 [testenv:django11]
 deps=
     django==1.1.4
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.