mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(gate): clear the xenon complexity failure + fixable test warnings
- transcript_retention.py: split select_prunable_transcripts into small helpers so the module averages complexity rank A (was B — failed make quality / xenon). - pyproject: move the markers table from [tool.coverage.run] (coverage warned 'Unrecognized option') to [tool.pytest.ini_options] where it belongs. - HTTP_422_UNPROCESSABLE_ENTITY -> HTTP_422_UNPROCESSABLE_CONTENT (old name deprecated) in the tasks/product/settings routes + the validation middleware. - conftest: drop pool_pre_ping on the per-test engine — pointless for a fresh per-test engine and it leaves an un-awaited asyncpg Connection._cancel coroutine that surfaced as a RuntimeWarning across ~30 integration tests.
This commit is contained in:
+6
-6
@@ -237,6 +237,12 @@ testpaths = ["tests"]
|
|||||||
python_files = ["test_*.py"]
|
python_files = ["test_*.py"]
|
||||||
asyncio_default_fixture_loop_scope = "function"
|
asyncio_default_fixture_loop_scope = "function"
|
||||||
addopts = "--cov=roboco --cov-report=term-missing"
|
addopts = "--cov=roboco --cov-report=term-missing"
|
||||||
|
markers = [
|
||||||
|
"asyncio: mark tests as async",
|
||||||
|
"slow: marks tests as slow",
|
||||||
|
"integration: marks tests as integration tests",
|
||||||
|
"unit: marks tests as unit tests",
|
||||||
|
]
|
||||||
|
|
||||||
[tool.coverage.run]
|
[tool.coverage.run]
|
||||||
# Coverage core. Python 3.12+ supports sys.monitoring; the legacy `pytrace`
|
# Coverage core. Python 3.12+ supports sys.monitoring; the legacy `pytrace`
|
||||||
@@ -286,12 +292,6 @@ omit = [
|
|||||||
# Auto-generated migrations.
|
# Auto-generated migrations.
|
||||||
"alembic/*",
|
"alembic/*",
|
||||||
]
|
]
|
||||||
markers = [
|
|
||||||
"asyncio: mark tests as async",
|
|
||||||
"slow: marks tests as slow",
|
|
||||||
"integration: marks tests as integration tests",
|
|
||||||
"unit: marks tests as unit tests",
|
|
||||||
]
|
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Vulture Configuration
|
# Vulture Configuration
|
||||||
|
|||||||
@@ -389,7 +389,7 @@ async def request_validation_handler(request: Request, exc: Exception) -> JSONRe
|
|||||||
if remediate is not None:
|
if remediate is not None:
|
||||||
content["remediate"] = remediate
|
content["remediate"] = remediate
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=http_status.HTTP_422_UNPROCESSABLE_ENTITY,
|
status_code=http_status.HTTP_422_UNPROCESSABLE_CONTENT,
|
||||||
content=content,
|
content=content,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ async def create_product(
|
|||||||
detail="Duplicate cell: each team may map to at most one project.",
|
detail="Duplicate cell: each team may map to at most one project.",
|
||||||
) from e
|
) from e
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status.HTTP_422_UNPROCESSABLE_ENTITY,
|
status.HTTP_422_UNPROCESSABLE_CONTENT,
|
||||||
detail="Invalid cell mapping: project_id does not reference a project.",
|
detail="Invalid cell mapping: project_id does not reference a project.",
|
||||||
) from e
|
) from e
|
||||||
return product_to_response(product)
|
return product_to_response(product)
|
||||||
@@ -131,7 +131,7 @@ async def update_product(
|
|||||||
detail="Duplicate cell: each team may map to at most one project.",
|
detail="Duplicate cell: each team may map to at most one project.",
|
||||||
) from e
|
) from e
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status.HTTP_422_UNPROCESSABLE_ENTITY,
|
status.HTTP_422_UNPROCESSABLE_CONTENT,
|
||||||
detail="Invalid cell mapping: project_id does not reference a project.",
|
detail="Invalid cell mapping: project_id does not reference a project.",
|
||||||
) from e
|
) from e
|
||||||
return product_to_response(product)
|
return product_to_response(product)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ async def update_setting(
|
|||||||
await service.set(key, data.value)
|
await service.set(key, data.value)
|
||||||
except SettingValidationError as exc:
|
except SettingValidationError as exc:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc)
|
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT, detail=str(exc)
|
||||||
) from exc
|
) from exc
|
||||||
# Write route commits explicitly (get_db auto-commit is unreliable).
|
# Write route commits explicitly (get_db auto-commit is unreliable).
|
||||||
await db.commit()
|
await db.commit()
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ async def create_task(
|
|||||||
agent_row = await get_agent_by_slug(db, data.assigned_to)
|
agent_row = await get_agent_by_slug(db, data.assigned_to)
|
||||||
if agent_row is None:
|
if agent_row is None:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
status_code=status.HTTP_422_UNPROCESSABLE_CONTENT,
|
||||||
detail={
|
detail={
|
||||||
"error": {
|
"error": {
|
||||||
"code": "ASSIGNEE_NOT_FOUND",
|
"code": "ASSIGNEE_NOT_FOUND",
|
||||||
|
|||||||
@@ -37,6 +37,19 @@ def is_agent_owned_dir(dir_name: str, workspaces_root: str) -> bool:
|
|||||||
return bool(encoded_root) and dir_name.startswith(encoded_root)
|
return bool(encoded_root) and dir_name.startswith(encoded_root)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_old_transcript(path: Path, cutoff_epoch: float) -> bool:
|
||||||
|
"""True if ``path`` is a regular .jsonl file last modified before the cutoff."""
|
||||||
|
try:
|
||||||
|
return path.is_file() and path.stat().st_mtime < cutoff_epoch
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _old_transcripts_in(directory: Path, cutoff_epoch: float) -> list[Path]:
|
||||||
|
"""Old ``*.jsonl`` transcripts directly inside one agent-owned dir."""
|
||||||
|
return [t for t in directory.glob("*.jsonl") if _is_old_transcript(t, cutoff_epoch)]
|
||||||
|
|
||||||
|
|
||||||
def select_prunable_transcripts(
|
def select_prunable_transcripts(
|
||||||
projects_root: Path, workspaces_root: str, cutoff_epoch: float
|
projects_root: Path, workspaces_root: str, cutoff_epoch: float
|
||||||
) -> list[Path]:
|
) -> list[Path]:
|
||||||
@@ -50,12 +63,6 @@ def select_prunable_transcripts(
|
|||||||
return []
|
return []
|
||||||
prunable: list[Path] = []
|
prunable: list[Path] = []
|
||||||
for child in sorted(projects_root.iterdir()):
|
for child in sorted(projects_root.iterdir()):
|
||||||
if not child.is_dir() or not is_agent_owned_dir(child.name, workspaces_root):
|
if child.is_dir() and is_agent_owned_dir(child.name, workspaces_root):
|
||||||
continue
|
prunable.extend(_old_transcripts_in(child, cutoff_epoch))
|
||||||
for transcript in child.glob("*.jsonl"):
|
|
||||||
try:
|
|
||||||
if transcript.is_file() and transcript.stat().st_mtime < cutoff_epoch:
|
|
||||||
prunable.append(transcript)
|
|
||||||
except OSError:
|
|
||||||
continue
|
|
||||||
return prunable
|
return prunable
|
||||||
|
|||||||
+4
-1
@@ -214,7 +214,10 @@ async def db_session(_test_database_url: str) -> AsyncIterator[AsyncSession]:
|
|||||||
Each test gets its own session and connection; teardown rolls back any
|
Each test gets its own session and connection; teardown rolls back any
|
||||||
uncommitted state and disposes the engine to keep connection counts low.
|
uncommitted state and disposes the engine to keep connection counts low.
|
||||||
"""
|
"""
|
||||||
engine = create_async_engine(_test_database_url, future=True, pool_pre_ping=True)
|
# No pool_pre_ping: a fresh per-test engine can't have stale connections, and
|
||||||
|
# pre-ping on asyncpg leaves an un-awaited Connection._cancel coroutine that
|
||||||
|
# surfaces as a RuntimeWarning during GC.
|
||||||
|
engine = create_async_engine(_test_database_url, future=True)
|
||||||
factory = async_sessionmaker(
|
factory = async_sessionmaker(
|
||||||
bind=engine, class_=AsyncSession, expire_on_commit=False
|
bind=engine, class_=AsyncSession, expire_on_commit=False
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user