datawhalechina/hello-agents · warning · ValueError

单位必须是 'metric' 或 'imperial'

Error message

单位必须是 'metric' 或 'imperial'

What it means

ValueError raised by WeatherClient.set_unit when the unit argument is not exactly 'metric' or 'imperial'. The unit is passed straight into the OpenWeather 'units' query parameter, and the API only accepts those two literals ('standard' would also be valid for OpenWeather but is deliberately excluded here). Case matters: 'Metric' or 'METRIC' raise.

Source

Thrown at Co-creation-projects/allen2000-FashionDailyDress/weather.py:136

        :return: 格式化后的天气信息字符串
        """
        weather_data = self._parse_weather_data(data)
        
        return (
            f"🏙️ 城市: {weather_data['city']}\n"
            f"🌡️ 温度: {weather_data['temperature']}{weather_data['temperature_unit']}\n"
            f"📝 天气: {weather_data['description']}\n"
            f"💧 湿度: {weather_data['humidity']}%\n"
            f"🌬️ 风速: {weather_data['wind_speed']} {weather_data['wind_unit']}"
        )
    
    def set_unit(self, unit):
        """
        设置温度单位
        :param unit: 温度单位(metric=摄氏,imperial=华氏)
        """
        if unit not in ['metric', 'imperial']:
            raise ValueError("单位必须是 'metric' 或 'imperial'")
        self.unit = unit
    
    def set_api_key(self, api_key):
        """
        设置API密钥
        :param api_key: 新的API密钥
        """
        self.api_key = api_key


def get_weather(city_name, api_key=os.environ.get("OPENWEATHER_API_KEY"), unit='metric'):
    """
    向后兼容的函数,使用Weather类实现
    :param city_name: 城市名称(英文)
    :param api_key: 你的OpenWeatherMap API密钥
    :param unit: 温度单位(metric=摄氏,imperial=华氏)
    :return: 格式化后的天气信息
    """

View on GitHub (pinned to 606a07d341)

Solutions

  1. Normalize before validating: unit = unit.strip().lower() and map synonyms ('c','celsius','℃' -> 'metric'; 'f','fahrenheit','℉' -> 'imperial')
  2. Use a Literal/Enum at the boundary so invalid values are rejected with a clear message earlier
  3. If 'standard' (Kelvin) should be supported, add it to the allowed set and update the display logic at line 107 which currently assumes a metric/imperial binary

Example fix

# before
def set_unit(self, unit):
    if unit not in ['metric', 'imperial']:
        raise ValueError("单位必须是 'metric' 或 'imperial'")
    self.unit = unit

# after
_UNIT_ALIASES = {
    'metric': 'metric', 'c': 'metric', 'celsius': 'metric', '℃': 'metric',
    'imperial': 'imperial', 'f': 'imperial', 'fahrenheit': 'imperial', '℉': 'imperial',
}

def set_unit(self, unit):
    unit = _UNIT_ALIASES.get(str(unit).strip().lower())
    if unit is None:
        raise ValueError(
            "单位必须是 'metric' 或 'imperial'(接受别名 c/celsius/f/fahrenheit)"
        )
    self.unit = unit
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED_UNITS = ('metric', 'imperial')

def normalize_unit(unit: str) -> str | None:
    u = str(unit).strip().lower()
    return u if u in ALLOWED_UNITS else None

unit = normalize_unit(raw)
if unit is None:
    # reject / re-prompt before touching the client
    ...

Type guard

from typing import Literal

Unit = Literal['metric', 'imperial']

def is_unit(v) -> bool:
    return v in ('metric', 'imperial')

Try / catch

try:
    client.set_unit(raw_unit)
except ValueError:
    client.set_unit('metric')  # safe default
    notify_user('unrecognized unit, using Celsius')

Prevention

When it happens

Trigger: set_unit('c'), set_unit('C'), set_unit('celsius'), set_unit('standard'), set_unit('Metric') — all raise; user-config or LLM-provided unit strings not normalized before the call; uppercase values from an enum or CLI flag; passing the display symbol '°C'.

Common situations: Dress-recommendation agent letting a user say '摄氏' or 'C' and forwarding it raw; config file storing unit as 'Celsius'; CLI accepting --unit without validation.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/1dd4af5c6406b156. Report an issue: GitHub.