2015-07-09 7 views
5

साथ (या रेगुलर एक्सप्रेशन का उपयोग) जब अजगर में argparse मॉड्यूल का उपयोग कर रहा जाल अमान्य विकल्प के लिए एक रास्ता खोज रहा है और उन्हें बेहतर रिपोर्ट करते हैं।रिपोर्ट अमान्य विकल्प पहले अजगर argparse मॉड्यूल

parser = argparse.ArgumentParser(prog='PROG' 
parser.add_argument('--foo', type=int) 
parser.add_argument('bar', nargs='?') 

# invalid option 
parser.parse_args(['--bar']) 
usage: PROG [-h] [--foo FOO] [bar] 
PROG: error: no such option: --bar 

हालांकि यह काफी इस ट्रिप हो जाने के रूप में बुरा विकल्प पहली रिपोर्ट नहीं किए जाते आसान है: https://docs.python.org/3/library/argparse.html#invalid-arguments पर दस्तावेज़ एक उदाहरण देता है। उदाहरण के लिए:

import argparse 
import datetime 

def convertIsoTime(timestamp): 
    """read ISO-8601 time-stamp using the AMS conventional format YYYY-MM-DDThh:mm:ssUTC""" 
    try: 
     return datetime.datetime.strptime(timestamp,"%Y-%m-%dT%H:%M:%SUTC") 
    except: 
     raise argparse.ArgumentTypeError("'{}' is not a valid ISO-8601 time-stamp".format(timestamp)) 

parser = argparse.ArgumentParser() 
parser.add_argument('startTime', type=convertIsoTime) 
parser.add_argument('--good', type=int, 
        help='foo') 

args = parser.parse_args(['--gold','5','2015-01-01T00:00:00UTC']) 

रिपोर्ट करेंगे:

error: argument startTime: '5' is not a valid ISO-8601 time-stamp 

जब मैं और अधिक उपयोगी रिपोर्ट करने के लिए यह पसंद करेंगे:

error: no such option: --gold 

यह इस लक्ष्य को हासिल करना संभव है? मुझे लगता है कि यह एक बहुत ही बुनियादी उपयोग मामला है। तर्क पार्सर्स को सीधे लिखते समय मैं आम तौर पर एक पैटर्न का उपयोग करता हूं, जैसे कि एक विकल्प विकल्प उपसर्ग जो किसी ज्ञात विकल्प नहीं है, तुरंत अस्वीकार कर दिया जाता है। बैश

# Process command-line arguments 
while [ $# -gt 0 ]; do 
    case "$1" in 
    --debug) 
     DEBUGOPTION="--debug" 
     shift 
     break;; 
    --) 
     shift 
     break;; 
    --*) 
     handleUsageError "$1" 
     shift;; 
    *) 
     break;; 
    esac 
done 

में उदाहरण के लिए मैं argparse नियमित अभिव्यक्ति आंतरिक रूप से उपयोग करता है लेकिन मुझे नहीं लगता कि वे add_argument के माध्यम से सुलभ हैं विश्वास करते हैं()

वहाँ argparse के साथ आसानी से बराबर करने के लिए कोई रास्ता नहीं है?

उत्तर

1

संक्षिप्त उत्तर यह है कि parse_argsparse_known_args का उपयोग करता है। यह विधि आपको --gold जैसे अज्ञात तर्कों को संभालने देती है। नतीजतन, unknown arguments त्रुटियों से पहले तर्क प्रकार त्रुटियां उठाई जाती हैं।

मैं एक समाधान है कि उपवर्गीकरण ArgumentParser और एक विधि अपने बुला ढेर में गहरी बदलाव करना शामिल है जोड़ दिया है।


मैं parse_args की रूपरेखा तैयार करने के रूप में अपने उदाहरण के लिए लागू की कोशिश करेंगे।

पहली चीज यह स्ट्रिंग को O या A के रूप में वर्गीकृत करती है। बस रखें, - से शुरू होने वाले O, अन्य A हैं। यह परिभाषित तर्क के साथ O लोगों से मेल खाता है।

आपके उदाहरण में, यह OAA पाता है। रेगेक्स का प्रयोग nargs तर्क द्वारा परिभाषित पैटर्न के खिलाफ इस स्ट्रिंग से मेल खाने के लिए किया जाता है। (यदि आवश्यक हो मैं और अधिक विस्तार में इस कदम की व्याख्या कर सकते)

--gold से मेल नहीं खाता; किसी बिंदु पर (चाहे इस प्रारंभिक पाश या बाद में) यह extras सूची में डाल दिया जाता है। (मैं विवरण के लिए कोड की जांच करूंगा)।

तार के माध्यम से 2 पाश के लिए यह बारी-बारी से postionals और optionals को संभालने के लिए कोशिश करता है।

5 से starttime के साथ मिलान करने का प्रयास करते समय यह है कि आपकी एक्शन क्लास टाइप त्रुटि को बढ़ाती है, जो उपयोग को प्रिंट करने और बाहर निकलने के लिए प्रचारित करती है। क्योंकि --gold परिभाषित नहीं है, 5 एक वैकल्पिक के तर्क के रूप में उपयोग नहीं कर रहा है।इस प्रकार यह पहली स्थितित्मक स्ट्रिंग के रूप में पार्स किया जाता है। (कुछ प्रकार के विकल्प 0 तर्क लेते हैं, इसलिए --... के बाद यह कुछ भी नहीं मानता है)।

मुझे लगता है, कि 5 बिना, अंतिम स्ट्रिंग से मेल खाएगा। parse_known_argsextras अवधि में --gold साथ लौट आते हैं। parse_argsparse_known_args का उपयोग करता है लेकिन एक त्रुटि को जन्म देती है जब extras खाली नहीं है।

तो एक अर्थ में पार्सर दोनों त्रुटियों का पता करता है, लेकिन यह starttime एक है कि त्रुटि संदेश से चलाता है। यह अपरिचित --gold के बारे में शिकायत करने के अंत तक प्रतीक्षा करता है।

एक सामान्य दर्शन के रूप में, argparse का पता लगाने और सभी त्रुटियों को पेश करने के लिए कोशिश नहीं करता। यह एक अंतिम व्यापक संदेश में मौजूद त्रुटियों की एक सूची एकत्र नहीं करता है।

मैं विवरण की जाँच करने के लिए कोड की समीक्षा करेंगे। मुझे नहीं लगता कि आप आसानी से बुनियादी पार्सिंग पैटर्न बदल सकते हैं। अगर मैं एक तरह से एक पहले unrecognized option त्रुटि के लिए मजबूर करने के बारे में सोच है, मैं इस उत्तर संपादित करेंगे।


def _parse_optional(self, arg_string): एक argv स्ट्रिंग वर्गीकृत करने के लिए कोशिश करता है। यदि स्ट्रिंग positional की तरह दिखती है तो यह None लौटाती है। यह एक एक्शन option_string से मेल खाता है, यह एक टपल '(कार्रवाई, option_string, कोई नहीं) `मिलान कार्रवाई के साथ देता है। अंत में अगर मेल नहीं है, यह रिटर्न:

# it was meant to be an optional but there is no such option 
    # in this parser (though it might be a valid option in a subparser) 
    return None, arg_string, None 

मुझे लगता है कि क्या अपने --gold साथ होता है। कारण है कि यह अभी भी एक मान्य विकल्प हो सकता है ध्यान दें।

इस समारोह से

def _parse_known_args(self, arg_strings, namespace): 
    ... 
    for i, arg_string in enumerate(arg_strings_iter): 
     .... 
     option_tuple = self._parse_optional(arg_string) 
     if option_tuple is None: 
     pattern = 'A' 
     else: 
     option_string_indices[i] = option_tuple 
     pattern = 'O' 
     arg_string_pattern_parts.append(pattern) 
    ... 
    # at the end 
    # return the updated namespace and the extra arguments 
    return namespace, extras 

कहा जाता है का संग्रह है कि 'AOO' पैटर्न, साथ ही इन tuples की एक सूची।

एक 2 पाश यह लेने वाली positionals और optionals के बीच alternates के दौरान

। समारोह है कि एक वैकल्पिक खपत है:

def consume_optional(start_index): 
    option_tuple = option_string_indices[start_index] 
    action, option_string, explicit_arg = option_tuple 
    if action is None: 
     extras.append(arg_strings[start_index]) 
    ...otherwise... 
     take_action(action, args, option_string) 

जैसा कि मैंने पहले लिखा था, अपने --goldextras सूची में रखा जाता है, जबकि 5 तर्क positionals के रूप में पार्स किया जा सकता की सूची पर बनी हुई है।

namespace और extras आप के लिए parse_known_args, उपयोगकर्ता, या parse_args के माध्यम से पारित कर दिया गया है।

निश्चित रूप से आप ArgumentParser उपclass कर सकते हैं और एक संशोधित _parse_optional विधि परिभाषित कर सकते हैं। यह बजाय कि (None, arg_string, None) टपल लौटने का एक त्रुटि बढ़ा सकता है।

import argparse 
import datetime 

class MyParser(argparse.ArgumentParser): 
    def _parse_optional(self, arg_string): 
     arg_tuple = super(MyParser, self)._parse_optional(arg_string) 
     if arg_tuple is None: 
      return arg_tuple # positional 
     else: 
      if arg_tuple[0] is not None: 
       return arg_tuple # valid optional 
      else: 
       msg = 'error: no such option: %s'%arg_string 
       self.error(msg) 

def convertIsoTime(timestamp): 
    """read ISO-8601 time-stamp using the AMS conventional format YYYY-MM-DDThh:mm:ssUTC""" 
    try: 
     return datetime.datetime.strptime(timestamp,"%Y-%m-%dT%H:%M:%SUTC") 
    except: 
     raise argparse.ArgumentTypeError("'{}' is not a valid ISO-8601 time-stamp".format(timestamp)) 

# parser = argparse.ArgumentParser() 
parser = MyParser() 
parser.add_argument('startTime', type=convertIsoTime) 
parser.add_argument('--good', type=int, 
        help='foo') 

args = parser.parse_args(['--good','5','2015-01-01T00:00:00UTC']) 
print(args) 

args = parser.parse_args(['--gold','5','2015-01-01T00:00:00UTC']) 

1505:~/mypy$ python3 stack31317166.py 
Namespace(good=5, startTime=datetime.datetime(2015, 1, 1, 0, 0)) 
usage: stack31317166.py [-h] [--good GOOD] startTime 
stack31317166.py: error: error: no such option: --gold 

उपवर्गीकरण प्रदान करने के लिए कस्टम क्रिया अच्छा argparse (और अजगर) अभ्यास है पैदा करता है।

यदि आप पाइथन डेवलपर्स द्वारा इस मामले पर अधिक विचार करना चाहते हैं, तो bug/issue लिखने पर विचार करें (पीईपी में अधिक विकसित औपचारिक विचारों के लिए है)। लेकिन argparse कीड़े/पैच का काफी बैकलॉग है, और पीछे की संगतता के बारे में बहुत सावधानी बरतनी है।


http://bugs.python.org/issue?%40columns=id%2Cactivity%2Ctitle%2Ccreator%2Cassignee%2Cstatus%2Ctype&%40sort=-activity&%40filter=status&%40action=searchid&ignore=file%3Acontent&%40search_text=_parse_optional&submit=search&status=-1%2C1%2C2%2C3

बग/मुद्दों है कि संदर्भ _parse_optional की एक सूची है। संभावित परिवर्तनों में शामिल हैं कि संदिग्ध विकल्प कैसे प्रबंधित किए जाते हैं। (मैं उन्हें यह देखने के लिए स्कैन करूंगा कि मैं कुछ भूल रहा हूं या नहीं। कुछ पैच मेरा हैं।) लेकिन super का उपयोग करके, मेरा सुझाया गया परिवर्तन फ़ंक्शन के भीतर परिवर्तनों से प्रभावित नहीं होता है। यह केवल तभी प्रभावित होता है जब फ़ंक्शन को कॉल किया जाता है और यह क्या लौटाता है, जो होने की संभावना कम होती है। अपनी खुद की समस्या दर्ज करके, आप कम से कम डेवलपर्स को ध्यान दें कि कोई इस इंटरफ़ेस पर निर्भर करता है।

+0

विस्तृत और उपयोगी स्पष्टीकरण के लिए धन्यवाद। मेरी एकमात्र चिंता यह होगी कि अगर Argparse अद्यतन किया जाता है तो यह तोड़ सकता है। मैं Argparse बैकलॉग के लिए एक अनुरोध जोड़ देंगे। –

+0

मैंने मौजूदा मुद्दों पर एक नोट जोड़ा। – hpaulj

संबंधित मुद्दे