Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
15 changes: 10 additions & 5 deletions Doc/library/mimetypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ 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 by *url*.
URL can be 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 +54,10 @@ 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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Schedule removal for Python 3.21. Also, please add a note that it was soft-deprecated since Python 3.13.

Passing a file path (or path-like object) instead of a URL.
Use :func:`guess_file_type` instead.
Soft-deprecated since Python 3.13, scheduled for removal in Python 3.21.


.. function:: guess_file_type(path, *, strict=True)
Expand Down Expand Up @@ -262,6 +263,10 @@ 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.
Soft-deprecated since Python 3.13, scheduled for removal in Python 3.21.

.. 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 @@ -520,6 +520,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`.)

.. Add deprecations above alphabetically, not here at the end.

.. include:: ../deprecations/pending-removal-in-3.17.rst
Expand Down
12 changes: 9 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 @@ -127,14 +127,20 @@ 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:
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 @@ -753,7 +759,7 @@ def _main(args=None):
return results
else:
for gtype in args.type:
guess, encoding = guess_type(gtype, not args.lenient)
guess, encoding = guess_file_type(gtype, strict=not args.lenient)
if guess:
results.append(f"type: {guess} encoding: {encoding}")
else:
Expand Down
47 changes: 31 additions & 16 deletions Lib/test/test_mimetypes.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import io
import mimetypes
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 +235,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 +392,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 +469,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 +501,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 +525,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