From 0cab0b830da637984f46bfa4af246d3c9098eca0 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 13 Apr 2023 12:19:08 +0530 Subject: [PATCH] refactor: replace imghdr with filetype (#20680) * refactor: replace `imaghdr` with `filetype` ``` 11:52:06 worker.1 | /home/ankush/benches/develop/apps/frappe/frappe/core/doctype/file/utils.py:2: DeprecationWarning: 'imghdr' is deprecated and slated for removal in Python 3.13 ``` * feat: improved extension guessing using filecontent --- frappe/core/doctype/file/test_file.py | 8 ++++++++ frappe/core/doctype/file/utils.py | 10 ++++++---- frappe/oauth.py | 2 +- frappe/workflow/doctype/workflow/workflow.py | 2 +- pyproject.toml | 1 + 5 files changed, 17 insertions(+), 6 deletions(-) diff --git a/frappe/core/doctype/file/test_file.py b/frappe/core/doctype/file/test_file.py index 86bd69eb5f..57c9d9a11f 100644 --- a/frappe/core/doctype/file/test_file.py +++ b/frappe/core/doctype/file/test_file.py @@ -17,6 +17,7 @@ from frappe.core.api.file import ( move_file, unzip_file, ) +from frappe.core.doctype.file.utils import get_extension from frappe.exceptions import ValidationError from frappe.tests.utils import FrappeTestCase from frappe.utils import get_files_path @@ -739,3 +740,10 @@ class TestFileOptimization(FrappeTestCase): size_after_rollback = os.stat(image_path).st_size self.assertEqual(size_before_optimization, size_after_rollback) + + def test_image_header_guessing(self): + file_path = frappe.get_app_path("frappe", "tests/data/sample_image_for_optimization.jpg") + with open(file_path, "rb") as f: + file_content = f.read() + + self.assertEqual(get_extension("", None, file_content), "jpeg") diff --git a/frappe/core/doctype/file/utils.py b/frappe/core/doctype/file/utils.py index 17a092e340..1d0d145303 100644 --- a/frappe/core/doctype/file/utils.py +++ b/frappe/core/doctype/file/utils.py @@ -1,5 +1,4 @@ import hashlib -import imghdr import mimetypes import os import re @@ -7,6 +6,7 @@ from io import BytesIO from typing import TYPE_CHECKING, Optional from urllib.parse import unquote +import filetype import requests import requests.exceptions from PIL import Image @@ -76,9 +76,11 @@ def get_extension( mimetype = mimetypes.guess_type(filename + "." + extn)[0] - if mimetype is None or not mimetype.startswith("image/") and content: - # detect file extension by reading image header properties - extn = imghdr.what(filename + "." + (extn or ""), h=content) + if mimetype is None and extn is None and content: + # detect file extension by using filetype matchers + _type_info = filetype.match(content) + if _type_info: + extn = _type_info.extension return extn diff --git a/frappe/oauth.py b/frappe/oauth.py index 8955078342..2d25b5dfb5 100644 --- a/frappe/oauth.py +++ b/frappe/oauth.py @@ -3,7 +3,7 @@ import datetime import hashlib import re from http import cookies -from urllib.parse import unquote, urlparse, urljoin +from urllib.parse import unquote, urljoin, urlparse import jwt import pytz diff --git a/frappe/workflow/doctype/workflow/workflow.py b/frappe/workflow/doctype/workflow/workflow.py index 54c8c6f61b..018b567ee9 100644 --- a/frappe/workflow/doctype/workflow/workflow.py +++ b/frappe/workflow/doctype/workflow/workflow.py @@ -126,7 +126,7 @@ class Workflow(Document): @frappe.whitelist() def get_workflow_state_count(doctype, workflow_state_field, states): - frappe.has_permission(doctype=doctype, ptype='read', throw=True) + frappe.has_permission(doctype=doctype, ptype="read", throw=True) states = frappe.parse_json(states) result = frappe.get_all( doctype, diff --git a/pyproject.toml b/pyproject.toml index daa0748e5f..5429682a33 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,7 @@ dependencies = [ "Babel~=2.12.1", "Click~=8.1.3", "filelock~=3.8.0", + "filetype~=1.2.0", "GitPython~=3.1.30", "Jinja2~=3.1.2", "Pillow~=9.3.0",