Skip to content

Commit

Permalink
refactor(mediatypes): address some review comments
Browse files Browse the repository at this point in the history
  • Loading branch information
vytas7 committed Oct 4, 2024
1 parent ec4c557 commit f6e2ef3
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 36 deletions.
25 changes: 19 additions & 6 deletions falcon/util/mediatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,10 +303,23 @@ def best_match(media_types: Iterable[str], header: str) -> str:
Best match from the supported candidates, or an empty string if the
provided header value does not match any of the given types.
"""
matching, best_quality = max(
((media_type, quality(media_type, header)) for media_type in media_types),
key=lambda mt_quality: mt_quality[1],
)
if best_quality > 0.0:
return matching
# PERF(vytas): Using the default parameter, i.e., max(..., default='', 0.0)
# would be much nicer than EAFP, but for some reason it is quite slow
# regardless of whether media_types is empty or not.
try:
matching, best_quality = max(
((media_type, quality(media_type, header)) for media_type in media_types),
key=lambda mt_quality: mt_quality[1],
)
if best_quality > 0.0:
return matching
except errors.InvalidMediaType:
# NOTE(vytas): Do not swallow instances of InvalidMediaType
# (it a subclass of ValueError).
raise
except ValueError:
# NOTE(vytas): Barring unknown bugs, we only expect unhandled
# ValueErrors from supplying an empty media_types value.
pass

return ''
77 changes: 47 additions & 30 deletions tests/test_mediatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,8 @@ def test_quality_rfc_examples(accept, media_type, quality_value):
),
(
'application/*, */wildcard; q=0.7, */*; q=0.25',
'test/wildcard; expect=pass',
0.7,
'test/something; expect=pass',
0.25,
),
(
'text/x-python, text/*; q=0.33, text/plain; format=fixed',
Expand Down Expand Up @@ -192,23 +192,23 @@ def test_quality_prefer_exact_match(accept, media_type):
assert pytest.approx(mediatypes.quality(media_type, accept)) == 0.2


@pytest.mark.parametrize(
'accept,media_type',
[
('application/json', 'application/yaml'),
('audio/*; q=0.2, audio/basic', 'video/mp3'),
(
'falcon/peregrine; speed=high; unladen=true',
'falcon/peregrine; speed=average',
),
('text/html, text/plain', 'text/x-python'),
('*/json; q=0.2, application/json', 'application/msgpack'),
(
'text/x-python, image/*; q=0.33, text/plain; format=fixed',
'text/plain; format=flowed',
),
],
)
_QUALITY_NONE_MATCHES_EXAMPLES = [
('application/json', 'application/yaml'),
('audio/*; q=0.2, audio/basic', 'video/mp3'),
(
'falcon/peregrine; speed=high; unladen=true',
'falcon/peregrine; speed=average',
),
('text/html, text/plain', 'text/x-python'),
('*/json; q=0.2, application/json', 'application/msgpack'),
(
'text/x-python, image/*; q=0.33, text/plain; format=fixed',
'text/plain; format=flowed',
),
]


@pytest.mark.parametrize('accept,media_type', _QUALITY_NONE_MATCHES_EXAMPLES)
def test_quality_none_matches(accept, media_type):
assert mediatypes.quality(media_type, accept) == 0.0

Expand All @@ -229,17 +229,18 @@ def test_best_match(media_types, accept, expected):
assert mediatypes.best_match(media_types, accept) == expected


@pytest.mark.parametrize(
'media_types,accept',
[
(['application/json'], 'application/yaml'),
(['application/json', 'application/yaml'], 'application/xml, text/*; q=0.7'),
(
['text/plain', 'falcon/peregrine; load=unladen'],
'falcon/peregrine; load=heavy',
),
],
)
_BEST_MATCH_NONE_MATCHES_EXAMPLES = [
([_mt], _acc) for _mt, _acc in _QUALITY_NONE_MATCHES_EXAMPLES
] + [
(['application/json', 'application/yaml'], 'application/xml, text/*; q=0.7'),
(
['text/plain', 'falcon/peregrine; load=unladen'],
'falcon/peregrine; load=heavy',
),
]


@pytest.mark.parametrize('media_types,accept', _BEST_MATCH_NONE_MATCHES_EXAMPLES)
def test_best_match_none_matches(media_types, accept):
assert mediatypes.best_match(media_types, accept) == ''

Expand All @@ -250,6 +251,10 @@ def test_invalid_media_type(media_type):
mediatypes.quality(media_type, '*/*')


def _generate_strings(items):
yield from items


@pytest.mark.parametrize(
'media_range',
[
Expand All @@ -266,3 +271,15 @@ def test_invalid_media_type(media_type):
def test_invalid_media_range(media_range):
with pytest.raises(errors.InvalidMediaRange):
mediatypes.quality('falcon/peregrine', media_range)

with pytest.raises(errors.InvalidMediaRange):
mediatypes.best_match(_generate_strings(['falcon/peregrine']), media_range)


@pytest.mark.parametrize(
'accept',
['*/*', 'application/xml, text/*; q=0.7, */*; q=0.3'],
)
@pytest.mark.parametrize('media_types', [(), [], {}, _generate_strings(())])
def test_empty_media_types(accept, media_types):
assert mediatypes.best_match(media_types, accept) == ''

0 comments on commit f6e2ef3

Please sign in to comment.