pymud 0.20.0__py3-none-any.whl → 0.20.0a2__py3-none-any.whl

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.
pymud/session.py CHANGED
@@ -1,15 +1,14 @@
1
- import asyncio, logging, re, math, os, pickle, datetime, importlib, importlib.util, sysconfig, time
1
+ import asyncio, logging, re, math, os, pickle, datetime, importlib, importlib.util, sysconfig
2
2
  from collections.abc import Iterable
3
3
  from collections import OrderedDict
4
4
  import logging, queue
5
5
  from logging import FileHandler
6
6
  from logging.handlers import QueueHandler, QueueListener
7
- from wcwidth import wcswidth, wcwidth
7
+
8
8
  from .logger import Logger
9
- from .extras import SessionBuffer, DotDict
9
+ from .extras import SessionBuffer, DotDict, Plugin
10
10
  from .protocol import MudClientProtocol
11
- from .modules import ModuleInfo
12
- from .objects import BaseObject, Trigger, Alias, Command, Timer, SimpleAlias, SimpleTrigger, SimpleTimer, GMCPTrigger, CodeBlock, CodeLine
11
+ from .objects import Trigger, Alias, Command, Timer, SimpleAlias, SimpleTrigger, SimpleTimer, GMCPTrigger, CodeBlock, CodeLine
13
12
  from .settings import Settings
14
13
 
15
14
 
@@ -30,14 +29,13 @@ class Session:
30
29
 
31
30
  """
32
31
  #_esc_regx = re.compile("\x1b\\[[^mz]+[mz]")
33
- _esc_regx = re.compile(r"\x1b\[[\d;]+[abcdmz]", flags = re.IGNORECASE)
32
+ _esc_regx = re.compile("\x1b\\[[\d;]+[abcdmz]", flags = re.IGNORECASE)
34
33
 
35
34
  _sys_commands = (
36
35
  "help",
37
36
  "exit",
38
37
  "close",
39
38
  "connect", # 连接到服务器
40
- "disconnect", # 从服务器断开连接
41
39
 
42
40
  "info", # 输出蓝色info
43
41
  "warning", # 输出黄色warning
@@ -91,7 +89,6 @@ class Session:
91
89
  "var" : "variable",
92
90
  "rep" : "repeat",
93
91
  "con" : "connect",
94
- "dis" : "disconnect",
95
92
  "wa" : "wait",
96
93
  "mess": "message",
97
94
  "action": "trigger",
@@ -142,8 +139,6 @@ class Session:
142
139
  self._status_maker = None # 创建状态窗口的函数(属性)
143
140
  self.display_line = ""
144
141
 
145
- self._activetime = time.time()
146
-
147
142
  self.initialize()
148
143
 
149
144
  self._loggers = dict()
@@ -257,6 +252,11 @@ class Session:
257
252
  if self.connected:
258
253
  self.write_eof()
259
254
 
255
+ # 两次保存,删掉一次
256
+ # # 断开时自动保存变量数据
257
+ # if Settings.client["var_autosave"]:
258
+ # self.handle_save()
259
+
260
260
  def onDisconnected(self, protocol):
261
261
  "当从服务器连接断开时执行的操作。包括保存变量(若设置)、打印断开时间、执行自定义事件(若设置)等。"
262
262
  # 断开时自动保存变量数据
@@ -294,15 +294,6 @@ class Session:
294
294
 
295
295
  return dura
296
296
 
297
- @property
298
- def idletime(self) -> float:
299
- "只读属性,返回当前会话空闲时间(即最后一次向服务器写入数据到现在的时间),以秒为单位。当服务器未连接时,返回-1"
300
- idle = -1
301
- if self._protocol and self._protocol.connected:
302
- idle = time.time() - self._activetime
303
-
304
- return idle
305
-
306
297
  @property
307
298
  def status_maker(self):
308
299
  """
@@ -764,7 +755,7 @@ class Session:
764
755
  lines = line.split(self.seperator)
765
756
  for ln in lines:
766
757
  if Settings.client["echo_input"]:
767
- self.writetobuffer(f"\x1b[32m{ln}\x1b[0m", True)
758
+ self.writetobuffer(f"\x1b[32m{ln}\x1b[0m")
768
759
  else:
769
760
  self.log.log(f"\x1b[32m{ln}\x1b[0m\n")
770
761
 
@@ -773,14 +764,12 @@ class Session:
773
764
 
774
765
  else:
775
766
  if Settings.client["echo_input"]:
776
- self.writetobuffer(f"\x1b[32m{line}\x1b[0m", True)
767
+ self.writetobuffer(f"\x1b[32m{line}\x1b[0m")
777
768
  else:
778
769
  self.log.log(f"\x1b[32m{line}\x1b[0m\n")
779
770
 
780
771
  cmd = line + self.newline
781
772
  self.write(cmd.encode(self.encoding, Settings.server["encoding_errors"]))
782
-
783
- self._activetime = time.time()
784
773
 
785
774
  async def waitfor(self, line: str, awaitable, wait_time = 0.05) -> None:
786
775
  """
@@ -804,7 +793,7 @@ class Session:
804
793
  return await awaitable
805
794
 
806
795
  def exec(self, cmd: str, name = None, *args, **kwargs):
807
- r"""
796
+ """
808
797
  在名称为name的会话中使用exec_command执行MUD命令。当不指定name时,在当前会话中执行。
809
798
 
810
799
  - exec 与 writeline 都会向服务器写入数据。其差异在于,exec执行的内容,会先经过Alias处理和Command处理,实际向远程发送内容与cmd可以不一致。
@@ -819,7 +808,7 @@ class Session:
819
808
  示例:
820
809
  .. code:: Python
821
810
 
822
- session.addAlias(SimpleAlias(self.session, r"^cb\s(\S+)\s(\S+)", "#3 get %1 from jinnang;#wa 250;combine gem;#wa 250;pack gem", id = "ali_combine"))
811
+ session.addAlias(SimpleAlias(self.session, "^cb\s(\S+)\s(\S+)", "#3 get %1 from jinnang;#wa 250;combine gem;#wa 250;pack gem", id = "ali_combine"))
823
812
  session.exec("cb j1a")
824
813
  """
825
814
  name = name or self.name
@@ -840,10 +829,12 @@ class Session:
840
829
  name = name or self.name
841
830
  if name in self.application.sessions.keys():
842
831
  session = self.application.sessions[name]
843
- return await session.exec_command_async(cmd, *args, **kwargs)
832
+ await session.exec_command_async(cmd, *args, **kwargs)
844
833
  else:
845
834
  self.error(f"不存在名称为{name}的会话")
846
835
 
836
+
837
+
847
838
  def exec_code(self, cl: CodeLine, *args, **kwargs):
848
839
  """
849
840
  执行解析为CodeLine形式的MUD命令(必定为单个命令)。一般情况下,脚本中不应调用该方法,而应使用exec/exec_command。
@@ -917,7 +908,6 @@ class Session:
917
908
  :param args: 保留兼容与扩展性所需
918
909
  :param kwargs: 保留兼容与扩展性所需
919
910
  """
920
-
921
911
  if cl.length == 0:
922
912
  self.writeline("")
923
913
 
@@ -945,9 +935,9 @@ class Session:
945
935
  else:
946
936
  try:
947
937
  cb = CodeBlock(sess_cmd)
948
- return await cb.async_execute(session, *args, **kwargs)
938
+ await cb.async_execute(session, *args, **kwargs)
949
939
  except Exception as e:
950
- return await session.exec_command_async(sess_cmd)
940
+ await session.exec_command_async(sess_cmd)
951
941
 
952
942
  else:
953
943
  if cmd in self._commands_alias.keys():
@@ -964,7 +954,7 @@ class Session:
964
954
 
965
955
  else:
966
956
  cmdtext, code = cl.expand(self, *args, **kwargs)
967
- return await self.exec_text_async(cmdtext)
957
+ await self.exec_text_async(cmdtext)
968
958
 
969
959
  def exec_text(self, cmdtext: str):
970
960
  """
@@ -1004,14 +994,14 @@ class Session:
1004
994
 
1005
995
  异步调用时,该函数要等待对应的代码执行完毕后才会返回。可以用于确保命令执行完毕。
1006
996
  """
1007
- result = None
997
+
1008
998
  isNotCmd = True
1009
999
  for command in self._commands.values():
1010
1000
  if isinstance(command, Command) and command.enabled:
1011
1001
  state = command.match(cmdtext)
1012
1002
  if state.result == Command.SUCCESS:
1013
1003
  # 命令的任务名称采用命令id,以便于后续查错
1014
- result = await self.create_task(command.execute(cmdtext), name = "task-{0}".format(command.id))
1004
+ await self.create_task(command.execute(cmdtext), name = "task-{0}".format(command.id))
1015
1005
  isNotCmd = False
1016
1006
  break
1017
1007
 
@@ -1029,8 +1019,6 @@ class Session:
1029
1019
  if notAlias:
1030
1020
  self.writeline(cmdtext)
1031
1021
 
1032
- return result
1033
-
1034
1022
  def exec_command(self, line: str, *args, **kwargs) -> None:
1035
1023
  """
1036
1024
  在当前会话中执行MUD命令。多个命令可以用分隔符隔开。
@@ -1081,18 +1069,15 @@ class Session:
1081
1069
  """
1082
1070
 
1083
1071
  ## 以下为函数执行本体
1084
- result = None
1085
1072
  if (not "#" in line) and (not "@" in line) and (not "%" in line):
1086
1073
  cmds = line.split(self.seperator)
1087
1074
  for cmd in cmds:
1088
- result = await self.exec_text_async(cmd)
1075
+ await self.exec_text_async(cmd)
1089
1076
  if Settings.client["interval"] > 0:
1090
1077
  await asyncio.sleep(Settings.client["interval"] / 1000.0)
1091
1078
  else:
1092
1079
  cb = CodeBlock(line)
1093
- result = await cb.async_execute(self)
1094
-
1095
- return result
1080
+ await cb.async_execute(self)
1096
1081
 
1097
1082
  def write_eof(self) -> None:
1098
1083
  """
@@ -1156,212 +1141,50 @@ class Session:
1156
1141
 
1157
1142
  return counts
1158
1143
 
1159
- # def _addObjects(self, objs: dict, cls: type):
1160
- # if cls == Alias:
1161
- # self._aliases.update(objs)
1162
- # elif cls == Command:
1163
- # self._commands.update(objs)
1164
- # elif cls == Trigger:
1165
- # self._triggers.update(objs)
1166
- # elif cls == Timer:
1167
- # self._timers.update(objs)
1168
- # elif cls == GMCPTrigger:
1169
- # self._gmcp.update(objs)
1170
-
1171
- def _addObjects(self, objs):
1172
- if isinstance(objs, list) or isinstance(objs, tuple):
1173
- for item in objs:
1174
- self._addObject(item)
1175
-
1176
- elif isinstance(objs, dict):
1177
- for key, item in objs.items():
1178
- if isinstance(item, BaseObject):
1179
- if key != item.id:
1180
- self.warning(f'对象 {item} 字典键值 {key} 与其id {item.id} 不一致,将丢弃键值,以其id添加到会话中...')
1181
-
1182
- self._addObject(item)
1183
-
1184
- # def _addObject(self, obj, cls: type):
1185
- # #if type(obj) == cls:
1186
- # if isinstance(obj, cls):
1187
- # if cls == Alias:
1188
- # self._aliases[obj.id] = obj
1189
- # elif cls == Command:
1190
- # self._commands[obj.id] = obj
1191
- # elif cls == Trigger:
1192
- # self._triggers[obj.id] = obj
1193
- # elif cls == Timer:
1194
- # self._timers[obj.id] = obj
1195
- # elif cls == GMCPTrigger:
1196
- # self._gmcp[obj.id] = obj
1197
-
1198
- def _addObject(self, obj):
1199
- if isinstance(obj, Alias):
1200
- self._aliases[obj.id] = obj
1201
- elif isinstance(obj, Command):
1202
- self._commands[obj.id] = obj
1203
- elif isinstance(obj, Trigger):
1204
- self._triggers[obj.id] = obj
1205
- elif isinstance(obj, Timer):
1206
- self._timers[obj.id] = obj
1207
- elif isinstance(obj, GMCPTrigger):
1208
- self._gmcp[obj.id] = obj
1209
-
1210
- def addObject(self, obj: BaseObject):
1211
- """
1212
- 向会话中增加单个对象,可直接添加 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类
1213
-
1214
- :param obj: 特定对象本身,可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或其子类
1215
-
1216
- 示例:
1217
- .. code:: Python
1218
-
1219
- class Configuration:
1220
- def __init__(self, session):
1221
- self.session = session
1222
-
1223
- self.session.addObject(SimpleAlias(session, r'^gta$', 'get all'),)
1224
- self.session.addObject(SimpleTrigger(session, r'^[> ]*你嘻嘻地笑了起来.+', 'haha'))
1225
- self.session.addObject(SimpleTimer(session, 'xixi', timeout = 10))
1226
-
1227
- """
1228
- self._addObject(obj)
1229
-
1230
- def addObjects(self, objs):
1231
- """
1232
- 向会话中增加多个对象,可直接添加 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类的元组、列表或者字典(保持兼容性)
1233
-
1234
- :param objs: 多个特定对象组成的元组、列表或者字典,可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或其子类
1235
-
1236
- 示例:
1237
- .. code:: Python
1238
-
1239
- class Configuration:
1240
- def __init__(self, session):
1241
- self.session = session
1242
-
1243
- self.objs = [
1244
- SimpleAlias(session, r'^gta$', 'get all;xixi'),
1245
- SimpleTrigger(session, r'^[> ]*你嘻嘻地笑了起来.+', 'haha'),
1246
- SimpleTimer(session, 'xixi', timeout = 10)
1247
- ]
1248
-
1249
- self.session.addObjects(self.objs)
1250
-
1251
- """
1252
- self._addObjects(objs)
1144
+ def _addObjects(self, objs: dict, cls: type):
1145
+ if cls == Alias:
1146
+ self._aliases.update(objs)
1147
+ elif cls == Command:
1148
+ self._commands.update(objs)
1149
+ elif cls == Trigger:
1150
+ self._triggers.update(objs)
1151
+ elif cls == Timer:
1152
+ self._timers.update(objs)
1153
+ elif cls == GMCPTrigger:
1154
+ self._gmcp.update(objs)
1155
+
1156
+ def _addObject(self, obj, cls: type):
1157
+ #if type(obj) == cls:
1158
+ if isinstance(obj, cls):
1159
+ if cls == Alias:
1160
+ self._aliases[obj.id] = obj
1161
+ elif cls == Command:
1162
+ self._commands[obj.id] = obj
1163
+ elif cls == Trigger:
1164
+ self._triggers[obj.id] = obj
1165
+ elif cls == Timer:
1166
+ self._timers[obj.id] = obj
1167
+ elif cls == GMCPTrigger:
1168
+ self._gmcp[obj.id] = obj
1253
1169
 
1254
1170
  def _delObject(self, id, cls: type):
1255
1171
  if cls == Alias:
1256
1172
  self._aliases.pop(id, None)
1257
1173
  elif cls == Command:
1258
- cmd = self._commands.pop(id, None)
1259
- if isinstance(cmd, Command):
1260
- cmd.reset()
1261
- cmd.unload()
1262
- cmd.__unload__()
1263
-
1174
+ self._commands.pop(id, None)
1264
1175
  elif cls == Trigger:
1265
1176
  self._triggers.pop(id, None)
1266
1177
  elif cls == Timer:
1267
- timer = self._timers.pop(id, None)
1268
- if isinstance(timer, Timer):
1269
- timer.enabled = False
1178
+ self._timers.pop(id, None)
1270
1179
  elif cls == GMCPTrigger:
1271
1180
  self._gmcp.pop(id, None)
1272
1181
 
1273
-
1274
1182
  def _delObjects(self, ids: Iterable, cls: type):
1275
1183
  "删除多个指定元素"
1276
1184
  for id in ids:
1277
1185
  self._delObject(id, cls)
1278
1186
 
1279
- def delObject(self, obj):
1280
- """
1281
- 从会话中移除一个对象,可直接删除 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类本身
1282
-
1283
- ** 注 ** 现在 delObject 和 delObjects 使用结果相同,都可以清除单个对象、对个对象的list, tuple或dict, 可以有效防止代码写错
1284
-
1285
- :param obj: 要删除的多个特定对象组成的元组、列表或者字典,可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或其子类
1286
-
1287
- 示例:
1288
- .. code:: Python
1289
-
1290
- class Configuration:
1291
- def __init__(self, session):
1292
- self.session = session
1293
-
1294
- ali = SimpleAlias(session, r'^gta$', 'get all', id = 'my_ali1')
1295
-
1296
- # 以下几种方式均可将该别名添加到会话
1297
- session.addObject(ali)
1298
- session.addAlias(ali)
1299
-
1300
- # 以下三种方式均可以删除该别名
1301
- session.delObject(ali)
1302
- session.delAlias(ali)
1303
- session.delAlias("my_ali1")
1304
-
1305
- """
1306
- if isinstance(obj, Alias):
1307
- self._aliases.pop(obj.id, None)
1308
- elif isinstance(obj, Command):
1309
- obj.reset()
1310
- obj.unload()
1311
- obj.__unload__()
1312
- self._commands.pop(obj.id, None)
1313
- elif isinstance(obj, Trigger):
1314
- self._triggers.pop(obj.id, None)
1315
- elif isinstance(obj, Timer):
1316
- obj.enabled = False
1317
- self._timers.pop(obj.id, None)
1318
- elif isinstance(obj, GMCPTrigger):
1319
- self._gmcp.pop(obj.id, None)
1320
-
1321
- elif isinstance(obj, (list, tuple, dict)):
1322
- self.delObjects(obj)
1323
-
1324
- def delObjects(self, objs):
1325
- """
1326
- 从会话中移除一组对象,可直接删除多个 Alias, Trigger, GMCPTrigger, Command, Timer
1327
-
1328
- ** 注 ** 现在 delObject 和 delObjects 使用结果相同,都可以清除单个对象、对个对象的list, tuple或dict, 可以有效防止代码写错
1329
-
1330
- :param objs: 要删除的一组对象的元组、列表或者字典(保持兼容性),其中对象可以为 Alias, Trigger, GMCPTrigger, Command, Timer 或它们的子类
1331
-
1332
- 示例:
1333
-
1334
- .. code:: Python
1335
-
1336
- class Configuration:
1337
- def __init__(self, session):
1338
- self.session = session
1339
-
1340
- self.objs = [
1341
- SimpleAlias(session, r'^gta$', 'get all;xixi'),
1342
- SimpleTrigger(session, r'^[> ]*你嘻嘻地笑了起来.+', 'haha'),
1343
- SimpleTimer(session, 'xixi', timeout = 10)
1344
- ]
1345
-
1346
- self.session.addObjects(self.objs)
1347
-
1348
- def __unload__(self):
1349
- "卸载本模块时,删除所有本模块添加的对象"
1350
- self.session.delObjects(self.objs)
1351
-
1352
- """
1353
- if isinstance(objs, list) or isinstance(objs, tuple):
1354
- for item in objs:
1355
- self.delObject(item)
1356
-
1357
- elif isinstance(objs, dict):
1358
- for key, item in objs.items():
1359
- self.delObject(item)
1360
-
1361
- elif isinstance(objs, BaseObject):
1362
- self.delObject(objs)
1363
-
1364
- def addAliases(self, alis):
1187
+ def addAliases(self, alis: dict):
1365
1188
  """
1366
1189
  向会话中增加多个别名
1367
1190
 
@@ -1382,55 +1205,55 @@ class Session:
1382
1205
  self._aliases['my_ali2'] = SimpleAlias(self.session, "s", "south", id = "my_ali2")
1383
1206
  self.session.addAliases(self._aliases)
1384
1207
  """
1385
- self._addObjects(alis)
1208
+ self._addObjects(alis, Alias)
1386
1209
 
1387
- def addCommands(self, cmds):
1210
+ def addCommands(self, cmds: dict):
1388
1211
  """
1389
1212
  向会话中增加多个命令。使用方法与 addAliases 类似。
1390
1213
 
1391
1214
  :param cmds: 多个命令的字典。字典 key 应为每个命令的 id。
1392
1215
  """
1393
- self._addObjects(cmds)
1216
+ self._addObjects(cmds, Command)
1394
1217
 
1395
- def addTriggers(self, tris):
1218
+ def addTriggers(self, tris: dict):
1396
1219
  """
1397
1220
  向会话中增加多个触发器。使用方法与 addAliases 类似。
1398
1221
 
1399
1222
  :param tris: 多个触发器的字典。字典 key 应为每个触发器的 id。
1400
1223
  """
1401
- self._addObjects(tris)
1224
+ self._addObjects(tris, Trigger)
1402
1225
 
1403
- def addGMCPs(self, gmcps):
1226
+ def addGMCPs(self, gmcps: dict):
1404
1227
  """
1405
1228
  向会话中增加多个GMCPTrigger。使用方法与 addAliases 类似。
1406
1229
 
1407
1230
  :param gmcps: 多个GMCPTrigger的字典。字典 key 应为每个GMCPTrigger的 id。
1408
1231
  """
1409
- self._addObjects(gmcps)
1232
+ self._addObjects(gmcps, GMCPTrigger)
1410
1233
 
1411
- def addTimers(self, tis):
1234
+ def addTimers(self, tis: dict):
1412
1235
  """
1413
1236
  向会话中增加多个定时器。使用方法与 addAliases 类似。
1414
1237
 
1415
1238
  :param tis: 多个定时器的字典。字典 key 应为每个定时器的 id。
1416
1239
  """
1417
- self._addObjects(tis)
1240
+ self._addObjects(tis, Timer)
1418
1241
 
1419
- def addAlias(self, ali):
1242
+ def addAlias(self, ali: Alias):
1420
1243
  """
1421
1244
  向会话中增加一个别名。
1422
1245
 
1423
1246
  :param ali: 要增加的别名对象,应为 Alias 类型或其子类
1424
1247
  """
1425
- self._addObject(ali)
1248
+ self._addObject(ali, Alias)
1426
1249
 
1427
- def addCommand(self, cmd):
1250
+ def addCommand(self, cmd: Command):
1428
1251
  """
1429
1252
  向会话中增加一个命令。
1430
1253
 
1431
1254
  :param cmd: 要增加的命令对象,应为 Command 类型或其子类
1432
1255
  """
1433
- self._addObject(cmd)
1256
+ self._addObject(cmd, Command)
1434
1257
 
1435
1258
  def addTrigger(self, tri: Trigger):
1436
1259
  """
@@ -1438,7 +1261,7 @@ class Session:
1438
1261
 
1439
1262
  :param tri: 要增加的触发器对象,应为 Trigger 类型或其子类
1440
1263
  """
1441
- self._addObject(tri)
1264
+ self._addObject(tri, Trigger)
1442
1265
 
1443
1266
  def addTimer(self, ti: Timer):
1444
1267
  """
@@ -1446,7 +1269,7 @@ class Session:
1446
1269
 
1447
1270
  :param ti: 要增加的定时器对象,应为 Timer 类型或其子类
1448
1271
  """
1449
- self._addObject(ti)
1272
+ self._addObject(ti, Timer)
1450
1273
 
1451
1274
  def addGMCP(self, gmcp: GMCPTrigger):
1452
1275
  """
@@ -1455,7 +1278,7 @@ class Session:
1455
1278
  :param gmcp: 要增加的GMCP触发器对象,应为 GMCPTrigger 类型或其子类
1456
1279
  """
1457
1280
 
1458
- self._addObject(gmcp)
1281
+ self._addObject(gmcp, GMCPTrigger)
1459
1282
 
1460
1283
  def delAlias(self, ali):
1461
1284
  """
@@ -1574,7 +1397,7 @@ class Session:
1574
1397
  for ti in ti_s:
1575
1398
  self.delTimer(ti)
1576
1399
 
1577
- def delGMCP(self, gmcp):
1400
+ def delGMCP(self, gmcp: GMCPTrigger):
1578
1401
  """
1579
1402
  从会话中移除一个GMCP触发器,可接受 GMCPTrigger 对象或其的id。使用方法与 delAlias 类似
1580
1403
 
@@ -1890,7 +1713,6 @@ class Session:
1890
1713
  该函数不应该在代码中直接调用。
1891
1714
 
1892
1715
  相关命令:
1893
- - #disconnect
1894
1716
  - #close
1895
1717
  - #exit
1896
1718
  '''
@@ -1912,18 +1734,6 @@ class Session:
1912
1734
 
1913
1735
  self.info("已经与服务器连接了 {}".format(time_msg))
1914
1736
 
1915
- def handle_disconnect(self, code: CodeLine = None, *args, **kwargs):
1916
- '''
1917
- 嵌入命令 #disconnect / #dis 的执行函数,断开到远程服务器的连接(仅当远程服务器已连接时有效)。
1918
- 该函数不应该在代码中直接调用。
1919
-
1920
- 相关命令:
1921
- - #connect
1922
- - #close
1923
- '''
1924
-
1925
- self.disconnect()
1926
-
1927
1737
  def handle_variable(self, code: CodeLine = None, *args, **kwargs):
1928
1738
  '''
1929
1739
  嵌入命令 #variable / #var 的执行函数,操作会话变量。
@@ -1962,7 +1772,7 @@ class Session:
1962
1772
  else:
1963
1773
  vars_simple[k] = v
1964
1774
 
1965
- width = self.application.get_width() - 2 # 保留2个字符,防止 > 导致换行
1775
+ width = self.application.get_width()
1966
1776
 
1967
1777
  title = f" VARIABLE LIST IN SESSION {self.name} "
1968
1778
  left = (width - len(title)) // 2
@@ -1970,7 +1780,6 @@ class Session:
1970
1780
  self.writetobuffer("="*left + title + "="*right, newline = True)
1971
1781
 
1972
1782
  # print vars in simple, 每个变量占40格,一行可以多个变量
1973
- # 这里可以考虑调整一下,默认40, 但如果一个变量值太长,则选择占两个位置
1974
1783
  var_count = len(vars_simple)
1975
1784
  var_per_line = (width - 2) // 40
1976
1785
  lines = math.ceil(var_count / var_per_line)
@@ -1986,18 +1795,14 @@ class Session:
1986
1795
  self.writetobuffer(" " * left_space)
1987
1796
  line_vars = var_keys[start:end]
1988
1797
  for var in line_vars:
1989
- repr = vars_simple[var].__repr__()
1990
- vwidth = 22 - (wcswidth(repr) - len(repr))
1991
- self.writetobuffer("{0} = {1}".format(var.rjust(20), repr.ljust(vwidth)))
1992
- #self.writetobuffer("{0:>18} = {1:<19}".format(var, vars_simple[var].__repr__()))
1798
+ self.writetobuffer("{0:>18} = {1:<19}".format(var, vars_simple[var].__repr__()))
1993
1799
 
1994
1800
  self.writetobuffer("", newline = True)
1995
1801
 
1996
1802
  # print vars in complex, 每个变量占1行
1997
- var_keys = sorted(vars_complex.keys())
1998
- for key in var_keys:
1803
+ for k, v in vars_complex.items():
1999
1804
  self.writetobuffer(" " * left_space)
2000
- self.writetobuffer("{0:>20} = {1}".format(key, vars_complex[key].__repr__()), newline = True)
1805
+ self.writetobuffer("{0:>18} = {1}".format(k, v.__repr__()), newline = True)
2001
1806
 
2002
1807
  self.writetobuffer("="*width, newline = True)
2003
1808
 
@@ -2050,7 +1855,7 @@ class Session:
2050
1855
  else:
2051
1856
  vars_simple[k] = v
2052
1857
 
2053
- width = self.application.get_width() - 2 # 保留2个字符,防止 > 导致换行
1858
+ width = self.application.get_width()
2054
1859
 
2055
1860
  title = f" GLOBAL VARIABLES LIST "
2056
1861
  left = (width - len(title)) // 2
@@ -2073,23 +1878,21 @@ class Session:
2073
1878
  self.writetobuffer(" " * left_space)
2074
1879
  line_vars = var_keys[start:end]
2075
1880
  for var in line_vars:
2076
- repr = vars_simple[var].__repr__()
2077
- vwidth = 22 - (wcswidth(repr) - len(repr))
2078
- self.writetobuffer("{0} = {1}".format(var.rjust(20), repr.ljust(vwidth)))
1881
+ self.writetobuffer("{0:>18} = {1:<19}".format(var, vars_simple[var].__repr__()))
2079
1882
 
2080
1883
  self.writetobuffer("", newline = True)
2081
1884
 
2082
1885
  # print vars in complex, 每个变量占1行
2083
1886
  for k, v in vars_complex.items():
2084
1887
  self.writetobuffer(" " * left_space)
2085
- self.writetobuffer("{0:>20} = {1}".format(k, v.__repr__()), newline = True)
1888
+ self.writetobuffer("{0:>18} = {1}".format(k, v.__repr__()), newline = True)
2086
1889
 
2087
1890
  self.writetobuffer("="*width, newline = True)
2088
1891
 
2089
1892
  elif len(args) == 1:
2090
1893
  var = args[0]
2091
1894
  if var in self.application.globals.keys():
2092
- self.info("{0:>20} = {1:<22}".format(var, self.application.get_globals(var).__repr__()), "全局变量")
1895
+ self.info("{0:>18} = {1:<19}".format(var, self.application.get_globals(var).__repr__()), "全局变量")
2093
1896
  else:
2094
1897
  self.info("全局空间不存在名称为 {} 的变量".format(var), "全局变量")
2095
1898
 
@@ -2164,7 +1967,7 @@ class Session:
2164
1967
  self.info("创建Timer {} 成功: {}".format(ti.id, ti.__repr__()))
2165
1968
 
2166
1969
  def handle_alias(self, code: CodeLine = None, *args, **kwargs):
2167
- r"""
1970
+ '''
2168
1971
  嵌入命令 #alias / #ali 的执行函数,操作别名。该命令可以不带参数、带一个参数或者两个参数。
2169
1972
  该函数不应该在代码中直接调用。
2170
1973
 
@@ -2195,7 +1998,7 @@ class Session:
2195
1998
  - #trigger
2196
1999
  - #timer
2197
2000
  - #command
2198
- """
2001
+ '''
2199
2002
 
2200
2003
  self._handle_objs("Alias", self._aliases, *code.code[2:])
2201
2004
 
@@ -2554,7 +2357,6 @@ class Session:
2554
2357
  self._variables.clear()
2555
2358
  self._tasks.clear()
2556
2359
 
2557
-
2558
2360
  def load_module(self, module_names):
2559
2361
  """
2560
2362
  模块加载函数。
@@ -2578,12 +2380,32 @@ class Session:
2578
2380
  "加载指定名称模块"
2579
2381
  try:
2580
2382
  if module_name not in self._modules.keys():
2581
- self._modules[module_name] = ModuleInfo(module_name, self)
2383
+ mod = importlib.import_module(module_name)
2384
+ if hasattr(mod, 'Configuration'):
2385
+ config = mod.Configuration(self)
2386
+ self._modules[module_name] = {"module": mod, "config": config}
2387
+ self.info(f"主配置模块 {module_name} 加载完成.")
2388
+ else:
2389
+ self._modules[module_name] = {"module": mod, "config": None}
2390
+ self.info(f"子配置模块 {module_name} 加载完成.")
2582
2391
 
2583
2392
  else:
2584
- mod = self._modules[module_name]
2585
- if isinstance(mod, ModuleInfo):
2586
- mod.reload()
2393
+ mod = self._modules[module_name]["module"]
2394
+ config = self._modules[module_name]["config"]
2395
+ if config:
2396
+ if hasattr(config, "unload"):
2397
+ unload = getattr(config, "unload", None)
2398
+ if callable(unload):
2399
+ unload(config)
2400
+ del config
2401
+ mod = importlib.reload(mod)
2402
+ if hasattr(mod, 'Configuration'):
2403
+ config = mod.Configuration(self)
2404
+ self._modules[module_name] = {"module": mod, "config": config}
2405
+ self.info(f"主配置模块 {module_name} 重新加载完成.")
2406
+ else:
2407
+ self._modules[module_name] = {"module": mod, "config": None}
2408
+ self.info(f"子配置模块 {module_name} 重新加载完成.")
2587
2409
 
2588
2410
  except Exception as e:
2589
2411
  import traceback
@@ -2609,11 +2431,20 @@ class Session:
2609
2431
  self._unload_module(mod)
2610
2432
 
2611
2433
  def _unload_module(self, module_name):
2612
- "卸载指定名称模块。卸载支持需要模块的Configuration实现 __unload__ 或 unload 方法"
2434
+ "卸载指定名称模块。卸载支持需要模块的Configuration实现__del__方法"
2613
2435
  if module_name in self._modules.keys():
2614
- mod = self._modules.pop(module_name)
2615
- if isinstance(mod, ModuleInfo):
2616
- mod.unload()
2436
+ mod = self._modules[module_name]["module"]
2437
+ config = self._modules[module_name]["config"]
2438
+ if config:
2439
+ if hasattr(config, "unload"):
2440
+ unload = getattr(config, "unload", None)
2441
+ if callable(unload):
2442
+ unload(config)
2443
+
2444
+ del config
2445
+ del mod
2446
+ self._modules.pop(module_name)
2447
+ self.info(f"配置模块 {module_name} 已成功卸载.")
2617
2448
 
2618
2449
  else:
2619
2450
  self.warning(f"指定模块名称 {module_name} 并未加载.")
@@ -2627,9 +2458,9 @@ class Session:
2627
2458
  :param module_names: 要重新加载的模块清单。为元组/列表时,卸载指定名称的系列模块,当名称为字符串时,卸载单个模块。当不指定时,重新加载所有已加载模块。
2628
2459
  """
2629
2460
  if module_names is None:
2630
- for name, module in self._modules.items():
2631
- if isinstance(module, ModuleInfo):
2632
- module.reload()
2461
+ self.clean()
2462
+ mods = list(self._modules.keys())
2463
+ self.load_module(mods)
2633
2464
 
2634
2465
  self.info(f"所有配置模块全部重新加载完成.")
2635
2466
 
@@ -2637,17 +2468,14 @@ class Session:
2637
2468
  for mod in module_names:
2638
2469
  mod = mod.strip()
2639
2470
  if mod in self._modules.keys():
2640
- module = self._modules[mod]
2641
- if isinstance(module, ModuleInfo):
2642
- module.reload()
2471
+ self.load_module(mod)
2643
2472
  else:
2644
2473
  self.warning(f"指定模块名称 {mod} 并未加载,无法重新加载.")
2645
2474
 
2646
2475
  elif isinstance(module_names, str):
2647
2476
  if module_names in self._modules.keys():
2648
- module = self._modules[module_names]
2649
- if isinstance(module, ModuleInfo):
2650
- module.reload()
2477
+ mod = module_names.strip()
2478
+ self.load_module(mod)
2651
2479
  else:
2652
2480
  self.warning(f"指定模块名称 {module_names} 并未加载,无法重新加载.")
2653
2481
 
@@ -2731,7 +2559,7 @@ class Session:
2731
2559
 
2732
2560
  elif mod in self.plugins.keys():
2733
2561
  self.application.reload_plugin(self.plugins[mod])
2734
- self.info(f'插件 {mod} 重新加载完成!')
2562
+
2735
2563
  else:
2736
2564
  self.warning(f"指定名称 {mod} 既未找到模块,也未找到插件,重新加载失败..")
2737
2565
 
@@ -2785,29 +2613,12 @@ class Session:
2785
2613
  - #reload
2786
2614
  '''
2787
2615
 
2788
- args = code.code[2:]
2789
-
2790
- if len(args) == 0:
2791
- count = len(self._modules.keys())
2792
- if count == 0:
2793
- self.info("当前会话并未加载任何模块。", "MODULES")
2794
- else:
2795
- self.info(f"当前会话已加载 {count} 个模块,包括(按加载顺序排列):{list(self._modules.keys())}", "MODULES")
2616
+ count = len(self._modules.keys())
2617
+ if count == 0:
2618
+ self.info("当前会话并未加载任何模块。", "MODULES")
2619
+ else:
2620
+ self.info(f"当前会话已加载 {count} 个模块,包括(按加载顺序排列):{list(self._modules.keys())}", "MODULES")
2796
2621
 
2797
- elif len(args) >= 1:
2798
- modules = ",".join(args).split(",")
2799
- for mod in modules:
2800
- if mod in self._modules.keys():
2801
- module = self._modules[mod]
2802
- if isinstance(module, ModuleInfo):
2803
- if module.ismainmodule:
2804
- self.info(f"模块 {module.name} 中包含的配置包括: {', '.join(module.config.keys())}")
2805
- else:
2806
- self.info(f"模块 {module.name} 为子模块,不包含配置。")
2807
-
2808
- else:
2809
- self.info(f"本会话中不存在指定名称 {mod} 的模块,可能是尚未加载到本会话中")
2810
-
2811
2622
  def handle_reset(self, code: CodeLine = None, *args, **kwargs):
2812
2623
  '''
2813
2624
  嵌入命令 #reset 的执行函数,复位全部脚本。该命令不带参数。
@@ -2827,8 +2638,7 @@ class Session:
2827
2638
 
2828
2639
  def handle_save(self, code: CodeLine = None, *args, **kwargs):
2829
2640
  '''
2830
- 嵌入命令 #save 的执行函数,保存当前会话变量(系统变量和临时变量除外)至文件。该命令不带参数。
2831
- 系统变量包括 %line, %copy 和 %raw 三个,临时变量是指变量名已下划线开头的变量
2641
+ 嵌入命令 #save 的执行函数,保存当前会话变量(系统变量除外)至文件。该命令不带参数。
2832
2642
  该函数不应该在代码中直接调用。
2833
2643
 
2834
2644
  使用:
@@ -2849,10 +2659,10 @@ class Session:
2849
2659
  with open(file, "wb") as fp:
2850
2660
  saved = dict()
2851
2661
  saved.update(self._variables)
2852
- keys = list(saved.keys())
2853
- for key in keys:
2854
- if key.startswith("_"):
2855
- saved.pop(key)
2662
+ # keys = list(saved.keys())
2663
+ # for key in keys:
2664
+ # if key.startswith("%"):
2665
+ # saved.pop(key)
2856
2666
  saved.pop("%line", None)
2857
2667
  saved.pop("%raw", None)
2858
2668
  saved.pop("%copy", None)
@@ -2951,7 +2761,7 @@ class Session:
2951
2761
  if name in self.plugins.keys():
2952
2762
  plugin = self.plugins[name]
2953
2763
  self.info(f"{plugin.desc['DESCRIPTION']}, 版本 {plugin.desc['VERSION']} 作者 {plugin.desc['AUTHOR']} 发布日期 {plugin.desc['RELEASE_DATE']}", f"PLUGIN {name}")
2954
- self.writetobuffer(plugin.help, True)
2764
+ self.writetobuffer(plugin.help)
2955
2765
 
2956
2766
  def handle_replace(self, code: CodeLine = None, *args, **kwargs):
2957
2767
  '''
@@ -3130,8 +2940,8 @@ class Session:
3130
2940
 
3131
2941
  示例:
3132
2942
  - ``#log`` : 在当前会话窗口列出所有记录器状态
3133
- - ``#log start`` : 启动本会话默认记录器(记录器名为会话名)。该记录器以纯文本模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 log 目录下 name.log 文件的后端
3134
- - ``#log start -r`` : 启动本会话默认记录器。该记录器以raw模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 log 目录下 name.log 文件的后端
2943
+ - ``#log start`` : 启动本会话默认记录器(记录器名为会话名)。该记录器以纯文本模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 name.log 文件的后端
2944
+ - ``#log start -r`` : 启动本会话默认记录器。该记录器以raw模式,将后续所有屏幕输出、键盘键入、命令输入等记录到 name.log 文件的后端
3135
2945
  - ``#log start chat`` : 启动名为 chat 的记录器。该记录器以纯文本模式,记录代码中调用过该记录器 .log 进行记录的信息
3136
2946
  - ``#log stop`` : 停止本会话默认记录器(记录器名为会话名)。
3137
2947
 
@@ -3189,19 +2999,8 @@ class Session:
3189
2999
  elif (args[0] == "show"):
3190
3000
  if len(args) > 1 and not args[1].startswith('-'):
3191
3001
  file = args[1]
3192
- if os.path.exists(file):
3193
- filepath = os.path.abspath(file)
3194
- #self.info(f'file {filepath} exists, will be shown.')
3195
- self.application.logFileShown = filepath
3196
- self.application.showLogInTab()
3197
- elif os.path.exists(os.path.join('./log', file)):
3198
- filepath = os.path.abspath(os.path.join('./log', file))
3199
- #self.info(f'file {filepath} exists, will be shown.')
3200
- self.application.logFileShown = filepath
3201
- self.application.showLogInTab()
3202
- else:
3203
- self.warning(f'指定记录文件 {file} 不存在!')
3204
-
3002
+ self.application.logFileShown = file
3003
+ self.application.showLogInTab()
3205
3004
  else:
3206
3005
  self.application.show_logSelectDialog()
3207
3006