diff --git a/branca/utilities.py b/branca/utilities.py index 2d25e11..0db25f3 100644 --- a/branca/utilities.py +++ b/branca/utilities.py @@ -10,6 +10,7 @@ import json import math import os +import re import struct import zlib @@ -387,19 +388,22 @@ def _camelify(out): def _parse_size(value): - try: - if isinstance(value, int) or isinstance(value, float): - value_type = "px" - value = float(value) - assert value > 0 + if isinstance(value, (int, float)): + return float(value), "px" + elif isinstance(value, str): + # match digits or a point, possibly followed by a space, + # followed by a unit: either 1 to 5 letters or a percent sign + match = re.fullmatch(r"([\d.]+)\s?(\w{1,5}|%)", value.strip()) + if match: + return float(match.group(1)), match.group(2) else: - value_type = "%" - value = float(value.strip("%")) - assert 0 <= value <= 100 - except Exception: - msg = "Cannot parse value {!r} as {!r}".format - raise ValueError(msg(value, value_type)) - return value, value_type + raise ValueError( + f"Cannot parse {value!r}, it should be a number followed by a unit.", + ) + else: + raise TypeError( + f"Cannot parse {value!r}, it should be a number or a string containing a number and a unit.", + ) def _locations_mirror(x): diff --git a/tests/test_utilities.py b/tests/test_utilities.py index f2aeb9b..e51d3a2 100644 --- a/tests/test_utilities.py +++ b/tests/test_utilities.py @@ -104,3 +104,31 @@ def test_color_avoid_unexpected_error(): for n in [str(color_brewer_minimum_n), float(color_brewer_minimum_n), "abc"]: with pytest.raises(TypeError): ut.color_brewer(sname, n) + + +@pytest.mark.parametrize( + "value,result", + [ + (1, (1.0, "px")), + ("1 px", (1.0, "px")), + ("80 % ", (80.0, "%")), + ("100% ", (100.0, "%")), + ("3 vw", (3.0, "vw")), + ("3.14 rem", (3.14, "rem")), + ], +) +def test_parse_size(value, result): + assert ut._parse_size(value) == result + + +@pytest.mark.parametrize( + "value", + [ + "what?", + "1.21 jigawatts", + ut._parse_size, + ], +) +def test_parse_size_exceptions(value): + with pytest.raises((ValueError, TypeError)): + ut._parse_size(value)