Python

Python Argparse: Membangun CLI Tools

Tutorial lengkap Python Argparse — positional arguments, optional arguments, subcommands, validation, custom types, dan membangun command-line tools yang profesional

1. Pengenalan Argparse

argparse adalah modul bawaan Python (standard library) untuk membuat command-line interface (CLI). Argparse menyediakan parsing argumen, auto-generate help messages, dan validasi input dari pengguna.

Mengapa Argparse?

Fitur argparse sys.argv click
Built-in✅ Ya✅ Ya❌ Perlu install
Auto help--help❌ Manual✅ Ya
Type checking✅ Otomatis❌ Manual✅ Dekorator
Error messages✅ Jelas❌ Manual✅ Jelas
Subcommands✅ Ya❌ Manual✅ Ya
KompleksitasSedangRendahRendah
Diagram: Komponen Argparse
┌──────────────────────────────────────────────────────────────┐
│                 ANATOMI CLI ARGUMENTS                        │
│                                                              │
│  $ mytool -v --name "Budi" copy source.txt dest.txt         │
│    │     │    │          │    │      │          │            │
│    │     │    │          │    └──────┴──────────┘            │
│    │     │    │          │    Positional Args                │
│    │     │    │          │                                   │
│    │     │    └──────────┘                                   │
│    │     │    Optional Args (--name "Budi")                  │
│    │     │                                                   │
│    │     └─── Flags (-v = --verbose)                         │
│    │                                                         │
│    └─────── Program name                                     │
│                                                              │
│  $ mytool copy -f source.txt dest.txt                        │
│          │                                                   │
│          └─── Subcommand                                     │
└──────────────────────────────────────────────────────────────┘

2. Argparse Hello World

Python — Argparse Hello World
import argparse

# Buat parser
parser = argparse.ArgumentParser(description='Program sederhana')

# Tambahkan argumen
parser.add_argument('nama', help='Nama Anda')

# Parse argumen dari command line
args = parser.parse_args()

print(f"Halo, {args.nama}!")

# Jalankan dari terminal:
# $ python hello.py Budi
# Halo, Budi!
#
# $ python hello.py --help
# usage: hello.py [-h] nama
#
# Program sederhana
#
# positional arguments:
#   nama        Nama Anda
#
# options:
#   -h, --help  show this help message and exit
#
# $ python hello.py
# usage: hello.py [-h] nama
# hello.py: error: the following arguments are required: nama

3. Positional Arguments

Positional arguments wajib diisi dan dikenali berdasarkan urutan posisinya di command line.

Python — Positional Arguments
import argparse

parser = argparse.ArgumentParser(description='Kalkulator sederhana')

# Beberapa positional arguments
parser.add_argument('angka1', type=float, help='Angka pertama')
parser.add_argument('operasi', help='Operasi: tambah, kurang, kali, bagi')
parser.add_argument('angka2', type=float, help='Angka kedua')

args = parser.parse_args()

if args.operasi == 'tambah':
    print(f"Hasil: {args.angka1 + args.angka2}")
elif args.operasi == 'kurang':
    print(f"Hasil: {args.angka1 - args.angka2}")
elif args.operasi == 'kali':
    print(f"Hasil: {args.angka1 * args.angka2}")
elif args.operasi == 'bagi':
    if args.angka2 == 0:
        print("Error: Tidak bisa membagi dengan nol!")
    else:
        print(f"Hasil: {args.angka1 / args.angka2}")

# Usage:
# $ python kalk.py 10 tambah 5
# Hasil: 15.0
#
# $ python kalk.py 20 kali 3
# Hasil: 60.0

nargs: Multiple Values

Python — nargs
import argparse

parser = argparse.ArgumentParser(description='Contoh nargs')

# nargs='+' — satu atau lebih nilai
parser.add_argument('files', nargs='+', help='Satu atau lebih file')

# nargs='*' — nol atau lebih nilai
parser.add_argument('patterns', nargs='*', help='Pattern opsional')

# nargs='?' — nol atau satu nilai
parser.add_argument('output', nargs='?', default='output.txt', help='File output')

# nargs=N — tepat N nilai
# parser.add_argument('coords', nargs=3, type=float, help='x y z')

args = parser.parse_args()
print(f"Files: {args.files}")
print(f"Patterns: {args.patterns}")
print(f"Output: {args.output}")

# Usage:
# $ python contoh.py file1.txt file2.txt --help
# $ python contoh.py *.py
# $ python contoh.py file1.txt file2.txt output.csv

4. Optional Arguments

Optional arguments dimulai dengan - (short form) atau -- (long form) dan bersifat opsional.

Python — Optional Arguments
import argparse

parser = argparse.ArgumentParser(description='Backup tool')

# Short dan long form
parser.add_argument('-s', '--source', required=True, help='Folder sumber')
parser.add_argument('-d', '--dest', default='./backup', help='Folder tujuan (default: ./backup)')

# Boolean flag (store_true / store_false)
parser.add_argument('-v', '--verbose', action='store_true', help='Mode verbose')
parser.add_argument('--no-compress', action='store_true', help='Kompresi dinonaktifkan')

# Count flags (-vvv = 3)
parser.add_argument('-V', '--verbosity', action='count', default=0, help='Tingkat verbosity (-V, -VV, -VVV)')

# Multiple values
parser.add_argument('-e', '--exclude', action='append', help='Folder yang dikecualikan (bisa beberapa)')

# Const value
parser.add_argument('--mode', nargs='?', const='default_mode', default=None, help='Mode operasi')

args = parser.parse_args()

print(f"Source: {args.source}")
print(f"Dest: {args.dest}")
print(f"Verbose: {args.verbose}")
print(f"Compress: {not args.no_compress}")
print(f"Verbosity level: {args.verbosity}")
print(f"Exclude: {args.exclude}")

# Usage:
# $ python backup.py -s /data -d /backup -v
# $ python backup.py --source /data --verbose --exclude .git --exclude __pycache__
# $ python backup.py -s /data -VVV

Argument Actions

Action Fungsi Contoh
storeSimpan nilai (default)--name Budiargs.name = "Budi"
store_trueSimpan True jika ada flag-vargs.verbose = True
store_falseSimpan False jika ada flag--no-colorargs.color = False
countHitung jumlah flag-vvvargs.verbose = 3
appendAppend ke list-e a -e bargs.e = ['a', 'b']
append_constAppend const valueDigunakan untuk mengumpulkan const values
versionPrint version--versionmyapp 1.0.0

5. Tipe Data dan Type Casting

Python — Type Arguments
import argparse
from pathlib import Path

parser = argparse.ArgumentParser(description='Contoh tipe data')

# Tipe data dasar
parser.add_argument('-n', '--name', type=str, help='Nama (string)')
parser.add_argument('-a', '--age', type=int, help='Umur (integer)')
parser.add_argument('-h', '--height', type=float, help='Tinggi (float)')

# File
parser.add_argument('-i', '--input', type=argparse.FileType('r'), help='Input file')
parser.add_argument('-o', '--output', type=argparse.FileType('w'), help='Output file')

# Path
parser.add_argument('-d', '--dir', type=Path, help='Direktori')

# Boolean parsing
parser.add_argument('--debug', type=lambda x: x.lower() in ('true', '1', 'yes'),
                    default=False, help='Debug mode (true/false)')

# Range validation
def range_type(min_val, max_val):
    """Buat type function untuk range validation."""
    def check_range(value):
        fval = float(value)
        if fval < min_val or fval > max_val:
            raise argparse.ArgumentTypeError(
                f"Nilai harus antara {min_val} dan {max_val}"
            )
        return fval
    return check_range

parser.add_argument('--port', type=range_type(1024, 65535), 
                    help='Port number (1024-65535)')

# Custom validation
def positive_int(value):
    """Pastikan integer positif."""
    ivalue = int(value)
    if ivalue <= 0:
        raise argparse.ArgumentTypeError(f"'{value}' harus positif")
    return ivalue

parser.add_argument('--count', type=positive_int, help='Jumlah (harus positif)')

args = parser.parse_args()
print(f"Name: {args.name}")
print(f"Age: {args.age}")
print(f"Port: {args.port}")

6. Choices dan Validation

Python — Choices
import argparse

parser = argparse.ArgumentParser(description='File converter')

# Choices: membatasi nilai yang valid
parser.add_argument('format', choices=['json', 'csv', 'xml', 'yaml'],
                    help='Format output (json/csv/xml/yaml)')
parser.add_argument('-c', '--compress', choices=['gzip', 'bz2', 'lzma', 'none'],
                    default='none', help='Metode kompresi')

# Choices dengan range
parser.add_argument('-l', '--level', type=int, choices=range(0, 10),
                    default=5, help='Level kompresi (0-9)')

# Required optional argument
parser.add_argument('-i', '--input', required=True, help='File input')

# Default value
parser.add_argument('-o', '--output', default=None, help='File output')

# metavar: tampilkan nama custom di help
parser.add_argument('-u', '--user', metavar='USERNAME', help='Username')
parser.add_argument('-p', '--password', metavar='PASS', help='Password')

args = parser.parse_args()

print(f"Format: {args.format}")
print(f"Input: {args.input}")
print(f"Compress: {args.compress}")
print(f"Level: {args.level}")

# Usage:
# $ python converter.py json -i data.txt
# $ python converter.py csv -i data.txt --compress gzip -l 9
# $ python converter.py invalid -i data.txt
# error: argument format: invalid choice: 'invalid' (choose from 'json', 'csv', 'xml', 'yaml')

7. Subcommands

Subcommands memungkinkan Anda membuat CLI dengan perintah seperti git commit, git push, docker run, dll.

Python — Subcommands
import argparse

def cmd_init(args):
    """Handler untuk subcommand 'init'."""
    print(f"Menginisialisasi project: {args.nama}")
    print(f"Template: {args.template}")

def cmd_build(args):
    """Handler untuk subcommand 'build'."""
    print(f"Building project...")
    print(f"Output: {args.output}")
    print(f"Verbose: {args.verbose}")
    if args.watch:
        print("Mode watch aktif!")

def cmd_deploy(args):
    """Handler untuk subcommand 'deploy'."""
    print(f"Deploying ke: {args.target}")
    print(f"Environment: {args.env}")

# Main parser
parser = argparse.ArgumentParser(description='CLI Tool untuk Development')
parser.add_argument('-V', '--version', action='version', version='%(prog)s 1.0.0')
subparsers = parser.add_subparsers(title='Perintah', dest='command', 
                                    help='Perintah yang tersedia')

# Subcommand: init
init_parser = subparsers.add_parser('init', help='Inisialisasi project baru')
init_parser.add_argument('nama', help='Nama project')
init_parser.add_argument('-t', '--template', default='basic',
                        choices=['basic', 'api', 'fullstack', 'cli'],
                        help='Template project (default: basic)')
init_parser.set_defaults(func=cmd_init)

# Subcommand: build
build_parser = subparsers.add_parser('build', help='Build project')
build_parser.add_argument('-o', '--output', default='./dist', help='Folder output')
build_parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
build_parser.add_argument('-w', '--watch', action='store_true', help='Watch mode')
build_parser.set_defaults(func=cmd_build)

# Subcommand: deploy
deploy_parser = subparsers.add_parser('deploy', help='Deploy project')
deploy_parser.add_argument('target', choices=['staging', 'production'],
                          help='Target deployment')
deploy_parser.add_argument('-e', '--env', default='.env',
                          help='File environment')
deploy_parser.set_defaults(func=cmd_deploy)

args = parser.parse_args()

if hasattr(args, 'func'):
    args.func(args)
else:
    parser.print_help()

# Usage:
# $ python mycli.py init myapp --template api
# $ python mycli.py build -v --watch
# $ python mycli.py deploy staging
# $ python mycli.py --help
# $ python mycli.py init --help

Nested Subcommands

Python — Nested Subcommands
import argparse

parser = argparse.ArgumentParser(description='Database CLI')
subparsers = parser.add_subparsers(dest='command')

# db create
db_parser = subparsers.add_parser('db', help='Database operations')
db_sub = db_parser.add_subparsers(dest='db_command')

create_parser = db_sub.add_parser('create', help='Create database')
create_parser.add_argument('name', help='Database name')
create_parser.add_argument('--engine', default='sqlite', 
                          choices=['sqlite', 'postgres', 'mysql'])

migrate_parser = db_sub.add_parser('migrate', help='Run migrations')
migrate_parser.add_argument('--revision', help='Target revision')

# Usage:
# $ python db.py db create mydb --engine postgres
# $ python db.py db migrate --revision head

8. Mutually Exclusive Groups

Python — Mutually Exclusive
import argparse

parser = argparse.ArgumentParser(description='Contoh argument groups')

# Mutually exclusive: pilih salah satu
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('--json', action='store_true', help='Output format JSON')
group.add_argument('--csv', action='store_true', help='Output format CSV')
group.add_argument('--xml', action='store_true', help='Output format XML')

# Mutually exclusive dengan value
mode_group = parser.add_mutually_exclusive_group()
mode_group.add_argument('--create', metavar='NAME', help='Buat baru')
mode_group.add_argument('--delete', metavar='NAME', help='Hapus')
mode_group.add_argument('--update', metavar='NAME', help='Update')

# Argument group (untuk help display, bukan eksklusif)
output_group = parser.add_argument_group('Output options')
output_group.add_argument('-o', '--output', help='File output')
output_group.add_argument('-q', '--quiet', action='store_true', help='Quiet mode')
output_group.add_argument('-v', '--verbose', action='count', default=0, help='Verbose')

args = parser.parse_args()

if args.json:
    print("Format: JSON")
elif args.csv:
    print("Format: CSV")
elif args.xml:
    print("Format: XML")

# Usage:
# $ python contoh.py --json
# $ python contoh.py --csv --create mydata
# $ python contoh.py --json --csv  ← ERROR: not allowed

9. Custom Type dan Action

Python — Custom Type & Action
import argparse
import os
from pathlib import Path

# --- Custom Type Functions ---
def existing_file(value):
    """Validasi bahwa file ada."""
    path = Path(value)
    if not path.exists():
        raise argparse.ArgumentTypeError(f"File tidak ditemukan: {value}")
    if not path.is_file():
        raise argparse.ArgumentTypeError(f"Bukan file: {value}")
    return path

def dir_or_create(value):
    """Validasi direktori, buat jika tidak ada."""
    path = Path(value)
    if not path.exists():
        path.mkdir(parents=True, exist_ok=True)
    return path

def ip_address(value):
    """Validasi IP address sederhana."""
    parts = value.split('.')
    if len(parts) != 4:
        raise argparse.ArgumentTypeError(f"IP tidak valid: {value}")
    for part in parts:
        if not part.isdigit() or not 0 <= int(part) <= 255:
            raise argparse.ArgumentTypeError(f"IP tidak valid: {value}")
    return value

def port_number(value):
    """Validasi port number."""
    ivalue = int(value)
    if not 1 <= ivalue <= 65535:
        raise argparse.ArgumentTypeError(f"Port harus 1-65535, dapat: {value}")
    return ivalue

# --- Custom Action ---
class EnvDefault(argparse.Action):
    """Action yang mengambil default dari environment variable."""
    def __init__(self, env_var, required=True, default=None, **kwargs):
        self.env_var = env_var
        default = os.environ.get(env_var, default)
        if default:
            required = False
        super().__init__(default=default, required=required, **kwargs)
    
    def __call__(self, parser, namespace, values, option_string=None):
        setattr(namespace, self.dest, values)


# --- Parser ---
parser = argparse.ArgumentParser(description='Custom types demo')

parser.add_argument('-c', '--config', type=existing_file, 
                    help='File konfigurasi (harus ada)')
parser.add_argument('-o', '--output-dir', type=dir_or_create, 
                    default='./output', help='Direktori output')
parser.add_argument('--host', type=ip_address, 
                    default='127.0.0.1', help='IP address server')
parser.add_argument('--port', type=port_number, 
                    default=8080, help='Port server')
parser.add_argument('--db-url', action=EnvDefault, env_var='DATABASE_URL',
                    help='Database URL (default: $DATABASE_URL)')

args = parser.parse_args()

print(f"Config: {args.config}")
print(f"Output dir: {args.output_dir}")
print(f"Server: {args.host}:{args.port}")
print(f"DB URL: {args.db_url}")

10. Contoh Aplikasi Nyata

Contoh 1: File Manager CLI

Python — filemgr.py
#!/usr/bin/env python3
"""File Manager CLI — contoh argparse nyata."""
import argparse
import os
import shutil
from pathlib import Path
from datetime import datetime


def cmd_list(args):
    """List files in directory."""
    target = Path(args.path)
    if not target.exists():
        print(f"Error: '{args.path}' tidak ditemukan")
        return
    
    files = sorted(target.iterdir(), key=lambda f: f.name)
    if args.type == 'files':
        files = [f for f in files if f.is_file()]
    elif args.type == 'dirs':
        files = [f for f in files if f.is_dir()]
    
    total_size = 0
    for f in files:
        if f.is_file():
            size = f.stat().st_size
            total_size += size
            if args.human:
                size_str = format_size(size)
            else:
                size_str = str(size)
            mod_time = datetime.fromtimestamp(f.stat().st_mtime).strftime('%Y-%m-%d %H:%M')
            print(f"{size_str:>10}  {mod_time}  {f.name}")
        else:
            print(f"{'DIR':>10}  {'':>16}  {f.name}/")
    
    print(f"\nTotal: {len(files)} item(s)")
    if args.human:
        print(f"Size: {format_size(total_size)}")


def cmd_find(args):
    """Find files matching pattern."""
    root = Path(args.path)
    pattern = args.pattern
    
    count = 0
    for f in root.rglob(pattern):
        if args.type == 'files' and not f.is_file():
            continue
        if args.type == 'dirs' and not f.is_dir():
            continue
        print(f"  {f.relative_to(root)}")
        count += 1
    
    print(f"\nDitemukan: {count} item(s)")


def cmd_clean(args):
    """Clean temporary files."""
    target = Path(args.path)
    patterns = ['*.pyc', '__pycache__', '*.tmp', '.DS_Store', 'Thumbs.db']
    
    if args.custom_pattern:
        patterns.extend(args.custom_pattern)
    
    removed = 0
    for pattern in patterns:
        for f in target.rglob(pattern):
            if args.dry_run:
                print(f"  [DRY RUN] Akan hapus: {f}")
            else:
                if f.is_file():
                    f.unlink()
                elif f.is_dir():
                    shutil.rmtree(f)
                print(f"  Dihapus: {f}")
            removed += 1
    
    if args.dry_run:
        print(f"\n[DRY RUN] Akan menghapus {removed} item(s)")
    else:
        print(f"\nDihapus {removed} item(s)")


def format_size(size):
    """Format size ke human-readable."""
    for unit in ['B', 'KB', 'MB', 'GB']:
        if size < 1024:
            return f"{size:.1f}{unit}"
        size /= 1024
    return f"{size:.1f}TB"


def main():
    parser = argparse.ArgumentParser(
        prog='filemgr',
        description='🗂️ File Manager CLI — kelola file dari terminal',
        epilog='Contoh: filemgr list -p ~/Documents --human'
    )
    parser.add_argument('-V', '--version', action='version', version='filemgr 2.0.0')
    
    subparsers = parser.add_subparsers(title='Perintah', dest='command')
    
    # List
    list_p = subparsers.add_parser('list', aliases=['ls'], help='List file dan folder')
    list_p.add_argument('-p', '--path', default='.', help='Path target (default: .)')
    list_p.add_argument('-t', '--type', choices=['all', 'files', 'dirs'], default='all')
    list_p.add_argument('--human', '-H', action='store_true', help='Human-readable size')
    list_p.set_defaults(func=cmd_list)
    
    # Find
    find_p = subparsers.add_parser('find', help='Cari file berdasarkan pattern')
    find_p.add_argument('pattern', help='Pattern glob (*.py, *.txt, dll)')
    find_p.add_argument('-p', '--path', default='.', help='Path root pencarian')
    find_p.add_argument('-t', '--type', choices=['all', 'files', 'dirs'], default='all')
    find_p.set_defaults(func=cmd_find)
    
    # Clean
    clean_p = subparsers.add_parser('clean', help='Hapus file temporary')
    clean_p.add_argument('-p', '--path', default='.', help='Path target')
    clean_p.add_argument('--dry-run', action='store_true', help='Preview tanpa hapus')
    clean_p.add_argument('--custom-pattern', nargs='*', help='Pattern tambahan')
    clean_p.set_defaults(func=cmd_clean)
    
    args = parser.parse_args()
    
    if hasattr(args, 'func'):
        args.func(args)
    else:
        parser.print_help()


if __name__ == '__main__':
    main()

# Usage:
# $ python filemgr.py list --human
# $ python filemgr.py find "*.py" -p ~/projects
# $ python filemgr.py clean --dry-run
# $ python filemgr.py clean -p /tmp --custom-pattern "*.log"

Contoh 2: HTTP Client CLI (Mini curl)

Python — minicurl.py
#!/usr/bin/env python3
"""Mini curl — contoh CLI tool dengan argparse."""
import argparse
import json
import sys
from urllib.request import Request, urlopen
from urllib.error import URLError


def main():
    parser = argparse.ArgumentParser(
        prog='minicurl',
        description='🌐 Mini curl — HTTP client sederhana',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Contoh:
  minicurl GET https://api.github.com/users/octocat
  minicurl POST https://httpbin.org/post -d '{"key": "value"}'
  minicurl GET https://api.github.com -H "Accept: application/json"
        """
    )
    
    parser.add_argument('method', choices=['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
                       help='HTTP method')
    parser.add_argument('url', help='URL target')
    parser.add_argument('-d', '--data', help='Request body (JSON string)')
    parser.add_argument('-H', '--header', action='append',
                       help='Header (format: "Key: Value")')
    parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
    parser.add_argument('-i', '--include-headers', action='store_true',
                       help='Tampilkan response headers')
    parser.add_argument('-o', '--output', help='Simpan response ke file')
    parser.add_argument('--timeout', type=int, default=30, help='Timeout (detik)')
    
    args = parser.parse_args()
    
    # Parse headers
    headers = {'User-Agent': 'minicurl/1.0'}
    if args.header:
        for h in args.header:
            key, _, value = h.partition(':')
            headers[key.strip()] = value.strip()
    
    # Parse body
    data = None
    if args.data:
        data = args.data.encode('utf-8')
        headers.setdefault('Content-Type', 'application/json')
    
    # Buat request
    req = Request(args.url, data=data, headers=headers, method=args.method)
    
    if args.verbose:
        print(f">>> {args.method} {args.url}", file=sys.stderr)
        for k, v in headers.items():
            print(f">>> {k}: {v}", file=sys.stderr)
        if data:
            print(f">>> Body: {args.data}", file=sys.stderr)
        print(file=sys.stderr)
    
    try:
        with urlopen(req, timeout=args.timeout) as response:
            # Response headers
            if args.include_headers or args.verbose:
                print(f"<<< HTTP/{response.version // 10} {response.status} {response.reason}",
                      file=sys.stderr)
                for k, v in response.headers.items():
                    print(f"<<< {k}: {v}", file=sys.stderr)
                print(file=sys.stderr)
            
            # Response body
            body = response.read().decode('utf-8')
            
            # Pretty print JSON
            try:
                parsed = json.loads(body)
                formatted = json.dumps(parsed, indent=2, ensure_ascii=False)
                if args.output:
                    with open(args.output, 'w') as f:
                        f.write(formatted)
                    print(f"Disimpan ke {args.output}")
                else:
                    print(formatted)
            except json.JSONDecodeError:
                if args.output:
                    with open(args.output, 'w') as f:
                        f.write(body)
                    print(f"Disimpan ke {args.output}")
                else:
                    print(body)
    
    except URLError as e:
        print(f"Error: {e.reason}", file=sys.stderr)
        sys.exit(1)
    except Exception as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)


if __name__ == '__main__':
    main()

11. Best Practices

💡 Tips Penting
  • Selalu berikan description — pengguna perlu tahu apa yang dilakukan tool
  • Gunakan epilog untuk contoh penggunaan
  • Berikan help untuk setiap argument
  • Tentukan default untuk optional arguments
  • Gunakan metavar untuk membuat help lebih informatif
  • Validasi input menggunakan type function atau choices
  • Gunakan set_defaults(func=...) untuk dispatcher pattern
  • Tambahkan --version untuk tool yang didistribusikan

Tips Display

Python — Display Tips
import argparse

# RawDescriptionHelpFormatter — tidak wrap teks di description/epilog
parser = argparse.ArgumentParser(
    description='''Ini adalah tool CLI.
    
Contoh penggunaan:
  tool.py --input data.csv --output result.json
  tool.py -i data.csv -o result.json -v
''',
    formatter_class=argparse.RawDescriptionHelpFormatter
)

# RawTextHelpFormatter — tidak wrap teks di help strings
parser = argparse.ArgumentParser(
    formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument('--mode', help='''Mode operasi:
  fast   = Mode cepat (kurang akurat)
  normal = Mode normal (default)
  slow   = Mode lambat (paling akurat)
''')

# ArgumentDefaultsHelpFormatter — tampilkan default di help
parser = argparse.ArgumentParser(
    formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument('-n', '--count', type=int, default=10, help='Jumlah item')
# Help: Jumlah item (default: 10)

# Metavar untuk grouped display
parser.add_argument('-o', '--output', metavar='FILE', help='Output file')
# Help: -o FILE, --output FILE  Output file

12. Quiz Pemahaman

🧠 Quiz: Python Argparse

1. Apa fungsi utama argparse?

2. Bagaimana cara membuat optional argument?

3. Apa fungsi action='store_true'?

4. Bagaimana cara membuat subcommands?

5. Apa yang terjadi jika positional argument tidak diberikan?

🔍 Zoom
100%
🎨 Tema