Skip to content

Commit cbf7e8f

Browse files
authored
✨ upgrade to newer githubkit
1 parent 06dc64c commit cbf7e8f

File tree

87 files changed

+3448
-2074
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+3448
-2074
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,11 @@ async with bot.as_installation(installation_id=1):
132132
```python
133133
github = bot.github
134134
```
135+
136+
## 开发
137+
138+
生成事件列表:
139+
140+
```bash
141+
python -m codegen && ruff check --fix -e . && isort . && black .
142+
```

codegen/__init__.py

Lines changed: 63 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
import shutil
12
import inspect
23
from pathlib import Path
34
from itertools import chain
5+
from typing import Union, cast
46
from dataclasses import dataclass
5-
from typing import Dict, List, Union, get_args, get_origin
7+
from typing_extensions import get_args, get_origin
68

9+
from githubkit import GitHubModel
710
from jinja2 import Environment, PackageLoader
8-
from githubkit.webhooks.models import GitHubWebhookModel
9-
from githubkit.webhooks.types import webhook_action_types
11+
from githubkit.versions.latest.webhooks import webhook_action_types
1012

1113
MESSAGE_EVENTS = {
1214
"CommitCommentCreated",
@@ -26,8 +28,9 @@
2628

2729
@dataclass
2830
class Data:
31+
action: str | None
2932
class_name: str
30-
payload_type: str
33+
payload_types: list[str]
3134

3235

3336
def pascal_case(*names: str) -> str:
@@ -36,43 +39,72 @@ def pascal_case(*names: str) -> str:
3639

3740

3841
def build_event():
39-
imports: List[str] = []
40-
events: List[Data] = []
41-
event_types: Dict[str, Union[str, Dict[str, str]]] = {}
42+
event_types: dict[str, list[Data]] = {}
4243
for event, types in webhook_action_types.items():
44+
# event has no sub action
4345
if not isinstance(types, dict):
44-
imports.append(f"{types.__name__} as {types.__name__}Payload")
45-
events.append(Data(types.__name__, f"{types.__name__}Payload"))
46-
event_types[event] = types.__name__
46+
types = cast(type[GitHubModel], types)
47+
event_types[event] = [
48+
Data(
49+
None,
50+
types.__name__.removeprefix("Webhook"),
51+
[types.__name__],
52+
)
53+
]
4754
continue
4855

49-
action_types: Dict[str, str] = {}
56+
action_types: list[Data] = []
5057
event_types[event] = action_types
51-
for action, type in types.items():
52-
if inspect.isclass(type) and issubclass(type, GitHubWebhookModel):
53-
imports.append(f"{type.__name__} as {type.__name__}Payload")
54-
events.append(Data(type.__name__, f"{type.__name__}Payload"))
55-
action_types[action] = type.__name__
58+
for action, model in types.items():
59+
# action type is a simple model
60+
if inspect.isclass(model) and issubclass(model, GitHubModel):
61+
action_types.append(
62+
Data(
63+
action, model.__name__.removeprefix("Webhook"), [model.__name__]
64+
)
65+
)
66+
# action type is a union of models
5667
else:
57-
assert get_origin(type) is Union
58-
imports.extend(model.__name__ for model in get_args(type))
59-
events.append(
68+
assert get_origin(model) is Union
69+
action_types.append(
6070
Data(
71+
action,
6172
pascal_case(event, action),
62-
"Union["
63-
f"{', '.join(model.__name__ for model in get_args(type))}"
64-
"]",
73+
[model.__name__ for model in get_args(model)],
6574
)
6675
)
67-
action_types[action] = pascal_case(event, action)
76+
77+
output_dir = Path("./nonebot/adapters/github/event/")
78+
79+
if output_dir.exists():
80+
shutil.rmtree(output_dir)
81+
82+
output_dir.mkdir(parents=True, exist_ok=True)
6883

6984
env = Environment(loader=PackageLoader("codegen"))
85+
86+
# generate base model
87+
template = env.get_template("_base.py.jinja")
88+
base_text = template.render()
89+
(output_dir / "_base.py").write_text(base_text)
90+
91+
# generate types
92+
template = env.get_template("_types.py.jinja")
93+
types_text = template.render(types=event_types)
94+
(output_dir / "_types.py").write_text(types_text)
95+
96+
# generate event models
7097
template = env.get_template("event.py.jinja")
71-
event_text = template.render(
72-
imports=imports,
73-
events=events,
74-
types=event_types,
75-
message_events=MESSAGE_EVENTS,
76-
has_message_events=HAS_MESSAGE_EVENTS,
77-
)
78-
Path("./nonebot/adapters/github/event.py").write_text(event_text)
98+
for event, actions in event_types.items():
99+
event_text = template.render(
100+
event=event,
101+
actions=actions,
102+
message_events=MESSAGE_EVENTS,
103+
has_message_events=HAS_MESSAGE_EVENTS,
104+
)
105+
(output_dir / f"{event}.py").write_text(event_text)
106+
107+
# generate init file
108+
template = env.get_template("__init__.py.jinja")
109+
init_text = template.render(types=event_types)
110+
(output_dir / "__init__.py").write_text(init_text)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from typing import TYPE_CHECKING
2+
3+
if TYPE_CHECKING:
4+
from ._base import Event as Event
5+
from ._types import events as events
6+
{% for event, actions in types.items() %}
7+
{% for action in actions %}
8+
from .{{ event }} import {{ action.class_name }} as {{ action.class_name }}
9+
{% endfor %}
10+
{% endfor %}
11+
else:
12+
__lazy_vars__ = {
13+
{% for event, actions in types.items() %}
14+
".{{ event }}": (
15+
{% for action in actions %}
16+
"{{ action.class_name }}",
17+
{% endfor %}
18+
),
19+
{% endfor %}
20+
"._base": (
21+
"Event",
22+
),
23+
"._types": (
24+
"events",
25+
)
26+
}

codegen/templates/_base.py.jinja

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from typing import Any, Dict
2+
from typing_extensions import override
3+
4+
from nonebot.utils import escape_tag
5+
6+
from nonebot.adapters import Event as BaseEvent
7+
8+
from ..message import Message
9+
from ..utils import get_attr_or_item
10+
11+
12+
class Event(BaseEvent):
13+
id: str
14+
name: str
15+
payload: Dict[str, Any]
16+
17+
to_me: bool = False
18+
19+
@override
20+
def get_type(self) -> str:
21+
return "notice"
22+
23+
@override
24+
def get_event_name(self) -> str:
25+
return self.name + (
26+
f".{action}" if (action := get_attr_or_item(self.payload, "action")) else ""
27+
)
28+
29+
@override
30+
def get_event_description(self) -> str:
31+
return escape_tag(
32+
f"{self.__class__.__name__} {self.id}"
33+
+ (
34+
f" from sender {sender_name}"
35+
if (sender := get_attr_or_item(self.payload, "sender"))
36+
and (sender_name := get_attr_or_item(sender, "login"))
37+
else ""
38+
)
39+
+ (
40+
f" in repository {repo_name}"
41+
if (repo := get_attr_or_item(self.payload, "repository"))
42+
and (repo_name := get_attr_or_item(repo, "full_name"))
43+
else ""
44+
)
45+
)
46+
47+
@override
48+
def get_message(self) -> Message:
49+
raise ValueError("Event has no message!")
50+
51+
@override
52+
def get_user_id(self) -> str:
53+
if sender := get_attr_or_item(self.payload, "sender"):
54+
return sender.login
55+
raise ValueError("Event has no context!")
56+
57+
@override
58+
def get_session_id(self) -> str:
59+
return self.get_user_id()
60+
61+
@override
62+
def is_tome(self) -> bool:
63+
return self.to_me

codegen/templates/_types.py.jinja

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
events = {
2+
{% for event, actions in types.items() %}
3+
{% if (actions | first).action %}
4+
"{{ event }}": {
5+
{% for action in actions %}
6+
"{{ action.action }}": "{{ action.class_name }}",
7+
{% endfor %}
8+
},
9+
{% else %}
10+
"{{ event }}": "{{ (actions | first).class_name }}",
11+
{% endif %}
12+
{% endfor %}
13+
}

codegen/templates/event.py.jinja

Lines changed: 19 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,38 @@
1-
from typing import Any, Dict, Union
1+
from typing import Union
22
from functools import cached_property
3+
from typing_extensions import override
34

4-
{% for import_ in imports %}
5-
from githubkit.webhooks.models import {{ import_ }}
5+
{% for action in actions %}
6+
{% for model in action.payload_types %}
7+
from githubkit.versions.latest.models import {{ model }}
8+
{% endfor %}
69
{% endfor %}
7-
from nonebot.typing import overrides
8-
from nonebot.utils import escape_tag
9-
10-
from nonebot.adapters import Event as BaseEvent
11-
12-
from .message import Message
13-
from .utils import get_attr_or_item
14-
15-
16-
class Event(BaseEvent):
17-
id: str
18-
name: str
19-
payload: Dict[str, Any]
20-
21-
to_me: bool = False
22-
23-
@overrides(BaseEvent)
24-
def get_type(self) -> str:
25-
return "notice"
26-
27-
@overrides(BaseEvent)
28-
def get_event_name(self) -> str:
29-
return self.name + (
30-
f".{action}" if (action := get_attr_or_item(self.payload, "action")) else ""
31-
)
32-
33-
@overrides(BaseEvent)
34-
def get_event_description(self) -> str:
35-
return escape_tag(
36-
f"{self.__class__.__name__} {self.id}"
37-
+ (
38-
f" from sender {sender_name}"
39-
if (sender := get_attr_or_item(self.payload, "sender"))
40-
and (sender_name := get_attr_or_item(sender, "login"))
41-
else ""
42-
)
43-
+ (
44-
f" in repository {repo_name}"
45-
if (repo := get_attr_or_item(self.payload, "repository"))
46-
and (repo_name := get_attr_or_item(repo, "full_name"))
47-
else ""
48-
)
49-
)
50-
51-
@overrides(BaseEvent)
52-
def get_message(self) -> Message:
53-
raise ValueError("Event has no message!")
54-
55-
@overrides(BaseEvent)
56-
def get_user_id(self) -> str:
57-
if sender := get_attr_or_item(self.payload, "sender"):
58-
return sender.login
59-
raise ValueError("Event has no context!")
60-
61-
@overrides(BaseEvent)
62-
def get_session_id(self) -> str:
63-
return self.get_user_id()
6410

65-
@overrides(BaseEvent)
66-
def is_tome(self) -> bool:
67-
return self.to_me
11+
from ..message import Message
6812

13+
from ._base import Event
6914

70-
{% for event in events %}
15+
{% for action in actions %}
7116

72-
class {{ event.class_name }}(Event):
73-
payload: {{ event.payload_type }}
17+
class {{ action.class_name }}(Event):
18+
{% if action.payload_types | length > 1 %}
19+
payload: Union[{{ action.payload_types | join(", ") }}]
20+
{% else %}
21+
payload: {{ action.payload_types | first }}
22+
{% endif %}
7423

75-
{% if event.class_name in message_events %}
76-
@overrides(Event)
24+
{% if action.class_name in message_events %}
25+
@override
7726
def get_type(self) -> str:
7827
return "message"
7928
{% endif %}
8029

81-
{% if event.class_name in has_message_events %}
30+
{% if action.class_name in has_message_events %}
8231
@cached_property
8332
def _message(self):
8433
return Message(self.payload.comment.body)
8534

86-
87-
@overrides(Event)
35+
@override
8836
def get_message(self):
8937
return self._message
9038

@@ -93,17 +41,3 @@ class {{ event.class_name }}(Event):
9341

9442
{% endif %}
9543
{% endfor %}
96-
97-
events = {
98-
{% for event, types in types.items() %}
99-
{% if types is mapping %}
100-
"{{ event }}": {
101-
{% for action, type in types.items() %}
102-
"{{ action }}": {{ type }},
103-
{% endfor %}
104-
},
105-
{% else %}
106-
"{{ event }}": {{ types }},
107-
{% endif %}
108-
{% endfor %}
109-
}

nonebot/adapters/github/__init__.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
1+
from typing import TYPE_CHECKING
2+
3+
from . import lazy_module
4+
5+
lazy_module.apply()
6+
7+
if TYPE_CHECKING:
8+
from .event import * # noqa: F403
9+
else:
10+
from . import event
11+
12+
def __getattr__(name: str):
13+
try:
14+
return getattr(event, name)
15+
except AttributeError:
16+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
17+
18+
119
from .bot import Bot as Bot
2-
from .event import * # noqa: F403
320
from .bot import OAuthBot as OAuthBot
421
from .adapter import Adapter as Adapter
522
from .bot import GitHubBot as GitHubBot

0 commit comments

Comments
 (0)