feat: added parsing dimensions

main
Ricard Illa 2023-06-23 10:05:24 +02:00
parent 9c19835746
commit e716fc1cd3
2 changed files with 180 additions and 0 deletions

View File

@ -0,0 +1,67 @@
"""Functions to parse the dimensions string into a dictionary that represents
those dimenions in cm
"""
import logging
from typing import Dict, Optional
import re
UNIT_CONVERSIONS = {"inches": 2.54, "feet": 30.48, "cm": 1}
def parse_dimensions_measure(dimensions: str, measure: str) -> Optional[Dict]:
"""Using a regex, parse a measurement out of a dimensions string
I expect to find a value of the form `1.2 inches (W)` specifying the value,
unit and measurement.
Return a dictionary representing the parsed value and its unit.
"""
expr = rf"(?P<value>\d*[.,]?\d*)\s+(?P<unit>[a-zA-Z]*)\s+\({measure}\)"
if match := re.search(expr, dimensions):
match_value = match.group("value")
try:
value = float(match_value)
except ValueError:
logging.error("could not parse value `%s` as a float for a dimension")
return None
return {
"value": value,
"unit": match.group("unit").lower(),
}
return None
def units_to_cm(value: float, unit: str) -> Optional[float]:
"""Convert a given dimension unit into centimeters.
If unrecognized unit, return None"""
try:
conversion = UNIT_CONVERSIONS[unit]
except KeyError:
logging.error("unrecognized unit: %s", unit)
return None
return value * conversion
def parse_dimensions(dimensions: Optional[str]) -> Dict[str, Optional[float]]:
"""Parse a string representing dimensions"""
if dimensions is None:
return {
"height": None,
"width": None,
"depth": None,
}
height = parse_dimensions_measure(dimensions, "H")
width = parse_dimensions_measure(dimensions, "W")
depth = parse_dimensions_measure(dimensions, "D")
parsed_dimensions = {
"height": height,
"width": width,
"depth": depth,
}
result = {}
for key, value in parsed_dimensions.items():
if value is None:
result[key] = value
else:
result[key] = units_to_cm(**value)
return result

View File

@ -0,0 +1,113 @@
"""Test the `parse_dimensions` function and its helpers"""
from helpers.dimensions import parse_dimensions, parse_dimensions_measure, units_to_cm
def test_none():
"""Test None value"""
assert parse_dimensions(None) == {"height": None, "width": None, "depth": None}
def test_parse_dimensions():
"""Test a normal example from the sample file"""
dimensions_str = "23 inches (H) x 1 inches (W) x 23 inches (D)"
assert parse_dimensions_measure(dimensions_str, "W") == {
"unit": "inches",
"value": 1.0,
}
assert parse_dimensions_measure(dimensions_str, "H") == {
"unit": "inches",
"value": 23.0,
}
assert parse_dimensions_measure(dimensions_str, "D") == {
"unit": "inches",
"value": 23.0,
}
assert parse_dimensions(dimensions_str) == {
"depth": 58.42,
"height": 58.42,
"width": 2.54,
}
def test_parse_dimensions_comma():
"""Test a normal example from the sample file, but the separator is a comma"""
dimensions_str = "23 inches (H), 1 inches (W), 23 inches (D)"
assert parse_dimensions_measure(dimensions_str, "W") == {
"unit": "inches",
"value": 1.0,
}
assert parse_dimensions_measure(dimensions_str, "H") == {
"unit": "inches",
"value": 23.0,
}
assert parse_dimensions_measure(dimensions_str, "D") == {
"unit": "inches",
"value": 23.0,
}
assert parse_dimensions(dimensions_str) == {
"depth": 58.42,
"height": 58.42,
"width": 2.54,
}
def test_parse_dimensions_feet():
"""Test a normal example from the sample file, but the units is feet"""
dimensions_str = "23 feet (H) x 1 feet (W) x 23 feet (D)"
assert parse_dimensions_measure(dimensions_str, "W") == {
"unit": "feet",
"value": 1.0,
}
assert parse_dimensions_measure(dimensions_str, "H") == {
"unit": "feet",
"value": 23.0,
}
assert parse_dimensions_measure(dimensions_str, "D") == {
"unit": "feet",
"value": 23.0,
}
assert parse_dimensions(dimensions_str) == {
"depth": 701.04,
"height": 701.04,
"width": 30.48,
}
def test_parse_dimensions_missing():
"""Test a normal example from the sample file but some measurement is missing"""
dimensions_str = "23 inches (H) x 23 inches (D)"
assert parse_dimensions_measure(dimensions_str, "W") is None
assert parse_dimensions_measure(dimensions_str, "H") == {
"unit": "inches",
"value": 23.0,
}
assert parse_dimensions_measure(dimensions_str, "D") == {
"unit": "inches",
"value": 23.0,
}
assert parse_dimensions(dimensions_str) == {
"depth": 58.42,
"height": 58.42,
"width": None,
}
def test_units_to_cm_inches():
"""Test `units_to_cm` where the units is inches"""
assert units_to_cm(value=0.5, unit="inches") == 1.27
def test_units_to_cm_feet():
"""Test `units_to_cm` where the units is inches"""
assert units_to_cm(value=0.5, unit="feet") == 15.24
def test_units_to_cm_cm():
"""Test `units_to_cm` where the units is already cm"""
assert units_to_cm(value=0.5, unit="cm") == 0.5
def test_units_to_cm_unrecognized():
"""Test `units_to_cm` where the units are not recognized"""
assert units_to_cm(value=0.5, unit="yard") is None