PEP 389 – argparse - 새로운 명령줄 파싱 모듈
- Author:
- Steven Bethard <steven.bethard at gmail.com>
- Status:
- Final
- Type:
- Standards Track
- Created:
- 25-Sep-2009
- Python-Version:
- 2.7, 3.2
- Post-History:
- 27-Sep-2009, 24-Oct-2009
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
수락
이 PEP는 2010년 2월 21일 python-dev에서 Guido의 승인을 받았습니다 [17].
초록
이 PEP는 Python 2.7 및 3.2에서 argparse [1] 모듈을 Python 표준 라이브러리에 포함할 것을 제안합니다.
동기
argparse 모듈은 표준 라이브러리에 있는 기존 명령줄 파싱 모듈인 getopt [2] 및 optparse [3]보다 더 많은 기능을 제공하는 명령줄 파싱 라이브러리입니다. 이 모듈은 위치 인자(옵션만이 아닌), 하위 명령, 필수 옵션, “/f”나 “+rgb” 같은 옵션 문법, 0개 이상 및 1개 이상 형태의 인자를 지원하며, 그 밖에도 다른 두 모듈에는 없는 많은 기능을 제공합니다.
argparse 모듈은 이미 이러한 모듈을 대체하는 인기 있는 서드파티 모듈이기도 합니다. 이 모듈은 IPython(Scipy Python 셸) [4] 같은 프로젝트에서 사용되고, Debian testing 및 unstable에 포함되어 있으며 [5], 2007년부터 표준 라이브러리에 포함해 달라는 다양한 요청이 있었습니다 [6] [7] [8]. 이러한 인기로 볼 때 이 모듈은 Python 라이브러리에 가치 있는 추가 요소가 될 수 있습니다.
getopt와 optparse로는 왜 충분하지 않습니까?
argparse 추가에 반대하는 논거 중 하나는 “표준 라이브러리에 이미 서로 다른 옵션 파싱 모듈이 두 개 있다”는 것입니다 [9]. 다음은 argparse가 제공하지만 getopt나 optparse에는 없는 기능의 목록입니다:
- 옵션 파싱 라이브러리가 두 개 있는 것은 사실이지만, 완전한 명령줄 파싱 라이브러리는 없습니다 – getopt와 optparse는 모두 옵션만 지원하고 위치 인자는 지원하지 않습니다. argparse 모듈은 둘 다 처리하므로 더 나은 도움말 메시지를 생성할 수 있으며, optparse에서 보통 필요한
usage=문자열 같은 중복을 피할 수 있습니다. - argparse 모듈은 순수성보다 실용성을 중시합니다. 그래서 argparse는 필수 옵션을 허용하고 옵션을 식별하는 데 쓰이는 문자를 사용자 정의할 수 있게 합니다. 반면 optparse는 “‘필수 옵션’이라는 표현은 자기모순”이라고 명시하며,
-pf,-file,+f,+rgb,/f,/file옵션 문법은 “optparse에서 지원되지 않으며, 앞으로도 결코 지원되지 않을 것”이라고 밝힙니다. - argparse 모듈에서는
nargs='?',nargs='*'또는nargs='+'를 사용하여 옵션이 가변 개수의 인자를 받도록 할 수 있습니다. optparse 모듈은 이 기능의 일부에 대해 검증되지 않은 레시피를 제공하지만 [10], “옵션이 가변 개수의 인자를 받게 하려면 일이 복잡해진다”고 인정합니다. - argparse 모듈은 서브커맨드를 지원하는데, 이는 주 명령줄 파서가 명령줄 인자에 따라 다른 명령줄 파서로 처리를 넘기는 방식입니다. 이는 명령줄 인터페이스에서 흔한 패턴이며, 예를 들어
svn co와svn up이 있습니다.
왜 이 기능을 그냥 optparse에 추가하지 않습니까?
위의 모든 기능은 분명히 optparse로 할 수 있는 것보다 개선된 점을 제공합니다. 그렇다면 완전히 새로운 모듈을 도입하는 대신 왜 이러한 기능을 단순히 optparse에 대한 패치로 제공하지 않느냐는 질문은 합리적입니다. 사실 argparse는 원래 바로 그렇게 하려는 의도로 개발되었지만, optparse의 상당히 제약이 큰 여러 설계 결정 때문에 실제로는 불가능했습니다. 문제 중 일부는 다음과 같습니다:
- optparse 모듈은 파싱 알고리즘의 내부를 노출합니다. 특히
parser.largs와parser.rargs는 콜백에서 사용할 수 있음이 보장됩니다 [11]. 이 때문에 argparse에서 위치 인자와 가변 길이 인자를 제대로 처리하는 데 필요했던 것처럼 파싱 알고리즘을 개선하기가 극도로 어려워집니다. 예를 들어 argparse의nargs='+'는 정규 표현식을 사용해 매칭되므로parser.largs같은 개념이 없습니다. - optparse의 확장 API는 매우 복잡합니다. 예를 들어, 간단한 사용자 정의 문자열-객체 변환 함수 하나를 사용하려고 해도
Option의 서브클래스를 만들고, 클래스 속성을 조작한 다음, 다음과 같이 파서에 사용자 정의 옵션 타입을 지정해야 합니다:class MyOption(Option): TYPES = Option.TYPES + ("mytype",) TYPE_CHECKER = copy(Option.TYPE_CHECKER) TYPE_CHECKER["mytype"] = check_mytype parser = optparse.OptionParser(option_class=MyOption) parser.add_option("-m", type="mytype")
이와 비교하면, argparse에서는 변환 함수를
type=인자로 바로 사용할 수 있습니다. 예를 들면 다음과 같습니다.:parser = argparse.ArgumentParser() parser.add_option("-m", type=check_mytype)
하지만 optparse의 사용자 정의 API가 지나치게 복잡하기 때문에, 그러한 기능이 그 API들과 어떻게 상호 작용해야 할지 불분명하며, 간단한 argparse API를 도입하면 기존의 사용자 정의 Option 코드가 동작하지 않을 가능성이 상당히 높습니다.
- optparse와 argparse는 모두 명령줄 인자를 파싱하여
parse_args가 반환하는 객체에 속성으로 할당합니다. 그러나 optparse 모듈은 사용자 정의 액션의take_action메서드에ensure_value메서드를 제공하는values객체가 항상 전달된다고 보장하는 반면 [12], argparse 모듈은 어떤 객체에든 속성을 할당할 수 있게 해 줍니다. 예를 들면 다음과 같습니다.:foo_object = ... parser.parse_args(namespace=foo_object) foo_object.some_attribute_parsed_from_command_line
임의의 객체를 전달받을 수 있도록 optparse를 수정하기는 어려울 것입니다.
Values인스턴스 대신foo_object를 전달하기만 해도ensure_value메서드에 의존하는 기존 사용자 정의 액션이 동작하지 않게 되기 때문입니다.
이와 같은 문제들 때문에 argparse가 optparse API와의 호환성을 유지하기가 지나치게 어려웠으므로, argparse는 독립적인 모듈로 개발되었습니다. 이러한 문제들을 고려하면, 하위 호환성을 깨뜨리지 않고 argparse의 모든 기능을 optparse에 병합하기는 어려워 보입니다.
optparse의 폐지 예정
optparse의 모든 기능을 argparse에서 사용할 수 있으므로, optparse 모듈은 폐지 예정(deprecated)으로 지정됩니다. 그러나 optparse가 널리 사용되고 있으므로, 폐지 예정 전략에는 문서 변경과 기본적으로 표시되지 않는 경고만 포함됩니다:
- Python 2.7+ 및 3.2+ – optparse 문서에 다음 참고 사항이 추가됩니다:optparse 모듈은 폐지 예정이며 더 이상 개발되지 않습니다. 개발은 argparse 모듈에서 계속됩니다.
- Python 2.7+ – 명령줄에 Python 3 호환성 플래그인
-3이 주어지면, optparse를 임포트할 때 DeprecationWarning이 발생합니다. 그렇지 않으면 아무런 경고도 발생하지 않습니다. - Python 3.2+ – optparse를 임포트하면 PendingDeprecationWarning이 발생하며, 이 경고는 기본적으로 표시되지 않습니다.
optparse의 제거 일정은 제안하지 않는다는 점에 유의하십시오.
getopt 문서 갱신
getopt 모듈은 폐지 예정으로 지정되지 않습니다. 그러나 그 문서는 몇몇 곳에서 argparse를 안내하도록 갱신됩니다. 모듈 문서의 맨 위에 다음 참고 사항이 추가됩니다:
getopt 모듈은 명령줄 옵션 파서이며, 그 API는 C getopt 함수 사용자에게 익숙하도록 설계되었습니다. C getopt 함수에 익숙하지 않거나, 더 적은 코드로 더 나은 도움말과 오류 메시지를 얻고 싶은 사용자는 대신 argparse 모듈을 사용하는 것을 고려하십시오.
또한, 마지막 getopt 예제 뒤에 다음 참고 사항이 추가됩니다:
argparse 모듈을 사용하면 동등한 명령줄 인터페이스를 더 적은 코드로 만들 수 있다는 점에 유의하십시오:import argparse if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('-o', '--output') parser.add_argument('-v', dest='verbose', action='store_true') args = parser.parse_args() # ... do something with args.output ... # ... do something with args.verbose ..
보류: 문자열 포매팅
argparse 모듈은 Python 2.3부터 3.2까지를 지원하며, 그 때문에 전통적인 %(foo)s 스타일의 문자열 포매팅에 의존합니다. 새로운 스타일인 {foo} 문자열 포매팅을 사용하는 편이 더 나을 수 있다는 제안이 있었습니다 [13]. 표준 라이브러리 모듈에서 이를 가장 잘 처리하는 방법에 대한 논의가 있었으며 [14], 여러 사람이 %-포매팅을 {}-포매팅으로 자동 변환하는 함수를 개발하고 있습니다 [15] [16]. 이 중 하나가 표준 라이브러리에 추가되면, argparse는 이를 사용하여 두 포매팅 스타일을 모두 지원할 것입니다.
거부됨: getopt 호환 메서드
이전에 이 PEP가 optparse뿐만 아니라 getopt의 폐지도 제안하던 시기에, 다음과 같은 메서드를 추가하자는 이야기가 있었습니다.:
ArgumentParser.add_getopt_arguments(options[, long_options])
그러나 이 메서드는 여러 이유로 추가되지 않습니다.
- getopt 모듈은 사용 중단되지 않으므로 그 필요성이 적습니다.
- 위 API는 인자에 도움말 메시지를 추가할 방법을 제공하지 않으므로, 이미 사용법 메시지를 유지 관리하던 getopt 사용자에게는 이 메서드가 실제로 전환을 쉽게 해 주지 못합니다.
- getopt 사용자 중 일부는 함수 호출이 단 한 번만 필요하다는 점을 매우 중요하게 여깁니다. 위 API는
ArgumentParser()와parse_args()도 모두 호출해야 하므로 이 요구 사항을 충족하지 못합니다.
범위 밖: 여러 기능 요청
이 PEP에 대한 논의에서 argparse에 대한 여러 기능 요청이 있었습니다.
- 환경 변수에서 인자 기본값을 가져오는 기능 지원
- 설정 파일에서 인자 기본값을 가져오는 기능 지원
- 현재 지원되는 “foo subcommand –help”에 더해 “foo –help subcommand” 지원
이들은 모두 argparse 모듈에 대한 합리적인 기능 요청이지만, 이 PEP의 범위를 벗어나므로 argparse 이슈 트래커로 넘겨졌습니다.
논의: sys.stderr와 sys.exit
잘못된 인자가 주어지면 argparse가 기본적으로 항상 sys.stderr에 출력하고 항상 sys.exit를 호출한다는 점에 대해 몇 가지 우려가 있었습니다. 이는 간단한 명령줄 인터페이스를 중심으로 하는 대다수 argparse 사용 사례에서 바람직한 동작입니다. 그러나 경우에 따라서는 argparse가 종료되지 않도록 하거나, 메시지를 sys.stderr 이외의 대상에 출력하도록 하는 것이 바람직할 수 있습니다. 이러한 사용 사례는 ArgumentParser를 서브클래싱하고 exit 또는 _print_message 메서드를 재정의하여 지원할 수 있습니다. 후자는 문서화되지 않은 구현 세부 사항이지만, 흔히 필요한 것으로 드러나면 공식적으로 공개될 수 있습니다.
참고 문헌
Copyright
This document has been placed in the public domain.