diff --git a/backend/app/routers/analyze.py b/backend/app/routers/analyze.py index 495ec5df..022c583a 100644 --- a/backend/app/routers/analyze.py +++ b/backend/app/routers/analyze.py @@ -1,4 +1,5 @@ """Full analysis router - POST /analyze/ and POST /analyze/zip/.""" + from __future__ import annotations import time diff --git a/backend/app/routers/share.py b/backend/app/routers/share.py index da1a100f..46978153 100644 --- a/backend/app/routers/share.py +++ b/backend/app/routers/share.py @@ -23,13 +23,18 @@ def create_share(payload: ShareCreateRequest, db: Session = Depends(get_db)): token = "" for _ in range(5): candidate = secrets.token_urlsafe(8) - exists = db.execute(select(SharedSnippet).where(SharedSnippet.token == candidate)).scalar_one_or_none() + exists = db.execute( + select(SharedSnippet).where(SharedSnippet.token == candidate) + ).scalar_one_or_none() if exists is None: token = candidate break if not token: - raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Could not create share token") + raise HTTPException( + status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + detail="Could not create share token", + ) record = SharedSnippet( token=token, @@ -56,13 +61,24 @@ def get_share(token: str, db: Session = Depends(get_db)): _Base.metadata.create_all(bind=db.get_bind()) - record = db.execute(select(SharedSnippet).where(SharedSnippet.token == token)).scalar_one_or_none() + record = db.execute( + select(SharedSnippet).where(SharedSnippet.token == token) + ).scalar_one_or_none() if record is None: # fallback: try raw SQL in case ORM mapping/env differences hide the record from sqlalchemy import text - raw = db.execute(text("SELECT token, code, result_json, created_at FROM shares WHERE token = :t"), {"t": token}).first() + + raw = db.execute( + text( + "SELECT token, code, result_json, created_at FROM shares WHERE token = :t" + ), + {"t": token}, + ).first() if raw is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Shared result not found or expired") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Shared result not found or expired", + ) # parse created_at which may be string or datetime token_val, code_val, result_json_val, created_at_val = raw @@ -74,20 +90,32 @@ def get_share(token: str, db: Session = Depends(get_db)): created_at = _dt.datetime.fromisoformat(created_at) except Exception: try: - created_at = _dt.datetime.strptime(created_at, "%Y-%m-%d %H:%M:%S.%f") + created_at = _dt.datetime.strptime( + created_at, "%Y-%m-%d %H:%M:%S.%f" + ) except Exception: created_at = None if created_at is None: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Shared result not found or expired") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Shared result not found or expired", + ) if created_at.tzinfo is None: created_at = created_at.replace(tzinfo=_dt.timezone.utc) if created_at < _dt.datetime.now(_dt.timezone.utc) - _dt.timedelta(days=7): - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Shared result expired") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail="Shared result expired" + ) - return ShareRecord(id=token_val, code=code_val, result=json.loads(result_json_val), created_at=created_at.isoformat()) + return ShareRecord( + id=token_val, + code=code_val, + result=json.loads(result_json_val), + created_at=created_at.isoformat(), + ) # expire shares older than 7 days — normalize tzinfo if necessary from datetime import datetime, timezone, timedelta @@ -97,7 +125,9 @@ def get_share(token: str, db: Session = Depends(get_db)): created_at = created_at.replace(tzinfo=timezone.utc) if created_at < datetime.now(timezone.utc) - timedelta(days=7): - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Shared result expired") + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, detail="Shared result expired" + ) return ShareRecord( id=record.token, diff --git a/backend/app/services/code_assistant.py b/backend/app/services/code_assistant.py index 40ec2502..2b8c97f4 100644 --- a/backend/app/services/code_assistant.py +++ b/backend/app/services/code_assistant.py @@ -12,6 +12,17 @@ # ── Language Detection ───────────────────────────────────────────────────────── LANG_SIGNATURES: dict[str, list[str]] = { + "Swift": [ + r"\bimport\s+Foundation\b", + r"\bfunc\s+\w+\s*\(", + r"\b(let|var)\s+\w+\s*:\s*\w+", + r"\bclass\s+\w+", + r"\bstruct\s+\w+", + r"\bprotocol\s+\w+", + r"\bextension\s+\w+", + r"\bguard\s+let\b", + r"\bprint\s*\(", + ], "Python": [ r"\bdef\s+\w+\s*\(", r"\bimport\s+\w+", @@ -52,13 +63,13 @@ r"\bint\s+main\s*\(", r"::\w+", ], - "Swift": [ + "Go": [ r"\bfunc\s+\w+\s*\(", - r"\bvar\s+\w+\s*:", - r"\blet\s+\w+\s*=", - r"print\s*\(", - r"import\s+\w+", - r"guard\s+let\b", + r"\bpackage\s+\w+", + r'\bimport\s+"', + r"fmt\.Print", + r"\bgo\s+func\b", + r":=", ], "PHP": [ r"<\?php", @@ -215,6 +226,7 @@ class BugPattern: "C++", "PHP", "Rust", + "Swift", ] ) diff --git a/backend/app/services/email_service.py b/backend/app/services/email_service.py index 42716064..3c977fb1 100644 --- a/backend/app/services/email_service.py +++ b/backend/app/services/email_service.py @@ -156,7 +156,7 @@ def _build_html(stats: dict, unsubscribe_url: str) -> str: score_line = f""" Average Score - {stats['avg_score']}/100 {emoji}{change} + {stats["avg_score"]}/100 {emoji}{change} """ bug_line = "" @@ -164,7 +164,7 @@ def _build_html(stats: dict, unsubscribe_url: str) -> str: bug_line = f""" Most Common Bug - {stats['top_bug']} + {stats["top_bug"]} """ return f""" @@ -176,32 +176,32 @@ def _build_html(stats: dict, unsubscribe_url: str) -> str:

QyverixAI Weekly Digest

-

{stats['week_start']} – {stats['week_end']}

+

{stats["week_start"]} – {stats["week_end"]}

Here's your weekly code analysis summary.

- + - + {score_line} - + {bug_line}
Analyses Run{stats['total_analyses']}{stats["total_analyses"]}
Languages{', '.join(stats['languages'])}{", ".join(stats["languages"])}
Issues Found{stats['total_issues']}{stats["total_issues"]}
- Open QyverixAI + Open QyverixAI
-

This email was sent to {stats['email']} because you subscribed to the QyverixAI weekly digest.

+

This email was sent to {stats["email"]} because you subscribed to the QyverixAI weekly digest.

Unsubscribe

diff --git a/backend/tests/test_digest.py b/backend/tests/test_digest.py index 698acdd7..1e3231f1 100644 --- a/backend/tests/test_digest.py +++ b/backend/tests/test_digest.py @@ -8,7 +8,8 @@ from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker -import sys, os +import sys +import os sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) diff --git a/backend/tests/test_endpoints.py b/backend/tests/test_endpoints.py index beb07e76..f2f00e23 100644 --- a/backend/tests/test_endpoints.py +++ b/backend/tests/test_endpoints.py @@ -2,14 +2,20 @@ QyverixAI — Test Suite Run: cd backend && pytest -v """ -import io -import zipfile + +import os +import sys import pytest from fastapi.testclient import TestClient -import sys, os +<<<<<<< HEAD +======= +import sys +import os +>>>>>>> fix/labeler-yaml sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) + from app import main as app_main client = TestClient(app_main.app) diff --git a/backend/tests/test_share.py b/backend/tests/test_share.py index 22826e0b..b3bcbe16 100644 --- a/backend/tests/test_share.py +++ b/backend/tests/test_share.py @@ -25,7 +25,7 @@ def _configure_test_db(monkeypatch, tmp_path): def test_create_and_fetch_share(monkeypatch, tmp_path): - session_local = _configure_test_db(monkeypatch, tmp_path) + _configure_test_db(monkeypatch, tmp_path) from fastapi.testclient import TestClient