Coverage for src/utils/cli.py: 96%
49 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-05-25 13:51 -0400
« prev ^ index » next coverage.py v7.8.2, created at 2025-05-25 13:51 -0400
1# Copyright (c) CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
2# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
3# Direct all questions to legal@cloudzero.com
5"""
6Command line interface utilities for CloudZero Data Tool.
7Handles argument parsing and validation.
8"""
10import argparse
11import sys
12from pathlib import Path
13from rich.console import Console
15console = Console()
18def create_argument_parser() -> argparse.ArgumentParser:
19 """Create and configure the argument parser for czdt."""
20 parser = argparse.ArgumentParser(
21 description="Analyze Perplexity CSV data with interactive column exploration"
22 )
23 parser.add_argument(
24 "--in",
25 type=Path,
26 dest="input_file",
27 help="Path to CSV file to analyze (required for analysis operations)",
28 )
29 parser.add_argument(
30 "--column", type=str, help="Specific column to analyze (skips interactive mode)"
31 )
32 parser.add_argument(
33 "--analysis",
34 action="store_true",
35 help="Run interactive CloudZero telemetry mapping analysis to identify how CSV data can be mapped to CloudZero telemetry records",
36 )
37 parser.add_argument(
38 "--costformation",
39 type=Path,
40 help="Optional costformation.yaml file to suggest cost dimensions for telemetry mapping",
41 )
42 parser.add_argument(
43 "--config",
44 type=Path,
45 help="Configuration file (JSON/YAML) containing predefined answers for telemetry analysis automation",
46 )
47 parser.add_argument(
48 "--rollup",
49 type=str,
50 help="Create rollup/pivot table. Format: 'group_cols:agg_specs' (e.g., 'MODEL_SKU,RUNTIME_MODEL_NAME:count(LLM_INPUT_TOKENS),sum(CT_TOTAL_COMPLETION_TOKENS)'). Use with --group-by for time-based analysis.",
51 )
52 parser.add_argument(
53 "--rollup-limit",
54 type=int,
55 default=None,
56 help="Maximum number of rollup rows to display (default: show all)",
57 )
58 parser.add_argument(
59 "--out",
60 type=str,
61 help="Export rollup results to CSV file instead of displaying on screen",
62 )
63 parser.add_argument(
64 "--group-by",
65 choices=["hour", "day"],
66 help="Group rollup data by time period (hour or day). Requires --rollup option.",
67 )
68 parser.add_argument(
69 "--datetime-col",
70 type=str,
71 help="Specify datetime column for time grouping. If not provided, will auto-detect.",
72 )
73 parser.add_argument(
74 "--allow-none",
75 action="store_true",
76 help="Allow rows with None/null values in non-aggregate columns when creating rollup. By default, null values are ignored.",
77 )
78 parser.add_argument(
79 "--lazy",
80 action="store_true",
81 help="Use lazy loading for better memory efficiency with very large datasets",
82 )
83 parser.add_argument(
84 "--fast",
85 action="store_true",
86 help="Enable all performance optimizations (lazy loading, column selection, etc.)",
87 )
88 parser.add_argument(
89 "--sample",
90 type=int,
91 help="Process only a sample of N rows for faster analysis of large files",
92 )
93 parser.add_argument(
94 "--generate-schema",
95 type=Path,
96 help="Generate schema manifest for all CSV files in the specified folder",
97 )
98 parser.add_argument(
99 "--interactive",
100 action="store_true",
101 help="Start interactive mode for column exploration",
102 )
104 return parser
107def validate_arguments(args) -> bool:
108 """Validate parsed arguments and show appropriate errors."""
109 # Validate group-by requires rollup
110 if args.group_by and not args.rollup:
111 console.print(
112 "❌ [red]Error: --group-by option requires --rollup to be specified[/red]"
113 )
114 return False
116 # Validate allow-none requires rollup
117 if args.allow_none and not args.rollup:
118 console.print(
119 "❌ [red]Error: --allow-none option requires --rollup to be specified[/red]"
120 )
121 return False
123 # Check if analysis operation requires --in argument
124 analysis_operations = [args.analysis, args.rollup, args.column, args.interactive]
125 if any(analysis_operations) and not args.input_file:
126 console.print(
127 "❌ [red]Error: --in argument is required for analysis operations[/red]"
128 )
129 return False
131 return True
134def should_show_help(args) -> bool:
135 """Determine if help should be shown (no meaningful arguments provided)."""
136 return not any(
137 [
138 args.analysis,
139 args.rollup,
140 args.column,
141 args.interactive,
142 args.generate_schema,
143 ]
144 )
147def parse_and_validate_args():
148 """Parse command line arguments and validate them."""
149 parser = create_argument_parser()
150 args = parser.parse_args()
152 # Handle schema generation first (doesn't require --in argument)
153 if args.generate_schema:
154 return args, True # Valid, special case
156 # Check if no arguments provided, show help and exit
157 if should_show_help(args):
158 parser.print_help()
159 sys.exit(0)
161 # Validate arguments
162 if not validate_arguments(args):
163 sys.exit(1)
165 return args, True