Divyasri-18's picture
Initial commit
9a13e79 verified
Raw
History Blame Contribute Delete
4.98 kB
"""
CLI entry point for the Multi-Source Candidate Data Transformer.
Responsibilities:
- Parse command-line arguments (input paths, config path, output path).
- Orchestrate the pipeline: parse -> normalize -> merge -> project -> write output.
- Handle top-level errors and exit codes.
Business logic is delegated to parser, normalizer, merger, and projector modules.
"""
import argparse
from dataclasses import asdict
import json
import sys
from pathlib import Path
from typing import Any
from .normalizer import normalize_candidate
from .parser import read_ats_json, read_resume_pdf, read_github_profile, ParserError
from .merger import merge_candidates
from .projector import load_output_config, project_candidates
from .utils import write_json_file
# Project root is one level above src/
PROJECT_ROOT = Path(__file__).resolve().parent.parent
DEFAULT_ATS_PATH = PROJECT_ROOT / "inputs" / "ats.json"
DEFAULT_RESUME_PATH = PROJECT_ROOT / "inputs" / "resume.pdf"
DEFAULT_CONFIG_PATH = PROJECT_ROOT / "config" / "output_config.json"
DEFAULT_OUTPUT_PATH = PROJECT_ROOT / "output" / "final_candidate.json"
def _print_section(title: str, data: Any) -> None:
"""Print a labeled JSON block."""
print("========================")
print(title)
print("========================")
print()
print(json.dumps(data, indent=2, ensure_ascii=False))
print()
def main() -> int:
"""
Step 7 entry point: Parse CLI arguments and run the candidate transformation pipeline.
Returns:
Process exit code (0 = success, non-zero = failure).
"""
parser = argparse.ArgumentParser(
description="Multi-Source Candidate Data Transformer CLI."
)
parser.add_argument(
"--ats",
type=str,
default=str(DEFAULT_ATS_PATH),
help="Path to ATS JSON input file."
)
parser.add_argument(
"--resume",
type=str,
default=str(DEFAULT_RESUME_PATH),
help="Path to Resume PDF input file."
)
parser.add_argument(
"--config",
type=str,
default=str(DEFAULT_CONFIG_PATH),
help="Path to output projection configuration JSON file."
)
parser.add_argument(
"--output",
type=str,
default=str(DEFAULT_OUTPUT_PATH),
help="Path to save the projected output JSON file."
)
parser.add_argument(
"--github",
type=str,
default=None,
help="GitHub profile URL or username (optional third data source)."
)
args = parser.parse_args()
try:
# 1. Parse & Normalize
raw_ats = read_ats_json(args.ats)
raw_resume = read_resume_pdf(args.resume)
# 2. Normalize
normalized_ats = normalize_candidate(raw_ats)
normalized_resume = normalize_candidate(raw_resume)
# Attach raw dictionaries for provenance retrieval
normalized_ats["_raw"] = raw_ats
normalized_resume["_raw"] = raw_resume
candidates_to_merge = [normalized_ats, normalized_resume]
# Optional GitHub profile integration
if args.github:
raw_github = read_github_profile(args.github)
normalized_github = normalize_candidate(raw_github)
normalized_github["_raw"] = raw_github
candidates_to_merge.append(normalized_github)
# 3. Merge
merged_list = merge_candidates(candidates_to_merge)
# 4. Project
try:
config = load_output_config(args.config)
except FileNotFoundError:
print(f"Error: Configuration file not found at '{args.config}'", file=sys.stderr)
return 1
except json.JSONDecodeError as exc:
print(f"Error: Configuration file at '{args.config}' contains invalid JSON: {exc}", file=sys.stderr)
return 1
except Exception as exc:
print(f"Error: Unable to load configuration file: {exc}", file=sys.stderr)
return 1
projected_list = project_candidates(merged_list, config)
# 5. Print Final Output JSON
_print_section("FINAL OUTPUT JSON", projected_list)
# 6. Save to disk if output path is specified
if args.output:
try:
write_json_file(args.output, projected_list)
print(f"Successfully saved projected candidates to '{args.output}'")
except Exception as exc:
print(f"Error: Failed to write output file to '{args.output}': {exc}", file=sys.stderr)
return 1
return 0
except ParserError as exc:
print(f"Parser Error: {exc}", file=sys.stderr)
return 1
except Exception as exc:
print(f"Unexpected Pipeline Error: {exc}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())