Skip to content

Commit 9137158

Browse files
committed
update plugin setting
1 parent bc31e2f commit 9137158

File tree

5 files changed

+133
-8
lines changed

5 files changed

+133
-8
lines changed

src/wechaty/plugin.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@
7575
error
7676
)
7777
from wechaty.types import EndPoint
78+
from wechaty.utils import HookDict
7879

7980
from .config import config
8081

@@ -396,9 +397,11 @@ def __init__(self, options: Optional[WechatyPluginOptions] = None):
396397
self.options = options
397398
self._default_logger: Optional[Logger] = None
398399
self._cache_dir: Optional[str] = None
399-
400400
self.setting_file: str = os.path.join(self.cache_dir, 'setting.json')
401401

402+
if not os.path.exists(self.setting_file):
403+
self.setting = {} # type: ignore
404+
402405
def metadata(self) -> NavMetadata:
403406
"""get the default nav metadata
404407
@@ -414,18 +417,27 @@ def metadata(self) -> NavMetadata:
414417
)
415418

416419
@property
417-
def setting(self) -> dict:
420+
def setting(self) -> HookDict[str, Any]:
418421
"""get the setting of a plugin"""
419422
with open(self.setting_file, 'r', encoding='utf-8') as f:
420423
setting = json.load(f)
421-
return setting
422424

423-
@setting.setter
424-
def setting(self, value: dict) -> None:
425+
def set_item_hooks(_: str, __: Any, value: dict) -> None:
426+
"""hook set_item event, and save the setting"""
427+
self._save_setting(value)
428+
429+
return HookDict(setting, set_item_hooks=set_item_hooks)
430+
431+
def _save_setting(self, value: dict) -> None:
425432
"""update the plugin setting"""
426433
with open(self.setting_file, 'w', encoding='utf-8') as f:
427434
json.dump(value, f, ensure_ascii=True)
428435

436+
@setting.setter # type: ignore
437+
def setting(self, value: dict) -> None:
438+
"""update the plugin setting"""
439+
self._save_setting(value)
440+
429441
def get_ui_dir(self) -> Optional[str]:
430442
"""get the ui asset dir
431443
"""
@@ -658,7 +670,7 @@ async def update_plugin_setting() -> Response:
658670
return error(f'plugin<{name}> not exist ...')
659671

660672
plugin: WechatyPlugin = self._plugins[name]
661-
plugin.setting = data['setting']
673+
plugin.setting = data['setting'] # type: ignore
662674
return success(None)
663675

664676
@app.route("/js/<string:name>", methods=['GET'])

src/wechaty/utils/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
from .qr_code import qr_terminal
33
from .type_check import default_str
44
from .date_util import timestamp_to_date
5+
from .data_util import HookDict
56
# from .type_check import type_check
67

78
__all__ = [
89
'qr_terminal',
910
'default_str',
10-
'timestamp_to_date'
11+
'timestamp_to_date',
12+
'HookDict'
1113
# 'type_check'
1214
]

src/wechaty/utils/data_util.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
Python Wechaty - https://github.com/wechaty/python-wechaty
3+
4+
Authors: Huan LI (李卓桓) <https://github.com/huan>
5+
Jingjing WU (吴京京) <https://github.com/wj-Mcat>
6+
7+
2020-now @ Copyright Wechaty
8+
9+
Licensed under the Apache License, Version 2.0 (the 'License');
10+
you may not use this file except in compliance with the License.
11+
You may obtain a copy of the License at
12+
13+
http://www.apache.org/licenses/LICENSE-2.0
14+
15+
Unless required by applicable law or agreed to in writing, software
16+
distributed under the License is distributed on an 'AS IS' BASIS,
17+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
See the License for the specific language governing permissions and
19+
limitations under the License.
20+
"""
21+
from __future__ import annotations
22+
23+
from typing import (
24+
Callable,
25+
Any,
26+
Dict,
27+
Iterable,
28+
Iterator,
29+
Optional,
30+
Type,
31+
TypeVar,
32+
MutableMapping,
33+
Generic
34+
)
35+
36+
_KT = TypeVar("_KT")
37+
_VT = TypeVar("_VT")
38+
39+
40+
class HookDict(MutableMapping[_KT, _VT], Generic[_KT, _VT]):
41+
"""add hooks to the dict data
42+
"""
43+
def __init__(
44+
self,
45+
data: Dict[_KT, _VT],
46+
set_item_hooks: Optional[Callable[[_KT, _VT, Dict[_KT, _VT]], None]] = None,
47+
default_type: Type = int,
48+
):
49+
self._dict_data = data
50+
self._set_item_hooks = set_item_hooks
51+
self.default_type = default_type
52+
53+
def __setitem__(self, key: _KT, value: Any) -> None:
54+
"""triggered by `data[key] = value`"""
55+
self._dict_data[key] = value
56+
if self._set_item_hooks is not None:
57+
self._set_item_hooks(key, value, self._dict_data)
58+
59+
def __getitem__(self, __k: _KT) -> _VT:
60+
"""get item data"""
61+
return self._dict_data.get(__k, self.default_type())
62+
63+
def __delitem__(self, __v: _KT) -> None:
64+
"""del item by key"""
65+
del self._dict_data[__v]
66+
67+
def __iter__(self) -> Iterator[_KT]:
68+
"""get the iterable data of data"""
69+
return iter(self._dict_data)
70+
71+
def __len__(self) -> int:
72+
"""get the length of dict data"""
73+
return len(self._dict_data)

tests/plugin_test.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
"""unittest for plugin"""
2+
import json
3+
import os
4+
import tempfile
5+
from wechaty.plugin import WechatyPlugin
6+
7+
8+
def test_setting():
9+
with tempfile.TemporaryDirectory() as cache_dir:
10+
os.environ['CACHE_DIR'] = cache_dir
11+
plugin = WechatyPlugin()
12+
13+
plugin.setting['unk'] = 11
14+
15+
# load the setting file
16+
assert os.path.exists(plugin.setting_file)
17+
18+
with open(plugin.setting_file, 'r', encoding='utf-8') as f:
19+
data = json.load(f)
20+
21+
assert data['unk'] == 11

tests/utils_test.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from wechaty.utils.async_helper import gather_with_concurrency
44
from wechaty.utils.link import fetch_github_user_avatar_url, get_url_metadata
55
from wechaty.utils.async_helper import SingleIdContainer
6+
from wechaty.utils.data_util import HookDict
67

78

89
async def number_task(num: int):
@@ -39,4 +40,20 @@ def test_single_id_container():
3940
for index in range(SingleIdContainer.instance().max_size):
4041
assert not SingleIdContainer.instance().exist(index)
4142

42-
assert len(SingleIdContainer.instance().ids) == 0
43+
assert len(SingleIdContainer.instance().ids) == 0
44+
45+
46+
def test_hook_dict():
47+
48+
def change_value(key: str, _: int, data: HookDict):
49+
data[key] += 10
50+
51+
data = HookDict({}, default_type=int, set_item_hooks=change_value)
52+
53+
assert data['unk-key'] == 0
54+
55+
data['1'] = 1
56+
assert data['1'] == 11
57+
58+
data['1'] = 20
59+
assert data['1'] == 30

0 commit comments

Comments
 (0)