generated from john/python-template
style: apply ruff formatting sweep
Co-authored-by: Copilot App <[email protected]>
This commit is contained in:
co-authored by
Copilot App
parent
4aaa9bd581
commit
2a56365847
@@ -26,9 +26,7 @@ from transcription.services.workflows import advance_job
|
||||
async def _attempts_for_job(session, job) -> list[ExecutionAttempt]:
|
||||
"""Load execution attempts for a job; V4.7 moved evidence off JobSource."""
|
||||
job_source_ids = [job_source.id for job_source in job.job_sources]
|
||||
result = await session.exec(
|
||||
select(ExecutionAttempt).where(col(ExecutionAttempt.job_source_id).in_(job_source_ids))
|
||||
)
|
||||
result = await session.exec(select(ExecutionAttempt).where(col(ExecutionAttempt.job_source_id).in_(job_source_ids)))
|
||||
return list(result.all())
|
||||
|
||||
|
||||
|
||||
@@ -154,11 +154,7 @@ class TestJobService:
|
||||
finally:
|
||||
event.remove(bind, "before_cursor_execute", capture)
|
||||
|
||||
claim_sql = [
|
||||
item
|
||||
for item in statements
|
||||
if item.lstrip().upper().startswith(("SELECT", "UPDATE"))
|
||||
]
|
||||
claim_sql = [item for item in statements if item.lstrip().upper().startswith(("SELECT", "UPDATE"))]
|
||||
assert len(claim_sql) == 1, claim_sql
|
||||
assert "LIMIT" in claim_sql[0].upper()
|
||||
assert "JOIN" not in claim_sql[0].upper()
|
||||
|
||||
@@ -7,10 +7,13 @@ from transcription.db.models import Person
|
||||
from transcription.services.people import PeopleService
|
||||
from transcription.services.photos import PhotosService
|
||||
|
||||
PNG_BYTES = bytes.fromhex(
|
||||
"89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c4890000000a49444154789c6360000002000100"
|
||||
"05fe02fea7b1b8000000004945"
|
||||
) + b"NDAE\xae\x42\x60\x82"
|
||||
PNG_BYTES = (
|
||||
bytes.fromhex(
|
||||
"89504e470d0a1a0a0000000d49484452000000010000000108060000001f15c4890000000a49444154789c6360000002000100"
|
||||
"05fe02fea7b1b8000000004945"
|
||||
)
|
||||
+ b"NDAE\xae\x42\x60\x82"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
||||
@@ -35,9 +35,7 @@ def test_quality_analysis_accepts_clean_transcription():
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_quality_warning_payload_is_versioned():
|
||||
payload = quality_warning_payload(
|
||||
analyze_transcription_quality("[document body typeset]\nBroken \ufffd")
|
||||
)
|
||||
payload = quality_warning_payload(analyze_transcription_quality("[document body typeset]\nBroken \ufffd"))
|
||||
|
||||
assert payload["schema_name"] == "transcription.quality-warnings"
|
||||
assert payload["schema_version"] == "1"
|
||||
|
||||
@@ -73,10 +73,7 @@ async def test_create_job_for_document_sorts_sources_and_creates_links(async_ses
|
||||
assert all(source.filename.endswith(".pdf") for source in sources)
|
||||
assert all("A_page" not in source.filename and "b_page" not in source.filename for source in sources)
|
||||
assert all(Path(source.filename).stem == str(source.id) for source in sources)
|
||||
assert all(
|
||||
source.file_path == f"documents/{document.id}/{source.filename}"
|
||||
for source in sources
|
||||
)
|
||||
assert all(source.file_path == f"documents/{document.id}/{source.filename}" for source in sources)
|
||||
assert [source.file_hash for source in sources] == [
|
||||
"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb",
|
||||
"3e23e8160039594a33894f6564e1b1348bbd7a0088d42c4acb73eeaed59c009d",
|
||||
|
||||
@@ -43,13 +43,7 @@ pytestmark = [
|
||||
def _real_image_paths() -> list[Path]:
|
||||
if not REAL_IMAGES_DIR.exists():
|
||||
return []
|
||||
return sorted(
|
||||
[
|
||||
p
|
||||
for p in REAL_IMAGES_DIR.iterdir()
|
||||
if p.is_file() and p.suffix.lower() in SUPPORTED_EXTENSIONS
|
||||
]
|
||||
)
|
||||
return sorted([p for p in REAL_IMAGES_DIR.iterdir() if p.is_file() and p.suffix.lower() in SUPPORTED_EXTENSIONS])
|
||||
|
||||
|
||||
def _artifact_filename(image_path: Path) -> str:
|
||||
@@ -78,11 +72,7 @@ class TestRealImageExternalTranscription:
|
||||
ARTIFACTS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
artifact_path = ARTIFACTS_DIR / _artifact_filename(image_path)
|
||||
artifact_text = (
|
||||
f"source: {image_path.name}\n"
|
||||
f"provider: {result.provider}\n"
|
||||
f"model: {result.model}\n"
|
||||
"---\n"
|
||||
f"{result.text}\n"
|
||||
f"source: {image_path.name}\nprovider: {result.provider}\nmodel: {result.model}\n---\n{result.text}\n"
|
||||
)
|
||||
artifact_path.write_text(artifact_text, encoding="utf-8")
|
||||
assert artifact_path.exists()
|
||||
|
||||
@@ -107,15 +107,12 @@ class TestWorkflowReliability:
|
||||
|
||||
async with services.jobs._session_scope() as session:
|
||||
attempts = (
|
||||
(
|
||||
await session.exec(
|
||||
select(ExecutionAttempt).where(
|
||||
col(ExecutionAttempt.job_source_id).in_([js.id for js in result.job_sources])
|
||||
)
|
||||
await session.exec(
|
||||
select(ExecutionAttempt).where(
|
||||
col(ExecutionAttempt.job_source_id).in_([js.id for js in result.job_sources])
|
||||
)
|
||||
)
|
||||
.all()
|
||||
)
|
||||
).all()
|
||||
error_detail = next(attempt.error_detail for attempt in attempts if attempt.error_detail is not None)
|
||||
assert "timed out" in error_detail.lower()
|
||||
assert "20.0s" in error_detail
|
||||
@@ -179,15 +176,12 @@ class TestWorkflowReliability:
|
||||
|
||||
async with services.jobs._session_scope() as session:
|
||||
attempts = (
|
||||
(
|
||||
await session.exec(
|
||||
select(ExecutionAttempt).where(
|
||||
col(ExecutionAttempt.job_source_id).in_([js.id for js in result.job_sources])
|
||||
)
|
||||
await session.exec(
|
||||
select(ExecutionAttempt).where(
|
||||
col(ExecutionAttempt.job_source_id).in_([js.id for js in result.job_sources])
|
||||
)
|
||||
)
|
||||
.all()
|
||||
)
|
||||
).all()
|
||||
assert len(attempts) == 1
|
||||
duration_ms = attempts[0].duration_ms
|
||||
|
||||
@@ -242,15 +236,12 @@ class TestWorkflowReliability:
|
||||
|
||||
async with services.jobs._session_scope() as session:
|
||||
attempts = (
|
||||
(
|
||||
await session.exec(
|
||||
select(ExecutionAttempt).where(
|
||||
col(ExecutionAttempt.job_source_id).in_([js.id for js in result.job_sources])
|
||||
)
|
||||
await session.exec(
|
||||
select(ExecutionAttempt).where(
|
||||
col(ExecutionAttempt.job_source_id).in_([js.id for js in result.job_sources])
|
||||
)
|
||||
)
|
||||
.all()
|
||||
)
|
||||
).all()
|
||||
assert len(attempts) == 1
|
||||
attempt = attempts[0]
|
||||
timing = (attempt.normalized_metadata or {}).get("processing_timing")
|
||||
|
||||
+11
-14
@@ -163,16 +163,13 @@ async def test_create_all_declares_hot_path_indexes(tmp_path):
|
||||
)
|
||||
}
|
||||
job_source_unique = [
|
||||
constraint["column_names"]
|
||||
for constraint in database.get_unique_constraints("job_source")
|
||||
constraint["column_names"] for constraint in database.get_unique_constraints("job_source")
|
||||
]
|
||||
document_tag_unique = [
|
||||
constraint["column_names"]
|
||||
for constraint in database.get_unique_constraints("document_tag")
|
||||
constraint["column_names"] for constraint in database.get_unique_constraints("document_tag")
|
||||
]
|
||||
person_tag_unique = [
|
||||
constraint["column_names"]
|
||||
for constraint in database.get_unique_constraints("person_tag")
|
||||
constraint["column_names"] for constraint in database.get_unique_constraints("person_tag")
|
||||
]
|
||||
return indexes, job_source_unique, document_tag_unique, person_tag_unique
|
||||
|
||||
@@ -252,11 +249,11 @@ async def test_reconcile_legacy_job_source_columns_drops_executed_at(tmp_path):
|
||||
await connection.execute(
|
||||
text(
|
||||
'create table "job_source" ('
|
||||
'id char(32) not null primary key, '
|
||||
'job_id char(32) not null, '
|
||||
'source_id char(32) not null, '
|
||||
'status varchar(11) not null, '
|
||||
'executed_at datetime not null, '
|
||||
"id char(32) not null primary key, "
|
||||
"job_id char(32) not null, "
|
||||
"source_id char(32) not null, "
|
||||
"status varchar(11) not null, "
|
||||
"executed_at datetime not null, "
|
||||
'constraint "uq_job_source_job_source" unique ("job_id", "source_id"), '
|
||||
'foreign key("job_id") references "job" ("id"), '
|
||||
'foreign key("source_id") references "source" ("id")'
|
||||
@@ -291,14 +288,14 @@ async def test_reconcile_canonical_media_paths_normalizes_source_and_photo_paths
|
||||
await connection.execute(
|
||||
text(
|
||||
'insert into "person" (id, given_names, last_name, created_at, updated_at) '
|
||||
'values (:id, :given_names, :last_name, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)'
|
||||
"values (:id, :given_names, :last_name, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
|
||||
),
|
||||
{"id": "11" * 16, "given_names": "Portrait", "last_name": "Person"},
|
||||
)
|
||||
await connection.execute(
|
||||
text(
|
||||
'insert into "photo" (id, person_id, path, is_primary, created_at, updated_at) '
|
||||
'values (:id, :person_id, :path, :is_primary, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)'
|
||||
"values (:id, :person_id, :path, :is_primary, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
|
||||
),
|
||||
{
|
||||
"id": "44" * 16,
|
||||
@@ -310,7 +307,7 @@ async def test_reconcile_canonical_media_paths_normalizes_source_and_photo_paths
|
||||
await connection.execute(
|
||||
text(
|
||||
'insert into "document" (id, name, created_at, updated_at) '
|
||||
'values (:id, :name, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)'
|
||||
"values (:id, :name, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
|
||||
),
|
||||
{"id": "22" * 16, "name": "Doc"},
|
||||
)
|
||||
|
||||
@@ -109,10 +109,7 @@ def _declared_env_example_keys(*, include_commented: bool) -> set[str]:
|
||||
|
||||
def _active_env_example_values() -> dict[str, str]:
|
||||
text = _read(".env.example")
|
||||
return {
|
||||
key: value.strip()
|
||||
for key, value in re.findall(r"^\s*([A-Z0-9_]+)\s*=\s*(.*)$", text, flags=re.MULTILINE)
|
||||
}
|
||||
return {key: value.strip() for key, value in re.findall(r"^\s*([A-Z0-9_]+)\s*=\s*(.*)$", text, flags=re.MULTILINE)}
|
||||
|
||||
|
||||
def _normalize_env_path_value(value: str | None) -> str | None:
|
||||
|
||||
@@ -57,9 +57,7 @@ def _source_files() -> list[Path]:
|
||||
|
||||
|
||||
def _is_registered_with_framework(node: ast.FunctionDef | ast.AsyncFunctionDef | ast.ClassDef) -> bool:
|
||||
return any(
|
||||
ast.unparse(decorator).startswith(REGISTRATION_DECORATOR_PREFIXES) for decorator in node.decorator_list
|
||||
)
|
||||
return any(ast.unparse(decorator).startswith(REGISTRATION_DECORATOR_PREFIXES) for decorator in node.decorator_list)
|
||||
|
||||
|
||||
def _public_definitions() -> dict[str, str]:
|
||||
|
||||
@@ -35,9 +35,7 @@ async def _document_ids(settings: Settings) -> set[str]:
|
||||
|
||||
async def _source_counts_by_document(settings: Settings) -> dict[str, int]:
|
||||
async with session_scope(settings=settings) as session:
|
||||
rows = await session.exec(
|
||||
select(Source.document_id, func.count(Source.id)).group_by(Source.document_id)
|
||||
)
|
||||
rows = await session.exec(select(Source.document_id, func.count(Source.id)).group_by(Source.document_id))
|
||||
return {str(document_id): int(count) for document_id, count in rows}
|
||||
|
||||
|
||||
@@ -93,9 +91,7 @@ async def assert_storage_reconciliation(*, upload_dir: Path, settings: Settings)
|
||||
if mismatches:
|
||||
report = "\n".join(f"- {item}" for item in mismatches)
|
||||
raise AssertionError(
|
||||
"Storage reconciliation mismatch(es) detected.\n"
|
||||
f"Reconciling item count: {len(mismatches)}\n"
|
||||
f"{report}"
|
||||
f"Storage reconciliation mismatch(es) detected.\nReconciling item count: {len(mismatches)}\n{report}"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -129,11 +129,7 @@ def _notifies_negative(tree: ast.Module) -> bool:
|
||||
):
|
||||
continue
|
||||
for keyword in node.keywords:
|
||||
if (
|
||||
keyword.arg == "type"
|
||||
and isinstance(keyword.value, ast.Constant)
|
||||
and keyword.value.value == "negative"
|
||||
):
|
||||
if keyword.arg == "type" and isinstance(keyword.value, ast.Constant) and keyword.value.value == "negative":
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -149,6 +145,4 @@ def test_no_page_hand_rolls_error_notifications():
|
||||
offenders = sorted(
|
||||
path.stem for path in _page_paths() if _notifies_negative(ast.parse(path.read_text(encoding="utf-8")))
|
||||
)
|
||||
assert offenders == [], (
|
||||
f"Pages must render errors via error_presenter.show_error, not ui.notify: {offenders}"
|
||||
)
|
||||
assert offenders == [], f"Pages must render errors via error_presenter.show_error, not ui.notify: {offenders}"
|
||||
|
||||
@@ -153,7 +153,7 @@ def test_export_import_migration_backfills_legacy_portraits_and_homepage_images(
|
||||
connection.execute(
|
||||
text(
|
||||
'insert into "person" (id, full_name, portrait_path, created_at, updated_at) '
|
||||
'values (:id, :full_name, :portrait_path, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)'
|
||||
"values (:id, :full_name, :portrait_path, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
|
||||
),
|
||||
{"id": person_id, "full_name": "Legacy Portrait", "portrait_path": "persons/legacy/portrait.png"},
|
||||
)
|
||||
@@ -264,7 +264,7 @@ def test_migration_backfills_legacy_media_when_photo_table_contains_stale_rows(t
|
||||
connection.execute(
|
||||
text(
|
||||
'insert into "person" (id, full_name, portrait_path, created_at, updated_at) '
|
||||
'values (:id, :full_name, :portrait_path, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)'
|
||||
"values (:id, :full_name, :portrait_path, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)"
|
||||
),
|
||||
{"id": person_id, "full_name": "Legacy Portrait", "portrait_path": "persons/legacy/portrait.png"},
|
||||
)
|
||||
|
||||
@@ -56,8 +56,7 @@ def app_client(tmp_path_factory: pytest.TempPathFactory) -> Generator[tuple[Fast
|
||||
expected_path = Path(database.path).resolve()
|
||||
if runtime_path != expected_path:
|
||||
raise RuntimeError(
|
||||
"Refusing to initialize destructive UI fixtures against "
|
||||
f"{runtime_path}; expected {expected_path}"
|
||||
f"Refusing to initialize destructive UI fixtures against {runtime_path}; expected {expected_path}"
|
||||
)
|
||||
yield app, client
|
||||
|
||||
|
||||
@@ -30,12 +30,8 @@ def test_person_selector_label_disambiguates_without_changing_identity():
|
||||
|
||||
|
||||
def test_family_search_url_uses_fixed_person_details_route():
|
||||
assert family_search_url("G8T4-MDQ") == (
|
||||
"https://www.familysearch.org/tree/person/details/G8T4-MDQ"
|
||||
)
|
||||
assert family_search_url("G8T4-MDQ") == ("https://www.familysearch.org/tree/person/details/G8T4-MDQ")
|
||||
|
||||
|
||||
def test_google_maps_search_url_encodes_place_query():
|
||||
assert google_maps_search_url("New York, NY") == (
|
||||
"https://www.google.com/maps/search/?api=1&query=New+York%2C+NY"
|
||||
)
|
||||
assert google_maps_search_url("New York, NY") == ("https://www.google.com/maps/search/?api=1&query=New+York%2C+NY")
|
||||
|
||||
@@ -184,9 +184,7 @@ class TestJobsPageRendering:
|
||||
assert "Delete is blocked while the job is processing." in response.text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_job_delete_page_allows_deletion_for_queued_job(
|
||||
self, app_client, seed_document_with_unlinked_job
|
||||
):
|
||||
async def test_job_delete_page_allows_deletion_for_queued_job(self, app_client, seed_document_with_unlinked_job):
|
||||
_, client = app_client
|
||||
_, job_id = seed_document_with_unlinked_job
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class TestPageRendering:
|
||||
assert response.status_code == 200
|
||||
assert "Home" in response.text
|
||||
assert "Edit Home Page" in response.text
|
||||
assert '/homepage' in response.text
|
||||
assert "/homepage" in response.text
|
||||
|
||||
def test_homepage_edit_page_renders(self, app_client):
|
||||
"""GET /ui/homepage/edit renders the edit page."""
|
||||
|
||||
Reference in New Issue
Block a user