Merge branch 'oom' into 'master'

Prevent Out Of Memory errors with image cache, fix #118

Closes #118 and #117

See merge request phyks/Flatisfy!26
This commit is contained in:
Phyks 2018-02-24 23:02:39 +01:00
commit 3855888bcb

View File

@ -5,6 +5,7 @@ Caching function for pictures.
from __future__ import absolute_import, print_function, unicode_literals from __future__ import absolute_import, print_function, unicode_literals
import collections
import hashlib import hashlib
import os import os
import requests import requests
@ -31,7 +32,7 @@ class MemoryCache(object):
def __init__(self): def __init__(self):
self.hits = 0 self.hits = 0
self.misses = 0 self.misses = 0
self.map = {} self.map = collections.OrderedDict()
def get(self, key): def get(self, key):
""" """
@ -99,24 +100,36 @@ class ImageCache(MemoryCache):
""" """
Helper to actually retrieve photos if not already cached. Helper to actually retrieve photos if not already cached.
""" """
# If two many items in the cache, pop one
if len(self.map.keys()) > self.max_items:
self.map.popitem(last=False)
# Try to load from local folder
if self.storage_dir:
filepath = os.path.join( filepath = os.path.join(
self.storage_dir, self.storage_dir,
self.compute_filename(url) self.compute_filename(url)
) )
if os.path.isfile(filepath): if os.path.isfile(filepath):
image = PIL.Image.open(filepath) return PIL.Image.open(filepath)
else: # Otherwise, fetch it
req = requests.get(url) req = requests.get(url)
try: try:
req.raise_for_status() req.raise_for_status()
image = PIL.Image.open(BytesIO(req.content)) image = PIL.Image.open(BytesIO(req.content))
if self.storage_dir: if self.storage_dir:
image.save(filepath, format=image.format) image.save(filepath, format=image.format)
return image
except (requests.HTTPError, IOError): except (requests.HTTPError, IOError):
return None return None
return image
def __init__(self, storage_dir=None): def __init__(self, max_items=200, storage_dir=None):
"""
:param max_items: Max number of items in the cache, to prevent Out Of
Memory errors.
:param storage_dir: Directory in which images should be stored.
"""
self.max_items = max_items
self.storage_dir = storage_dir self.storage_dir = storage_dir
if self.storage_dir and not os.path.isdir(self.storage_dir): if self.storage_dir and not os.path.isdir(self.storage_dir):
os.makedirs(self.storage_dir) os.makedirs(self.storage_dir)