xref: /aosp_15_r20/external/fmtlib/support/docopt.py (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
1*5c90c05cSAndroid Build Coastguard Worker"""Pythonic command-line interface parser that will make you smile.
2*5c90c05cSAndroid Build Coastguard Worker
3*5c90c05cSAndroid Build Coastguard Worker * http://docopt.org
4*5c90c05cSAndroid Build Coastguard Worker * Repository and issue-tracker: https://github.com/docopt/docopt
5*5c90c05cSAndroid Build Coastguard Worker * Licensed under terms of MIT license (see LICENSE-MIT)
6*5c90c05cSAndroid Build Coastguard Worker * Copyright (c) 2013 Vladimir Keleshev, [email protected]
7*5c90c05cSAndroid Build Coastguard Worker
8*5c90c05cSAndroid Build Coastguard Worker"""
9*5c90c05cSAndroid Build Coastguard Workerimport sys
10*5c90c05cSAndroid Build Coastguard Workerimport re
11*5c90c05cSAndroid Build Coastguard Worker
12*5c90c05cSAndroid Build Coastguard Worker
13*5c90c05cSAndroid Build Coastguard Worker__all__ = ['docopt']
14*5c90c05cSAndroid Build Coastguard Worker__version__ = '0.6.1'
15*5c90c05cSAndroid Build Coastguard Worker
16*5c90c05cSAndroid Build Coastguard Worker
17*5c90c05cSAndroid Build Coastguard Workerclass DocoptLanguageError(Exception):
18*5c90c05cSAndroid Build Coastguard Worker
19*5c90c05cSAndroid Build Coastguard Worker    """Error in construction of usage-message by developer."""
20*5c90c05cSAndroid Build Coastguard Worker
21*5c90c05cSAndroid Build Coastguard Worker
22*5c90c05cSAndroid Build Coastguard Workerclass DocoptExit(SystemExit):
23*5c90c05cSAndroid Build Coastguard Worker
24*5c90c05cSAndroid Build Coastguard Worker    """Exit in case user invoked program with incorrect arguments."""
25*5c90c05cSAndroid Build Coastguard Worker
26*5c90c05cSAndroid Build Coastguard Worker    usage = ''
27*5c90c05cSAndroid Build Coastguard Worker
28*5c90c05cSAndroid Build Coastguard Worker    def __init__(self, message=''):
29*5c90c05cSAndroid Build Coastguard Worker        SystemExit.__init__(self, (message + '\n' + self.usage).strip())
30*5c90c05cSAndroid Build Coastguard Worker
31*5c90c05cSAndroid Build Coastguard Worker
32*5c90c05cSAndroid Build Coastguard Workerclass Pattern(object):
33*5c90c05cSAndroid Build Coastguard Worker
34*5c90c05cSAndroid Build Coastguard Worker    def __eq__(self, other):
35*5c90c05cSAndroid Build Coastguard Worker        return repr(self) == repr(other)
36*5c90c05cSAndroid Build Coastguard Worker
37*5c90c05cSAndroid Build Coastguard Worker    def __hash__(self):
38*5c90c05cSAndroid Build Coastguard Worker        return hash(repr(self))
39*5c90c05cSAndroid Build Coastguard Worker
40*5c90c05cSAndroid Build Coastguard Worker    def fix(self):
41*5c90c05cSAndroid Build Coastguard Worker        self.fix_identities()
42*5c90c05cSAndroid Build Coastguard Worker        self.fix_repeating_arguments()
43*5c90c05cSAndroid Build Coastguard Worker        return self
44*5c90c05cSAndroid Build Coastguard Worker
45*5c90c05cSAndroid Build Coastguard Worker    def fix_identities(self, uniq=None):
46*5c90c05cSAndroid Build Coastguard Worker        """Make pattern-tree tips point to same object if they are equal."""
47*5c90c05cSAndroid Build Coastguard Worker        if not hasattr(self, 'children'):
48*5c90c05cSAndroid Build Coastguard Worker            return self
49*5c90c05cSAndroid Build Coastguard Worker        uniq = list(set(self.flat())) if uniq is None else uniq
50*5c90c05cSAndroid Build Coastguard Worker        for i, child in enumerate(self.children):
51*5c90c05cSAndroid Build Coastguard Worker            if not hasattr(child, 'children'):
52*5c90c05cSAndroid Build Coastguard Worker                assert child in uniq
53*5c90c05cSAndroid Build Coastguard Worker                self.children[i] = uniq[uniq.index(child)]
54*5c90c05cSAndroid Build Coastguard Worker            else:
55*5c90c05cSAndroid Build Coastguard Worker                child.fix_identities(uniq)
56*5c90c05cSAndroid Build Coastguard Worker
57*5c90c05cSAndroid Build Coastguard Worker    def fix_repeating_arguments(self):
58*5c90c05cSAndroid Build Coastguard Worker        """Fix elements that should accumulate/increment values."""
59*5c90c05cSAndroid Build Coastguard Worker        either = [list(child.children) for child in transform(self).children]
60*5c90c05cSAndroid Build Coastguard Worker        for case in either:
61*5c90c05cSAndroid Build Coastguard Worker            for e in [child for child in case if case.count(child) > 1]:
62*5c90c05cSAndroid Build Coastguard Worker                if type(e) is Argument or type(e) is Option and e.argcount:
63*5c90c05cSAndroid Build Coastguard Worker                    if e.value is None:
64*5c90c05cSAndroid Build Coastguard Worker                        e.value = []
65*5c90c05cSAndroid Build Coastguard Worker                    elif type(e.value) is not list:
66*5c90c05cSAndroid Build Coastguard Worker                        e.value = e.value.split()
67*5c90c05cSAndroid Build Coastguard Worker                if type(e) is Command or type(e) is Option and e.argcount == 0:
68*5c90c05cSAndroid Build Coastguard Worker                    e.value = 0
69*5c90c05cSAndroid Build Coastguard Worker        return self
70*5c90c05cSAndroid Build Coastguard Worker
71*5c90c05cSAndroid Build Coastguard Worker
72*5c90c05cSAndroid Build Coastguard Workerdef transform(pattern):
73*5c90c05cSAndroid Build Coastguard Worker    """Expand pattern into an (almost) equivalent one, but with single Either.
74*5c90c05cSAndroid Build Coastguard Worker
75*5c90c05cSAndroid Build Coastguard Worker    Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d)
76*5c90c05cSAndroid Build Coastguard Worker    Quirks: [-a] => (-a), (-a...) => (-a -a)
77*5c90c05cSAndroid Build Coastguard Worker
78*5c90c05cSAndroid Build Coastguard Worker    """
79*5c90c05cSAndroid Build Coastguard Worker    result = []
80*5c90c05cSAndroid Build Coastguard Worker    groups = [[pattern]]
81*5c90c05cSAndroid Build Coastguard Worker    while groups:
82*5c90c05cSAndroid Build Coastguard Worker        children = groups.pop(0)
83*5c90c05cSAndroid Build Coastguard Worker        parents = [Required, Optional, OptionsShortcut, Either, OneOrMore]
84*5c90c05cSAndroid Build Coastguard Worker        if any(t in map(type, children) for t in parents):
85*5c90c05cSAndroid Build Coastguard Worker            child = [c for c in children if type(c) in parents][0]
86*5c90c05cSAndroid Build Coastguard Worker            children.remove(child)
87*5c90c05cSAndroid Build Coastguard Worker            if type(child) is Either:
88*5c90c05cSAndroid Build Coastguard Worker                for c in child.children:
89*5c90c05cSAndroid Build Coastguard Worker                    groups.append([c] + children)
90*5c90c05cSAndroid Build Coastguard Worker            elif type(child) is OneOrMore:
91*5c90c05cSAndroid Build Coastguard Worker                groups.append(child.children * 2 + children)
92*5c90c05cSAndroid Build Coastguard Worker            else:
93*5c90c05cSAndroid Build Coastguard Worker                groups.append(child.children + children)
94*5c90c05cSAndroid Build Coastguard Worker        else:
95*5c90c05cSAndroid Build Coastguard Worker            result.append(children)
96*5c90c05cSAndroid Build Coastguard Worker    return Either(*[Required(*e) for e in result])
97*5c90c05cSAndroid Build Coastguard Worker
98*5c90c05cSAndroid Build Coastguard Worker
99*5c90c05cSAndroid Build Coastguard Workerclass LeafPattern(Pattern):
100*5c90c05cSAndroid Build Coastguard Worker
101*5c90c05cSAndroid Build Coastguard Worker    """Leaf/terminal node of a pattern tree."""
102*5c90c05cSAndroid Build Coastguard Worker
103*5c90c05cSAndroid Build Coastguard Worker    def __init__(self, name, value=None):
104*5c90c05cSAndroid Build Coastguard Worker        self.name, self.value = name, value
105*5c90c05cSAndroid Build Coastguard Worker
106*5c90c05cSAndroid Build Coastguard Worker    def __repr__(self):
107*5c90c05cSAndroid Build Coastguard Worker        return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value)
108*5c90c05cSAndroid Build Coastguard Worker
109*5c90c05cSAndroid Build Coastguard Worker    def flat(self, *types):
110*5c90c05cSAndroid Build Coastguard Worker        return [self] if not types or type(self) in types else []
111*5c90c05cSAndroid Build Coastguard Worker
112*5c90c05cSAndroid Build Coastguard Worker    def match(self, left, collected=None):
113*5c90c05cSAndroid Build Coastguard Worker        collected = [] if collected is None else collected
114*5c90c05cSAndroid Build Coastguard Worker        pos, match = self.single_match(left)
115*5c90c05cSAndroid Build Coastguard Worker        if match is None:
116*5c90c05cSAndroid Build Coastguard Worker            return False, left, collected
117*5c90c05cSAndroid Build Coastguard Worker        left_ = left[:pos] + left[pos + 1:]
118*5c90c05cSAndroid Build Coastguard Worker        same_name = [a for a in collected if a.name == self.name]
119*5c90c05cSAndroid Build Coastguard Worker        if type(self.value) in (int, list):
120*5c90c05cSAndroid Build Coastguard Worker            if type(self.value) is int:
121*5c90c05cSAndroid Build Coastguard Worker                increment = 1
122*5c90c05cSAndroid Build Coastguard Worker            else:
123*5c90c05cSAndroid Build Coastguard Worker                increment = ([match.value] if type(match.value) is str
124*5c90c05cSAndroid Build Coastguard Worker                             else match.value)
125*5c90c05cSAndroid Build Coastguard Worker            if not same_name:
126*5c90c05cSAndroid Build Coastguard Worker                match.value = increment
127*5c90c05cSAndroid Build Coastguard Worker                return True, left_, collected + [match]
128*5c90c05cSAndroid Build Coastguard Worker            same_name[0].value += increment
129*5c90c05cSAndroid Build Coastguard Worker            return True, left_, collected
130*5c90c05cSAndroid Build Coastguard Worker        return True, left_, collected + [match]
131*5c90c05cSAndroid Build Coastguard Worker
132*5c90c05cSAndroid Build Coastguard Worker
133*5c90c05cSAndroid Build Coastguard Workerclass BranchPattern(Pattern):
134*5c90c05cSAndroid Build Coastguard Worker
135*5c90c05cSAndroid Build Coastguard Worker    """Branch/inner node of a pattern tree."""
136*5c90c05cSAndroid Build Coastguard Worker
137*5c90c05cSAndroid Build Coastguard Worker    def __init__(self, *children):
138*5c90c05cSAndroid Build Coastguard Worker        self.children = list(children)
139*5c90c05cSAndroid Build Coastguard Worker
140*5c90c05cSAndroid Build Coastguard Worker    def __repr__(self):
141*5c90c05cSAndroid Build Coastguard Worker        return '%s(%s)' % (self.__class__.__name__,
142*5c90c05cSAndroid Build Coastguard Worker                           ', '.join(repr(a) for a in self.children))
143*5c90c05cSAndroid Build Coastguard Worker
144*5c90c05cSAndroid Build Coastguard Worker    def flat(self, *types):
145*5c90c05cSAndroid Build Coastguard Worker        if type(self) in types:
146*5c90c05cSAndroid Build Coastguard Worker            return [self]
147*5c90c05cSAndroid Build Coastguard Worker        return sum([child.flat(*types) for child in self.children], [])
148*5c90c05cSAndroid Build Coastguard Worker
149*5c90c05cSAndroid Build Coastguard Worker
150*5c90c05cSAndroid Build Coastguard Workerclass Argument(LeafPattern):
151*5c90c05cSAndroid Build Coastguard Worker
152*5c90c05cSAndroid Build Coastguard Worker    def single_match(self, left):
153*5c90c05cSAndroid Build Coastguard Worker        for n, pattern in enumerate(left):
154*5c90c05cSAndroid Build Coastguard Worker            if type(pattern) is Argument:
155*5c90c05cSAndroid Build Coastguard Worker                return n, Argument(self.name, pattern.value)
156*5c90c05cSAndroid Build Coastguard Worker        return None, None
157*5c90c05cSAndroid Build Coastguard Worker
158*5c90c05cSAndroid Build Coastguard Worker    @classmethod
159*5c90c05cSAndroid Build Coastguard Worker    def parse(class_, source):
160*5c90c05cSAndroid Build Coastguard Worker        name = re.findall('(<\S*?>)', source)[0]
161*5c90c05cSAndroid Build Coastguard Worker        value = re.findall('\[default: (.*)\]', source, flags=re.I)
162*5c90c05cSAndroid Build Coastguard Worker        return class_(name, value[0] if value else None)
163*5c90c05cSAndroid Build Coastguard Worker
164*5c90c05cSAndroid Build Coastguard Worker
165*5c90c05cSAndroid Build Coastguard Workerclass Command(Argument):
166*5c90c05cSAndroid Build Coastguard Worker
167*5c90c05cSAndroid Build Coastguard Worker    def __init__(self, name, value=False):
168*5c90c05cSAndroid Build Coastguard Worker        self.name, self.value = name, value
169*5c90c05cSAndroid Build Coastguard Worker
170*5c90c05cSAndroid Build Coastguard Worker    def single_match(self, left):
171*5c90c05cSAndroid Build Coastguard Worker        for n, pattern in enumerate(left):
172*5c90c05cSAndroid Build Coastguard Worker            if type(pattern) is Argument:
173*5c90c05cSAndroid Build Coastguard Worker                if pattern.value == self.name:
174*5c90c05cSAndroid Build Coastguard Worker                    return n, Command(self.name, True)
175*5c90c05cSAndroid Build Coastguard Worker                else:
176*5c90c05cSAndroid Build Coastguard Worker                    break
177*5c90c05cSAndroid Build Coastguard Worker        return None, None
178*5c90c05cSAndroid Build Coastguard Worker
179*5c90c05cSAndroid Build Coastguard Worker
180*5c90c05cSAndroid Build Coastguard Workerclass Option(LeafPattern):
181*5c90c05cSAndroid Build Coastguard Worker
182*5c90c05cSAndroid Build Coastguard Worker    def __init__(self, short=None, long=None, argcount=0, value=False):
183*5c90c05cSAndroid Build Coastguard Worker        assert argcount in (0, 1)
184*5c90c05cSAndroid Build Coastguard Worker        self.short, self.long, self.argcount = short, long, argcount
185*5c90c05cSAndroid Build Coastguard Worker        self.value = None if value is False and argcount else value
186*5c90c05cSAndroid Build Coastguard Worker
187*5c90c05cSAndroid Build Coastguard Worker    @classmethod
188*5c90c05cSAndroid Build Coastguard Worker    def parse(class_, option_description):
189*5c90c05cSAndroid Build Coastguard Worker        short, long, argcount, value = None, None, 0, False
190*5c90c05cSAndroid Build Coastguard Worker        options, _, description = option_description.strip().partition('  ')
191*5c90c05cSAndroid Build Coastguard Worker        options = options.replace(',', ' ').replace('=', ' ')
192*5c90c05cSAndroid Build Coastguard Worker        for s in options.split():
193*5c90c05cSAndroid Build Coastguard Worker            if s.startswith('--'):
194*5c90c05cSAndroid Build Coastguard Worker                long = s
195*5c90c05cSAndroid Build Coastguard Worker            elif s.startswith('-'):
196*5c90c05cSAndroid Build Coastguard Worker                short = s
197*5c90c05cSAndroid Build Coastguard Worker            else:
198*5c90c05cSAndroid Build Coastguard Worker                argcount = 1
199*5c90c05cSAndroid Build Coastguard Worker        if argcount:
200*5c90c05cSAndroid Build Coastguard Worker            matched = re.findall('\[default: (.*)\]', description, flags=re.I)
201*5c90c05cSAndroid Build Coastguard Worker            value = matched[0] if matched else None
202*5c90c05cSAndroid Build Coastguard Worker        return class_(short, long, argcount, value)
203*5c90c05cSAndroid Build Coastguard Worker
204*5c90c05cSAndroid Build Coastguard Worker    def single_match(self, left):
205*5c90c05cSAndroid Build Coastguard Worker        for n, pattern in enumerate(left):
206*5c90c05cSAndroid Build Coastguard Worker            if self.name == pattern.name:
207*5c90c05cSAndroid Build Coastguard Worker                return n, pattern
208*5c90c05cSAndroid Build Coastguard Worker        return None, None
209*5c90c05cSAndroid Build Coastguard Worker
210*5c90c05cSAndroid Build Coastguard Worker    @property
211*5c90c05cSAndroid Build Coastguard Worker    def name(self):
212*5c90c05cSAndroid Build Coastguard Worker        return self.long or self.short
213*5c90c05cSAndroid Build Coastguard Worker
214*5c90c05cSAndroid Build Coastguard Worker    def __repr__(self):
215*5c90c05cSAndroid Build Coastguard Worker        return 'Option(%r, %r, %r, %r)' % (self.short, self.long,
216*5c90c05cSAndroid Build Coastguard Worker                                           self.argcount, self.value)
217*5c90c05cSAndroid Build Coastguard Worker
218*5c90c05cSAndroid Build Coastguard Worker
219*5c90c05cSAndroid Build Coastguard Workerclass Required(BranchPattern):
220*5c90c05cSAndroid Build Coastguard Worker
221*5c90c05cSAndroid Build Coastguard Worker    def match(self, left, collected=None):
222*5c90c05cSAndroid Build Coastguard Worker        collected = [] if collected is None else collected
223*5c90c05cSAndroid Build Coastguard Worker        l = left
224*5c90c05cSAndroid Build Coastguard Worker        c = collected
225*5c90c05cSAndroid Build Coastguard Worker        for pattern in self.children:
226*5c90c05cSAndroid Build Coastguard Worker            matched, l, c = pattern.match(l, c)
227*5c90c05cSAndroid Build Coastguard Worker            if not matched:
228*5c90c05cSAndroid Build Coastguard Worker                return False, left, collected
229*5c90c05cSAndroid Build Coastguard Worker        return True, l, c
230*5c90c05cSAndroid Build Coastguard Worker
231*5c90c05cSAndroid Build Coastguard Worker
232*5c90c05cSAndroid Build Coastguard Workerclass Optional(BranchPattern):
233*5c90c05cSAndroid Build Coastguard Worker
234*5c90c05cSAndroid Build Coastguard Worker    def match(self, left, collected=None):
235*5c90c05cSAndroid Build Coastguard Worker        collected = [] if collected is None else collected
236*5c90c05cSAndroid Build Coastguard Worker        for pattern in self.children:
237*5c90c05cSAndroid Build Coastguard Worker            m, left, collected = pattern.match(left, collected)
238*5c90c05cSAndroid Build Coastguard Worker        return True, left, collected
239*5c90c05cSAndroid Build Coastguard Worker
240*5c90c05cSAndroid Build Coastguard Worker
241*5c90c05cSAndroid Build Coastguard Workerclass OptionsShortcut(Optional):
242*5c90c05cSAndroid Build Coastguard Worker
243*5c90c05cSAndroid Build Coastguard Worker    """Marker/placeholder for [options] shortcut."""
244*5c90c05cSAndroid Build Coastguard Worker
245*5c90c05cSAndroid Build Coastguard Worker
246*5c90c05cSAndroid Build Coastguard Workerclass OneOrMore(BranchPattern):
247*5c90c05cSAndroid Build Coastguard Worker
248*5c90c05cSAndroid Build Coastguard Worker    def match(self, left, collected=None):
249*5c90c05cSAndroid Build Coastguard Worker        assert len(self.children) == 1
250*5c90c05cSAndroid Build Coastguard Worker        collected = [] if collected is None else collected
251*5c90c05cSAndroid Build Coastguard Worker        l = left
252*5c90c05cSAndroid Build Coastguard Worker        c = collected
253*5c90c05cSAndroid Build Coastguard Worker        l_ = None
254*5c90c05cSAndroid Build Coastguard Worker        matched = True
255*5c90c05cSAndroid Build Coastguard Worker        times = 0
256*5c90c05cSAndroid Build Coastguard Worker        while matched:
257*5c90c05cSAndroid Build Coastguard Worker            # could it be that something didn't match but changed l or c?
258*5c90c05cSAndroid Build Coastguard Worker            matched, l, c = self.children[0].match(l, c)
259*5c90c05cSAndroid Build Coastguard Worker            times += 1 if matched else 0
260*5c90c05cSAndroid Build Coastguard Worker            if l_ == l:
261*5c90c05cSAndroid Build Coastguard Worker                break
262*5c90c05cSAndroid Build Coastguard Worker            l_ = l
263*5c90c05cSAndroid Build Coastguard Worker        if times >= 1:
264*5c90c05cSAndroid Build Coastguard Worker            return True, l, c
265*5c90c05cSAndroid Build Coastguard Worker        return False, left, collected
266*5c90c05cSAndroid Build Coastguard Worker
267*5c90c05cSAndroid Build Coastguard Worker
268*5c90c05cSAndroid Build Coastguard Workerclass Either(BranchPattern):
269*5c90c05cSAndroid Build Coastguard Worker
270*5c90c05cSAndroid Build Coastguard Worker    def match(self, left, collected=None):
271*5c90c05cSAndroid Build Coastguard Worker        collected = [] if collected is None else collected
272*5c90c05cSAndroid Build Coastguard Worker        outcomes = []
273*5c90c05cSAndroid Build Coastguard Worker        for pattern in self.children:
274*5c90c05cSAndroid Build Coastguard Worker            matched, _, _ = outcome = pattern.match(left, collected)
275*5c90c05cSAndroid Build Coastguard Worker            if matched:
276*5c90c05cSAndroid Build Coastguard Worker                outcomes.append(outcome)
277*5c90c05cSAndroid Build Coastguard Worker        if outcomes:
278*5c90c05cSAndroid Build Coastguard Worker            return min(outcomes, key=lambda outcome: len(outcome[1]))
279*5c90c05cSAndroid Build Coastguard Worker        return False, left, collected
280*5c90c05cSAndroid Build Coastguard Worker
281*5c90c05cSAndroid Build Coastguard Worker
282*5c90c05cSAndroid Build Coastguard Workerclass Tokens(list):
283*5c90c05cSAndroid Build Coastguard Worker
284*5c90c05cSAndroid Build Coastguard Worker    def __init__(self, source, error=DocoptExit):
285*5c90c05cSAndroid Build Coastguard Worker        self += source.split() if hasattr(source, 'split') else source
286*5c90c05cSAndroid Build Coastguard Worker        self.error = error
287*5c90c05cSAndroid Build Coastguard Worker
288*5c90c05cSAndroid Build Coastguard Worker    @staticmethod
289*5c90c05cSAndroid Build Coastguard Worker    def from_pattern(source):
290*5c90c05cSAndroid Build Coastguard Worker        source = re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source)
291*5c90c05cSAndroid Build Coastguard Worker        source = [s for s in re.split('\s+|(\S*<.*?>)', source) if s]
292*5c90c05cSAndroid Build Coastguard Worker        return Tokens(source, error=DocoptLanguageError)
293*5c90c05cSAndroid Build Coastguard Worker
294*5c90c05cSAndroid Build Coastguard Worker    def move(self):
295*5c90c05cSAndroid Build Coastguard Worker        return self.pop(0) if len(self) else None
296*5c90c05cSAndroid Build Coastguard Worker
297*5c90c05cSAndroid Build Coastguard Worker    def current(self):
298*5c90c05cSAndroid Build Coastguard Worker        return self[0] if len(self) else None
299*5c90c05cSAndroid Build Coastguard Worker
300*5c90c05cSAndroid Build Coastguard Worker
301*5c90c05cSAndroid Build Coastguard Workerdef parse_long(tokens, options):
302*5c90c05cSAndroid Build Coastguard Worker    """long ::= '--' chars [ ( ' ' | '=' ) chars ] ;"""
303*5c90c05cSAndroid Build Coastguard Worker    long, eq, value = tokens.move().partition('=')
304*5c90c05cSAndroid Build Coastguard Worker    assert long.startswith('--')
305*5c90c05cSAndroid Build Coastguard Worker    value = None if eq == value == '' else value
306*5c90c05cSAndroid Build Coastguard Worker    similar = [o for o in options if o.long == long]
307*5c90c05cSAndroid Build Coastguard Worker    if tokens.error is DocoptExit and similar == []:  # if no exact match
308*5c90c05cSAndroid Build Coastguard Worker        similar = [o for o in options if o.long and o.long.startswith(long)]
309*5c90c05cSAndroid Build Coastguard Worker    if len(similar) > 1:  # might be simply specified ambiguously 2+ times?
310*5c90c05cSAndroid Build Coastguard Worker        raise tokens.error('%s is not a unique prefix: %s?' %
311*5c90c05cSAndroid Build Coastguard Worker                           (long, ', '.join(o.long for o in similar)))
312*5c90c05cSAndroid Build Coastguard Worker    elif len(similar) < 1:
313*5c90c05cSAndroid Build Coastguard Worker        argcount = 1 if eq == '=' else 0
314*5c90c05cSAndroid Build Coastguard Worker        o = Option(None, long, argcount)
315*5c90c05cSAndroid Build Coastguard Worker        options.append(o)
316*5c90c05cSAndroid Build Coastguard Worker        if tokens.error is DocoptExit:
317*5c90c05cSAndroid Build Coastguard Worker            o = Option(None, long, argcount, value if argcount else True)
318*5c90c05cSAndroid Build Coastguard Worker    else:
319*5c90c05cSAndroid Build Coastguard Worker        o = Option(similar[0].short, similar[0].long,
320*5c90c05cSAndroid Build Coastguard Worker                   similar[0].argcount, similar[0].value)
321*5c90c05cSAndroid Build Coastguard Worker        if o.argcount == 0:
322*5c90c05cSAndroid Build Coastguard Worker            if value is not None:
323*5c90c05cSAndroid Build Coastguard Worker                raise tokens.error('%s must not have an argument' % o.long)
324*5c90c05cSAndroid Build Coastguard Worker        else:
325*5c90c05cSAndroid Build Coastguard Worker            if value is None:
326*5c90c05cSAndroid Build Coastguard Worker                if tokens.current() in [None, '--']:
327*5c90c05cSAndroid Build Coastguard Worker                    raise tokens.error('%s requires argument' % o.long)
328*5c90c05cSAndroid Build Coastguard Worker                value = tokens.move()
329*5c90c05cSAndroid Build Coastguard Worker        if tokens.error is DocoptExit:
330*5c90c05cSAndroid Build Coastguard Worker            o.value = value if value is not None else True
331*5c90c05cSAndroid Build Coastguard Worker    return [o]
332*5c90c05cSAndroid Build Coastguard Worker
333*5c90c05cSAndroid Build Coastguard Worker
334*5c90c05cSAndroid Build Coastguard Workerdef parse_shorts(tokens, options):
335*5c90c05cSAndroid Build Coastguard Worker    """shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;"""
336*5c90c05cSAndroid Build Coastguard Worker    token = tokens.move()
337*5c90c05cSAndroid Build Coastguard Worker    assert token.startswith('-') and not token.startswith('--')
338*5c90c05cSAndroid Build Coastguard Worker    left = token.lstrip('-')
339*5c90c05cSAndroid Build Coastguard Worker    parsed = []
340*5c90c05cSAndroid Build Coastguard Worker    while left != '':
341*5c90c05cSAndroid Build Coastguard Worker        short, left = '-' + left[0], left[1:]
342*5c90c05cSAndroid Build Coastguard Worker        similar = [o for o in options if o.short == short]
343*5c90c05cSAndroid Build Coastguard Worker        if len(similar) > 1:
344*5c90c05cSAndroid Build Coastguard Worker            raise tokens.error('%s is specified ambiguously %d times' %
345*5c90c05cSAndroid Build Coastguard Worker                               (short, len(similar)))
346*5c90c05cSAndroid Build Coastguard Worker        elif len(similar) < 1:
347*5c90c05cSAndroid Build Coastguard Worker            o = Option(short, None, 0)
348*5c90c05cSAndroid Build Coastguard Worker            options.append(o)
349*5c90c05cSAndroid Build Coastguard Worker            if tokens.error is DocoptExit:
350*5c90c05cSAndroid Build Coastguard Worker                o = Option(short, None, 0, True)
351*5c90c05cSAndroid Build Coastguard Worker        else:  # why copying is necessary here?
352*5c90c05cSAndroid Build Coastguard Worker            o = Option(short, similar[0].long,
353*5c90c05cSAndroid Build Coastguard Worker                       similar[0].argcount, similar[0].value)
354*5c90c05cSAndroid Build Coastguard Worker            value = None
355*5c90c05cSAndroid Build Coastguard Worker            if o.argcount != 0:
356*5c90c05cSAndroid Build Coastguard Worker                if left == '':
357*5c90c05cSAndroid Build Coastguard Worker                    if tokens.current() in [None, '--']:
358*5c90c05cSAndroid Build Coastguard Worker                        raise tokens.error('%s requires argument' % short)
359*5c90c05cSAndroid Build Coastguard Worker                    value = tokens.move()
360*5c90c05cSAndroid Build Coastguard Worker                else:
361*5c90c05cSAndroid Build Coastguard Worker                    value = left
362*5c90c05cSAndroid Build Coastguard Worker                    left = ''
363*5c90c05cSAndroid Build Coastguard Worker            if tokens.error is DocoptExit:
364*5c90c05cSAndroid Build Coastguard Worker                o.value = value if value is not None else True
365*5c90c05cSAndroid Build Coastguard Worker        parsed.append(o)
366*5c90c05cSAndroid Build Coastguard Worker    return parsed
367*5c90c05cSAndroid Build Coastguard Worker
368*5c90c05cSAndroid Build Coastguard Worker
369*5c90c05cSAndroid Build Coastguard Workerdef parse_pattern(source, options):
370*5c90c05cSAndroid Build Coastguard Worker    tokens = Tokens.from_pattern(source)
371*5c90c05cSAndroid Build Coastguard Worker    result = parse_expr(tokens, options)
372*5c90c05cSAndroid Build Coastguard Worker    if tokens.current() is not None:
373*5c90c05cSAndroid Build Coastguard Worker        raise tokens.error('unexpected ending: %r' % ' '.join(tokens))
374*5c90c05cSAndroid Build Coastguard Worker    return Required(*result)
375*5c90c05cSAndroid Build Coastguard Worker
376*5c90c05cSAndroid Build Coastguard Worker
377*5c90c05cSAndroid Build Coastguard Workerdef parse_expr(tokens, options):
378*5c90c05cSAndroid Build Coastguard Worker    """expr ::= seq ( '|' seq )* ;"""
379*5c90c05cSAndroid Build Coastguard Worker    seq = parse_seq(tokens, options)
380*5c90c05cSAndroid Build Coastguard Worker    if tokens.current() != '|':
381*5c90c05cSAndroid Build Coastguard Worker        return seq
382*5c90c05cSAndroid Build Coastguard Worker    result = [Required(*seq)] if len(seq) > 1 else seq
383*5c90c05cSAndroid Build Coastguard Worker    while tokens.current() == '|':
384*5c90c05cSAndroid Build Coastguard Worker        tokens.move()
385*5c90c05cSAndroid Build Coastguard Worker        seq = parse_seq(tokens, options)
386*5c90c05cSAndroid Build Coastguard Worker        result += [Required(*seq)] if len(seq) > 1 else seq
387*5c90c05cSAndroid Build Coastguard Worker    return [Either(*result)] if len(result) > 1 else result
388*5c90c05cSAndroid Build Coastguard Worker
389*5c90c05cSAndroid Build Coastguard Worker
390*5c90c05cSAndroid Build Coastguard Workerdef parse_seq(tokens, options):
391*5c90c05cSAndroid Build Coastguard Worker    """seq ::= ( atom [ '...' ] )* ;"""
392*5c90c05cSAndroid Build Coastguard Worker    result = []
393*5c90c05cSAndroid Build Coastguard Worker    while tokens.current() not in [None, ']', ')', '|']:
394*5c90c05cSAndroid Build Coastguard Worker        atom = parse_atom(tokens, options)
395*5c90c05cSAndroid Build Coastguard Worker        if tokens.current() == '...':
396*5c90c05cSAndroid Build Coastguard Worker            atom = [OneOrMore(*atom)]
397*5c90c05cSAndroid Build Coastguard Worker            tokens.move()
398*5c90c05cSAndroid Build Coastguard Worker        result += atom
399*5c90c05cSAndroid Build Coastguard Worker    return result
400*5c90c05cSAndroid Build Coastguard Worker
401*5c90c05cSAndroid Build Coastguard Worker
402*5c90c05cSAndroid Build Coastguard Workerdef parse_atom(tokens, options):
403*5c90c05cSAndroid Build Coastguard Worker    """atom ::= '(' expr ')' | '[' expr ']' | 'options'
404*5c90c05cSAndroid Build Coastguard Worker             | long | shorts | argument | command ;
405*5c90c05cSAndroid Build Coastguard Worker    """
406*5c90c05cSAndroid Build Coastguard Worker    token = tokens.current()
407*5c90c05cSAndroid Build Coastguard Worker    result = []
408*5c90c05cSAndroid Build Coastguard Worker    if token in '([':
409*5c90c05cSAndroid Build Coastguard Worker        tokens.move()
410*5c90c05cSAndroid Build Coastguard Worker        matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token]
411*5c90c05cSAndroid Build Coastguard Worker        result = pattern(*parse_expr(tokens, options))
412*5c90c05cSAndroid Build Coastguard Worker        if tokens.move() != matching:
413*5c90c05cSAndroid Build Coastguard Worker            raise tokens.error("unmatched '%s'" % token)
414*5c90c05cSAndroid Build Coastguard Worker        return [result]
415*5c90c05cSAndroid Build Coastguard Worker    elif token == 'options':
416*5c90c05cSAndroid Build Coastguard Worker        tokens.move()
417*5c90c05cSAndroid Build Coastguard Worker        return [OptionsShortcut()]
418*5c90c05cSAndroid Build Coastguard Worker    elif token.startswith('--') and token != '--':
419*5c90c05cSAndroid Build Coastguard Worker        return parse_long(tokens, options)
420*5c90c05cSAndroid Build Coastguard Worker    elif token.startswith('-') and token not in ('-', '--'):
421*5c90c05cSAndroid Build Coastguard Worker        return parse_shorts(tokens, options)
422*5c90c05cSAndroid Build Coastguard Worker    elif token.startswith('<') and token.endswith('>') or token.isupper():
423*5c90c05cSAndroid Build Coastguard Worker        return [Argument(tokens.move())]
424*5c90c05cSAndroid Build Coastguard Worker    else:
425*5c90c05cSAndroid Build Coastguard Worker        return [Command(tokens.move())]
426*5c90c05cSAndroid Build Coastguard Worker
427*5c90c05cSAndroid Build Coastguard Worker
428*5c90c05cSAndroid Build Coastguard Workerdef parse_argv(tokens, options, options_first=False):
429*5c90c05cSAndroid Build Coastguard Worker    """Parse command-line argument vector.
430*5c90c05cSAndroid Build Coastguard Worker
431*5c90c05cSAndroid Build Coastguard Worker    If options_first:
432*5c90c05cSAndroid Build Coastguard Worker        argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ;
433*5c90c05cSAndroid Build Coastguard Worker    else:
434*5c90c05cSAndroid Build Coastguard Worker        argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ;
435*5c90c05cSAndroid Build Coastguard Worker
436*5c90c05cSAndroid Build Coastguard Worker    """
437*5c90c05cSAndroid Build Coastguard Worker    parsed = []
438*5c90c05cSAndroid Build Coastguard Worker    while tokens.current() is not None:
439*5c90c05cSAndroid Build Coastguard Worker        if tokens.current() == '--':
440*5c90c05cSAndroid Build Coastguard Worker            return parsed + [Argument(None, v) for v in tokens]
441*5c90c05cSAndroid Build Coastguard Worker        elif tokens.current().startswith('--'):
442*5c90c05cSAndroid Build Coastguard Worker            parsed += parse_long(tokens, options)
443*5c90c05cSAndroid Build Coastguard Worker        elif tokens.current().startswith('-') and tokens.current() != '-':
444*5c90c05cSAndroid Build Coastguard Worker            parsed += parse_shorts(tokens, options)
445*5c90c05cSAndroid Build Coastguard Worker        elif options_first:
446*5c90c05cSAndroid Build Coastguard Worker            return parsed + [Argument(None, v) for v in tokens]
447*5c90c05cSAndroid Build Coastguard Worker        else:
448*5c90c05cSAndroid Build Coastguard Worker            parsed.append(Argument(None, tokens.move()))
449*5c90c05cSAndroid Build Coastguard Worker    return parsed
450*5c90c05cSAndroid Build Coastguard Worker
451*5c90c05cSAndroid Build Coastguard Worker
452*5c90c05cSAndroid Build Coastguard Workerdef parse_defaults(doc):
453*5c90c05cSAndroid Build Coastguard Worker    defaults = []
454*5c90c05cSAndroid Build Coastguard Worker    for s in parse_section('options:', doc):
455*5c90c05cSAndroid Build Coastguard Worker        # FIXME corner case "bla: options: --foo"
456*5c90c05cSAndroid Build Coastguard Worker        _, _, s = s.partition(':')  # get rid of "options:"
457*5c90c05cSAndroid Build Coastguard Worker        split = re.split('\n[ \t]*(-\S+?)', '\n' + s)[1:]
458*5c90c05cSAndroid Build Coastguard Worker        split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])]
459*5c90c05cSAndroid Build Coastguard Worker        options = [Option.parse(s) for s in split if s.startswith('-')]
460*5c90c05cSAndroid Build Coastguard Worker        defaults += options
461*5c90c05cSAndroid Build Coastguard Worker    return defaults
462*5c90c05cSAndroid Build Coastguard Worker
463*5c90c05cSAndroid Build Coastguard Worker
464*5c90c05cSAndroid Build Coastguard Workerdef parse_section(name, source):
465*5c90c05cSAndroid Build Coastguard Worker    pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)',
466*5c90c05cSAndroid Build Coastguard Worker                         re.IGNORECASE | re.MULTILINE)
467*5c90c05cSAndroid Build Coastguard Worker    return [s.strip() for s in pattern.findall(source)]
468*5c90c05cSAndroid Build Coastguard Worker
469*5c90c05cSAndroid Build Coastguard Worker
470*5c90c05cSAndroid Build Coastguard Workerdef formal_usage(section):
471*5c90c05cSAndroid Build Coastguard Worker    _, _, section = section.partition(':')  # drop "usage:"
472*5c90c05cSAndroid Build Coastguard Worker    pu = section.split()
473*5c90c05cSAndroid Build Coastguard Worker    return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )'
474*5c90c05cSAndroid Build Coastguard Worker
475*5c90c05cSAndroid Build Coastguard Worker
476*5c90c05cSAndroid Build Coastguard Workerdef extras(help, version, options, doc):
477*5c90c05cSAndroid Build Coastguard Worker    if help and any((o.name in ('-h', '--help')) and o.value for o in options):
478*5c90c05cSAndroid Build Coastguard Worker        print(doc.strip("\n"))
479*5c90c05cSAndroid Build Coastguard Worker        sys.exit()
480*5c90c05cSAndroid Build Coastguard Worker    if version and any(o.name == '--version' and o.value for o in options):
481*5c90c05cSAndroid Build Coastguard Worker        print(version)
482*5c90c05cSAndroid Build Coastguard Worker        sys.exit()
483*5c90c05cSAndroid Build Coastguard Worker
484*5c90c05cSAndroid Build Coastguard Worker
485*5c90c05cSAndroid Build Coastguard Workerclass Dict(dict):
486*5c90c05cSAndroid Build Coastguard Worker    def __repr__(self):
487*5c90c05cSAndroid Build Coastguard Worker        return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items()))
488*5c90c05cSAndroid Build Coastguard Worker
489*5c90c05cSAndroid Build Coastguard Worker
490*5c90c05cSAndroid Build Coastguard Workerdef docopt(doc, argv=None, help=True, version=None, options_first=False):
491*5c90c05cSAndroid Build Coastguard Worker    """Parse `argv` based on command-line interface described in `doc`.
492*5c90c05cSAndroid Build Coastguard Worker
493*5c90c05cSAndroid Build Coastguard Worker    `docopt` creates your command-line interface based on its
494*5c90c05cSAndroid Build Coastguard Worker    description that you pass as `doc`. Such description can contain
495*5c90c05cSAndroid Build Coastguard Worker    --options, <positional-argument>, commands, which could be
496*5c90c05cSAndroid Build Coastguard Worker    [optional], (required), (mutually | exclusive) or repeated...
497*5c90c05cSAndroid Build Coastguard Worker
498*5c90c05cSAndroid Build Coastguard Worker    Parameters
499*5c90c05cSAndroid Build Coastguard Worker    ----------
500*5c90c05cSAndroid Build Coastguard Worker    doc : str
501*5c90c05cSAndroid Build Coastguard Worker        Description of your command-line interface.
502*5c90c05cSAndroid Build Coastguard Worker    argv : list of str, optional
503*5c90c05cSAndroid Build Coastguard Worker        Argument vector to be parsed. sys.argv[1:] is used if not
504*5c90c05cSAndroid Build Coastguard Worker        provided.
505*5c90c05cSAndroid Build Coastguard Worker    help : bool (default: True)
506*5c90c05cSAndroid Build Coastguard Worker        Set to False to disable automatic help on -h or --help
507*5c90c05cSAndroid Build Coastguard Worker        options.
508*5c90c05cSAndroid Build Coastguard Worker    version : any object
509*5c90c05cSAndroid Build Coastguard Worker        If passed, the object will be printed if --version is in
510*5c90c05cSAndroid Build Coastguard Worker        `argv`.
511*5c90c05cSAndroid Build Coastguard Worker    options_first : bool (default: False)
512*5c90c05cSAndroid Build Coastguard Worker        Set to True to require options precede positional arguments,
513*5c90c05cSAndroid Build Coastguard Worker        i.e. to forbid options and positional arguments intermix.
514*5c90c05cSAndroid Build Coastguard Worker
515*5c90c05cSAndroid Build Coastguard Worker    Returns
516*5c90c05cSAndroid Build Coastguard Worker    -------
517*5c90c05cSAndroid Build Coastguard Worker    args : dict
518*5c90c05cSAndroid Build Coastguard Worker        A dictionary, where keys are names of command-line elements
519*5c90c05cSAndroid Build Coastguard Worker        such as e.g. "--verbose" and "<path>", and values are the
520*5c90c05cSAndroid Build Coastguard Worker        parsed values of those elements.
521*5c90c05cSAndroid Build Coastguard Worker
522*5c90c05cSAndroid Build Coastguard Worker    Example
523*5c90c05cSAndroid Build Coastguard Worker    -------
524*5c90c05cSAndroid Build Coastguard Worker    >>> from docopt import docopt
525*5c90c05cSAndroid Build Coastguard Worker    >>> doc = '''
526*5c90c05cSAndroid Build Coastguard Worker    ... Usage:
527*5c90c05cSAndroid Build Coastguard Worker    ...     my_program tcp <host> <port> [--timeout=<seconds>]
528*5c90c05cSAndroid Build Coastguard Worker    ...     my_program serial <port> [--baud=<n>] [--timeout=<seconds>]
529*5c90c05cSAndroid Build Coastguard Worker    ...     my_program (-h | --help | --version)
530*5c90c05cSAndroid Build Coastguard Worker    ...
531*5c90c05cSAndroid Build Coastguard Worker    ... Options:
532*5c90c05cSAndroid Build Coastguard Worker    ...     -h, --help  Show this screen and exit.
533*5c90c05cSAndroid Build Coastguard Worker    ...     --baud=<n>  Baudrate [default: 9600]
534*5c90c05cSAndroid Build Coastguard Worker    ... '''
535*5c90c05cSAndroid Build Coastguard Worker    >>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30']
536*5c90c05cSAndroid Build Coastguard Worker    >>> docopt(doc, argv)
537*5c90c05cSAndroid Build Coastguard Worker    {'--baud': '9600',
538*5c90c05cSAndroid Build Coastguard Worker     '--help': False,
539*5c90c05cSAndroid Build Coastguard Worker     '--timeout': '30',
540*5c90c05cSAndroid Build Coastguard Worker     '--version': False,
541*5c90c05cSAndroid Build Coastguard Worker     '<host>': '127.0.0.1',
542*5c90c05cSAndroid Build Coastguard Worker     '<port>': '80',
543*5c90c05cSAndroid Build Coastguard Worker     'serial': False,
544*5c90c05cSAndroid Build Coastguard Worker     'tcp': True}
545*5c90c05cSAndroid Build Coastguard Worker
546*5c90c05cSAndroid Build Coastguard Worker    See also
547*5c90c05cSAndroid Build Coastguard Worker    --------
548*5c90c05cSAndroid Build Coastguard Worker    * For video introduction see http://docopt.org
549*5c90c05cSAndroid Build Coastguard Worker    * Full documentation is available in README.rst as well as online
550*5c90c05cSAndroid Build Coastguard Worker      at https://github.com/docopt/docopt#readme
551*5c90c05cSAndroid Build Coastguard Worker
552*5c90c05cSAndroid Build Coastguard Worker    """
553*5c90c05cSAndroid Build Coastguard Worker    argv = sys.argv[1:] if argv is None else argv
554*5c90c05cSAndroid Build Coastguard Worker
555*5c90c05cSAndroid Build Coastguard Worker    usage_sections = parse_section('usage:', doc)
556*5c90c05cSAndroid Build Coastguard Worker    if len(usage_sections) == 0:
557*5c90c05cSAndroid Build Coastguard Worker        raise DocoptLanguageError('"usage:" (case-insensitive) not found.')
558*5c90c05cSAndroid Build Coastguard Worker    if len(usage_sections) > 1:
559*5c90c05cSAndroid Build Coastguard Worker        raise DocoptLanguageError('More than one "usage:" (case-insensitive).')
560*5c90c05cSAndroid Build Coastguard Worker    DocoptExit.usage = usage_sections[0]
561*5c90c05cSAndroid Build Coastguard Worker
562*5c90c05cSAndroid Build Coastguard Worker    options = parse_defaults(doc)
563*5c90c05cSAndroid Build Coastguard Worker    pattern = parse_pattern(formal_usage(DocoptExit.usage), options)
564*5c90c05cSAndroid Build Coastguard Worker    # [default] syntax for argument is disabled
565*5c90c05cSAndroid Build Coastguard Worker    #for a in pattern.flat(Argument):
566*5c90c05cSAndroid Build Coastguard Worker    #    same_name = [d for d in arguments if d.name == a.name]
567*5c90c05cSAndroid Build Coastguard Worker    #    if same_name:
568*5c90c05cSAndroid Build Coastguard Worker    #        a.value = same_name[0].value
569*5c90c05cSAndroid Build Coastguard Worker    argv = parse_argv(Tokens(argv), list(options), options_first)
570*5c90c05cSAndroid Build Coastguard Worker    pattern_options = set(pattern.flat(Option))
571*5c90c05cSAndroid Build Coastguard Worker    for options_shortcut in pattern.flat(OptionsShortcut):
572*5c90c05cSAndroid Build Coastguard Worker        doc_options = parse_defaults(doc)
573*5c90c05cSAndroid Build Coastguard Worker        options_shortcut.children = list(set(doc_options) - pattern_options)
574*5c90c05cSAndroid Build Coastguard Worker        #if any_options:
575*5c90c05cSAndroid Build Coastguard Worker        #    options_shortcut.children += [Option(o.short, o.long, o.argcount)
576*5c90c05cSAndroid Build Coastguard Worker        #                    for o in argv if type(o) is Option]
577*5c90c05cSAndroid Build Coastguard Worker    extras(help, version, argv, doc)
578*5c90c05cSAndroid Build Coastguard Worker    matched, left, collected = pattern.fix().match(argv)
579*5c90c05cSAndroid Build Coastguard Worker    if matched and left == []:  # better error message if left?
580*5c90c05cSAndroid Build Coastguard Worker        return Dict((a.name, a.value) for a in (pattern.flat() + collected))
581*5c90c05cSAndroid Build Coastguard Worker    raise DocoptExit()
582