Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:04:14 +08:00
commit 70c36b5eff
248 changed files with 47482 additions and 0 deletions

View File

@@ -0,0 +1,151 @@
#!/usr/bin/env bash
# Convert argparse code to Click decorators
set -euo pipefail
usage() {
cat <<EOF
Convert argparse parser to Click decorators
Usage: $(basename "$0") ARGPARSE_FILE [OUTPUT_FILE]
Performs basic conversion from argparse to Click:
- ArgumentParser → @click.group() or @click.command()
- add_argument() → @click.option() or @click.argument()
- add_subparsers() → @group.command()
- choices=[] → type=click.Choice([])
- action='store_true' → is_flag=True
Note: This is a basic converter. Manual refinement may be needed.
Examples:
$(basename "$0") mycli.py mycli_click.py
$(basename "$0") basic-parser.py
EOF
exit 1
}
if [ $# -eq 0 ]; then
usage
fi
ARGPARSE_FILE="$1"
OUTPUT_FILE="${2:-}"
if [ ! -f "$ARGPARSE_FILE" ]; then
echo "Error: File not found: $ARGPARSE_FILE"
exit 1
fi
echo "Converting argparse to Click: $ARGPARSE_FILE"
convert_to_click() {
cat <<'EOF'
#!/usr/bin/env python3
"""
Converted from argparse to Click
This is a basic conversion. You may need to adjust:
- Argument order and grouping
- Type conversions
- Custom validators
- Error handling
"""
import click
@click.group()
@click.version_option(version='1.0.0')
@click.pass_context
def cli(ctx):
"""CLI tool converted from argparse"""
ctx.ensure_object(dict)
# Convert your subcommands here
# Example pattern:
#
# @cli.command()
# @click.argument('target')
# @click.option('--env', type=click.Choice(['dev', 'staging', 'prod']), default='dev')
# @click.option('--force', is_flag=True, help='Force operation')
# def deploy(target, env, force):
# """Deploy to environment"""
# click.echo(f"Deploying {target} to {env}")
# if force:
# click.echo("Force mode enabled")
if __name__ == '__main__':
cli()
EOF
echo ""
echo "# Detected argparse patterns:"
echo ""
# Detect subcommands
if grep -q "add_subparsers(" "$ARGPARSE_FILE"; then
echo "# Subcommands found:"
grep -oP "add_parser\('\K[^']+(?=')" "$ARGPARSE_FILE" | while read -r cmd; do
echo "# - $cmd"
done
echo ""
fi
# Detect arguments
if grep -q "add_argument(" "$ARGPARSE_FILE"; then
echo "# Arguments found:"
grep "add_argument(" "$ARGPARSE_FILE" | grep -oP "'[^']+'" | head -n1 | while read -r arg; do
echo "# $arg"
done
echo ""
fi
# Detect choices
if grep -q "choices=" "$ARGPARSE_FILE"; then
echo "# Choices found (convert to click.Choice):"
grep -oP "choices=\[\K[^\]]+(?=\])" "$ARGPARSE_FILE" | while read -r choices; do
echo "# [$choices]"
done
echo ""
fi
# Provide conversion hints
cat <<'EOF'
# Conversion Guide:
#
# argparse → Click
# ----------------------------------|--------------------------------
# parser.add_argument('arg') → @click.argument('arg')
# parser.add_argument('--opt') → @click.option('--opt')
# action='store_true' → is_flag=True
# choices=['a', 'b'] → type=click.Choice(['a', 'b'])
# type=int → type=int
# required=True → required=True
# default='value' → default='value'
# help='...' → help='...'
#
# For nested subcommands:
# Use @group.command() decorator
#
# For more info: https://click.palletsprojects.com/
EOF
}
# Output
if [ -n "$OUTPUT_FILE" ]; then
convert_to_click > "$OUTPUT_FILE"
chmod +x "$OUTPUT_FILE"
echo "Converted to Click: $OUTPUT_FILE"
echo ""
echo "Next steps:"
echo " 1. Review the generated file"
echo " 2. Add your command implementations"
echo " 3. Install Click: pip install click"
echo " 4. Test: python $OUTPUT_FILE --help"
else
convert_to_click
fi

View File

@@ -0,0 +1,213 @@
#!/usr/bin/env bash
# Generate argparse parser from specification
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
TEMPLATES_DIR="$(dirname "$SCRIPT_DIR")/templates"
usage() {
cat <<EOF
Generate argparse parser from specification
Usage: $(basename "$0") [OPTIONS]
Options:
-n, --name NAME Parser name (required)
-d, --description DESC Parser description
-s, --subcommands Include subcommands
-c, --choices Include choice validation
-g, --groups Include argument groups
-o, --output FILE Output file (default: stdout)
-h, --help Show this help
Examples:
$(basename "$0") -n mycli -d "My CLI tool" -o mycli.py
$(basename "$0") -n deploy -s -c -o deploy.py
EOF
exit 1
}
# Parse arguments
NAME=""
DESCRIPTION=""
SUBCOMMANDS=false
CHOICES=false
GROUPS=false
OUTPUT=""
while [[ $# -gt 0 ]]; do
case $1 in
-n|--name)
NAME="$2"
shift 2
;;
-d|--description)
DESCRIPTION="$2"
shift 2
;;
-s|--subcommands)
SUBCOMMANDS=true
shift
;;
-c|--choices)
CHOICES=true
shift
;;
-g|--groups)
GROUPS=true
shift
;;
-o|--output)
OUTPUT="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo "Error: Unknown option $1"
usage
;;
esac
done
if [ -z "$NAME" ]; then
echo "Error: --name is required"
usage
fi
# Set defaults
DESCRIPTION="${DESCRIPTION:-$NAME CLI tool}"
# Generate parser
generate_parser() {
cat <<EOF
#!/usr/bin/env python3
"""
$DESCRIPTION
Generated by generate-parser.sh
"""
import argparse
import sys
def main():
parser = argparse.ArgumentParser(
description='$DESCRIPTION',
formatter_class=argparse.RawDescriptionHelpFormatter
)
parser.add_argument(
'--version',
action='version',
version='1.0.0'
)
parser.add_argument(
'--verbose', '-v',
action='store_true',
help='Enable verbose output'
)
EOF
if [ "$GROUPS" = true ]; then
cat <<EOF
# Configuration group
config_group = parser.add_argument_group(
'configuration',
'Configuration options'
)
config_group.add_argument(
'--config',
help='Configuration file'
)
EOF
fi
if [ "$SUBCOMMANDS" = true ]; then
cat <<EOF
# Create subparsers
subparsers = parser.add_subparsers(
dest='command',
help='Available commands',
required=True
)
# Example subcommand
cmd_parser = subparsers.add_parser(
'run',
help='Run the application'
)
cmd_parser.add_argument(
'target',
help='Target to run'
)
EOF
if [ "$CHOICES" = true ]; then
cat <<EOF
cmd_parser.add_argument(
'--env',
choices=['development', 'staging', 'production'],
default='development',
help='Environment (default: %(default)s)'
)
EOF
fi
else
cat <<EOF
# Arguments
parser.add_argument(
'target',
help='Target to process'
)
EOF
if [ "$CHOICES" = true ]; then
cat <<EOF
parser.add_argument(
'--env',
choices=['development', 'staging', 'production'],
default='development',
help='Environment (default: %(default)s)'
)
EOF
fi
fi
cat <<EOF
# Parse arguments
args = parser.parse_args()
# Display configuration
if args.verbose:
print("Verbose mode enabled")
print(f"Arguments: {args}")
return 0
if __name__ == '__main__':
sys.exit(main())
EOF
}
# Output
if [ -n "$OUTPUT" ]; then
generate_parser > "$OUTPUT"
chmod +x "$OUTPUT"
echo "Generated parser: $OUTPUT"
else
generate_parser
fi

View File

@@ -0,0 +1,149 @@
#!/usr/bin/env bash
# Test argparse parser with various argument combinations
set -euo pipefail
usage() {
cat <<EOF
Test argparse parser with various arguments
Usage: $(basename "$0") PARSER_FILE
Tests:
- Help display (--help)
- Version display (--version)
- Missing required arguments
- Invalid choices
- Type validation
- Subcommands (if present)
Examples:
$(basename "$0") mycli.py
$(basename "$0") ../templates/basic-parser.py
EOF
exit 1
}
if [ $# -eq 0 ]; then
usage
fi
PARSER_FILE="$1"
if [ ! -f "$PARSER_FILE" ]; then
echo "Error: File not found: $PARSER_FILE"
exit 1
fi
# Make executable if needed
if [ ! -x "$PARSER_FILE" ]; then
chmod +x "$PARSER_FILE"
fi
echo "Testing argparse parser: $PARSER_FILE"
echo ""
PASSED=0
FAILED=0
run_test() {
local description="$1"
shift
local expected_result="$1"
shift
echo -n "Testing: $description ... "
if "$PARSER_FILE" "$@" >/dev/null 2>&1; then
result="success"
else
result="failure"
fi
if [ "$result" = "$expected_result" ]; then
echo "✓ PASS"
((PASSED++))
else
echo "✗ FAIL (expected $expected_result, got $result)"
((FAILED++))
fi
}
# Test --help
run_test "Help display" "success" --help
# Test --version
if grep -q "action='version'" "$PARSER_FILE"; then
run_test "Version display" "success" --version
fi
# Test with no arguments
run_test "No arguments" "failure"
# Test invalid option
run_test "Invalid option" "failure" --invalid-option
# Detect and test subcommands
if grep -q "add_subparsers(" "$PARSER_FILE"; then
echo ""
echo "Subcommands detected, testing subcommand patterns..."
# Try to extract subcommand names
subcommands=$(grep -oP "add_parser\('\K[^']+(?=')" "$PARSER_FILE" || true)
if [ -n "$subcommands" ]; then
for cmd in $subcommands; do
run_test "Subcommand: $cmd --help" "success" "$cmd" --help
done
fi
fi
# Test choices if present
if grep -q "choices=\[" "$PARSER_FILE"; then
echo ""
echo "Choices validation detected, testing..."
# Extract valid and invalid choices
valid_choice=$(grep -oP "choices=\[\s*'([^']+)" "$PARSER_FILE" | head -n1 | grep -oP "'[^']+'" | tr -d "'" || echo "valid")
invalid_choice="invalid_choice_12345"
if grep -q "add_subparsers(" "$PARSER_FILE" && [ -n "$subcommands" ]; then
first_cmd=$(echo "$subcommands" | head -n1)
run_test "Valid choice" "success" "$first_cmd" target --env "$valid_choice" 2>/dev/null || true
run_test "Invalid choice" "failure" "$first_cmd" target --env "$invalid_choice" 2>/dev/null || true
fi
fi
# Test type validation if present
if grep -q "type=int" "$PARSER_FILE"; then
echo ""
echo "Type validation detected, testing..."
run_test "Valid integer" "success" --port 8080 2>/dev/null || true
run_test "Invalid integer" "failure" --port invalid 2>/dev/null || true
fi
# Test boolean flags if present
if grep -q "action='store_true'" "$PARSER_FILE"; then
echo ""
echo "Boolean flags detected, testing..."
run_test "Boolean flag present" "success" --verbose 2>/dev/null || true
fi
# Summary
echo ""
echo "Test Summary:"
echo " Passed: $PASSED"
echo " Failed: $FAILED"
echo " Total: $((PASSED + FAILED))"
if [ $FAILED -eq 0 ]; then
echo ""
echo "✓ All tests passed"
exit 0
else
echo ""
echo "✗ Some tests failed"
exit 1
fi

View File

@@ -0,0 +1,173 @@
#!/usr/bin/env bash
# Validate argparse parser structure and completeness
set -euo pipefail
usage() {
cat <<EOF
Validate argparse parser structure
Usage: $(basename "$0") PARSER_FILE
Checks:
- Valid Python syntax
- Imports argparse
- Creates ArgumentParser
- Has main() function
- Calls parse_args()
- Has proper shebang
- Has help text
- Has version info
Examples:
$(basename "$0") mycli.py
$(basename "$0") ../templates/basic-parser.py
EOF
exit 1
}
if [ $# -eq 0 ]; then
usage
fi
PARSER_FILE="$1"
if [ ! -f "$PARSER_FILE" ]; then
echo "Error: File not found: $PARSER_FILE"
exit 1
fi
echo "Validating argparse parser: $PARSER_FILE"
echo ""
ERRORS=0
WARNINGS=0
# Check shebang
if head -n1 "$PARSER_FILE" | grep -q '^#!/usr/bin/env python'; then
echo "✓ Has proper Python shebang"
else
echo "✗ Missing or invalid shebang"
((ERRORS++))
fi
# Check syntax
if python3 -m py_compile "$PARSER_FILE" 2>/dev/null; then
echo "✓ Valid Python syntax"
else
echo "✗ Invalid Python syntax"
((ERRORS++))
fi
# Check imports
if grep -q "import argparse" "$PARSER_FILE"; then
echo "✓ Imports argparse"
else
echo "✗ Does not import argparse"
((ERRORS++))
fi
# Check ArgumentParser creation
if grep -q "ArgumentParser(" "$PARSER_FILE"; then
echo "✓ Creates ArgumentParser"
else
echo "✗ Does not create ArgumentParser"
((ERRORS++))
fi
# Check main function
if grep -q "^def main(" "$PARSER_FILE"; then
echo "✓ Has main() function"
else
echo "⚠ No main() function found"
((WARNINGS++))
fi
# Check parse_args call
if grep -q "\.parse_args()" "$PARSER_FILE"; then
echo "✓ Calls parse_args()"
else
echo "✗ Does not call parse_args()"
((ERRORS++))
fi
# Check version
if grep -q "action='version'" "$PARSER_FILE"; then
echo "✓ Has version info"
else
echo "⚠ No version info found"
((WARNINGS++))
fi
# Check help text
if grep -q "help=" "$PARSER_FILE"; then
echo "✓ Has help text for arguments"
else
echo "⚠ No help text found"
((WARNINGS++))
fi
# Check description
if grep -q "description=" "$PARSER_FILE"; then
echo "✓ Has parser description"
else
echo "⚠ No parser description"
((WARNINGS++))
fi
# Check if executable
if [ -x "$PARSER_FILE" ]; then
echo "✓ File is executable"
else
echo "⚠ File is not executable (run: chmod +x $PARSER_FILE)"
((WARNINGS++))
fi
# Check subparsers if present
if grep -q "add_subparsers(" "$PARSER_FILE"; then
echo "✓ Has subparsers"
# Check if dest is set
if grep -q "add_subparsers(.*dest=" "$PARSER_FILE"; then
echo " ✓ Subparsers have dest set"
else
echo " ⚠ Subparsers missing dest parameter"
((WARNINGS++))
fi
fi
# Check for choices
if grep -q "choices=" "$PARSER_FILE"; then
echo "✓ Uses choices for validation"
fi
# Check for type coercion
if grep -q "type=" "$PARSER_FILE"; then
echo "✓ Uses type coercion"
fi
# Check for argument groups
if grep -q "add_argument_group(" "$PARSER_FILE"; then
echo "✓ Uses argument groups"
fi
# Check for mutually exclusive groups
if grep -q "add_mutually_exclusive_group(" "$PARSER_FILE"; then
echo "✓ Uses mutually exclusive groups"
fi
# Summary
echo ""
echo "Validation Summary:"
echo " Errors: $ERRORS"
echo " Warnings: $WARNINGS"
if [ $ERRORS -eq 0 ]; then
echo ""
echo "✓ Parser validation passed"
exit 0
else
echo ""
echo "✗ Parser validation failed"
exit 1
fi