fix: resolve all mypy type errors across service modules
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f11947aad2
commit
74249fa24c
10 changed files with 39 additions and 31 deletions
|
|
@ -232,7 +232,7 @@ async def _request_arxiv_feed(
|
||||||
timeout_value = _timeout_seconds(timeout_seconds)
|
timeout_value = _timeout_seconds(timeout_seconds)
|
||||||
headers = {"User-Agent": f"scholar-scraper/1.0 (mailto:{_contact_email(request_email)})"}
|
headers = {"User-Agent": f"scholar-scraper/1.0 (mailto:{_contact_email(request_email)})"}
|
||||||
async with httpx.AsyncClient(timeout=timeout_value, follow_redirects=True, headers=headers) as client:
|
async with httpx.AsyncClient(timeout=timeout_value, follow_redirects=True, headers=headers) as client:
|
||||||
return await client.get(_ARXIV_API_URL, params=params)
|
return await client.get(_ARXIV_API_URL, params=params) # type: ignore[arg-type]
|
||||||
|
|
||||||
return await run_with_global_arxiv_limit(
|
return await run_with_global_arxiv_limit(
|
||||||
fetch=_fetch,
|
fetch=_fetch,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
||||||
from datetime import UTC, datetime
|
from datetime import UTC, datetime
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from sqlalchemy import delete, exists, func, select, update
|
from sqlalchemy import CursorResult, delete, exists, func, select, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.db.models import DataRepairJob, IngestionQueueItem, Publication, ScholarProfile, ScholarPublication
|
from app.db.models import DataRepairJob, IngestionQueueItem, Publication, ScholarProfile, ScholarPublication
|
||||||
|
|
@ -152,7 +152,7 @@ def _job_summary(
|
||||||
|
|
||||||
|
|
||||||
async def _delete_links_for_targets(db_session: AsyncSession, *, target_scholar_profile_ids: list[int]) -> int:
|
async def _delete_links_for_targets(db_session: AsyncSession, *, target_scholar_profile_ids: list[int]) -> int:
|
||||||
result = await db_session.execute(
|
result: CursorResult[Any] = await db_session.execute( # type: ignore[assignment]
|
||||||
delete(ScholarPublication).where(ScholarPublication.scholar_profile_id.in_(target_scholar_profile_ids))
|
delete(ScholarPublication).where(ScholarPublication.scholar_profile_id.in_(target_scholar_profile_ids))
|
||||||
)
|
)
|
||||||
return int(result.rowcount or 0)
|
return int(result.rowcount or 0)
|
||||||
|
|
@ -167,7 +167,7 @@ async def _delete_queue_for_targets(
|
||||||
stmt = delete(IngestionQueueItem).where(IngestionQueueItem.scholar_profile_id.in_(target_scholar_profile_ids))
|
stmt = delete(IngestionQueueItem).where(IngestionQueueItem.scholar_profile_id.in_(target_scholar_profile_ids))
|
||||||
if user_id is not None:
|
if user_id is not None:
|
||||||
stmt = stmt.where(IngestionQueueItem.user_id == user_id)
|
stmt = stmt.where(IngestionQueueItem.user_id == user_id)
|
||||||
result = await db_session.execute(stmt)
|
result: CursorResult[Any] = await db_session.execute(stmt) # type: ignore[assignment]
|
||||||
return int(result.rowcount or 0)
|
return int(result.rowcount or 0)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -180,7 +180,7 @@ async def _reset_scholar_tracking_state(
|
||||||
stmt = update(ScholarProfile).where(ScholarProfile.id.in_(target_scholar_profile_ids))
|
stmt = update(ScholarProfile).where(ScholarProfile.id.in_(target_scholar_profile_ids))
|
||||||
if user_id is not None:
|
if user_id is not None:
|
||||||
stmt = stmt.where(ScholarProfile.user_id == user_id)
|
stmt = stmt.where(ScholarProfile.user_id == user_id)
|
||||||
result = await db_session.execute(
|
result: CursorResult[Any] = await db_session.execute( # type: ignore[assignment]
|
||||||
stmt.values(
|
stmt.values(
|
||||||
baseline_completed=False,
|
baseline_completed=False,
|
||||||
last_initial_page_fingerprint_sha256=None,
|
last_initial_page_fingerprint_sha256=None,
|
||||||
|
|
@ -193,7 +193,7 @@ async def _reset_scholar_tracking_state(
|
||||||
|
|
||||||
|
|
||||||
async def _delete_orphan_publications(db_session: AsyncSession) -> int:
|
async def _delete_orphan_publications(db_session: AsyncSession) -> int:
|
||||||
result = await db_session.execute(
|
result: CursorResult[Any] = await db_session.execute( # type: ignore[assignment]
|
||||||
delete(Publication).where(~exists(select(1).where(ScholarPublication.publication_id == Publication.id)))
|
delete(Publication).where(~exists(select(1).where(ScholarPublication.publication_id == Publication.id)))
|
||||||
)
|
)
|
||||||
return int(result.rowcount or 0)
|
return int(result.rowcount or 0)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import asyncio
|
||||||
import logging
|
import logging
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import UTC, datetime, timedelta
|
from datetime import UTC, datetime, timedelta
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
|
|
||||||
|
|
@ -158,7 +159,7 @@ class SchedulerService:
|
||||||
continue
|
continue
|
||||||
await self._run_candidate(candidate)
|
await self._run_candidate(candidate)
|
||||||
|
|
||||||
async def _load_candidate_rows(self) -> list[tuple]:
|
async def _load_candidate_rows(self) -> list[Any]:
|
||||||
session_factory = get_session_factory()
|
session_factory = get_session_factory()
|
||||||
async with session_factory() as session:
|
async with session_factory() as session:
|
||||||
result = await session.execute(
|
result = await session.execute(
|
||||||
|
|
@ -173,10 +174,10 @@ class SchedulerService:
|
||||||
.where(User.is_active.is_(True), UserSetting.auto_run_enabled.is_(True))
|
.where(User.is_active.is_(True), UserSetting.auto_run_enabled.is_(True))
|
||||||
.order_by(UserSetting.user_id.asc())
|
.order_by(UserSetting.user_id.asc())
|
||||||
)
|
)
|
||||||
return result.all()
|
return list(result.all())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _candidate_from_row(row: tuple, *, now_utc: datetime) -> _AutoRunCandidate | None:
|
def _candidate_from_row(row: Any, *, now_utc: datetime) -> _AutoRunCandidate | None:
|
||||||
user_id, run_interval_minutes, request_delay_seconds, cooldown_until, cooldown_reason = row
|
user_id, run_interval_minutes, request_delay_seconds, cooldown_until, cooldown_reason = row
|
||||||
if cooldown_until is not None and cooldown_until.tzinfo is None:
|
if cooldown_until is not None and cooldown_until.tzinfo is None:
|
||||||
cooldown_until = cooldown_until.replace(tzinfo=UTC)
|
cooldown_until = cooldown_until.replace(tzinfo=UTC)
|
||||||
|
|
|
||||||
|
|
@ -547,7 +547,7 @@ async def run_scholar_iteration(
|
||||||
queue_delay_seconds: int,
|
queue_delay_seconds: int,
|
||||||
) -> RunProgress:
|
) -> RunProgress:
|
||||||
progress = RunProgress()
|
progress = RunProgress()
|
||||||
scholar_kwargs = {
|
scholar_kwargs: dict[str, Any] = {
|
||||||
"request_delay_seconds": request_delay_seconds,
|
"request_delay_seconds": request_delay_seconds,
|
||||||
"network_error_retries": network_error_retries,
|
"network_error_retries": network_error_retries,
|
||||||
"retry_backoff_seconds": retry_backoff_seconds,
|
"retry_backoff_seconds": retry_backoff_seconds,
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ def _serialize_export_scholar(profile: ScholarProfile) -> dict[str, Any]:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _serialize_export_publication(row: tuple[Any, ...]) -> dict[str, Any]:
|
def _serialize_export_publication(row: Any) -> dict[str, Any]:
|
||||||
(
|
(
|
||||||
scholar_id,
|
scholar_id,
|
||||||
cluster_id,
|
cluster_id,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import UTC, datetime, timedelta
|
from datetime import UTC, datetime, timedelta
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from sqlalchemy import Select, and_, func, literal, or_, select, union_all
|
from sqlalchemy import Select, and_, func, literal, or_, select, union_all
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
@ -43,7 +44,7 @@ def _retry_item_label(display_name: str | None, scholar_id: str | None) -> str:
|
||||||
def _retry_item_from_publication(
|
def _retry_item_from_publication(
|
||||||
publication: Publication,
|
publication: Publication,
|
||||||
*,
|
*,
|
||||||
link_row: tuple | None,
|
link_row: Any | None,
|
||||||
) -> PublicationListItem:
|
) -> PublicationListItem:
|
||||||
if link_row is None:
|
if link_row is None:
|
||||||
scholar_profile_id = 0
|
scholar_profile_id = 0
|
||||||
|
|
@ -270,7 +271,7 @@ class PdfQueueListItem:
|
||||||
display_identifier: DisplayIdentifier | None = None
|
display_identifier: DisplayIdentifier | None = None
|
||||||
|
|
||||||
|
|
||||||
def _queue_item_from_row(row: tuple) -> PdfQueueListItem:
|
def _queue_item_from_row(row: Any) -> PdfQueueListItem:
|
||||||
return PdfQueueListItem(
|
return PdfQueueListItem(
|
||||||
publication_id=int(row[0]),
|
publication_id=int(row[0]),
|
||||||
title=str(row[1] or ""),
|
title=str(row[1] or ""),
|
||||||
|
|
@ -292,7 +293,7 @@ def _queue_item_from_row(row: tuple) -> PdfQueueListItem:
|
||||||
async def _hydrated_queue_items(
|
async def _hydrated_queue_items(
|
||||||
db_session: AsyncSession,
|
db_session: AsyncSession,
|
||||||
*,
|
*,
|
||||||
rows: list[tuple],
|
rows: list[Any],
|
||||||
) -> list[PdfQueueListItem]:
|
) -> list[PdfQueueListItem]:
|
||||||
items = [_queue_item_from_row(row) for row in rows]
|
items = [_queue_item_from_row(row) for row in rows]
|
||||||
return await identifier_service.overlay_pdf_queue_items_with_display_identifiers(
|
return await identifier_service.overlay_pdf_queue_items_with_display_identifiers(
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from sqlalchemy import Select, case, func, select
|
from sqlalchemy import Select, case, false as sa_false, func, select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.db.models import (
|
from app.db.models import (
|
||||||
|
|
@ -124,7 +125,7 @@ def publications_query(
|
||||||
stmt = stmt.where(ScholarPublication.is_read.is_(False))
|
stmt = stmt.where(ScholarPublication.is_read.is_(False))
|
||||||
if mode == MODE_LATEST:
|
if mode == MODE_LATEST:
|
||||||
if latest_run_id is None:
|
if latest_run_id is None:
|
||||||
return stmt.where(False)
|
return stmt.where(sa_false())
|
||||||
stmt = stmt.where(ScholarPublication.first_seen_run_id == latest_run_id)
|
stmt = stmt.where(ScholarPublication.first_seen_run_id == latest_run_id)
|
||||||
if snapshot_before is not None:
|
if snapshot_before is not None:
|
||||||
stmt = stmt.where(ScholarPublication.created_at <= snapshot_before)
|
stmt = stmt.where(ScholarPublication.created_at <= snapshot_before)
|
||||||
|
|
@ -195,7 +196,7 @@ async def get_publication_item_for_user(
|
||||||
|
|
||||||
|
|
||||||
def publication_list_item_from_row(
|
def publication_list_item_from_row(
|
||||||
row: tuple,
|
row: Any,
|
||||||
*,
|
*,
|
||||||
latest_run_id: int | None,
|
latest_run_id: int | None,
|
||||||
) -> PublicationListItem:
|
) -> PublicationListItem:
|
||||||
|
|
@ -232,7 +233,7 @@ def publication_list_item_from_row(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def unread_item_from_row(row: tuple) -> UnreadPublicationItem:
|
def unread_item_from_row(row: Any) -> UnreadPublicationItem:
|
||||||
(
|
(
|
||||||
publication_id,
|
publication_id,
|
||||||
scholar_profile_id,
|
scholar_profile_id,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from sqlalchemy import select, tuple_, update
|
from typing import Any
|
||||||
|
|
||||||
|
from sqlalchemy import CursorResult, select, tuple_, update
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from app.db.models import ScholarProfile, ScholarPublication
|
from app.db.models import ScholarProfile, ScholarPublication
|
||||||
|
|
@ -34,7 +36,7 @@ async def mark_all_unread_as_read_for_user(
|
||||||
)
|
)
|
||||||
.values(is_read=True)
|
.values(is_read=True)
|
||||||
)
|
)
|
||||||
result = await db_session.execute(stmt)
|
result: CursorResult[Any] = await db_session.execute(stmt) # type: ignore[assignment]
|
||||||
await db_session.commit()
|
await db_session.commit()
|
||||||
return int(result.rowcount or 0)
|
return int(result.rowcount or 0)
|
||||||
|
|
||||||
|
|
@ -62,7 +64,7 @@ async def mark_selected_as_read_for_user(
|
||||||
)
|
)
|
||||||
.values(is_read=True)
|
.values(is_read=True)
|
||||||
)
|
)
|
||||||
result = await db_session.execute(stmt)
|
result: CursorResult[Any] = await db_session.execute(stmt) # type: ignore[assignment]
|
||||||
await db_session.commit()
|
await db_session.commit()
|
||||||
return int(result.rowcount or 0)
|
return int(result.rowcount or 0)
|
||||||
|
|
||||||
|
|
@ -85,6 +87,6 @@ async def set_publication_favorite_for_user(
|
||||||
)
|
)
|
||||||
.values(is_favorite=bool(is_favorite))
|
.values(is_favorite=bool(is_favorite))
|
||||||
)
|
)
|
||||||
result = await db_session.execute(stmt)
|
result: CursorResult[Any] = await db_session.execute(stmt) # type: ignore[assignment]
|
||||||
await db_session.commit()
|
await db_session.commit()
|
||||||
return int(result.rowcount or 0)
|
return int(result.rowcount or 0)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from sqlalchemy import and_, select
|
from sqlalchemy import and_, select
|
||||||
|
|
||||||
from app.db.models import IngestionQueueItem, ScholarProfile
|
from app.db.models import IngestionQueueItem, ScholarProfile
|
||||||
|
|
@ -38,7 +40,7 @@ def queue_item_select(*, user_id: int):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def queue_list_item_from_row(row: tuple) -> QueueListItem:
|
def queue_list_item_from_row(row: Any) -> QueueListItem:
|
||||||
(
|
(
|
||||||
item_id,
|
item_id,
|
||||||
scholar_profile_id,
|
scholar_profile_id,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import UTC, datetime, timedelta
|
from datetime import UTC, datetime, timedelta
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from sqlalchemy import delete, func, select
|
from sqlalchemy import delete, func, select
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
@ -136,14 +137,14 @@ def _deserialize_parsed_author_search_page(payload: object) -> ParsedAuthorSearc
|
||||||
state_reason=str(payload.get("state_reason", "")).strip() or "unknown",
|
state_reason=str(payload.get("state_reason", "")).strip() or "unknown",
|
||||||
candidates=[
|
candidates=[
|
||||||
ScholarSearchCandidate(
|
ScholarSearchCandidate(
|
||||||
scholar_id=item["scholar_id"],
|
scholar_id=cast(str, item["scholar_id"]),
|
||||||
display_name=item["display_name"],
|
display_name=cast(str, item["display_name"]),
|
||||||
affiliation=item["affiliation"],
|
affiliation=cast("str | None", item["affiliation"]),
|
||||||
email_domain=item["email_domain"],
|
email_domain=cast("str | None", item["email_domain"]),
|
||||||
cited_by_count=item["cited_by_count"],
|
cited_by_count=cast("int | None", item["cited_by_count"]),
|
||||||
interests=item["interests"],
|
interests=cast("list[str]", item["interests"]),
|
||||||
profile_url=item["profile_url"],
|
profile_url=cast(str, item["profile_url"]),
|
||||||
profile_image_url=item["profile_image_url"],
|
profile_image_url=cast("str | None", item["profile_image_url"]),
|
||||||
)
|
)
|
||||||
for item in normalized_candidates
|
for item in normalized_candidates
|
||||||
],
|
],
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue