hyper-bot 0.82.4__tar.gz → 0.90.0__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 (49) hide show
  1. {hyper_bot-0.82.4/src/hyper_bot.egg-info → hyper_bot-0.90.0}/PKG-INFO +1 -1
  2. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/pyproject.toml +19 -1
  3. {hyper_bot-0.82.4 → hyper_bot-0.90.0/src/hyper_bot.egg-info}/PKG-INFO +1 -1
  4. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyper_bot.egg-info/SOURCES.txt +6 -2
  5. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyper_bot.egg-info/dependency_links.txt +0 -0
  6. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyper_bot.egg-info/requires.txt +0 -0
  7. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyper_bot.egg-info/top_level.txt +0 -0
  8. hyper_bot-0.90.0/src/hyperot/LecAdapters/Milky.py +336 -0
  9. hyper_bot-0.90.0/src/hyperot/LecAdapters/MilkyLib/Manager.py +25 -0
  10. {hyper_bot-0.82.4/src/hyperot/LecAdapters/OneBotLib → hyper_bot-0.90.0/src/hyperot/LecAdapters/MilkyLib}/Res.py +14 -15
  11. hyper_bot-0.90.0/src/hyperot/LecAdapters/MilkyLib/translator.py +424 -0
  12. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/LecAdapters/OneBot.py +51 -92
  13. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/LecAdapters/OneBotLib/Manager.py +4 -8
  14. {hyper_bot-0.82.4/src/hyperot/LecAdapters/MilkyLib → hyper_bot-0.90.0/src/hyperot/LecAdapters/OneBotLib}/Res.py +9 -41
  15. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/__init__.py +42 -36
  16. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/adapters/__init__.py +0 -0
  17. hyper_bot-0.90.0/src/hyperot/adapters/builtins.py +29 -0
  18. hyper_bot-0.90.0/src/hyperot/adapters/common.py +6 -0
  19. hyper_bot-0.90.0/src/hyperot/adapters/listener.py +75 -0
  20. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/adapters/obuilder.py +64 -120
  21. hyper_bot-0.90.0/src/hyperot/adapters/res.py +18 -0
  22. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/common.py +7 -8
  23. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/configurator.py +22 -18
  24. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/events.py +203 -47
  25. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/hyperogger.py +13 -8
  26. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/listener.py +1 -1
  27. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/network.py +23 -15
  28. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/segments.py +72 -75
  29. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/__init__.py +0 -1
  30. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/apiresponse.py +23 -22
  31. hyper_bot-0.82.4/src/hyperot/utils/ArkSignHelper.py → hyper_bot-0.90.0/src/hyperot/utils/ark_sign_helper.py +27 -30
  32. hyper_bot-0.90.0/src/hyperot/utils/errors.py +33 -0
  33. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/hypetyping.py +2 -2
  34. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/screens.py +6 -12
  35. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/src/hyperot/utils/typextensions.py +9 -21
  36. hyper_bot-0.90.0/tests/test_events.py +107 -0
  37. hyper_bot-0.90.0/tests/test_milky.py +710 -0
  38. hyper_bot-0.90.0/tests/test_segments.py +67 -0
  39. hyper_bot-0.90.0/tests/test_utils.py +93 -0
  40. hyper_bot-0.82.4/src/hyperot/LecAdapters/Milky.py +0 -215
  41. hyper_bot-0.82.4/src/hyperot/LecAdapters/MilkyLib/Manager.py +0 -13
  42. hyper_bot-0.82.4/src/hyperot/LecAdapters/MilkyLib/translator.py +0 -217
  43. hyper_bot-0.82.4/src/hyperot/adapters/builtins.py +0 -15
  44. hyper_bot-0.82.4/src/hyperot/adapters/common.py +0 -8
  45. hyper_bot-0.82.4/src/hyperot/adapters/listener.py +0 -95
  46. hyper_bot-0.82.4/src/hyperot/adapters/res.py +0 -22
  47. hyper_bot-0.82.4/src/hyperot/utils/errors.py +0 -27
  48. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/LICENSE +0 -0
  49. {hyper_bot-0.82.4 → hyper_bot-0.90.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyper-bot
3
- Version: 0.82.4
3
+ Version: 0.90.0
4
4
  Summary: 稳定高效、易于开发的QQ Bot框架
5
5
  Author-email: Harcic <harcic@outlook.com>
6
6
  Project-URL: repository, https://github.com/HarcicYang/HypeR_Bot
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "hyper-bot"
7
- version = "0.82.4"
7
+ version = "0.90.0"
8
8
  description = "稳定高效、易于开发的QQ Bot框架"
9
9
  authors = [
10
10
  { name = "Harcic", email = "harcic@outlook.com" },
@@ -25,3 +25,21 @@ dependencies = [
25
25
  [tool.setuptools.packages.find]
26
26
  where = ["src"]
27
27
  include = ["hyperot*"]
28
+
29
+ [tool.ruff]
30
+ target-version = "py311"
31
+ line-length = 120
32
+
33
+ [tool.ruff.lint]
34
+ # 工作区挂载在 NTFS (fuseblk) 上,无法表示可执行位,文件总是 rwxrwxrwx。
35
+ # git index 中已通过 `git update-index --chmod=-x` 修正为 644,此处忽略该检查。
36
+ extend-per-file-ignores = { "*.py" = ["EXE002"] }
37
+
38
+ [dependency-groups]
39
+ dev = [
40
+ "pytest>=9.1.1",
41
+ "ruff>=0.16.1",
42
+ ]
43
+
44
+ [tool.pytest.ini_options]
45
+ testpaths = ["tests"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyper-bot
3
- Version: 0.82.4
3
+ Version: 0.90.0
4
4
  Summary: 稳定高效、易于开发的QQ Bot框架
5
5
  Author-email: Harcic <harcic@outlook.com>
6
6
  Project-URL: repository, https://github.com/HarcicYang/HypeR_Bot
@@ -26,10 +26,14 @@ src/hyperot/adapters/common.py
26
26
  src/hyperot/adapters/listener.py
27
27
  src/hyperot/adapters/obuilder.py
28
28
  src/hyperot/adapters/res.py
29
- src/hyperot/utils/ArkSignHelper.py
30
29
  src/hyperot/utils/__init__.py
31
30
  src/hyperot/utils/apiresponse.py
31
+ src/hyperot/utils/ark_sign_helper.py
32
32
  src/hyperot/utils/errors.py
33
33
  src/hyperot/utils/hypetyping.py
34
34
  src/hyperot/utils/screens.py
35
- src/hyperot/utils/typextensions.py
35
+ src/hyperot/utils/typextensions.py
36
+ tests/test_events.py
37
+ tests/test_milky.py
38
+ tests/test_segments.py
39
+ tests/test_utils.py
@@ -0,0 +1,336 @@
1
+ import asyncio
2
+ import json
3
+ import sys
4
+ import time
5
+ from collections.abc import Callable
6
+ from typing import NoReturn
7
+
8
+ from .. import common, configurator, events, hyperogger, segments
9
+ from ..events import *
10
+ from ..utils import errors
11
+ from ..utils.apiresponse import *
12
+ from .MilkyLib.Manager import Packet
13
+ from .MilkyLib.translator import (
14
+ MilkyHttpConnection,
15
+ message_translator,
16
+ msg_deid,
17
+ msg_enid,
18
+ node_list_to_milky_forward,
19
+ to_milky_message,
20
+ )
21
+
22
+ config = configurator.BotConfig.get("hyper-bot")
23
+ logger = hyperogger.Logger()
24
+ logger.set_level(config.log_level)
25
+ listener_ran = False
26
+
27
+
28
+ class Actions:
29
+ def __init__(self, cnt: MilkyHttpConnection):
30
+ self.connection = cnt
31
+
32
+ class CustomAction:
33
+ def __init__(self, cnt_i: MilkyHttpConnection):
34
+ self.connection = cnt_i
35
+
36
+ def __getattr__(self, item) -> Callable:
37
+ async def wrapper(**kwargs) -> dict | None:
38
+ res = await Packet(str(item), **kwargs).send_to(self.connection)
39
+ return res.get("data")
40
+
41
+ return wrapper
42
+
43
+ self.custom = CustomAction(self.connection)
44
+
45
+ async def send_msg(
46
+ self, message: common.Message | str, group_id: int | None = None, user_id: int | None = None
47
+ ) -> common.Ret[MsgSendRsp]:
48
+ if isinstance(message, str):
49
+ message = common.Message(segments.Text(message))
50
+ elif not isinstance(message, common.Message):
51
+ message = common.Message(message)
52
+ if group_id is not None:
53
+ endpoint, scene, peer = "send_group_message", 1, group_id
54
+ elif user_id is not None:
55
+ endpoint, scene, peer = "send_private_message", 0, user_id
56
+ else:
57
+ raise errors.ArgsInvalidError("'send' API requires 'group_id' or 'user_id' but none of them are provided.")
58
+ res = await Packet(
59
+ endpoint,
60
+ **{("group_id" if group_id is not None else "user_id"): peer},
61
+ message=to_milky_message(message),
62
+ ).send_to(self.connection)
63
+ ret = common.Ret(res)
64
+ ret.data = MsgSendRsp({"message_id": msg_enid(scene, res["data"]["message_seq"], peer)})
65
+ logger.info(f"向{'群 ' + str(peer) if scene else '用户 ' + str(peer)}发送:{message!s}")
66
+ return ret
67
+
68
+ async def send_group_msg(
69
+ self, message: common.Message | str, group_id: int | None = None
70
+ ) -> common.Ret[MsgSendRsp]:
71
+ return await self.send_msg(message, group_id=group_id)
72
+
73
+ async def send_private_msg(
74
+ self, message: common.Message | str, user_id: int | None = None
75
+ ) -> common.Ret[MsgSendRsp]:
76
+ return await self.send_msg(message, user_id=user_id)
77
+
78
+ async def del_msg(self, message_id: int) -> None:
79
+ scene, seq, peer = msg_deid(message_id)
80
+ if scene == 0:
81
+ await Packet("recall_private_message", user_id=peer, message_seq=seq).send_to(self.connection)
82
+ else:
83
+ await Packet("recall_group_message", group_id=peer, message_seq=seq).send_to(self.connection)
84
+ logger.info(f"撤回消息 {message_id}")
85
+
86
+ async def set_group_kick(self, group_id: int, user_id: int) -> None:
87
+ await Packet("kick_group_member", group_id=group_id, user_id=user_id).send_to(self.connection)
88
+ logger.info(f"将用户 {user_id} 移出群 {group_id}")
89
+
90
+ async def set_group_ban(self, group_id: int, user_id: int, duration: int = 60) -> None:
91
+ await Packet("set_group_member_mute", group_id=group_id, user_id=user_id, duration=duration).send_to(
92
+ self.connection
93
+ )
94
+ logger.info(f"在群 {group_id} 将用户 {user_id} 禁言 {duration}s")
95
+
96
+ async def get_login_info(self) -> common.Ret[GetLoginInfoRsp]:
97
+ res = await Packet("get_login_info").send_to(self.connection)
98
+ ret = common.Ret(res)
99
+ ret.data = GetLoginInfoRsp({"user_id": res["data"]["uin"], "nickname": res["data"]["nickname"]})
100
+ return ret
101
+
102
+ async def get_version_info(self) -> common.Ret[GetVerInfoRsp]:
103
+ res = await Packet("get_impl_info").send_to(self.connection)
104
+ ret = common.Ret(res)
105
+ ret.data = GetVerInfoRsp(
106
+ {
107
+ "app_name": res["data"]["impl_name"],
108
+ "app_version": res["data"]["impl_version"],
109
+ "protocol_version": res["data"]["milky_version"],
110
+ }
111
+ )
112
+ return ret
113
+
114
+ async def send_forward_msg(self, message: common.Message) -> common.Ret[SendForwardRsp]:
115
+ raise NotImplementedError("Milky adapter 发送合并转发请使用 send_group_forward_msg")
116
+
117
+ async def get_forward_msg(self, sid: str) -> common.Ret[common.Message]:
118
+ res = await Packet("get_forwarded_messages", forward_id=sid).send_to(self.connection)
119
+ nodes = []
120
+ for fm in res["data"]["messages"]:
121
+ content = events.gen_message({"message": message_translator(fm.get("segments", []), 0, 0)})
122
+ nodes.append(
123
+ segments.Node(
124
+ user_id=str(fm.get("message_seq", 0)), nickname=fm.get("sender_name", ""), content=content
125
+ )
126
+ )
127
+ ret = common.Ret(res)
128
+ ret.data = common.Message(*nodes)
129
+ return ret
130
+
131
+ async def forward_solve(self, message: common.Message) -> common.Message:
132
+ for i in message:
133
+ if isinstance(i, segments.Forward):
134
+ data = await self.get_forward_msg(i.id)
135
+ return data.data
136
+ raise ValueError("Incorrect message type")
137
+
138
+ async def send_group_forward_msg(self, group_id: int, message: common.Message) -> common.Ret[SendGrpForwardRsp]:
139
+ res = await Packet("send_group_msg", group_id=group_id, message=[node_list_to_milky_forward(message)]).send_to(
140
+ self.connection
141
+ )
142
+ ret = common.Ret(res)
143
+ ret.data = SendGrpForwardRsp({"message_id": res["data"]["message_seq"], "forward_id": ""})
144
+ return ret
145
+
146
+ async def set_group_add_request(
147
+ self, flag: str, sub_type: str, approve: bool, reason: str = "Not Mentioned"
148
+ ) -> None:
149
+ group_id, seq = (int(x) for x in flag.split(":"))
150
+ notification_type = "join_request" if sub_type == "add" else "invited_join_request"
151
+ endpoint = "accept_group_request" if approve else "reject_group_request"
152
+ params = {
153
+ "notification_seq": seq,
154
+ "notification_type": notification_type,
155
+ "group_id": group_id,
156
+ }
157
+ if not approve:
158
+ params["reason"] = reason
159
+ await Packet(endpoint, **params).send_to(self.connection)
160
+ logger.info(f"由于 {reason},{'通过' if approve else '拒绝'} {flag} 请求")
161
+
162
+ async def get_stranger_info(self, user_id: int) -> common.Ret[GetStrInfoRsp]:
163
+ res = await Packet("get_user_profile", user_id=user_id).send_to(self.connection)
164
+ ret = common.Ret(res)
165
+ d = res["data"]
166
+ ret.data = GetStrInfoRsp(
167
+ {
168
+ "user_id": user_id,
169
+ "nickname": d.get("nickname", ""),
170
+ "sex": d.get("sex", "unknown"),
171
+ "age": d.get("age", 0),
172
+ }
173
+ )
174
+ return ret
175
+
176
+ async def get_group_member_info(self, group_id: int, user_id: int) -> common.Ret[GetGrpMemInfoRsp]:
177
+ res = await Packet("get_group_member_info", group_id=group_id, user_id=user_id).send_to(self.connection)
178
+ ret = common.Ret(res)
179
+ d = res["data"].get("member", {})
180
+ ret.data = GetGrpMemInfoRsp(
181
+ {
182
+ "group_id": d.get("group_id", group_id),
183
+ "user_id": d.get("user_id", user_id),
184
+ "nickname": d.get("nickname", ""),
185
+ "card": d.get("card", ""),
186
+ "sex": d.get("sex", "unknown"),
187
+ "age": 0,
188
+ "area": "",
189
+ "join_time": d.get("join_time", 0),
190
+ "last_sent_time": d.get("last_sent_time", 0),
191
+ "level": str(d.get("level", "")),
192
+ "role": d.get("role", "member"),
193
+ "unfriendly": False,
194
+ "title": d.get("title", ""),
195
+ "title_expire_time": 0,
196
+ "card_changeable": False,
197
+ }
198
+ )
199
+ return ret
200
+
201
+ async def get_group_info(self, group_id: int) -> common.Ret[GetGrpInfoRsp]:
202
+ res = await Packet("get_group_info", group_id=group_id).send_to(self.connection)
203
+ ret = common.Ret(res)
204
+ d = res["data"].get("group", {})
205
+ ret.data = GetGrpInfoRsp(
206
+ {
207
+ "group_id": d.get("group_id", group_id),
208
+ "group_name": d.get("group_name", ""),
209
+ "member_count": d.get("member_count", 0),
210
+ "max_member_count": d.get("max_member_count", 0),
211
+ }
212
+ )
213
+ return ret
214
+
215
+ async def get_status(self) -> common.Ret:
216
+ return common.Ret({"status": "ok", "retcode": 0, "data": {}})
217
+
218
+ async def set_essence_msg(self, message_id: int) -> None:
219
+ scene, seq, peer = msg_deid(message_id)
220
+ if scene != 1:
221
+ raise ValueError("Only group messages can be set as essence")
222
+ await Packet("set_group_essence_message", group_id=peer, message_seq=seq, is_set=True).send_to(self.connection)
223
+
224
+ async def set_group_special_title(self, group_id: int, user_id: int, title: str) -> None:
225
+ await Packet("set_group_member_special_title", group_id=group_id, user_id=user_id, special_title=title).send_to(
226
+ self.connection
227
+ )
228
+
229
+ async def get_msg(self, msg_id: int) -> common.Ret[GetMsgRsp]:
230
+ scene, seq, peer = msg_deid(msg_id)
231
+ message_scene = "friend" if scene == 0 else "group"
232
+ res = await Packet("get_message", message_scene=message_scene, peer_id=peer, message_seq=seq).send_to(
233
+ self.connection
234
+ )
235
+ ret = common.Ret(res)
236
+ d = res["data"]
237
+ ret.data = GetMsgRsp(
238
+ {
239
+ "time": d.get("time", 0),
240
+ "message_type": "group" if d.get("message_scene") == "group" else "private",
241
+ "message_id": 0,
242
+ "real_id": d.get("message_seq", 0),
243
+ "sender": d.get("group_member", d.get("friend", {})),
244
+ "message": message_translator(d.get("segments", []), d.get("peer_id", 0), scene),
245
+ }
246
+ )
247
+ return ret
248
+
249
+ async def send_callback(self, group_id: int, bot_id: int, data: dict) -> None:
250
+ raise NotImplementedError("Milky adapter does not support send_callback")
251
+
252
+
253
+ async def tester(message_data: Event | HyperNotify, actions: Actions) -> None: ...
254
+
255
+
256
+ async def __handler(data: dict | HyperNotify | None, actions: Actions) -> None:
257
+ if data is None:
258
+ return
259
+ try:
260
+ if isinstance(data, dict):
261
+ await handler(events.em.new(data), actions)
262
+ else:
263
+ await handler(data, actions)
264
+ except Exception:
265
+ logger.exception("处理事件时发生异常")
266
+
267
+
268
+ handler: Callable = tester
269
+
270
+
271
+ def reg(func: Callable) -> None:
272
+ global handler
273
+ handler = func
274
+
275
+
276
+ connection: MilkyHttpConnection
277
+
278
+
279
+ async def run() -> NoReturn:
280
+ global connection, listener_ran
281
+ listener_ran = True
282
+ try:
283
+ if handler is tester:
284
+ raise errors.ListenerNotRegisteredError("No handler registered")
285
+ if not isinstance(config.connection, configurator.MilkyConnection):
286
+ raise TypeError("Milky 协议需要 MilkyConnection 类型的连接配置")
287
+ connection = MilkyHttpConnection(
288
+ f"ws://{config.connection.host}:{config.connection.port}", auth=config.connection.auth
289
+ )
290
+ retried = 0
291
+
292
+ while True:
293
+ try:
294
+ await connection.connect()
295
+ except (ConnectionRefusedError, TimeoutError, OSError):
296
+ if retried >= config.connection.retries:
297
+ logger.critical(f"重试次数达到最大值({config.connection.retries}),退出")
298
+ break
299
+
300
+ logger.warning(f"连接建立失败,3秒后重试({retried}/{config.connection.retries})")
301
+ retried += 1
302
+ await asyncio.sleep(3)
303
+ continue
304
+ retried = 0
305
+ logger.info(f"成功在 {connection.url} 建立连接")
306
+ actions = Actions(connection)
307
+ start_data = HyperListenerStartNotify(
308
+ time_now=int(time.time()), notify_type="listener_start", connection=connection
309
+ )
310
+ asyncio.create_task(__handler(start_data, actions))
311
+ while True:
312
+ try:
313
+ data = await connection.recv()
314
+ except ConnectionResetError:
315
+ logger.error("连接断开")
316
+ break
317
+ except json.decoder.JSONDecodeError:
318
+ logger.error("收到错误的JSON内容")
319
+ continue
320
+ if data is not None:
321
+ asyncio.create_task(__handler(data, actions))
322
+ except KeyboardInterrupt:
323
+ logger.warning("正在退出(Ctrl+C)")
324
+ try:
325
+ await connection.close()
326
+ except Exception:
327
+ logger.exception("关闭连接失败")
328
+ sys.exit()
329
+
330
+
331
+ def stop() -> None:
332
+ try:
333
+ connection.close()
334
+ except Exception:
335
+ logger.exception("停止监听器时关闭连接失败")
336
+ logger.log("停止运行监听器", level=hyperogger.levels.WARNING)
@@ -0,0 +1,25 @@
1
+ from ... import configurator, hyperogger, utils
2
+ from .translator import MilkyHttpConnection
3
+
4
+ reports = utils.KeyQueue()
5
+
6
+ config: configurator.BotConfig
7
+ logger: hyperogger.Logger
8
+
9
+
10
+ def init() -> None:
11
+ global config, logger
12
+ config = configurator.BotConfig.get("hyper-bot")
13
+ logger = hyperogger.Logger()
14
+ logger.set_level(config.log_level)
15
+
16
+
17
+ class Packet:
18
+ def __init__(self, endpoint: str, **kwargs):
19
+ self.endpoint = endpoint
20
+ self.paras = kwargs
21
+
22
+ async def send_to(self, connection: MilkyHttpConnection) -> dict:
23
+ if isinstance(connection, MilkyHttpConnection):
24
+ return await connection.http_send(self.endpoint, self.paras)
25
+ raise TypeError(f"Invalid connection: {connection}")
@@ -1,9 +1,11 @@
1
1
  from abc import ABC
2
2
 
3
3
  from ...utils.hypetyping import OneBotSegReg
4
+ from .translator import milky_seg_from_dict
4
5
 
5
6
  message_types = {}
6
7
 
8
+
7
9
  class SegmentBase(ABC):
8
10
  def __init__(self, *args, **kwargs):
9
11
  var = self.__var
@@ -14,17 +16,17 @@ class SegmentBase(ABC):
14
16
  arg[list(anns.keys())[list(args).index(i)]] = i
15
17
 
16
18
  if len(kwargs) > 0:
17
- for i in kwargs:
19
+ for i, v in kwargs.items():
18
20
  try:
19
- arg[i] = anns[i](kwargs[i])
21
+ arg[i] = anns[i](v)
20
22
  except TypeError:
21
- arg[i] = kwargs[i]
23
+ arg[i] = v
22
24
  new_arg = arg.copy()
23
25
 
24
26
  if len(anns) > len(arg):
25
- for i in anns.keys():
26
- if i not in arg.keys():
27
- if i not in var.keys():
27
+ for i in anns:
28
+ if i not in arg:
29
+ if i not in var:
28
30
  new_arg[i] = None
29
31
  continue
30
32
  if not isinstance(var[i], anns[i]):
@@ -44,7 +46,7 @@ class SegmentBase(ABC):
44
46
 
45
47
  cls.__sg_type = sg_type
46
48
  cls.__var = dict(vars(cls))
47
- cls.__anns: dict = cls.__var.get("__annotations__", False) or dict()
49
+ cls.__anns: dict = cls.__var.get("__annotations__", False) or {}
48
50
 
49
51
  def to_str(self) -> str:
50
52
  text = summary_tmp
@@ -83,17 +85,14 @@ class SegmentBase(ABC):
83
85
  base["data"][i] = getattr(self, i)
84
86
  return base
85
87
 
88
+ def milky_outgoing_seg(self) -> dict:
89
+ return milky_seg_from_dict(self.to_json())
90
+
86
91
  def __str__(self) -> str:
87
92
  return "__not_set__"
88
93
 
89
94
  def __eq__(self, other) -> bool:
90
- if type(self) is type(other) and self.to_json() == other.to_json():
91
- return True
92
- else:
93
- return False
95
+ return type(self) is type(other) and self.to_json() == other.to_json()
94
96
 
95
97
  def __ne__(self, other) -> bool:
96
- if type(self) is type(other) and self.to_json() == other.to_json():
97
- return False
98
- else:
99
- return True
98
+ return not (type(self) is type(other) and self.to_json() == other.to_json())