Skip to content

Commit ba7eed3

Browse files
committed
🍻 keeping()
1 parent b3aacf4 commit ba7eed3

File tree

9 files changed

+83
-14
lines changed

9 files changed

+83
-14
lines changed

arclet/entari/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
from .plugin import Plugin as Plugin
4949
from .plugin import PluginMetadata as PluginMetadata
5050
from .plugin import dispose as dispose_plugin # noqa: F401
51+
from .plugin import keeping as keeping
5152
from .plugin import load_plugin as load_plugin
5253
from .plugin import load_plugins as load_plugins
5354
from .plugin import metadata as metadata

arclet/entari/command/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
config,
1313
output_manager,
1414
)
15-
from arclet.alconna.typing import TAValue
1615
from arclet.alconna.tools.construct import AlconnaString, alconna_from_format
16+
from arclet.alconna.typing import TAValue
1717
from arclet.letoderea import BaseAuxiliary, Provider, Publisher, Scope, Subscriber
1818
from arclet.letoderea.handler import depend_handler
1919
from arclet.letoderea.provider import ProviderFactory

arclet/entari/event.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
from datetime import datetime
4-
from typing import Callable, ClassVar, TypeVar, Generic, Any
4+
from typing import Any, Callable, ClassVar, Generic, TypeVar
55

66
from arclet.letoderea import Contexts, Param, Provider
77
from satori import ArgvInteraction, ButtonInteraction, Channel
@@ -31,7 +31,7 @@ def __get__(self, instance: Event, owner: type[Event]) -> T:
3131

3232
def __set__(self, instance: Event, value):
3333
raise AttributeError("can't set attribute")
34-
34+
3535

3636
def attr(key: str | None = None) -> Any:
3737
return Attr(key)
@@ -67,7 +67,18 @@ async def gather(self, context: Contexts):
6767
context["$account"] = self.account
6868
context["$origin_event"] = self._origin
6969

70-
for attrname in {"argv", "button", "channel", "guild", "login", "member", "message", "operator", "role", "user"}:
70+
for attrname in {
71+
"argv",
72+
"button",
73+
"channel",
74+
"guild",
75+
"login",
76+
"member",
77+
"message",
78+
"operator",
79+
"role",
80+
"user",
81+
}:
7182
value = getattr(self, attrname)
7283
if value is not None:
7384
context["$message_origin" if attrname == "message" else attrname] = value

arclet/entari/plugin/__init__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
from loguru import logger
99
from tarina import init_spec
1010

11-
from .model import Plugin, RegisterNotInPluginError
11+
from .model import Plugin
1212
from .model import PluginMetadata as PluginMetadata
13-
from .model import _current_plugin
13+
from .model import RegisterNotInPluginError, _current_plugin
14+
from .model import keeping as keeping
1415
from .module import import_plugin
1516
from .module import package as package
1617
from .service import service
@@ -40,6 +41,7 @@ def load_plugin(path: str) -> Plugin | None:
4041
logger.error(f"cannot found plugin {path!r}")
4142
return
4243
logger.success(f"loaded plugin {path!r}")
44+
4345
return mod.__plugin__
4446
except RegisterNotInPluginError as e:
4547
logger.exception(f"{e.args[0]}", exc_info=e)

arclet/entari/plugin/model.py

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@
44
from contextvars import ContextVar
55
from dataclasses import dataclass, field
66
from types import ModuleType
7-
from typing import TYPE_CHECKING, Any, Callable
7+
from typing import TYPE_CHECKING, Any, Callable, TypeVar
88
from weakref import finalize
99

1010
from arclet.letoderea import BaseAuxiliary, Provider, Publisher, StepOut, system_ctx
1111
from arclet.letoderea.builtin.breakpoint import R
1212
from arclet.letoderea.typing import TTarget
1313
from satori.client import Account
14-
from tarina import init_spec
1514

1615
from .service import service
1716

@@ -66,6 +65,7 @@ def dispose(self):
6665
if TYPE_CHECKING:
6766
register = Publisher.register
6867
else:
68+
6969
def register(self, *args, **kwargs):
7070
wrapper = super().register(*args, **kwargs)
7171

@@ -144,6 +144,8 @@ def metadata(self) -> PluginMetadata | None:
144144

145145
def __post_init__(self):
146146
service.plugins[self.id] = self
147+
if self.id not in service._keep_values:
148+
service._keep_values[self.id] = {}
147149
finalize(self, self.dispose)
148150

149151
def dispose(self):
@@ -169,6 +171,34 @@ def validate(self, func):
169171
if "__plugin__" in func.__globals__ and func.__globals__["__plugin__"] is self:
170172
return
171173
raise RegisterNotInPluginError(
172-
f"Handler {func.__qualname__} should define in the same module as the plugin: {self.module.__name__}. "
173-
f"Please use the `load_plugin({func.__module__!r})` or `package({func.__module__!r})` before import it."
174+
f"Handler {func.__qualname__} should define "
175+
f"in the same module as the plugin: {self.module.__name__}. "
176+
f"Please use the `load_plugin({func.__module__!r})` or "
177+
f"`package({func.__module__!r})` before import it."
174178
)
179+
180+
181+
class KeepingVariable:
182+
def __init__(self, obj: T, dispose: Callable[[T], None] | None = None):
183+
self.obj = obj
184+
self._dispose = dispose
185+
186+
def dispose(self):
187+
if hasattr(self.obj, "dispose"):
188+
self.obj.dispose() # type: ignore
189+
elif self._dispose:
190+
self._dispose(self.obj)
191+
del self.obj
192+
193+
194+
T = TypeVar("T")
195+
196+
197+
def keeping(id_: str, obj: T, dispose: Callable[[T], None] | None = None) -> T:
198+
if not (plug := _current_plugin.get(None)):
199+
raise LookupError("no plugin context found")
200+
if id_ not in service._keep_values[plug.id]:
201+
service._keep_values[plug.id][id_] = KeepingVariable(obj, dispose)
202+
else:
203+
obj = service._keep_values[plug.id][id_].obj # type: ignore
204+
return obj

arclet/entari/plugin/module.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from .model import Plugin, PluginMetadata, _current_plugin
1010
from .service import service
1111

12-
1312
_SUBMODULE_WAITLIST = set()
1413

1514

arclet/entari/plugin/service.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,19 @@
66
from loguru import logger
77

88
if TYPE_CHECKING:
9-
from .model import Plugin
9+
from .model import KeepingVariable, Plugin
1010

1111

1212
class PluginService(Service):
1313
id = "arclet.entari.plugin_service"
1414

1515
plugins: dict[str, "Plugin"]
16+
_keep_values: dict[str, dict[str, "KeepingVariable"]]
1617

1718
def __init__(self):
1819
super().__init__()
1920
self.plugins = {}
21+
self._keep_values = {}
2022

2123
@property
2224
def required(self) -> set[str]:
@@ -46,6 +48,11 @@ async def launch(self, manager: Launart):
4648
except Exception as e:
4749
logger.error(f"failed to dispose plugin {plug.id} caused by {e!r}")
4850
self.plugins.pop(plug_id, None)
51+
for values in self._keep_values.values():
52+
for value in values.values():
53+
value.dispose()
54+
values.clear()
55+
self._keep_values.clear()
4956

5057

5158
service = PluginService()

arclet/entari/session.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,9 @@ async def send(
120120
) -> list[MessageObject]:
121121
if not protocol_cls:
122122
return await self.account.protocol.send(self.context, message)
123-
return await self.account.custom(self.account.config, protocol_cls).send(self.context._origin, message)
123+
return await self.account.custom(self.account.config, protocol_cls).send(
124+
self.context._origin, message
125+
)
124126

125127
async def send_message(
126128
self,
@@ -269,7 +271,9 @@ async def guild_member_role_unset(self, role_id: str, user_id: str | None = None
269271
if not self.context.guild:
270272
raise RuntimeError("Event cannot use to guild member role unset!")
271273
if user_id:
272-
return await self.account.protocol.guild_member_role_unset(self.context.guild.id, user_id, role_id)
274+
return await self.account.protocol.guild_member_role_unset(
275+
self.context.guild.id, user_id, role_id
276+
)
273277
if not self.context.user:
274278
raise RuntimeError("Event cannot use to guild member role unset!")
275279
return await self.account.protocol.guild_member_role_unset(

example_plugin.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
is_public_message,
1212
bind,
1313
metadata,
14+
keeping
1415
)
1516
from arclet.entari.command import Match
1617

@@ -70,3 +71,17 @@ async def _(content: Match[MessageChain], session: Session):
7071
@command.on("add {a} {b}")
7172
async def add(a: int, b: int, session: Session):
7273
await session.send_message(f"{a + b =}")
74+
75+
76+
kept_data = keeping("foo", [], lambda x: x.clear())
77+
78+
79+
@command.on("append {data}")
80+
async def append(data: str, session: Session):
81+
kept_data.append(data)
82+
await session.send_message(f"Appended {data}")
83+
84+
85+
@command.on("show")
86+
async def show(session: Session):
87+
await session.send_message(f"Data: {kept_data}")

0 commit comments

Comments
 (0)