ci: add ruff linting and mypy type checking
Add ruff and mypy to dev dependencies with configuration in pyproject.toml. Add a lint CI job that runs ruff check, ruff format --check, and mypy. Auto-fix import sorting and formatting across the codebase. Exclude alembic/versions from linting (auto-generated migrations). Ignore B008 (FastAPI Depends pattern) and RUF001 (unicode in user-facing strings). 21 ruff lint errors and 50 mypy errors remain for manual review. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
399276ea69
commit
bf04c77aa9
137 changed files with 3066 additions and 1900 deletions
|
|
@ -1,22 +1,24 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from unittest.mock import patch, AsyncMock, MagicMock
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from app.db.models import CrawlRun, Publication, ScholarProfile, ScholarPublication, RunStatus, RunTriggerType
|
||||
from app.db.models import CrawlRun, Publication, RunStatus, RunTriggerType, ScholarProfile, ScholarPublication
|
||||
from app.services.domains.ingestion.application import ScholarIngestionService
|
||||
from app.services.domains.openalex.types import OpenAlexWork
|
||||
from tests.integration.helpers import insert_user
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
async def test_deferred_enrichment_sweeps_previous_runs(db_session: AsyncSession) -> None:
|
||||
# 1. Setup: Create user and scholar
|
||||
user_id = await insert_user(db_session, email="test@example.com", password="password123")
|
||||
|
||||
|
||||
scholar = ScholarProfile(
|
||||
user_id=user_id,
|
||||
scholar_id="SaiiI5MAAAAJ",
|
||||
|
|
@ -25,17 +27,17 @@ async def test_deferred_enrichment_sweeps_previous_runs(db_session: AsyncSession
|
|||
)
|
||||
db_session.add(scholar)
|
||||
await db_session.flush()
|
||||
|
||||
|
||||
# 2. Simulate a previous FAILED run that left an un-enriched publication
|
||||
failed_run = CrawlRun(
|
||||
user_id=user_id,
|
||||
status=RunStatus.FAILED,
|
||||
trigger_type=RunTriggerType.MANUAL,
|
||||
start_dt=datetime.now(timezone.utc),
|
||||
start_dt=datetime.now(UTC),
|
||||
)
|
||||
db_session.add(failed_run)
|
||||
await db_session.flush()
|
||||
|
||||
|
||||
pub = Publication(
|
||||
title_raw="A fast quantum mechanical algorithm for database search",
|
||||
title_normalized="a fast quantum mechanical algorithm for database search",
|
||||
|
|
@ -45,7 +47,7 @@ async def test_deferred_enrichment_sweeps_previous_runs(db_session: AsyncSession
|
|||
)
|
||||
db_session.add(pub)
|
||||
await db_session.flush()
|
||||
|
||||
|
||||
link = ScholarPublication(
|
||||
scholar_profile_id=scholar.id,
|
||||
publication_id=pub.id,
|
||||
|
|
@ -53,17 +55,17 @@ async def test_deferred_enrichment_sweeps_previous_runs(db_session: AsyncSession
|
|||
)
|
||||
db_session.add(link)
|
||||
await db_session.commit()
|
||||
|
||||
|
||||
# 3. Create a NEW run
|
||||
new_run = CrawlRun(
|
||||
user_id=user_id,
|
||||
status=RunStatus.RUNNING,
|
||||
trigger_type=RunTriggerType.MANUAL,
|
||||
start_dt=datetime.now(timezone.utc),
|
||||
start_dt=datetime.now(UTC),
|
||||
)
|
||||
db_session.add(new_run)
|
||||
await db_session.commit()
|
||||
|
||||
|
||||
# 4. Mock OpenAlex client to return enrichment data
|
||||
mock_work = OpenAlexWork(
|
||||
openalex_id="W1234567",
|
||||
|
|
@ -76,26 +78,30 @@ async def test_deferred_enrichment_sweeps_previous_runs(db_session: AsyncSession
|
|||
is_oa=True,
|
||||
oa_url="http://example.com/grover.pdf",
|
||||
)
|
||||
|
||||
|
||||
mock_source = MagicMock()
|
||||
service = ScholarIngestionService(source=mock_source)
|
||||
|
||||
|
||||
# We patch the client at its source, and also mock arXiv to avoid real HTTP calls
|
||||
with patch("app.services.domains.openalex.client.OpenAlexClient") as MockClient, \
|
||||
patch("app.services.domains.arxiv.application.discover_arxiv_id_for_publication", new=AsyncMock(return_value=None)):
|
||||
with (
|
||||
patch("app.services.domains.openalex.client.OpenAlexClient") as MockClient,
|
||||
patch(
|
||||
"app.services.domains.arxiv.application.discover_arxiv_id_for_publication", new=AsyncMock(return_value=None)
|
||||
),
|
||||
):
|
||||
mock_instance = MockClient.return_value
|
||||
mock_instance.get_works_by_filter = AsyncMock(return_value=[mock_work])
|
||||
|
||||
# 5. Execute the enrichment pass for the NEW run
|
||||
await service._enrich_pending_publications(db_session, run_id=new_run.id)
|
||||
await db_session.commit()
|
||||
|
||||
|
||||
# 6. Verification: The publication from the FAILED run should now be enriched
|
||||
await db_session.refresh(pub)
|
||||
assert pub.openalex_enriched is True
|
||||
assert pub.citation_count == 1000
|
||||
assert pub.pdf_url == "http://example.com/grover.pdf"
|
||||
|
||||
|
||||
# Double check it was indeed processed
|
||||
stmt = select(Publication).where(Publication.id == pub.id)
|
||||
result = await db_session.execute(stmt)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue