Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion prek.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ hooks = [{ id = "gitleaks" }]

[[repos]]
repo = "https://github.com/astral-sh/ruff-pre-commit"
rev = "01a675ea018f2fb714478a5ffb83fcea8374bb06" # frozen: v0.15.21
rev = "cb8c523fd4835aba42af70f4cad5568db4df0b6c" # frozen: v0.16.0
hooks = [
{ id = "ruff-check", args = ["--fix"] },
{ id = "ruff-format" }
Expand Down
1 change: 1 addition & 0 deletions tests/test_any_llm_provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ async def test_any_llm_provider_assesses_notification_value_with_a_narrow_schema
)
async def test_factory_normalizes_provider_native_request_errors( # noqa: PLR0913
monkeypatch,
*,
provider_name: str,
error_factory: Callable[[httpx.Response], Exception],
operation: str,
Expand Down
16 changes: 10 additions & 6 deletions tests/test_geocoding.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,9 +501,11 @@ def handler(request: httpx.Request) -> httpx.Response:
[
'"invalid"',
'{"id":"example","name":"Example"}',
'{"id":"example","name":"Example","latitude":1,"longitude":2,'
'"country_code":null,"administrative_area":null,"timezone":null,'
'"is_mainland_china":false,"summary_language":"english"}',
(
'{"id":"example","name":"Example","latitude":1,"longitude":2,'
'"country_code":null,"administrative_area":null,"timezone":null,'
'"is_mainland_china":false,"summary_language":"english"}'
),
],
)
async def test_resolver_rejects_invalid_cached_reverse_record(tmp_path: Path, cached: str) -> None:
Expand All @@ -527,9 +529,11 @@ async def test_resolver_rejects_invalid_cached_reverse_record(tmp_path: Path, ca
"cached",
[
'{"id":"example","name":"Example"}',
'{"id":"example","name":"Example","latitude":1,"longitude":2,'
'"country_code":null,"administrative_area":null,"timezone":null,'
'"is_mainland_china":false,"summary_language":"english"}',
(
'{"id":"example","name":"Example","latitude":1,"longitude":2,'
'"country_code":null,"administrative_area":null,"timezone":null,'
'"is_mainland_china":false,"summary_language":"english"}'
),
],
)
async def test_resolver_rejects_obsolete_cache_record(tmp_path: Path, cached: str) -> None:
Expand Down
39 changes: 20 additions & 19 deletions tests/test_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ def notification_decisions(self) -> NotificationDecisionProvider:
...


def _briefing_service( # noqa: PLR0913
# Test factory mirroring BriefingService; kept positional across 37 call sites.
def _briefing_service( # noqa: PLR0913, PLR0917
settings: _TestSettings,
location: ResolvedLocation,
state: SQLiteStateStore,
Expand All @@ -252,15 +253,15 @@ def _briefing_service( # noqa: PLR0913
llm.notification_decisions if isinstance(llm, _NotificationDecisionOwner) else RecordingNotificationDecisions()
)
return _BriefingService(
settings,
location,
state,
rss_source,
llm,
notification_decisions,
delivery,
ops_delivery,
weather_context_provider,
settings=settings,
location=location,
state=state,
rss_source=rss_source,
llm=llm,
notification_decisions=notification_decisions,
delivery=delivery,
ops_delivery=ops_delivery,
weather_context_provider=weather_context_provider,
)


Expand Down Expand Up @@ -1541,15 +1542,15 @@ async def test_forced_audible_briefing_does_not_depend_on_notification_decision(

with SQLiteStateStore(tmp_path / "forced-audible.sqlite3") as state:
service = _BriefingService(
settings,
_location(),
state,
EmptyRSSSource(),
llm,
decision_provider,
delivery,
delivery,
StaticWeatherContextProvider(),
settings=settings,
location=_location(),
state=state,
rss_source=EmptyRSSSource(),
llm=llm,
notification_decisions=decision_provider,
delivery=delivery,
ops_delivery=delivery,
weather_context_provider=StaticWeatherContextProvider(),
)
body = await service.run(
"briefing",
Expand Down
51 changes: 13 additions & 38 deletions tests/test_service_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ async def test_mismatched_official_language_is_translated(tmp_path: Path) -> Non
)
with SQLiteStateStore(tmp_path / "state.sqlite3") as state:
await ServiceStatusMonitor(
(provider,), state.service_status, (("test", delivery),), decision, translator, "zh-CN"
(provider,), state.service_status, (("test", delivery),), decision, translator, language="zh-CN"
).run(pendulum.now("UTC"))

translator.translate_service_status.assert_awaited_once_with(
Expand All @@ -597,7 +597,7 @@ async def test_translation_failure_falls_back_to_official_text(tmp_path: Path, c
caplog.at_level("WARNING", logger="weather_briefing.service_status"),
):
await ServiceStatusMonitor(
(provider,), state.service_status, (("test", delivery),), decision, translator, "zh-CN"
(provider,), state.service_status, (("test", delivery),), decision, translator, language="zh-CN"
).run(pendulum.now("UTC"))

delivery.publish_alert.assert_awaited_once_with(
Expand Down Expand Up @@ -634,22 +634,12 @@ def test_state_rejects_handling_a_changed_observation(tmp_path: Path) -> None:
with SQLiteStateStore(tmp_path / "state.sqlite3") as state:
state.service_status.observe_service_status_message(
"source",
"incident",
"new",
"Title",
"monitoring",
"Body",
now,
_message(incident_id="incident", revision_id="new", title="Title", status="monitoring", body="Body"),
)
with pytest.raises(RuntimeError, match="changed before handling"):
state.service_status.mark_service_status_message_handled(
"source",
"incident",
"old",
"Title",
"monitoring",
"Body",
(ServiceSurface.API,),
_message(incident_id="incident", revision_id="old", title="Title", status="monitoring", body="Body"),
now,
)

Expand All @@ -658,25 +648,15 @@ def test_state_rejects_invalid_stored_service_status_surfaces(tmp_path: Path) ->
now = pendulum.now("UTC")
state_path = tmp_path / "state.sqlite3"
with SQLiteStateStore(state_path) as state:
state.service_status.observe_service_status_message(
"source",
"incident",
"revision",
"Title",
"monitoring",
"Body",
now,
)
state.service_status.mark_service_status_message_handled(
"source",
"incident",
"revision",
"Title",
"monitoring",
"Body",
(ServiceSurface.API,),
now,
message = _message(
incident_id="incident",
revision_id="revision",
title="Title",
status="monitoring",
body="Body",
)
state.service_status.observe_service_status_message("source", message)
state.service_status.mark_service_status_message_handled("source", message, now)
for stored_value, message in (
("{}", "must be a list"),
("[1]", "must contain strings"),
Expand All @@ -698,12 +678,7 @@ def test_state_rejects_deciding_a_changed_observation(tmp_path: Path) -> None:
with SQLiteStateStore(tmp_path / "state.sqlite3") as state:
state.service_status.observe_service_status_message(
"source",
"incident",
"new",
"Title",
"monitoring",
"Body",
pendulum.now("UTC"),
_message(incident_id="incident", revision_id="new", title="Title", status="monitoring", body="Body"),
)
with pytest.raises(RuntimeError, match="changed before its decision"):
state.service_status.mark_service_status_message_decided(
Expand Down
20 changes: 10 additions & 10 deletions weather_briefing/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,20 +158,20 @@ async def _run_unlocked(
briefing_sent_today=briefing_sent_today,
)
service = BriefingService(
settings,
location,
state,
RSSSource(
settings=settings,
location=location,
state=state,
rss_source=RSSSource(
client,
max_attempts=settings.rss_max_attempts,
retry_min_seconds=settings.rss_retry_min_seconds,
retry_max_seconds=settings.rss_retry_max_seconds,
),
llm_provider,
notification_decisions,
delivery,
delivery,
_weather_context_provider(settings, client, location),
llm=llm_provider,
notification_decisions=notification_decisions,
delivery=delivery,
ops_delivery=delivery,
weather_context_provider=_weather_context_provider(settings, client, location),
)
body = await service.run(
kind,
Expand Down Expand Up @@ -220,7 +220,7 @@ async def run_service_status() -> None:
deliveries,
notification_decisions,
service_status_llm,
settings.service_status_language,
language=settings.service_status_language,
)
published = await monitor.run(pendulum.now(settings.timezone))
_LOGGER.info("Service-status run published %d notification(s)", published)
Expand Down
2 changes: 1 addition & 1 deletion weather_briefing/delivery/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ def rendered_text_logging_enabled(diagnostics: RenderedTextDiagnostics | None) -
return False
try:
enabled = diagnostics.rendered_text_logging_enabled()
except Exception: # noqa: BLE001
except Exception:
_LOGGER.warning("Rendered text diagnostic state check failed", exc_info=True)
return False
return enabled and _LOGGER.isEnabledFor(logging.DEBUG)
6 changes: 4 additions & 2 deletions weather_briefing/delivery/telegram_renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ def render_briefing(
}
source_links.update({document.id: _html_link(document.url, document.name) for document in context})
lines = [
f"<b>{_html_text(result.headline)}</b> "
f"{_html_attribution(result.headline_source_ids, source_links, labels)}",
(
f"<b>{_html_text(result.headline)}</b> "
f"{_html_attribution(result.headline_source_ids, source_links, labels)}"
),
"",
]
lines.extend(_html_items(labels["weather"], result.conclusions, source_links, labels))
Expand Down
2 changes: 1 addition & 1 deletion weather_briefing/llm/any_llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def _sensitive_llm_diagnostics_enabled(diagnostics: SensitiveLLMDiagnostics | No
return False
try:
return diagnostics.rendered_text_logging_enabled()
except Exception: # noqa: BLE001
except Exception:
_LOGGER.warning("Sensitive LLM diagnostic state check failed", exc_info=True)
return False

Expand Down
44 changes: 22 additions & 22 deletions weather_briefing/persistence/service_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

import pendulum

from weather_briefing.service_status.models import ServiceStatusMessage


@dataclass(frozen=True, slots=True)
class ServiceStatusMessageState:
Expand Down Expand Up @@ -86,15 +88,10 @@ def service_status_message_state(
handled_surfaces=_stored_surfaces(row["handled_surfaces"]),
)

def observe_service_status_message( # noqa: PLR0913
def observe_service_status_message(
self,
source_id: str,
incident_id: str,
revision_id: str,
title: str,
status: str,
body: str,
observed_at: pendulum.DateTime,
message: ServiceStatusMessage,
) -> None:
"""Persist an official message without claiming handling succeeded."""
self._connection.execute(
Expand All @@ -108,7 +105,15 @@ def observe_service_status_message( # noqa: PLR0913
observed_status = excluded.observed_status,
observed_body = excluded.observed_body,
observed_at = excluded.observed_at""",
(source_id, incident_id, revision_id, title, status, body, storage_time(observed_at)),
(
source_id,
message.incident_id,
message.revision_id,
message.title,
message.status,
message.body,
storage_time(message.published_at),
),
)
self._connection.commit()

Expand Down Expand Up @@ -165,15 +170,10 @@ def mark_service_status_message_delivered(
)
self._connection.commit()

def mark_service_status_message_handled( # noqa: PLR0913
def mark_service_status_message_handled(
self,
source_id: str,
incident_id: str,
revision_id: str,
title: str,
status: str,
body: str,
surfaces: tuple[ServiceSurface, ...],
message: ServiceStatusMessage,
handled_at: pendulum.DateTime,
) -> None:
"""Mark one observed message as delivered or intentionally skipped."""
Expand All @@ -187,15 +187,15 @@ def mark_service_status_message_handled( # noqa: PLR0913
handled_at = ?
WHERE source_id = ? AND incident_id = ? AND observed_revision_id = ?""",
(
revision_id,
title,
status,
body,
json.dumps([surface.value for surface in surfaces], ensure_ascii=False, separators=(",", ":")),
message.revision_id,
message.title,
message.status,
message.body,
json.dumps([surface.value for surface in message.surfaces], ensure_ascii=False, separators=(",", ":")),
storage_time(handled_at),
source_id,
incident_id,
revision_id,
message.incident_id,
message.revision_id,
),
)
if cursor.rowcount != 1:
Expand Down
1 change: 1 addition & 0 deletions weather_briefing/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class BriefingService:

def __init__( # noqa: PLR0913
self,
*,
settings: BriefingSettings,
location: ResolvedLocation,
state: SQLiteStateStore,
Expand Down
Loading