Skip to content

Commit

Permalink
Allow both int and str for limit and offset
Browse files Browse the repository at this point in the history
Update the `validate_input` function in `utils.py` to allow for
both `int` and `str` types for the `limit` and `offset` parameters
in the `search`.
  • Loading branch information
andreztz committed Oct 19, 2023
1 parent da0f913 commit d107de1
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 42 deletions.
1 change: 0 additions & 1 deletion pyradios/radios.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,6 @@ def search(self, **kwargs):
limit (int, optional): Number of returned datarows (stations)
starting with offset (default 100000)
hidebroken (bool, optional): do list/not list broken stations.
Note: Not documented in the "Advanced Station Search".
Returns:
list: Stations.
Expand Down
77 changes: 43 additions & 34 deletions pyradios/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,35 @@


types = {
"search": {
"name": str,
"name_exact": bool,
"codec": str,
"codec_exact": bool,
"country": str,
"country_exact": bool,
"countrycode": str,
"state": str,
"state_exact": bool,
"language": str,
"language_exact": bool,
"tag": str,
"tag_exact": bool,
"tag_list": str,
"bitrate_min": int,
"bitrate_max": int,
"order": str,
"reverse": bool,
"offset": int,
"limit": int,
"hidebroken": bool, # Not documented in the "Advanced Station Search"
'search': {
'name': str,
'name_exact': bool,
'codec': str,
'codec_exact': bool,
'country': str,
'country_exact': bool,
'countrycode': str,
'state': str,
'state_exact': bool,
'language': str,
'language_exact': bool,
'tag': str,
'tag_exact': bool,
'tag_list': str,
'bitrate_min': int,
'bitrate_max': int,
'order': str,
'reverse': bool,
'offset': (int, str),
'limit': (int, str),
'hidebroken': bool,
},
"countries": {"code": str},
"countrycodes": {"code": str},
"codecs": {"codec": str},
"states": {"country": str, "state": str},
"languages": {"language": str},
"tags": {"tag": str},
'countries': {'code': str},
'countrycodes': {'code': str},
'codecs': {'codec': str},
'states': {'country': str, 'state': str},
'languages': {'language': str},
'tags': {'tag': str},
}


Expand Down Expand Up @@ -59,14 +59,14 @@ def bool_to_string(b):
str: String representation of a bool type.
"""
s = str(b).lower()
if s in ["true", "false"]:
if s in ['true', 'false']:
return s
raise TypeError("Value must be True or False.")
raise TypeError('Value must be True or False.')


def snake_to_camel(s):
first, *others = s.split("_")
return "".join([first.lower(), *map(str.title, others)])
first, *others = s.split('_')
return ''.join([first.lower(), *map(str.title, others)])


def radio_browser_adapter(**kwargs):
Expand All @@ -88,10 +88,19 @@ def validate_input(types, input_data):
raise IllegalArgumentError(
"There is no paramter named '{}'".format(exc.args[0])
)
else:
if key in ("limit", "offset"):
if not str(value).isdigit():
raise TypeError(
'Argument {!r} must be {}, not {}'.format(
key,
"`int` or `str`",
type(value).__name__,
)
)
elif not isinstance(value, type_):
if not isinstance(value, type_):
raise TypeError(
"Argument {!r} must be {}, not {}".format(
'Argument {!r} must be {}, not {}'.format(
key,
type_.__name__,
type(value).__name__,
Expand Down
45 changes: 38 additions & 7 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,55 @@
import pytest

from pyradios.utils import types
from pyradios.utils import bool_to_string
from pyradios.utils import validate_input


@pytest.mark.parametrize(
"inp, expected",
[(True, "true"), (False, "false")]
)
@pytest.mark.parametrize('inp, expected', [(True, 'true'), (False, 'false')])
def test_bool_to_string(inp, expected):
assert bool_to_string(inp) == expected


@pytest.mark.parametrize(
"inp, expected",
'inp, expected',
[
("a", pytest.raises(TypeError)),
('a', pytest.raises(TypeError)),
(1, pytest.raises(TypeError)),
],
)
def test_bool_to_string_value_error(inp, expected):
with expected as exc_info:
bool_to_string(inp)
assert "Value must be True or False." == str(exc_info.value)
assert 'Value must be True or False.' == str(exc_info.value)


@pytest.mark.parametrize(
'input_data',
[{'limit': 10, 'offset': 0}, {'limit': '10', 'offset': '0'}],
)
def test_validate_input(input_data):
"""
Allow `str` and `int` for limit and offset
"""
validate_input(types['search'], input_data)


@pytest.mark.parametrize(
'input_data, expected',
[
({'limit': 10, 'offset': 'a'}, ('offset', '`int` or `str`', 'str')),
({'limit': 10.1}, ('limit', '`int` or `str`', 'float')),
(
{'offset': True, 'limit': None},
('offset', '`int` or `str`', 'bool'),
),
({'limit': None}, ('limit', '`int` or `str`', 'NoneType')),
],
)
def test_validate_input_with_invalid_limit_and_offset(input_data, expected):
with pytest.raises(TypeError) as exc:
validate_input(types['search'], input_data)

assert str(exc.value) == 'Argument {!r} must be {}, not {}'.format(
*expected
)

0 comments on commit d107de1

Please sign in to comment.