Skip to content

Commit da87d45

Browse files
AddisonSchillerfelliott
authored andcommitted
Add renderer/exporter names to cached files
* Allow for more targeted cache cleaning by indicating the renderer or exporter that generated the cache file. [SVCS-159]
1 parent 9ac539b commit da87d45

File tree

4 files changed

+85
-2
lines changed

4 files changed

+85
-2
lines changed

mfr/core/utils.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import pkg_resources
12
from stevedore import driver
23

34
from mfr.core import exceptions
@@ -97,6 +98,46 @@ def make_renderer(name, metadata, file_path, url, assets_url, export_url):
9798
}
9899
)
99100

101+
def get_renderer_name(name):
102+
""" Return the name of the renderer used for a certain file extension.
103+
104+
:param str name: The name of the extension to get the renderer name for. (.jpg, .docx, etc)
105+
106+
:rtype : `str`
107+
"""
108+
109+
# This can give back empty tuples
110+
try:
111+
entry_attrs = pkg_resources.iter_entry_points(group='mfr.renderers', name=name)
112+
113+
# ep.attrs is a tuple of attributes. There should only ever be one or `None`.
114+
# None case occurs when trying to render an unsupported file type
115+
# entry_attrs is an iterable object, so we turn into a list to index it
116+
return list(entry_attrs)[0].attrs[0]
117+
118+
# This means the file type is not supported. Just return the blank string so `make_renderers`
119+
# can log a real exception with all the variables and names it has
120+
except IndexError:
121+
return ''
122+
123+
def get_exporter_name(name):
124+
""" Return the name of the exporter used for a certain file extension.
125+
126+
:param str name: The name of the extension to get the exporter name for. (.jpg, .docx, etc)
127+
128+
:rtype : `str`
129+
"""
130+
131+
# `make_renderer` should have already caught if an extension doesn't exist.
132+
133+
# should be a list of length one, since we don't have multiple entrypoints per group
134+
entry_attrs = pkg_resources.iter_entry_points(group='mfr.exporters', name=name)
135+
136+
# ep.attrs is a tuple of attributes. There should only ever be one or `None`.
137+
# For our case however there shouldn't be `None`
138+
return list(entry_attrs)[0].attrs[0]
139+
140+
100141
def sizeof_fmt(num, suffix='B'):
101142
if abs(num) < 1000:
102143
return '%3.0f%s' % (num, suffix)

mfr/server/handlers/export.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,12 @@ async def prepare(self):
2929
" appropriate extension")
3030
# TODO: do we need to catch exceptions for decoding?
3131
self.format = format[0].decode('utf-8')
32+
self.exporter_name = utils.get_exporter_name(self.metadata.ext)
3233

3334
self.cache_file_id = '{}.{}'.format(self.metadata.unique_key, self.format)
3435

3536
self.cache_file_path = await self.cache_provider.validate_path(
36-
'/export/{}'.format(self.cache_file_id)
37+
'/export/{}.{}'.format(self.cache_file_id, self.exporter_name)
3738
)
3839
self.source_file_path = await self.local_cache_provider.validate_path(
3940
'/export/{}'.format(self.source_file_id)

mfr/server/handlers/render.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ async def prepare(self):
2424

2525
await super().prepare()
2626

27+
self.renderer_name = utils.get_renderer_name(self.metadata.ext)
28+
2729
self.cache_file_id = self.metadata.unique_key
2830
self.cache_file_path = await self.cache_provider.validate_path(
29-
'/render/{}'.format(self.cache_file_id)
31+
'/render/{}.{}'.format(self.cache_file_id, self.renderer_name)
3032
)
3133
self.source_file_path = await self.local_cache_provider.validate_path(
3234
'/render/{}'.format(self.source_file_id)

tests/core/test_utils.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import pytest
2+
import pkg_resources
3+
4+
from mfr.core import utils as mfr_utils
5+
6+
7+
class TestGetRendererName:
8+
9+
def test_get_renderer_name_explicit_assertions(self):
10+
assert mfr_utils.get_renderer_name('.jpg') == 'ImageRenderer'
11+
assert mfr_utils.get_renderer_name('.txt') == 'CodePygmentsRenderer'
12+
assert mfr_utils.get_renderer_name('.xlsx') == 'TabularRenderer'
13+
assert mfr_utils.get_renderer_name('.odt') == 'UnoconvRenderer'
14+
assert mfr_utils.get_renderer_name('.pdf') == 'PdfRenderer'
15+
16+
def test_get_renderer_name(self):
17+
entry_points = pkg_resources.iter_entry_points(group='mfr.renderers')
18+
for ep in entry_points:
19+
expected = ep.attrs[0]
20+
assert mfr_utils.get_renderer_name(ep.name) == expected
21+
22+
def test_get_renderer_name_no_entry_point(self):
23+
assert mfr_utils.get_renderer_name('jpg') == ''
24+
25+
class TestGetExporterName:
26+
27+
def test_get_exporter_name_explicit_assertions(self):
28+
assert mfr_utils.get_exporter_name('.jpg') == 'ImageExporter'
29+
assert mfr_utils.get_exporter_name('.odt') == 'UnoconvExporter'
30+
31+
def test_get_exporter_name(self):
32+
entry_points = pkg_resources.iter_entry_points(group='mfr.exporters')
33+
for ep in entry_points:
34+
expected = ep.attrs[0]
35+
assert mfr_utils.get_exporter_name(ep.name) == expected
36+
37+
def test_get_exporter_name_no_entry_point(self):
38+
with pytest.raises(IndexError):
39+
mfr_utils.get_exporter_name('jpg')

0 commit comments

Comments
 (0)