Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
1788ed3
gh-151575: Emit DeprecationWarning in mimetypes.guess_type() for file…
NaveenKumarG-dev Jun 17, 2026
afd0726
Merge branch 'main' into gh-mimetypes-guess-type-deprecation
NaveenKumarG-dev Jun 17, 2026
9276f2c
feat: introduce MimeTypes class and deprecate file path support in gu…
NaveenKumarG-dev Jun 17, 2026
95c0ab0
Merge branch 'gh-mimetypes-guess-type-deprecation' of https://github.…
NaveenKumarG-dev Jun 17, 2026
dbe1247
Merge branch 'main' into gh-mimetypes-guess-type-deprecation
NaveenKumarG-dev Jun 17, 2026
89980ed
Merge branch 'main' into gh-mimetypes-guess-type-deprecation
NaveenKumarG-dev Jun 18, 2026
2c00715
Merge branch 'main' into gh-mimetypes-guess-type-deprecation
NaveenKumarG-dev Jun 18, 2026
1aba67d
feat: add guess_file_type to mimetypes module to support path-based M…
NaveenKumarG-dev Jun 28, 2026
2f7b8ed
test: add test suite for mimetypes module
NaveenKumarG-dev Jun 28, 2026
71871a5
Merge branch 'main' into gh-mimetypes-guess-type-deprecation
NaveenKumarG-dev Jun 28, 2026
c7a343d
Merge branch 'main' into gh-mimetypes-guess-type-deprecation
NaveenKumarG-dev Jun 29, 2026
d6ac72c
Merge branch 'main' into gh-mimetypes-guess-type-deprecation
NaveenKumarG-dev Jun 29, 2026
ec6e1da
Merge branch 'main' into gh-mimetypes-guess-type-deprecation
NaveenKumarG-dev Jul 6, 2026
4b8515d
Address PR feedback: fix mimetypes CLI, lazy imports, and doc depreca…
NaveenKumarG-dev Jul 30, 2026
36d97a7
Merge branch 'main' into gh-mimetypes-guess-type-deprecation
NaveenKumarG-dev Jul 30, 2026
e819067
Revert pre-commit adding newlines to mypy symlinks
NaveenKumarG-dev Jul 30, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Doc/deprecations/pending-removal-in-future.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 7 additions & 5 deletions Doc/library/mimetypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ the information :func:`init` sets up.

.. index:: pair: MIME; headers

Guess the type of a file based on its filename, path or URL, given by *url*.
URL can be a string or a :term:`path-like object`.
Guess the type of a file based on its URL, given as a string.

The return value is a tuple ``(type, encoding)`` where *type* is ``None`` if the
type can't be guessed (missing or unknown suffix) or a string of the form
Expand All @@ -54,9 +53,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-removed:: 3.16 3.21
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)
Expand Down Expand Up @@ -263,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-removed:: 3.16 3.21
Passing a file path (or path-like object) instead of a URL.
Use :func:`guess_file_type` instead.

.. method:: MimeTypes.guess_file_type(path, *, strict=True)

Expand Down
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.16.rst
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,13 @@ New deprecations
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`.)

* :mod:`struct`:

* Soft-deprecated since Python 3.15, using ``'F'`` and ``'D'`` type codes are now
Expand Down
17 changes: 14 additions & 3 deletions Lib/mimetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ 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.

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
Expand All @@ -128,13 +128,19 @@ def guess_type(self, url, strict=True):
import os
import urllib.parse

# 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:
import warnings
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:
Expand Down Expand Up @@ -752,8 +758,13 @@ def _main(args=None):
results.append(f"error: unknown type {gtype}")
return results
else:
import urllib.parse
for gtype in args.type:
guess, encoding = guess_type(gtype, not args.lenient)
p = urllib.parse.urlparse(gtype)
if p.scheme and len(p.scheme) > 1:
guess, encoding = guess_type(gtype, strict=not args.lenient)
else:
guess, encoding = guess_file_type(gtype, strict=not args.lenient)
if guess:
results.append(f"type: {guess} encoding: {encoding}")
else:
Expand Down
46 changes: 30 additions & 16 deletions Lib/test/test_mimetypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import os
import shlex
import sys
import unittest
import unittest.mock

from platform import win32_edition
from test import support
from test.support import cpython_only, force_not_colorized, os_helper, requires_subprocess
Expand Down Expand Up @@ -232,14 +234,14 @@ def test_init_knownfiles(self):

def test_added_types_are_used(self):
mimetypes.add_type('testing/default-type', '')
mime_type, _ = mimetypes.guess_type('')
mime_type, _ = mimetypes.guess_file_type('')
self.assertEqual(mime_type, 'testing/default-type')

mime_type, _ = mimetypes.guess_type('test.myext')
mime_type, _ = mimetypes.guess_file_type('test.myext')
self.assertEqual(mime_type, None)

mimetypes.add_type('testing/type', '.myext')
mime_type, _ = mimetypes.guess_type('test.myext')
mime_type, _ = mimetypes.guess_file_type('test.myext')
self.assertEqual(mime_type, 'testing/type')

def test_add_type_with_undotted_extension_not_supported(self):
Expand Down Expand Up @@ -389,21 +391,26 @@ def test_filename_with_url_delimiters(self):
path = prefix + name
with self.subTest(path=path):
eq(self.db.guess_file_type(path), gzip_expected)
eq(self.db.guess_type(path), gzip_expected)
with self.assertWarns(DeprecationWarning):
eq(self.db.guess_type(path), gzip_expected)
expected = (None, None) if os.name == 'nt' else gzip_expected
for prefix in ('//', '\\\\', '//share/', '\\\\share\\'):
path = prefix + name
with self.subTest(path=path):
eq(self.db.guess_file_type(path), expected)
eq(self.db.guess_type(path), expected)
with self.assertWarns(DeprecationWarning):
eq(self.db.guess_type(path), expected)
eq(self.db.guess_file_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected)
eq(self.db.guess_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected)
with self.assertWarns(DeprecationWarning):
eq(self.db.guess_type(r" \"\`;b&b&c |.tar.gz"), gzip_expected)

eq(self.db.guess_file_type(r'foo/.tar.gz'), (None, 'gzip'))
eq(self.db.guess_type(r'foo/.tar.gz'), (None, 'gzip'))
with self.assertWarns(DeprecationWarning):
eq(self.db.guess_type(r'foo/.tar.gz'), (None, 'gzip'))
expected = (None, 'gzip') if os.name == 'nt' else gzip_expected
eq(self.db.guess_file_type(r'foo\.tar.gz'), expected)
eq(self.db.guess_type(r'foo\.tar.gz'), expected)
with self.assertWarns(DeprecationWarning):
eq(self.db.guess_type(r'foo\.tar.gz'), expected)
eq(self.db.guess_type(r'scheme:foo\.tar.gz'), gzip_expected)

def test_url(self):
Expand Down Expand Up @@ -461,16 +468,20 @@ def test_path_like_ob(self):
expected = self.db.guess_file_type(filename)

self.assertEqual(self.db.guess_file_type(filepath), expected)
self.assertEqual(self.db.guess_type(filepath), expected)
with self.assertWarns(DeprecationWarning):
self.assertEqual(self.db.guess_type(filepath), expected)
self.assertEqual(self.db.guess_file_type(
filepath_with_abs_dir), expected)
self.assertEqual(self.db.guess_type(
filepath_with_abs_dir), expected)
with self.assertWarns(DeprecationWarning):
self.assertEqual(self.db.guess_type(
filepath_with_abs_dir), expected)
self.assertEqual(self.db.guess_file_type(filepath_relative), expected)
self.assertEqual(self.db.guess_type(filepath_relative), expected)
with self.assertWarns(DeprecationWarning):
self.assertEqual(self.db.guess_type(filepath_relative), expected)

self.assertEqual(self.db.guess_file_type(path_dir), (None, None))
self.assertEqual(self.db.guess_type(path_dir), (None, None))
with self.assertWarns(DeprecationWarning):
self.assertEqual(self.db.guess_type(path_dir), (None, None))

def test_bytes_path(self):
self.assertEqual(self.db.guess_file_type(b'foo.html'),
Expand All @@ -489,6 +500,9 @@ def test_keywords_args_api(self):
type='image/jpeg', strict=True), ['.jpg', '.jpe', '.jpeg'])





@unittest.skipUnless(sys.platform.startswith("win"), "Windows only")
class Win32MimeTypesTestCase(unittest.TestCase):
def setUp(self):
Expand All @@ -510,9 +524,9 @@ def test_registry_parsing(self):
# Windows registry is undocumented AFAIK.
# Use file types that should *always* exist:
eq = self.assertEqual
eq(self.db.guess_type("foo.txt"), ("text/plain", None))
eq(self.db.guess_type("image.jpg"), ("image/jpeg", None))
eq(self.db.guess_type("image.png"), ("image/png", None))
eq(self.db.guess_file_type("foo.txt"), ("text/plain", None))
eq(self.db.guess_file_type("image.jpg"), ("image/jpeg", None))
eq(self.db.guess_file_type("image.png"), ("image/png", None))

@unittest.skipIf(not hasattr(_winapi, "_mimetypes_read_windows_registry"),
"read_windows_registry accelerator unavailable")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Deprecate passing a file path to :func:`mimetypes.guess_type`. Use :func:`mimetypes.guess_file_type` instead.
Loading