2017-11-09 7 views
2

우리는 사용중인 명령 줄 도구를 통해 래퍼 스크립트를 작성하려고합니다. 래퍼 스크립트의 옵션에 따라 도구 인수를 설정하고 싶습니다. 커맨드 라인 도구에 직접 인자를 전달할 수있는 가능성도 커지고 있습니다.대시로 시작하는 선택적 위치 인수가있는 'argparse'

import argparse 

parser = argparse.ArgumentParser() 

parser.add_argument('positional') 
parser.add_argument('-f', '--foo', action='store_true') 
parser.add_argument('-b', '--bar', action='store_true') 

parser.add_argument('native_arg', nargs='*') 

args = parser.parse_args() 
print (args) 

positional이 필수입니다 : 여기

우리가 해낸 것입니다. -f-b 옵션을 기반으로 툴킷에 몇 가지 추가 옵션이 추가됩니다. 나중에 남아있는 것 (있는 경우)은 원시 도구 인수로 취급되어 도구에 직접 제공되어야합니다. -h 우리의 스크립트를 호출하면 다음 사용을 생성합니다

usage: test.py [-h] [-f] [-b] positional [native_arg [native_arg ...]] 

비결은 예를 -native0-native1를 들어, 이러한 기본 인수는 도구에 대한 옵션을 스스로하고 선도적 인 대시를 포함한다는 것이다. 우리는 이미 더블 대쉬로 트릭을 알고 더 많은 옵션을 찾기 위해 argparse을 찾지 못했습니다. 다음 전화 :

./test.py pos -- -native0 -native1 

은 예상 분석 인수를 생성합니다

Namespace(bar=False, foo=False, native_arg=['-native0', '-native1'], positional='pos') 

는하지만, 작동하지 않는 첫 번째 위치 인수 후 옵션을 추가하려고합니다. 보다 구체적으로, 다음 호출 : 인쇄되어 다음과 같이

./test.py --foo pos -- -native0 -native1 

가 작동하는 것 같다 다음 positionals 전에 선택적 인수를 두는

usage: [...shortened...] 
test.py: error: unrecognized arguments: -- -native0 -native1 

:

./test.py pos --foo -- -native0 -native1 

는 다음과 같은 출력을 생성 :

Namespace(bar=False, foo=True, native_arg=['-native0', '-native1'], positional='pos') 

native_arg에서 '+'에 대한 nargs의 값을 변경하는 것은 낯선 사람이라도 위의 모든 상황에서 작동합니다 (물론 적어도 하나는 native_arg입니다).

파이썬 코드에서 뭔가 잘못되었거나 이런 종류의 코드가 입니다. argparse 버그?

답변

3

argparse은 선택적 인수와 함께 불필요한 위치 인수를 혼합하는 데 어려움이 있습니다 (버그 보고서에 대한 자세한 내용은 https://stackoverflow.com/a/47208725/1399279 참조). 이 문제를 해결할 방법을 제안하는 대신, 대안적인 접근법을 제시 할 것입니다.

설명하는 상황에 맞게 작성된 parse_known_args 메소드를 확인해야합니다 (즉, 포장 된 도구에 옵션을 전달).

In [1]: import argparse 

In [2]: parser = argparse.ArgumentParser() 

In [3]: parser.add_argument('positional') 

In [4]: parser.add_argument('-f', '--foo', action='store_true') 

In [5]: parser.add_argument('-b', '--bar', action='store_true') 

In [6]: parser.parse_known_args(['pos', '--foo', '-native0', '-native1']) 
Out[6]: (Namespace(bar=False, foo=True, positional='pos'), ['-native0', '-native1']) 

parse_args는 달리 parse_known_args의 출력은 두 개의 원소 튜플이다.첫 번째 요소는 parse_args에서 가져올 것으로 예상되는 Namespace 인스턴스이며 add_argument에 대한 호출로 정의 된 모든 특성을 포함합니다. 두 번째 요소는 파서에 알려지지 않은 모든 인수 목록입니다.

저는 사용자가 프로그램 호출 방법이나 오류가 발생하지 않는 옵션 순서에 대해 기억할 필요가 없기 때문에 개인적으로이 방법을 선호합니다.

2

이 알려진 문제입니다 (https://bugs.python.org/issue15112, argparse : nargs의 = '*'위치 인수가 옵션 앞에 경우 어떤 항목과 다른 위치 허용하지 않습니다)

positionals 및 선택적 항목을 처리 구문 분석 번갈아. 위치 지정을 처리 할 때 입력 문자열만큼 많은 문자를 처리하려고합니다. 그러나 ? 또는 * 위치는 문자열의 빈 목록 []으로 만족합니다. 반면에 + 적어도 하나의 문자열

./test.py pos --foo -- -native0 -native1 

파서는 positional에 'POS'를 제공이 필요하며, native-arg[]. 그런 다음 선택적으로 '--foo'를 제공합니다. 더 이상 positionals이 남아있는 문자열을 처리하지 않으므로 오류가 발생합니다.

입력 문자열의 할당은 양식 일치 형식 regex 문자열 일치로 수행됩니다. AA?과 같은 패턴과 일치한다고 상상해보십시오.

이 문제를 해결하려면 파서가 앞을보고 지연 처리 native-arg을 처리해야합니다. 우리는 패치를 제안했지만 제작에 들지 않았습니다.

@ SethMMorton의 제안은 parse_known_args을 사용하는 것이 좋습니다.

이전 구문 분석기 (예 : Optparse)는 플래그가 지정된 모든 인수를 처리하지만 나머지는 위치를 알 수없는 목록으로 반환합니다. 해당 목록을 분할하는 것은 사용자가 결정합니다. argparsepositionals의 이름을 지정하고 구문을 분석 할 수있는 기능을 추가했으나 알고리즘은 고정 된 nargs으로 가장 잘 작동하고 너무 많은 변수 nargs로 인해 불규칙하게 나타납니다.

+0

'--' 전에 구문을 분석 한 다음 나머지를 하나의 큰 blob로 얻는 방법에 만족합니다. 'parse_known_args'는 스크립트 옵션처럼 보이는 것들이'native_args'에 빠져 나가게합니다. 나는 그것에 대해 조금 생각해 왔으며 2 개의 연결된 서브퍼의 조합으로 해결할 수 있습니다. 네이티브 args는 대부분 다른 스크립트에서도 사용되기 때문에 항상'--' 전에 위치가 끝나는 해결 방법을 사용하는 것이 좋다고 생각합니다. –

+0

이중 대시는 '-native0'과 같은 문자열을 해석하는 방법을 변경하지만 '위치 지정'에 할당하는 방법은 변경하지 않습니다. 'nargs = '...'','REMAINDER'도 있지만 같은 할당 문제가 있다고 생각합니다. 나중에 테스트 할 수 있습니다. – hpaulj

+0

나는 그것을 시도하고 그것은'위치'가 처음 본 후에 모든 것을 먹는다. 이것은'test.py position --foo - -native0'에서'--foo' 옵션이'native_args'에 집중된다는 것을 의미합니다. –