Skip to content

Commit 64c2cb9

Browse files
committed
Weather command/tests. Finally Whispers.
1 parent a6fbeab commit 64c2cb9

File tree

31 files changed

+3476
-397
lines changed

31 files changed

+3476
-397
lines changed

bot/apis/weather/open_meteo/models.py

Lines changed: 497 additions & 250 deletions
Large diffs are not rendered by default.

bot/apis/weather/open_meteo/open_meteo.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,21 @@ async def forecast(
111111
timezone=timezone,
112112
)
113113
data = await self._request(url=url)
114-
return Forecast.model_validate(data)
114+
return Forecast(data)
115115

116116
async def geocoding(self, *, name: str, language: str = "en") -> Geocoding:
117117
url = URL("https://nominatim.openstreetmap.org/search.php").with_query(
118-
q=name, # name=name,
118+
q=name,
119119
# count=count,
120120
language=language,
121121
format="jsonv2",
122+
addressdetails=1,
123+
extratags=1,
124+
namedetails=1,
125+
entrances=1
122126
)
123127
data = await self._request(url=url)
124-
return Geocoding.model_validate({"results": data})
128+
return Geocoding({"results": data})
125129

126130
async def close(self) -> None:
127131
"""Close open client session."""

bot/bot.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

3030
from bot.ext import Context
3131

32+
# quit(0)
33+
3234

3335
class Gorenmu(TypesBot):
3436
def __init__(self, configs: Config, case_insensitive: bool, log: Logger, adapter) -> None:
@@ -73,7 +75,7 @@ async def event_ready(self) -> None:
7375

7476
@commands.Component.listener("Whisper")
7577
async def event_message_whisper(self, payload: twitchio.Whisper):
76-
return await self.event_message_whisper(payload)
78+
return await self.LifecycleHandler.event_message_whisper(payload)
7779

7880
async def global_guard(self, ctx: Context) -> bool:
7981
return await self.LifecycleHandler.global_guard(ctx)

bot/cogs/accountage/command/translations.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from typing import TYPE_CHECKING
44

5-
from bot.ext import Admonitions, CommandExemples, Response, TranslationBase
5+
from bot.ext import CommandExemples, Response, TranslationBase
66
from bot.ext.translations.extras import TBase
77

88
if TYPE_CHECKING:
@@ -99,10 +99,4 @@ def deco_commands(self, ctx: Context, *args, **kwargs) -> CommandExemples:
9999
)
100100
return self._untangle_commands(ctx, self._cname)
101101

102-
def deco_admonitions(self, ctx: Context, *args, **kwargs) -> Admonitions:
103-
with self.lang_dict.once(self._cname):
104-
self.lang_dict.add_with("en", Admonitions([]))
105-
self.lang_dict.add_with(["pt_br", "pt"], Admonitions([]))
106-
return self._untangle_admonitions(ctx, self._cname)
107-
108102
AccountAge: AccountAge

bot/cogs/set/command/set.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ async def set_mention(self, ctx: Context, *, args: str) -> Response:
4545
@set.command(name="city", aliases=["savecity", "savelocation", "location"])
4646
async def set_city(self, ctx: Context, *, args: str) -> Response:
4747
translations = self.translations.City
48-
args, hidden = self.StringTools.extract_and_remove_field(args, "hidden")
48+
args, hidden = self.StringTools.extract_and_remove_bool_field(args, "hidden", self.translations, ctx)
4949
city = args.lower()
50-
if hidden:
51-
ctx.user.city_hidden = True
50+
ctx.user.city_hidden = True
51+
if hidden is False:
52+
ctx.user.city_hidden = False
5253
if city == "remove":
5354
ctx.user.city = None
5455
await ctx.user.save()

bot/cogs/weather/__init__.py

Whitespace-only changes.

bot/cogs/weather/command/__init__.py

Whitespace-only changes.

bot/cogs/weather/command/translations.py

Lines changed: 342 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
from __future__ import annotations
2+
3+
import datetime
4+
from typing import TYPE_CHECKING
5+
6+
from bot.apis.weather import DailyParameters, HourlyParameters, OpenMeteo
7+
from bot.ext import Context, Response, commands
8+
from bot.models import User
9+
from bot.utils import SessionsCaches, StringTools
10+
11+
from .translations import Translations
12+
13+
if TYPE_CHECKING:
14+
from bot.bot import Gorenmu
15+
16+
17+
class WeatherCmd(commands.CustomComponent):
18+
def __init__(self, bot: Gorenmu) -> None:
19+
self.bot = bot
20+
self.translations: Translations = Translations(bot)
21+
self.SessionsCaches: SessionsCaches = SessionsCaches(bot)
22+
self.StringTools: StringTools = StringTools()
23+
24+
cooldown_rate = 3
25+
cooldown_per = 10
26+
cooldown_key = commands.BucketType.user
27+
28+
async def component_command_error(self, payload: commands.CommandErrorPayload) -> bool | None: ...
29+
30+
@commands.Component.guard()
31+
def guards_component(self, ctx: commands.Context) -> bool: # NOQA
32+
return True
33+
34+
@commands.command(name='weather', aliases=['wt'])
35+
async def weather(self, ctx: Context, *, location: str = "") -> Response:
36+
from_chat = True
37+
location, from_user = self.StringTools.extract_and_remove_field(location, "user", False)
38+
user = None
39+
if from_user:
40+
user = await User.get_user_or_none(ctx, self.translations, name=from_user)
41+
if not user:
42+
return self.translations.Exceptions.user_not_found_name(ctx, name=from_user)
43+
if not user.city:
44+
return self.translations.Weather.user_has_no_city(ctx, from_user)
45+
from_chat = False
46+
location = user.city
47+
if ctx.user.city and not location:
48+
location = ctx.user.city
49+
from_chat = False
50+
51+
is_private = not from_chat and (user or ctx.user).city_hidden
52+
safe_location_name = self.translations.Weather.hidden(ctx) if is_private else location
53+
if not location:
54+
return self.translations.Weather.city_not_passed(ctx)
55+
56+
meteo = OpenMeteo(self.SessionsCaches.Weather.session)
57+
try:
58+
async with meteo as open_meteo:
59+
geocoding_result = await open_meteo.geocoding(name=location)
60+
if geocoding_result.results:
61+
city = geocoding_result.results[0]
62+
else:
63+
return self.translations.Weather.city_not_found(ctx, safe_location_name)
64+
except Exception as e:
65+
ctx.bot.log.error(e)
66+
return self.translations.Weather.city_not_found(ctx, safe_location_name)
67+
68+
async with meteo as open_meteo:
69+
weather_obj = await open_meteo.forecast(
70+
latitude=city.latitude,
71+
longitude=city.longitude,
72+
current_weather=True,
73+
daily=[
74+
DailyParameters.SUNRISE,
75+
DailyParameters.SUNSET,
76+
DailyParameters.PRECIPITATION_HOURS,
77+
DailyParameters.TEMPERATURE_2M_MAX,
78+
],
79+
hourly=[
80+
HourlyParameters.APPARENT_TEMPERATURE,
81+
HourlyParameters.TEMPERATURE_2M,
82+
HourlyParameters.RELATIVE_HUMIDITY_2M,
83+
HourlyParameters.PRESSURE_MSL,
84+
HourlyParameters.WIND_SPEED_10M,
85+
HourlyParameters.PRECIPITATION,
86+
HourlyParameters.IS_DAY,
87+
],
88+
)
89+
if not weather_obj.current_weather:
90+
return self.translations.Weather.no_weather_found(ctx, safe_location_name)
91+
hour = weather_obj.hourly.time
92+
index = min(range(len(hour)), key=lambda i: abs(hour[i] - datetime.datetime.now()))
93+
94+
weather_str, emoji = self.translations.Weather.weather_from_codes(
95+
ctx, weather_obj.current_weather.weather_code, weather_obj.hourly.is_day[index]
96+
)
97+
wind_direction = self.translations.Weather.weather_wind_direction(
98+
ctx, weather_obj.current_weather.wind_direction, True
99+
)
100+
101+
return self.translations.Weather.weather(
102+
ctx,
103+
weather_obj=weather_obj,
104+
index=index,
105+
city_name=safe_location_name if is_private else city.display,
106+
weather_str=weather_str,
107+
emoji=emoji,
108+
wind_direction=wind_direction,
109+
)
110+
111+
112+
async def setup(bot: Gorenmu) -> None:
113+
await bot.add_component(WeatherCmd(bot))
114+
115+
116+
async def teardown(bot: Gorenmu) -> None: ... # NOQA

bot/cogs/weather/extras/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)