diff options
| author | Markus Heiser <markus.heiser@darmarit.de> | 2025-10-07 15:47:03 +0200 |
|---|---|---|
| committer | Markus Heiser <markus.heiser@darmarIT.de> | 2025-10-08 13:47:22 +0200 |
| commit | d16283d93a7b7b691bf12c13db1f1020829b4278 (patch) | |
| tree | be95a529032b4c53505cdf12c7cbe3d454a45762 /searx | |
| parent | 8fdc59a7604cd661638586ff0381530da86eb76c (diff) | |
[fix:py3.14] using a non-empty mutable collection as default is unsafe
Starting with Python 3.14 msgspec reports::
File "/share/searxng/searx/weather.py", line 261, in <module>
class Temperature(msgspec.Struct, kw_only=True):
...<60 lines>...
return template.format(value=val_str, unit=unit)
TypeError: Using a non-empty mutable collection (['°C', '°F', 'K']) \
as a default value is unsafe.\
Instead configure a `default_factory` for this field.
The problem is solved by the fact that there are now global constants for the
units (BTW singular/plural names of the type definitions are fixed):
- TEMPERATURE_UNITS
- PRESSURE_UNITS
- WIND_SPEED_UNITS
- RELATIVE_HUMIDITY_UNITS
- COMPASS_POINTS
- COMPASS_UNITS
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
Diffstat (limited to 'searx')
| -rw-r--r-- | searx/weather.py | 63 |
1 files changed, 37 insertions, 26 deletions
diff --git a/searx/weather.py b/searx/weather.py index 449b261ae..429758055 100644 --- a/searx/weather.py +++ b/searx/weather.py @@ -255,7 +255,8 @@ class DateTime(msgspec.Struct): return babel.dates.format_date(self.datetime, format=fmt, locale=locale) -TemperatureUnits: t.TypeAlias = t.Literal["°C", "°F", "K"] +TemperatureUnit: t.TypeAlias = t.Literal["°C", "°F", "K"] +TEMPERATURE_UNITS: t.Final[tuple[TemperatureUnit]] = t.get_args(TemperatureUnit) class Temperature(msgspec.Struct, kw_only=True): @@ -263,19 +264,19 @@ class Temperature(msgspec.Struct, kw_only=True): measured values.""" val: float - unit: TemperatureUnits + unit: TemperatureUnit si_name: t.ClassVar[str] = "Q11579" - units: t.ClassVar[list[str]] = list(t.get_args(TemperatureUnits)) + UNITS: t.ClassVar[tuple[TemperatureUnit]] = TEMPERATURE_UNITS def __post_init__(self): - if self.unit not in self.units: + if self.unit not in self.UNITS: raise ValueError(f"invalid unit: {self.unit}") def __str__(self): return self.l10n() - def value(self, unit: TemperatureUnits) -> float: + def value(self, unit: TemperatureUnit) -> float: if unit == self.unit: return self.val si_val = convert_to_si(si_name=self.si_name, symbol=self.unit, value=self.val) @@ -283,7 +284,7 @@ class Temperature(msgspec.Struct, kw_only=True): def l10n( self, - unit: TemperatureUnits | None = None, + unit: TemperatureUnit | None = None, locale: babel.Locale | GeoLocation | None = None, template: str = "{value} {unit}", num_pattern: str = "#,##0", @@ -322,7 +323,8 @@ class Temperature(msgspec.Struct, kw_only=True): return template.format(value=val_str, unit=unit) -PressureUnits: t.TypeAlias = t.Literal["Pa", "hPa", "cm Hg", "bar"] +PressureUnit: t.TypeAlias = t.Literal["Pa", "hPa", "cm Hg", "bar"] +PRESSURE_UNITS: t.Final[tuple[PressureUnit]] = t.get_args(PressureUnit) class Pressure(msgspec.Struct, kw_only=True): @@ -330,19 +332,19 @@ class Pressure(msgspec.Struct, kw_only=True): measured values.""" val: float - unit: PressureUnits + unit: PressureUnit si_name: t.ClassVar[str] = "Q44395" - units: t.ClassVar[list[str]] = list(t.get_args(PressureUnits)) + UNITS: t.ClassVar[tuple[PressureUnit]] = PRESSURE_UNITS def __post_init__(self): - if self.unit not in self.units: + if self.unit not in self.UNITS: raise ValueError(f"invalid unit: {self.unit}") def __str__(self): return self.l10n() - def value(self, unit: PressureUnits) -> float: + def value(self, unit: PressureUnit) -> float: if unit == self.unit: return self.val si_val = convert_to_si(si_name=self.si_name, symbol=self.unit, value=self.val) @@ -350,7 +352,7 @@ class Pressure(msgspec.Struct, kw_only=True): def l10n( self, - unit: PressureUnits | None = None, + unit: PressureUnit | None = None, locale: babel.Locale | GeoLocation | None = None, template: str = "{value} {unit}", num_pattern: str = "#,##0", @@ -367,7 +369,8 @@ class Pressure(msgspec.Struct, kw_only=True): return template.format(value=val_str, unit=unit) -WindSpeedUnits: t.TypeAlias = t.Literal["m/s", "km/h", "kn", "mph", "mi/h", "Bft"] +WindSpeedUnit: t.TypeAlias = t.Literal["m/s", "km/h", "kn", "mph", "mi/h", "Bft"] +WIND_SPEED_UNITS: t.Final[tuple[WindSpeedUnit]] = t.get_args(WindSpeedUnit) class WindSpeed(msgspec.Struct, kw_only=True): @@ -382,19 +385,19 @@ class WindSpeed(msgspec.Struct, kw_only=True): """ val: float - unit: WindSpeedUnits + unit: WindSpeedUnit si_name: t.ClassVar[str] = "Q182429" - units: t.ClassVar[list[str]] = list(t.get_args(WindSpeedUnits)) + UNITS: t.ClassVar[tuple[WindSpeedUnit]] = WIND_SPEED_UNITS def __post_init__(self): - if self.unit not in self.units: + if self.unit not in self.UNITS: raise ValueError(f"invalid unit: {self.unit}") def __str__(self): return self.l10n() - def value(self, unit: WindSpeedUnits) -> float: + def value(self, unit: WindSpeedUnit) -> float: if unit == self.unit: return self.val si_val = convert_to_si(si_name=self.si_name, symbol=self.unit, value=self.val) @@ -402,7 +405,7 @@ class WindSpeed(msgspec.Struct, kw_only=True): def l10n( self, - unit: WindSpeedUnits | None = None, + unit: WindSpeedUnit | None = None, locale: babel.Locale | GeoLocation | None = None, template: str = "{value} {unit}", num_pattern: str = "#,##0", @@ -419,7 +422,8 @@ class WindSpeed(msgspec.Struct, kw_only=True): return template.format(value=val_str, unit=unit) -RelativeHumidityUnits: t.TypeAlias = t.Literal["%"] +RelativeHumidityUnit: t.TypeAlias = t.Literal["%"] +RELATIVE_HUMIDITY_UNITS: t.Final[tuple[RelativeHumidityUnit]] = t.get_args(RelativeHumidityUnit) class RelativeHumidity(msgspec.Struct): @@ -428,8 +432,12 @@ class RelativeHumidity(msgspec.Struct): val: float # there exists only one unit (%) --> set "%" as the final value (constant) - unit: t.ClassVar["t.Final[RelativeHumidityUnits]"] = "%" - units: t.ClassVar[list[str]] = list(t.get_args(RelativeHumidityUnits)) + unit: t.ClassVar[RelativeHumidityUnit] = "%" + UNITS: t.ClassVar[tuple[RelativeHumidityUnit]] = RELATIVE_HUMIDITY_UNITS + + def __post_init__(self): + if self.unit not in self.UNITS: + raise ValueError(f"invalid unit: {self.unit}") def __str__(self): return self.l10n() @@ -457,20 +465,23 @@ CompassPoint: t.TypeAlias = t.Literal[ "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW" ] """Compass point type definition""" +COMPASS_POINTS: t.Final[tuple[CompassPoint]] = t.get_args(CompassPoint) -CompassUnits: t.TypeAlias = t.Literal["°", "Point"] +CompassUnit: t.TypeAlias = t.Literal["°", "Point"] +COMPASS_UNITS: t.Final[tuple[CompassUnit]] = t.get_args(CompassUnit) class Compass(msgspec.Struct): """Class for converting compass points and azimuth values (360°)""" val: "float | int | CompassPoint" - unit: CompassUnits = "°" + unit: CompassUnit = "°" + UNITS: t.ClassVar[tuple[CompassUnit]] = COMPASS_UNITS TURN: t.ClassVar[float] = 360.0 """Full turn (360°)""" - POINTS: t.ClassVar[list[CompassPoint]] = list(t.get_args(CompassPoint)) + POINTS: t.ClassVar[tuple[CompassPoint]] = COMPASS_POINTS """Compass points.""" RANGE: t.ClassVar[float] = TURN / len(POINTS) @@ -488,7 +499,7 @@ class Compass(msgspec.Struct): def __str__(self): return self.l10n() - def value(self, unit: CompassUnits): + def value(self, unit: CompassUnit): if unit == "Point" and isinstance(self.val, float): return self.point(self.val) if unit == "°": @@ -507,7 +518,7 @@ class Compass(msgspec.Struct): def l10n( self, - unit: CompassUnits = "Point", + unit: CompassUnit = "Point", locale: babel.Locale | GeoLocation | None = None, template: str = "{value}{unit}", num_pattern: str = "#,##0", |