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