Source code for usda_fdc.utils

"""
Utility functions for the USDA FDC client.
"""

import re
from typing import Dict, Any, Optional, Tuple, Union
from pint import UnitRegistry, UndefinedUnitError, DimensionalityError

# Initialize unit registry
ureg = UnitRegistry()

# Define common food measurement units
ureg.define('serving = 1 = serving')
ureg.define('cup = 236.588 * milliliter = cup')
ureg.define('tablespoon = 14.7868 * milliliter = tbsp')
ureg.define('teaspoon = 4.92892 * milliliter = tsp')
ureg.define('ounce = 28.3495 * gram = oz')
ureg.define('pound = 453.592 * gram = lb')
ureg.define('slice = 1 = slice')
ureg.define('piece = 1 = piece')


[docs]def parse_unit_and_value(measurement_str: str) -> Tuple[float, str]: """ Parse a measurement string into a value and unit. Args: measurement_str: A string containing a measurement (e.g., "100 g", "1 cup"). Returns: A tuple of (value, unit). """ # Match patterns like "100g", "100 g", "1.5cups", "1.5 cups", "1/2 cup", etc. pattern = r'([\d./]+)\s*([a-zA-Z]+)' match = re.match(pattern, measurement_str) if not match: raise ValueError(f"Could not parse measurement: {measurement_str}") value_str, unit = match.groups() # Handle fractions if '/' in value_str: num, denom = value_str.split('/') value = float(num) / float(denom) else: value = float(value_str) return value, unit
[docs]def convert_to_grams(amount: float, unit: str) -> float: """ Convert a measurement to grams. Args: amount: The amount to convert. unit: The unit to convert from. Returns: The equivalent amount in grams. Raises: ValueError: If the unit cannot be converted to grams. """ try: # Try to convert to grams quantity = amount * ureg(unit) return quantity.to('gram').magnitude except (UndefinedUnitError, DimensionalityError) as e: raise ValueError(f"Cannot convert {unit} to grams: {str(e)}")
[docs]def convert_to_milliliters(amount: float, unit: str) -> float: """ Convert a measurement to milliliters. Args: amount: The amount to convert. unit: The unit to convert from. Returns: The equivalent amount in milliliters. Raises: ValueError: If the unit cannot be converted to milliliters. """ try: # Try to convert to milliliters quantity = amount * ureg(unit) return quantity.to('milliliter').magnitude except (UndefinedUnitError, DimensionalityError) as e: raise ValueError(f"Cannot convert {unit} to milliliters: {str(e)}")
[docs]def convert_measurement( amount: float, from_unit: str, to_unit: str ) -> float: """ Convert a measurement from one unit to another. Args: amount: The amount to convert. from_unit: The unit to convert from. to_unit: The unit to convert to. Returns: The converted amount. Raises: ValueError: If the conversion is not possible. """ try: quantity = amount * ureg(from_unit) return quantity.to(to_unit).magnitude except (UndefinedUnitError, DimensionalityError) as e: raise ValueError(f"Cannot convert {from_unit} to {to_unit}: {str(e)}")
[docs]def normalize_nutrient_value( value: float, unit: str, target_unit: str = 'g' ) -> Tuple[float, str]: """ Normalize a nutrient value to a standard unit. Args: value: The nutrient value. unit: The unit of the nutrient value. target_unit: The target unit to normalize to. Returns: A tuple of (normalized_value, normalized_unit). """ # Map of common unit conversions unit_map = { 'G': 'g', 'MG': 'mg', 'UG': 'µg', 'IU': 'IU', 'KCAL': 'kcal', 'KJ': 'kJ', } # Normalize the unit normalized_unit = unit_map.get(unit.upper(), unit.lower()) # If the normalized unit is already the target unit, return as is if normalized_unit == target_unit: return value, normalized_unit # Try to convert the value to the target unit try: converted_value = convert_measurement(value, normalized_unit, target_unit) return converted_value, target_unit except ValueError: # If conversion fails, return the original value and normalized unit return value, normalized_unit