Skip to content

Commit 3bb5a4a

Browse files
committed
Generate Literal type from discord.py
1 parent 65b3393 commit 3bb5a4a

7 files changed

Lines changed: 106 additions & 83 deletions

File tree

.pre-commit-config.yaml

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,30 @@ repos:
2222

2323
- repo: local
2424
hooks:
25-
- id: ty-check
26-
name: ty check
27-
entry: uv run --active ty check
25+
# generate/update files first and in parallel (priority 1)
26+
- id: update-generated-types
27+
name: update generated types
28+
entry: uv run --active scripts/update-generated-types.py
2829
language: python
2930
pass_filenames: false
30-
require_serial: true
31+
priority: 1
3132

3233
- id: update-json-schema
3334
name: update json schema
3435
entry: uv run --active scripts/update-json-schema.py
35-
language: system
36-
types: [python]
36+
language: python
3737
pass_filenames: false
38-
require_serial: true
38+
priority: 1
3939

4040
- id: update-json-configs
4141
name: update json configs
4242
entry: uv run --active scripts/update-json-configs.py
43-
language: system
44-
types: [python]
43+
language: python
44+
pass_filenames: false
45+
priority: 1
46+
47+
- id: ty-check
48+
name: ty check
49+
entry: uv run --active ty check --color never --no-progress
50+
language: python
4551
pass_filenames: false
46-
require_serial: true

pyproject.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,7 @@ fixable = [
7979
convention = "pep257"
8080

8181
[tool.ruff.lint.flake8-tidy-imports.banned-api]
82-
"pydantic.BaseModel" = { msg = "Use the custom StrictBaseModel instead" }
82+
"pydantic.BaseModel" = { msg = "Use discord_build_configurator._utils.StrictBaseModel instead" }
83+
84+
[tool.ruff.lint.flake8-type-checking]
85+
runtime-evaluated-base-classes = ["discord_guild_configurator._utils.StrictBaseModel"]

scripts/update-generated-types.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""Generate types based on Discord API."""
2+
3+
from pathlib import Path
4+
5+
import discord
6+
7+
import discord_guild_configurator.generated_models
8+
9+
generated_file = Path(discord_guild_configurator.generated_models.__file__)
10+
11+
12+
permission_options: list[str] = sorted(discord.Permissions.VALID_FLAGS)
13+
14+
lines = [
15+
"from typing import Literal",
16+
"",
17+
"Permission = Literal[",
18+
*(f' "{option}",' for option in permission_options),
19+
"]",
20+
"",
21+
]
22+
23+
generated_file.write_text("\n".join(lines), encoding="UTF-8", newline="\n")

scripts/update-json-configs.py

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
1+
"""Update JSON configs from Python config files."""
2+
13
import importlib
24
import sys
35
from pathlib import Path
46

57
from discord_guild_configurator.models import GuildConfig
68

7-
exit_code = 0
8-
99
configs_dir = Path(__file__).parent.parent / "configs"
1010
sys.path.append(str(configs_dir.absolute()))
11+
1112
for config_py_file in Path("configs").glob("*.py"):
12-
# load config from file
1313
config_module = importlib.import_module(config_py_file.stem)
1414
config = getattr(config_module, "CONFIG", None)
1515

1616
if config is None:
17-
exit_code = 1
1817
print(f"{config_py_file.name}: No variable 'CONFIG' found")
1918
continue
2019

2120
if not isinstance(config, GuildConfig):
22-
exit_code = 1
2321
print(f"{config_py_file.name}: Variable 'CONFIG' is not of type GuildConfig")
2422
continue
2523

@@ -32,6 +30,5 @@
3230
print(f"JSON config is up-to-date: {config_json_file.name}")
3331
continue
3432

35-
exit_code = 1
3633
config_json_file.write_text(new_config_str, encoding="UTF-8")
3734
print(f"Updated JSON config: {config_json_file.name}")

scripts/update-json-schema.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
"""Update exported JSON schema if necessary."""
22

33
import json
4-
import sys
54
from pathlib import Path
65

76
from discord_guild_configurator.models import GuildConfig
@@ -15,10 +14,4 @@
1514
if new_schema_str.endswith("}"):
1615
new_schema_str += "\n"
1716

18-
if schema_file.exists() and schema_file.read_text(encoding="UTF-8") == new_schema_str:
19-
print(f"JSON schema is up-to-date: {schema_file.name}")
20-
sys.exit(0)
21-
2217
schema_file.write_text(new_schema_str, encoding="UTF-8", newline="\n")
23-
print(f"Updated JSON schema: {schema_file.name}")
24-
sys.exit(1)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from typing import Literal
2+
3+
Permission = Literal[
4+
"add_reactions",
5+
"administrator",
6+
"attach_files",
7+
"ban_members",
8+
"change_nickname",
9+
"connect",
10+
"create_events",
11+
"create_expressions",
12+
"create_instant_invite",
13+
"create_polls",
14+
"create_private_threads",
15+
"create_public_threads",
16+
"deafen_members",
17+
"embed_links",
18+
"external_emojis",
19+
"external_stickers",
20+
"kick_members",
21+
"manage_channels",
22+
"manage_emojis",
23+
"manage_emojis_and_stickers",
24+
"manage_events",
25+
"manage_expressions",
26+
"manage_guild",
27+
"manage_messages",
28+
"manage_nicknames",
29+
"manage_permissions",
30+
"manage_roles",
31+
"manage_threads",
32+
"manage_webhooks",
33+
"mention_everyone",
34+
"moderate_members",
35+
"move_members",
36+
"mute_members",
37+
"priority_speaker",
38+
"read_message_history",
39+
"read_messages",
40+
"request_to_speak",
41+
"send_messages",
42+
"send_messages_in_threads",
43+
"send_polls",
44+
"send_tts_messages",
45+
"send_voice_messages",
46+
"speak",
47+
"stream",
48+
"use_application_commands",
49+
"use_embedded_activities",
50+
"use_external_apps",
51+
"use_external_emojis",
52+
"use_external_sounds",
53+
"use_external_stickers",
54+
"use_soundboard",
55+
"use_voice_activation",
56+
"view_audit_log",
57+
"view_channel",
58+
"view_creator_monetization_analytics",
59+
"view_guild_insights",
60+
]

src/discord_guild_configurator/models.py

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -7,71 +7,13 @@
77
from pydantic import AfterValidator, Field, model_validator
88

99
from discord_guild_configurator._utils import StrictBaseModel
10+
from discord_guild_configurator.generated_models import Permission
1011

1112
MultilineString = Annotated[
1213
str,
1314
AfterValidator(lambda text: textwrap.dedent(text.strip("\r\n").rstrip())),
1415
]
1516

16-
Permission = Literal[
17-
"add_reactions",
18-
"administrator",
19-
"attach_files",
20-
"ban_members",
21-
"change_nickname",
22-
"connect",
23-
"create_events",
24-
"create_expressions",
25-
"create_instant_invite",
26-
"create_polls",
27-
"create_private_threads",
28-
"create_public_threads",
29-
"deafen_members",
30-
"embed_links",
31-
"external_emojis",
32-
"external_stickers",
33-
"kick_members",
34-
"manage_channels",
35-
"manage_emojis",
36-
"manage_emojis_and_stickers",
37-
"manage_events",
38-
"manage_expressions",
39-
"manage_guild",
40-
"manage_messages",
41-
"manage_nicknames",
42-
"manage_permissions",
43-
"manage_roles",
44-
"manage_threads",
45-
"manage_webhooks",
46-
"mention_everyone",
47-
"moderate_members",
48-
"move_members",
49-
"mute_members",
50-
"priority_speaker",
51-
"read_message_history",
52-
"read_messages",
53-
"request_to_speak",
54-
"send_messages",
55-
"send_messages_in_threads",
56-
"send_polls",
57-
"send_tts_messages",
58-
"send_voice_messages",
59-
"speak",
60-
"stream",
61-
"use_application_commands",
62-
"use_embedded_activities",
63-
"use_external_apps",
64-
"use_external_emojis",
65-
"use_external_sounds",
66-
"use_external_stickers",
67-
"use_soundboard",
68-
"use_voice_activation",
69-
"view_audit_log",
70-
"view_channel",
71-
"view_creator_monetization_analytics",
72-
"view_guild_insights",
73-
]
74-
7517

7618
class PermissionOverwrite(StrictBaseModel):
7719
roles: list[str]

0 commit comments

Comments
 (0)