Commits

Michael Elsdörfer committed b5062c7

Make all storages available via direct import from top-level module.

Comments (0)

Files changed (8)

django_storages/DatabaseStorage.py

 
 import pyodbc
 
+
+__all__ = ('DatabaseStorage',)
+
+
 class DatabaseStorage(Storage):
     """
-    Class DatabaseStorage provides storing files in the database. 
+    Class DatabaseStorage provides storing files in the database.
     """
 
     def __init__(self, option=settings.DB_FILES):
-        """Constructor. 
-        
+        """Constructor.
+
         Constructs object using dictionary either specified in contucotr or
-in settings.DB_FILES. 
-        
+in settings.DB_FILES.
+
         @param option dictionary with 'db_table', 'fname_column',
-'blob_column', 'size_column', 'base_url'  keys. 
-        
+'blob_column', 'size_column', 'base_url'  keys.
+
         option['db_table']
             Table to work with.
         option['fname_column']
             Column in the 'db_table' containing filenames (filenames can
 contain pathes). Values should be the same as where FileField keeps
-filenames. 
+filenames.
             It is used to map filename to blob_column. In sql it's simply
-used in where clause. 
+used in where clause.
         option['blob_column']
             Blob column (for example 'image' type), created manually in the
 'db_table', used to store image.
 method (another way is to open file and get size)
         option['base_url']
             Url prefix used with filenames. Should be mapped to the view,
-that returns an image as result. 
+that returns an image as result.
         """
-        
+
         if not option or not (option.has_key('db_table') and option.has_key('fname_column') and option.has_key('blob_column')
                               and option.has_key('size_column') and option.has_key('base_url') ):
             raise ValueError("You didn't specify required options")
         self.DATABASE_USER = settings.DATABASE_USER
         self.DATABASE_PASSWORD = settings.DATABASE_PASSWORD
         self.DATABASE_HOST = settings.DATABASE_HOST
-        
+
         self.connection = pyodbc.connect('DRIVER=%s;SERVER=%s;DATABASE=%s;UID=%s;PWD=%s'%(self.DATABASE_ODBC_DRIVER,self.DATABASE_HOST,self.DATABASE_NAME,
                                                                                           self.DATABASE_USER, self.DATABASE_PASSWORD) )
         self.cursor = self.connection.cursor()
 
     def _open(self, name, mode='rb'):
-        """Open a file from database. 
-        
+        """Open a file from database.
+
         @param name filename or relative path to file based on base_url. path should contain only "/", but not "\". Apache sends pathes with "/".
         If there is no such file in the db, returs None
         """
-        
+
         assert mode == 'rb', "You've tried to open binary file without specifying binary mode! You specified: %s"%mode
 
         row = self.cursor.execute("SELECT %s from %s where %s = '%s'"%(self.blob_column,self.db_table,self.fname_column,name) ).fetchone()
         inMemFile = StringIO.StringIO(row[0])
         inMemFile.name = name
         inMemFile.mode = mode
-        
+
         retFile = File(inMemFile)
         return retFile
 
     def _save(self, name, content):
         """Save 'content' as file named 'name'.
-        
-        @note '\' in path will be converted to '/'. 
+
+        @note '\' in path will be converted to '/'.
         """
-        
+
         name = name.replace('\\', '/')
         binary = pyodbc.Binary(content.read())
         size = len(binary)
-        
+
         #todo: check result and do something (exception?) if failed.
         if self.exists(name):
-            self.cursor.execute("UPDATE %s SET %s = ?, %s = ? WHERE %s = '%s'"%(self.db_table,self.blob_column,self.size_column,self.fname_column,name), 
+            self.cursor.execute("UPDATE %s SET %s = ?, %s = ? WHERE %s = '%s'"%(self.db_table,self.blob_column,self.size_column,self.fname_column,name),
                                  (binary, size)  )
         else:
             self.cursor.execute("INSERT INTO %s VALUES(?, ?, ?)"%(self.db_table), (name, binary, size)  )
     def exists(self, name):
         row = self.cursor.execute("SELECT %s from %s where %s = '%s'"%(self.fname_column,self.db_table,self.fname_column,name)).fetchone()
         return row is not None
-    
+
     def get_available_name(self, name):
         return name
 
         if self.base_url is None:
             raise ValueError("This file is not accessible via a URL.")
         return urlparse.urljoin(self.base_url, name).replace('\\', '/')
-    
+
     def size(self, name):
         row = self.cursor.execute("SELECT %s from %s where %s = '%s'"%(self.size_column,self.db_table,self.fname_column,name)).fetchone()
         if row is None:

django_storages/FTPStorage.py

 from django.core.files.base import File
 from django.core.files.storage import Storage
 
+
+__all__ = ('FTPStorage',)
+
+
 class FTPStorageException(Exception): pass
 
 class FTPStorage(Storage):
         """Return splitted configuration data from location."""
         splitted_url = urlparse.urlparse(location)
         config = {}
-        
+
         if splitted_url.scheme not in ('ftp', 'aftp'):
             raise ImproperlyConfigured('FTPStorage works only with FTP protocol!')
         if splitted_url.hostname == '':
             raise ImproperlyConfigured('You must at least provide hostname!')
-            
+
         if splitted_url.scheme == 'aftp':
             config['active'] = True
         else:
         config['user'] = splitted_url.username
         config['passwd'] = splitted_url.password
         config['port'] = int(splitted_url.port)
-        
+
         return config
 
     def _start_connection(self):
                 self._connection.pwd()
             except ftplib.all_errors, e:
                 self._connection = None
-        
+
         # Real reconnect
         if self._connection is None:
             ftp = ftplib.FTP()
                     self._connection.mkd(path_part)
                     self._connection.cwd(path_part)
                 except ftplib.all_errors, e:
-                    raise FTPStorageException('Cannot create directory chain %s' % path)                    
+                    raise FTPStorageException('Cannot create directory chain %s' % path)
         self._connection.cwd(pwd)
         return
 
             return memory_file
         except ftplib.all_errors, e:
             raise FTPStorageException('Error reading file %s' % name)
-        
+
     def _save(self, name, content):
         content.open()
         if hasattr(content, 'chunks'):
         try:
             self._connection.delete(name)
         except ftplib.all_errors, e:
-            raise FTPStorageException('Error when removing %s' % name)                 
+            raise FTPStorageException('Error when removing %s' % name)
 
     def exists(self, name):
         self._start_connection()
         except ftplib.error_temp, e:
             return False
         except ftplib.all_errors, e:
-            raise FTPStorageException('Error when testing existence of %s' % name)            
+            raise FTPStorageException('Error when testing existence of %s' % name)
 
     def size(self, name):
         self._start_connection()
         self._is_dirty = False
         self.file = StringIO()
         self._is_read = False
-    
+
     @property
     def size(self):
         if not hasattr(self, '_size'):
             self.file = self._storage._read(self._name)
             self._storage._end_connection()
             self._is_read = True
-            
+
         return self.file.read(num_bytes)
 
     def write(self, content):

django_storages/ImageStorage.py

 from django.core.files.storage import FileSystemStorage
 
 
+__all__ = ('ImageStorage',)
+
+
 class ImageStorage(FileSystemStorage):
     """
     A FileSystemStorage which normalizes extensions for images.
-    
+
     Comes from http://www.djangosnippets.org/snippets/965/
     """
-    
+
     def find_extension(self, format):
         """Normalizes PIL-returned format into a standard, lowercase extension."""
         format = format.lower()
-        
+
         if format == 'jpeg':
             format = 'jpg'
-        
+
         return format
-    
+
     def save(self, name, content):
         dirname = os.path.dirname(name)
         basename = os.path.basename(name)
-        
+
         # Use PIL to determine filetype
-        
+
         p = PILImageFile.Parser()
         while 1:
             data = content.read(1024)
             if p.image:
                 im = p.image
                 break
-        
+
         extension = self.find_extension(im.format)
-        
+
         # Does the basename already have an extension? If so, replace it.
         # bare as in without extension
         bare_basename = basename if '.' not in basename else basename[:basename.rindex('.')]
         basename = bare_basename + '.' + extension
-        
+
         name = os.path.join(dirname, basename)
         return super(ImageStorage, self).save(name, content)
-    
+

django_storages/MogileFSStorage.py

 import mogilefs
 
 
+__all__ = ('MogileFSStorage',)
+
+
 class MogileFSStorage(Storage):
     """MogileFS filesystem storage"""
     def __init__(self, base_url=settings.MEDIA_URL):
-        
+
         # the MOGILEFS_MEDIA_URL overrides MEDIA_URL
         if hasattr(settings, 'MOGILEFS_MEDIA_URL'):
             self.base_url = settings.MOGILEFS_MEDIA_URL
         else:
             self.base_url = base_url
-                
+
         for var in ('MOGILEFS_TRACKERS', 'MOGILEFS_DOMAIN',):
             if not hasattr(settings, var):
                 raise ImproperlyConfigured, "You must define %s to use the MogileFS backend." % var
-            
+
         self.trackers = settings.MOGILEFS_TRACKERS
         self.domain = settings.MOGILEFS_DOMAIN
         self.client = mogilefs.Client(self.domain, self.trackers)
-    
+
     def get_mogile_paths(self, filename):
-        return self.client.get_paths(filename)  
-    
+        return self.client.get_paths(filename)
+
     # The following methods define the Backend API
 
     def filesize(self, filename):
         raise NotImplemented
         #return os.path.getsize(self._get_absolute_path(filename))
-    
+
     def path(self, filename):
         paths = self.get_mogile_paths(filename)
         if paths:
             return self.get_mogile_paths(filename)[0]
         else:
             return None
-    
+
     def url(self, filename):
         return urlparse.urljoin(self.base_url, filename).replace('\\', '/')
 
 
     def save(self, filename, raw_contents):
         filename = self.get_available_filename(filename)
-        
+
         if not hasattr(self, 'mogile_class'):
             self.mogile_class = None
 
         return force_unicode(filename.replace('\\', '/'))
 
     def delete(self, filename):
-        
+
         self.client.delete(filename)
-            
-        
+
+
 def serve_mogilefs_file(request, key=None):
     """
     Called when a user requests an image.
     client = mogilefs.Client(settings.MOGILEFS_DOMAIN, settings.MOGILEFS_TRACKERS)
     if hasattr(settings, "SERVE_WITH_PERLBAL") and settings.SERVE_WITH_PERLBAL:
         # we're reproxying with perlbal
-        
+
         # check the path cache
-        
+
         path = cache.get(key)
 
         if not path:
             path = client.get_paths(key)
             cache.set(key, path, 60)
-    
+
         if path:
             response = HttpResponse(content_type=mimetype)
             response['X-REPROXY-URL'] = path[0]
         else:
             response = HttpResponseNotFound()
-    
+
     else:
         # we don't have perlbal, let's just serve the image via django
         file_data = client[key]
             response = HttpResponse(file_data, mimetype=mimetype)
         else:
             response = HttpResponseNotFound()
-    
+
     return response

django_storages/OverwriteStorage.py

 from django.conf import settings
 from django.core.files.storage import FileSystemStorage
 
+
+__all__ = ('OverwriteStorage',)
+
+
 class OverwriteStorage(FileSystemStorage):
-    
+
     def get_available_name(self, name):
         """
         Returns a filename that's free on the target storage system, and
         available for new content to be written to.
-        
+
         Comes from http://www.djangosnippets.org/snippets/976/
         (even if it already exists in S3Storage for ages)
         """

django_storages/S3BotoStorage.py

 from django.core.files.storage import Storage
 from django.utils.functional import curry
 
+
+__all__ = ('S3BotoStorage',)
+
+
 ACCESS_KEY_NAME = 'AWS_ACCESS_KEY_ID'
 SECRET_KEY_NAME = 'AWS_SECRET_ACCESS_KEY'
 AWS_HEADERS     = 'AWS_HEADERS'
 
 class S3BotoStorage(Storage):
     """Amazon Simple Storage Service using Boto"""
-    
+
     def __init__(self, bucket="root", bucketprefix=AWS_BUCKET_PREFIX, access_key=None, secret_key=None, acl='public-read'):
         self.acl = acl
-        
+
         if not access_key and not secret_key:
              access_key, secret_key = self._get_access_keys()
-        
+
         self.connection = S3Connection(access_key, secret_key)
         self.bucket = self.connection.create_bucket(bucketprefix + bucket)
         self.headers = getattr(settings, AWS_HEADERS, {})
-    
+
     def _get_access_keys(self):
         access_key = getattr(settings, ACCESS_KEY_NAME, None)
         secret_key = getattr(settings, SECRET_KEY_NAME, None)
         if (access_key or secret_key) and (not access_key or not secret_key):
             access_key = os.environ.get(ACCESS_KEY_NAME)
             secret_key = os.environ.get(SECRET_KEY_NAME)
-        
+
         if access_key and secret_key:
             # Both were provided, so use them
             return access_key, secret_key
-        
+
         return None, None
-    
+
     def _open(self, name, mode='rb'):
         return S3BotoStorageFile(name, mode, self)
-    
+
     def _save(self, name, content):
         k = self.bucket.get_key(name)
         if not k:
             k = self.bucket.new_key(name)
         k.set_contents_from_file(content)
         return name
-    
+
     def delete(self, name):
         self.bucket.delete_key(name)
-    
+
     def exists(self, name):
         k = Key(self.bucket, name)
         return k.exists()
-    
+
     def listdir(self, name):
         return [l.name for l in self.bucket.list() if not len(name) or l.name[:len(name)] == name]
-    
+
     def size(self, name):
         return self.bucket.get_key(name).size
-    
+
     def url(self, name):
         return self.bucket.get_key(name).generate_url(3600, method='GET')
-    
+
     def get_available_name(self, name):
         """ Overwrite existing file with the same name. """
         return name
         self._name = name
         self._mode = mode
         self.key = storage.bucket.get_key(name)
-    
+
     def size(self):
         return self.key.size
-    
+
     def read(self, *args, **kwargs):
         return self.key.read(*args, **kwargs)
-    
+
     def write(self, content):
         self.key.set_contents_from_string(content)
-    
+
     def close(self):
         self.key.close()
 

django_storages/S3Storage.py

 from django.core.files.storage import Storage
 from django.utils.functional import curry
 
+
+__all__ = ('S3Storage',)
+
+
 ACCESS_KEY_NAME = 'AWS_ACCESS_KEY_ID'
 SECRET_KEY_NAME = 'AWS_SECRET_ACCESS_KEY'
 HEADERS = 'AWS_HEADERS'
 class S3Storage(Storage):
     """Amazon Simple Storage Service"""
 
-    def __init__(self, bucket=settings.AWS_STORAGE_BUCKET_NAME, 
-            access_key=None, secret_key=None, acl=DEFAULT_ACL, 
+    def __init__(self, bucket=settings.AWS_STORAGE_BUCKET_NAME,
+            access_key=None, secret_key=None, acl=DEFAULT_ACL,
             calling_format=settings.AWS_CALLING_FORMAT):
         self.bucket = bucket
         self.acl = acl
         if not access_key and not secret_key:
              access_key, secret_key = self._get_access_keys()
 
-        self.connection = AWSAuthConnection(access_key, secret_key, 
+        self.connection = AWSAuthConnection(access_key, secret_key,
                             calling_format=calling_format)
-        self.generator = QueryStringAuthGenerator(access_key, secret_key, 
+        self.generator = QueryStringAuthGenerator(access_key, secret_key,
                             calling_format=calling_format, is_secure=False)
         self.generator.set_expires_in(QUERYSTRING_EXPIRE)
-        
+
         self.headers = getattr(settings, HEADERS, {})
 
     def _get_access_keys(self):
             raise IOError("S3StorageError: %s" % response.message)
         headers = response.http_response.msg
         return response.object.data, headers.get('etag', None), headers.get('content-range', None)
-        
+
     def _save(self, name, content):
         content.open()
         if hasattr(content, 'chunks'):
             content_str = content.read()
         self._put_file(name, content_str)
         return name
-    
+
     def delete(self, name):
         response = self.connection.delete(self.bucket, name)
         if response.http_response.status != 204:
         response = self.connection._make_request('HEAD', self.bucket, name)
         content_length = response.getheader('Content-Length')
         return content_length and int(content_length) or 0
-    
+
     def url(self, name):
         if QUERYSTRING_ACTIVE:
             return self.generator.generate_url('GET', self.bucket, name)
         self._is_dirty = False
         self.file = StringIO()
         self.start_range = 0
-    
+
     @property
     def size(self):
         if not hasattr(self, '_size'):

django_storages/__init__.py

+from S3Storage import *
+from S3BotoStorage import *
+from OverwriteStorage import *
+from MogileFSStorage import *
+from ImageStorage import *
+from FTPStorage import *
+from DatabaseStorage import *