c2e 1.dev6__tar.gz → 1.dev8__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.
- {c2e-1.dev6/src/c2e.egg-info → c2e-1.dev8}/PKG-INFO +1 -1
- {c2e-1.dev6 → c2e-1.dev8}/pyproject.toml +1 -1
- {c2e-1.dev6 → c2e-1.dev8}/src/c2e/dsl.py +77 -33
- {c2e-1.dev6 → c2e-1.dev8/src/c2e.egg-info}/PKG-INFO +1 -1
- {c2e-1.dev6 → c2e-1.dev8}/LICENSE +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/README.md +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/setup.cfg +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/src/c2e/__init__.py +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/src/c2e/colors.py +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/src/c2e/core.py +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/src/c2e/dispatch.py +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/src/c2e.egg-info/SOURCES.txt +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/src/c2e.egg-info/dependency_links.txt +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/src/c2e.egg-info/requires.txt +0 -0
- {c2e-1.dev6 → c2e-1.dev8}/src/c2e.egg-info/top_level.txt +0 -0
|
@@ -3,9 +3,11 @@ import inspect
|
|
|
3
3
|
|
|
4
4
|
from mapres import res
|
|
5
5
|
|
|
6
|
-
|
|
7
6
|
COMMANDS = {}
|
|
8
7
|
|
|
8
|
+
# ------------------------------------------------------------
|
|
9
|
+
# Shared metadata structures
|
|
10
|
+
# ------------------------------------------------------------
|
|
9
11
|
|
|
10
12
|
@dataclass
|
|
11
13
|
class ParamSpec:
|
|
@@ -15,14 +17,12 @@ class ParamSpec:
|
|
|
15
17
|
func: callable
|
|
16
18
|
desc: str | None
|
|
17
19
|
|
|
18
|
-
|
|
19
20
|
@dataclass
|
|
20
21
|
class FlagSpec:
|
|
21
22
|
name: str
|
|
22
23
|
func: callable
|
|
23
24
|
desc: str | None
|
|
24
25
|
|
|
25
|
-
|
|
26
26
|
@dataclass
|
|
27
27
|
class ArgMeta:
|
|
28
28
|
name: str
|
|
@@ -32,28 +32,38 @@ class ArgMeta:
|
|
|
32
32
|
required_flags: set[str]
|
|
33
33
|
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
# ------------------------------------------------------------
|
|
36
|
+
# Base class for CommandSpec and ChildSpec
|
|
37
|
+
# ------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
class BaseSpec:
|
|
40
|
+
def __init__(self, func):
|
|
39
41
|
self.func = func
|
|
40
42
|
self.params = {}
|
|
41
43
|
self.flags = {}
|
|
42
44
|
self.args_meta = {}
|
|
43
45
|
self.desc = self._doc(func)
|
|
46
|
+
|
|
44
47
|
self._extract_args_block()
|
|
45
48
|
self._parse_args_meta()
|
|
46
49
|
self._infer_arg_requirement()
|
|
47
50
|
|
|
51
|
+
# ------------------------------
|
|
52
|
+
# Docstring extraction
|
|
53
|
+
# ------------------------------
|
|
48
54
|
def _doc(self, f):
|
|
49
55
|
d = f.__doc__
|
|
50
56
|
return d.strip().splitlines()[0].strip() if d else None
|
|
51
57
|
|
|
58
|
+
# ------------------------------
|
|
59
|
+
# __args__ block extraction
|
|
60
|
+
# ------------------------------
|
|
52
61
|
def _extract_args_block(self):
|
|
53
62
|
src = inspect.getsource(self.func)
|
|
54
63
|
lines = src.splitlines()
|
|
55
64
|
block = []
|
|
56
65
|
in_block = False
|
|
66
|
+
|
|
57
67
|
for line in lines:
|
|
58
68
|
s = line.strip()
|
|
59
69
|
if s.startswith('__args__'):
|
|
@@ -66,18 +76,24 @@ class ChildSpec:
|
|
|
66
76
|
else:
|
|
67
77
|
break
|
|
68
78
|
block.append(line)
|
|
79
|
+
|
|
69
80
|
if block:
|
|
70
81
|
raw = '\n'.join(l.strip() for l in block)
|
|
71
82
|
setattr(self.func, '__args__', raw)
|
|
72
83
|
|
|
84
|
+
# ------------------------------
|
|
85
|
+
# Parse __args__ metadata
|
|
86
|
+
# ------------------------------
|
|
73
87
|
def _parse_args_meta(self):
|
|
74
88
|
raw = getattr(self.func, '__args__', None)
|
|
75
89
|
if not raw:
|
|
76
90
|
return
|
|
91
|
+
|
|
77
92
|
for line in raw.splitlines():
|
|
78
93
|
s = line.strip()
|
|
79
94
|
if not s:
|
|
80
95
|
continue
|
|
96
|
+
|
|
81
97
|
if ':' in s:
|
|
82
98
|
arg, rest = s.split(':', 1)
|
|
83
99
|
arg = arg.strip()
|
|
@@ -85,15 +101,18 @@ class ChildSpec:
|
|
|
85
101
|
else:
|
|
86
102
|
arg = s
|
|
87
103
|
tokens = []
|
|
104
|
+
|
|
88
105
|
params = []
|
|
89
106
|
flags = []
|
|
90
107
|
req_p = set()
|
|
91
108
|
req_f = set()
|
|
109
|
+
|
|
92
110
|
for t in tokens:
|
|
93
111
|
required = True
|
|
94
112
|
if t.startswith('[') and t.endswith(']'):
|
|
95
113
|
required = False
|
|
96
114
|
t = t[1:-1].strip()
|
|
115
|
+
|
|
97
116
|
if t.startswith('--'):
|
|
98
117
|
f = t[2:]
|
|
99
118
|
flags.append(f)
|
|
@@ -103,11 +122,16 @@ class ChildSpec:
|
|
|
103
122
|
params.append(t)
|
|
104
123
|
if required:
|
|
105
124
|
req_p.add(t)
|
|
125
|
+
|
|
106
126
|
self.args_meta[arg] = ArgMeta(arg, params, flags, req_p, req_f)
|
|
107
127
|
|
|
128
|
+
# ------------------------------
|
|
129
|
+
# Infer required/optional positional arg
|
|
130
|
+
# ------------------------------
|
|
108
131
|
def _infer_arg_requirement(self):
|
|
109
132
|
sig = inspect.signature(self.func)
|
|
110
133
|
ps = list(sig.parameters.values())
|
|
134
|
+
|
|
111
135
|
if len(ps) == 1:
|
|
112
136
|
self.requires_arg = False
|
|
113
137
|
self.optional_arg = False
|
|
@@ -123,6 +147,9 @@ class ChildSpec:
|
|
|
123
147
|
self.requires_arg = False
|
|
124
148
|
self.optional_arg = False
|
|
125
149
|
|
|
150
|
+
# ------------------------------
|
|
151
|
+
# Param decorator
|
|
152
|
+
# ------------------------------
|
|
126
153
|
def param(self, name, type=str, default=None):
|
|
127
154
|
def deco(f):
|
|
128
155
|
py = name.replace('-', '_')
|
|
@@ -131,6 +158,9 @@ class ChildSpec:
|
|
|
131
158
|
return f
|
|
132
159
|
return deco
|
|
133
160
|
|
|
161
|
+
# ------------------------------
|
|
162
|
+
# Flag decorator
|
|
163
|
+
# ------------------------------
|
|
134
164
|
def flag(self, name):
|
|
135
165
|
def deco(f):
|
|
136
166
|
py = name.replace('-', '_')
|
|
@@ -140,35 +170,27 @@ class ChildSpec:
|
|
|
140
170
|
return deco
|
|
141
171
|
|
|
142
172
|
|
|
143
|
-
|
|
144
|
-
|
|
173
|
+
# ------------------------------------------------------------
|
|
174
|
+
# ChildSpec (inherits BaseSpec)
|
|
175
|
+
# ------------------------------------------------------------
|
|
176
|
+
|
|
177
|
+
class ChildSpec(BaseSpec):
|
|
178
|
+
def __init__(self, parent, name, func):
|
|
179
|
+
self.parent = parent
|
|
145
180
|
self.name = name
|
|
146
|
-
|
|
147
|
-
self.children = {}
|
|
148
|
-
self.params = {}
|
|
149
|
-
self.flags = {}
|
|
150
|
-
self.desc = self._doc(func)
|
|
151
|
-
self.is_namespace = namespace
|
|
181
|
+
super().__init__(func)
|
|
152
182
|
|
|
153
|
-
def _doc(self, f):
|
|
154
|
-
d = f.__doc__
|
|
155
|
-
return d.strip().splitlines()[0].strip() if d else None
|
|
156
183
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
d = f.__doc__.strip().splitlines()[0].strip() if f.__doc__ else None
|
|
161
|
-
self.params[py] = ParamSpec(name, type, default, f, d)
|
|
162
|
-
return f
|
|
163
|
-
return deco
|
|
184
|
+
# ------------------------------------------------------------
|
|
185
|
+
# CommandSpec (inherits BaseSpec)
|
|
186
|
+
# ------------------------------------------------------------
|
|
164
187
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
return deco
|
|
188
|
+
class CommandSpec(BaseSpec):
|
|
189
|
+
def __init__(self, name, func, namespace=False):
|
|
190
|
+
self.name = name
|
|
191
|
+
self.children = {}
|
|
192
|
+
self.is_namespace = namespace
|
|
193
|
+
super().__init__(func)
|
|
172
194
|
|
|
173
195
|
def child(self, name):
|
|
174
196
|
def deco(f):
|
|
@@ -179,6 +201,10 @@ class CommandSpec:
|
|
|
179
201
|
return deco
|
|
180
202
|
|
|
181
203
|
|
|
204
|
+
# ------------------------------------------------------------
|
|
205
|
+
# DSL entry point
|
|
206
|
+
# ------------------------------------------------------------
|
|
207
|
+
|
|
182
208
|
class CommandDSL:
|
|
183
209
|
def __call__(self, name, namespace=False):
|
|
184
210
|
def deco(f):
|
|
@@ -187,10 +213,13 @@ class CommandDSL:
|
|
|
187
213
|
return spec
|
|
188
214
|
return deco
|
|
189
215
|
|
|
190
|
-
|
|
191
216
|
command = CommandDSL()
|
|
192
217
|
|
|
193
218
|
|
|
219
|
+
# ------------------------------------------------------------
|
|
220
|
+
# ParsedArgs structure
|
|
221
|
+
# ------------------------------------------------------------
|
|
222
|
+
|
|
194
223
|
@dataclass
|
|
195
224
|
class ParsedArgs:
|
|
196
225
|
sub: str | None
|
|
@@ -199,15 +228,21 @@ class ParsedArgs:
|
|
|
199
228
|
params: dict[str, str]
|
|
200
229
|
|
|
201
230
|
|
|
231
|
+
# ------------------------------------------------------------
|
|
232
|
+
# Line parser
|
|
233
|
+
# ------------------------------------------------------------
|
|
234
|
+
|
|
202
235
|
def parse_line(raw):
|
|
203
236
|
raw = raw.strip()
|
|
204
237
|
if not raw:
|
|
205
238
|
return ParsedArgs(None, [], {}, {})
|
|
239
|
+
|
|
206
240
|
parts = raw.split()
|
|
207
241
|
sub = parts[0]
|
|
208
242
|
pos = []
|
|
209
243
|
flags = {}
|
|
210
244
|
params = {}
|
|
245
|
+
|
|
211
246
|
for t in parts[1:]:
|
|
212
247
|
if t.startswith('--'):
|
|
213
248
|
flags[t[2:]] = True
|
|
@@ -216,9 +251,14 @@ def parse_line(raw):
|
|
|
216
251
|
params[k.lower()] = v
|
|
217
252
|
else:
|
|
218
253
|
pos.append(t)
|
|
254
|
+
|
|
219
255
|
return ParsedArgs(sub, pos, flags, params)
|
|
220
256
|
|
|
221
257
|
|
|
258
|
+
# ------------------------------------------------------------
|
|
259
|
+
# Help generation (unchanged)
|
|
260
|
+
# ------------------------------------------------------------
|
|
261
|
+
|
|
222
262
|
def help_command(cmd):
|
|
223
263
|
lines = []
|
|
224
264
|
d = cmd.desc or 'No description'
|
|
@@ -309,6 +349,7 @@ def help_arg(child, meta):
|
|
|
309
349
|
u = res(f'<aqua>Usage:<reset> <gold>{p}<reset> <green>{child.name}<reset> <aqua>{a}<reset>')
|
|
310
350
|
req = []
|
|
311
351
|
opt = []
|
|
352
|
+
|
|
312
353
|
for pn in meta.params:
|
|
313
354
|
ps = child.params.get(pn)
|
|
314
355
|
t = ps.type_.__name__ if ps else 'str'
|
|
@@ -316,12 +357,15 @@ def help_arg(child, meta):
|
|
|
316
357
|
req.append(res(f'<dark_gray>\\<<reset>{pn}:{t}<dark_gray>\\><reset>'))
|
|
317
358
|
else:
|
|
318
359
|
opt.append(res(f'<dark_gray>[<reset>{pn}:{t}<dark_gray>]<reset>'))
|
|
360
|
+
|
|
319
361
|
if req:
|
|
320
362
|
u += ' ' + ' '.join(req)
|
|
321
363
|
if opt:
|
|
322
364
|
u += ' ' + ' '.join(opt)
|
|
365
|
+
|
|
323
366
|
if meta.flags:
|
|
324
367
|
u += res(' <dark_gray>[<reset>--flags<dark_gray>]<reset>')
|
|
368
|
+
|
|
325
369
|
lines.append(u)
|
|
326
370
|
|
|
327
371
|
if meta.params:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|