Skip to content

Commit c87667b

Browse files
committed
gh-149682: Fix mimetypes CLI to write error messages to stderr
1 parent 56171da commit c87667b

4 files changed

Lines changed: 74 additions & 15 deletions

File tree

Doc/library/mimetypes.rst

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -373,34 +373,32 @@ interface:
373373
$ python -m mimetypes filename.tar.gz
374374
type: application/x-tar encoding: gzip
375375
376-
$ # get a MIME type for a rare file extension
377-
$ python -m mimetypes filename.pict
378-
error: unknown extension of filename.pict
379-
380-
$ # now look in the extended database built into Python
381-
$ python -m mimetypes --lenient filename.pict
382-
type: image/pict encoding: None
376+
$ # get a MIME type for an unknown file extension
377+
$ python -m mimetypes filename.zzz
378+
error: media type unknown for filename.zzz
383379
384380
$ # get a file extension by a MIME type
385381
$ python -m mimetypes --extension text/javascript
386382
.js
387383
388-
$ # get a file extension by a rare MIME type
384+
$ # get a file extension by a rare MIME type (error goes to stderr)
389385
$ python -m mimetypes --extension text/xul
390386
error: unknown type text/xul
391387
392388
$ # now look in the extended database again
393389
$ python -m mimetypes --extension --lenient text/xul
394390
.xul
395391
396-
$ # try to feed an unknown file extension
397-
$ python -m mimetypes filename.sh filename.nc filename.xxx filename.txt
392+
$ # try to feed an unknown file extension (error goes to stderr)
393+
$ python -m mimetypes filename.sh filename.nc filename.zzz filename.txt
398394
type: application/x-sh encoding: None
399395
type: application/x-netcdf encoding: None
400-
error: unknown extension of filename.xxx
396+
error: media type unknown for filename.zzz
397+
type: text/plain encoding: None
401398
402-
$ # try to feed an unknown MIME type
399+
$ # try to feed an unknown MIME type (error goes to stderr)
403400
$ python -m mimetypes --extension audio/aac audio/opus audio/future audio/x-wav
404401
.aac
405402
.opus
406403
error: unknown type audio/future
404+
.wav

Lib/mimetypes.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,5 +756,11 @@ def _main(args=None):
756756
import sys
757757

758758
results = _main()
759-
print("\n".join(results))
760-
sys.exit(any(result.startswith("error: ") for result in results))
759+
has_error = False
760+
for result in results:
761+
if result.startswith("error: "):
762+
print(result, file=sys.stderr, flush=True)
763+
has_error = True
764+
else:
765+
print(result, flush=True)
766+
sys.exit(has_error)

Lib/test/test_mimetypes.py

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@
66
import unittest.mock
77
from platform import win32_edition
88
from test import support
9-
from test.support import cpython_only, force_not_colorized, os_helper
9+
from test.support import cpython_only, force_not_colorized, os_helper, requires_subprocess
1010
from test.support.import_helper import ensure_lazy_imports
11+
from test.support.script_helper import assert_python_ok, assert_python_failure
1112

1213
try:
1314
import _winapi
@@ -508,5 +509,57 @@ def test_invocation_error(self):
508509
self.assertEqual(result, expected)
509510

510511

512+
@requires_subprocess()
513+
class CommandLineSubprocessTest(unittest.TestCase):
514+
def test_help(self):
515+
rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', '--help')
516+
self.assertIn(b'mimetypes', stdout)
517+
self.assertIn(b'--extension', stdout)
518+
self.assertIn(b'--lenient', stdout)
519+
520+
def test_type_lookup(self):
521+
rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', 'foo.pdf')
522+
self.assertIn(b'application/pdf', stdout)
523+
self.assertEqual(stderr, b'')
524+
525+
def test_type_lookup_unknown(self):
526+
rc, stdout, stderr = assert_python_failure('-m', 'mimetypes', 'foo.unknownext12345')
527+
self.assertEqual(stdout, b'')
528+
self.assertIn(b'error:', stderr)
529+
530+
def test_extension_flag(self):
531+
rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', '-e', 'image/jpeg')
532+
self.assertIn(b'.jpg', stdout)
533+
self.assertEqual(stderr, b'')
534+
535+
def test_extension_flag_unknown(self):
536+
rc, stdout, stderr = assert_python_failure('-m', 'mimetypes', '-e', 'image/unknowntype12345')
537+
self.assertEqual(stdout, b'')
538+
self.assertIn(b'error:', stderr)
539+
540+
def test_lenient_flag(self):
541+
rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', '-e', '--lenient', 'text/xul')
542+
self.assertIn(b'.xul', stdout)
543+
self.assertEqual(stderr, b'')
544+
545+
def test_multiple_inputs(self):
546+
rc, stdout, stderr = assert_python_ok('-m', 'mimetypes', 'foo.pdf', 'foo.png')
547+
self.assertIn(b'application/pdf', stdout)
548+
self.assertIn(b'image/png', stdout)
549+
self.assertEqual(stderr, b'')
550+
551+
def test_multiple_inputs_with_error(self):
552+
rc, stdout, stderr = assert_python_failure(
553+
'-m', 'mimetypes', 'foo.pdf', 'foo.unknownext12345'
554+
)
555+
self.assertIn(b'application/pdf', stdout)
556+
self.assertNotIn(b'error:', stdout)
557+
self.assertIn(b'error:', stderr)
558+
559+
def test_unknown_flag(self):
560+
rc, stdout, stderr = assert_python_failure('-m', 'mimetypes', '--unknown-flag')
561+
self.assertNotEqual(rc, 0)
562+
563+
511564
if __name__ == "__main__":
512565
unittest.main()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix :mod:`mimetypes` CLI to write error messages to stderr instead of stdout,
2+
and update the documentation examples to reflect the correct behavior.

0 commit comments

Comments
 (0)