Skip to content

Commit 273baed

Browse files
committed
Improve metadata mime type handling
1 parent 626a6ad commit 273baed

File tree

9 files changed

+53
-13
lines changed

9 files changed

+53
-13
lines changed

CHANGELOG.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ Changelog
44
Current
55
-------
66

7-
- Added ``copy`` and ``move`` operations
8-
- `delete` now supports directories (or prefixes for key/value stores)
7+
- Added ``copy()`` and ``move()`` operations
8+
- `delete()` now supports directories (or prefixes for key/value stores)
9+
- Improve `metadata()` `mime` handling
910

1011
0.5.1 (2018-03-12)
1112
------------------

flask_fs/backends/__init__.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
import six
55

6+
from flask_fs import files
7+
68
__all__ = [i.encode('ascii') for i in ('BaseBackend', 'DEFAULT_BACKEND')]
79

810

@@ -14,6 +16,7 @@ class BaseBackend(object):
1416
Abstract class to implement backend.
1517
'''
1618
root = None
19+
DEFAULT_MIME = 'application/octet-stream'
1720

1821
def __init__(self, name, config):
1922
self.name = name
@@ -66,6 +69,21 @@ def save(self, file_or_wfs, filename, overwrite=False):
6669
self.write(filename, file_or_wfs.read())
6770
return filename
6871

72+
def metadata(self, filename):
73+
'''
74+
Fetch all available metadata for a given file
75+
'''
76+
meta = self.get_metadata(filename)
77+
# Fix backend mime misdetection
78+
meta['mime'] = meta.get('mime') or files.mime(filename, self.DEFAULT_MIME)
79+
return meta
80+
81+
def get_metadata(self, filename):
82+
'''
83+
Backend specific method to retrieve metadata for a given file
84+
'''
85+
raise NotImplementedError('Copy operation is not implemented')
86+
6987
def serve(self, filename):
7088
'''Serve a file given its filename'''
7189
raise NotImplementedError('serve operation is not implemented')

flask_fs/backends/gridfs.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
from gridfs import GridFS
1313
from pymongo import MongoClient
1414

15-
from flask_fs import files
16-
1715
from . import BaseBackend
1816

1917
log = logging.getLogger(__name__)
@@ -75,11 +73,11 @@ def serve(self, filename):
7573
file = self.fs.get_last_version(filename)
7674
return send_file(file, mimetype=file.content_type)
7775

78-
def metadata(self, filename):
76+
def get_metadata(self, filename):
7977
f = self.fs.get_last_version(filename)
8078
return {
8179
'checksum': 'md5:{0}'.format(f.md5),
8280
'size': f.length,
83-
'mime': f.content_type or files.mime(filename),
81+
'mime': f.content_type,
8482
'modified': f.upload_date,
8583
}

flask_fs/backends/local.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ def serve(self, filename):
122122
'''Serve files for storages with direct file access'''
123123
return send_from_directory(self.root, filename)
124124

125-
def metadata(self, filename):
126-
'''Fetch all availabe metadata'''
125+
def get_metadata(self, filename):
126+
'''Fetch all available metadata'''
127127
dest = self.path(filename)
128128
with open(dest, 'rb', buffering=0) as f:
129129
checksum = 'sha1:{0}'.format(sha1(f))

flask_fs/backends/s3.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,15 @@ def list_files(self):
8686
for f in self.bucket.objects.all():
8787
yield f.key
8888

89-
def metadata(self, filename):
89+
def get_metadata(self, filename):
9090
'''Fetch all availabe metadata'''
9191
obj = self.bucket.Object(filename)
9292
checksum = 'md5:{0}'.format(obj.e_tag[1:-1])
93+
mime = obj.content_type.split(';', 1)[0] if obj.content_type else None
9394
return {
9495
'checksum': checksum,
9596
'size': obj.content_length,
96-
'mime': obj.content_type,
97+
'mime': mime,
9798
'modified': obj.last_modified,
9899
}
99100

flask_fs/backends/swift.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def list_files(self):
7575
for i in items:
7676
yield i['name']
7777

78-
def metadata(self, filename):
78+
def get_metadata(self, filename):
7979
data = self.conn.head_object(self.name, filename)
8080
return {
8181
'checksum': 'md5:{0}'.format(data['etag']),

flask_fs/files.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,11 @@ def lower_extension(filename):
6868
return filename
6969

7070

71-
def mime(filename):
71+
def mime(filename, default=None):
7272
'''
7373
A basic helper to guess mime type from a filename or url
7474
'''
75-
return mimetypes.guess_type(filename)[0]
75+
return mimetypes.guess_type(filename)[0] or default
7676

7777

7878
class All(object):

tests/test_backend_mixin.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,13 @@ def test_metadata(self, app, faker):
184184
assert metadata['mime'] == 'text/plain'
185185
assert isinstance(metadata['modified'], datetime)
186186

187+
def test_metadata_unknown_mime(self, app, faker):
188+
content = six.text_type(faker.sentence())
189+
self.put_file('file.whatever', content)
190+
191+
metadata = self.backend.metadata('file.whatever')
192+
assert metadata['mime'] in ('application/octet-stream', 'text/plain')
193+
187194
def test_copy(self, faker):
188195
content = faker.sentence()
189196
self.put_file('file.test', content)

tests/test_files.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,18 @@ def test_all_except():
3838
all_except = files.AllExcept('exe')
3939
assert 'csv' in all_except
4040
assert 'exe' not in all_except
41+
42+
43+
def test_mime_known_type():
44+
assert files.mime('test.txt') == 'text/plain'
45+
assert files.mime('test.csv') == 'text/csv'
46+
47+
48+
def test_mime_default_to_none():
49+
assert files.mime('test') is None
50+
assert files.mime('test', default=None) is None
51+
52+
53+
def test_mime_default_to_custom():
54+
default = 'application/octet-stream'
55+
assert files.mime('test', default=default) == default

0 commit comments

Comments
 (0)