अर्गपर्स: आवश्यक तर्क 'y' यदि 'x' मौजूद है


118

मेरी आवश्यकता इस प्रकार है:

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

प्रोक्स के लिए, मैं यह जांचने के लिए कि क्या मौजूद है या नहीं, मैं एक्शन = '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.')

प्लगिंग, लेकिन मैं अपनी लाइब्रेरी जॉफ्री का उल्लेख करना चाहता था । ऐसा करें कि आप यह प्रश्न क्या चाहते हैं, उदाहरण के लिए, बिना आपको सब कुछ मान्य किए (जैसे कि स्वीकृत उत्तर में) या एक लूफै़डी हैक पर भरोसा करें (जैसा कि दूसरे सबसे ज्यादा वोट देने वाले जवाब में है)।
MI राइट

यहां पहुंचने वाले किसी भी अन्य व्यक्ति के लिए, एक और अद्भुत उपाय: stackoverflow.com/a/44210638/6045800
टोमेरिको

जवाबों:


120

नहीं, विकल्प के परस्पर समावेशी सेट बनाने के लिए कोई विकल्प नहीं है ।

इससे निपटने का सबसे सरल तरीका होगा:

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

2
Thats मैंने क्या किया
asudhak

20
parser.errorविधि के लिए धन्यवाद , यह वही है जो मैं देख रहा था!
मारसॉफ्ट

7
क्या आपको 'या' का उपयोग नहीं करना चाहिए? आखिरकार आपको दोनों if args.prox and (args.lport is None or args.rport is None):
आर्ग की

1
इसके बजाय args.lport is None, आप बस का उपयोग कर सकते हैं not args.lport। मुझे लगता है कि यह थोड़ा अधिक पायथोनिक है।
CGFoX

7
जो आपको सेटिंग करने --lportया --rportकरने से रोक देगा 0, जो प्रोग्राम के लिए एक वैध इनपुट हो सकता है।
जन्मे

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तो प्राप्त करता है Trueया Falseइस पर निर्भर करता है कि उपयोगकर्ता का उपयोग किया गया है --prox। यह भी गारंटी देता है कि -lportऔर -rportएक दूसरे के बीच एक स्वतंत्र व्यवहार है।


8
ध्यान दें कि ArgumentParserइसका उपयोग किसी अन्य सूची से तर्कों को पार्स करने के लिए किया जा सकता है sys.argv, जो इस मामले में विफल हो जाएगा।
बॉलपॉइंटबैन

--prox=<value>सिंटैक्स का उपयोग करने पर भी यह विफल हो जाएगा ।
fnkr

11

कैसे parser.parse_known_args()विधि का उपयोग करने के बारे में और फिर मौजूद है --lportऔर --rportयदि आवश्यक हो तो args जोड़ने के रूप में --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। यदि नहीं, तो क्यों नहीं बना lportऔर rportके तर्कों 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
उदाहरण की पूर्णता के लिए, जब आपका विवरण> 1 है, तो आपको पार्स किए गए तर्क आदि में एक सूची मिलेगी, जिसे आप सामान्य शिष्टाचार में संबोधित कर सकते हैं। उदाहरण के लिए, a,b = args.prox, a = args.prox[0], आदि
Dannid

1

स्वीकृत उत्तर ने मेरे लिए बहुत अच्छा काम किया! चूँकि यहाँ परीक्षण के बिना सभी कोड को तोड़ दिया जाता है, इसलिए मैंने स्वीकृत उत्तर का परीक्षण किया। इसके बजाय parser.error()एक argparse.ArgumentErrorत्रुटि नहीं उठाता है यह प्रक्रिया से बाहर निकलता है। आपको परीक्षण करना होगा SystemExit

पाइस्ट के साथ

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"])

से प्रेरित: परीक्षण त्रुटि से बाहर निकलने के लिए एकतम प्रयोग करना - त्रुटियों से बाहर निकलना

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.