복붙노트

[PYTHON] Python Argparse 조건부 필수 인수

PYTHON

Python Argparse 조건부 필수 인수

가능한 많은 연구를 해왔지만 특정 조건에서만 필요한 cmdline 인수를 만드는 가장 좋은 방법을 찾지 못했습니다.이 경우에는 다른 인수가 주어진 경우에만 가능합니다. 다음은 내가 아주 기본적인 수준에서하고 싶은 일입니다.

p = argparse.ArgumentParser(description='...')
p.add_argument('--argument', required=False)
p.add_argument('-a', required=False) # only required if --argument is given
p.add_argument('-b', required=False) # only required if --argument is given

내가 본 것에서 다른 사람들은 결국 자신의 수 표를 추가하는 것처럼 보입니다.

if args.argument and (args.a is None or args.b is None):
    # raise argparse error here

argparse 패키지 내에서이 작업을 네이티브 방식으로 수행 할 수 있습니까?

해결법

  1. ==============================

    1.나는이 질문에 대한 간단한 대답을 얼마 동안 찾고 있었다. '--argument'가 sys.argv에 있는지 확인하기 만하면되므로 기본적으로 수행 할 수있는 코드 샘플에 대해 기본적으로 다음을 수행하십시오.

    나는이 질문에 대한 간단한 대답을 얼마 동안 찾고 있었다. '--argument'가 sys.argv에 있는지 확인하기 만하면되므로 기본적으로 수행 할 수있는 코드 샘플에 대해 기본적으로 다음을 수행하십시오.

    import argparse
    import sys
    
    if __name__ == '__main__':
        p = argparse.ArgumentParser(description='...')
        p.add_argument('--argument', required=False)
        p.add_argument('-a', required='--argument' in sys.argv) #only required if --argument is given
        p.add_argument('-b', required='--argument' in sys.argv) #only required if --argument is given
        args = p.parse_args()
    

    이 방법은 사용자가 사용했는지 여부에 따라 True 또는 False를받습니다. 이미 테스트 한 결과 작동하는 것으로 보입니다. -a와 -b가 서로간에 독립적 인 동작을한다는 것을 보장합니다.

  2. ==============================

    2.--argument에 대한 사용자 정의 작업을 제공하여 점검을 구현할 수 있습니다. 추가 인수를 사용하여 --argument가 사용될 경우 필요한 다른 조치를 지정합니다.

    --argument에 대한 사용자 정의 작업을 제공하여 점검을 구현할 수 있습니다. 추가 인수를 사용하여 --argument가 사용될 경우 필요한 다른 조치를 지정합니다.

    import argparse
    
    class CondAction(argparse.Action):
        def __init__(self, option_strings, dest, nargs=None, **kwargs):
            x = kwargs.pop('to_be_required', [])
            super(CondAction, self).__init__(option_strings, dest, **kwargs)
            self.make_required = x
    
        def __call__(self, parser, namespace, values, option_string=None):
            for x in self.make_required:
                x.required = True
            try:
                return super(CondAction, self).__call__(parser, namespace, values, option_string)
            except NotImplementedError:
                pass
    
    p = argparse.ArgumentParser()
    x = p.add_argument("--a")
    p.add_argument("--argument", action=CondAction, to_be_required=[x])
    

    CondAction의 정확한 정의는 정확히 무엇을해야하는지에 달려 있습니다. 그러나 예를 들어, --argument가 일반적인 인수, 인수 및 저장 작업 유형 인 경우 argparse._StoreAction에서 상속받은 것만으로 충분해야합니다.

    예제 파서에서는 --argument 옵션에 --a 옵션에 대한 참조를 저장하고 명령 행에 --argument가 표시되면 --a에 필수 플래그를 True로 설정합니다. 모든 옵션이 처리되면 argparse는 required로 표시된 옵션이 설정되었는지 확인합니다.

  3. ==============================

    3.게시물 파싱 테스트는 괜찮습니다. 특히 기본값으로 테스트하면 필요에 맞지 않음이 선택됩니다.

    게시물 파싱 테스트는 괜찮습니다. 특히 기본값으로 테스트하면 필요에 맞지 않음이 선택됩니다.

    http://bugs.python.org/issue11588 '필수적으로 포함하는'그룹을 'argparse에 추가'하면 그룹 메커니즘 (mutuall_exclusive_groups의 일반화)을 사용하여 이와 같은 테스트를 구현합니다.

    xor (상호 배타적), and, and, and 같은 테스트를 구현하는 UsageGroups 세트를 작성했습니다. 나는 그것들이 포괄적 인 곳에서 생각했지만, 나는 그러한 작업들에 관하여 당신의 주장을 표현할 수 없었습니다. (내가 낸드를 필요로하는 것처럼 보입니다 - 아니라고, 아래를보십시오)

    이 스크립트는 사용자 정의 테스트 클래스를 사용합니다.이 클래스는 본질적으로 사후 파싱 테스트를 구현합니다. seen_actions는 구문 분석이 본 Action 목록입니다.

    class Test(argparse.UsageGroup):
        def _add_test(self):
            self.usage = '(if --argument then -a and -b are required)'
            def testfn(parser, seen_actions, *vargs, **kwargs):
                "custom error"
                actions = self._group_actions
                if actions[0] in seen_actions:
                    if actions[1] not in seen_actions or actions[2] not in seen_actions:
                        msg = '%s - 2nd and 3rd required with 1st'
                        self.raise_error(parser, msg)
                return True
            self.testfn = testfn
            self.dest = 'Test'
    p = argparse.ArgumentParser(formatter_class=argparse.UsageGroupHelpFormatter)
    g1 = p.add_usage_group(kind=Test)
    g1.add_argument('--argument')
    g1.add_argument('-a')
    g1.add_argument('-b')
    print(p.parse_args())
    

    샘플 출력은 다음과 같습니다.

    1646:~/mypy/argdev/usage_groups$ python3 issue25626109.py --arg=1 -a1
    usage: issue25626109.py [-h] [--argument ARGUMENT] [-a A] [-b B]
                            (if --argument then -a and -b are required)
    issue25626109.py: error: group Test: argument, a, b - 2nd and 3rd required with 1st
    

    사용 및 오류 메시지는 여전히 작업이 필요합니다. 그리고 파싱 후 테스트가 할 수없는 일은하지 않습니다.

    테스트에서 (인수 & (! a 또는! b)) 오류가 발생합니다. 반대로 허용되는 것은! (인수 & (! a 또는! b)) =! (인수 &! (a와 b))입니다. 내 UsageGroup 클래스에 nand 테스트를 추가하면 다음과 같이 사례를 구현할 수 있습니다.

    p = argparse.ArgumentParser(formatter_class=argparse.UsageGroupHelpFormatter)
    g1 = p.add_usage_group(kind='nand', dest='nand1')
    arg = g1.add_argument('--arg', metavar='C')
    g11 = g1.add_usage_group(kind='nand', dest='nand2')
    g11.add_argument('-a')
    g11.add_argument('-b')
    

    사용법은! ()를 사용하여 'nand'테스트를 표시합니다.

    usage: issue25626109.py [-h] !(--arg C & !(-a A & -b B))
    

    이것은 범용 사용 그룹을 사용하여이 문제를 표현하는 가장 짧고 명확한 방법이라고 생각합니다.

    내 테스트에서 성공적으로 구문 분석 한 입력은 다음과 같습니다.

    ''
    '-a1'
    '-a1 -b2'
    '--arg=3 -a1 -b2'
    

    오류를 발생시키는 것은 다음과 같습니다.

    '--arg=3'
    '--arg=3 -a1'
    '--arg=3 -b2'
    
  4. ==============================

    4.http://bugs.python.org/issue11588이 해결 될 때까지는 nargs 만 사용합니다.

    http://bugs.python.org/issue11588이 해결 될 때까지는 nargs 만 사용합니다.

    p = argparse.ArgumentParser(description='...')
    p.add_argument('--arguments', required=False, nargs=2, metavar=('A', 'B'))
    

    이 방법으로, 누군가가 - 인수를 제공하면, 그것은 2 개의 값을 가질 것이다.

    어쩌면 자사의 CLI 결과가 덜 읽을 수 있지만 코드는 훨씬 작습니다. 좋은 문서 / 도움으로 해결할 수 있습니다.

  5. ==============================

    5.인수를 위해 나는 이렇게 빠른 n 더러운 해결책을 생각해 냈다. 가정 : (1) '--help'는 도움을 표시하고 필수 인수에 대해 불평하지 않아야하며 (2) sys.argv를 구문 분석해야합니다.

    인수를 위해 나는 이렇게 빠른 n 더러운 해결책을 생각해 냈다. 가정 : (1) '--help'는 도움을 표시하고 필수 인수에 대해 불평하지 않아야하며 (2) sys.argv를 구문 분석해야합니다.

    p = argparse.ArgumentParser(...)
    p.add_argument('-required', ..., required = '--help' not in sys.argv )
    

    이것은 특정 설정과 일치하도록 쉽게 수정할 수 있습니다. 필요한 위치 지정 (명령 행에 '--help'가 주어지면 필요하지 않음)에 대해서는 다음과 같이 작성했습니다 : [위치 지정은 필수 = ... 키워드 인수를 허용하지 않습니다!]

    p.add_argument('pattern', ..., narg = '+' if '--help' not in sys.argv else '*' )
    

    기본적으로 이것은 '--help'가 지정된 경우 명령 줄에서 'pattern'이 필요한 항목의 수를 하나 이상으로 0 또는 그 이상으로 바꿉니다.

  6. from https://stackoverflow.com/questions/25626109/python-argparse-conditionally-required-arguments by cc-by-sa and MIT license