Source code for woob.capabilities.weather

# Copyright(C) 2010-2011 Romain Bignon
#
# This file is part of woob.
#
# woob is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# woob is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with woob. If not, see <http://www.gnu.org/licenses/>.


from datetime import date, datetime

from .base import (
    BaseObject,
    Capability,
    Enum,
    EnumField,
    Field,
    FloatField,
    IntField,
    NotLoaded,
    StringField,
    UserError,
)
from .date import DateField


__all__ = [
    "Forecast",
    "Current",
    "City",
    "CityNotFound",
    "Temperature",
    "CapWeather",
    "BaseWeather",
    "Direction",
    "Precipitation",
]


[docs]class Direction(Enum): S = "South" N = "North" E = "East" W = "West" SE = "Southeast" SW = "Southwest" NW = "Northwest" NE = "Northeast" SSE = "South-Southeast" SSW = "South-Southwest" NNW = "North-Northwest" NNE = "North-Northeast" ESE = "East-Southeast" ENE = "East-Northeast" WSW = "West-Southwest" WNW = "West-Northwest" Variable = "Variable"
# METAR keys
[docs]class Precipitation(Enum): RA = "Rain" SN = "Snow" GR = "Hail" PL = "Ice pellets" GS = "Small hail" DZ = "Drizzle" IC = "Ice cristals" SG = "Small grains" UP = "Unknown precipiation"
[docs]class Temperature(BaseObject): value = FloatField("Temperature value") unit = StringField("Input unit") def __init__(self, value=NotLoaded, unit="", url=None): super().__init__(str(value), url) self.value = value if unit not in ["C", "F"]: unit = "" self.unit = unit
[docs] def asfahrenheit(self): if not self.unit: return "%s" % int(round(self.value)) elif self.unit == "F": return "%s °F" % int(round(self.value)) else: return "%s °F" % int(round((self.value * 9.0 / 5.0) + 32))
[docs] def ascelsius(self): if not self.unit: return "%s" % int(round(self.value)) elif self.unit == "C": return "%s °C" % int(round(self.value)) else: return "%s °C" % int(round((self.value - 32.0) * 5.0 / 9.0))
def __repr__(self): if self.value is not None and self.unit: return f"{self.value!r} {self.unit!r}" return ""
[docs]class BaseWeather(BaseObject): precipitation = EnumField("Precipitation type", Precipitation) precipitation_probability = FloatField("Probability of precipitation (ratio)") wind_direction = EnumField("Wind direction", Direction) wind_speed = FloatField("Wind speed (in km/h)") humidity = FloatField("Relative humidity (ratio)") pressure = FloatField("Atmospheric pressure (in hPa)") visibility = FloatField("Horizontal visibility distance (in km)") cloud = IntField("Cloud coverage (in okta (0-8))")
[docs]class Forecast(BaseWeather): """ Weather forecast. """ date = Field("Date for the forecast", datetime, date, str) low = Field("Low temperature", Temperature) high = Field("High temperature", Temperature) text = StringField("Comment on forecast") def __init__(self, date=NotLoaded, low=None, high=None, text=None, unit=None, url=None): super().__init__(str(date or ""), url) self.date = date self.low = Temperature(low, unit) self.high = Temperature(high, unit) self.text = text
[docs]class Current(BaseWeather): """ Current weather. """ date = DateField("Date of measure") text = StringField("Comment about current weather") temp = Field("Current temperature", Temperature) def __init__(self, date=NotLoaded, temp=None, text=None, unit=None, url=None): super().__init__(str(date or ""), url) self.date = date self.text = text self.temp = Temperature(temp, unit)
[docs]class City(BaseObject): """ City where to find weather. """ name = StringField("Name of city") def __init__(self, id="", name=None, url=None): super().__init__(id, url) self.name = name
[docs]class CityNotFound(UserError): """ Raised when a city is not found. """
[docs]class CapWeather(Capability): """ Capability for weather websites. """
[docs] def get_current(self, city_id): """ Get current weather. :param city_id: ID of the city :rtype: :class:`Current` """ raise NotImplementedError()
[docs] def iter_forecast(self, city_id): """ Iter forecasts of a city. :param city_id: ID of the city :rtype: iter[:class:`Forecast`] """ raise NotImplementedError()