2017-01-02 2 views
1

현재 argparse을 테스트 중이지만 예상대로 작동하지 않습니다. (옵션)이 지난 경우 예상대로모든 인수를 포함하는 선택적 인수

python3 myprogram.py positional argument --optional something 

# Outcome 
Namespace(optional='something') 

이 프로그램은 작동하지만, 다른 순서에있는 경우, 그것은을 폐기 이다 : 나는 subparsers 및 선택적 인수의 부부, 다음과 같은 방법을 호출되고 있습니다. argparse 문서를보고

python3 myprogram.py positional --optional argument 
python3 myprogram.py --optional positional argument 

# Outcome 
Namespace(optional=None) 

나는 선택적 인수 글로벌을 만들 수있는 방법을 찾을 수 없습니다.

for 루프에서 각 위치에 대한 위치 지정 인수를 생성하고 있는데, 이는 가장 좋은 방법은 아닙니다. 그렇지 않기 때문에 선택적 인수 만 마지막 서브 파서에 추가합니다.

import argparse 

class Parsing(object): 

    def __init__(self): 

     parser = argparse.ArgumentParser(prog='python3 myprogram.py', 
      formatter_class=argparse.RawDescriptionHelpFormatter, 
      description='some description') 

     self.subparser = parser.add_subparsers(title='Positional', help='help description') 

     for sub in self.Generate(): # Method with a bunch of subparsers 
      self.Subparser(sub) 

    def Subparser(self, parsers): 

     for each in sorted(parsers): 
      positional = subparser.add_parser(each) 
      self.Optional(positional) # Method with some optional arguments for each of the second subparsers 

     self.Optional(parser) # Adding the optional arguments to the first subparser 

    def Optional(self, parser): 

     # ... Optional arguments 

    def Generate(self): 

     # ... Subparsers 

위의 예에서 일부 코드가 누락되었을 수 있으므로 가능한 한 단순화하고 인식하기를 바랍니다.

질문 : 모든 하위 구성 요소에서 선택적 인수를 만들 수있는 방법이 있습니까?

답변

2

설명과 코드는 따르기가 어렵지만 주 및 하위 해석자가 dest을 공유 할 때 기본값을 처리하는 방법에 문제가 있다고 결론을 냈습니다. , foo는 구문 분석 문자열로 설정되어 나는이 개 실행

처음에
1315:~/mypy$ python3.5 stack41431025.py cmd1 --foo 1 
Namespace(cmd='cmd1', foo='1') 

1316:~/mypy$ python3.5 stack41431025.py --foo 1 cmd1 
Namespace(cmd='cmd1', foo='sub') 

얻을

import argparse 
class Parsing(object): 
    def __init__(self): 
     self.parser = argparse.ArgumentParser(prog='prog', 
      description='some description') 
     self.subparser = self.parser.add_subparsers(dest='cmd', title='Cmds', help='help description') 
     self.make_subparsers(['cmd1','cmd2']) 

    def make_subparsers(self, parsers): 
     for each in parsers: 
      subp = self.subparser.add_parser(each) 
      self.optional(subp, default='sub') 
     self.optional(self.parser, default='main') 

    def optional(self, parser, default=None): 
     parser.add_argument('--foo', default=default) 

args = Parsing().parser.parse_args() 
print(args) 

:

나는 조금 내가 테스트 실행을 만들 수있는 코드를 응축 cmd1 subparser.

두 번째 경우 foo은 하위 파서가 설정 한 기본값을 가져옵니다. 주 파서는 --foo을 파싱했지만 그 값은 서브 파서가 작성한 것 이상이었습니다.

버그/문제에서 이에 대한 논의가있었습니다. http://bugs.python.org/issue9351은 처리를 변경하여 하위 파서 기본값이 주 파서 값보다 우선 순위가 높습니다. 나는 그 패치에 문제가 있다고 생각하지만, 2 년 동안 유효했다.

다른 컨트롤이있는 경우 dest을 지정합니다.

def make_subparsers(self, parsers): 
    for each in parsers: 
     subp = self.subparser.add_parser(each) 
     self.optional(subp, default='sub') 
    self.optional(self.parser, default='main', dest='main_foo') 

def optional(self, parser, default=None, dest=None): 
    parser.add_argument('--foo', default=default, dest=dest) 

1325:~/mypy$ python3.5 stack41431025.py --foo 1 cmd1 
Namespace(cmd='cmd1', foo='sub', main_foo='1') 
1325:~/mypy$ python3.5 stack41431025.py cmd1 
Namespace(cmd='cmd1', foo='sub', main_foo='main') 
1325:~/mypy$ python3.5 stack41431025.py --foo 1 cmd1 --foo 2 
Namespace(cmd='cmd1', foo='2', main_foo='1') 

====================

내가 인수의 가능한 조합을 스케치하려고합니다

(이전 대답)

python prog.py foo [--mainopt bar] cmd1 sfoo [--subopt baz] 
:

parser = argparse.ArgumentParser() 
parser.add_argument('mainpos', help='positional for main') 
parser.add_argument('--mainopt', help='optional defined for main') 
sp = parser.add_subparser(dest='cmd') 
p1 = sp.add_parser('cmd1') 
p1.add_argument('subpos', help='postional for sub') 
p1.add_argument('--subopt', help='optional defined for sub') 

복합 usage과 같을 것이다

해당 positionals은 올바른 순서로 지정해야합니다. 서브 파서 cmd은 실질적으로 main의 위치입니다.

main에 대해 정의 된 선택적 요소는 하위 구문 이름 앞에 있어야합니다. 서브 파서에 대해 정의 된 옵션은 이후에 발생해야합니다. flag 또는 dest을 가질 수 있지만 별도로 정의해야합니다. 그리고 그들이 동일한 dest을 가지고 있다면, 값들, 특히 디폴트들에 충돌이있을 수 있습니다.

parser.parse_args()은 인수를 입력 문자열과 일치시키기 시작합니다. 그것은 --mainopt이 선택적 인수를 구문 분석하는 것으로 보는 경우. 그렇지 않으면 그것은 2 개의 postionals을 기대합니다. 두 번째는 서브 파서 이름 중 하나 여야합니다.

하위 파서 이름을 가져 오면 나머지 문자열을 해당 하위 파서에 전달합니다. 하위 파서는 나머지를 처리하고 주 네임 스페이스에 값을 저장합니다. 서브 파서가하는 첫 번째 작업은 기본값으로 설정됩니다. 이 동작이 주 파서에 의해 설정된 값을 덮어 쓰는지 아닌지는 namespace이 둘 사이에서 어떻게 전달되는지에 달려 있습니다.

================

파싱 명령 행에서 인수의 순서에 의해 구동된다. 플래그가 지정된 인수를 임의의 순서로 허용합니다. 그러나 구문 분석이 하위 파서로 전달되면 주 파서는 구문 분석을 수행하지 않습니다. 단지 몇 가지 정리 작업을 수행합니다.

그러나 parse_known_args을 사용하면 구문 분석기가 처리하지 않은 문자열을 수집하고 구문 분석을 한 번 더 수행 할 수 있습니다.

parser1 = argparse.ArgumentParser() 
parser1.add_argument('--foo') 
sp = parser1.add_subparsers(dest='cmd') 
sp1 = sp.add_parser('cmd1') 
args, extra = parser1.parse_known_args() 

parser2 = argparse.ArgumentParser() 
parser2.add_argument('--foo') 
if extra: 
    args = parser2.parse_args(extra) 
print(args) 

실행

1815:~/mypy$ python stack41431025.py --foo 1 cmd1 
Namespace(cmd='cmd1', foo='1') 

1815:~/mypy$ python stack41431025.py cmd1 --foo 2 
Namespace(foo='2') 

1815:~/mypy$ python stack41431025.py --foo 1 cmd1 --foo 3 
Namespace(foo='3') 

는 좀 더 복잡한 아무것도에서이 아이디어를 테스트하지, 그래서 내가 생각하지 않은 몇 가지 상호 작용이있을 수 있습니다. 그러나 이것은 어디에서나 발생할 수있는 논쟁의 여지가있는 가장 가까운 곳이며, default 문제와 충돌하지 않아야합니다.

+0

고맙습니다. Hpaulj, 내 코드에 맞게 테스트 해 보겠습니다. – Flippym

+0

올바르게 이해했다면,'argparse'는 전역 인수를 지원하지 않습니다. 각각의 서브 파서에서'dest'로 제어해야합니다. ? – Flippym

+0

'parse_known_args'와 두 번째 파싱 실행을 사용하여 예제를 추가했습니다. – hpaulj