preparse 0.0.2__tar.gz → 0.0.4__tar.gz
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.
- {preparse-0.0.2/src/preparse.egg-info → preparse-0.0.4}/PKG-INFO +2 -1
- {preparse-0.0.2 → preparse-0.0.4}/pyproject.toml +2 -1
- {preparse-0.0.2 → preparse-0.0.4}/src/preparse/core/__init__.py +106 -83
- preparse-0.0.4/src/preparse/tests/test_extra.py +160213 -0
- preparse-0.0.4/src/preparse/tests/test_extra_no_permutation.py +160213 -0
- preparse-0.0.4/src/preparse/tests/test_extra_posix.py +159704 -0
- preparse-0.0.4/src/preparse/tests/test_long_only.py +48826 -0
- preparse-0.0.4/src/preparse/tests/test_long_only_no_permutation.py +48826 -0
- preparse-0.0.4/src/preparse/tests/test_long_only_posix.py +48805 -0
- preparse-0.0.4/src/preparse/tests/test_parse.py +48715 -0
- preparse-0.0.4/src/preparse/tests/test_parse_no_permutation.py +48715 -0
- preparse-0.0.4/src/preparse/tests/test_parse_posix.py +48540 -0
- preparse-0.0.4/src/preparse/tests/test_warn.py +42 -0
- preparse-0.0.4/src/preparse/tests/test_warn_9001.py +80 -0
- preparse-0.0.4/src/preparse/tests/test_warn_9002.py +104 -0
- preparse-0.0.4/src/preparse/tests/test_warn_9003.py +21 -0
- preparse-0.0.4/src/preparse/tests/test_warn_9004.py +68 -0
- preparse-0.0.4/src/preparse/tests/test_warn_9005.py +28 -0
- preparse-0.0.4/src/preparse/tests/test_warn_9006.py +76 -0
- preparse-0.0.4/src/preparse/tests/test_warn_9007.py +122 -0
- preparse-0.0.4/src/preparse/tests/test_warn_even_more.py +80 -0
- preparse-0.0.4/src/preparse/tests/test_warn_more.py +68 -0
- {preparse-0.0.2 → preparse-0.0.4/src/preparse.egg-info}/PKG-INFO +2 -1
- preparse-0.0.4/src/preparse.egg-info/SOURCES.txt +32 -0
- {preparse-0.0.2 → preparse-0.0.4}/src/preparse.egg-info/requires.txt +1 -0
- preparse-0.0.2/src/preparse/tests/test_1984.py +0 -10
- preparse-0.0.2/src/preparse.egg-info/SOURCES.txt +0 -14
- {preparse-0.0.2 → preparse-0.0.4}/LICENSE.txt +0 -0
- {preparse-0.0.2 → preparse-0.0.4}/MANIFEST.in +0 -0
- {preparse-0.0.2 → preparse-0.0.4}/README.rst +0 -0
- {preparse-0.0.2 → preparse-0.0.4}/setup.cfg +0 -0
- {preparse-0.0.2 → preparse-0.0.4}/src/preparse/__init__.py +0 -0
- {preparse-0.0.2 → preparse-0.0.4}/src/preparse/tests/__init__.py +0 -0
- {preparse-0.0.2 → preparse-0.0.4}/src/preparse.egg-info/dependency_links.txt +0 -0
- {preparse-0.0.2 → preparse-0.0.4}/src/preparse.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: preparse
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.4
|
|
4
4
|
Summary: preparse arguments
|
|
5
5
|
Author-email: Johannes <johannes-programming@mailfence.com>
|
|
6
6
|
License: The MIT License (MIT)
|
|
@@ -40,6 +40,7 @@ License-File: LICENSE.txt
|
|
|
40
40
|
Requires-Dist: click>=8.1.7
|
|
41
41
|
Requires-Dist: datarepr>=0.0.4
|
|
42
42
|
Requires-Dist: makeprop>=0.1.0
|
|
43
|
+
Requires-Dist: tofunc>=1.0
|
|
43
44
|
|
|
44
45
|
========
|
|
45
46
|
preparse
|
|
@@ -19,13 +19,14 @@ dependencies = [
|
|
|
19
19
|
"click>=8.1.7",
|
|
20
20
|
"datarepr>=0.0.4",
|
|
21
21
|
"makeprop>=0.1.0",
|
|
22
|
+
"tofunc>=1.0",
|
|
22
23
|
]
|
|
23
24
|
description = "preparse arguments"
|
|
24
25
|
keywords = []
|
|
25
26
|
name = "preparse"
|
|
26
27
|
readme = "README.rst"
|
|
27
28
|
requires-python = ">=3.8"
|
|
28
|
-
version = "0.0.
|
|
29
|
+
version = "0.0.4"
|
|
29
30
|
|
|
30
31
|
[project.license]
|
|
31
32
|
file = "LICENSE.txt"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import dataclasses
|
|
2
2
|
import enum
|
|
3
3
|
import functools
|
|
4
|
+
import inspect
|
|
4
5
|
import operator
|
|
5
6
|
import os
|
|
6
7
|
import sys
|
|
@@ -11,8 +12,9 @@ from typing import *
|
|
|
11
12
|
import click as cl
|
|
12
13
|
from datarepr import datarepr
|
|
13
14
|
from makeprop import makeprop
|
|
15
|
+
from tofunc import tofunc
|
|
14
16
|
|
|
15
|
-
__all__ = ["PreParser"]
|
|
17
|
+
__all__ = ["Abbrev", "Nargs", "PreParser"]
|
|
16
18
|
|
|
17
19
|
|
|
18
20
|
class Abbrev(enum.IntEnum):
|
|
@@ -36,7 +38,7 @@ class PreParser:
|
|
|
36
38
|
abbrev: Any = Abbrev.COMPLETE,
|
|
37
39
|
permutate: Any = True,
|
|
38
40
|
posix: Any = "infer",
|
|
39
|
-
):
|
|
41
|
+
) -> None:
|
|
40
42
|
self._optdict = dict()
|
|
41
43
|
self.optdict = optdict
|
|
42
44
|
self.prog = prog
|
|
@@ -45,16 +47,53 @@ class PreParser:
|
|
|
45
47
|
self.posix = posix
|
|
46
48
|
|
|
47
49
|
def __repr__(self) -> str:
|
|
50
|
+
"""Return repr(self)."""
|
|
48
51
|
return datarepr(type(self).__name__, **self.todict())
|
|
49
52
|
|
|
50
53
|
@makeprop()
|
|
51
|
-
def abbrev(self, value):
|
|
54
|
+
def abbrev(self, value: SupportsInt) -> Abbrev:
|
|
55
|
+
"""Property that decides how to handle abbreviations."""
|
|
52
56
|
return Abbrev(value)
|
|
53
57
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
+
@tofunc
|
|
59
|
+
@dataclasses.dataclass
|
|
60
|
+
class click:
|
|
61
|
+
"""Return a decorator that infuses the current instance into parse_args."""
|
|
62
|
+
|
|
63
|
+
_self: Any
|
|
64
|
+
cmd: Any = True
|
|
65
|
+
ctx: Any = True
|
|
66
|
+
|
|
67
|
+
@functools.singledispatchmethod
|
|
68
|
+
def __call__(self, target):
|
|
69
|
+
target.parse_args = self(target.parse_args)
|
|
70
|
+
return target
|
|
71
|
+
|
|
72
|
+
@__call__.register
|
|
73
|
+
def _(self, target: types.FunctionType):
|
|
74
|
+
@functools.wraps(target)
|
|
75
|
+
def ans(cmd, ctx, args):
|
|
76
|
+
p = self._self.copy()
|
|
77
|
+
if self.cmd:
|
|
78
|
+
p.clickCommand(cmd)
|
|
79
|
+
if self.ctx:
|
|
80
|
+
p.clickContext(ctx)
|
|
81
|
+
return target(cmd, ctx, p.parse_args(args))
|
|
82
|
+
|
|
83
|
+
return ans
|
|
84
|
+
|
|
85
|
+
@__call__.register
|
|
86
|
+
def _(self, target: types.MethodType):
|
|
87
|
+
func = self(target.__func__)
|
|
88
|
+
ans = types.MethodType(func, target.__self__)
|
|
89
|
+
return ans
|
|
90
|
+
|
|
91
|
+
click.__signature__ = inspect.signature(click).replace(
|
|
92
|
+
return_annotation=click.__wrapped__
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
def clickCommand(self, cmd: cl.Command) -> None:
|
|
96
|
+
"""Reflect a click.Command object."""
|
|
58
97
|
optdict = dict()
|
|
59
98
|
for p in cmd.params:
|
|
60
99
|
if not isinstance(p, cl.Option):
|
|
@@ -70,14 +109,17 @@ class PreParser:
|
|
|
70
109
|
self.optdict.clear()
|
|
71
110
|
self.optdict.update(optdict)
|
|
72
111
|
|
|
73
|
-
def clickContext(self, ctx: cl.Context):
|
|
112
|
+
def clickContext(self, ctx: cl.Context) -> None:
|
|
113
|
+
"""Reflect a click.Context object."""
|
|
74
114
|
self.prog = ctx.info_name
|
|
75
115
|
|
|
76
|
-
def copy(self):
|
|
116
|
+
def copy(self) -> Self:
|
|
117
|
+
"""Return a copy."""
|
|
77
118
|
return type(self)(**self.todict())
|
|
78
119
|
|
|
79
120
|
@makeprop()
|
|
80
|
-
def optdict(self, value):
|
|
121
|
+
def optdict(self, value: Any) -> dict:
|
|
122
|
+
"""Dictionary of options."""
|
|
81
123
|
if value is None:
|
|
82
124
|
self._optdict.clear()
|
|
83
125
|
return self._optdict
|
|
@@ -86,32 +128,42 @@ class PreParser:
|
|
|
86
128
|
self._optdict.update(value)
|
|
87
129
|
return self._optdict
|
|
88
130
|
|
|
89
|
-
def parse_args(
|
|
131
|
+
def parse_args(
|
|
132
|
+
self,
|
|
133
|
+
args: Optional[Iterable] = None,
|
|
134
|
+
) -> List[str]:
|
|
135
|
+
"""Parse args."""
|
|
90
136
|
if args is None:
|
|
91
137
|
args = sys.argv[1:]
|
|
92
|
-
return
|
|
138
|
+
return Parsing(
|
|
93
139
|
parser=self.copy(),
|
|
94
|
-
args=
|
|
140
|
+
args=[str(a) for a in args],
|
|
95
141
|
).ans
|
|
96
142
|
|
|
97
143
|
@makeprop()
|
|
98
|
-
def permutate(self, value):
|
|
144
|
+
def permutate(self, value: Any) -> bool:
|
|
145
|
+
"""Property that decides if the arguments will be permutated."""
|
|
99
146
|
return bool(value)
|
|
100
147
|
|
|
101
148
|
@makeprop()
|
|
102
|
-
def posix(self, value):
|
|
149
|
+
def posix(self, value: Any) -> bool:
|
|
150
|
+
"""Property that decides if posix parsing is used, \
|
|
151
|
+
i.e. a positional argument causes all the arguments after it \
|
|
152
|
+
to be also interpreted as positional."""
|
|
103
153
|
if value == "infer":
|
|
104
154
|
value = os.environ.get("POSIXLY_CORRECT")
|
|
105
155
|
value = bool(value)
|
|
106
156
|
return value
|
|
107
157
|
|
|
108
158
|
@makeprop()
|
|
109
|
-
def prog(self, value):
|
|
159
|
+
def prog(self, value: Any) -> str:
|
|
160
|
+
"""Property that represents the name of the program."""
|
|
110
161
|
if value is None:
|
|
111
162
|
value = os.path.basename(sys.argv[0])
|
|
112
163
|
return str(value)
|
|
113
164
|
|
|
114
165
|
def todict(self) -> dict:
|
|
166
|
+
"""Return a dict representing the current instance."""
|
|
115
167
|
return dict(
|
|
116
168
|
optdict=self.optdict,
|
|
117
169
|
prog=self.prog,
|
|
@@ -120,76 +172,40 @@ class PreParser:
|
|
|
120
172
|
posix=self.posix,
|
|
121
173
|
)
|
|
122
174
|
|
|
123
|
-
def warn(self, message):
|
|
175
|
+
def warn(self, message: Any) -> None:
|
|
176
|
+
"""Warn about something."""
|
|
124
177
|
warnings.warn("%s: %s" % (self.prog, message))
|
|
125
178
|
|
|
126
|
-
def warnAboutUnrecognizedOption(self, option):
|
|
179
|
+
def warnAboutUnrecognizedOption(self, option: Any) -> None:
|
|
180
|
+
"""Warn about an unrecognized option."""
|
|
127
181
|
self.warn("unrecognized option %r" % option)
|
|
128
182
|
|
|
129
|
-
def warnAboutInvalidOption(self, option):
|
|
183
|
+
def warnAboutInvalidOption(self, option: Any) -> None:
|
|
184
|
+
"""Warn about an invalid option."""
|
|
130
185
|
self.warn("invalid option -- %r" % option)
|
|
131
186
|
|
|
132
|
-
def
|
|
187
|
+
def warnAboutAmbiguousOption(self, option: Any, possibilities: Iterable) -> None:
|
|
188
|
+
"""Warn about an ambiguous option."""
|
|
133
189
|
msg = "option %r is ambiguous; possibilities:" % option
|
|
134
190
|
for x in possibilities:
|
|
135
191
|
msg += " %r" % x
|
|
136
192
|
self.warn(msg)
|
|
137
193
|
|
|
138
|
-
def
|
|
194
|
+
def warnAboutUnallowedArgument(self, option: Any) -> None:
|
|
195
|
+
"""Warn about an unallowed argument."""
|
|
139
196
|
self.warn("option %r doesn't allow an argument" % option)
|
|
140
197
|
|
|
141
|
-
def warnAboutRequiredArgument(self, option):
|
|
198
|
+
def warnAboutRequiredArgument(self, option: Any) -> None:
|
|
199
|
+
"""Warn about a required argument."""
|
|
142
200
|
self.warn("option requires an argument -- %r" % option)
|
|
143
201
|
|
|
144
202
|
|
|
145
203
|
@dataclasses.dataclass
|
|
146
|
-
class
|
|
147
|
-
parser: Any
|
|
148
|
-
cmd: Any
|
|
149
|
-
ctx: Any
|
|
150
|
-
|
|
151
|
-
def __call__(self, target: Any):
|
|
152
|
-
if isinstance(target, types.FunctionType):
|
|
153
|
-
return self._f(target)
|
|
154
|
-
elif isinstance(target, types.MethodType):
|
|
155
|
-
return self._m(target)
|
|
156
|
-
elif isinstance(target, type):
|
|
157
|
-
return self._t(target)
|
|
158
|
-
else:
|
|
159
|
-
return self._o(target)
|
|
160
|
-
|
|
161
|
-
def _f(self, target):
|
|
162
|
-
@functools.wraps(target)
|
|
163
|
-
def ans(cmd, ctx, args):
|
|
164
|
-
p = self.parser.copy()
|
|
165
|
-
if self.cmd:
|
|
166
|
-
p.clickCommand(cmd)
|
|
167
|
-
if self.ctx:
|
|
168
|
-
p.clickContext(ctx)
|
|
169
|
-
return target(cmd, ctx, p.parse_args(args))
|
|
170
|
-
|
|
171
|
-
return ans
|
|
172
|
-
|
|
173
|
-
def _m(self, target):
|
|
174
|
-
func = self._f(target.__func__)
|
|
175
|
-
ans = types.MethodType(func, target.__self__)
|
|
176
|
-
return ans
|
|
177
|
-
|
|
178
|
-
def _t(self, target):
|
|
179
|
-
target.parse_args = self._f(target.parse_args)
|
|
180
|
-
return target
|
|
181
|
-
|
|
182
|
-
def _o(self, target):
|
|
183
|
-
target.parse_args = self._m(target.parse_args)
|
|
184
|
-
return target
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
@dataclasses.dataclass
|
|
188
|
-
class _Parsing:
|
|
204
|
+
class Parsing:
|
|
189
205
|
parser: PreParser
|
|
190
206
|
args: list[str]
|
|
191
207
|
|
|
192
|
-
def __post_init__(self):
|
|
208
|
+
def __post_init__(self) -> None:
|
|
193
209
|
self.ans = list()
|
|
194
210
|
self.spec = list()
|
|
195
211
|
optn = 0
|
|
@@ -197,10 +213,14 @@ class _Parsing:
|
|
|
197
213
|
optn = self.tick(optn)
|
|
198
214
|
if optn == 1:
|
|
199
215
|
self.parser.warnAboutRequiredArgument(self.ans[-1])
|
|
216
|
+
self.dumpspec()
|
|
217
|
+
|
|
218
|
+
def dumpspec(self):
|
|
200
219
|
self.ans += self.spec
|
|
220
|
+
self.spec.clear()
|
|
201
221
|
|
|
202
222
|
@functools.cached_property
|
|
203
|
-
def islongonly(self):
|
|
223
|
+
def islongonly(self) -> bool:
|
|
204
224
|
for k in self.optdict.keys():
|
|
205
225
|
if len(k) < 3:
|
|
206
226
|
continue
|
|
@@ -212,7 +232,7 @@ class _Parsing:
|
|
|
212
232
|
return False
|
|
213
233
|
|
|
214
234
|
@functools.cached_property
|
|
215
|
-
def optdict(self):
|
|
235
|
+
def optdict(self) -> Dict[str, Nargs]:
|
|
216
236
|
ans = dict()
|
|
217
237
|
for k, v in self.parser.optdict.items():
|
|
218
238
|
ans[str(k)] = Nargs(v)
|
|
@@ -242,21 +262,13 @@ class _Parsing:
|
|
|
242
262
|
return "break"
|
|
243
263
|
elif arg.startswith("-") and arg != "-":
|
|
244
264
|
if arg.startswith("--") or self.islongonly:
|
|
245
|
-
return self.
|
|
265
|
+
return self.tick_opt_long(arg)
|
|
246
266
|
else:
|
|
247
|
-
return self.
|
|
267
|
+
return self.tick_opt_short(arg)
|
|
248
268
|
else:
|
|
249
|
-
|
|
250
|
-
self.spec.append(arg)
|
|
251
|
-
return "break"
|
|
252
|
-
elif self.parser.permutate:
|
|
253
|
-
self.spec.append(arg)
|
|
254
|
-
return 0
|
|
255
|
-
else:
|
|
256
|
-
self.ans.append(arg)
|
|
257
|
-
return 0
|
|
269
|
+
return self.tick_pos(arg)
|
|
258
270
|
|
|
259
|
-
def
|
|
271
|
+
def tick_opt_long(self, arg: str):
|
|
260
272
|
try:
|
|
261
273
|
i = arg.index("=")
|
|
262
274
|
except ValueError:
|
|
@@ -268,7 +280,7 @@ class _Parsing:
|
|
|
268
280
|
self.ans.append(arg)
|
|
269
281
|
return 0
|
|
270
282
|
if len(possibilities) > 1:
|
|
271
|
-
self.parser.
|
|
283
|
+
self.parser.warnAboutAmbiguousOption(arg, possibilities)
|
|
272
284
|
self.ans.append(arg)
|
|
273
285
|
return 0
|
|
274
286
|
opt = possibilities[0]
|
|
@@ -278,12 +290,12 @@ class _Parsing:
|
|
|
278
290
|
self.ans.append(arg)
|
|
279
291
|
if "=" in arg:
|
|
280
292
|
if self.optdict[opt] == 0:
|
|
281
|
-
self.parser.
|
|
293
|
+
self.parser.warnAboutUnallowedArgument(opt)
|
|
282
294
|
return 0
|
|
283
295
|
else:
|
|
284
296
|
return self.optdict[opt]
|
|
285
297
|
|
|
286
|
-
def
|
|
298
|
+
def tick_opt_short(self, arg: str):
|
|
287
299
|
self.ans.append(arg)
|
|
288
300
|
for i in range(1 - len(arg), 0):
|
|
289
301
|
optn = self.optdict.get("-" + arg[i])
|
|
@@ -295,3 +307,14 @@ class _Parsing:
|
|
|
295
307
|
if i == -1 and optn == 1:
|
|
296
308
|
return 1
|
|
297
309
|
return 0
|
|
310
|
+
|
|
311
|
+
def tick_pos(self, arg: str):
|
|
312
|
+
if self.parser.posix:
|
|
313
|
+
self.spec.append(arg)
|
|
314
|
+
return "break"
|
|
315
|
+
elif self.parser.permutate:
|
|
316
|
+
self.spec.append(arg)
|
|
317
|
+
return 0
|
|
318
|
+
else:
|
|
319
|
+
self.ans.append(arg)
|
|
320
|
+
return 0
|