optparse — 명령줄 옵션 파서

optparse — 명령줄 옵션 파서

optparse는 명령줄 옵션을 파싱하는 데 편리하고 유연하며 확장 가능한 방식으로 도움말과 사용법(usage) 메시지를 생성해주는 모듈이에요. 다만 버전 3.2부터 optparse는 더 이상 사용되지 않고(deprecated) argparse로 대체됐어요. 새 코드를 작성할 때는 argparse를 사용하는 걸 권장하고, 기존 optparse 코드를 옮기는 방법은 "Migrating optparse code to argparse" 문서를 참고해요.

기존 optparse 사용자에게 argparse는 더 강력하기 때문에 마이그레이션 가치가 있어요. argparseoptparse보다 유연한 것은 아니지만, 옵션 종류가 더 많고 기본적으로 도움말 텍스트나 오류 메시지를 보기 좋게 표시하며, 가변 개수 인자를 지원해요. 다만 optparse의 "이것이 기본으로 동작하면 좋겠다"는 결정 중 일부를 뒤집어서 좀 더 명시적으로 만들어야 하는 부분도 있어요.

더 알아보기

  • getopt — C 스타일 명령줄 파서를 제공하는 대안적인 모듈
  • argparseoptparse를 대체하는 최신 명령줄 옵션 파서
  • "Migrating optparse code to argparse" — optparse 코드를 argparse로 옮기는 가이드

출처: Python 표준 라이브러리

본문

인자 파싱 라이브러리 고르기

인자 파싱 라이브러리의 종류와 목적은 크게 세 가지 범주로 나눌 수 있어요.

  • 옵션을 지원하지 않는 단순 명령의 경우 인자를 그대로 받아 처리하고 싶을 수도 있어요.
  • 단순 옵션이 몇 개 있는 경우 getopt가 유용하고 널리 알려져 있어요.
  • 옵션이 많아지거나 도움말 텍스트 같은 기능이 필요하면 argparse가 선택지가 되어요.

이 문서는 argparse가 출현하기 전에 쓰였던 optparse를 다루지만, 이해를 돕기 위해 처음부터 살펴볼게요.

들어가기 (Introduction)

optparse는 다른 명령줄 파서들보다 더 단순하고 직관적으로 설계했어요. 프로그램이 취할 수 있는 옵션을 선언만 하면 optparse가 명령줄에서 그 옵션들을 찾아서 파싱하고 사용자에게 도움말을 생성해줘요. 옵션에 값을 저장(store)할 속성(attribute)이나 값을 넣을 기본값을 두는 것 따위는 optparse가 처리하니까, 여러분은 옵션 정의와 값 설정에만 집중하면 돼요.

옵션 정의는 마치 데코레이터를 쓰는 것처럼 간단해요. 아래 예시에서는 -f(짧은 옵션)와 --file(긴 옵션)이라는 두 옵션 문자열로 --file 옵션을 정의하고 있어요.

parser.add_option("-f", "--file", ...)

위에서 ...에는 나중에 설명할 옵션 속성들이 들어가요. 이 옵션은 명령줄에서 나타날 때 값을 기대하는데, optparse가 값을 읽고 명령줄을 파싱해서 내부적으로 만들어 둔 options 객체의 file이라는 속성에 저장해요.

또한 optparse는 옵션을 짧은 옵션 문자열(-f)과 긴 옵션 문자열(--file) 모두에서 지원하고, 값 있는 옵션(-f foo)과 붙여 쓰는 옵션(-ffoo, --file=foo) 형태를 모두 받아들여요.

배경 (Background)

optparse를 이해하려면 명령줄 파싱의 전통적인 관례를 먼저 알아야 해요. 유닉스 계열 명령줄 인터페이스의 관례에 따르면 명령줄 인자는 크게 **옵션(option)**과 **위치 인자(positional argument)**로 나뉘어요.

  • 옵션-a-f foo, --file foo, --file=foo처럼 하이픈으로 시작하는 인자들이에요. 옵션은 명령줄에서 명령 이름 바로 뒤와 위치 인자 앞에 나와요.
  • 위치 인자는 옵션이 아닌 모든 인자로, 보통 파일명이에요.

optparse 접근 방식의 좋은 점은 옵션을 필요에 따라 선택적으로 해석한다는 거예요. 옵션은 처리 순서에 예민하지 않아서, -a -b-b -a가 동일하게 동작해요.

옵션은 무엇을 위한 것인가? (What are options for?)

옵션은 주로 프로그램의 동작을 조율하는 데 쓰여요. 예를 들어 ls-l은 장문(long) 파일 목록을 요청하고, -a는 숨김 파일도 함께 보여달라고 요청하는 식이에요. 옵션에 따라 값을 요구하기도 해요.

위치 인자는 무엇을 위한 것인가? (What are positional arguments for?)

위치 인자는 프로그램이 어떤 것을 처리할지 알려주는 데 쓰여요. 예를 들어 prog의 위치 인자 infileoutfile은 입력 파일과 출력 파일을 의미하죠.

이제 optparse를 "어떻게"와 "무엇"의 관점에서 정리하면, 옵션은 프로그램의 how(어떻게 동작하는지)를 지정하고, 위치 인자는 what(무엇을 처리하는지)를 지정한다고 볼 수 있어요.

튜토리얼 (Tutorial)

optparse를 쓰려면 먼저 OptionParser 인스턴스를 만들어야 해요. 다음에 옵션을 정의하고, 마지막으로 parse_args()를 호출해서 명령줄을 파싱해요.

from optparse import OptionParser

parser = OptionParser()
parser.add_option("-f", "--file", dest="filename",
                  help="write report to FILE", metavar="FILE")

(options, args) = parser.parse_args()

OptionParser가 명령줄을 파싱하면 두 개의 값을 반환해요.

  • options — 각 옵션에 대한 값을 담은 객체 (optparse.Values 인스턴스)
  • args — 옵션으로 처리되지 않고 남은 위치 인자들의 리스트

-f foo 또는 --file foo--file=foo가 명령줄에 나타나면 options.filename"foo"로 설정돼요. 값이 없는 옵션에 값을 붙이려 하면 optparse가 오류를 내요. 옵션이 아예 나타나지 않으면 options.filenameNone이 돼요 (기본값을 설정하지 않았을 때).

위 예시에서 dest="filename"options.filename으로 접근되는 이유이기도 해요. dest를 생략하면 optparse가 첫 번째 긴 옵션 문자열에서 유도하므로(예: --foo-barfoo_bar), 위 예시에서는 dest를 생략해도 options.filename으로 동일하게 동작해요.

옵션 동작 이해하기 (Understanding option actions)

옵션을 정의할 때 넘기는 속성 중에서 action이 가장 중요해요. actionoptparse가 명령줄에서 해당 옵션을 만났을 때 무엇을 할지 결정해요. 표준으로 내장된 동작은 "store"예요.

store 동작 (The store action)

"store" 동작은 옵션 인자를 저장하는 가장 일반적인 동작이에요. -f--file처럼 값을 기대하는 옵션들이 여기 해당해요.

parser.add_option("-f", "--file",
                  action="store", type="string", dest="filename")
args = ["-f", "foo.txt"]
(options, args) = parser.parse_args(args)
print(options.filename)

optparse는 옵션 값이 어떤 타입인지 검사하고, 필요한 경우 문자열을 다른 타입으로 변환도 해줘요. 다음 예시에서는 -i 옵션의 값을 정수로 변환해요.

parser.add_option("-i", action="store", type="int", dest="i")

type을 생략하면 기본값은 "string"이에요. 만약 사용자가 -i 4x처럼 변환할 수 없는 값을 주면 optparse는 오류를 내고 종료해요.

일반적으로 store 동작을 쓸 때 type, dest 두 속성을 함께 쓰게 돼요.

불리언(플래그) 옵션 처리하기 (Handling boolean (flag) options)

"store_true""store_false" 동작은 값을 인자로 받는 대신, 명령줄에 옵션이 나타났는지 여부에 따라 True/False를 저장해요.

parser.add_option("-v", action="store_true", dest="verbose")
parser.add_option("-q", action="store_false", dest="verbose")

여기서 짧은 -v-q 옵션이 같은 목적지 verbose를 쓰고 있어요. -v가 나타나면 options.verboseTrue가 되고, -q가 나타나면 False가 돼요. 명령줄에서 나중에 나타난 옵션이 이기(win)니까, -q가 먼저 나오고 -v가 나중에 나오면 True가 저장돼요.

다른 동작들 (Other actions)

"store_const"는 명령줄에 옵션이 나타났을 때 미리 정해둔 상수를 저장하고, "append"는 옵션 인자를 리스트에 추가하며, "count"는 카운터를 증가시켜요.

parser.add_option("-n", "--noisy", action="store_const", const=2, dest="verbose")

"append"는 같은 옵션이 여러 번 나타날 때 유용해요.

parser.add_option("-t", "--tracks", action="append", type="int")

명령줄에 -t3 -t4가 있으면 options.tracks[3, 4]가 돼요.

기본값 (Default values)

default 속성으로 옵션이 명령줄에 나타나지 않을 때의 기본값을 설정할 수 있어요. OptionParser.set_defaults()로 동시에 여러 옵션의 기본값을 설정할 수도 있고, 생성자에 OptionParser(..., defaults={...})처럼 넘길 수도 있어요. 아래처럼 옵션별로 default를 지정하는 방식이 가장 명확해요.

parser.add_option("-v", action="store_true", dest="verbose", default=True)
parser.add_option("-q", action="store_false", dest="verbose", default=False)

만약 값 있는 옵션과 값 없는 옵션(플래그)이 같은 dest를 공유하면, 개념상 모순이 될 수 있으니 두 방식을 섞어 쓰지 않는 게 좋아요.

도움말 생성하기 (Generating help)

optparse는 도움말과 사용법(usage) 텍스트를 자동 생성하는 강력한 기능을 제공해요. 각 옵션에 help 값을 주고, 프로그램 전체에 짧은 usage 메시지도 선택적으로 줄 수 있어요.

usage = "usage: %prog [options] arg1 arg2"
parser = OptionParser(usage=usage)
parser.add_option("-v", "--verbose",
                  action="store_true", dest="verbose", default=True,
                  help="make lots of noise [default]")
parser.add_option("-q", "--quiet",
                  action="store_false", dest="verbose",
                  help="be vewwy quiet (I'm hunting wabbits)")
parser.add_option("-f", "--filename",
                  metavar="FILE", help="write output to FILE")
parser.add_option("-m", "--mode",
                  default="intermediate",
                  help="interaction mode: novice, intermediate, "
                       "or expert [default: %default]")

명령줄에서 -h--help를 만나면(또는 parser.print_help()를 호출하면) 다음과 같은 도움말을 표준 출력으로 출력해요.

Usage: <yourscript> [options] arg1 arg2

Options:
  -h, --help            show this help message and exit
  -v, --verbose         make lots of noise [default]
  -q, --quiet           be vewwy quiet (I'm hunting wabbits)
  -f FILE, --filename=FILE
                        write output to FILE
  -m MODE, --mode=MODE  interaction mode: novice, intermediate, or
                        expert [default: intermediate]

optparse가 최상의 도움말을 생성하도록 도와주는 요소는 많아요.

  • 스크립트는 자신만의 usage 메시지를 정의할 수 있어요. %prog는 현재 프로그램 이름(os.path.basename(sys.argv[0]))으로 확장된 뒤, 상세 옵션 도움말보다 먼저 출력돼요. usage 문자열을 주지 않으면 기본값은 "Usage: %prog [options]"예요.
  • 각 옵션은 help 문자열을 정의하고 줄바꿈은 optparse가 알아서 처리해요.
  • 값을 취하는 옵션은 자동 생성된 도움말에 그 사실을 표시해요. 예를 들어 -m MODE, --mode=MODE에서 MODE는 **메타 변수(meta-variable)**로, 사용자가 -m/--mode에 줄 인자를 나타내요. 기본적으로 optparse는 목적지 변수명을 대문자로 바꿔 메타 변수로 쓰지만, metavar="FILE"처럼 명시적으로 지정할 수도 있어요.
  • 기본값이 있는 옵션은 help 문자열에 %default를 넣을 수 있고, optparse가 그 옵션의 기본값의 str()로 치환해요. 기본값이 없거나 None이면 %defaultnone으로 확장돼요.
옵션 그룹화하기 (Grouping Options)

옵션이 많을 때는 옵션을 그룹으로 묶어 도움말 출력을 정리하는 게 편리해요. OptionParser는 여러 개의 OptionGroup을 가질 수 있고, 각 그룹은 여러 옵션을 담을 수 있어요.

class optparse.OptionGroup(parser, title, description=None)
  • parser — 그룹이 삽입될 OptionParser 인스턴스
  • title — 그룹 제목
  • description (선택) — 그룹에 대한 긴 설명

OptionGroupOptionContainer를 상속하므로 add_option()으로 그룹에 옵션을 추가할 수 있어요. 모든 옵션을 선언한 뒤에는 OptionParseradd_option_group()으로 그룹을 파서에 추가해요.

group = OptionGroup(parser, "Dangerous Options",
                    "Caution: use these options at your own risk.  "
                    "It is believed that some of them bite.")
group.add_option("-g", action="store_true", help="Group option.")
parser.add_option_group(group)

이 경우 도움말 출력에는 그룹 제목과 설명이 함께 나와요. 그룹을 둘 이상 쓸 수도 있죠.

OptionParser.get_option(opt_str)은 짧거나 긴 옵션 문자열(-o--option)이 속한 OptionGroup을 반환하고, 없으면 None을 반환해요.

버전 문자열 출력하기 (Printing a version string)

OptionParserversion 인자로 프로그램의 버전 문자열을 넣으면, optparse가 자동으로 --version 옵션을 추가해요. 만나면 %prog를 확장해 버전 문자열을 표준 출력으로 출력하고 종료해요.

parser = OptionParser(usage="%prog [-f] [-q]", version="%prog 1.0")

script/usr/bin/foo라면:

$ /usr/bin/foo --version
foo 1.0
  • OptionParser.print_version(file=None) — 현재 프로그램의 버전 메시지(self.version)를 file(기본 stdout)에 출력. %prog는 프로그램 이름으로 치환. self.version이 비어 있거나 없으면 아무것도 안 함.
  • OptionParser.get_version()print_version()과 같지만 출력 대신 문자열을 반환.

optparse가 오류를 처리하는 방법 (How optparse handles errors)

optparse가 다루어야 하는 오류는 크게 두 종류예요.

  • 프로그래머 오류OptionParser.add_option()의 잘못된 호출(잘못된 옵션 문자열, 알 수 없는 옵션 속성 등). 보통 optparse.OptionErrorTypeError 예외를 던져 프로그램을 중단시켜요.
  • 사용자 오류 — 코드가 아무리 안정적이어도 발생하는 오류로, 훨씬 더 중요해요. 잘못된 옵션 인자(-n 4x), 누락된 인자(-n이 마지막에 옴) 등을 optparse가 자동으로 감지하고, OptionParser.error()를 호출해 애플리케이션 정의 오류 조건을 알릴 수도 있어요.
(options, args) = parser.parse_args()
...
if options.a and options.b:
    parser.error("options -a and -b are mutually exclusive")

어느 경우든 optparse는 같은 방식으로 처리해요. 프로그램의 usage 메시지와 오류 메시지를 표준 오류로 출력하고, 오류 상태 2로 종료해요.

$ /usr/bin/foo -n 4x
Usage: foo [options]

foo: error: option -n: invalid integer value: '4x'
$ /usr/bin/foo -n
Usage: foo [options]

foo: error: -n option requires an argument

optparse가 생성하는 오류 메시지는 항상 관련 옵션을 언급하도록 되어 있어요. 애플리케이션 코드에서 OptionParser.error()를 호출할 때도 마찬가지로 해주는 게 좋아요. 기본 오류 처리 동작이 마음에 들지 않으면 OptionParser를 서브클래싱해서 exit()error() 메서드를 재정의하면 돼요.

모두 정리하기 (Putting it all together)

optparse 기반 스크립트는 보통 다음과 같이 생겼어요.

from optparse import OptionParser
...
def main():
    usage = "usage: %prog [options] arg"
    parser = OptionParser(usage)
    parser.add_option("-f", "--file", dest="filename",
                      help="read data from FILENAME")
    parser.add_option("-v", "--verbose",
                      action="store_true", dest="verbose")
    parser.add_option("-q", "--quiet",
                      action="store_false", dest="verbose")
    ...
    (options, args) = parser.parse_args()
    if len(args) != 1:
        parser.error("incorrect number of arguments")
    if options.verbose:
        print("reading %s..." % options.filename)
    ...

if __name__ == "__main__":
    main()

참조 가이드 (Reference Guide)

파서 생성하기 (Creating the parser)

class optparse.OptionParser(...)

OptionParser 생성자는 필수 인자가 없고, 여러 선택적 키워드 인자를 가져요. 항상 키워드 인자로 넘기는 게 좋아요(선언 순서에 의존하지 말 것).

  • usage (기본 "%prog [options]") — 프로그램이 잘못 실행되거나 help 옵션과 함께 쓸 때 출력할 usage 요약. %progos.path.basename(sys.argv[0])(또는 prog를 넘기면 그것)로 확장돼요. usage 메시지를 생략하려면 optparse.SUPPRESS_USAGE를 넘겨요.
  • option_list (기본 []) — 파서에 채울 Option 객체 리스트. standard_option_list(서브클래스가 설정할 수 있는 클래스 속성) 뒤, version/help 옵션보다 먼저 추가돼요. 비권장 — 파서 생성 후 add_option()을 쓰는 걸 권장해요.
  • option_class (기본 optparse.Option) — add_option()에서 옵션 추가에 쓸 클래스.
  • version (기본 None) — 사용자가 version 옵션을 줄 때 출력할 버전 문자열. 참값을 주면 optparse--version 옵션을 자동으로 추가해요.
  • conflict_handler (기본 "error") — 충돌하는 옵션 문자열이 추가될 때 처리 방법 지정 ("Conflicts between options" 섹션 참고).
  • description (기본 None) — 프로그램 개요를 주는 한 문단의 텍스트. 사용자가 help를 요청할 때 터미널 너비에 맞춰 재정렬되어 출력돼요.
  • formatter (기본 새 IndentedHelpFormatter) — 도움말 텍스트 출력에 쓰는 optparse.HelpFormatter 인스턴스. IndentedHelpFormatterTitledHelpFormatter 두 구체 클래스가 제공돼요.
  • add_help_option (기본 True) — 참이면 -h--help 옵션 문자열을 가진 help 옵션을 추가해요.
  • progusageversion에서 %prog를 확장할 때 os.path.basename(sys.argv[0]) 대신 쓸 문자열.
  • epilog (기본 None) — 옵션 도움말 뒤에 출력할 도움말 텍스트 문단.

파서 채우기 (Populating the parser)

파서에 옵션을 채우는 방법은 여러 가지가 있어요. 권장 방식은 OptionParser.add_option()을 쓰는 거예요. 두 가지 방식으로 호출할 수 있어요.

  • Option 인스턴스(make_option()이 반환하는)를 넘기기
  • make_option()(즉 Option 생성자)에 허용되는 위치/키워드 인자의 조합을 넘기면 optparseOption 인스턴스를 알아서 만들어줘요

또는 미리 만든 Option 인스턴스 리스트를 생성자에 넘길 수도 있어요.

option_list = [
    make_option("-f", "--filename",
                action="store", type="string", dest="filename"),
    make_option("-q", "--quiet",
                action="store_false", dest="verbose"),
    ]
parser = OptionParser(option_list=option_list)

make_option()Option 인스턴스를 만드는 팩토리 함수예요. 현재는 Option 생성자의 별칭이지만, 미래 버전에서 Option이 여러 클래스로 나뉠 수 있으니 Option을 직접 인스턴스화하지 말아요.

옵션 정의하기 (Defining options)

Option 인스턴스는 동의어인 명령줄 옵션 문자열 집합(예: -f--file)을 나타내요. Option 인스턴스를 만드는 표준 방법은 OptionParser.add_option()을 쓰는 것이에요.

OptionParser.add_option(option)
OptionParser.add_option(*opt_str, attr=value, ...)

짧은 옵션만 정의하려면 parser.add_option("-f", attr=value, ...), 긴 옵션만 정의하려면 parser.add_option("--foo", attr=value, ...)처럼 해요. 키워드 인자는 새 Option 객체의 속성을 정의해요. 가장 중요한 속성은 action이고, 그것이 어떤 다른 속성이 관련되거나 필수인지를 크게 결정해요. 관련 없는 속성을 넘기거나 필수 속성을 빠뜨리면 optparse가 실수를 설명하는 OptionError 예외를 던져요.

옵션의 actionoptparse가 명령줄에서 해당 옵션을 만났을 때 무엇을 할지 결정해요. optparse에 하드코딩된 표준 옵션 동작은 다음과 같아요.

  • "store" — 이 옵션의 인자를 저장 (기본)
  • "store_const"Option.const로 미리 설정된 상수 저장
  • "store_true"True 저장
  • "store_false"False 저장
  • "append" — 이 옵션의 인자를 리스트에 추가
  • "append_const"Option.const로 미리 설정된 상수를 리스트에 추가
  • "count" — 카운터를 1 증가
  • "callback" — 지정된 함수 호출
  • "help" — 모든 옵션과 문서가 포함된 usage 메시지 출력

(action을 주지 않으면 기본은 "store"예요. 대부분의 동작은 어딘가에 값을 저장하거나 갱신하는 것이고, optparse는 이를 위해 관례적으로 options라 부르는 특별한 객체 optparse.Values를 만들어요.)

class optparse.Values

파싱된 인자 이름과 값을 속성으로 담는 객체예요. 보통 OptionParser.parse_args() 호출 시 만들어지며, OptionParser.parse_args()values 인자로 넘기는 커스텀 서브클래스로 대체할 수 있어요. 옵션 인자(및 여러 값)는 dest에 따라 이 객체의 속성으로 저장돼요.

예를 들어 옵션을

parser.add_option("-f", "--file", action="store", type="string", dest="filename")

로 정의하면, 명령줄에 -ffoo, -f foo, --file=foo, --file foo 중 어느 것이든 optparseoptions.filename = "foo"와 동등한 일을 해요.

옵션 속성들 (Option attributes)

class optparse.Option

생성자에 키워드로 넘겨지는 다양한 속성을 가진 단일 명령줄 인자예요. 보통 직접 만드는 대신 OptionParser.add_option()으로 만들고, OptionParseroption_class 인자로 커스텀 클래스로 대체할 수 있어요.

OptionParser.add_option()에 키워드 인자로 넘길 수 있는 옵션 속성들이에요. 특정 옵션에 관련 없는 속성을 넘기거나 필수 속성을 빠뜨리면 optparseOptionError를 던져요.

  • Option.action (기본 "store") — 명령줄에서 이 옵션을 봤을 때 optparse의 동작 결정.
  • Option.type (기본 "string") — 이 옵션이 기대하는 인자 타입(예: "string" 또는 "int").
  • Option.dest (기본: 옵션 문자열에서 유도) — 옵션 동작이 어딘가에 값을 쓰거나 수정할 때 어디에 쓸지. options 객체의 속성 이름을 지정해요.
  • Option.default — 명령줄에서 옵션이 나타나지 않을 때 목적지에 쓸 값. OptionParser.set_defaults()도 참고.
  • Option.nargs (기본 1) — 이 옵션을 봤을 때 소비할 type 타입 인자의 개수. > 1이면 optparse가 값들의 튜플을 dest에 저장해요.
  • Option.const — 상수를 저장하는 동작에서 저장할 상수 값.
  • Option.choices"choice" 타입 옵션에서 사용자가 고를 수 있는 문자열 리스트.
  • Option.callbackaction"callback"인 옵션에서 이 옵션을 봤을 때 호출할 콜러블.
  • Option.callback_args / Option.callback_kwargs — 네 개의 표준 콜백 인자 뒤에 callback에 넘길 추가 위치/키워드 인자.
  • Option.help — 사용자가 help 옵션(--help)을 주었을 때 모든 옵션을 나열할 때 출력할 도움말 텍스트. 주지 않으면 도움말 없이 나열되고, 숨기려면 optparse.SUPPRESS_HELP를 써요.
  • Option.metavar (기본: 옵션 문자열에서 유도) — 도움말 텍스트를 출력할 때 옵션 인자 대신 쓸 자리 표시자.

표준 옵션 동작들 (Standard option actions)

각 옵션 동작은 요구 사항과 효과가 조금씩 달라요.

"store" [관련: type, dest, nargs, choices]

옵션 뒤에 인자가 와야 하고, type에 따라 값으로 변환되어 dest에 저장돼요. nargs > 1이면 명령줄에서 여러 인자를 소비하고 모두 type으로 변환해 튜플로 dest에 저장해요. choices(문자열 리스트/튜플)를 주면 type 기본값이 "choice"가 되고, type을 주지 않으면 "string"이 돼요. dest를 주지 않으면 첫 번째 긴 옵션 문자열(--foo-barfoo_bar)에서, 긴 옵션이 없으면 첫 짧은 옵션(-ff)에서 유도해요.

parser.add_option("-f")
parser.add_option("-p", type="float", nargs=3, dest="point")

명령줄 -f foo.txt -p 1 -3.5 4 -fbar.txt를 파싱하면:

options.f = "foo.txt"
options.point = (1.0, -3.5, 4.0)
options.f = "bar.txt"

"store_const" [필수: const; 관련: dest]

const 값을 dest에 저장해요.

parser.add_option("-q", "--quiet",
                  action="store_const", const=0, dest="verbose")
parser.add_option("-v", "--verbose",
                  action="store_const", const=1, dest="verbose")
parser.add_option("--noisy",
                  action="store_const", const=2, dest="verbose")

--noisy가 보이면 options.verbose = 2가 돼요.

"store_true" [관련: dest] — Truedest에 저장하는 "store_const"의 특수 경우. "store_false" [관련: dest] — "store_true"와 같지만 False를 저장.

parser.add_option("--clobber", action="store_true", dest="clobber")
parser.add_option("--no-clobber", action="store_false", dest="clobber")

"append" [관련: type, dest, nargs, choices]

옵션 뒤에 인자가 와야 하고 dest의 리스트에 추가돼요. dest 기본값을 주지 않으면 optparse가 처음 만났을 때 빈 리스트를 자동 생성해요. nargs > 1이면 여러 인자를 소비하고 길이 nargs의 튜플을 dest에 추가해요. typedest 기본값은 "store"와 같아요.

parser.add_option("-t", "--tracks", action="append", type="int")

-t3이 보이면 options.tracks = []options.tracks.append(int("3"))을 하고, 이후 --tracks=4가 보이면 options.tracks.append(int("4"))를 해요.

append 동작은 현재 값의 append 메서드를 호출해요. 즉 지정된 기본값은 append 메서드가 있어야 하고, 기본값이 비어 있지 않으면 파싱된 값에 기본 요소가 남아 있고 명령줄 값이 그 뒤에 추가돼요.

>>> parser.add_option("--files", action="append", default=['~/.mypkg/defaults'])
>>> opts, args = parser.parse_args(['--files', 'overrides.mypkg'])
>>> opts.files
['~/.mypkg/defaults', 'overrides.mypkg']

"append_const" [필수: const; 관련: dest] — "store_const"와 같지만 const 값을 dest에 추가해요. "append"처럼 dest 기본값이 None이고 처음 만났을 때 빈 리스트가 자동 생성돼요.

"count" [관련: dest] — dest에 저장된 정수를 증가. 기본값을 주지 않으면 첫 증가 전에 dest를 0으로 설정.

parser.add_option("-v", action="count", dest="verbosity")

-v를 처음 보면 options.verbosity = 0; options.verbosity += 1이고, 이후 -v마다 options.verbosity += 1이 돼요.

"callback" [필수: callback; 관련: type, nargs, callback_args, callback_kwargs]

callback이 지정하는 함수를 호출해요.

func(option, opt_str, value, parser, *args, **kwargs)

자세한 내용은 "Option Callbacks" 섹션을 참고해요.

"help" — 현재 파서의 모든 옵션에 대한 완전한 도움말 메시지를 출력. OptionParser 생성자에 넘긴 usage 문자열과 각 옵션에 넘긴 help 문자열로 구성돼요. help 문자열이 없어도 옵션은 목록에 나타나고, 완전히 생략하려면 optparse.SUPPRESS_HELP를 써요. optparse는 모든 OptionParser에 help 옵션을 자동 추가하므로 보통 직접 만들 필요가 없어요.

from optparse import OptionParser, SUPPRESS_HELP

# usually, a help option is added automatically, but that can
# be suppressed using the add_help_option argument
parser = OptionParser(add_help_option=False)

parser.add_option("-h", "--help", action="help")
parser.add_option("-v", action="store_true", dest="verbose",
                  help="Be moderately verbose")
parser.add_option("--file", dest="filename",
                  help="Input file to read data from")
parser.add_option("--secret", help=SUPPRESS_HELP)

-h--help를 보면(sys.argv[0]"foo.py"라고 가정):

Usage: foo.py [options]

Options:
  -h, --help        Show this help message and exit
  -v                Be moderately verbose
  --file=FILENAME   Input file to read data from

도움말 출력 후 optparsesys.exit(0)으로 프로세스를 종료해요.

"version"OptionParser에 준 버전 번호를 stdout에 출력하고 종료. 보통 version 인자를 생성자에 준 경우에만 관련 있고, OptionParser.print_version()으로 출력돼요. help 옵션처럼 필요할 때 자동 추가되므로 직접 만들 일은 드물어요.

표준 옵션 타입들 (Standard option types)

optparse에는 다섯 가지 내장 옵션 타입이 있어요: "string", "int", "choice", "float", "complex". 새 타입을 추가하려면 "Extending optparse" 섹션을 참고해요.

  • 문자열 옵션의 인자는 검사나 변환 없이 그대로 목적지에 저장(또는 콜백에 전달)돼요.
  • 정수(type "int") 인자는 다음과 같이 파싱돼요.
    • 숫자가 0x로 시작하면 16진수로 파싱
    • 숫자가 0으로 시작하면 8진수로 파싱
    • 숫자가 0b로 시작하면 2진수로 파싱
    • 그 외에는 10진수로 파싱
    • 변환은 적절한 밑(2, 8, 10, 16)으로 int()를 호출해 수행. 실패하면 optparse도 실패하지만 더 유용한 오류 메시지를 줘요.
  • "float""complex" 인자는 각각 float()complex()로 직접 변환하고, 오류 처리도 비슷해요.
  • "choice""string"의 하위 타입으로, choices 속성(문자열 시퀀스)이 허용 옵션 인자 집합을 정의해요. optparse.check_choice()가 사용자 인자를 이 목록과 비교해 유효하지 않으면 OptionValueError를 던져요.

인자 파싱하기 (Parsing arguments)

OptionParser.parse_args(args=None, values=None)

args에서 명령줄 옵션을 파싱해요.

  • args — 처리할 인자 리스트 (기본: sys.argv[1:])
  • values — 옵션 인자를 저장할 Values 객체 (기본: 새 Values 인스턴스). 기존 객체를 주면 옵션 기본값이 그 객체에 초기화되지 않아요.

반환값은 쌍 (options, args)이에요.

  • optionsvalues로 넘긴 것과 같은 객체 또는 optparse가 만든 optparse.Values 인스턴스
  • args — 모든 옵션이 처리된 뒤 남은 위치 인자들

가장 흔한 사용법은 두 키워드 인자 모두 주지 않는 거예요. values를 주면 반복된 setattr() 호출로 수정되고 parse_args()가 반환해요. parse_args()가 인자 목록에서 오류를 만나면 적절한 사용자 오류 메시지와 함께 error() 메서드를 호출하고, 결국 종료 상태 2(명령줄 오류의 전통적인 유닉스 종료 상태)로 프로세스를 종료해요.

옵션 파서 조회·조작하기 (Querying and manipulating your option parser)

  • OptionParser.disable_interspersed_args() — 첫 번째 비옵션에서 파싱을 멈추도록 설정. 예를 들어 -a, -b가 인자를 안 받는 단순 옵션이면 optparse는 보통 prog -a arg1 -b arg2prog -a -b arg1 arg2와 동등하게 취급해요. 이 기능을 끄면 전통적인 유닉스 문법으로 복원되어, 첫 비옵션 인자에서 옵션 파싱이 멈춰요. 자기 고유 옵션이 있는 다른 명령을 실행하는 명령 처리기에서 유용해요.
  • OptionParser.enable_interspersed_args() — 첫 비옵션에서 파싱을 멈추지 않도록 설정해 스위치와 명령 인자를 섞을 수 있게 해요. 기본 동작이에요.
  • OptionParser.get_option(opt_str) — 옵션 문자열 opt_str을 가진 Option 인스턴스를 반환하고, 없으면 None.
  • OptionParser.has_option(opt_str)OptionParser가 옵션 문자열 opt_str(예: -q 또는 --verbose)을 가진 옵션을 가지면 True 반환.
  • OptionParser.remove_option(opt_str) — 해당 옵션을 제거. 그 옵션이 다른 옵션 문자열도 제공했다면 그 문자열들도 모두 무효가 돼요. opt_str이 어떤 옵션에도 없으면 ValueError를 던져요.

옵션 간 충돌 (Conflicts between options)

잘못 다루면 충돌하는 옵션 문자열을 가진 옵션을 정의하기 쉬워요.

parser.add_option("-n", "--dry-run", ...)
...
parser.add_option("-n", "--noisy", ...)

옵션을 추가할 때마다 optparse는 기존 옵션과의 충돌을 검사하고, 발견하면 현재 충돌 처리 메커니즘을 호출해요. 충돌 처리 메커니즘은 생성자(OptionParser(..., conflict_handler=handler))나 별도 호출(parser.set_conflict_handler(handler))로 설정할 수 있어요.

사용 가능한 충돌 처리기는 다음과 같아요.

  • "error" (기본) — 옵션 충돌을 프로그래밍 오류로 간주하고 OptionConflictError를 던짐
  • "resolve" — 옵션 충돌을 지능적으로 해결
parser = OptionParser(conflict_handler="resolve")
parser.add_option("-n", "--dry-run", ..., help="do no harm")
parser.add_option("-n", "--noisy", ..., help="be noisy")

conflict_handler"resolve"이면, optparse는 이전 옵션의 옵션 문자열 목록에서 -n을 제거해 해결해요. 이제 --dry-run이 그 옵션을 활성화하는 유일한 방법이 돼요.

parser.add_option("--dry-run", ..., help="new dry-run option")

이제 원래 -n/--dry-run 옵션은 더 이상 접근할 수 없으므로 optparse가 완전히 제거해요.

정리 (Cleanup)

OptionParser 인스턴스는 순환 참조가 여러 개 있어요. Python 가비지 컬렉터에는 문제가 되지 않지만, OptionParser 사용을 마친 뒤 destroy()를 호출해 순환 참조를 명시적으로 끊고 싶을 수도 있어요. 특히 긴 실행 애플리케이션에서 큰 객체 그래프가 OptionParser에서 도달 가능할 때 유용해요.

다른 메서드들 (Other methods)

  • OptionParser.set_usage(usage) — 위에서 설명한 규칙대로 usage 문자열을 설정. None을 넘기면 기본 usage 문자열로 설정하고, optparse.SUPPRESS_USAGE는 사용법 메시지를 생략.
  • OptionParser.print_usage(file=None)self.usagefile(기본 stdout)에 출력. %prog는 프로그램 이름으로 치환. 비어 있거나 없으면 아무것도 안 함.
  • OptionParser.get_usage()print_usage()와 같지만 문자열을 반환.
  • OptionParser.set_defaults(dest=value, ...) — 여러 옵션 목적지의 기본값을 한 번에 설정. 여러 옵션이 같은 목적지를 공유할 수 있으므로 기본값 설정의 권장 방법이에요.
parser.set_defaults(mode="advanced")
parser.add_option("--advanced", action="store_const",
                  dest="mode", const="advanced")
parser.add_option("--novice", action="store_const",
                  dest="mode", const="novice")

옵션 콜백 (Option Callbacks)

내장 동작과 타입만으로 부족할 때는 두 가지 선택지가 있어요: optparse를 확장하거나 콜백 옵션을 정의하는 것. 콜백 옵션을 정의하는 두 단계는 다음과 같아요.

  1. "callback" 동작으로 옵션 자체를 정의
  2. 콜백(최소 네 인자를 받는 함수/메서드)을 작성

콜백 옵션 정의하기 (Defining a callback option)

action 외에 꼭 지정해야 할 속성은 호출할 함수 callback이에요.

parser.add_option("-c", action="callback", callback=my_callback)

optparse는 콜백에 항상 네 개의 특정 인자를 넘기고, callback_args/callback_kwargs로 지정한 추가 인자만 더 넘겨요. 따라서 최소 콜백 함수 시그니처는 다음과 같아요.

def my_callback(option, opt, value, parser):

콜백 옵션을 정의할 때 줄 수 있는 다른 옵션 속성들은 다음과 같아요.

  • type — 평소와 같은 의미. "store"/"append"처럼 인자 하나를 소비해 type으로 변환하라고 지시. 변환된 값을 저장하는 대신 콜백에 전달해요.
  • nargs — 평소와 같은 의미. 주어지고 > 1이면 nargs 인자를 소비하고, 각각 type으로 변환 가능해야 해요. 변환된 값의 튜플을 콜백에 전달.
  • callback_args — 콜백에 넘길 추가 위치 인자의 튜플
  • callback_kwargs — 콜백에 넘길 추가 키워드 인자의 딕셔너리

콜백이 호출되는 방법 (How callbacks are called)

모든 콜백은 다음과 같이 호출돼요.

func(option, opt_str, value, parser, *args, **kwargs)
  • option — 콜백을 호출하는 Option 인스턴스
  • opt_str — 콜백을 촉발하는 명령줄에서 본 옵션 문자열. 축약된 긴 옵션을 쓰면 전체 표준 옵션 문자열이 돼요 (예: --foobar의 축약 --fooopt_str"--foobar").
  • value — 명령줄에서 본 이 옵션의 인자. type이 설정된 경우에만 인자가 기대되고, 값의 타입은 옵션 type이 뜻하는 타입이에요. typeNone(인자 없음)이면 valueNone, nargs > 1이면 적절한 타입 값의 튜플.
  • parser — 전체를 구동하는 OptionParser 인스턴스. 인스턴스 속성으로 흥미로운 데이터에 접근할 수 있어요.
    • parser.largs — 남은(consumed but neither options nor option arguments) 인자의 현재 리스트. 수정해도 되고, 이 리스트가 parse_args()의 두 번째 반환값 args가 돼요.
    • parser.rargs — 남아 있는(remaining) 인자의 현재 리스트. opt_strvalue(해당하면)가 제거되고 뒤의 인자만 남아 있어요. 수정해도 돼요(더 많은 인자 소비 등).
    • parser.values — 옵션 값을 기본으로 저장하는 객체(optparse.OptionValues 인스턴스). 전역이나 클로저를 건드리지 않고도 같은 메커니즘을 쓰게 해줘요.
  • argscallback_args로 준 임의 위치 인자의 튜플
  • kwargscallback_kwargs로 준 임의 키워드 인자의 딕셔너리

콜백에서 오류 일으키기 (Raising errors in a callback)

옵션이나 그 인자에 문제가 있으면 콜백 함수는 OptionValueError를 던져야 해요. optparse가 이를 잡아 프로그램을 종료하고, 준 오류 메시지를 stderr에 출력해요. 메시지는 명확하고 간결하며 정확해야 하고, 문제의 옵션을 언급해야 해요.

콜백 예제 1: 사소한 콜백 (Callback example 1: trivial callback)

인자를 안 받고 옵션이 보였다는 것만 기록하는 예시예요.

def record_foo_seen(option, opt_str, value, parser):
    parser.values.saw_foo = True

parser.add_option("--foo", action="callback", callback=record_foo_seen)

물론 "store_true" 동작으로도 같은 일을 할 수 있어요.

콜백 예제 2: 옵션 순서 확인 (Callback example 2: check option order)

-a가 보였다는 걸 기록하지만, 명령줄에서 -b 뒤에 오면 실패하는 예시예요.

def check_order(option, opt_str, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use -a after -b")
    parser.values.a = 1
...
parser.add_option("-a", action="callback", callback=check_order)
parser.add_option("-b", action="store_true", dest="b")

콜백 예제 3: 옵션 순서 확인 (일반화) (Callback example 3: generalized)

여러 비슷한 옵션에 재사용하려면(플래그를 세우되 -b가 이미 보였으면 실패) 오류 메시지와 설정 플래그를 일반화해야 해요.

def check_order(option, opt_str, value, parser):
    if parser.values.b:
        raise OptionValueError("can't use %s after -b" % opt_str)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("-a", action="callback", callback=check_order, dest='a')
parser.add_option("-b", action="store_true", dest="b")
parser.add_option("-c", action="callback", callback=check_order, dest='c')

콜백 예제 4: 임의 조건 확인 (Callback example 4: arbitrary condition)

이미 정의된 옵션 값 확인에 제한되지 않아요. 예를 들어 달이 가득 찼을 때 호출하면 안 되는 옵션이 있다면:

def check_moon(option, opt_str, value, parser):
    if is_moon_full():
        raise OptionValueError("%s option invalid when moon is full"
                               % opt_str)
    setattr(parser.values, option.dest, 1)
...
parser.add_option("--foo",
                  action="callback", callback=check_moon, dest="foo")

콜백 예제 5: 고정 개수 인자 (Callback example 5: fixed arguments)

고정 개수의 인자를 받는 콜백 옵션은 "store"/"append"와 비슷하게, type을 정의하면 인자 하나를, nargs까지 정의하면 nargs 개수 인자를 받아요.

def store_value(option, opt_str, value, parser):
    setattr(parser.values, option.dest, value)
...
parser.add_option("--foo",
                  action="callback", callback=store_value,
                  type="int", nargs=3, dest="foo")

optparse가 3개 인자를 소비해 정수로 변환해주고, 여러분은 저장만 하면 돼요.

콜백 예제 6: 가변 개수 인자 (Callback example 6: variable arguments)

가변 개수 인자를 받는 옵션을 원하면 콜백을 직접 써야 해요. 콜백은 전통 유닉스 명령줄 파싱의 특정 규칙을 구현해야 해요.

  • ---가 옵션 인자가 될 수 있음
  • 네이키드 --(어떤 옵션의 인자가 아니라면): 명령줄 처리를 멈추고 --를 버림
  • 네이키드 -(어떤 옵션의 인자가 아니라면): 명령줄 처리를 멈추되 -는 유지(parser.largs에 추가)

다음은 가변 개수 인자 옵션을 위한 콜백 예시예요.

def vararg_callback(option, opt_str, value, parser):
    assert value is None
    value = []

    def floatable(str):
        try:
            float(str)
            return True
        except ValueError:
            return False

    for arg in parser.rargs:
        # stop on --foo like options
        if arg[:2] == "--" and len(arg) > 2:
            break
        # stop on -a, but not on -3 or -3.0
        if arg[:1] == "-" and len(arg) > 1 and not floatable(arg):
            break
        value.append(arg)

    del parser.rargs[:len(value)]
    setattr(parser.values, option.dest, value)

...
parser.add_option("-c", "--callback", dest="vararg_attr",
                  action="callback", callback=vararg_callback)

optparse 확장하기 (Extending optparse)

새 타입 추가하기 (Adding new types)

새 타입을 추가하려면 optparseOption 클래스의 서브클래스를 정의해야 해요. 이 클래스에는 optparse 타입을 정의하는 TYPESTYPE_CHECKER 두 속성이 있어요.

  • Option.TYPES — 타입 이름의 튜플. 서브클래스에서 표준 튜플을 확장한 새 튜플 TYPES를 정의하면 돼요.
  • Option.TYPE_CHECKER — 타입 이름을 타입 검사 함수에 매핑하는 딕셔너리. 타입 검사 함수 시그니처:
def check_mytype(option, opt, value)

optionOption 인스턴스, opt는 옵션 문자열(예: -f), value는 명령줄에서 검사·변환할 문자열이에요. check_mytype()은 가상의 타입 mytype 객체를 반환해야 하고, 반환값은 OptionValues 인스턴스에 담기거나 콜백에 value 매개변수로 전달돼요. 문제가 있으면 OptionValueError를 던져야 해요.

다음은 명령줄에서 Python 스타일 복소수를 파싱하는 "complex" 옵션 타입을 추가하는 예시예요 (내장 표준 타입에 이미 있지만 데모용).

from copy import copy
from optparse import Option, OptionValueError
def check_complex(option, opt, value):
    try:
        return complex(value)
    except ValueError:
        raise OptionValueError(
            "option %s: invalid complex value: %r" % (opt, value))
class MyOption (Option):
    TYPES = Option.TYPES + ("complex",)
    TYPE_CHECKER = copy(Option.TYPE_CHECKER)
    TYPE_CHECKER["complex"] = check_complex

(Option.TYPE_CHECKERcopy()하지 않으면 optparseOption 클래스의 TYPE_CHECKER 속성을 수정하게 돼요.)

이제 OptionParserMyOption을 쓰라고 지시하면 돼요.

parser = OptionParser(option_class=MyOption)
parser.add_option("-c", type="complex")

또는 자신의 옵션 리스트를 만들어 OptionParser에 넘길 수도 있어요.

option_list = [MyOption("-c", action="store", type="complex", dest="c")]
parser = OptionParser(option_list=option_list)

새 동작 추가하기 (Adding new actions)

새 동작 추가는 조금 더 까다로워요. optparse는 동작을 두 가지로 분류해요.

  • "store" 동작optparse가 현재 OptionValues 인스턴스의 속성에 값을 저장하는 결과를 낳는 동작. 이 옵션은 Option 생성자에 dest 속성이 필요해요.
  • "typed" 동작 — 명령줄에서 값을 받아 특정 타입(또는 특정 타입으로 변환 가능한 문자열)이길 기대하는 동작. Option 생성자에 type 속성이 필요해요.

이 집합은 겹쳐요. 기본 "store" 동작은 "store", "store_const", "append", "count"이고, 기본 "typed" 동작은 "store", "append", "callback"이에요.

동작을 추가할 때는 다음 Option 클래스 속성(모두 문자열 리스트) 중 적어도 하나에 나열해 분류해야 해요.

  • Option.ACTIONS — 모든 동작은 ACTIONS에 나열되어야 함
  • Option.STORE_ACTIONS — "store" 동작은 여기에 추가로 나열
  • Option.TYPED_ACTIONS — "typed" 동작은 여기에 추가로 나열
  • Option.ALWAYS_TYPED_ACTIONS — 항상 타입을 취하는(즉 항상 값을 취하는) 동작은 여기에 추가로 나열. optparse가 명시적 타입이 없는 옵션에 기본 타입 "string"을 할당하게 하는 효과가 있어요.

새 동작을 실제로 구현하려면 Optiontake_action() 메서드를 재정의하고 새 동작을 인식하는 case를 추가해야 해요. 예를 들어 "extend" 동작을 추가해보죠. 표준 "append"와 비슷하지만 단일 값 대신 쉼표로 구분된 여러 값을 받아 기존 리스트를 확장해요.

class MyOption(Option):

    ACTIONS = Option.ACTIONS + ("extend",)
    STORE_ACTIONS = Option.STORE_ACTIONS + ("extend",)
    TYPED_ACTIONS = Option.TYPED_ACTIONS + ("extend",)
    ALWAYS_TYPED_ACTIONS = Option.ALWAYS_TYPED_ACTIONS + ("extend",)

    def take_action(self, action, dest, opt, value, values, parser):
        if action == "extend":
            lvalue = value.split(",")
            values.ensure_value(dest, []).extend(lvalue)
        else:
            Option.take_action(
                self, action, dest, opt, value, values, parser)

주의할 점들:

  • "extend"는 명령줄에서 값을 기대하고 그 값을 어딘가에 저장하므로 STORE_ACTIONSTYPED_ACTIONS 둘 다에 들어가요.
  • 기본 타입 "string"을 할당받도록 ALWAYS_TYPED_ACTIONS에도 넣어요.
  • MyOption.take_action()은 이 새 동작만 구현하고, 표준 optparse 동작은 Option.take_action()에 제어를 넘겨요.
  • valuesoptparse_parser.Values 인스턴스로, 유용한 ensure_value() 메서드를 제공해요. values.ensure_value(attr, value)는 본질적으로 안전 밸브가 있는 getattr()이에요. attr 속성이 없거나 None이면 먼저 value로 설정한 뒤 반환해요. "extend", "append", "count"처럼 변수에 데이터를 축적하는 동작에 매우 유용해요.

예외 (Exceptions)

  • exception optparse.OptionError — 잘못되거나 모순된 인자로 Option 인스턴스를 만들 때 발생.
  • exception optparse.OptionConflictError — 충돌하는 옵션이 OptionParser에 추가될 때 발생.
  • exception optparse.OptionValueError — 명령줄에서 잘못된 옵션 값을 만났을 때 발생.
  • exception optparse.BadOptionError — 명령줄에서 잘못된 옵션이 전달될 때 발생.
  • exception optparse.AmbiguousOptionError — 명령줄에서 모호한 옵션이 전달될 때 발생.