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.
Files changed (24) hide show
  1. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/PKG-INFO +2 -2
  2. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/pyproject.toml +2 -2
  3. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/flow_manager.py +7 -0
  4. rainbow_rb_utils-0.0.9.dev25/src/rainbow/rb_utils/helper.py +121 -0
  5. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow_rb_utils.egg-info/PKG-INFO +2 -2
  6. rainbow_rb_utils-0.0.9.dev25/src/rainbow_rb_utils.egg-info/requires.txt +2 -0
  7. rainbow_rb_utils-0.0.9.dev23/src/rainbow/rb_utils/helper.py +0 -35
  8. rainbow_rb_utils-0.0.9.dev23/src/rainbow_rb_utils.egg-info/requires.txt +0 -2
  9. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/README.md +0 -0
  10. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/setup.cfg +0 -0
  11. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/__init__.py +0 -0
  12. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/asyncio_helper.py +0 -0
  13. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/date.py +0 -0
  14. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/file.py +0 -0
  15. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/manipulate.py +0 -0
  16. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/pagination.py +0 -0
  17. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/parser.py +0 -0
  18. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/path_utils.py +0 -0
  19. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/program.py +0 -0
  20. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/py.typed +0 -0
  21. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow/rb_utils/service_exception.py +0 -0
  22. {rainbow_rb_utils-0.0.9.dev23 → rainbow_rb_utils-0.0.9.dev25}/src/rainbow_rb_utils.egg-info/SOURCES.txt +0 -0
  23. {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
  24. {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.dev23
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.dev23
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.dev23"
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.dev23",
17
+ "rainbow-rb-log==0.0.9.dev25",
18
18
  ]
19
19
 
20
20
  [tool.setuptools]
@@ -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)
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rainbow-rb-utils
3
- Version: 0.0.9.dev23
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.dev23
9
+ Requires-Dist: rainbow-rb-log==0.0.9.dev25
10
10
 
11
11
  # rb_utils
12
12
 
@@ -0,0 +1,2 @@
1
+ psutil<8.0.0,>=7.0.0
2
+ rainbow-rb-log==0.0.9.dev25
@@ -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"
@@ -1,2 +0,0 @@
1
- psutil<8.0.0,>=7.0.0
2
- rainbow-rb-log==0.0.9.dev23