From f4e5c6a7376cc4e309a87ed4261e0aa0e5a92131 Mon Sep 17 00:00:00 2001 From: Bernardo Heynemann Date: Sun, 30 Jan 2022 00:19:38 -0300 Subject: [PATCH] Lint fixes --- tests/test_context.py | 16 ++++++---------- thumbor/context.py | 19 ++++++++++++++---- thumbor/engines/pil.py | 33 ++++++++++++++++++++++++++++---- thumbor/error_handlers/sentry.py | 5 +++-- thumbor/optimizers/__init__.py | 8 ++++---- thumbor/server.py | 13 ++++++++++--- 6 files changed, 67 insertions(+), 27 deletions(-) diff --git a/tests/test_context.py b/tests/test_context.py index a99ddc871..29a0dc573 100644 --- a/tests/test_context.py +++ b/tests/test_context.py @@ -125,10 +125,8 @@ def test_can_create_server_parameters(): expect(params.log_level).to_equal("debug") expect(params.app_class).to_equal("app") expect( - params._security_key - ).to_equal( # pylint: disable=protected-access - "SECURITY_KEY_FILE" - ) + params._security_key # pylint: disable=protected-access + ).to_equal("SECURITY_KEY_FILE") expect(params.fd).to_equal("fd") expect(params.gifsicle_path).to_equal("gifsicle_path") @@ -149,10 +147,8 @@ def test_can_set_security_key(): params.security_key = "testé" expect( - params._security_key - ).to_equal( # pylint: disable=protected-access - "testé".encode("utf-8") - ) + params._security_key # pylint: disable=protected-access + ).to_equal("testé".encode("utf-8")) @staticmethod def test_loading_does_nothing_if_no_keyfile(): @@ -167,8 +163,8 @@ def test_loading_does_nothing_if_no_keyfile(): gifsicle_path="gifsicle_path", ) expect( - params._security_key - ).to_be_null() # pylint: disable=protected-access + params._security_key # pylint: disable=protected-access + ).to_be_null() @staticmethod def test_cant_load_invalid_security_key_file(): diff --git a/thumbor/context.py b/thumbor/context.py index 87f53cae3..d8c3629fa 100644 --- a/thumbor/context.py +++ b/thumbor/context.py @@ -33,8 +33,10 @@ def __init__( ): self.server = server self.config = config + if importer: self.modules = ContextImporter(self, importer) + if importer.metrics: self.metrics = importer.metrics(config) else: @@ -89,8 +91,8 @@ def __init__( processes=1, ): self.port = port - self.ip = ( - ip # Other people may depend on this pylint: disable=invalid-name + self.ip = ( # Other people may depend on this pylint: disable=invalid-name + ip ) self.config_path = config_path self.keyfile = keyfile @@ -99,8 +101,8 @@ def __init__( self.debug = debug self._security_key = None self.load_security_key() - self.fd = ( - fd # Other people may depend on this pylint: disable=invalid-name + self.fd = ( # Other people may depend on this pylint: disable=invalid-name + fd ) self.gifsicle_path = gifsicle_path self.use_environment = use_environment @@ -119,6 +121,7 @@ def load_security_key(self): return path = abspath(self.keyfile) + if not exists(path): raise ValueError( ( @@ -172,6 +175,7 @@ def __init__( self.debug = bool(debug) self.meta = bool(meta) self.trim = trim + if trim is not None: trim_parts = trim.split(":") self.trim_pos = ( @@ -251,22 +255,27 @@ def __init__(self, context, importer): self.importer = importer self.engine = None + if importer.engine: self.engine = importer.engine(context) self.gif_engine = None + if importer.gif_engine: self.gif_engine = importer.gif_engine(context) self.storage = None + if importer.storage: self.storage = importer.storage(context) self.result_storage = None + if importer.result_storage: self.result_storage = importer.result_storage(context) self.upload_photo_storage = None + if importer.upload_photo_storage: self.upload_photo_storage = importer.upload_photo_storage(context) @@ -279,12 +288,14 @@ def __init__(self, context, importer): self.compatibility_legacy_loader = importer.compatibility_legacy_loader self.compatibility_legacy_storage = None + if importer.compatibility_legacy_storage is not None: self.compatibility_legacy_storage = ( importer.compatibility_legacy_storage(context) ) self.compatibility_legacy_result_storage = None + if importer.compatibility_legacy_result_storage is not None: self.compatibility_legacy_result_storage = ( importer.compatibility_legacy_result_storage(context) diff --git a/thumbor/engines/pil.py b/thumbor/engines/pil.py index b8d5942cb..2391b03af 100644 --- a/thumbor/engines/pil.py +++ b/thumbor/engines/pil.py @@ -40,6 +40,7 @@ ImageFile.LOAD_TRUNCATED_IMAGES = True DECOMPRESSION_BOMB_EXCEPTIONS = (Image.DecompressionBombWarning,) + if hasattr(Image, "DecompressionBombError"): DECOMPRESSION_BOMB_EXCEPTIONS += (Image.DecompressionBombError,) @@ -66,6 +67,7 @@ def gen_image(self, size, color): if color == "transparent": color = None img = Image.new("RGBA", size, color) + return img def create_image(self, buffer): @@ -73,12 +75,14 @@ def create_image(self, buffer): img = Image.open(BytesIO(buffer)) except DECOMPRESSION_BOMB_EXCEPTIONS as error: logger.warning("[PILEngine] create_image failed: %s", error) + return None self.icc_profile = img.info.get("icc_profile") self.exif = img.info.get("exif") self.original_mode = img.mode self.subsampling = JpegImagePlugin.get_sampling(img) + if self.subsampling == -1: # n/a for this file self.subsampling = None self.qtables = getattr(img, "quantization", None) @@ -88,10 +92,12 @@ def create_image(self, buffer): and self.extension == ".gif" ): frames = [] + for frame in ImageSequence.Iterator(img): frames.append(frame.convert("P")) img.seek(0) self.frame_count = len(frames) + return frames return img @@ -128,10 +134,12 @@ def resize(self, width, height): # Indexed color modes (such as 1 and P) will be forced to use a # nearest neighbor resampling algorithm. So we convert them to # RGB(A) mode before resizing to avoid nasty scaling artifacts. + if self.image.mode in ["1", "P"]: logger.debug( "converting image from 8-bit/1-bit palette to 32-bit RGB(A) for resize" ) + if self.image.mode == "1": target_mode = "RGB" else: @@ -153,6 +161,7 @@ def crop(self, left, top, right, bottom): def rotate(self, degrees): # PIL rotates counter clockwise + if degrees == 90: self.image = self.image.transpose(Image.ROTATE_90) elif degrees == 180: @@ -170,12 +179,16 @@ def flip_horizontally(self): def get_default_extension(self): # extension is not present => force JPEG or PNG + if self.image.mode in ["P", "RGBA", "LA"]: return ".png" + return ".jpeg" - # TODO: Refactor this - pylint: disable=too-many-statements,too-many-branches - def read(self, extension=None, quality=None): # NOQA + # TODO: Refactor this + def read( # noqa + self, extension=None, quality=None + ): # noqa pylint: disable=too-many-statements,too-many-branches # returns image buffer in byte format. img_buffer = BytesIO() @@ -183,6 +196,7 @@ def read(self, extension=None, quality=None): # NOQA # 1 and P mode images will be much smaller if converted back to # their original mode. So let's do that after resizing. Get $$. + if ( self.context.config.PILLOW_PRESERVE_INDEXED_MODE and requested_extension in [None, ".png", ".gif"] @@ -204,8 +218,10 @@ def read(self, extension=None, quality=None): # NOQA ext = requested_extension or self.get_default_extension() options = {"quality": quality} + if ext in (".jpg", ".jpeg"): options["optimize"] = True + if self.context.config.PROGRESSIVE_JPEG: # Can't simply set options['progressive'] to the value # of self.context.config.PROGRESSIVE_JPEG because save @@ -271,6 +287,7 @@ def read(self, extension=None, quality=None): # NOQA logger.debug("webp quality is 100, using lossless instead") options["lossless"] = True options.pop("quality") + if self.image.mode not in ["RGB", "RGBA"]: if self.image.mode == "P": mode = "RGBA" @@ -294,6 +311,7 @@ def read(self, extension=None, quality=None): # NOQA results = img_buffer.getvalue() img_buffer.close() self.extension = ext + return results def read_multiple(self, images, extension=None): @@ -328,9 +346,9 @@ def read_multiple(self, images, extension=None): command = ["gifsicle", "--colors", "256", tmp_file_path] - popen = Popen( + popen = Popen( # pylint: disable=consider-using-with command, stdout=PIPE - ) # pylint: disable=consider-using-with + ) pipe = popen.stdout pipe_output = pipe.read() pipe.close() @@ -355,6 +373,7 @@ def get_image_mode(self): def image_data_as_rgb(self, update_image=True): converted_image = self.image + if converted_image.mode not in ["RGB", "RGBA"]: if "A" in converted_image.mode: converted_image = converted_image.convert("RGBA") @@ -363,8 +382,10 @@ def image_data_as_rgb(self, update_image=True): converted_image = converted_image.convert(None) else: converted_image = converted_image.convert("RGB") + if update_image: self.image = converted_image + return converted_image.mode, converted_image.tobytes() def convert_to_grayscale(self, update_image=True, alpha=True): @@ -372,14 +393,17 @@ def convert_to_grayscale(self, update_image=True, alpha=True): image = self.image.convert("LA") else: image = self.image.convert("L") + if update_image: self.image = image + return image def has_transparency(self): has_transparency = ( "A" in self.image.mode or "transparency" in self.image.info ) + if has_transparency: # If the image has alpha channel, # we check for any pixels that are not opaque (255) @@ -387,6 +411,7 @@ def has_transparency(self): min(self.image.convert("RGBA").getchannel("A").getextrema()) < 255 ) + return has_transparency def paste(self, other_engine, pos, merge=True): diff --git a/thumbor/error_handlers/sentry.py b/thumbor/error_handlers/sentry.py index ff41907a0..df8643b85 100644 --- a/thumbor/error_handlers/sentry.py +++ b/thumbor/error_handlers/sentry.py @@ -27,6 +27,7 @@ def __init__(self, config): } env = config.get("SENTRY_ENVIRONMENT") + if env is not None: kwargs["environment"] = env @@ -34,9 +35,9 @@ def __init__(self, config): ignore_logger("thumbor") ignore_logger("tornado.access") - sentry_sdk.init( + sentry_sdk.init( # pylint: disable=abstract-class-instantiated **kwargs - ) # pylint: disable=abstract-class-instantiated + ) def handle_error(self, _, handler, exception): req = handler.request diff --git a/thumbor/optimizers/__init__.py b/thumbor/optimizers/__init__.py index 0cb3b552d..0533a65fd 100644 --- a/thumbor/optimizers/__init__.py +++ b/thumbor/optimizers/__init__.py @@ -26,12 +26,12 @@ def run_optimizer(self, image_extension, buffer): if not self.should_run(image_extension, buffer): return buffer - ifile = NamedTemporaryFile( + ifile = NamedTemporaryFile( # pylint: disable=consider-using-with delete=False - ) # pylint: disable=consider-using-with - ofile = NamedTemporaryFile( + ) + ofile = NamedTemporaryFile( # pylint: disable=consider-using-with delete=False - ) # pylint: disable=consider-using-with + ) try: ifile.write(buffer) ifile.close() diff --git a/thumbor/server.py b/thumbor/server.py index a69c68881..b266664c9 100644 --- a/thumbor/server.py +++ b/thumbor/server.py @@ -63,9 +63,12 @@ def get_importer(config): importer.import_modules() if importer.error_handler_class is not None: - importer.error_handler = importer.error_handler_class( - config - ) # pylint: disable=not-callable + importer.error_handler = ( + importer.error_handler_class( # pylint: disable=not-callable + config + ) + ) + return importer @@ -85,6 +88,7 @@ def validate_config(config, server_parameters): if config.USE_GIFSICLE_ENGINE: server_parameters.gifsicle_path = which("gifsicle") + if server_parameters.gifsicle_path is None: raise RuntimeError( "If using USE_GIFSICLE_ENGINE configuration to True," @@ -106,6 +110,7 @@ def run_server(application, context): if context.server.fd is not None: fd_number = get_as_integer(context.server.fd) + if fd_number is not None: # TODO: replace with socket.socket(fileno=fd_number) when we require Python>=3.7 sock = socket_from_fd( # pylint: disable=too-many-function-args @@ -125,11 +130,13 @@ def run_server(application, context): ) server.start(context.server.processes) + return server def main(arguments=None): """Runs thumbor server with the specified arguments.""" + if arguments is None: arguments = sys.argv[1:]