pymud 0.20.0a4__py3-none-any.whl → 0.20.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,5 +1,6 @@
1
1
  from .settings import Settings
2
2
  from .pymud import PyMudApp
3
+ from .modules import IConfig
3
4
  from .objects import CodeBlock, Alias, SimpleAlias, Trigger, SimpleTrigger, Command, SimpleCommand, Timer, SimpleTimer, GMCPTrigger
4
5
  from .extras import DotDict
5
6
  from .session import Session
@@ -7,5 +8,5 @@ from .logger import Logger
7
8
  from .main import main
8
9
 
9
10
  __all__ = [
10
- "PyMudApp", "Settings", "CodeBlock", "Alias", "SimpleAlias", "Trigger", "SimpleTrigger", "Command", "SimpleCommand", "Timer", "SimpleTimer", "GMCPTrigger", "Session", "PyMudApp", "DotDict", "Logger", "main"
11
+ "IConfig", "PyMudApp", "Settings", "CodeBlock", "Alias", "SimpleAlias", "Trigger", "SimpleTrigger", "Command", "SimpleCommand", "Timer", "SimpleTimer", "GMCPTrigger", "Session", "PyMudApp", "DotDict", "Logger", "main"
11
12
  ]
pymud/modules.py ADDED
@@ -0,0 +1,80 @@
1
+
2
+ import importlib
3
+ from abc import ABC, ABCMeta
4
+
5
+ class ModuleInfo:
6
+ def __init__(self, module_name: str, session):
7
+ self.session = session
8
+ self._name = module_name
9
+ self.load()
10
+
11
+ def _load(self, reload = False):
12
+ result = True
13
+ if reload:
14
+ self._module = importlib.reload(self._module)
15
+ else:
16
+ self._module = importlib.import_module(self.name)
17
+ self._config = {}
18
+ for attr_name in dir(self._module):
19
+ attr = getattr(self._module, attr_name)
20
+ if isinstance(attr, type) and attr.__module__ == self._module.__name__:
21
+ if (attr_name == "Configuration") or issubclass(attr, IConfig):
22
+ try:
23
+ self._config[f"{self.name}.{attr_name}"] = attr(self.session)
24
+ self.session.info(f"配置对象 {self.name}.{attr_name} 创建成功.")
25
+ except Exception as e:
26
+ result = False
27
+ self.session.error(f"配置对象 {self.name}.{attr_name} 创建失败. 错误信息为: {e}")
28
+
29
+ return result
30
+
31
+ def _unload(self):
32
+ for key, config in self._config.items():
33
+ if hasattr(config, "__unload__"):
34
+ unload = getattr(config, "__unload__", None)
35
+ if callable(unload): unload()
36
+
37
+ if hasattr(config, "unload"):
38
+ unload = getattr(config, "unload", None)
39
+ if callable(unload): unload()
40
+
41
+ del config
42
+ self._config.clear()
43
+
44
+ def load(self):
45
+ if self._load():
46
+ self.session.info(f"{'主' if self.ismainmodule else '从'}配置模块 {self.name} 加载完成.")
47
+ else:
48
+ self.session.error(f"{'主' if self.ismainmodule else '从'}配置模块 {self.name} 加载失败.")
49
+
50
+ def unload(self):
51
+ self._unload()
52
+ self.session.info(f"{'主' if self.ismainmodule else '从'}配置模块 {self.name} 卸载完成.")
53
+
54
+ def reload(self):
55
+ self._unload()
56
+ self._load(reload = True)
57
+ self.session.info(f"{'主' if self.ismainmodule else '从'}配置模块 {self.name} 重新加载完成.")
58
+
59
+ @property
60
+ def name(self):
61
+ return self._name
62
+
63
+ @property
64
+ def module(self):
65
+ return self._module
66
+
67
+ @property
68
+ def config(self):
69
+ return self._config
70
+
71
+ @property
72
+ def ismainmodule(self):
73
+ return self._config != {}
74
+
75
+ class IConfig(metaclass = ABCMeta):
76
+ def __init__(self, session, *args, **kwargs):
77
+ self.session = session
78
+
79
+ def __unload__(self):
80
+ self.session.delObject(self)
pymud/objects.py CHANGED
@@ -2,7 +2,8 @@
2
2
  MUD会话(session)中, 支持的对象列表
3
3
  """
4
4
 
5
- import asyncio, logging, re
5
+ import asyncio, logging, re, importlib
6
+ from abc import ABC, ABCMeta, abstractmethod
6
7
  from collections.abc import Iterable
7
8
  from collections import namedtuple
8
9
  from typing import Any
@@ -342,6 +343,8 @@ class BaseObject:
342
343
 
343
344
  self.log.debug(f"对象实例 {self} 创建成功.")
344
345
 
346
+ self.session.addObject(self)
347
+
345
348
  @property
346
349
  def enabled(self):
347
350
  "可读写属性,使能或取消使能本对象"
@@ -477,7 +480,7 @@ class MatchObject(BaseObject):
477
480
  super().__init__(session, patterns = patterns, *args, **kwargs)
478
481
 
479
482
  def __del__(self):
480
- self.reset()
483
+ pass
481
484
 
482
485
  @property
483
486
  def patterns(self):
pymud/session.py CHANGED
@@ -8,6 +8,7 @@ from logging.handlers import QueueHandler, QueueListener
8
8
  from .logger import Logger
9
9
  from .extras import SessionBuffer, DotDict, Plugin
10
10
  from .protocol import MudClientProtocol
11
+ from .modules import ModuleInfo
11
12
  from .objects import BaseObject, Trigger, Alias, Command, Timer, SimpleAlias, SimpleTrigger, SimpleTimer, GMCPTrigger, CodeBlock, CodeLine
12
13
  from .settings import Settings
13
14
 
@@ -256,11 +257,6 @@ class Session:
256
257
  if self.connected:
257
258
  self.write_eof()
258
259
 
259
- # 两次保存,删掉一次
260
- # # 断开时自动保存变量数据
261
- # if Settings.client["var_autosave"]:
262
- # self.handle_save()
263
-
264
260
  def onDisconnected(self, protocol):
265
261
  "当从服务器连接断开时执行的操作。包括保存变量(若设置)、打印断开时间、执行自定义事件(若设置)等。"
266
262
  # 断开时自动保存变量数据
@@ -808,7 +804,7 @@ class Session:
808
804
  return await awaitable
809
805
 
810
806
  def exec(self, cmd: str, name = None, *args, **kwargs):
811
- """
807
+ r"""
812
808
  在名称为name的会话中使用exec_command执行MUD命令。当不指定name时,在当前会话中执行。
813
809
 
814
810
  - exec 与 writeline 都会向服务器写入数据。其差异在于,exec执行的内容,会先经过Alias处理和Command处理,实际向远程发送内容与cmd可以不一致。
@@ -2151,7 +2147,7 @@ class Session:
2151
2147
  self.info("创建Timer {} 成功: {}".format(ti.id, ti.__repr__()))
2152
2148
 
2153
2149
  def handle_alias(self, code: CodeLine = None, *args, **kwargs):
2154
- """
2150
+ r"""
2155
2151
  嵌入命令 #alias / #ali 的执行函数,操作别名。该命令可以不带参数、带一个参数或者两个参数。
2156
2152
  该函数不应该在代码中直接调用。
2157
2153
 
@@ -2541,6 +2537,7 @@ class Session:
2541
2537
  self._variables.clear()
2542
2538
  self._tasks.clear()
2543
2539
 
2540
+
2544
2541
  def load_module(self, module_names):
2545
2542
  """
2546
2543
  模块加载函数。
@@ -2564,33 +2561,12 @@ class Session:
2564
2561
  "加载指定名称模块"
2565
2562
  try:
2566
2563
  if module_name not in self._modules.keys():
2567
- mod = importlib.import_module(module_name)
2568
- if hasattr(mod, 'Configuration'):
2569
- config = mod.Configuration(self)
2570
- self._modules[module_name] = {"module": mod, "config": config}
2571
- self.info(f"主配置模块 {module_name} 加载完成.")
2572
- else:
2573
- self._modules[module_name] = {"module": mod, "config": None}
2574
- self.info(f"子配置模块 {module_name} 加载完成.")
2564
+ self._modules[module_name] = ModuleInfo(module_name, self)
2575
2565
 
2576
2566
  else:
2577
- mod = self._modules[module_name]["module"]
2578
- config = self._modules[module_name]["config"]
2579
- if config:
2580
- if hasattr(config, "__unload__") or hasattr(config, "unload"):
2581
- unload = getattr(config, "__unload__", None) or getattr(config, "unload", None)
2582
- if callable(unload):
2583
- unload()
2584
-
2585
- del config
2586
- mod = importlib.reload(mod)
2587
- if hasattr(mod, 'Configuration'):
2588
- config = mod.Configuration(self)
2589
- self._modules[module_name] = {"module": mod, "config": config}
2590
- self.info(f"主配置模块 {module_name} 重新加载完成.")
2591
- else:
2592
- self._modules[module_name] = {"module": mod, "config": None}
2593
- self.info(f"子配置模块 {module_name} 重新加载完成.")
2567
+ mod = self._modules[module_name]
2568
+ if isinstance(mod, ModuleInfo):
2569
+ mod.reload()
2594
2570
 
2595
2571
  except Exception as e:
2596
2572
  import traceback
@@ -2618,18 +2594,9 @@ class Session:
2618
2594
  def _unload_module(self, module_name):
2619
2595
  "卸载指定名称模块。卸载支持需要模块的Configuration实现 __unload__ 或 unload 方法"
2620
2596
  if module_name in self._modules.keys():
2621
- mod = self._modules[module_name]["module"]
2622
- config = self._modules[module_name]["config"]
2623
- if config:
2624
- if hasattr(config, "__unload__") or hasattr(config, "unload"):
2625
- unload = getattr(config, "__unload__", None) or getattr(config, "unload", None)
2626
- if callable(unload):
2627
- unload()
2628
-
2629
- del config
2630
- del mod
2631
- self._modules.pop(module_name)
2632
- self.info(f"配置模块 {module_name} 已成功卸载.")
2597
+ mod = self._modules.pop(module_name)
2598
+ if isinstance(mod, ModuleInfo):
2599
+ mod.unload()
2633
2600
 
2634
2601
  else:
2635
2602
  self.warning(f"指定模块名称 {module_name} 并未加载.")
@@ -2643,9 +2610,9 @@ class Session:
2643
2610
  :param module_names: 要重新加载的模块清单。为元组/列表时,卸载指定名称的系列模块,当名称为字符串时,卸载单个模块。当不指定时,重新加载所有已加载模块。
2644
2611
  """
2645
2612
  if module_names is None:
2646
- self.clean()
2647
- mods = list(self._modules.keys())
2648
- self.load_module(mods)
2613
+ for name, module in self._modules.items():
2614
+ if isinstance(module, ModuleInfo):
2615
+ module.reload()
2649
2616
 
2650
2617
  self.info(f"所有配置模块全部重新加载完成.")
2651
2618
 
@@ -2653,14 +2620,17 @@ class Session:
2653
2620
  for mod in module_names:
2654
2621
  mod = mod.strip()
2655
2622
  if mod in self._modules.keys():
2656
- self.load_module(mod)
2623
+ module = self._modules[mod]
2624
+ if isinstance(module, ModuleInfo):
2625
+ module.reload()
2657
2626
  else:
2658
2627
  self.warning(f"指定模块名称 {mod} 并未加载,无法重新加载.")
2659
2628
 
2660
2629
  elif isinstance(module_names, str):
2661
2630
  if module_names in self._modules.keys():
2662
- mod = module_names.strip()
2663
- self.load_module(mod)
2631
+ module = self._modules[module_names]
2632
+ if isinstance(module, ModuleInfo):
2633
+ module.reload()
2664
2634
  else:
2665
2635
  self.warning(f"指定模块名称 {module_names} 并未加载,无法重新加载.")
2666
2636
 
@@ -2798,12 +2768,29 @@ class Session:
2798
2768
  - #reload
2799
2769
  '''
2800
2770
 
2801
- count = len(self._modules.keys())
2802
- if count == 0:
2803
- self.info("当前会话并未加载任何模块。", "MODULES")
2804
- else:
2805
- self.info(f"当前会话已加载 {count} 个模块,包括(按加载顺序排列):{list(self._modules.keys())}", "MODULES")
2771
+ args = code.code[2:]
2772
+
2773
+ if len(args) == 0:
2774
+ count = len(self._modules.keys())
2775
+ if count == 0:
2776
+ self.info("当前会话并未加载任何模块。", "MODULES")
2777
+ else:
2778
+ self.info(f"当前会话已加载 {count} 个模块,包括(按加载顺序排列):{list(self._modules.keys())}", "MODULES")
2806
2779
 
2780
+ elif len(args) >= 1:
2781
+ modules = ",".join(args).split(",")
2782
+ for mod in modules:
2783
+ if mod in self._modules.keys():
2784
+ module = self._modules[mod]
2785
+ if isinstance(module, ModuleInfo):
2786
+ if module.ismainmodule:
2787
+ self.info(f"模块 {module.name} 中包含的配置包括: {', '.join(module.config.keys())}")
2788
+ else:
2789
+ self.info(f"模块 {module.name} 为子模块,不包含配置。")
2790
+
2791
+ else:
2792
+ self.info(f"本会话中不存在指定名称 {mod} 的模块,可能是尚未加载到本会话中")
2793
+
2807
2794
  def handle_reset(self, code: CodeLine = None, *args, **kwargs):
2808
2795
  '''
2809
2796
  嵌入命令 #reset 的执行函数,复位全部脚本。该命令不带参数。
@@ -2823,7 +2810,8 @@ class Session:
2823
2810
 
2824
2811
  def handle_save(self, code: CodeLine = None, *args, **kwargs):
2825
2812
  '''
2826
- 嵌入命令 #save 的执行函数,保存当前会话变量(系统变量除外)至文件。该命令不带参数。
2813
+ 嵌入命令 #save 的执行函数,保存当前会话变量(系统变量和临时变量除外)至文件。该命令不带参数。
2814
+ 系统变量包括 %line, %copy 和 %raw 三个,临时变量是指变量名已下划线开头的变量
2827
2815
  该函数不应该在代码中直接调用。
2828
2816
 
2829
2817
  使用:
@@ -2844,10 +2832,10 @@ class Session:
2844
2832
  with open(file, "wb") as fp:
2845
2833
  saved = dict()
2846
2834
  saved.update(self._variables)
2847
- # keys = list(saved.keys())
2848
- # for key in keys:
2849
- # if key.startswith("%"):
2850
- # saved.pop(key)
2835
+ keys = list(saved.keys())
2836
+ for key in keys:
2837
+ if key.startswith("_"):
2838
+ saved.pop(key)
2851
2839
  saved.pop("%line", None)
2852
2840
  saved.pop("%raw", None)
2853
2841
  saved.pop("%copy", None)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pymud
3
- Version: 0.20.0a4
3
+ Version: 0.20.0a5
4
4
  Summary: a MUD Client written in Python
5
5
  Author-email: "newstart@pkuxkx" <crapex@crapex.cc>
6
6
  Maintainer-email: "newstart@pkuxkx" <crapex@crapex.cc>
@@ -743,10 +743,12 @@ Requires-Dist: prompt-toolkit
743
743
  + 功能调整: 在没有session的时候,也可以执行#exit命令
744
744
  + 功能新增: #session 命令增加快捷创建会话功能,假如已有快捷菜单 世界->pkuxkx->newstart , 则可以通过 #session pkuxkx.newstart 直接创建该会话,效果等同于点击该菜单
745
745
  + 功能调整: 点击菜单创建会话时,若会话已存在,则将该会话切换为当前会话
746
- + 问题修复: 修复原unload方法不能正确卸载的问题
747
- + 功能新增: 主模块卸载现在既可以定义在__unload__方法中,也可以定义在unload方法中。可以根据自己喜好选择一个即可。
748
- + 功能调整: 模块加载和重新加载前,会自动调用模块的__unload__方法或unload方法(若有)
746
+ + 重大更新: 完全重写了模块的加载、卸载、重新加载方法,修复模块使用中的问题
747
+ + 功能调整: 现在只要将一个类型继承 IConfig 接口,即被识别为配置类型。这种类型在模块加载时会自动创建其实例。当然,名称为Configuration的类型也同样被认为是配置类型,保持向前兼容性。唯一要求是,该类型的构造函数允许仅传递一个session对象。
748
+ + 功能新增: 各类配置类型的卸载现在既可以定义在__unload__方法中,也可以定义在unload方法中。可以根据自己喜好选择一个即可。
749
+ + 功能调整: 各配置类型加载和重新加载前,会自动调用模块的__unload__方法或unload方法(若有)
749
750
  + 功能新增: Command基类增加__unload__方法和unload方法,二者在从会话中移除该 Command 时均会自动调用。自定义的Command子类应覆盖这两种方法中的一种方法,并在其中增加清除类型自行创建的 Trigger, Alias 等会话对象。这样,模块卸载时只要移除命令本身,在命令中新建的其他关联对象将被一同移除。
751
+ + 功能新增: 所有PyMUD基础对象类型及其子类型,包括 Alias, Trigger, Timer, Command, GMCPTrigger 及它们的子类型,在创建的时候会自动添加到会话中,无需再进行 addObject 等操作了
750
752
  + 问题修复: 修复部分正则表达式书写错误问题
751
753
  + 功能新增: Session类新增waitfor函数,用于执行一段代码后立即等待某个触发器的情况,简化原三行代码写法
752
754
 
@@ -792,6 +794,8 @@ Requires-Dist: prompt-toolkit
792
794
  + 功能新增: Session的所有异步命令调用函数增加返回值,现在调用 session.exec_async, exec_command_async 等方法执行的内容若匹配为命令时,会返回最后最后一个 Command 对象的 execute 函数的返回值
793
795
  - 例如, result = await self.session.cmds.cmd_runto.execute('rt yz') 与 result = await self.session.exec_async('rt yz') 等价,返回值相同
794
796
  - 但 result = await self.session.exec_async('rt yz;dzt'),该返回的result 仅是 dzt 命令的 execute 的返回值。 rt yz 命令返回值被丢弃。
797
+ + 功能新增: 增加临时变量概念,变量名以下划线开头的为临时变量,此类变量不会被保存到 .mud 文件中。
798
+
795
799
 
796
800
  ## 0.19.4 (2024-04-20)
797
801
  + 功能调整: info 现在 msg 恢复为可接受任何类型参数,不一定是 str
@@ -1,18 +1,19 @@
1
- pymud/__init__.py,sha256=hvX7Ga2xPG9J3ZpxBLrC6BvrzUo-Dj26HsRKf41Brhw,533
1
+ pymud/__init__.py,sha256=AP4Edhx90gMKrNfD1O_KVciA3SOnyX5Qt9fZY_JhsTY,574
2
2
  pymud/__main__.py,sha256=hFzZjadLlcOuoLM7D8wFiFVO8mqF7vMuo9y-9xfIhRc,64
3
3
  pymud/dialogs.py,sha256=D0ZtCeoBchF5eYzXumkOi3p-maCQZu4v9-wJgxQ790o,6500
4
4
  pymud/extras.py,sha256=QwWwLavVtuXfg0Qb0f_040va1_kej27P-ZB_19HB6Qk,42422
5
5
  pymud/logger.py,sha256=elYfbpvmKYJfB-rnPYZWY5r8ROu9yja9t-dBi1faRGc,5358
6
6
  pymud/main.py,sha256=b_Ui_cN4W8IfhYNyc1duwr3Bp7pYYZQusKTSafCWZIA,6534
7
- pymud/objects.py,sha256=aV3RzhZZ7y3qK_kwaYbtnpmaqfBxVwQ8fMwvEs9Dh-A,38534
7
+ pymud/modules.py,sha256=GoNmGnMfi2BEsonJA4iq-unkgHkZRR-XBr1Wix_3-a4,2756
8
+ pymud/objects.py,sha256=5lx9Z9ijrwpqy2KNJu0OyUxXVh_VVYP2PTE82inAW9c,38623
8
9
  pymud/pkuxkx.py,sha256=jRQRUs2xtw7GzYHtLYZXOASnqMumKh0iCoOeKZs8NnU,11467
9
10
  pymud/protocol.py,sha256=QfDXjlg2OcJXmVoXf_3mAemnYotRXDUlEZNQjhkfXdA,49106
10
11
  pymud/pymud.py,sha256=N9WxaHDqqsTWIBG8UJ38gdMC_pQ30wphcN2LtT66eA4,49584
11
- pymud/session.py,sha256=BCmQljeEjWS6n35WTwmxMZBZenNTAoixaqcAjhTROGs,130095
12
+ pymud/session.py,sha256=3u_ctb3ev5MPYfB7-vrLDd9ag9yw1z-K24hQ40hSrME,129365
12
13
  pymud/settings.py,sha256=CRNpHl4RjOuQYzAIWyUEvOo7q-f4lo01X1v_CriHWO4,7145
13
- pymud-0.20.0a4.dist-info/LICENSE.txt,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
14
- pymud-0.20.0a4.dist-info/METADATA,sha256=tDJ-Og3BTghz3zG6YwEKRnI6EwT083VHG5aeBeW_XCA,72291
15
- pymud-0.20.0a4.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
16
- pymud-0.20.0a4.dist-info/entry_points.txt,sha256=diPUOtTkhgC1hVny7Cdg4aRhaHSynMQoraE7ZhJxUcw,37
17
- pymud-0.20.0a4.dist-info/top_level.txt,sha256=8Gp1eXjxixXjqhhti6tLCspV_8s9sNV3z5Em2_KRhD4,6
18
- pymud-0.20.0a4.dist-info/RECORD,,
14
+ pymud-0.20.0a5.dist-info/LICENSE.txt,sha256=IwGE9guuL-ryRPEKi6wFPI_zOhg7zDZbTYuHbSt_SAk,35823
15
+ pymud-0.20.0a5.dist-info/METADATA,sha256=kaZCuQ8_FyybVKP0c7ksj_jk_qksVwda-YEgSCsmqT4,73061
16
+ pymud-0.20.0a5.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
17
+ pymud-0.20.0a5.dist-info/entry_points.txt,sha256=diPUOtTkhgC1hVny7Cdg4aRhaHSynMQoraE7ZhJxUcw,37
18
+ pymud-0.20.0a5.dist-info/top_level.txt,sha256=8Gp1eXjxixXjqhhti6tLCspV_8s9sNV3z5Em2_KRhD4,6
19
+ pymud-0.20.0a5.dist-info/RECORD,,