Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions openfoia/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3916,24 +3916,29 @@ def records_search(
if filing_type:
kwargs["filing_type"] = filing_type

with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
console=console,
) as progress:
progress.add_task(f"Searching {source} for '{query}'...", total=None)

try:
try:
if raw:
# Raw output is intended for pipes and scripts, so it must contain
# only JSON -- no spinner or Rich markup before the document.
result = asyncio.run(adapter.search(query, **kwargs))
except Exception as e:
rprint(f"[red]Search failed: {e}[/red]")
raise typer.Exit(1) from None
else:
with Progress(
SpinnerColumn(),
TextColumn("[progress.description]{task.description}"),
console=console,
) as progress:
progress.add_task(f"Searching {source} for '{query}'...", total=None)
result = asyncio.run(adapter.search(query, **kwargs))
except Exception as e:
rprint(f"[red]Search failed: {e}[/red]")
raise typer.Exit(1) from None

if raw:
rprint(
typer.echo(
json.dumps(
[e.to_dict() for e in result.entities[:limit]],
indent=2,
ensure_ascii=False,
default=str,
)
)
Expand Down
53 changes: 53 additions & 0 deletions tests/test_records_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
"""Regression tests for public-records CLI output."""

from __future__ import annotations

import json

from typer.testing import CliRunner

from openfoia.cli import app
from openfoia.records.base import RecordEntity, SearchResult


def test_records_search_raw_is_parseable_json_without_terminal_output(monkeypatch):
"""Raw mode must be pipe-safe even when upstream data has control characters."""

class Adapter:
async def search(self, query, **kwargs):
return SearchResult(
source="sec",
query=query,
total_results=1,
entities=[
RecordEntity(
entity_type="ORGANIZATION",
name="Uranium\x1fEnergy",
source="sec",
extra_data={"snippet": "filing\x00text"},
)
],
)

monkeypatch.setattr("openfoia.records.get_adapter", lambda source: Adapter())

result = CliRunner().invoke(
app,
["records", "search", "Uranium Energy", "--source", "sec", "--raw"],
)

assert result.exit_code == 0
assert "\x1f" not in result.stdout
assert "\x00" not in result.stdout
assert json.loads(result.stdout) == [
{
"entity_type": "ORGANIZATION",
"name": "Uranium\x1fEnergy",
"source": "sec",
"source_url": None,
"jurisdiction": None,
"status": None,
"identifiers": {},
"extra_data": {"snippet": "filing\x00text"},
}
]
Loading