Bump mimetypes to 3.14.2 (#6808)

* Bump mimetypes to 3.14.2

* Unmark resolved tests

* Mark failed test in Windows
This commit is contained in:
Lee Dogeon authored and GitHub committed 2026-01-21 20:14:30 +09:00
1 parent 2df879c5ee
commit ce1bbc7938
6 files changed
+539 -204

No files matched your search

+217 -84
View File
@@ -23,10 +23,11 @@ init([files]) -- parse a list of files, default knownfiles (on Windows, the
read_mime_types(file) -- parse one file, return a dictionary or None
"""
import os
import sys
import posixpath
import urllib.parse
try:
from _winapi import _mimetypes_read_windows_registry
except ImportError:
_mimetypes_read_windows_registry = None
try:
import winreg as _winreg
except ImportError:
@@ -34,7 +35,7 @@ except ImportError:
__all__ = [
"knownfiles", "inited", "MimeTypes",
"guess_type", "guess_all_extensions", "guess_extension",
"guess_type", "guess_file_type", "guess_all_extensions", "guess_extension",
"add_type", "init", "read_mime_types",
"suffix_map", "encodings_map", "types_map", "common_types"
]
@@ -88,7 +89,21 @@ class MimeTypes:
If strict is true, information will be added to
list of standard types, else to the list of non-standard
types.
Valid extensions are empty or start with a '.'.
"""
if ext and not ext.startswith('.'):
from warnings import _deprecated
_deprecated(
"Undotted extensions",
"Using undotted extensions is deprecated and "
"will raise a ValueError in Python {remove}",
remove=(3, 16),
)
if not type:
return
self.types_map[strict][ext] = type
exts = self.types_map_inv[strict].setdefault(type, [])
if ext not in exts:
@@ -110,11 +125,21 @@ class MimeTypes:
mapped to '.tar.gz'. (This is table-driven too, using the
dictionary suffix_map.)
Optional `strict' argument when False adds a bunch of commonly found,
Optional 'strict' argument when False adds a bunch of commonly found,
but non-standard types.
"""
# Lazy import to improve module import time
import os
import urllib.parse
# TODO: Deprecate accepting file paths (in particular path-like objects).
url = os.fspath(url)
scheme, url = urllib.parse._splittype(url)
p = urllib.parse.urlparse(url)
if p.scheme and len(p.scheme) > 1:
scheme = p.scheme
url = p.path
else:
return self.guess_file_type(url, strict=strict)
if scheme == 'data':
# syntax of data URLs:
# dataurl := "data:" [ mediatype ] [ ";base64" ] "," data
@@ -134,26 +159,43 @@ class MimeTypes:
if '=' in type or '/' not in type:
type = 'text/plain'
return type, None # never compressed, so encoding is None
base, ext = posixpath.splitext(url)
while ext in self.suffix_map:
base, ext = posixpath.splitext(base + self.suffix_map[ext])
# Lazy import to improve module import time
import posixpath
return self._guess_file_type(url, strict, posixpath.splitext)
def guess_file_type(self, path, *, strict=True):
"""Guess the type of a file based on its path.
Similar to guess_type(), but takes file path instead of URL.
"""
# Lazy import to improve module import time
import os
path = os.fsdecode(path)
path = os.path.splitdrive(path)[1]
return self._guess_file_type(path, strict, os.path.splitext)
def _guess_file_type(self, path, strict, splitext):
base, ext = splitext(path)
while (ext_lower := ext.lower()) in self.suffix_map:
base, ext = splitext(base + self.suffix_map[ext_lower])
# encodings_map is case sensitive
if ext in self.encodings_map:
encoding = self.encodings_map[ext]
base, ext = posixpath.splitext(base)
base, ext = splitext(base)
else:
encoding = None
ext = ext.lower()
types_map = self.types_map[True]
if ext in types_map:
return types_map[ext], encoding
elif ext.lower() in types_map:
return types_map[ext.lower()], encoding
elif strict:
return None, encoding
types_map = self.types_map[False]
if ext in types_map:
return types_map[ext], encoding
elif ext.lower() in types_map:
return types_map[ext.lower()], encoding
else:
return None, encoding
@@ -163,13 +205,13 @@ class MimeTypes:
Return value is a list of strings giving the possible filename
extensions, including the leading dot ('.'). The extension is not
guaranteed to have been associated with any particular data stream,
but would be mapped to the MIME type `type' by guess_type().
but would be mapped to the MIME type 'type' by guess_type().
Optional `strict' argument when false adds a bunch of commonly found,
Optional 'strict' argument when false adds a bunch of commonly found,
but non-standard types.
"""
type = type.lower()
extensions = self.types_map_inv[True].get(type, [])
extensions = list(self.types_map_inv[True].get(type, []))
if not strict:
for ext in self.types_map_inv[False].get(type, []):
if ext not in extensions:
@@ -182,11 +224,11 @@ class MimeTypes:
Return value is a string giving a filename extension,
including the leading dot ('.'). The extension is not
guaranteed to have been associated with any particular data
stream, but would be mapped to the MIME type `type' by
guess_type(). If no extension can be guessed for `type', None
stream, but would be mapped to the MIME type 'type' by
guess_type(). If no extension can be guessed for 'type', None
is returned.
Optional `strict' argument when false adds a bunch of commonly found,
Optional 'strict' argument when false adds a bunch of commonly found,
but non-standard types.
"""
extensions = self.guess_all_extensions(type, strict)
@@ -213,10 +255,7 @@ class MimeTypes:
list of standard types, else to the list of non-standard
types.
"""
while 1:
line = fp.readline()
if not line:
break
while line := fp.readline():
words = line.split()
for i in range(len(words)):
if words[i][0] == '#':
@@ -237,10 +276,21 @@ class MimeTypes:
types.
"""
# Windows only
if not _winreg:
if not _mimetypes_read_windows_registry and not _winreg:
return
add_type = self.add_type
if strict:
add_type = lambda type, ext: self.add_type(type, ext, True)
# Accelerated function if it is available
if _mimetypes_read_windows_registry:
_mimetypes_read_windows_registry(add_type)
elif _winreg:
self._read_windows_registry(add_type)
@classmethod
def _read_windows_registry(cls, add_type):
def enum_types(mimedb):
i = 0
while True:
@@ -265,7 +315,7 @@ class MimeTypes:
subkey, 'Content Type')
if datatype != _winreg.REG_SZ:
continue
self.add_type(mimetype, subkeyname, strict)
add_type(mimetype, subkeyname)
except OSError:
continue
@@ -284,7 +334,7 @@ def guess_type(url, strict=True):
to ".tar.gz". (This is table-driven too, using the dictionary
suffix_map).
Optional `strict' argument when false adds a bunch of commonly found, but
Optional 'strict' argument when false adds a bunch of commonly found, but
non-standard types.
"""
if _db is None:
@@ -292,17 +342,27 @@ def guess_type(url, strict=True):
return _db.guess_type(url, strict)
def guess_file_type(path, *, strict=True):
"""Guess the type of a file based on its path.
Similar to guess_type(), but takes file path instead of URL.
"""
if _db is None:
init()
return _db.guess_file_type(path, strict=strict)
def guess_all_extensions(type, strict=True):
"""Guess the extensions for a file based on its MIME type.
Return value is a list of strings giving the possible filename
extensions, including the leading dot ('.'). The extension is not
guaranteed to have been associated with any particular data
stream, but would be mapped to the MIME type `type' by
guess_type(). If no extension can be guessed for `type', None
stream, but would be mapped to the MIME type 'type' by
guess_type(). If no extension can be guessed for 'type', None
is returned.
Optional `strict' argument when false adds a bunch of commonly found,
Optional 'strict' argument when false adds a bunch of commonly found,
but non-standard types.
"""
if _db is None:
@@ -315,10 +375,10 @@ def guess_extension(type, strict=True):
Return value is a string giving a filename extension, including the
leading dot ('.'). The extension is not guaranteed to have been
associated with any particular data stream, but would be mapped to the
MIME type `type' by guess_type(). If no extension can be guessed for
`type', None is returned.
MIME type 'type' by guess_type(). If no extension can be guessed for
'type', None is returned.
Optional `strict' argument when false adds a bunch of commonly found,
Optional 'strict' argument when false adds a bunch of commonly found,
but non-standard types.
"""
if _db is None:
@@ -349,8 +409,8 @@ def init(files=None):
if files is None or _db is None:
db = MimeTypes()
if _winreg:
db.read_windows_registry()
# Quick return if not supported
db.read_windows_registry()
if files is None:
files = knownfiles
@@ -359,6 +419,9 @@ def init(files=None):
else:
db = _db
# Lazy import to improve module import time
import os
for file in files:
if os.path.isfile(file):
db.read(file)
@@ -401,23 +464,28 @@ def _default_mime_types():
'.Z': 'compress',
'.bz2': 'bzip2',
'.xz': 'xz',
'.br': 'br',
}
# Before adding new types, make sure they are either registered with IANA,
# at http://www.iana.org/assignments/media-types
# at https://www.iana.org/assignments/media-types/media-types.xhtml
# or extensions, i.e. using the x- prefix
# If you add to these, please keep them sorted by mime type.
# Make sure the entry with the preferred file extension for a particular mime type
# appears before any others of the same mimetype.
types_map = _types_map_default = {
'.js' : 'application/javascript',
'.mjs' : 'application/javascript',
'.js' : 'text/javascript',
'.mjs' : 'text/javascript',
'.epub' : 'application/epub+zip',
'.gz' : 'application/gzip',
'.json' : 'application/json',
'.webmanifest': 'application/manifest+json',
'.doc' : 'application/msword',
'.dot' : 'application/msword',
'.wiz' : 'application/msword',
'.nq' : 'application/n-quads',
'.nt' : 'application/n-triples',
'.bin' : 'application/octet-stream',
'.a' : 'application/octet-stream',
'.dll' : 'application/octet-stream',
@@ -426,24 +494,37 @@ def _default_mime_types():
'.obj' : 'application/octet-stream',
'.so' : 'application/octet-stream',
'.oda' : 'application/oda',
'.ogx' : 'application/ogg',
'.pdf' : 'application/pdf',
'.p7c' : 'application/pkcs7-mime',
'.ps' : 'application/postscript',
'.ai' : 'application/postscript',
'.eps' : 'application/postscript',
'.trig' : 'application/trig',
'.m3u' : 'application/vnd.apple.mpegurl',
'.m3u8' : 'application/vnd.apple.mpegurl',
'.xls' : 'application/vnd.ms-excel',
'.xlb' : 'application/vnd.ms-excel',
'.eot' : 'application/vnd.ms-fontobject',
'.ppt' : 'application/vnd.ms-powerpoint',
'.pot' : 'application/vnd.ms-powerpoint',
'.ppa' : 'application/vnd.ms-powerpoint',
'.pps' : 'application/vnd.ms-powerpoint',
'.pwz' : 'application/vnd.ms-powerpoint',
'.odg' : 'application/vnd.oasis.opendocument.graphics',
'.odp' : 'application/vnd.oasis.opendocument.presentation',
'.ods' : 'application/vnd.oasis.opendocument.spreadsheet',
'.odt' : 'application/vnd.oasis.opendocument.text',
'.pptx' : 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'.xlsx' : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'.docx' : 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'.rar' : 'application/vnd.rar',
'.wasm' : 'application/wasm',
'.7z' : 'application/x-7z-compressed',
'.bcpio' : 'application/x-bcpio',
'.cpio' : 'application/x-cpio',
'.csh' : 'application/x-csh',
'.deb' : 'application/x-debian-package',
'.dvi' : 'application/x-dvi',
'.gtar' : 'application/x-gtar',
'.hdf' : 'application/x-hdf',
@@ -453,10 +534,12 @@ def _default_mime_types():
'.cdf' : 'application/x-netcdf',
'.nc' : 'application/x-netcdf',
'.p12' : 'application/x-pkcs12',
'.php' : 'application/x-httpd-php',
'.pfx' : 'application/x-pkcs12',
'.ram' : 'application/x-pn-realaudio',
'.pyc' : 'application/x-python-code',
'.pyo' : 'application/x-python-code',
'.rpm' : 'application/x-rpm',
'.sh' : 'application/x-sh',
'.shar' : 'application/x-shar',
'.swf' : 'application/x-shockwave-flash',
@@ -479,29 +562,61 @@ def _default_mime_types():
'.rdf' : 'application/xml',
'.wsdl' : 'application/xml',
'.xpdl' : 'application/xml',
'.yaml' : 'application/yaml',
'.yml' : 'application/yaml',
'.zip' : 'application/zip',
'.3gp' : 'audio/3gpp',
'.3gpp' : 'audio/3gpp',
'.3g2' : 'audio/3gpp2',
'.3gpp2' : 'audio/3gpp2',
'.aac' : 'audio/aac',
'.adts' : 'audio/aac',
'.loas' : 'audio/aac',
'.ass' : 'audio/aac',
'.au' : 'audio/basic',
'.snd' : 'audio/basic',
'.flac' : 'audio/flac',
'.mka' : 'audio/matroska',
'.m4a' : 'audio/mp4',
'.mp3' : 'audio/mpeg',
'.mp2' : 'audio/mpeg',
'.ogg' : 'audio/ogg',
'.opus' : 'audio/opus',
'.aif' : 'audio/x-aiff',
'.aifc' : 'audio/x-aiff',
'.aiff' : 'audio/x-aiff',
'.ra' : 'audio/x-pn-realaudio',
'.wav' : 'audio/x-wav',
'.wav' : 'audio/vnd.wave',
'.otf' : 'font/otf',
'.ttf' : 'font/ttf',
'.weba' : 'audio/webm',
'.woff' : 'font/woff',
'.woff2' : 'font/woff2',
'.avif' : 'image/avif',
'.bmp' : 'image/bmp',
'.emf' : 'image/emf',
'.fits' : 'image/fits',
'.g3' : 'image/g3fax',
'.gif' : 'image/gif',
'.ief' : 'image/ief',
'.jp2' : 'image/jp2',
'.jpg' : 'image/jpeg',
'.jpe' : 'image/jpeg',
'.jpeg' : 'image/jpeg',
'.jpm' : 'image/jpm',
'.jpx' : 'image/jpx',
'.heic' : 'image/heic',
'.heif' : 'image/heif',
'.png' : 'image/png',
'.svg' : 'image/svg+xml',
'.t38' : 'image/t38',
'.tiff' : 'image/tiff',
'.tif' : 'image/tiff',
'.tfx' : 'image/tiff-fx',
'.ico' : 'image/vnd.microsoft.icon',
'.webp' : 'image/webp',
'.wmf' : 'image/wmf',
'.ras' : 'image/x-cmu-raster',
'.bmp' : 'image/x-ms-bmp',
'.pnm' : 'image/x-portable-anymap',
'.pbm' : 'image/x-portable-bitmap',
'.pgm' : 'image/x-portable-graymap',
@@ -514,34 +629,49 @@ def _default_mime_types():
'.mht' : 'message/rfc822',
'.mhtml' : 'message/rfc822',
'.nws' : 'message/rfc822',
'.gltf' : 'model/gltf+json',
'.glb' : 'model/gltf-binary',
'.stl' : 'model/stl',
'.css' : 'text/css',
'.csv' : 'text/csv',
'.html' : 'text/html',
'.htm' : 'text/html',
'.md' : 'text/markdown',
'.markdown': 'text/markdown',
'.n3' : 'text/n3',
'.txt' : 'text/plain',
'.bat' : 'text/plain',
'.c' : 'text/plain',
'.h' : 'text/plain',
'.ksh' : 'text/plain',
'.pl' : 'text/plain',
'.srt' : 'text/plain',
'.rtx' : 'text/richtext',
'.rtf' : 'text/rtf',
'.tsv' : 'text/tab-separated-values',
'.vtt' : 'text/vtt',
'.py' : 'text/x-python',
'.rst' : 'text/x-rst',
'.etx' : 'text/x-setext',
'.sgm' : 'text/x-sgml',
'.sgml' : 'text/x-sgml',
'.vcf' : 'text/x-vcard',
'.xml' : 'text/xml',
'.mkv' : 'video/matroska',
'.mk3d' : 'video/matroska-3d',
'.mp4' : 'video/mp4',
'.mpeg' : 'video/mpeg',
'.m1v' : 'video/mpeg',
'.mpa' : 'video/mpeg',
'.mpe' : 'video/mpeg',
'.mpg' : 'video/mpeg',
'.ogv' : 'video/ogg',
'.mov' : 'video/quicktime',
'.qt' : 'video/quicktime',
'.webm' : 'video/webm',
'.avi' : 'video/x-msvideo',
'.avi' : 'video/vnd.avi',
'.m4v' : 'video/x-m4v',
'.wmv' : 'video/x-ms-wmv',
'.movie' : 'video/x-sgi-movie',
}
@@ -551,6 +681,7 @@ def _default_mime_types():
# Please sort these too
common_types = _common_types_default = {
'.rtf' : 'application/rtf',
'.apk' : 'application/vnd.android.package-archive',
'.midi': 'audio/midi',
'.mid' : 'audio/midi',
'.jpg' : 'image/jpg',
@@ -564,51 +695,53 @@ def _default_mime_types():
_default_mime_types()
def _main():
import getopt
def _parse_args(args):
from argparse import ArgumentParser
USAGE = """\
Usage: mimetypes.py [options] type
parser = ArgumentParser(
description='map filename extensions to MIME types', color=True
)
parser.add_argument(
'-e', '--extension',
action='store_true',
help='guess extension instead of type'
)
parser.add_argument(
'-l', '--lenient',
action='store_true',
help='additionally search for common but non-standard types'
)
parser.add_argument('type', nargs='+', help='a type to search')
args = parser.parse_args(args)
return args, parser.format_help()
Options:
--help / -h -- print this message and exit
--lenient / -l -- additionally search of some common, but non-standard
types.
--extension / -e -- guess extension instead of type
More than one type argument may be given.
"""
def _main(args=None):
"""Run the mimetypes command-line interface and return a text to print."""
args, help_text = _parse_args(args)
def usage(code, msg=''):
print(USAGE)
if msg: print(msg)
sys.exit(code)
try:
opts, args = getopt.getopt(sys.argv[1:], 'hle',
['help', 'lenient', 'extension'])
except getopt.error as msg:
usage(1, msg)
strict = 1
extension = 0
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-l', '--lenient'):
strict = 0
elif opt in ('-e', '--extension'):
extension = 1
for gtype in args:
if extension:
guess = guess_extension(gtype, strict)
if not guess: print("I don't know anything about type", gtype)
else: print(guess)
else:
guess, encoding = guess_type(gtype, strict)
if not guess: print("I don't know anything about type", gtype)
else: print('type:', guess, 'encoding:', encoding)
results = []
if args.extension:
for gtype in args.type:
guess = guess_extension(gtype, not args.lenient)
if guess:
results.append(str(guess))
else:
results.append(f"error: unknown type {gtype}")
return results
else:
for gtype in args.type:
guess, encoding = guess_type(gtype, not args.lenient)
if guess:
results.append(f"type: {guess} encoding: {encoding}")
else:
results.append(f"error: media type unknown for {gtype}")
return results
if __name__ == '__main__':
_main()
import sys
results = _main()
print("\n".join(results))
sys.exit(any(result.startswith("error: ") for result in results))
-2
View File
@@ -2098,7 +2098,6 @@ class HTTPSTest(TestCase):
h.request('GET', '/')
self.assertEqual(exc_info.exception.reason, 'CERTIFICATE_VERIFY_FAILED')
@unittest.expectedFailure # TODO: RUSTPYTHON http.client.RemoteDisconnected: Remote end closed connection without response
def test_local_good_hostname(self):
# The (valid) cert validates the HTTPS hostname
import ssl
@@ -2112,7 +2111,6 @@ class HTTPSTest(TestCase):
self.addCleanup(resp.close)
self.assertEqual(resp.status, 404)
@unittest.expectedFailure # TODO: RUSTPYTHON http.client.RemoteDisconnected: Remote end closed connection without response
def test_local_bad_hostname(self):
# The (valid) cert doesn't validate the HTTPS hostname
import ssl
-11
View File
@@ -498,7 +498,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
@unittest.skipUnless(os_helper.TESTFN_NONASCII,
'need os_helper.TESTFN_NONASCII')
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_list_dir_nonascii_filename(self):
filename = os_helper.TESTFN_NONASCII + '.txt'
self.check_list_dir_filename(filename)
@@ -519,7 +518,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
'undecodable name cannot be decoded on win32')
@unittest.skipUnless(os_helper.TESTFN_UNDECODABLE,
'need os_helper.TESTFN_UNDECODABLE')
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_list_dir_undecodable_filename(self):
filename = os.fsdecode(os_helper.TESTFN_UNDECODABLE) + '.txt'
self.check_list_dir_filename(filename)
@@ -536,7 +534,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
@unittest.skipUnless(os_helper.TESTFN_UNENCODABLE,
'need os_helper.TESTFN_UNENCODABLE')
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_list_dir_unencodable_filename(self):
filename = os_helper.TESTFN_UNENCODABLE + '.txt'
self.check_list_dir_filename(filename)
@@ -550,7 +547,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
self.check_list_dir_dirname(dirname,
quotedname=urllib.parse.quote(dirname, safe='&<>\'"'))
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_list_dir_escape_filename(self):
# Characters that need special treating in URL or HTML.
for name in ('q?', 'f#', '&amp;', '&amp', '<i>', '"dq"', "'sq'",
@@ -618,7 +614,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
# follows that isn't important in this Location: header.
self.assertStartsWith(location, 'https://pypi.org/')
@unittest.expectedFailure # TODO: RUSTPYTHON
def test_get(self):
#constructs the path relative to the root directory of the HTTPServer
response = self.request(self.base_url + '/test')
@@ -670,7 +665,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
finally:
os.chmod(self.tempdir, 0o755)
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_head(self):
response = self.request(
self.base_url + '/test', method='HEAD')
@@ -680,7 +674,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
self.assertEqual(response.getheader('content-type'),
'application/octet-stream')
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_browser_cache(self):
"""Check that when a request to /test is sent with the request header
If-Modified-Since set to date of last modification, the server returns
@@ -699,7 +692,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
response = self.request(self.base_url + '/test', headers=headers)
self.check_status_and_reason(response, HTTPStatus.NOT_MODIFIED)
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_browser_cache_file_changed(self):
# with If-Modified-Since earlier than Last-Modified, must return 200
dt = self.last_modif_datetime
@@ -711,7 +703,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
response = self.request(self.base_url + '/test', headers=headers)
self.check_status_and_reason(response, HTTPStatus.OK)
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_browser_cache_with_If_None_Match_header(self):
# if If-None-Match header is present, ignore If-Modified-Since
@@ -730,7 +721,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
response = self.request('/', method='GETs')
self.check_status_and_reason(response, HTTPStatus.NOT_IMPLEMENTED)
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_last_modified(self):
"""Checks that the datetime returned in Last-Modified response header
is the actual datetime of last modification, rounded to the second
@@ -740,7 +730,6 @@ class SimpleHTTPServerTestCase(BaseTestCase):
last_modif_header = response.headers['Last-modified']
self.assertEqual(last_modif_header, self.last_modif_header)
@unittest.expectedFailure # TODO: RUSTPYTHON; http.client.RemoteDisconnected: Remote end closed connection without response
def test_path_without_leading_slash(self):
response = self.request(self.tempdir_name + '/test')
self.check_status_and_reason(response, HTTPStatus.OK, data=self.data)
+321 -105
View File
@@ -1,12 +1,18 @@
import io
import locale
import mimetypes
import pathlib
import os
import shlex
import sys
import unittest
from test import support
import unittest.mock
from platform import win32_edition
from test import support
from test.support import cpython_only, force_not_colorized, os_helper
from test.support.import_helper import ensure_lazy_imports
try:
import _winapi
except ImportError:
_winapi = None
def setUpModule():
@@ -28,15 +34,30 @@ class MimeTypesTestCase(unittest.TestCase):
def setUp(self):
self.db = mimetypes.MimeTypes()
def test_case_sensitivity(self):
eq = self.assertEqual
eq(self.db.guess_file_type("foobar.html"), ("text/html", None))
eq(self.db.guess_type("scheme:foobar.html"), ("text/html", None))
eq(self.db.guess_file_type("foobar.HTML"), ("text/html", None))
eq(self.db.guess_type("scheme:foobar.HTML"), ("text/html", None))
eq(self.db.guess_file_type("foobar.tgz"), ("application/x-tar", "gzip"))
eq(self.db.guess_type("scheme:foobar.tgz"), ("application/x-tar", "gzip"))
eq(self.db.guess_file_type("foobar.TGZ"), ("application/x-tar", "gzip"))
eq(self.db.guess_type("scheme:foobar.TGZ"), ("application/x-tar", "gzip"))
eq(self.db.guess_file_type("foobar.tar.Z"), ("application/x-tar", "compress"))
eq(self.db.guess_type("scheme:foobar.tar.Z"), ("application/x-tar", "compress"))
eq(self.db.guess_file_type("foobar.tar.z"), (None, None))
eq(self.db.guess_type("scheme:foobar.tar.z"), (None, None))
def test_default_data(self):
eq = self.assertEqual
eq(self.db.guess_type("foo.html"), ("text/html", None))
eq(self.db.guess_type("foo.HTML"), ("text/html", None))
eq(self.db.guess_type("foo.tgz"), ("application/x-tar", "gzip"))
eq(self.db.guess_type("foo.tar.gz"), ("application/x-tar", "gzip"))
eq(self.db.guess_type("foo.tar.Z"), ("application/x-tar", "compress"))
eq(self.db.guess_type("foo.tar.bz2"), ("application/x-tar", "bzip2"))
eq(self.db.guess_type("foo.tar.xz"), ("application/x-tar", "xz"))
eq(self.db.guess_file_type("foo.html"), ("text/html", None))
eq(self.db.guess_file_type("foo.HTML"), ("text/html", None))
eq(self.db.guess_file_type("foo.tgz"), ("application/x-tar", "gzip"))
eq(self.db.guess_file_type("foo.tar.gz"), ("application/x-tar", "gzip"))
eq(self.db.guess_file_type("foo.tar.Z"), ("application/x-tar", "compress"))
eq(self.db.guess_file_type("foo.tar.bz2"), ("application/x-tar", "bzip2"))
eq(self.db.guess_file_type("foo.tar.xz"), ("application/x-tar", "xz"))
def test_data_urls(self):
eq = self.assertEqual
@@ -50,12 +71,10 @@ class MimeTypesTestCase(unittest.TestCase):
eq = self.assertEqual
sio = io.StringIO("x-application/x-unittest pyunit\n")
self.db.readfp(sio)
eq(self.db.guess_type("foo.pyunit"),
eq(self.db.guess_file_type("foo.pyunit"),
("x-application/x-unittest", None))
eq(self.db.guess_extension("x-application/x-unittest"), ".pyunit")
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_read_mime_types(self):
eq = self.assertEqual
@@ -64,32 +83,40 @@ class MimeTypesTestCase(unittest.TestCase):
with os_helper.temp_dir() as directory:
data = "x-application/x-unittest pyunit\n"
file = pathlib.Path(directory, "sample.mimetype")
file.write_text(data)
file = os.path.join(directory, "sample.mimetype")
with open(file, 'w', encoding="utf-8") as f:
f.write(data)
mime_dict = mimetypes.read_mime_types(file)
eq(mime_dict[".pyunit"], "x-application/x-unittest")
data = "x-application/x-unittest2 pyunit2\n"
file = os.path.join(directory, "sample2.mimetype")
with open(file, 'w', encoding="utf-8") as f:
f.write(data)
mime_dict = mimetypes.read_mime_types(os_helper.FakePath(file))
eq(mime_dict[".pyunit2"], "x-application/x-unittest2")
# bpo-41048: read_mime_types should read the rule file with 'utf-8' encoding.
# Not with locale encoding. _bootlocale has been imported because io.open(...)
# uses it.
with os_helper.temp_dir() as directory:
data = "application/no-mans-land Fran\u00E7ais"
file = pathlib.Path(directory, "sample.mimetype")
file.write_text(data, encoding='utf-8')
import _bootlocale
with support.swap_attr(_bootlocale, 'getpreferredencoding', lambda do_setlocale=True: 'ASCII'):
mime_dict = mimetypes.read_mime_types(file)
eq(mime_dict[".Français"], "application/no-mans-land")
data = "application/no-mans-land Fran\u00E7ais"
filename = "filename"
fp = io.StringIO(data)
with unittest.mock.patch.object(mimetypes, 'open',
return_value=fp) as mock_open:
mime_dict = mimetypes.read_mime_types(filename)
mock_open.assert_called_with(filename, encoding='utf-8')
eq(mime_dict[".Français"], "application/no-mans-land")
def test_non_standard_types(self):
eq = self.assertEqual
# First try strict
eq(self.db.guess_type('foo.xul', strict=True), (None, None))
eq(self.db.guess_file_type('foo.xul', strict=True), (None, None))
eq(self.db.guess_extension('image/jpg', strict=True), None)
# And then non-strict
eq(self.db.guess_type('foo.xul', strict=False), ('text/xul', None))
eq(self.db.guess_type('foo.XUL', strict=False), ('text/xul', None))
eq(self.db.guess_type('foo.invalid', strict=False), (None, None))
eq(self.db.guess_file_type('foo.xul', strict=False), ('text/xul', None))
eq(self.db.guess_file_type('foo.XUL', strict=False), ('text/xul', None))
eq(self.db.guess_file_type('foo.invalid', strict=False), (None, None))
eq(self.db.guess_extension('image/jpg', strict=False), '.jpg')
eq(self.db.guess_extension('image/JPG', strict=False), '.jpg')
@@ -99,37 +126,77 @@ class MimeTypesTestCase(unittest.TestCase):
# compared to when interpreted as filename because of the semicolon.
eq = self.assertEqual
gzip_expected = ('application/x-tar', 'gzip')
eq(self.db.guess_type(";1.tar.gz"), gzip_expected)
eq(self.db.guess_type("?1.tar.gz"), gzip_expected)
eq(self.db.guess_type("#1.tar.gz"), gzip_expected)
eq(self.db.guess_type("#1#.tar.gz"), gzip_expected)
eq(self.db.guess_type(";1#.tar.gz"), gzip_expected)
eq(self.db.guess_type(";&1=123;?.tar.gz"), gzip_expected)
eq(self.db.guess_type("?k1=v1&k2=v2.tar.gz"), gzip_expected)
for name in (
';1.tar.gz',
'?1.tar.gz',
'#1.tar.gz',
'#1#.tar.gz',
';1#.tar.gz',
';&1=123;?.tar.gz',
'?k1=v1&k2=v2.tar.gz',
):
for prefix in ('', '/', '\\',
'c:', 'c:/', 'c:\\', 'c:/d/', 'c:\\d\\',
'//share/server/', '\\\\share\\server\\'):
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)
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)
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)
eq(self.db.guess_file_type(r'foo/.tar.gz'), (None, 'gzip'))
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)
eq(self.db.guess_type(r'scheme:foo\.tar.gz'), gzip_expected)
def test_url(self):
result = self.db.guess_type('http://example.com/host.html')
result = self.db.guess_type('http://host.html')
msg = 'URL only has a host name, not a file'
self.assertSequenceEqual(result, (None, None), msg)
result = self.db.guess_type('http://example.com/host.html')
msg = 'Should be text/html'
self.assertSequenceEqual(result, ('text/html', None), msg)
result = self.db.guess_type('http://example.com/host.html#x.tar')
self.assertSequenceEqual(result, ('text/html', None))
result = self.db.guess_type('http://example.com/host.html?q=x.tar')
self.assertSequenceEqual(result, ('text/html', None))
def test_guess_all_types(self):
eq = self.assertEqual
unless = self.assertTrue
# First try strict. Use a set here for testing the results because if
# test_urllib2 is run before test_mimetypes, global state is modified
# such that the 'all' set will have more items in it.
all = set(self.db.guess_all_extensions('text/plain', strict=True))
unless(all >= set(['.bat', '.c', '.h', '.ksh', '.pl', '.txt']))
all = self.db.guess_all_extensions('text/plain', strict=True)
self.assertTrue(set(all) >= {'.bat', '.c', '.h', '.ksh', '.pl', '.txt'})
self.assertEqual(len(set(all)), len(all)) # no duplicates
# And now non-strict
all = self.db.guess_all_extensions('image/jpg', strict=False)
all.sort()
eq(all, ['.jpg'])
self.assertEqual(all, ['.jpg'])
# And now for no hits
all = self.db.guess_all_extensions('image/jpg', strict=True)
eq(all, [])
self.assertEqual(all, [])
# And now for type existing in both strict and non-strict mappings.
self.db.add_type('test-type', '.strict-ext')
self.db.add_type('test-type', '.non-strict-ext', strict=False)
all = self.db.guess_all_extensions('test-type', strict=False)
self.assertEqual(all, ['.strict-ext', '.non-strict-ext'])
all = self.db.guess_all_extensions('test-type')
self.assertEqual(all, ['.strict-ext'])
# Test that changing the result list does not affect the global state
all.append('.no-such-ext')
all = self.db.guess_all_extensions('test-type')
self.assertNotIn('.no-such-ext', all)
def test_encoding(self):
getpreferredencoding = locale.getpreferredencoding
self.addCleanup(setattr, locale, 'getpreferredencoding',
getpreferredencoding)
locale.getpreferredencoding = lambda: 'ascii'
filename = support.findfile("mime.types")
mimes = mimetypes.MimeTypes([filename])
exts = mimes.guess_all_extensions('application/vnd.geocube+xml',
@@ -146,29 +213,110 @@ class MimeTypesTestCase(unittest.TestCase):
# Poison should be gone.
self.assertEqual(mimetypes.guess_extension('foo/bar'), None)
@unittest.skipIf(sys.platform.startswith("win"), "Non-Windows only")
def test_guess_known_extensions(self):
# Issue 37529
# The test fails on Windows because Windows adds mime types from the Registry
# and that creates some duplicates.
from mimetypes import types_map
for v in types_map.values():
self.assertIsNotNone(mimetypes.guess_extension(v))
def test_preferred_extension(self):
def check_extensions():
self.assertEqual(mimetypes.guess_extension('application/octet-stream'), '.bin')
self.assertEqual(mimetypes.guess_extension('application/postscript'), '.ps')
self.assertEqual(mimetypes.guess_extension('application/vnd.apple.mpegurl'), '.m3u')
self.assertEqual(mimetypes.guess_extension('application/vnd.ms-excel'), '.xls')
self.assertEqual(mimetypes.guess_extension('application/vnd.ms-powerpoint'), '.ppt')
self.assertEqual(mimetypes.guess_extension('application/x-texinfo'), '.texi')
self.assertEqual(mimetypes.guess_extension('application/x-troff'), '.roff')
self.assertEqual(mimetypes.guess_extension('application/xml'), '.xsl')
self.assertEqual(mimetypes.guess_extension('audio/mpeg'), '.mp3')
self.assertEqual(mimetypes.guess_extension('image/jpeg'), '.jpg')
self.assertEqual(mimetypes.guess_extension('image/tiff'), '.tiff')
self.assertEqual(mimetypes.guess_extension('message/rfc822'), '.eml')
self.assertEqual(mimetypes.guess_extension('text/html'), '.html')
self.assertEqual(mimetypes.guess_extension('text/plain'), '.txt')
self.assertEqual(mimetypes.guess_extension('video/mpeg'), '.mpeg')
self.assertEqual(mimetypes.guess_extension('video/quicktime'), '.mov')
for mime_type, ext in (
("application/epub+zip", ".epub"),
("application/octet-stream", ".bin"),
("application/gzip", ".gz"),
("application/ogg", ".ogx"),
("application/postscript", ".ps"),
("application/vnd.apple.mpegurl", ".m3u"),
("application/vnd.ms-excel", ".xls"),
("application/vnd.ms-fontobject", ".eot"),
("application/vnd.ms-powerpoint", ".ppt"),
("application/vnd.oasis.opendocument.graphics", ".odg"),
("application/vnd.oasis.opendocument.presentation", ".odp"),
("application/vnd.oasis.opendocument.spreadsheet", ".ods"),
("application/vnd.oasis.opendocument.text", ".odt"),
("application/vnd.openxmlformats-officedocument.presentationml.presentation", ".pptx"),
("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ".xlsx"),
("application/vnd.openxmlformats-officedocument.wordprocessingml.document", ".docx"),
("application/vnd.rar", ".rar"),
("application/x-7z-compressed", ".7z"),
("application/x-debian-package", ".deb"),
("application/x-httpd-php", ".php"),
("application/x-rpm", ".rpm"),
("application/x-texinfo", ".texi"),
("application/x-troff", ".roff"),
("application/xml", ".xsl"),
("application/yaml", ".yaml"),
("audio/flac", ".flac"),
("audio/matroska", ".mka"),
("audio/mp4", ".m4a"),
("audio/mpeg", ".mp3"),
("audio/ogg", ".ogg"),
("audio/vnd.wave", ".wav"),
("audio/webm", ".weba"),
("font/otf", ".otf"),
("font/ttf", ".ttf"),
("font/woff", ".woff"),
("font/woff2", ".woff2"),
("image/avif", ".avif"),
("image/emf", ".emf"),
("image/fits", ".fits"),
("image/g3fax", ".g3"),
("image/jp2", ".jp2"),
("image/jpeg", ".jpg"),
("image/jpm", ".jpm"),
("image/t38", ".t38"),
("image/tiff", ".tiff"),
("image/tiff-fx", ".tfx"),
("image/webp", ".webp"),
("image/wmf", ".wmf"),
("message/rfc822", ".eml"),
("model/gltf+json", ".gltf"),
("model/gltf-binary", ".glb"),
("model/stl", ".stl"),
("text/html", ".html"),
("text/plain", ".txt"),
("text/rtf", ".rtf"),
("text/x-rst", ".rst"),
("video/matroska", ".mkv"),
("video/matroska-3d", ".mk3d"),
("video/mpeg", ".mpeg"),
("video/ogg", ".ogv"),
("video/quicktime", ".mov"),
("video/vnd.avi", ".avi"),
("video/x-m4v", ".m4v"),
("video/x-ms-wmv", ".wmv"),
):
with self.subTest(mime_type=mime_type, ext=ext):
self.assertEqual(mimetypes.guess_extension(mime_type), ext)
check_extensions()
mimetypes.init()
check_extensions()
def test_guess_file_type(self):
def check_file_type():
for mime_type, ext in (
("application/yaml", ".yaml"),
("application/yaml", ".yml"),
("audio/mpeg", ".mp2"),
("audio/mpeg", ".mp3"),
("video/mpeg", ".m1v"),
("video/mpeg", ".mpe"),
("video/mpeg", ".mpeg"),
("video/mpeg", ".mpg"),
):
with self.subTest(mime_type=mime_type, ext=ext):
result, _ = mimetypes.guess_file_type(f"filename{ext}")
self.assertEqual(result, mime_type)
check_file_type()
mimetypes.init()
check_file_type()
def test_init_stability(self):
mimetypes.init()
@@ -189,27 +337,59 @@ class MimeTypesTestCase(unittest.TestCase):
def test_path_like_ob(self):
filename = "LICENSE.txt"
filepath = pathlib.Path(filename)
filepath_with_abs_dir = pathlib.Path('/dir/'+filename)
filepath_relative = pathlib.Path('../dir/'+filename)
path_dir = pathlib.Path('./')
filepath = os_helper.FakePath(filename)
filepath_with_abs_dir = os_helper.FakePath('/dir/'+filename)
filepath_relative = os_helper.FakePath('../dir/'+filename)
path_dir = os_helper.FakePath('./')
expected = self.db.guess_type(filename)
expected = self.db.guess_file_type(filename)
self.assertEqual(self.db.guess_file_type(filepath), expected)
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)
self.assertEqual(self.db.guess_file_type(filepath_relative), expected)
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))
def test_bytes_path(self):
self.assertEqual(self.db.guess_file_type(b'foo.html'),
self.db.guess_file_type('foo.html'))
self.assertEqual(self.db.guess_file_type(b'foo.tar.gz'),
self.db.guess_file_type('foo.tar.gz'))
self.assertEqual(self.db.guess_file_type(b'foo.tgz'),
self.db.guess_file_type('foo.tgz'))
def test_keywords_args_api(self):
self.assertEqual(self.db.guess_file_type(
path="foo.html", strict=True), ("text/html", None))
self.assertEqual(self.db.guess_type(
url="foo.html", strict=True), ("text/html", None))
url="scheme:foo.html", strict=True), ("text/html", None))
self.assertEqual(self.db.guess_all_extensions(
type='image/jpg', strict=True), [])
self.assertEqual(self.db.guess_extension(
type='image/jpg', strict=False), '.jpg')
def test_added_types_are_used(self):
mimetypes.add_type('testing/default-type', '')
mime_type, _ = mimetypes.guess_type('')
self.assertEqual(mime_type, 'testing/default-type')
mime_type, _ = mimetypes.guess_type('test.myext')
self.assertEqual(mime_type, None)
mimetypes.add_type('testing/type', '.myext')
mime_type, _ = mimetypes.guess_type('test.myext')
self.assertEqual(mime_type, 'testing/type')
def test_add_type_with_undotted_extension_deprecated(self):
with self.assertWarns(DeprecationWarning):
mimetypes.add_type("testing/type", "undotted")
@unittest.skipUnless(sys.platform.startswith("win"), "Windows only")
class Win32MimeTypesTestCase(unittest.TestCase):
@@ -236,58 +416,94 @@ class Win32MimeTypesTestCase(unittest.TestCase):
eq(self.db.guess_type("image.jpg"), ("image/jpeg", None))
eq(self.db.guess_type("image.png"), ("image/png", None))
@unittest.skipIf(not hasattr(_winapi, "_mimetypes_read_windows_registry"),
"read_windows_registry accelerator unavailable")
def test_registry_accelerator(self):
from_accel = {}
from_reg = {}
_winapi._mimetypes_read_windows_registry(
lambda v, k: from_accel.setdefault(k, set()).add(v)
)
mimetypes.MimeTypes._read_windows_registry(
lambda v, k: from_reg.setdefault(k, set()).add(v)
)
self.assertEqual(list(from_reg), list(from_accel))
for k in from_reg:
self.assertEqual(from_reg[k], from_accel[k])
class MiscTestCase(unittest.TestCase):
def test__all__(self):
support.check__all__(self, mimetypes)
@cpython_only
def test_lazy_import(self):
ensure_lazy_imports("mimetypes", {"os", "posixpath", "urllib.parse", "argparse"})
class MimetypesCliTestCase(unittest.TestCase):
def mimetypes_cmd(self, *args, **kwargs):
support.patch(self, sys, "argv", [sys.executable, *args])
with support.captured_stdout() as output:
mimetypes._main()
return output.getvalue().strip()
class CommandLineTest(unittest.TestCase):
@force_not_colorized
def test_parse_args(self):
args, help_text = mimetypes._parse_args("-h")
self.assertTrue(help_text.startswith("usage: "))
def test_help_option(self):
support.patch(self, sys, "argv", [sys.executable, "-h"])
with support.captured_stdout() as output:
with self.assertRaises(SystemExit) as cm:
mimetypes._main()
args, help_text = mimetypes._parse_args("--invalid")
self.assertTrue(help_text.startswith("usage: "))
self.assertIn("Usage: mimetypes.py", output.getvalue())
self.assertEqual(cm.exception.code, 0)
args, _ = mimetypes._parse_args(shlex.split("-l -e image/jpg"))
self.assertTrue(args.extension)
self.assertTrue(args.lenient)
self.assertEqual(args.type, ["image/jpg"])
def test_invalid_option(self):
support.patch(self, sys, "argv", [sys.executable, "--invalid"])
with support.captured_stdout() as output:
with self.assertRaises(SystemExit) as cm:
mimetypes._main()
args, _ = mimetypes._parse_args(shlex.split("-e image/jpg"))
self.assertTrue(args.extension)
self.assertFalse(args.lenient)
self.assertEqual(args.type, ["image/jpg"])
self.assertIn("Usage: mimetypes.py", output.getvalue())
self.assertEqual(cm.exception.code, 1)
args, _ = mimetypes._parse_args(shlex.split("-l foo.webp"))
self.assertFalse(args.extension)
self.assertTrue(args.lenient)
self.assertEqual(args.type, ["foo.webp"])
def test_guess_extension(self):
eq = self.assertEqual
args, _ = mimetypes._parse_args(shlex.split("foo.pic"))
self.assertFalse(args.extension)
self.assertFalse(args.lenient)
self.assertEqual(args.type, ["foo.pic"])
extension = self.mimetypes_cmd("-l", "-e", "image/jpg")
eq(extension, ".jpg")
def test_multiple_inputs(self):
result = "\n".join(mimetypes._main(shlex.split("foo.pdf foo.png")))
self.assertEqual(
result,
"type: application/pdf encoding: None\n"
"type: image/png encoding: None"
)
extension = self.mimetypes_cmd("-e", "image/jpg")
eq(extension, "I don't know anything about type image/jpg")
def test_multiple_inputs_error(self):
result = "\n".join(mimetypes._main(shlex.split("foo.pdf foo.bar_ext")))
self.assertEqual(
result,
"type: application/pdf encoding: None\n"
"error: media type unknown for foo.bar_ext"
)
extension = self.mimetypes_cmd("-e", "image/jpeg")
eq(extension, ".jpg")
def test_guess_type(self):
eq = self.assertEqual
def test_invocation(self):
for command, expected in [
("-l -e image/jpg", ".jpg"),
("-e image/jpeg", ".jpg"),
("-l foo.webp", "type: image/webp encoding: None"),
]:
result = "\n".join(mimetypes._main(shlex.split(command)))
self.assertEqual(result, expected)
type_info = self.mimetypes_cmd("-l", "foo.pic")
eq(type_info, "type: image/pict encoding: None")
type_info = self.mimetypes_cmd("foo.pic")
eq(type_info, "I don't know anything about type foo.pic")
def test_invocation_error(self):
for command, expected in [
("-e image/jpg", "error: unknown type image/jpg"),
("foo.bar_ext", "error: media type unknown for foo.bar_ext"),
]:
with self.subTest(command=command):
result = "\n".join(mimetypes._main(shlex.split(command)))
self.assertEqual(result, expected)
if __name__ == "__main__":
+1 -1
View File
@@ -3525,7 +3525,7 @@ class ThreadedTests(unittest.TestCase):
else:
s.close()
@unittest.expectedFailure # TODO: RUSTPYTHON
@unittest.expectedFailureIfWindows("TODO: RUSTPYTHON")
def test_socketserver(self):
"""Using socketserver to create and manage SSL connections."""
server = make_https_server(self, certfile=SIGNED_CERTFILE)
-1
View File
@@ -727,7 +727,6 @@ def sanepathname2url(path):
class HandlerTests(unittest.TestCase, ExtraAssertions):
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: None != 'image/gif'
def test_ftp(self):
class MockFTPWrapper:
def __init__(self, data):