rainbow-rb-utils 0.0.9.dev5__tar.gz → 0.0.9.dev7__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.
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/PKG-INFO +2 -2
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/pyproject.toml +2 -2
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/file.py +3 -3
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/flow_manager.py +120 -59
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/manipulate.py +10 -10
- rainbow_rb_utils-0.0.9.dev7/src/rainbow/rb_utils/path_utils.py +29 -0
- rainbow_rb_utils-0.0.9.dev7/src/rainbow/rb_utils/program.py +12 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow_rb_utils.egg-info/PKG-INFO +2 -2
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow_rb_utils.egg-info/SOURCES.txt +2 -0
- rainbow_rb_utils-0.0.9.dev7/src/rainbow_rb_utils.egg-info/requires.txt +2 -0
- rainbow_rb_utils-0.0.9.dev5/src/rainbow_rb_utils.egg-info/requires.txt +0 -2
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/README.md +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/setup.cfg +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/__init__.py +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/asyncio_helper.py +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/date.py +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/helper.py +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/pagination.py +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/parser.py +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/py.typed +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/service_exception.py +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow_rb_utils.egg-info/dependency_links.txt +0 -0
- {rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow_rb_utils.egg-info/top_level.txt +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rainbow-rb-utils
|
|
3
|
-
Version: 0.0.9.
|
|
3
|
+
Version: 0.0.9.dev7
|
|
4
4
|
Summary: Rainbow Python Utilities
|
|
5
5
|
Author-email: Derek <dfd1123@rainbow-robotics.com>
|
|
6
6
|
Requires-Python: <3.13,>=3.12
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
Requires-Dist: psutil<8.0.0,>=7.0.0
|
|
9
|
-
Requires-Dist: rainbow-rb-log==0.0.9.
|
|
9
|
+
Requires-Dist: rainbow-rb-log==0.0.9.dev7
|
|
10
10
|
|
|
11
11
|
# rb_utils
|
|
12
12
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "rainbow-rb-utils"
|
|
7
|
-
version = "0.0.9.
|
|
7
|
+
version = "0.0.9.dev7"
|
|
8
8
|
requires-python = ">=3.12,<3.13"
|
|
9
9
|
description = "Rainbow Python Utilities"
|
|
10
10
|
authors = [
|
|
@@ -14,7 +14,7 @@ readme = "README.md"
|
|
|
14
14
|
|
|
15
15
|
dependencies = [
|
|
16
16
|
"psutil>=7.0.0,<8.0.0",
|
|
17
|
-
"rainbow-rb-log==0.0.9.
|
|
17
|
+
"rainbow-rb-log==0.0.9.dev7",
|
|
18
18
|
]
|
|
19
19
|
|
|
20
20
|
[tool.setuptools]
|
|
@@ -33,9 +33,9 @@ def get_env_path() -> Path | None:
|
|
|
33
33
|
meipass = getattr(sys, "_MEIPASS", None)
|
|
34
34
|
if meipass:
|
|
35
35
|
base = Path(meipass)
|
|
36
|
-
candidate
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
for candidate in [base / ".env", base / "rb_resources" / ".env"]:
|
|
37
|
+
if candidate.exists():
|
|
38
|
+
return candidate
|
|
39
39
|
|
|
40
40
|
# 개발 환경: __file__ 기준으로 위로 타고 올라가며 .env 검색
|
|
41
41
|
cur = Path(__file__).resolve()
|
{rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/flow_manager.py
RENAMED
|
@@ -59,58 +59,37 @@ ALLOWED_CONSTS = {
|
|
|
59
59
|
|
|
60
60
|
EXPLICIT_EXPR_PATTERN = re.compile(r"\$[A-Za-z_]\w*")
|
|
61
61
|
RB_GLOBAL_PATTERN = re.compile(r"\bRB_[A-Za-z_0-9]*\b")
|
|
62
|
+
GET_VAR_PATTERN = re.compile(r"\bget_var\s*\(")
|
|
62
63
|
|
|
63
64
|
|
|
64
65
|
def safe_eval_expr(
|
|
65
66
|
expr: Any,
|
|
66
67
|
variables: dict[str, dict[str, Any]] | None = None,
|
|
67
68
|
get_global_variable: Callable[[str], Any] | None = None,
|
|
69
|
+
get_var: Callable[..., Any] | None = None,
|
|
68
70
|
) -> Any:
|
|
69
71
|
if not isinstance(expr, str):
|
|
70
72
|
return expr
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
if variables is None:
|
|
75
|
+
vars_ = {"local": {}, "global": {}}
|
|
76
|
+
elif isinstance(variables.get("local"), dict) or isinstance(variables.get("global"), dict):
|
|
77
|
+
vars_ = variables
|
|
78
|
+
else:
|
|
79
|
+
vars_ = {"local": variables, "global": {}}
|
|
73
80
|
s = expr.strip()
|
|
74
81
|
if not s:
|
|
75
82
|
return ""
|
|
76
83
|
|
|
77
|
-
is_explicit_expression = bool(EXPLICIT_EXPR_PATTERN.search(s) or RB_GLOBAL_PATTERN.search(s))
|
|
84
|
+
is_explicit_expression = bool(EXPLICIT_EXPR_PATTERN.search(s) or RB_GLOBAL_PATTERN.search(s) or GET_VAR_PATTERN.search(s))
|
|
78
85
|
normalized = EXPLICIT_EXPR_PATTERN.sub(lambda match: match.group()[1:], s)
|
|
79
86
|
|
|
80
|
-
# --- 증감(식 전체일 때만 허용) ---------------------------------------------
|
|
81
|
-
inc_post = re.match(r"^([A-Za-z_]\w*)\s*\+\+$", s) # a++
|
|
82
|
-
dec_post = re.match(r"^([A-Za-z_]\w*)\s*--$", s) # a--
|
|
83
|
-
inc_pre = re.match(r"^\+\+\s*([A-Za-z_]\w*)$", s) # ++a
|
|
84
|
-
dec_pre = re.match(r"^--\s*([A-Za-z_]\w*)$", s) # --a
|
|
85
|
-
match = inc_post or dec_post or inc_pre or dec_pre
|
|
86
|
-
if match:
|
|
87
|
-
name = match.group(1)
|
|
88
|
-
exists = name in vars_.get("local", {}) or name in vars_.get("global", {})
|
|
89
|
-
cur: int | None = (
|
|
90
|
-
vars_.get("local", {}).get(name)
|
|
91
|
-
if name in vars_.get("local", {})
|
|
92
|
-
else vars_.get("global", {}).get(name, 0)
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
if cur is None:
|
|
96
|
-
raise ValueError(f"variable {name} not found")
|
|
97
|
-
|
|
98
|
-
if inc_post:
|
|
99
|
-
vars_.setdefault("local", {})[name] = cur + 1 if exists else 1
|
|
100
|
-
return cur
|
|
101
|
-
if dec_post:
|
|
102
|
-
vars_.setdefault("local", {})[name] = cur - 1 if exists else -1
|
|
103
|
-
return cur
|
|
104
|
-
if inc_pre:
|
|
105
|
-
v = cur + 1 if exists else 1
|
|
106
|
-
vars_.setdefault("local", {})[name] = v
|
|
107
|
-
return v
|
|
108
|
-
if dec_pre:
|
|
109
|
-
v = cur - 1 if exists else -1
|
|
110
|
-
vars_.setdefault("local", {})[name] = v
|
|
111
|
-
return v
|
|
112
|
-
|
|
113
87
|
# --- 내부 평가기 ------------------------------------------------------------
|
|
88
|
+
def _increment_value(cur: Any, delta: int, target_expr: str) -> Any:
|
|
89
|
+
if not isinstance(cur, int | float) or isinstance(cur, bool):
|
|
90
|
+
raise ValueError(f"increment target must be numeric: {target_expr}")
|
|
91
|
+
return cur + delta
|
|
92
|
+
|
|
114
93
|
def _eval(node: ast.AST) -> Any:
|
|
115
94
|
if isinstance(node, ast.Constant):
|
|
116
95
|
return node.value
|
|
@@ -197,6 +176,16 @@ def safe_eval_expr(
|
|
|
197
176
|
return any(_eval(v) for v in node.values)
|
|
198
177
|
|
|
199
178
|
if isinstance(node, ast.Call):
|
|
179
|
+
if isinstance(node.func, ast.Name) and node.func.id == "get_var":
|
|
180
|
+
if get_var is None:
|
|
181
|
+
raise ValueError("get_var is not available in this context")
|
|
182
|
+
if len(node.args) not in (2, 3):
|
|
183
|
+
raise ValueError("get_var requires 2 or 3 arguments: get_var(pid_or_model, var_name[, default])")
|
|
184
|
+
pid_or_model = _eval(node.args[0])
|
|
185
|
+
var_name = _eval(node.args[1])
|
|
186
|
+
if len(node.args) == 3:
|
|
187
|
+
return get_var(pid_or_model, var_name, _eval(node.args[2]))
|
|
188
|
+
return get_var(pid_or_model, var_name)
|
|
200
189
|
fn = _eval(node.func)
|
|
201
190
|
if fn not in ALLOWED_CALLABLES:
|
|
202
191
|
raise ValueError(f"function not allowed: {fn}")
|
|
@@ -220,6 +209,94 @@ def safe_eval_expr(
|
|
|
220
209
|
|
|
221
210
|
raise ValueError(f"unsupported expression: {ast.dump(node)}")
|
|
222
211
|
|
|
212
|
+
def _eval_subscript_key(node: ast.Subscript) -> Any:
|
|
213
|
+
sl = node.slice
|
|
214
|
+
if isinstance(sl, ast.Slice):
|
|
215
|
+
lo = _eval(sl.lower) if sl.lower else None
|
|
216
|
+
up = _eval(sl.upper) if sl.upper else None
|
|
217
|
+
st = _eval(sl.step) if sl.step else None
|
|
218
|
+
return slice(lo, up, st)
|
|
219
|
+
return _eval(sl)
|
|
220
|
+
|
|
221
|
+
def _apply_increment(target_expr: str, *, delta: int, is_prefix: bool) -> Any:
|
|
222
|
+
try:
|
|
223
|
+
target = ast.parse(target_expr, mode="eval").body
|
|
224
|
+
except SyntaxError:
|
|
225
|
+
raise ValueError(f"invalid increment target: {target_expr}") from None
|
|
226
|
+
|
|
227
|
+
if isinstance(target, ast.Name):
|
|
228
|
+
name = target.id
|
|
229
|
+
exists = name in vars_.get("local", {}) or name in vars_.get("global", {})
|
|
230
|
+
cur = (
|
|
231
|
+
vars_.get("local", {}).get(name)
|
|
232
|
+
if name in vars_.get("local", {})
|
|
233
|
+
else vars_.get("global", {}).get(name, 0)
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
if cur is None:
|
|
237
|
+
raise ValueError(f"variable {name} not found")
|
|
238
|
+
|
|
239
|
+
new_val = _increment_value(cur, delta, target_expr) if exists else delta
|
|
240
|
+
vars_.setdefault("local", {})[name] = new_val
|
|
241
|
+
return new_val if is_prefix else cur
|
|
242
|
+
|
|
243
|
+
if isinstance(target, ast.Subscript):
|
|
244
|
+
container = _eval(target.value)
|
|
245
|
+
key = _eval_subscript_key(target)
|
|
246
|
+
cur = container[key]
|
|
247
|
+
if cur is None:
|
|
248
|
+
raise ValueError(f"target {target_expr} not found")
|
|
249
|
+
|
|
250
|
+
new_val = _increment_value(cur, delta, target_expr)
|
|
251
|
+
container[key] = new_val
|
|
252
|
+
return new_val if is_prefix else cur
|
|
253
|
+
|
|
254
|
+
raise ValueError("only variable or subscript increment targets are allowed")
|
|
255
|
+
|
|
256
|
+
def _get_assign_target_value(target: ast.AST) -> Any:
|
|
257
|
+
if isinstance(target, ast.Name):
|
|
258
|
+
name = target.id
|
|
259
|
+
if name in vars_.get("local", {}):
|
|
260
|
+
return vars_["local"][name]
|
|
261
|
+
if name in vars_.get("global", {}):
|
|
262
|
+
return vars_["global"][name]
|
|
263
|
+
return 0
|
|
264
|
+
|
|
265
|
+
if isinstance(target, ast.Subscript):
|
|
266
|
+
container = _eval(target.value)
|
|
267
|
+
return container[_eval_subscript_key(target)]
|
|
268
|
+
|
|
269
|
+
raise ValueError("only variable or subscript assignment targets are allowed")
|
|
270
|
+
|
|
271
|
+
def _set_assign_target_value(target: ast.AST, value: Any) -> Any:
|
|
272
|
+
if isinstance(target, ast.Name):
|
|
273
|
+
vars_.setdefault("local", {})[target.id] = value
|
|
274
|
+
return value
|
|
275
|
+
|
|
276
|
+
if isinstance(target, ast.Subscript):
|
|
277
|
+
container = _eval(target.value)
|
|
278
|
+
container[_eval_subscript_key(target)] = value
|
|
279
|
+
return value
|
|
280
|
+
|
|
281
|
+
raise ValueError("only variable or subscript assignment targets are allowed")
|
|
282
|
+
|
|
283
|
+
# --- 증감(식 전체일 때만 허용) ---------------------------------------------
|
|
284
|
+
inc_target_pattern = r"([A-Za-z_]\w*(?:\s*\[[^\]]+\])*)"
|
|
285
|
+
inc_post = re.match(rf"^{inc_target_pattern}\s*\+\+$", normalized) # a++, a[0]++
|
|
286
|
+
dec_post = re.match(rf"^{inc_target_pattern}\s*--$", normalized) # a--, a[0]--
|
|
287
|
+
inc_pre = re.match(rf"^\+\+\s*{inc_target_pattern}$", normalized) # ++a, ++a[0]
|
|
288
|
+
dec_pre = re.match(rf"^--\s*{inc_target_pattern}$", normalized) # --a, --a[0]
|
|
289
|
+
match = inc_post or dec_post or inc_pre or dec_pre
|
|
290
|
+
if match:
|
|
291
|
+
if inc_post:
|
|
292
|
+
return _apply_increment(match.group(1).strip(), delta=1, is_prefix=False)
|
|
293
|
+
if dec_post:
|
|
294
|
+
return _apply_increment(match.group(1).strip(), delta=-1, is_prefix=False)
|
|
295
|
+
if inc_pre:
|
|
296
|
+
return _apply_increment(match.group(1).strip(), delta=1, is_prefix=True)
|
|
297
|
+
if dec_pre:
|
|
298
|
+
return _apply_increment(match.group(1).strip(), delta=-1, is_prefix=True)
|
|
299
|
+
|
|
223
300
|
# --- 단순 대입: a = <expr> (한 문장만 허용) ---------------------------------
|
|
224
301
|
try:
|
|
225
302
|
mod = ast.parse(normalized, mode="exec")
|
|
@@ -229,27 +306,11 @@ def safe_eval_expr(
|
|
|
229
306
|
# 1) 단순 대입: a = <expr>
|
|
230
307
|
if isinstance(stmt, ast.Assign):
|
|
231
308
|
tgt = stmt.targets[0]
|
|
232
|
-
if not isinstance(tgt, ast.Name):
|
|
233
|
-
raise ValueError("only simple assignment like `a = <expr>` is allowed")
|
|
234
309
|
val = _eval(stmt.value)
|
|
235
|
-
|
|
236
|
-
return val
|
|
310
|
+
return _set_assign_target_value(tgt, val)
|
|
237
311
|
|
|
238
312
|
# 2) 복합 대입: a *= <expr> (+=, -=, /= ... 포함)
|
|
239
313
|
if isinstance(stmt, ast.AugAssign):
|
|
240
|
-
if not isinstance(stmt.target, ast.Name):
|
|
241
|
-
raise ValueError("only simple aug assignment like `a *= <expr>` is allowed")
|
|
242
|
-
|
|
243
|
-
name = stmt.target.id
|
|
244
|
-
|
|
245
|
-
# 현재값 가져오기 (local 우선, 없으면 global, 그래도 없으면 0)
|
|
246
|
-
if name in vars_.get("local", {}):
|
|
247
|
-
cur = vars_["local"][name]
|
|
248
|
-
elif name in vars_.get("global", {}):
|
|
249
|
-
cur = vars_["global"][name]
|
|
250
|
-
else:
|
|
251
|
-
cur = 0
|
|
252
|
-
|
|
253
314
|
try:
|
|
254
315
|
bin_fn = BIN_OPS[type(stmt.op)]
|
|
255
316
|
except KeyError:
|
|
@@ -257,12 +318,10 @@ def safe_eval_expr(
|
|
|
257
318
|
f"unsupported operator in aug-assign: {type(stmt.op)}"
|
|
258
319
|
) from None
|
|
259
320
|
|
|
321
|
+
cur = _get_assign_target_value(stmt.target)
|
|
260
322
|
rhs = _eval(stmt.value)
|
|
261
323
|
new_val = bin_fn(cur, rhs)
|
|
262
|
-
|
|
263
|
-
# 로컬에 기록(네 증감 로직이랑 일관되게)
|
|
264
|
-
vars_.setdefault("local", {})[name] = new_val
|
|
265
|
-
return new_val
|
|
324
|
+
return _set_assign_target_value(stmt.target, new_val)
|
|
266
325
|
except SyntaxError:
|
|
267
326
|
pass # 표현식일 수 있으니 아래로 진행
|
|
268
327
|
except Exception as e:
|
|
@@ -341,6 +400,7 @@ def eval_value(
|
|
|
341
400
|
value: Any,
|
|
342
401
|
variables: dict[str, dict[str, Any]] | None = None,
|
|
343
402
|
get_global_variable: Callable[[str], Any] | None = None,
|
|
403
|
+
get_var: Callable[..., Any] | None = None,
|
|
344
404
|
) -> Any:
|
|
345
405
|
# 1) 문자열이면 → 기존 safe_eval_expr 호출
|
|
346
406
|
if isinstance(value, str):
|
|
@@ -348,26 +408,27 @@ def eval_value(
|
|
|
348
408
|
value,
|
|
349
409
|
variables=variables,
|
|
350
410
|
get_global_variable=get_global_variable,
|
|
411
|
+
get_var=get_var,
|
|
351
412
|
)
|
|
352
413
|
|
|
353
414
|
# 2) 리스트면 → 각 요소를 재귀적으로 평가
|
|
354
415
|
if isinstance(value, list):
|
|
355
416
|
return [
|
|
356
|
-
eval_value(v, variables=variables, get_global_variable=get_global_variable)
|
|
417
|
+
eval_value(v, variables=variables, get_global_variable=get_global_variable, get_var=get_var)
|
|
357
418
|
for v in value
|
|
358
419
|
]
|
|
359
420
|
|
|
360
421
|
# 3) 튜플도 동일
|
|
361
422
|
if isinstance(value, tuple):
|
|
362
423
|
return tuple(
|
|
363
|
-
eval_value(v, variables=variables, get_global_variable=get_global_variable)
|
|
424
|
+
eval_value(v, variables=variables, get_global_variable=get_global_variable, get_var=get_var)
|
|
364
425
|
for v in value
|
|
365
426
|
)
|
|
366
427
|
|
|
367
428
|
# 4) 딕셔너리면 → value만 재귀적으로 평가 (key는 그대로)
|
|
368
429
|
if isinstance(value, dict):
|
|
369
430
|
return {
|
|
370
|
-
k: eval_value(v, variables=variables, get_global_variable=get_global_variable)
|
|
431
|
+
k: eval_value(v, variables=variables, get_global_variable=get_global_variable, get_var=get_var)
|
|
371
432
|
for k, v in value.items()
|
|
372
433
|
}
|
|
373
434
|
|
{rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/manipulate.py
RENAMED
|
@@ -130,17 +130,17 @@ def parse_state_core_mv_to_dict(mv: memoryview) -> dict[str, object]:
|
|
|
130
130
|
return {
|
|
131
131
|
"heartBeat": obj.HeartBeat(),
|
|
132
132
|
"timestampUsecMono": obj.TimestampUsecMono(),
|
|
133
|
-
"jointQRef":
|
|
134
|
-
"jointQEnc":
|
|
135
|
-
"jointTEsti":
|
|
136
|
-
"jointTMeas":
|
|
137
|
-
"jointTemper":
|
|
138
|
-
"carteXRef":
|
|
139
|
-
"carteXEnc":
|
|
140
|
-
"carteSpeedRef":
|
|
141
|
-
"carteSpeedEnc":
|
|
133
|
+
"jointQRef": _numpy_or_list_to_list(obj.JointQRefAsNumpy()),
|
|
134
|
+
"jointQEnc": _numpy_or_list_to_list(obj.JointQEncAsNumpy()),
|
|
135
|
+
"jointTEsti": _numpy_or_list_to_list(obj.JointTEstiAsNumpy()),
|
|
136
|
+
"jointTMeas": _numpy_or_list_to_list(obj.JointTMeasAsNumpy()),
|
|
137
|
+
"jointTemper": _numpy_or_list_to_list(obj.JointTemperAsNumpy()),
|
|
138
|
+
"carteXRef": _numpy_or_list_to_list(obj.CarteXRefAsNumpy()),
|
|
139
|
+
"carteXEnc": _numpy_or_list_to_list(obj.CarteXEncAsNumpy()),
|
|
140
|
+
"carteSpeedRef": _numpy_or_list_to_list(obj.CarteSpeedRefAsNumpy()),
|
|
141
|
+
"carteSpeedEnc": _numpy_or_list_to_list(obj.CarteSpeedEncAsNumpy()),
|
|
142
142
|
"userfSelectionNo": obj.UserfSelectionNo(),
|
|
143
|
-
"userfXRef":
|
|
143
|
+
"userfXRef": _numpy_or_list_to_list(obj.UserfXRefAsNumpy()),
|
|
144
144
|
"toolSelectionNo": obj.ToolSelectionNo(),
|
|
145
145
|
"toolName": _parse_string(obj.ToolName()),
|
|
146
146
|
"toolTcpX": obj.ToolTcpX(),
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
PLACEHOLDER_PATTERN = r"{(\w+)}"
|
|
4
|
+
REGEX_PATTERN = r"(?P<\1>[^/]+)"
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def normalize_topic(topic: str) -> str:
|
|
8
|
+
# Normalize topic by removing leading/trailing slashes and collapsing multiple slashes, e.g. "/users/{user_id}/posts/{post_id}/" -> "users/{user_id}/posts/{post_id}"
|
|
9
|
+
parts = [part for part in topic.split("/") if part]
|
|
10
|
+
return "/".join(parts)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def is_match_path(path: str, regex: str) -> bool:
|
|
14
|
+
# Check if a path matches a path template with placeholders, e.g. "/users/123/posts/456" matches "/users/{user_id}/posts/{post_id}"
|
|
15
|
+
if not isinstance(path, str) or "{" not in path:
|
|
16
|
+
return False
|
|
17
|
+
regex_str = re.sub(PLACEHOLDER_PATTERN, REGEX_PATTERN, normalize_topic(path))
|
|
18
|
+
return re.fullmatch(regex_str, normalize_topic(regex)) is not None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def build_path_regex(path: str):
|
|
22
|
+
# Convert a path template with placeholders into a regex pattern, e.g. "/users/{user_id}/posts/{post_id}" -> re.compile(r"^/users/(?P<user_id>[^/]+)/posts/(?P<post_id>[^/]+)$")
|
|
23
|
+
regex_str = re.sub(PLACEHOLDER_PATTERN, REGEX_PATTERN, normalize_topic(path))
|
|
24
|
+
return re.compile(f"^{regex_str}$")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def extract_path_params(path: str) -> list[str]:
|
|
28
|
+
# Extract parameter names from a path template, e.g. "/users/{user_id}/posts/{post_id}" -> ["user_id", "post_id"]
|
|
29
|
+
return re.findall(PLACEHOLDER_PATTERN, path)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def get_task_id(args: Any | None) -> str:
|
|
5
|
+
if not args:
|
|
6
|
+
return "unknown_module"
|
|
7
|
+
|
|
8
|
+
# FlowManagerArgs 객체와 dict 입력을 모두 허용한다.
|
|
9
|
+
ctx = args.get("ctx") if isinstance(args, dict) else getattr(args, "ctx", None)
|
|
10
|
+
|
|
11
|
+
process_id = getattr(ctx, "process_id", None)
|
|
12
|
+
return str(process_id) if process_id else "unknown_module"
|
{rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow_rb_utils.egg-info/PKG-INFO
RENAMED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: rainbow-rb-utils
|
|
3
|
-
Version: 0.0.9.
|
|
3
|
+
Version: 0.0.9.dev7
|
|
4
4
|
Summary: Rainbow Python Utilities
|
|
5
5
|
Author-email: Derek <dfd1123@rainbow-robotics.com>
|
|
6
6
|
Requires-Python: <3.13,>=3.12
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
Requires-Dist: psutil<8.0.0,>=7.0.0
|
|
9
|
-
Requires-Dist: rainbow-rb-log==0.0.9.
|
|
9
|
+
Requires-Dist: rainbow-rb-log==0.0.9.dev7
|
|
10
10
|
|
|
11
11
|
# rb_utils
|
|
12
12
|
|
|
@@ -9,6 +9,8 @@ src/rainbow/rb_utils/helper.py
|
|
|
9
9
|
src/rainbow/rb_utils/manipulate.py
|
|
10
10
|
src/rainbow/rb_utils/pagination.py
|
|
11
11
|
src/rainbow/rb_utils/parser.py
|
|
12
|
+
src/rainbow/rb_utils/path_utils.py
|
|
13
|
+
src/rainbow/rb_utils/program.py
|
|
12
14
|
src/rainbow/rb_utils/py.typed
|
|
13
15
|
src/rainbow/rb_utils/service_exception.py
|
|
14
16
|
src/rainbow_rb_utils.egg-info/PKG-INFO
|
|
File without changes
|
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/__init__.py
RENAMED
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/asyncio_helper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev5 → rainbow_rb_utils-0.0.9.dev7}/src/rainbow/rb_utils/pagination.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|