Spaces:
Running
Running
Daniel Wiesmann commited on
Commit ·
ad8201c
1
Parent(s): 61f1033
Add ruff.toml and fix lint errors (imports, type hints, formatting)
Browse files- Add ruff.toml to configure lint rules (ignore BLE001/S110/B017 which are
intentional in health checks and error handling)
- Fix import sorting (I001) across api.py, lm.py, sql.py, test_lm.py, test_search.py
- Modernize type hints: Generator[str] instead of Generator[str, None, None]
(UP043), X | None instead of Optional[X] (UP045), collections.abc.Gen
erator instead of typing.Generator (UP035)
- Use str.removeprefix() instead of startswith + slicing (FURB188)
- Use from-module import instead of aliased import (PLR0402)
- Reformat all source and test files with ruff format
- ruff.toml +7 -0
- src/gazet/api.py +4 -5
- src/gazet/geometry.py +2 -2
- src/gazet/lm.py +2 -4
- src/gazet/sql.py +6 -5
- tests/test_config.py +1 -1
- tests/test_lm.py +1 -1
- tests/test_search.py +1 -1
ruff.toml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
target-version = "py313"
|
| 2 |
+
|
| 3 |
+
[lint]
|
| 4 |
+
# BLE001 – catching Exception is intentional in health checks and error-handling paths
|
| 5 |
+
# S110 – try/except/pass is intentional for health probes that must not crash
|
| 6 |
+
# B017 – pytest.raises(Exception) is acceptable for pydantic validation error checks
|
| 7 |
+
ignore = ["BLE001", "S110", "B017"]
|
src/gazet/api.py
CHANGED
|
@@ -1,15 +1,14 @@
|
|
| 1 |
import json
|
| 2 |
import logging
|
| 3 |
import uuid
|
|
|
|
| 4 |
from contextlib import asynccontextmanager
|
| 5 |
-
from
|
| 6 |
-
from typing import Any, Generator
|
| 7 |
-
from fastapi.responses import Response
|
| 8 |
|
| 9 |
import duckdb
|
| 10 |
import pandas as pd
|
| 11 |
from fastapi import FastAPI, HTTPException, Request
|
| 12 |
-
from fastapi.responses import StreamingResponse
|
| 13 |
|
| 14 |
from .export import to_feature_collection
|
| 15 |
from .geometry import normalize_geometry_to_geojson
|
|
@@ -83,7 +82,7 @@ def _df_to_records(df: pd.DataFrame) -> list[dict[str, Any]]:
|
|
| 83 |
|
| 84 |
def _run_stream(
|
| 85 |
base_con: duckdb.DuckDBPyConnection, query: str, backend: str = "gguf"
|
| 86 |
-
) -> Generator[str
|
| 87 |
"""Yield NDJSON lines as each stage of the search completes.
|
| 88 |
|
| 89 |
Event ``type`` values (in order of emission):
|
|
|
|
| 1 |
import json
|
| 2 |
import logging
|
| 3 |
import uuid
|
| 4 |
+
from collections.abc import AsyncIterator, Awaitable, Callable, Generator
|
| 5 |
from contextlib import asynccontextmanager
|
| 6 |
+
from typing import Any
|
|
|
|
|
|
|
| 7 |
|
| 8 |
import duckdb
|
| 9 |
import pandas as pd
|
| 10 |
from fastapi import FastAPI, HTTPException, Request
|
| 11 |
+
from fastapi.responses import Response, StreamingResponse
|
| 12 |
|
| 13 |
from .export import to_feature_collection
|
| 14 |
from .geometry import normalize_geometry_to_geojson
|
|
|
|
| 82 |
|
| 83 |
def _run_stream(
|
| 84 |
base_con: duckdb.DuckDBPyConnection, query: str, backend: str = "gguf"
|
| 85 |
+
) -> Generator[str]:
|
| 86 |
"""Yield NDJSON lines as each stage of the search completes.
|
| 87 |
|
| 88 |
Event ``type`` values (in order of emission):
|
src/gazet/geometry.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
| 1 |
import json
|
| 2 |
-
from typing import Any
|
| 3 |
|
| 4 |
import duckdb
|
| 5 |
import pandas as pd
|
|
@@ -38,7 +38,7 @@ def normalize_geometry_to_geojson(
|
|
| 38 |
if sample.empty:
|
| 39 |
return result_df
|
| 40 |
|
| 41 |
-
def _simplify(val: Any) ->
|
| 42 |
if val is None:
|
| 43 |
return None
|
| 44 |
if isinstance(val, (bytes, bytearray, memoryview)):
|
|
|
|
| 1 |
import json
|
| 2 |
+
from typing import Any
|
| 3 |
|
| 4 |
import duckdb
|
| 5 |
import pandas as pd
|
|
|
|
| 38 |
if sample.empty:
|
| 39 |
return result_df
|
| 40 |
|
| 41 |
+
def _simplify(val: Any) -> str | None:
|
| 42 |
if val is None:
|
| 43 |
return None
|
| 44 |
if isinstance(val, (bytes, bytearray, memoryview)):
|
src/gazet/lm.py
CHANGED
|
@@ -174,8 +174,7 @@ def _postprocess_sql(text: str) -> str:
|
|
| 174 |
cleaned = text.strip()
|
| 175 |
if "```sql" in cleaned:
|
| 176 |
cleaned = cleaned.split("```sql", 1)[1]
|
| 177 |
-
|
| 178 |
-
cleaned = cleaned[3:]
|
| 179 |
if "```" in cleaned:
|
| 180 |
cleaned = cleaned.split("```", 1)[0]
|
| 181 |
return cleaned.strip()
|
|
@@ -302,8 +301,7 @@ def generate_places(user_query: str) -> PlacesResult:
|
|
| 302 |
# Strip markdown fences if the model wrapped the JSON
|
| 303 |
if raw_output.startswith("```"):
|
| 304 |
raw_output = raw_output.split("```")[1]
|
| 305 |
-
|
| 306 |
-
raw_output = raw_output[4:]
|
| 307 |
raw_output = raw_output.strip()
|
| 308 |
|
| 309 |
try:
|
|
|
|
| 174 |
cleaned = text.strip()
|
| 175 |
if "```sql" in cleaned:
|
| 176 |
cleaned = cleaned.split("```sql", 1)[1]
|
| 177 |
+
cleaned = cleaned.removeprefix("```")
|
|
|
|
| 178 |
if "```" in cleaned:
|
| 179 |
cleaned = cleaned.split("```", 1)[0]
|
| 180 |
return cleaned.strip()
|
|
|
|
| 301 |
# Strip markdown fences if the model wrapped the JSON
|
| 302 |
if raw_output.startswith("```"):
|
| 303 |
raw_output = raw_output.split("```")[1]
|
| 304 |
+
raw_output = raw_output.removeprefix("json")
|
|
|
|
| 305 |
raw_output = raw_output.strip()
|
| 306 |
|
| 307 |
try:
|
src/gazet/sql.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
import logging
|
| 2 |
import re
|
| 3 |
-
from
|
|
|
|
| 4 |
|
| 5 |
import duckdb
|
| 6 |
import pandas as pd
|
|
@@ -91,7 +92,7 @@ def _normalize_ne_subtypes(sql: str) -> str:
|
|
| 91 |
return sql
|
| 92 |
|
| 93 |
|
| 94 |
-
def _strip_fences(sql:
|
| 95 |
"""Remove markdown code fences that the LM may wrap the SQL in."""
|
| 96 |
if not sql:
|
| 97 |
return ""
|
|
@@ -105,7 +106,7 @@ def _execute_sql(
|
|
| 105 |
sql: str,
|
| 106 |
label: str,
|
| 107 |
iteration: int,
|
| 108 |
-
) -> Generator[dict[str, Any]
|
| 109 |
"""Execute SQL and yield result/error events. Shared by both paths."""
|
| 110 |
try:
|
| 111 |
result_df = con.execute(sql).fetchdf()
|
|
@@ -135,7 +136,7 @@ def run_geo_sql_gguf(
|
|
| 135 |
con: duckdb.DuckDBPyConnection,
|
| 136 |
user_query: str,
|
| 137 |
candidates_df: pd.DataFrame,
|
| 138 |
-
) -> Generator[dict[str, Any]
|
| 139 |
"""Single-shot text-to-SQL via the finetuned GGUF model (llama-server).
|
| 140 |
|
| 141 |
Event types:
|
|
@@ -178,7 +179,7 @@ def run_geo_sql_dspy(
|
|
| 178 |
user_query: str,
|
| 179 |
candidates_df: pd.DataFrame,
|
| 180 |
max_iterations: int = MAX_SQL_ITERATIONS,
|
| 181 |
-
) -> Generator[dict[str, Any]
|
| 182 |
"""Code-act retry loop using the DSPy SQL writer (Ollama / cloud LM).
|
| 183 |
|
| 184 |
Same event types as ``run_geo_sql_gguf``.
|
|
|
|
| 1 |
import logging
|
| 2 |
import re
|
| 3 |
+
from collections.abc import Generator
|
| 4 |
+
from typing import Any
|
| 5 |
|
| 6 |
import duckdb
|
| 7 |
import pandas as pd
|
|
|
|
| 92 |
return sql
|
| 93 |
|
| 94 |
|
| 95 |
+
def _strip_fences(sql: str | None) -> str:
|
| 96 |
"""Remove markdown code fences that the LM may wrap the SQL in."""
|
| 97 |
if not sql:
|
| 98 |
return ""
|
|
|
|
| 106 |
sql: str,
|
| 107 |
label: str,
|
| 108 |
iteration: int,
|
| 109 |
+
) -> Generator[dict[str, Any]]:
|
| 110 |
"""Execute SQL and yield result/error events. Shared by both paths."""
|
| 111 |
try:
|
| 112 |
result_df = con.execute(sql).fetchdf()
|
|
|
|
| 136 |
con: duckdb.DuckDBPyConnection,
|
| 137 |
user_query: str,
|
| 138 |
candidates_df: pd.DataFrame,
|
| 139 |
+
) -> Generator[dict[str, Any]]:
|
| 140 |
"""Single-shot text-to-SQL via the finetuned GGUF model (llama-server).
|
| 141 |
|
| 142 |
Event types:
|
|
|
|
| 179 |
user_query: str,
|
| 180 |
candidates_df: pd.DataFrame,
|
| 181 |
max_iterations: int = MAX_SQL_ITERATIONS,
|
| 182 |
+
) -> Generator[dict[str, Any]]:
|
| 183 |
"""Code-act retry loop using the DSPy SQL writer (Ollama / cloud LM).
|
| 184 |
|
| 185 |
Same event types as ``run_geo_sql_gguf``.
|
tests/test_config.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
import os
|
| 4 |
from pathlib import Path
|
| 5 |
|
| 6 |
-
|
| 7 |
|
| 8 |
|
| 9 |
class TestPreferNormalized:
|
|
|
|
| 3 |
import os
|
| 4 |
from pathlib import Path
|
| 5 |
|
| 6 |
+
from gazet import config
|
| 7 |
|
| 8 |
|
| 9 |
class TestPreferNormalized:
|
tests/test_lm.py
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
"""Tests for gazet.lm — prompt templates, postprocessing, and GGUF helpers."""
|
| 2 |
|
| 3 |
from gazet.lm import (
|
| 4 |
-
_postprocess_sql,
|
| 5 |
_PLACES_SYSTEM_PROMPT,
|
| 6 |
_SYSTEM_PROMPT_TEMPLATE,
|
| 7 |
_USER_PROMPT_TEMPLATE,
|
|
|
|
| 8 |
)
|
| 9 |
from gazet.schemas import PlacesResult
|
| 10 |
|
|
|
|
| 1 |
"""Tests for gazet.lm — prompt templates, postprocessing, and GGUF helpers."""
|
| 2 |
|
| 3 |
from gazet.lm import (
|
|
|
|
| 4 |
_PLACES_SYSTEM_PROMPT,
|
| 5 |
_SYSTEM_PROMPT_TEMPLATE,
|
| 6 |
_USER_PROMPT_TEMPLATE,
|
| 7 |
+
_postprocess_sql,
|
| 8 |
)
|
| 9 |
from gazet.schemas import PlacesResult
|
| 10 |
|
tests/test_search.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
| 2 |
|
| 3 |
import pandas as pd
|
| 4 |
|
|
|
|
| 5 |
from gazet.search import (
|
| 6 |
get_by_id,
|
| 7 |
get_division_by_id,
|
|
@@ -10,7 +11,6 @@ from gazet.search import (
|
|
| 10 |
search_divisions_area,
|
| 11 |
search_natural_earth,
|
| 12 |
)
|
| 13 |
-
from gazet.schemas import Place
|
| 14 |
|
| 15 |
|
| 16 |
class TestSearchDivisionsArea:
|
|
|
|
| 2 |
|
| 3 |
import pandas as pd
|
| 4 |
|
| 5 |
+
from gazet.schemas import Place
|
| 6 |
from gazet.search import (
|
| 7 |
get_by_id,
|
| 8 |
get_division_by_id,
|
|
|
|
| 11 |
search_divisions_area,
|
| 12 |
search_natural_earth,
|
| 13 |
)
|
|
|
|
| 14 |
|
| 15 |
|
| 16 |
class TestSearchDivisionsArea:
|