feat(weather): wehaer value sky model instead of text cloudness
This commit is contained in:
@@ -16,6 +16,7 @@ RUN apt update && \
|
||||
dpkg-reconfigure --frontend=noninteractive locales
|
||||
ENV LANG=ru_RU.UTF-8
|
||||
ENV LC_ALL=ru_RU.UTF-8
|
||||
ENV TZ="Europe/Moscow"
|
||||
COPY --from=builder /app ./
|
||||
COPY gismeteo gismeteo/
|
||||
COPY weather weather/
|
||||
|
||||
@@ -10,7 +10,7 @@ class LocationValue(NamedTuple):
|
||||
|
||||
@classmethod
|
||||
def parse(cls, source: str) -> "LocationValue":
|
||||
location, name = source.split("-")
|
||||
name, location = source.split("-")
|
||||
return cls(int(location), name)
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ from typing import Dict, Iterable, List, Optional
|
||||
import dateparser
|
||||
from bs4 import Tag
|
||||
|
||||
from weather.model import Cloudness, Precipitation, Sky, WindDirection
|
||||
|
||||
from .core import BaseWidgetParser, RowParser
|
||||
|
||||
ONE_DAY_PARSER = BaseWidgetParser(".widget.widget-oneday .widget-items")
|
||||
@@ -40,12 +42,45 @@ class DateParser(RowParser[datetime.datetime]):
|
||||
yield time
|
||||
|
||||
|
||||
class CloudnessParser(RowParser[str]):
|
||||
KEY = "cloudness"
|
||||
class SkyParser(RowParser[Sky]):
|
||||
KEY = "sky"
|
||||
|
||||
def parse_row(self, tag: Tag) -> Iterable[str]:
|
||||
CLOUDNESS_MAP: Dict[str, Cloudness] = {
|
||||
"ясно": Cloudness.CLEAR,
|
||||
"малооблачно": Cloudness.PARTLY_CLOUDY,
|
||||
"облачно": Cloudness.CLOUDY,
|
||||
"пасмурно": Cloudness.MAINLY_CLOUDY,
|
||||
}
|
||||
|
||||
PRECIPITATION_MAP: Dict[str, Precipitation] = {
|
||||
"без осадков": Precipitation.NO,
|
||||
"небольшой дождь": Precipitation.SMALL_RAIN,
|
||||
"дождь": Precipitation.RAIN,
|
||||
"ливень": Precipitation.SHOWER,
|
||||
}
|
||||
|
||||
def parse_row(self, tag: Tag) -> Iterable[Sky]:
|
||||
for item in tag.select(".widget-row[data-row=icon-tooltip] > .row-item"):
|
||||
yield item.attrs["data-tooltip"]
|
||||
sky_str = item.attrs["data-tooltip"]
|
||||
values = {item.strip().lower() for item in sky_str.split(",")}
|
||||
cloudness = Cloudness.CLEAR
|
||||
precipitation = Precipitation.NO
|
||||
thunder = "гроза" in values
|
||||
fog = "дымка" in values
|
||||
for k, v in self.CLOUDNESS_MAP.items():
|
||||
if k in values:
|
||||
cloudness = v
|
||||
break
|
||||
for k, v in self.PRECIPITATION_MAP.items():
|
||||
if k in values:
|
||||
precipitation = v
|
||||
break
|
||||
yield Sky(
|
||||
cloudness=cloudness,
|
||||
precipitation=precipitation,
|
||||
thunder=thunder,
|
||||
fog=fog,
|
||||
)
|
||||
|
||||
|
||||
class TemperatureParser(RowParser[int]):
|
||||
@@ -77,14 +112,27 @@ class WindGustParser(RowParser[int]):
|
||||
yield int(value.attrs["value"]) if value else 0
|
||||
|
||||
|
||||
class WindDirectionParser(RowParser[str]):
|
||||
class WindDirectionParser(RowParser[WindDirection]):
|
||||
KEY = "wind_direction"
|
||||
|
||||
def parse_row(self, tag: Tag) -> Iterable[str]:
|
||||
WIND_DIRECTION_MAP: Dict[str, WindDirection] = {
|
||||
"штиль": WindDirection.CALM,
|
||||
"с": WindDirection.N,
|
||||
"св": WindDirection.NO,
|
||||
"в": WindDirection.O,
|
||||
"юв": WindDirection.SO,
|
||||
"ю": WindDirection.S,
|
||||
"юз": WindDirection.SW,
|
||||
"з": WindDirection.W,
|
||||
"сз": WindDirection.NW,
|
||||
}
|
||||
|
||||
def parse_row(self, tag: Tag) -> Iterable[WindDirection]:
|
||||
for item in tag.select(
|
||||
".widget-row[data-row=wind-direction] > .row-item > .direction"
|
||||
):
|
||||
yield item.text
|
||||
wind_direction_str = item.text.lower()
|
||||
yield self.WIND_DIRECTION_MAP[wind_direction_str]
|
||||
|
||||
|
||||
class WindPrecipitationParser(RowParser[float]):
|
||||
@@ -117,7 +165,7 @@ class HumidityParser(RowParser[int]):
|
||||
|
||||
ROW_PARSERS: List[RowParser] = [
|
||||
DateParser(),
|
||||
CloudnessParser(),
|
||||
SkyParser(),
|
||||
TemperatureParser(),
|
||||
WindSpeedParser(),
|
||||
WindGustParser(),
|
||||
|
||||
@@ -1,21 +1,60 @@
|
||||
import datetime
|
||||
from enum import Enum
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class WeatherValue(BaseModel):
|
||||
class Model(BaseModel):
|
||||
class Config:
|
||||
use_enum_values = True
|
||||
|
||||
|
||||
class Cloudness(str, Enum):
|
||||
CLEAR = "clear"
|
||||
PARTLY_CLOUDY = "party_cloudy"
|
||||
CLOUDY = "cloudy"
|
||||
MAINLY_CLOUDY = "mainly_cloudy"
|
||||
|
||||
|
||||
class Precipitation(str, Enum):
|
||||
NO = "no"
|
||||
SMALL_RAIN = "small_rain"
|
||||
RAIN = "rain"
|
||||
SHOWER = "shower"
|
||||
|
||||
|
||||
class Sky(Model):
|
||||
cloudness: Cloudness
|
||||
precipitation: Precipitation
|
||||
thunder: bool
|
||||
fog: bool
|
||||
|
||||
|
||||
class WindDirection(str, Enum):
|
||||
CALM = "calm"
|
||||
N = "N"
|
||||
NO = "NO"
|
||||
O = "O"
|
||||
SO = "SO"
|
||||
S = "S"
|
||||
SW = "SW"
|
||||
W = "W"
|
||||
NW = "NW"
|
||||
|
||||
|
||||
class WeatherValue(Model):
|
||||
date: datetime.datetime
|
||||
cloudness: str
|
||||
sky: Sky
|
||||
temperature: int
|
||||
wind_speed: int
|
||||
wind_gust: int
|
||||
wind_direction: str
|
||||
wind_direction: WindDirection
|
||||
precipitation: float
|
||||
pressure: int
|
||||
humidity: int
|
||||
|
||||
|
||||
class WeatherResponse(BaseModel):
|
||||
class WeatherResponse(Model):
|
||||
location: str
|
||||
date: datetime.date
|
||||
period: str
|
||||
|
||||
@@ -1,38 +1,39 @@
|
||||
def wind_direction_icon(wind_direction: str) -> str:
|
||||
from weather.model import Cloudness, Precipitation, Sky, WindDirection
|
||||
|
||||
|
||||
def wind_direction_icon(wind_direction: WindDirection) -> str:
|
||||
return {
|
||||
"С": "🡫",
|
||||
"СВ": "🡯",
|
||||
"В": "🡨",
|
||||
"ЮВ": "🡬",
|
||||
"Ю": "🡡",
|
||||
"ЮЗ": "🡭",
|
||||
"З": "🡪",
|
||||
"СЗ": "🡦",
|
||||
"штиль": "",
|
||||
WindDirection.N: "🡫",
|
||||
WindDirection.NO: "🡯",
|
||||
WindDirection.O: "🡨",
|
||||
WindDirection.SO: "🡬",
|
||||
WindDirection.S: "🡡",
|
||||
WindDirection.SW: "🡭",
|
||||
WindDirection.W: "🡪",
|
||||
WindDirection.NW: "🡦",
|
||||
WindDirection.CALM: "",
|
||||
}.get(wind_direction, wind_direction)
|
||||
|
||||
|
||||
def cloudness_icon(cloudness: str) -> list[str]:
|
||||
icons = []
|
||||
values = {item.strip().lower() for item in cloudness.split(",")}
|
||||
if "дымка" in values:
|
||||
def cloudness_icon(sky: Sky) -> list[str]:
|
||||
main_icon = ""
|
||||
if sky.thunder:
|
||||
if sky.cloudness == Cloudness.CLEAR:
|
||||
main_icon = "🌩️"
|
||||
if sky.precipitation == Precipitation.NO:
|
||||
main_icon = "⚡"
|
||||
else:
|
||||
main_icon = "⛈️"
|
||||
elif sky.precipitation == Precipitation.NO:
|
||||
main_icon = {
|
||||
Cloudness.CLEAR: "☀️",
|
||||
Cloudness.PARTLY_CLOUDY: "🌤️",
|
||||
Cloudness.CLOUDY: "⛅",
|
||||
Cloudness.MAINLY_CLOUDY: "☁️",
|
||||
}[sky.cloudness]
|
||||
else:
|
||||
main_icon = "🌧️"
|
||||
icons = [main_icon]
|
||||
if sky.fog:
|
||||
icons.append("🌫️")
|
||||
values.remove("дымка")
|
||||
icons = [
|
||||
{
|
||||
frozenset(["ясно"]): "☀️",
|
||||
frozenset(["малооблачно", "без осадков"]): "🌤️",
|
||||
frozenset(["облачно", "без осадков"]): "⛅",
|
||||
frozenset(["малооблачно", "небольшой дождь"]): "🌦️",
|
||||
frozenset(["пасмурно", "без осадков"]): "☁️",
|
||||
frozenset(["облачно", "небольшой дождь"]): "🌧️",
|
||||
frozenset(["облачно", "дождь"]): "🌧️",
|
||||
frozenset(["облачно", "небольшой дождь", "гроза"]): "⛈️",
|
||||
frozenset(["малооблачно", "дождь"]): "🌦️",
|
||||
frozenset(["пасмурно", "небольшой дождь"]): "🌧️",
|
||||
frozenset(["облачно", "дождь", "гроза"]): "⛈️",
|
||||
frozenset(["пасмурно", "дождь"]): "🌧️",
|
||||
frozenset(["пасмурно", "дождь", "гроза"]): "⛈️",
|
||||
}.get(frozenset(values), "|".join(values))
|
||||
] + icons
|
||||
return icons
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<tr>
|
||||
{% for value in response.values %}
|
||||
<td class="cloudness">
|
||||
{% for icon in value.cloudness | cloudness_icon %}
|
||||
{% for icon in value.sky | cloudness_icon %}
|
||||
<div class="icon">{{icon}}</div>
|
||||
{% endfor %}
|
||||
</td>
|
||||
@@ -76,7 +76,6 @@
|
||||
{% for value in response.values %}
|
||||
<td class="wind">
|
||||
<span class="icon">{{value.wind_direction | wind_direction_icon}}</span>
|
||||
<span class="direction">{{value.wind_direction}}</span>
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user