Skip to content

Commit

Permalink
fix: resolves #1443 - closes image when context cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
RaphaelVRossi committed Nov 17, 2023
1 parent e0d37c4 commit e76b238
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 12 deletions.
26 changes: 26 additions & 0 deletions tests/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
# Copyright (c) 2011 globo.com thumbor@googlegroups.com

from unittest import TestCase, mock
from os.path import abspath, dirname, join

from preggy import expect
from PIL._util import DeferredError

from thumbor.config import Config
from thumbor.context import (
Expand All @@ -24,6 +26,9 @@
from thumbor.importer import Importer
from thumbor.metrics.logger_metrics import Metrics

FIXTURES_PATH = abspath(join(dirname(__file__), "fixtures/"))
STORAGE_PATH = join(FIXTURES_PATH, "images")


class ContextTestCase(TestCase):
@staticmethod
Expand Down Expand Up @@ -103,6 +108,27 @@ def test_can_server_app_class_override_config():

expect(ctx.app_class).to_equal("server.app")

def test_should_cleanup_context(self):
cfg = Config()
importer = Importer(cfg)
importer.import_modules()

ctx = Context(config=cfg, importer=importer)
ctx.request = RequestParameters()
ctx.request.engine = ctx.modules.engine

with open(join(STORAGE_PATH, "1bit.png"), "rb") as image_file:
buffer = image_file.read()

ctx.modules.engine.load(buffer, "PNG")
expect(ctx.modules.engine.image).not_to_be_null()
expect(ctx.modules.engine.image.fp).not_to_be_null()

ctx.cleanup()

expect(ctx.modules.engine.image.fp).to_be_null()
expect(ctx.modules.engine.image.im).to_be_instance_of(DeferredError)


class ServerParametersTestCase(TestCase):
@staticmethod
Expand Down
13 changes: 11 additions & 2 deletions thumbor/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,17 @@ def __enter__(self):
return self

def __exit__(self, exception_type, value, traceback):
if self.modules:
if self.thread_pool:
self.thread_pool.cleanup()

self.cleanup()

def cleanup(self):
if hasattr(self, "modules") and self.modules:
self.modules.cleanup()

self.thread_pool.cleanup()
if hasattr(self, "request") and self.request.engine:
self.request.engine.cleanup()


class ServerParameters: # pylint: disable=too-many-instance-attributes
Expand Down Expand Up @@ -307,3 +314,5 @@ def __init__(self, context, importer):
def cleanup(self):
if self.engine:
self.engine.cleanup()
if self.gif_engine:
self.gif_engine.cleanup()
3 changes: 3 additions & 0 deletions thumbor/engines/gif.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,3 +172,6 @@ def convert_to_grayscale(self, update_image=True, alpha=True):
# gif have no exif data and thus can't be auto oriented
def reorientate(self, override_exif=True):
pass

def cleanup(self):
self.buffer = None
4 changes: 4 additions & 0 deletions thumbor/engines/pil.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,3 +599,7 @@ def strip_icc(self):

def strip_exif(self):
self.exif = None

def cleanup(self):
if self.image:
self.image.close()
11 changes: 1 addition & 10 deletions thumbor/handlers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,16 +672,7 @@ def _ensure_bytes(self, results):
return results

def _cleanup(self):
self.context.request_handler = None

if hasattr(self.context, "request"):
self.context.request.engine = None
self.context.modules = None
self.context.filters_factory = None
self.context.metrics = None
self.context.thread_pool = None
self.context.transformer = None
self.context = None # Handlers should not override __init__ pylint: disable=attribute-defined-outside-init
self.context.cleanup()

async def _write_results_to_client(self, results, content_type):
max_age = self.context.config.MAX_AGE
Expand Down

0 comments on commit e76b238

Please sign in to comment.