rainbow-rb-utils 0.0.9.dev23__tar.gz → 0.0.9.dev25__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.dev23 → rainbow_rb_utils-0.0.9.dev25}/PKG-INFO +2 -2
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/pyproject.toml +2 -2
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/flow_manager.py +7 -0
- rainbow_rb_utils-0.0.9.dev25/src/rainbow/rb_utils/helper.py +121 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow_rb_utils.egg-info/PKG-INFO +2 -2
- rainbow_rb_utils-0.0.9.dev25/src/rainbow_rb_utils.egg-info/requires.txt +2 -0
- rainbow_rb_utils-0.0.9.dev23/src/rainbow/rb_utils/helper.py +0 -35
- rainbow_rb_utils-0.0.9.dev23/src/rainbow_rb_utils.egg-info/requires.txt +0 -2
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/README.md +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/setup.cfg +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/__init__.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/asyncio_helper.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/date.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/file.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/manipulate.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/pagination.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/parser.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/path_utils.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/program.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/py.typed +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/service_exception.py +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow_rb_utils.egg-info/SOURCES.txt +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow_rb_utils.egg-info/dependency_links.txt +0 -0
- {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/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.dev25
|
|
4
4
|
Summary: Rainbow Python Utilities
|
|
5
5
|
Author-email: Derek <dfd1123@rainbow-robotics.com>
|
|
6
6
|
Requires-Python: >=3.11
|
|
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.dev25
|
|
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.dev25"
|
|
8
8
|
requires-python = ">=3.11"
|
|
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.dev25",
|
|
18
18
|
]
|
|
19
19
|
|
|
20
20
|
[tool.setuptools]
|
{rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/flow_manager.py
RENAMED
|
@@ -9,6 +9,8 @@ from collections.abc import Callable, Coroutine
|
|
|
9
9
|
from concurrent.futures import Future
|
|
10
10
|
from typing import Any
|
|
11
11
|
|
|
12
|
+
from .helper import list_to_str, list_to_str_int, point_dist, str_to_list
|
|
13
|
+
|
|
12
14
|
# --- 간단 테이블 (함수/상수/연산자) -----------------------------------------
|
|
13
15
|
BIN_OPS = {
|
|
14
16
|
ast.Add: operator.add,
|
|
@@ -28,6 +30,7 @@ CMP_OPS: dict[type[ast.cmpop], Callable] = {
|
|
|
28
30
|
ast.Gt: operator.gt,
|
|
29
31
|
ast.GtE: operator.ge,
|
|
30
32
|
}
|
|
33
|
+
|
|
31
34
|
ALLOWED_FUNCS = {
|
|
32
35
|
"sin": math.sin,
|
|
33
36
|
"cos": math.cos,
|
|
@@ -47,6 +50,10 @@ ALLOWED_FUNCS = {
|
|
|
47
50
|
"str": str,
|
|
48
51
|
"len": len,
|
|
49
52
|
"range": range,
|
|
53
|
+
"str_to_list": str_to_list,
|
|
54
|
+
"list_to_str": list_to_str,
|
|
55
|
+
"list_to_str_int": list_to_str_int,
|
|
56
|
+
"point_dist": point_dist,
|
|
50
57
|
}
|
|
51
58
|
ALLOWED_CALLABLES = set(ALLOWED_FUNCS.values())
|
|
52
59
|
ALLOWED_CONSTS = {
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import math
|
|
3
|
+
import socket
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
from .parser import t_to_dict
|
|
7
|
+
|
|
8
|
+
_MISSING = object()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def ManipulateZenohResHelper(obj: Any):
|
|
12
|
+
dict_obj = t_to_dict(obj)
|
|
13
|
+
|
|
14
|
+
if dict_obj.hasAttr("returnValue"):
|
|
15
|
+
dict_obj.set("return_value", dict_obj.get("returnValue"))
|
|
16
|
+
del dict_obj["returnValue"]
|
|
17
|
+
|
|
18
|
+
raise ValueError("obj is not a dict")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
async def get_current_ip(timeout: float = 0.5) -> str:
|
|
22
|
+
def resolve_ip() -> str:
|
|
23
|
+
try:
|
|
24
|
+
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
|
25
|
+
sock.connect(("8.8.8.8", 80))
|
|
26
|
+
return sock.getsockname()[0]
|
|
27
|
+
except Exception:
|
|
28
|
+
return socket.gethostbyname(socket.gethostname())
|
|
29
|
+
|
|
30
|
+
loop = asyncio.get_running_loop()
|
|
31
|
+
try:
|
|
32
|
+
return await asyncio.wait_for(
|
|
33
|
+
loop.run_in_executor(None, resolve_ip),
|
|
34
|
+
timeout=timeout,
|
|
35
|
+
)
|
|
36
|
+
except Exception:
|
|
37
|
+
# DNS가 막히면 이전 IP를 쓰거나, 로컬 IP로 폴백
|
|
38
|
+
return "127.0.0.1"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _parse_stx_etx_sep(stx_or_sep: str, etx: object, sep: object) -> tuple[str, str, str]:
|
|
42
|
+
if sep is _MISSING:
|
|
43
|
+
return "", "", stx_or_sep
|
|
44
|
+
return stx_or_sep, etx, sep # type: ignore[return-value]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def str_to_list(s: str, stx_or_sep: str, etx: object = _MISSING, sep: object = _MISSING) -> list:
|
|
48
|
+
"""구분자로 나뉜 문자열을 숫자 리스트로 변환한다.
|
|
49
|
+
|
|
50
|
+
2-arg 오버로드: str_to_list(s, sep) — STX/ETX 없이 구분자만 지정
|
|
51
|
+
4-arg 오버로드: str_to_list(s, stx, etx, sep) — 앞뒤 마커를 제거한 뒤 분리
|
|
52
|
+
|
|
53
|
+
각 토큰은 정수 또는 실수로 파싱된다. 변환 불가 토큰이 있으면 ValueError를 발생시킨다.
|
|
54
|
+
|
|
55
|
+
예시:
|
|
56
|
+
str_to_list(":1.23,4.56@", ":", "@", ",") -> [1.23, 4.56]
|
|
57
|
+
str_to_list("1,2,3", ",") -> [1, 2, 3]
|
|
58
|
+
"""
|
|
59
|
+
stx, etx_val, sep = _parse_stx_etx_sep(stx_or_sep, etx, sep)
|
|
60
|
+
if stx:
|
|
61
|
+
if not s.startswith(stx):
|
|
62
|
+
raise ValueError(f"str_to_list: string does not start with STX '{stx}'")
|
|
63
|
+
|
|
64
|
+
s = s[len(stx):]
|
|
65
|
+
|
|
66
|
+
if etx_val:
|
|
67
|
+
if not s.endswith(etx_val):
|
|
68
|
+
raise ValueError(f"str_to_list: string does not end with ETX '{etx_val}'")
|
|
69
|
+
|
|
70
|
+
s = s[: len(s) - len(etx_val)]
|
|
71
|
+
|
|
72
|
+
result = []
|
|
73
|
+
|
|
74
|
+
for p in s.split(sep):
|
|
75
|
+
p = p.strip()
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
result.append(int(p) if "." not in p and "e" not in p.lower() else float(p))
|
|
79
|
+
except ValueError as exc:
|
|
80
|
+
raise ValueError(f"str_to_list: cannot convert '{p}' to number — separator mismatch?") from exc
|
|
81
|
+
return result
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def list_to_str(lst: list, stx_or_sep: str, etx: object = _MISSING, sep: object = _MISSING) -> str:
|
|
85
|
+
"""숫자 리스트를 소수점 3자리 실수 문자열로 변환한다.
|
|
86
|
+
|
|
87
|
+
2-arg 오버로드: list_to_str(lst, sep)
|
|
88
|
+
4-arg 오버로드: list_to_str(lst, stx, etx, sep) — 결과 앞뒤에 마커를 붙임
|
|
89
|
+
|
|
90
|
+
예시:
|
|
91
|
+
list_to_str([1, 2, 3], "-") -> "1.000-2.000-3.000"
|
|
92
|
+
list_to_str([-1, -2], "@", "@", ",") -> "@-1.000,-2.000@"
|
|
93
|
+
"""
|
|
94
|
+
stx, etx_val, sep = _parse_stx_etx_sep(stx_or_sep, etx, sep)
|
|
95
|
+
body = sep.join(f"{float(v):.3f}" for v in lst)
|
|
96
|
+
return f"{stx}{body}{etx_val}"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def list_to_str_int(lst: list, stx_or_sep: str, etx: object = _MISSING, sep: object = _MISSING) -> str:
|
|
100
|
+
"""숫자 리스트를 정수 문자열로 변환한다. list_to_str의 정수 버전.
|
|
101
|
+
|
|
102
|
+
예시:
|
|
103
|
+
list_to_str_int([-1, -2, -3], "@", "@", ",") -> "@-1,-2,-3@"
|
|
104
|
+
"""
|
|
105
|
+
stx, etx_val, sep = _parse_stx_etx_sep(stx_or_sep, etx, sep)
|
|
106
|
+
body = sep.join(str(int(v)) for v in lst)
|
|
107
|
+
return f"{stx}{body}{etx_val}"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def point_dist(p1: list, p2: list) -> float:
|
|
111
|
+
"""두 3D 점 사이의 유클리드 거리를 반환한다.
|
|
112
|
+
|
|
113
|
+
p1, p2는 각각 [x, y, z] 형태의 리스트여야 한다. 길이가 3 미만이면 ValueError를 발생시킨다.
|
|
114
|
+
|
|
115
|
+
예시:
|
|
116
|
+
point_dist([1, 2, 3], [4, 6, 3]) -> 5.0
|
|
117
|
+
"""
|
|
118
|
+
if len(p1) < 3 or len(p2) < 3:
|
|
119
|
+
raise ValueError("point_dist: The list length must be at least 3.")
|
|
120
|
+
|
|
121
|
+
return math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2 + (p1[2] - p2[2]) ** 2)
|
{rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/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.dev25
|
|
4
4
|
Summary: Rainbow Python Utilities
|
|
5
5
|
Author-email: Derek <dfd1123@rainbow-robotics.com>
|
|
6
6
|
Requires-Python: >=3.11
|
|
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.dev25
|
|
10
10
|
|
|
11
11
|
# rb_utils
|
|
12
12
|
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import socket
|
|
3
|
-
from typing import Any
|
|
4
|
-
|
|
5
|
-
from .parser import t_to_dict
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def ManipulateZenohResHelper(obj: Any):
|
|
9
|
-
dict_obj = t_to_dict(obj)
|
|
10
|
-
|
|
11
|
-
if dict_obj.hasAttr("returnValue"):
|
|
12
|
-
dict_obj.set("return_value", dict_obj.get("returnValue"))
|
|
13
|
-
del dict_obj["returnValue"]
|
|
14
|
-
|
|
15
|
-
raise ValueError("obj is not a dict")
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
async def get_current_ip(timeout: float = 0.5) -> str:
|
|
19
|
-
def resolve_ip() -> str:
|
|
20
|
-
try:
|
|
21
|
-
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
|
|
22
|
-
sock.connect(("8.8.8.8", 80))
|
|
23
|
-
return sock.getsockname()[0]
|
|
24
|
-
except Exception:
|
|
25
|
-
return socket.gethostbyname(socket.gethostname())
|
|
26
|
-
|
|
27
|
-
loop = asyncio.get_running_loop()
|
|
28
|
-
try:
|
|
29
|
-
return await asyncio.wait_for(
|
|
30
|
-
loop.run_in_executor(None, resolve_ip),
|
|
31
|
-
timeout=timeout,
|
|
32
|
-
)
|
|
33
|
-
except Exception:
|
|
34
|
-
# DNS가 막히면 이전 IP를 쓰거나, 로컬 IP로 폴백
|
|
35
|
-
return "127.0.0.1"
|
|
File without changes
|
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/__init__.py
RENAMED
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/asyncio_helper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/manipulate.py
RENAMED
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/pagination.py
RENAMED
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/parser.py
RENAMED
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/path_utils.py
RENAMED
|
File without changes
|
{rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/program.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|