You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
4.6 KiB
Python
152 lines
4.6 KiB
Python
"""CLI for running the data pipeline.
|
|
|
|
Usage:
|
|
fithia2 pipeline run # run all 5 steps
|
|
fithia2 pipeline run --step poller|fetcher|parser|features|labels
|
|
fithia2 pipeline run --start-date 2026-03-15
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import asyncio
|
|
import sys
|
|
|
|
from rich.console import Console
|
|
|
|
_console = Console(width=120)
|
|
|
|
STEPS = ["poller", "fetcher", "parser", "features", "labels"]
|
|
|
|
|
|
def _run_id() -> str:
|
|
from libs.common.ids import new_job_run_id
|
|
return new_job_run_id()
|
|
|
|
|
|
def _configure() -> None:
|
|
import logging
|
|
try:
|
|
from dotenv import load_dotenv
|
|
load_dotenv()
|
|
except ImportError:
|
|
pass
|
|
from libs.common.config import get_settings
|
|
from libs.common.logging import configure_logging
|
|
configure_logging(get_settings().log_level)
|
|
# Suppress noisy HTTP request logs from httpx
|
|
logging.getLogger("httpx").setLevel(logging.WARNING)
|
|
logging.getLogger("httpcore").setLevel(logging.WARNING)
|
|
|
|
|
|
async def _run_steps_async(
|
|
steps: list[str],
|
|
start_date: str | None,
|
|
end_date: str | None,
|
|
continue_on_error: bool = False,
|
|
) -> dict[str, dict | str]:
|
|
"""Run all pipeline steps in a single event loop to avoid asyncpg loop conflicts."""
|
|
from apps.pipeline.filing_poller.main import poll_filings
|
|
from apps.pipeline.filing_fetcher.main import fetch_exhibits
|
|
from apps.pipeline.event_parser.main import run_event_parser
|
|
from apps.pipeline.feature_builder.main import run_feature_builder
|
|
from apps.pipeline.label_generator.main import run_label_generator
|
|
|
|
results: dict[str, dict | str] = {}
|
|
for step in steps:
|
|
try:
|
|
if step == "poller":
|
|
results[step] = await poll_filings(_run_id(), start_date=start_date, end_date=end_date)
|
|
elif step == "fetcher":
|
|
results[step] = await fetch_exhibits(_run_id(), start_date=start_date, end_date=end_date)
|
|
elif step == "parser":
|
|
results[step] = await run_event_parser(_run_id(), start_date=start_date, end_date=end_date)
|
|
elif step == "features":
|
|
results[step] = await run_feature_builder(_run_id(), start_date=start_date, end_date=end_date)
|
|
elif step == "labels":
|
|
results[step] = await run_label_generator(_run_id(), start_date=start_date, end_date=end_date)
|
|
except Exception as exc:
|
|
results[step] = f"ERROR: {exc}"
|
|
if not continue_on_error:
|
|
raise
|
|
return results
|
|
|
|
|
|
_STEP_NAMES = {
|
|
"poller": "Filing Poller",
|
|
"fetcher": "Filing Fetcher",
|
|
"parser": "Event Parser",
|
|
"features": "Feature Builder",
|
|
"labels": "Label Generator",
|
|
}
|
|
|
|
|
|
def cmd_run(args: argparse.Namespace) -> None:
|
|
_configure()
|
|
|
|
steps = [args.step] if args.step else STEPS
|
|
|
|
for step in steps:
|
|
_console.print(f"\n[bold cyan]▶ {_STEP_NAMES[step]}[/]")
|
|
|
|
try:
|
|
all_results = asyncio.run(
|
|
_run_steps_async(steps, args.start_date, args.end_date, args.continue_on_error)
|
|
)
|
|
except Exception as exc:
|
|
_console.print(f"[red]FAILED: {exc}[/]")
|
|
sys.exit(1)
|
|
|
|
_console.print()
|
|
failed = False
|
|
for step in steps:
|
|
result = all_results.get(step, {})
|
|
if isinstance(result, str) and result.startswith("ERROR:"):
|
|
_console.print(f" [bold cyan]{_STEP_NAMES[step]}:[/] [red]{result}[/]")
|
|
failed = True
|
|
else:
|
|
parts = [f"{k}={v}" for k, v in (result.items() if isinstance(result, dict) else [])]
|
|
_console.print(f" [bold cyan]{_STEP_NAMES[step]}:[/] [green]done[/] {', '.join(parts)}")
|
|
|
|
if failed:
|
|
sys.exit(1)
|
|
|
|
_console.print("\n[bold green]Pipeline complete.[/]")
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="fithia2 Pipeline Runner")
|
|
sub = parser.add_subparsers(dest="command", required=True)
|
|
|
|
p = sub.add_parser("run", help="Run pipeline steps")
|
|
p.add_argument(
|
|
"--step", "-s",
|
|
choices=STEPS,
|
|
default=None,
|
|
help="Run a single step (default: all steps in order)",
|
|
)
|
|
p.add_argument(
|
|
"--start-date",
|
|
default=None,
|
|
metavar="YYYY-MM-DD",
|
|
help="Start date for filing poller (default: 7 days ago)",
|
|
)
|
|
p.add_argument(
|
|
"--end-date",
|
|
default=None,
|
|
metavar="YYYY-MM-DD",
|
|
help="End date for filing poller (default: today)",
|
|
)
|
|
p.add_argument(
|
|
"--continue-on-error",
|
|
action="store_true",
|
|
help="Continue to next step even if a step fails",
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
if args.command == "run":
|
|
cmd_run(args)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|