pymud 0.21.0a4__py3-none-any.whl → 0.21.0a5__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/__init__.py CHANGED
@@ -1,17 +1,17 @@
1
1
  from .settings import Settings
2
2
  from .pymud import PyMudApp
3
- from .modules import IConfig, PymudDecorator, PymudMeta, alias, trigger, timer, gmcp
3
+ from .modules import IConfigBase, IConfig, PymudMeta
4
4
  from .objects import CodeBlock, Alias, SimpleAlias, Trigger, SimpleTrigger, Command, SimpleCommand, Timer, SimpleTimer, GMCPTrigger
5
5
  from .extras import DotDict
6
- from .session import Session, exception, async_exception
6
+ from .session import Session
7
7
  from .logger import Logger
8
8
  from .main import main
9
+ from .decorators import exception, async_exception, PymudDecorator, alias, trigger, timer, gmcp
9
10
 
10
11
  __all__ = [
11
- "PymudDecorator", "PymudMeta", "alias", "trigger", "timer", "gmcp",
12
- "IConfig", "PyMudApp", "Settings", "CodeBlock",
12
+ "PymudMeta", "IConfigBase", "IConfig", "PyMudApp", "Settings", "CodeBlock",
13
13
  "Alias", "SimpleAlias", "Trigger", "SimpleTrigger",
14
14
  "Command", "SimpleCommand", "Timer", "SimpleTimer",
15
15
  "GMCPTrigger", "Session", "DotDict", "Logger", "main",
16
- "exception", "async_exception"
16
+ "exception", "async_exception", "PymudDecorator", "alias", "trigger", "timer", "gmcp",
17
17
  ]
pymud/decorators.py ADDED
@@ -0,0 +1,234 @@
1
+ import sys, functools, traceback
2
+ from typing import Union, Optional, List
3
+
4
+ def print_exception(session, e: Exception):
5
+ """打印异常信息"""
6
+ from .settings import Settings
7
+ from .session import Session
8
+ if isinstance(session, Session):
9
+ # tb = sys.exc_info()[2]
10
+ # frames = traceback.extract_tb(tb)
11
+ # frame = frames[-1]
12
+ # session.error(Settings.gettext("exception_traceback", frame.filename, frame.lineno, frame.name), Settings.gettext("script_error"))
13
+ # if frame.line:
14
+ # session.error(f" {frame.line}", Settings.gettext("script_error"))
15
+
16
+ # session.error(Settings.gettext("exception_message", type(e).__name__, e), Settings.gettext("script_error"))
17
+ # session.error("===========================", Settings.gettext("script_error"))
18
+ session.error(traceback.format_exc(), Settings.gettext("script_error"))
19
+
20
+ def exception(func):
21
+ """方法异常处理装饰器,捕获异常后通过会话的session.error打印相关信息"""
22
+ @functools.wraps(func)
23
+ def wrapper(self, *args, **kwargs):
24
+ from .objects import BaseObject
25
+ from .modules import ModuleInfo, IConfig
26
+ from .session import Session
27
+ from .settings import Settings
28
+ try:
29
+ return func(self, *args, **kwargs)
30
+ except Exception as e:
31
+ # 调用类的错误处理方法
32
+ if isinstance(self, Session):
33
+ session = self
34
+ elif isinstance(self, (BaseObject, IConfig, ModuleInfo)):
35
+ session = self.session
36
+ else:
37
+ session = None
38
+
39
+ if isinstance(session, Session):
40
+ print_exception(session, e)
41
+ #session.error(Settings.gettext("exception_message", e, type(e)))
42
+ #session.error(Settings.gettext("exception_traceback", traceback.format_exc()))
43
+ else:
44
+ raise # 当没有会话时,选择重新抛出异常
45
+ return wrapper
46
+
47
+ def async_exception(func):
48
+ """异步方法异常处理装饰器,捕获异常后通过会话的session.error打印相关信息"""
49
+ @functools.wraps(func)
50
+ async def wrapper(self, *args, **kwargs):
51
+ from .objects import BaseObject
52
+ from .modules import ModuleInfo, IConfig
53
+ from .session import Session
54
+ from .settings import Settings
55
+ try:
56
+ return await func(self, *args, **kwargs)
57
+ except Exception as e:
58
+ if isinstance(self, Session):
59
+ session = self
60
+ elif isinstance(self, (BaseObject, IConfig, ModuleInfo)):
61
+ session = self.session
62
+ else:
63
+ session = None
64
+
65
+ if isinstance(session, Session):
66
+ print_exception(session, e)
67
+
68
+ else:
69
+ raise # 当没有会话时,选择重新抛出异常
70
+ return wrapper
71
+
72
+
73
+ class PymudDecorator:
74
+ """
75
+ 装饰器基类。使用装饰器可以快捷创建各类Pymud基础对象。
76
+
77
+ :param type: 装饰器的类型,用于区分不同的装饰器,为字符串类型。
78
+ :param args: 可变位置参数,用于传递额外的参数。
79
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
80
+ """
81
+ def __init__(self, type: str, *args, **kwargs):
82
+ self.type = type
83
+ self.args = args
84
+ self.kwargs = kwargs
85
+
86
+ def __call__(self, func):
87
+ decos = getattr(func, "__pymud_decorators__", [])
88
+ decos.append(self)
89
+ func.__pymud_decorators__ = decos
90
+
91
+ return func
92
+
93
+ def __repr__(self):
94
+ return f"<{self.__class__.__name__} type = {self.type} args = {self.args} kwargs = {self.kwargs}>"
95
+
96
+
97
+ def alias(
98
+ patterns: Union[List[str], str],
99
+ id: Optional[str] = None,
100
+ group: str = "",
101
+ enabled: bool = True,
102
+ ignoreCase: bool = False,
103
+ isRegExp: bool = True,
104
+ keepEval: bool = False,
105
+ expandVar: bool = True,
106
+ priority: int = 100,
107
+ oneShot: bool = False,
108
+ *args, **kwargs):
109
+ """
110
+ 使用装饰器创建一个别名(Alias)对象。被装饰的函数将在别名成功匹配时调用。
111
+ 被装饰的函数,除第一个参数为类实例本身self之外,另外包括id, line, wildcards三个参数。
112
+ 其中id为别名对象的唯一标识符,line为匹配的文本行,wildcards为匹配的通配符列表。
113
+
114
+ :param patterns: 别名匹配的模式。
115
+ :param id: 别名对象的唯一标识符,不指定时将自动生成唯一标识符。
116
+ :param group: 别名所属的组名,默认为空字符串。
117
+ :param enabled: 别名是否启用,默认为 True。
118
+ :param ignoreCase: 匹配时是否忽略大小写,默认为 False。
119
+ :param isRegExp: 模式是否为正则表达式,默认为 True。
120
+ :param keepEval: 若存在多个可匹配的别名时,是否持续匹配,默认为 False。
121
+ :param expandVar: 是否展开变量,默认为 True。
122
+ :param priority: 别名的优先级,值越小优先级越高,默认为 100。
123
+ :param oneShot: 别名是否只触发一次后自动失效,默认为 False。
124
+ :param args: 可变位置参数,用于传递额外的参数。
125
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
126
+ :return: PymudDecorator 实例,类型为 "alias"。
127
+ """
128
+ # 将传入的参数更新到 kwargs 字典中
129
+ kwargs.update({
130
+ "patterns": patterns,
131
+ "id": id,
132
+ "group": group,
133
+ "enabled": enabled,
134
+ "ignoreCase": ignoreCase,
135
+ "isRegExp": isRegExp,
136
+ "keepEval": keepEval,
137
+ "expandVar": expandVar,
138
+ "priority": priority,
139
+ "oneShot": oneShot})
140
+
141
+ # 如果 id 为 None,则从 kwargs 中移除 "id" 键
142
+ if not id:
143
+ kwargs.pop("id")
144
+
145
+ return PymudDecorator("alias", *args, **kwargs)
146
+
147
+ def trigger(
148
+ patterns: Union[List[str], str],
149
+ id: Optional[str] = None,
150
+ group: str = "",
151
+ enabled: bool = True,
152
+ ignoreCase: bool = False,
153
+ isRegExp: bool = True,
154
+ keepEval: bool = False,
155
+ expandVar: bool = True,
156
+ raw: bool = False,
157
+ priority: int = 100,
158
+ oneShot: bool = False,
159
+ *args, **kwargs):
160
+ """
161
+ 使用装饰器创建一个触发器(Trigger)对象。
162
+
163
+ :param patterns: 触发器匹配的模式。单行模式可以是字符串或正则表达式,多行模式必须是元组或列表,其中每个元素都是字符串或正则表达式。
164
+ :param id: 触发器对象的唯一标识符,不指定时将自动生成唯一标识符。
165
+ :param group: 触发器所属的组名,默认为空字符串。
166
+ :param enabled: 触发器是否启用,默认为 True。
167
+ :param ignoreCase: 匹配时是否忽略大小写,默认为 False。
168
+ :param isRegExp: 模式是否为正则表达式,默认为 True。
169
+ :param keepEval: 若存在多个可匹配的触发器时,是否持续匹配,默认为 False。
170
+ :param expandVar: 是否展开变量,默认为 True。
171
+ :param raw: 是否使用原始匹配方式,默认为 False。原始匹配方式下,不对 VT100 下的 ANSI 颜色进行解码,因此可以匹配颜色;正常匹配仅匹配文本。
172
+ :param priority: 触发器的优先级,值越小优先级越高,默认为 100。
173
+ :param oneShot: 触发器是否只触发一次后自动失效,默认为 False。
174
+ :param args: 可变位置参数,用于传递额外的参数。
175
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
176
+ :return: PymudDecorator 实例,类型为 "trigger"。
177
+ """
178
+ # 将传入的参数更新到 kwargs 字典中
179
+ kwargs.update({
180
+ "patterns": patterns,
181
+ "id": id,
182
+ "group": group,
183
+ "enabled": enabled,
184
+ "ignoreCase": ignoreCase,
185
+ "isRegExp": isRegExp,
186
+ "keepEval": keepEval,
187
+ "expandVar": expandVar,
188
+ "raw": raw,
189
+ "priority": priority,
190
+ "oneShot": oneShot})
191
+ if not id:
192
+ kwargs.pop("id")
193
+ return PymudDecorator("trigger", *args, **kwargs)
194
+
195
+ def timer(timeout: float, id: Optional[str] = None, group: str = "", enabled: bool = True, *args, **kwargs):
196
+ """
197
+ 使用装饰器创建一个定时器(Timer)对象。
198
+
199
+ :param timeout: 定时器超时时间,单位为秒。
200
+ :param id: 定时器对象的唯一标识符,不指定时将自动生成唯一标识符。
201
+ :param group: 定时器所属的组名,默认为空字符串。
202
+ :param enabled: 定时器是否启用,默认为 True。
203
+ :param args: 可变位置参数,用于传递额外的参数。
204
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
205
+ :return: PymudDecorator 实例,类型为 "timer"。
206
+ """
207
+ kwargs.update({
208
+ "timeout": timeout,
209
+ "id": id,
210
+ "group": group,
211
+ "enabled": enabled
212
+ })
213
+ if not id:
214
+ kwargs.pop("id")
215
+ return PymudDecorator("timer", *args, **kwargs)
216
+
217
+ def gmcp(name: str, group: str = "", enabled: bool = True, *args, **kwargs):
218
+ """
219
+ 使用装饰器创建一个GMCP触发器(GMCPTrigger)对象。
220
+
221
+ :param name: GMCP触发器的名称。
222
+ :param group: GMCP触发器所属的组名,默认为空字符串。
223
+ :param enabled: GMCP触发器是否启用,默认为 True。
224
+ :param args: 可变位置参数,用于传递额外的参数。
225
+ :param kwargs: 可变关键字参数,用于传递额外的键值对参数。
226
+ :return: PymudDecorator 实例,类型为 "gmcp"。
227
+ """
228
+ kwargs.update({
229
+ "id": name,
230
+ "group": group,
231
+ "enabled": enabled
232
+ })
233
+
234
+ return PymudDecorator("gmcp", *args, **kwargs)
pymud/extras.py CHANGED
@@ -310,7 +310,7 @@ class SessionBufferControl(BufferControl):
310
310
  # Focus buffer when clicked.
311
311
  cur_control = get_app().layout.current_control
312
312
  cur_buffer = get_app().layout.current_buffer
313
- # 这里时修改的内容
313
+ # 这里是修改的内容
314
314
  if (cur_control == self) or (cur_buffer and cur_buffer.name == "input"):
315
315
  if self._last_get_processed_line:
316
316
  processed_line = self._last_get_processed_line(position.y)
pymud/lang/i18n_chs.py CHANGED
@@ -86,13 +86,17 @@ TRANSLATION = {
86
86
  "load_fail" : "加载失败",
87
87
  "unload_ok" : "卸载完成",
88
88
  "reload_ok" : "重新加载完成",
89
+ "msg_plugin_unloaded" : "本会话中插件 {0} 已停用。",
90
+ "msg_plugin_loaded" : "本会话中插件 {0} 已启用。",
89
91
 
90
92
  # text in objects.py
91
93
  "excpetion_brace_not_matched" : "错误的代码块,大括号数量不匹配",
92
94
  "exception_quote_not_matched" : "引号的数量不匹配",
93
95
  "exception_forced_async" : "该命令中同时存在强制同步命令和强制异步命令,将使用异步执行,同步命令将失效。",
94
96
  "exception_session_type_fail" : "session 必须是 Session 类型对象的实例!",
95
- "exception_in_async" : "异步执行中遇到异常, {}",
97
+ "exception_message" : "异常信息: <{}> {}",
98
+ "exception_traceback" : '脚本执行异常, 异常位于文件"{}"中的第{}行的"{}"函数中。',
99
+ "script_error" : "脚本错误",
96
100
 
97
101
 
98
102
  # text display in session.py
@@ -173,7 +177,7 @@ TRANSLATION = {
173
177
 
174
178
  "msg_no_plugins" : "PYMUD当前并未加载任何插件。",
175
179
  "msg_plugins_list" : "PYMUD当前已加载 {0} 个插件,分别为:",
176
- "msg_plugins_info" : "{0}, 版本 {1} 作者 {2} 发布日期 {3}",
180
+ "msg_plugins_info" : "作者 {2} 版本 {1} 发布日期 {3}\n 简介: {0}",
177
181
 
178
182
  "msg_py_exception" : "Python执行错误:{0}",
179
183
 
pymud/lang/i18n_eng.py CHANGED
@@ -86,13 +86,17 @@ TRANSLATION = {
86
86
  "load_fail" : "Load failed",
87
87
  "unload_ok" : "Unload completed",
88
88
  "reload_ok" : "Reload completed",
89
+ "msg_plugin_unloaded" : "Plugin {0} has been disabled for this session.",
90
+ "msg_plugin_loaded" : "Plugin {0} has been enabled for this session.",
89
91
 
90
92
  # text in objects.py
91
93
  "excpetion_brace_not_matched" : "Invalid code block, number of braces does not match",
92
94
  "exception_quote_not_matched" : "Number of quotes does not match",
93
95
  "exception_forced_async" : "This command contains both forced synchronous and asynchronous commands, will use asynchronous execution, synchronous commands will be invalid.",
94
96
  "exception_session_type_fail" : "session must be an instance of Session type object!",
95
- "exception_in_async" : "Exception occurred during asynchronous execution, {}",
97
+ "exception_message" : "Exception information: <{}> {}",
98
+ "exception_traceback" : "Exception occurred at line number {1} in file '{0}', and function name is '{2}'",
99
+ "script_error" : "Script Error",
96
100
 
97
101
  # text display in session.py
98
102
  "msg_var_autoload_success" : "Variables automatically loaded from {0} successfully.",
@@ -172,7 +176,7 @@ TRANSLATION = {
172
176
 
173
177
  "msg_no_plugins" : "PYMUD currently has no plugins loaded.",
174
178
  "msg_plugins_list" : "PYMUD currently has {0} plugins loaded, respectively:",
175
- "msg_plugins_info" : "{0}, version {1} author {2} release date {3}",
179
+ "msg_plugins_info" : "Author {2} Version {1} Release Date {3}\n Description: {0}",
176
180
 
177
181
  "msg_py_exception" : "Python execution error: {0}",
178
182
 
@@ -363,21 +367,24 @@ TRANSLATION = {
363
367
 
364
368
  "handle_test" :
365
369
  '''
366
- The execution function of the embedded command #test/#show, trigger testing command. Similar to zmud's #show command.
370
+ The execution function of the embedded command #test/#show/#echo, trigger testing command. Similar to zmud's #show command.
367
371
  This function should not be called directly in the code.
368
372
 
369
373
  Usage:
370
- - #show {some_text}: Test trigger response when server receives {some_text}. Triggers won't actually execute.
371
- - #test {some_test}: Difference from #show is that matched triggers will execute regardless of enabled status.
374
+ - #show {some_text}: Test trigger response when receives {some_text}. Triggers won't actually execute.
375
+ - #test {some_text}: Difference from #show is that matched triggers will execute regardless of enabled status.
376
+ - #echo {some_text}: Simulate receiving {some_text} from server, triggers will execute normally but won't display test results.
372
377
 
373
378
  Examples:
374
379
  - ``#show You take a deep breath and stand up.``: Simulate trigger testing when server receives "You take a deep breath and stand up." (display test results only)
375
380
  - ``#test %copy``: Copy a sentence and simulate trigger testing when server receives the copied content again
376
381
  - ``#test You take a deep breath and stand up.``: Actual trigger execution will occur even if disabled
382
+ - ``#echo You take a deep breath and stand up.``: Simulate trigger testing when server receives "You take a deep breath and stand up." (won't display test results)
377
383
 
378
384
  Notes:
379
385
  - #show command only displays test results without actual trigger execution
380
- - #ttest command forces actual trigger execution regardless of enabled status
386
+ - #test command forces actual trigger execution regardless of enabled status
387
+ - #echo command can be used to manually trigger triggers
381
388
  ''',
382
389
 
383
390
  "handle_timer" :
pymud/main.py CHANGED
@@ -5,23 +5,28 @@ from .settings import Settings
5
5
 
6
6
  CFG_TEMPLATE = {
7
7
  "language" : "chs", # 语言设置,默认为简体中文
8
+
8
9
  "client": {
9
10
  "buffer_lines" : 5000, # 保留缓冲行数
10
11
 
11
12
  "interval" : 10, # 在自动执行中,两次命令输入中的间隔时间(ms)
12
13
  "auto_connect" : True, # 创建会话后,是否自动连接
13
14
  "auto_reconnect" : False, # 在会话异常断开之后,是否自动重连
15
+ "reconnect_wait" : 15, # 自动重连等待的时间(秒数)
14
16
  "var_autosave" : True, # 断开时自动保存会话变量
15
17
  "var_autoload" : True, # 初始化时自动加载会话变量
16
18
 
17
- "echo_input" : False,
18
19
  "beautify" : True, # 专门为解决控制台下PKUXKX字符画对不齐的问题
20
+ "history_records" : 500,
19
21
 
22
+ "status_divider" : False, # 是否显示状态栏的分隔线
20
23
  "status_display" : 1, # 状态窗口显示情况设置,0-不显示,1-显示在下方,2-显示在右侧
21
24
  "status_height" : 4, # 下侧状态栏的高度
22
25
  "status_width" : 30, # 右侧状态栏的宽度
26
+
23
27
 
24
28
  },
29
+
25
30
  "sessions" : {
26
31
  "pkuxkx" : {
27
32
  "host" : "mud.pkuxkx.net",
@@ -68,7 +73,11 @@ def init_pymud_env(args):
68
73
 
69
74
  dir = args.dir
70
75
  if dir:
71
- print(f"你已经指定了创建脚本的目录为 {args.dir}")
76
+ if dir == ".":
77
+ dir_msg = "当前目录"
78
+ else:
79
+ dir_msg = f": {dir}"
80
+ print(f"你已经指定了创建脚本的目录为{dir_msg}")
72
81
  dir = Path(dir)
73
82
  else:
74
83
  dir = Path.home().joinpath('pkuxkx')
@@ -112,7 +121,11 @@ def init_pymud_env(args):
112
121
  print("Starting to initialize the environment for the first time...")
113
122
  dir = args.dir
114
123
  if dir:
115
- print(f"You have specified the directory to create the script as {args.dir}")
124
+ if dir == ".":
125
+ dir_msg = "current directory"
126
+ else:
127
+ dir_msg = f": {dir}"
128
+ print(f"You have specified the directory to create the script as {dir_msg}")
116
129
  dir = Path(dir)
117
130
  else:
118
131
  dir = Path.home().joinpath('pkuxkx')
@@ -189,7 +202,7 @@ def main():
189
202
  subparsers = parser.add_subparsers(help = 'init用于初始化运行环境')
190
203
 
191
204
  par_init = subparsers.add_parser('init', description = '初始化pymud运行环境, 包括建立脚本目录, 创建默认配置文件, 创建样例脚本等.')
192
- par_init.add_argument('-d', '--dir', dest = 'dir', metavar = 'dir', type = str, default = '', help = '指定构建脚本目录的名称, 不指定时会根据操作系统选择不同默认值')
205
+ par_init.add_argument('-d', '--dir', dest = 'dir', metavar = 'dir', type = str, default = '.', help = '指定构建脚本目录的名称, 不指定时会根据操作系统选择不同默认值')
193
206
  par_init.set_defaults(func = init_pymud_env)
194
207
 
195
208
  parser.add_argument('-d', '--debug', dest = 'debug', action = 'store_true', default = False, help = '指定以调试模式进入PyMUD。此时,系统log等级将设置为logging.NOTSET, 所有log数据均会被记录。默认不启用。')