From 1788ed3741beeb36406dc6ba1e552836748f34ed Mon Sep 17 00:00:00 2001 From: NaveenKumarG-dev Date: Wed, 17 Jun 2026 10:21:10 +0530 Subject: [PATCH] gh-151575: Emit DeprecationWarning in mimetypes.guess_type() for file paths --- .../pending-removal-in-future.rst | 4 + Doc/library/mimetypes.rst | 9 +- Doc/whatsnew/3.16.rst | 7 ++ Lib/mimetypes.py | 15 ++- Lib/test/test_mimetypes.py | 91 +++++++++++++++++++ ...6-17-09-45-00.gh-issue-151575.mimetype.rst | 1 + 6 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-06-17-09-45-00.gh-issue-151575.mimetype.rst diff --git a/Doc/deprecations/pending-removal-in-future.rst b/Doc/deprecations/pending-removal-in-future.rst index 74f98d33a4b61f..b629abaea60e5b 100644 --- a/Doc/deprecations/pending-removal-in-future.rst +++ b/Doc/deprecations/pending-removal-in-future.rst @@ -75,6 +75,10 @@ although there is currently no date scheduled for their removal. * :mod:`mailbox`: Use of StringIO input and text mode is deprecated, use BytesIO and binary mode instead. +* :mod:`mimetypes`: Passing a file path (including path-like objects and bytes + paths) to :func:`~mimetypes.guess_type`. Use + :func:`~mimetypes.guess_file_type` instead. (:gh:`151575`) + * :mod:`os`: Calling :func:`os.register_at_fork` in a multi-threaded process. * :mod:`os.path`: :func:`os.path.commonprefix` is deprecated, use diff --git a/Doc/library/mimetypes.rst b/Doc/library/mimetypes.rst index 5c29fff146eef0..0659d0b3ec9375 100644 --- a/Doc/library/mimetypes.rst +++ b/Doc/library/mimetypes.rst @@ -54,9 +54,9 @@ the information :func:`init` sets up. .. versionchanged:: 3.8 Added support for *url* being a :term:`path-like object`. - .. soft-deprecated:: 3.13 - Passing a file path instead of URL. - Use :func:`guess_file_type` for this. + .. deprecated:: 3.16 + Passing a file path (or path-like object) instead of a URL. + Use :func:`guess_file_type` instead. .. function:: guess_file_type(path, *, strict=True) @@ -262,6 +262,9 @@ than one MIME-type database; it provides an interface similar to the one of the Similar to the :func:`guess_type` function, using the tables stored as part of the object. + .. deprecated:: 3.16 + Passing a file path (or path-like object) instead of a URL. + Use :meth:`guess_file_type` instead. .. method:: MimeTypes.guess_file_type(path, *, strict=True) diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 8e4c4a1e9b1de0..a8322f6233e02b 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -271,6 +271,13 @@ Deprecated 3.9, now issues a deprecation warning on use. This property is slated for removal in 3.21. Use ``ast.Tuple.elts`` instead. +* :mod:`mimetypes`: + + * Passing a file path (or :term:`path-like object`) to + :func:`mimetypes.guess_type` is now deprecated. + Use :func:`mimetypes.guess_file_type` instead. + (Contributed by Naveen Kumar G in :gh:`151575`.) + .. Add deprecations above alphabetically, not here at the end. .. include:: ../deprecations/pending-removal-in-3.17.rst diff --git a/Lib/mimetypes.py b/Lib/mimetypes.py index 4339ef5a61397d..c2c9245efaefa7 100644 --- a/Lib/mimetypes.py +++ b/Lib/mimetypes.py @@ -106,7 +106,11 @@ def add_type(self, type, ext, strict=True): exts.append(ext) def guess_type(self, url, strict=True): - """Guess the type of a file which is either a URL or a path-like object. + """Guess the type of a file based on its URL. + + .. deprecated:: 3.16 + Passing a file path (or path-like object) is deprecated. + Use :meth:`guess_file_type` instead. Return value is a tuple (type, encoding) where type is None if the type can't be guessed (no or unknown suffix) or a string @@ -127,14 +131,21 @@ def guess_type(self, url, strict=True): # Lazy import to improve module import time import os import urllib.parse + import warnings - # TODO: Deprecate accepting file paths (in particular path-like objects). url = os.fspath(url) p = urllib.parse.urlparse(url) if p.scheme and len(p.scheme) > 1: scheme = p.scheme url = p.path else: + # Input has no URL scheme — it is a file path, not a URL. + warnings.warn( + "Passing a file path to guess_type() is deprecated and will be " + "removed in a future version. Use guess_file_type() instead.", + DeprecationWarning, + stacklevel=2, + ) return self.guess_file_type(url, strict=strict) if scheme == 'data': # syntax of data URLs: diff --git a/Lib/test/test_mimetypes.py b/Lib/test/test_mimetypes.py index 19983fa3fa7628..c2e5c32203d8f8 100644 --- a/Lib/test/test_mimetypes.py +++ b/Lib/test/test_mimetypes.py @@ -1,9 +1,12 @@ import io import mimetypes import os +import pathlib import shlex import sys +import unittest import unittest.mock +import warnings from platform import win32_edition from test import support from test.support import cpython_only, force_not_colorized, os_helper, requires_subprocess @@ -489,6 +492,94 @@ def test_keywords_args_api(self): type='image/jpeg', strict=True), ['.jpg', '.jpe', '.jpeg']) +class GuessTypeDeprecationTestCase(unittest.TestCase): + """Tests that guess_type() emits DeprecationWarning for file path inputs.""" + + def setUp(self): + self.db = mimetypes.MimeTypes() + + # --- Module-level function tests --- + + def test_module_plain_string_path_warns(self): + """Module-level guess_type() warns for a plain string with no URL scheme.""" + with self.assertWarns(DeprecationWarning) as cm: + mimetypes.guess_type("file.txt") + self.assertIn("guess_file_type", str(cm.warning)) + self.assertIn("deprecated", str(cm.warning).lower()) + + def test_module_pathlike_warns(self): + """Module-level guess_type() warns for a path-like object.""" + with self.assertWarns(DeprecationWarning): + mimetypes.guess_type(pathlib.Path("file.txt")) + + def test_module_bytes_path_warns(self): + """Module-level guess_type() warns for a bytes path.""" + with self.assertWarns(DeprecationWarning): + mimetypes.guess_type(b"file.txt") + + def test_module_url_with_scheme_no_warning(self): + """Module-level guess_type() does NOT warn for a proper URL.""" + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + # Should not raise -- http:// is a valid multi-char scheme. + mimetypes.guess_type("http://example.com/file.html") + + def test_module_data_url_no_warning(self): + """Module-level guess_type() does NOT warn for data: URLs.""" + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + mimetypes.guess_type("data:text/plain,hello") + + # --- MimeTypes class method tests --- + + def test_method_plain_string_path_warns(self): + """MimeTypes.guess_type() warns for a plain string with no URL scheme.""" + with self.assertWarns(DeprecationWarning) as cm: + self.db.guess_type("file.html") + self.assertIn("guess_file_type", str(cm.warning)) + + def test_method_pathlike_warns(self): + """MimeTypes.guess_type() warns for a path-like object.""" + with self.assertWarns(DeprecationWarning): + self.db.guess_type(pathlib.Path("file.html")) + + def test_method_bytes_path_warns(self): + """MimeTypes.guess_type() warns for a bytes path.""" + with self.assertWarns(DeprecationWarning): + self.db.guess_type(b"file.html") + + def test_method_url_with_scheme_no_warning(self): + """MimeTypes.guess_type() does NOT warn for a proper URL.""" + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + self.db.guess_type("http://example.com/file.html") + + def test_method_ftp_url_no_warning(self): + """MimeTypes.guess_type() does NOT warn for an ftp: URL.""" + with warnings.catch_warnings(): + warnings.simplefilter("error", DeprecationWarning) + self.db.guess_type("ftp://example.com/file.tar.gz") + + def test_result_unchanged(self): + """guess_type() with a file path still returns the correct MIME type.""" + with self.assertWarns(DeprecationWarning): + result = mimetypes.guess_type("file.html") + expected = mimetypes.guess_file_type("file.html") + self.assertEqual(result, expected) + + def test_result_unchanged_pathlike(self): + """guess_type() with a PathLike still returns the correct MIME type.""" + with self.assertWarns(DeprecationWarning): + result = self.db.guess_type(pathlib.Path("file.tar.gz")) + expected = self.db.guess_file_type(pathlib.Path("file.tar.gz")) + self.assertEqual(result, expected) + + def test_os_helper_fakepath_warns(self): + """guess_type() warns for os_helper.FakePath (a path-like object).""" + with self.assertWarns(DeprecationWarning): + self.db.guess_type(os_helper.FakePath("file.tar.gz")) + + @unittest.skipUnless(sys.platform.startswith("win"), "Windows only") class Win32MimeTypesTestCase(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS.d/next/Library/2026-06-17-09-45-00.gh-issue-151575.mimetype.rst b/Misc/NEWS.d/next/Library/2026-06-17-09-45-00.gh-issue-151575.mimetype.rst new file mode 100644 index 00000000000000..f34b61e152a6fc --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-06-17-09-45-00.gh-issue-151575.mimetype.rst @@ -0,0 +1 @@ +Emit DeprecationWarning when a file path is passed to :func:`mimetypes.guess_type`. Use :func:`mimetypes.guess_file_type` instead.