Argparse : 'x'가있는 경우 필수 인수 'y'


118

다음과 같은 요구 사항이 있습니다.

./xyifier --prox --lport lport --rport rport

prox 인수의 경우 action = 'store_true'를 사용하여 존재 여부를 확인합니다. 나는 어떤 주장도 요구하지 않습니다. 그러나 --prox가 설정되면 rport 와 lport도 필요 합니다. 사용자 지정 조건부 코딩을 작성하지 않고 argparse를 사용하여 쉽게 수행 할 수있는 방법이 있습니까?

더 많은 코드 :

non_int.add_argument('--prox', action='store_true', help='Flag to turn on proxy')
non_int.add_argument('--lport', type=int, help='Listen Port.')
non_int.add_argument('--rport', type=int, help='Proxy port.')

플러그를 꽂았지만 내 라이브러리 joffrey 를 언급하고 싶었습니다 . 예를 들어 모든 것을 직접 검증하거나 (허용 된 답변에서와 같이) 허점 해킹 (두 번째로 높은 투표를받은 답변에서와 같이)에 의존하지 않고이 질문이 원하는 것을 수행 할 수 있습니다.
MI Wright

여기에 도착하는 모든 사람을위한 또 다른 놀라운 솔루션 : stackoverflow.com/a/44210638/6045800
Tomerikoo

답변:


120

아니요, argparse에는 상호 포괄적 인 옵션 집합 을 만드는 옵션이 없습니다 .

이를 처리하는 가장 간단한 방법은 다음과 같습니다.

if args.prox and (args.lport is None or args.rport is None):
    parser.error("--prox requires --lport and --rport.")

2
내가하고 결국 무엇 그게
asudhak을

20
parser.error방법 감사합니다 , 이것이 제가 찾고 있던 것입니다!
MarSoft 2015

7
'or'를 사용하면 안 되나요? 결국 당신은 두 인수가 필요 if args.prox and (args.lport is None or args.rport is None):
yossiz74

1
대신 args.lport is None, 당신은 간단하게 사용할 수 있습니다 not args.lport. 좀 더 비단뱀 적이라고 생각합니다.
CGFoX

7
그러면 프로그램에 대한 유효한 입력일 수있는 --lport또는 --rport로 설정하는 것이 중지 0됩니다.
borntyping

53

조건부로 필요한 인수에 대해 이야기하고 있습니다. @borntyping이 오류를 확인하고 할 수 있다고 말했듯이 새 인수를 추가 parser.error()--prox때 와 관련된 요구 사항을 적용 할 수도 있습니다 .

예제에 대한 간단한 해결책은 다음과 같습니다.

non_int.add_argument('--prox', action='store_true', help='Flag to turn on proxy')
non_int.add_argument('--lport', required='--prox' in sys.argv, type=int)
non_int.add_argument('--rport', required='--prox' in sys.argv, type=int)

이 방법 은 사용자가 사용되었는지 여부에 따라 또는 required수신합니다 . 이것은 또한 보장 과 서로 간의 독립적 인 행동을 가지고있다.TrueFalse--prox-lport-rport


8
참고 ArgumentParser이외의 목록에서 인수를 구문 분석하는 데 사용할 수있는 sys.argv이 실패 할 경우,.
BallpointBen

또한 --prox=<value>구문이 사용 되면 실패합니다 .
fnkr

11

parser.parse_known_args()메서드 를 사용 하고있는 경우 필수 인수로 --lport--rport인수 를 추가하는 것은 어떻습니까 --prox?

# just add --prox arg now
non_int = argparse.ArgumentParser(description="stackoverflow question", 
                                  usage="%(prog)s [-h] [--prox --lport port --rport port]")
non_int.add_argument('--prox', action='store_true', 
                     help='Flag to turn on proxy, requires additional args lport and rport')
opts, rem_args = non_int.parse_known_args()
if opts.prox:
    non_int.add_argument('--lport', required=True, type=int, help='Listen Port.')
    non_int.add_argument('--rport', required=True, type=int, help='Proxy port.')
    # use options and namespace from first parsing
    non_int.parse_args(rem_args, namespace = opts)

또한 네임 스페이스를 제공 할 수 있습니다. opts 두 번째로 나머지 인수를 구문 분석하는 동안 첫 번째 구문 분석 후 생성 된 . 이렇게하면 결국 모든 파싱이 완료된 후 모든 옵션이 포함 된 단일 네임 스페이스를 갖게됩니다.

단점 :

  • --prox이없는 경우 다른 두 종속 옵션이 네임 스페이스에 없습니다. 사용 사례를 기반으로하지만 --prox존재하지 않는 경우 다른 옵션에 어떤 일이 발생하는지는 관련이 없습니다.
  • 파서가 전체 구조를 모르기 때문에 사용 메시지를 수정해야합니다.
  • --lport--rport도움말 메시지에 표시되지 않습니다

5

설정되지 않은 lport경우 사용하세요 prox. 그렇지 않다면, 왜하지 lportrport의 인수 prox? 예 :

parser.add_argument('--prox', nargs=2, type=int, help='Prox: listen and proxy ports')

그러면 사용자가 입력하는 시간이 절약됩니다. 테스트 if args.prox is not None:if args.prox:.


1
예제의 완성도를 위해 nargs가 1보다 크면 구문 분석 된 인수 등의 목록이 표시되며 일반적인 방식으로 처리 할 수 ​​있습니다. 예, a,b = args.prox, a = args.prox[0], 등
Dannid

1

받아 들여진 대답은 나를 위해 잘 작동했습니다! 모든 코드가 테스트없이 깨 졌기 때문에 여기에서 내가 받아 들인 대답을 테스트 한 방법입니다. 오류를 발생 parser.error()시키지 않고 argparse.ArgumentError대신 프로세스를 종료합니다. 당신은 테스트해야SystemExit 합니다.

pytest와 함께

import pytest
from . import parse_arguments  # code that rasises parse.error()


def test_args_parsed_raises_error():
    with pytest.raises(SystemExit):
        parse_arguments(["argument that raises error"])

unittests로

from unittest import TestCase
from . import parse_arguments  # code that rasises parse.error()

class TestArgs(TestCase):

    def test_args_parsed_raises_error():
        with self.assertRaises(SystemExit) as cm:
            parse_arguments(["argument that raises error"])

영감을받은 : unittest를 사용하여 argparse 테스트-종료 오류

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.