diff --git a/dataforge/commands.py b/dataforge/commands.py index 2ae119a..88bdb85 100644 --- a/dataforge/commands.py +++ b/dataforge/commands.py @@ -20,7 +20,7 @@ from .type_check import validate_types, infer_schema_from_data def find_files( pattern: str, recursive: bool = False, - directory: Optional[str] = None, + directory: Optional[str] = None ) -> List[str]: """Find files matching a pattern.""" search_dir = directory or "." @@ -39,7 +39,7 @@ def resolve_format(fmt: Optional[str], file_path: str) -> str: if fmt not in SUPPORTED_FORMATS: raise click.BadParameter( f"Unsupported format: {fmt}. Supported: {', '.join(SUPPORTED_FORMATS)}", - param_hint="--format", + param_hint="--format" ) return fmt return detect_format(file_path) @@ -48,16 +48,8 @@ def resolve_format(fmt: Optional[str], file_path: str) -> str: @click.command() @click.argument("input_file", type=click.Path(exists=True)) @click.argument("output_file", type=click.Path()) -@click.option( - "--from", "-f", "from_format", help="Input format (json, yaml, toml)" -) -@click.option( - "--to", - "-t", - "to_format", - required=True, - help="Output format (json, yaml, toml)", -) +@click.option("--from", "-f", "from_format", help="Input format (json, yaml, toml)") +@click.option("--to", "-t", "to_format", required=True, help="Output format (json, yaml, toml)") @click.option("--indent", "-i", default=2, help="Indentation spaces (0 for compact)") @click.option("--quiet", "-q", is_flag=True, help="Minimal output") def convert( @@ -66,7 +58,7 @@ def convert( from_format: Optional[str], to_format: str, indent: int, - quiet: bool, + quiet: bool ) -> None: """Convert a file from one format to another. @@ -78,57 +70,42 @@ def convert( if to_format not in SUPPORTED_FORMATS: raise click.BadParameter( f"Unsupported format: {to_format}. Supported: {', '.join(SUPPORTED_FORMATS)}", - param_hint="--to", + param_hint="--to" ) - + if input_file == "-": import sys - content = sys.stdin.read() input_format = from_format or "json" data = load_data(content, input_format) else: input_format = resolve_format(from_format, input_file) data = load_data(input_file, input_format) - + output_format = to_format result = dump_data(data, output_format, indent=indent if indent > 0 else None) - + if output_file == "-": import sys - sys.stdout.write(result) else: with open(output_file, "w", encoding="utf-8") as f: f.write(result) - + if not quiet: click.echo(f"Successfully converted {input_file} to {output_file}") - + except Exception as e: raise click.ClickException(str(e)) @click.command() @click.argument("input_files", nargs=-1, type=click.Path(exists=True)) -@click.option( - "--from", "-f", "from_format", help="Input format (json, yaml, toml)" -) -@click.option( - "--to", - "-t", - "to_format", - required=True, - help="Output format (json, yaml, toml)", -) +@click.option("--from", "-f", "from_format", help="Input format (json, yaml, toml)") +@click.option("--to", "-t", "to_format", required=True, help="Output format (json, yaml, toml)") @click.option("--output-dir", "-o", default=".", help="Output directory for converted files") @click.option("--indent", "-i", default=2, help="Indentation spaces") -@click.option( - "--pattern", - "-p", - default="*.{json,yaml,yml,toml}", - help="File pattern for batch processing", -) +@click.option("--pattern", "-p", default="*.{json,yaml,yml,toml}", help="File pattern for batch processing") @click.option("--recursive", "-r", is_flag=True, help="Search recursively") @click.option("--quiet", "-q", is_flag=True, help="Minimal output") def batch_convert( @@ -139,7 +116,7 @@ def batch_convert( indent: int, pattern: str, recursive: bool, - quiet: bool, + quiet: bool ) -> None: """Convert multiple files from one format to another. @@ -149,26 +126,26 @@ def batch_convert( if to_format not in SUPPORTED_FORMATS: raise click.BadParameter( f"Unsupported format: {to_format}. Supported: {', '.join(SUPPORTED_FORMATS)}", - param_hint="--to", + param_hint="--to" ) - + os.makedirs(output_dir, exist_ok=True) - + files = list(input_files) if input_files else find_files(pattern, recursive) - + if not files: if not quiet: click.echo("No files found matching the pattern") return - + converted = 0 errors = 0 - + for file_path in files: try: input_format = resolve_format(from_format, file_path) data = load_data(file_path, input_format) - + output_filename = Path(file_path).stem + f".{to_format}" output_file = os.path.join(output_dir, output_filename) dump_data(data, to_format, output_file, indent=indent if indent > 0 else None) @@ -177,12 +154,12 @@ def batch_convert( errors += 1 if not quiet: click.echo(f"Error converting {file_path}: {e}") - + if not quiet: click.echo(f"Converted {converted} files, {errors} errors") elif errors > 0: click.echo(f"Converted {converted}, errors: {errors}", err=True) - + except Exception as e: raise click.ClickException(str(e)) @@ -196,7 +173,7 @@ def validate( input_file: str, schema_file: Optional[str], strict: bool, - quiet: bool, + quiet: bool ) -> None: """Validate a file against a JSON Schema. @@ -205,47 +182,37 @@ def validate( try: if input_file == "-": import sys - content = sys.stdin.read() input_format = "json" data = load_data(content, input_format) else: input_format = detect_format(input_file) data = load_data(input_file, input_format) - + if schema_file: validator = SchemaValidator(schema_file=schema_file) errors = validator.validate(data) - + if errors: if not quiet: for error in validator.get_error_messages(errors): click.echo(error) - raise click.ClickException( - f"Validation failed with {len(errors)} error(s)" - ) + raise click.ClickException(f"Validation failed with {len(errors)} error(s)") else: if not quiet: click.echo("Validation passed") else: if not quiet: click.echo(f"File is valid {input_format}") - + except Exception as e: raise click.ClickException(str(e)) @click.command() @click.argument("input_files", nargs=-1, type=click.Path(exists=True)) -@click.option( - "--schema", "-s", "schema_file", required=True, help="Path to JSON Schema file" -) -@click.option( - "--pattern", - "-p", - default="*.{json,yaml,yml,toml}", - help="File pattern for batch processing", -) +@click.option("--schema", "-s", "schema_file", required=True, help="Path to JSON Schema file") +@click.option("--pattern", "-p", default="*.{json,yaml,yml,toml}", help="File pattern for batch processing") @click.option("--recursive", "-r", is_flag=True, help="Search recursively") @click.option("--quiet", "-q", is_flag=True, help="Minimal output") def batch_validate( @@ -253,7 +220,7 @@ def batch_validate( schema_file: str, pattern: str, recursive: bool, - quiet: bool, + quiet: bool ) -> None: """Validate multiple files against a JSON Schema. @@ -261,23 +228,23 @@ def batch_validate( """ try: files = list(input_files) if input_files else find_files(pattern, recursive) - + if not files: if not quiet: click.echo("No files found matching the pattern") return - + validator = SchemaValidator(schema_file=schema_file) valid_count = 0 invalid_count = 0 invalid_files = [] - + for file_path in files: try: input_format = detect_format(file_path) data = load_data(file_path, input_format) errors = validator.validate(data) - + if errors: invalid_count += 1 invalid_files.append(file_path) @@ -294,17 +261,15 @@ def batch_validate( invalid_files.append(file_path) if not quiet: click.echo(f"Error: {file_path} - {e}") - + if not quiet: click.echo(f"\nSummary: {valid_count} valid, {invalid_count} invalid") elif invalid_count > 0: click.echo(f"Valid: {valid_count}, Invalid: {invalid_count}", err=True) - + if invalid_count > 0: - raise click.ClickException( - f"Validation failed for {invalid_count} file(s)" - ) - + raise click.ClickException(f"Validation failed for {invalid_count} file(s)") + except Exception as e: raise click.ClickException(str(e)) @@ -316,7 +281,7 @@ def batch_validate( def typecheck( input_file: str, infer: bool, - quiet: bool, + quiet: bool ) -> None: """Check types in a data file. @@ -325,19 +290,17 @@ def typecheck( try: if input_file == "-": import sys - content = sys.stdin.read() input_format = "json" data = load_data(content, input_format) else: input_format = detect_format(input_file) data = load_data(input_file, input_format) - + if infer: schema = infer_schema_from_data(data) if not quiet: import json - click.echo(json.dumps(schema, indent=2)) else: if not quiet: @@ -348,6 +311,6 @@ def typecheck( click.echo(f"Type: array with {len(data)} items") else: click.echo(f"Type: {inferred_type}") - + except Exception as e: raise click.ClickException(str(e))