Click Documention: https://click.palletsprojects.com/en/8.1.x/

Intro

  • Python에서 CLI(Command Line Interface) 프로그램을 쉽게 작성할 수 있는 라이브러리 Click 소개.
  • Click은 복잡한 명령어 처리와 옵션 parsing을 간단하게 구현할 수 있도록 도와준다.
  • click.group(), click.command(), click.add_command() 기능과 이를 이용한 예제를 통해 CLI 프로그램을 작성하고, 실행하는 방법을 알아보자.


1. Click 모듈 소개

1) click.group()

  • 새로운 그룹을 생성하고, 이 그룹을 상위의 다른 그룹에 추가하거나, 이 그룹의 하위에 명령어를 추가할 때 사용
  • Examples:
    @cli.group()
    def sub_group() -> None:
      pass
    

2) click.command()

  • 개별 명령어를 정의하고, 이를 그룹에 추가할 때 사용
  • 각 명령어는 독립적으로 실행될 수 있으며, 명령어 실행 시 수행할 작업을 정의한다.
  • Examples:
    @cli.command()
    def hello() -> None:
      click.echo("Hello, World!")
    

3) click.add_command()

  • 명령어 또는 그룹을 명시적으로 다른 그룹에 추가할 때 사용
  • Examples:
    cli.add_command(hello)
    cli.add_command(sub_group)
    


2. click.command()click.add_command()의 선택

click.command()click.add_command()는 개별 명령어를 그룹에 추가할 때 사용하는 두 가지 방법이다. 이 두 방법 중 하나만 선택해서 사용하면 된다. 동일한 명령어에 대해 두 방법을 동시에 사용할 필요는 없다.

1) click.command()

  • 데코레이터를 사용하여 개별 명령어를 그룹에 자동으로 추가한다.
  • 장점: 간결하고 직관적이며, 함수 바로 위에 명령어 정의를 명시할 수 있어 가독성이 좋다. (깔끔해서 내가 선호하는 방식! ⭐)
import click


@click.group(name='main')
def cli() -> None:
    pass

@cli.command()
def hello() -> None:
    click.echo("Hello, World!")

if __name__ == '__main__':
    cli()

2) click.add_command()

  • 명시적으로 개별 명령어를 그룹에 수동으로 추가한다.
  • 장점: 명령어 정의와 그룹 추가를 분리할 수 있어 유연성이 높고, 여러 명령어를 한꺼번에 추가하거나 조건에 따라 추가할 때 유용하다.
import click


@click.group(name='main')
def cli() -> None:
    pass

@click.command()
def hello() -> None:
    click.echo("Hello, World!")

cli.add_command(hello)

if __name__ == '__main__':
    cli()


3. 명령어와 그룹 추가 방법 정리 ✍️

1) 그룹을 그룹에 추가

  • 데코레이터 방식(@cli.group())을 사용하거나, click.add_command() 메서드를 사용할 수 있다.
  • Examples:
      @cli.group()
      def sub_group() -> None:
          pass
    

    또는

      cli.add_command(sub_group)
    

2) 개별 명령어를 그룹에 추가

  • 데코레이터 방식(@cli.command())을 사용하여 자동으로 추가할 수 있다.
  • 명령어를 명시적으로 추가하고 싶다면 click.add_command()를 사용할 수 있다.
  • Examples:
      @cli.command()
      def hello() -> None:
          click.echo("Hello, World!")
    

    또는

      cli.add_command(hello)
    


4. 예제 코드 비교

예제 트리 구조

main (Main command group)
├── hello (Hello command)
└── sub (Subcommand group)
    ├── goodbye (Goodbye command)
    └── seeyouagain (Seeyouagain command)
  • main 그룹: 최상위 명령어 그룹.
    • hello 명령어: main 그룹에 속한 명령어.
    • sub 그룹: main 그룹에 속한 하위 그룹.
      • goodbye 명령어: sub 그룹에 속한 명령어.
      • seeyouagain 명령어: sub 그룹에 속한 명령어.

1) 데코레이터를 사용하여 명령어 추가

import click


@click.group(name="main")
def cli() -> None:
    """
    Main command group.
    """
    pass

@cli.group(name="sub")
def sub_group() -> None:
    """
    Subcommand group.
    """
    pass

@cli.command()
def hello() -> None:
    """
    Hello command.
    """
    click.echo("Hello, World!")

@sub_group.command()
def goodbye() -> None:
    """
    Goodbye command.
    """
    click.echo("Goodbye, World!")

@sub_group.command()
def seeyouagain() -> None:
    """
    Seeyouagain command.
    """
    click.echo("See you again!")

if __name__ == "__main__":
    cli()

2) 명시적으로 명령어 추가 (add_command() 메서드 사용)

import click


@click.group(name="main")
def cli() -> None:
    """
    Main command group.
    """
    pass

@click.group(name="sub")
def sub_group() -> None:
    """
    Subcommand group.
    """
    pass

@click.command()
def hello() -> None:
    """
    Hello command.
    """
    click.echo("Hello, World!")

@click.command()
def goodbye() -> None:
    """
    Goodbye command.
    """
    click.echo("Goodbye, World!")

@click.command()
def seeyouagain() -> None:
    """
    Seeyouagain command.
    """
    click.echo("See you again!")

# Add the hello command to the main CLI group
cli.add_command(hello)

# Add the goodbye and seeyouagain commands to the subcommand group
sub_group.add_command(goodbye)
sub_group.add_command(seeyouagain)

# Add the subcommand group to the main CLI group
cli.add_command(sub_group)

if __name__ == "__main__":
    cli()


4. 디버깅 및 실행

실행 파일 이름: clicktest.py

1) 디버거 설정(VS Code)

.vscode/launch.json 설정

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: Click Debug",
            "type": "debugpy",
            "request": "launch",
            "program": "${workspaceFolder}/clicktest.py",
            "args": [
                "hello"
            ],
            "console": "integratedTerminal"
        },
        {
            "name": "Python: Click Debug (Subcommand)",
            "type": "debugpy",
            "request": "launch",
            "program": "${workspaceFolder}/clicktest.py",
            "args": [
                "sub",
                "goodbye"
            ],
            "console": "integratedTerminal"
        }
    ]
}

2) 실행

python clicktest.py hello  # "Hello, World!" 출력
python clicktest.py sub goodbye  # "Goodbye, World!" 출력

🙋 궁금궁금

❓ 명령어를 실행할 때 최상위 그룹(main)은 왜 빠질까?

💡 그 이유는 click 명령어 그룹 구조와 관련이 있다!

main 그룹은 최상위 그룹으로, CLI 프로그램을 실행할 때 기본적으로 호출되는 그룹이다.
따라서 명령어를 실행할 때는 최상위 그룹의 이름을 명시할 필요가 없다.
  • 최상위 그룹(main)은 기본적으로 프로그램의 엔트리 포인트 역할을 한다.
  • 명령어를 실행할 때는 최상위 그룹의 이름을 명시할 필요가 없다.
  • 하위 그룹의 명령어를 실행할 때는 하위 그룹의 이름을 명시해야 한다.

Leave a comment