Skill Tracer
Skills › Scientific Agent Skills › exploratory-data-analysis › tabular_profile.py

tabular_profile.py

109 lines · skills/exploratory-data-analysis/scripts/tabular_profile.py at 5f2bc03

1#!/usr/bin/env python3
2"""Bounded aggregate schema/profile CLI for local CSV and TSV files."""
3
4from __future__ import annotations
5
6import argparse
7
8from _capabilities import capability_for_path
9from _common import (
10 DEFAULT_MAX_FILE_BYTES,
11 DEFAULT_MAX_ROWS,
12 CliError,
13 bounded_file_limit,
14 checked_input_file,
15 emit_json,
16 run_cli,
18from _tabular import profile_table
21def build_parser() -> argparse.ArgumentParser:
22 parser = argparse.ArgumentParser(
23 description=(
24 "Profile bounded local CSV/TSV rows with aggregate statistics. "
25 "Raw cell values and full paths are never emitted."
26 )
27 )
28 parser.add_argument("input", help="Local .csv or .tsv path inside --root")
29 parser.add_argument(
30 "--root",
31 default=".",
32 help="Existing local directory that bounds all input/output paths",
33 )
34 parser.add_argument(
35 "--max-bytes",
36 type=int,
37 default=DEFAULT_MAX_FILE_BYTES,
38 help=f"Maximum input bytes (hard ceiling: {512 * 1024 * 1024})",
39 )
40 parser.add_argument(
41 "--max-rows",
42 type=int,
43 default=DEFAULT_MAX_ROWS,
44 help="Maximum rows to scan (hard ceiling: 1000000)",
45 )
46 parser.add_argument(
47 "--missing-token",
48 action="append",
49 help=(
50 "Explicit additional missing code; repeat as needed. Empty/whitespace "
51 "is always missing. Values such as NA are not assumed automatically."
52 ),
53 )
54 parser.add_argument(
55 "--reveal-identifiers",
56 action="store_true",
57 help="Emit sanitized column identifiers; values remain redacted",
58 )
59 parser.add_argument("--output", help="Optional local .json output path")
60 parser.add_argument(
61 "--force",
62 action="store_true",
63 help="Allow replacement of an existing regular output file",
64 )
65 return parser
68def _main() -> None:
69 args = build_parser().parse_args()
70 max_bytes = bounded_file_limit(args.max_bytes)
71 path = checked_input_file(
72 args.input,
73 root=args.root,
74 suffixes={".csv", ".tsv"},
75 max_bytes=max_bytes,
76 )
77 capability = capability_for_path(path)
78 if capability["tier"] != "automated_core":
79 raise CliError("the selected file has no core tabular capability")
80 report = {
81 "schema_version": "1.1",
82 "capability": capability,
83 "analysis": profile_table(
84 path,
85 max_rows=args.max_rows,
86 missing_tokens=args.missing_token,
87 reveal_identifiers=args.reveal_identifiers,
88 ),
89 "security": {
90 "local_only": True,
91 "file_text_is_untrusted_data": True,
92 "embedded_instructions_followed": False,
93 "raw_values_and_full_paths_emitted": False,
94 },
95 }
96 emit_json(
97 report,
98 output=args.output,
99 root=args.root,
100 force=args.force,
101 )
104def main() -> int:
105 return run_cli(_main)
108if __name__ == "__main__":
109 raise SystemExit(main())