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 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 collections.abc import AsyncIterator, Awaitable, Callable
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, None, None]:
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, Optional
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) -> Optional[str]:
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
- if cleaned.startswith("```"):
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
- if raw_output.startswith("json"):
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 typing import Any, Generator, Optional
 
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: Optional[str]) -> str:
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], None, None]:
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], None, None]:
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], None, None]:
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
- import gazet.config as config
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: