hikari-arc 0.4.0__tar.gz → 0.6.0__tar.gz
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.
- {hikari-arc-0.4.0/hikari_arc.egg-info → hikari-arc-0.6.0}/PKG-INFO +13 -8
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/README.md +5 -5
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/__init__.py +55 -5
- hikari-arc-0.6.0/arc/abc/__init__.py +57 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/abc/client.py +207 -67
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/abc/command.py +245 -34
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/abc/error_handler.py +33 -2
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/abc/hookable.py +24 -0
- hikari-arc-0.6.0/arc/abc/limiter.py +61 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/abc/option.py +73 -5
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/abc/plugin.py +185 -29
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/client.py +103 -33
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/message.py +21 -18
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/attachment.py +9 -5
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/bool.py +9 -6
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/channel.py +9 -5
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/float.py +11 -7
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/int.py +11 -7
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/mentionable.py +9 -5
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/role.py +9 -5
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/str.py +11 -7
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/user.py +9 -5
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/slash.py +222 -197
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/user.py +20 -17
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/context/autocomplete.py +1 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/context/base.py +216 -105
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/errors.py +52 -10
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/events.py +5 -1
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/extension.py +23 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/internal/about.py +1 -1
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/internal/deprecation.py +3 -4
- hikari-arc-0.6.0/arc/internal/options.py +106 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/internal/sigparse.py +19 -1
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/internal/sync.py +13 -10
- hikari-arc-0.6.0/arc/internal/types.py +66 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/locale.py +28 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/plugin.py +56 -5
- hikari-arc-0.6.0/arc/utils/__init__.py +54 -0
- hikari-arc-0.6.0/arc/utils/hooks/__init__.py +25 -0
- hikari-arc-0.4.0/arc/utils/hooks.py → hikari-arc-0.6.0/arc/utils/hooks/basic.py +28 -1
- hikari-arc-0.6.0/arc/utils/hooks/limiters.py +217 -0
- hikari-arc-0.6.0/arc/utils/ratelimiter.py +243 -0
- hikari-arc-0.6.0/dev_requirements.txt +6 -0
- hikari-arc-0.6.0/doc_requirements.txt +5 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0/hikari_arc.egg-info}/PKG-INFO +13 -8
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/hikari_arc.egg-info/SOURCES.txt +9 -1
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/hikari_arc.egg-info/requires.txt +7 -2
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/pyproject.toml +2 -1
- hikari-arc-0.6.0/tests/test_client.py +62 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/tests/test_context_command.py +4 -4
- hikari-arc-0.6.0/tests/test_inheritance.py +56 -0
- hikari-arc-0.6.0/tests/test_options.py +53 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/tests/test_sigparse.py +32 -1
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/tests/test_slash.py +5 -5
- hikari-arc-0.4.0/arc/abc/__init__.py +0 -26
- hikari-arc-0.4.0/arc/internal/types.py +0 -47
- hikari-arc-0.4.0/arc/utils/__init__.py +0 -3
- hikari-arc-0.4.0/dev_requirements.txt +0 -3
- hikari-arc-0.4.0/doc_requirements.txt +0 -3
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/LICENSE +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/MANIFEST.in +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/__main__.py +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/__init__.py +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/command/option/__init__.py +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/context/__init__.py +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/internal/__init__.py +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/internal/version.py +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/arc/py.typed +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/hikari_arc.egg-info/dependency_links.txt +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/hikari_arc.egg-info/not-zip-safe +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/hikari_arc.egg-info/top_level.txt +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/requirements.txt +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/rest_requirements.txt +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/setup.cfg +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/setup.py +0 -0
- {hikari-arc-0.4.0 → hikari-arc-0.6.0}/tests/test_di.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hikari-arc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: A command handler for hikari with a focus on type-safety and correctness.
|
|
5
5
|
Home-page: https://github.com/hypergonial/hikari-arc
|
|
6
6
|
Author: hypergonial
|
|
@@ -30,11 +30,16 @@ Requires-Dist: colorama; sys_platform == "win32"
|
|
|
30
30
|
Provides-Extra: docs
|
|
31
31
|
Requires-Dist: mkdocs-material[imaging]~=9.5.3; extra == "docs"
|
|
32
32
|
Requires-Dist: mkdocs~=1.5.3; extra == "docs"
|
|
33
|
-
Requires-Dist: mkdocstrings-python~=1.
|
|
33
|
+
Requires-Dist: mkdocstrings-python~=1.8.0; extra == "docs"
|
|
34
|
+
Requires-Dist: black~=23.12.1; extra == "docs"
|
|
35
|
+
Requires-Dist: griffe-inherited-docstrings~=1.0.0; extra == "docs"
|
|
34
36
|
Provides-Extra: dev
|
|
35
37
|
Requires-Dist: ruff==0.1.11; extra == "dev"
|
|
36
|
-
Requires-Dist: pyright==1.1.
|
|
38
|
+
Requires-Dist: pyright==1.1.345; extra == "dev"
|
|
37
39
|
Requires-Dist: nox==2023.4.22; extra == "dev"
|
|
40
|
+
Requires-Dist: typing_extensions==4.9.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pytest==7.4.4; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest-asyncio==0.23.3; extra == "dev"
|
|
38
43
|
Provides-Extra: rest
|
|
39
44
|
Requires-Dist: hikari[server]>=2.0.0.dev122; extra == "rest"
|
|
40
45
|
|
|
@@ -81,10 +86,10 @@ bot = hikari.GatewayBot("TOKEN") # or hikari.RESTBot
|
|
|
81
86
|
client = arc.GatewayClient(bot) # or arc.RESTClient
|
|
82
87
|
|
|
83
88
|
@client.include
|
|
84
|
-
@arc.slash_command(
|
|
89
|
+
@arc.slash_command("hi", "Say hi!")
|
|
85
90
|
async def ping(
|
|
86
91
|
ctx: arc.GatewayContext,
|
|
87
|
-
user: arc.Option[hikari.User, arc.UserParams(
|
|
92
|
+
user: arc.Option[hikari.User, arc.UserParams("The user to say hi to.")]
|
|
88
93
|
) -> None:
|
|
89
94
|
await ctx.respond(f"Hey {user.mention}!")
|
|
90
95
|
|
|
@@ -105,9 +110,9 @@ See [Contributing](./CONTRIBUTING.md)
|
|
|
105
110
|
`arc` is in large part a combination of all the parts I like in other command handlers, with my own spin on it. The following projects have inspired me and aided me greatly in the design of this library:
|
|
106
111
|
|
|
107
112
|
- [`hikari-lightbulb`](https://github.com/tandemdude/hikari-lightbulb) - The library initially started as a reimagination of lightbulb, it inherits a similar project structure and terminology.
|
|
108
|
-
- [`Tanjun`](https://github.com/FasterSpeeding/Tanjun) - For the idea of using `typing.Annotated` and dependency injection in a command handler. `arc` also uses the same dependency injection library, [`Alluka`](https://github.com/FasterSpeeding/Alluka), under the hood.
|
|
109
|
-
- [`hikari-crescent`](https://github.com/hikari-crescent/hikari-crescent) The design of hooks is largely inspired by `crescent`.
|
|
110
|
-
- [`FastAPI`](https://github.com/tiangolo/fastapi) - Some design ideas and most of the documentation configuration derives from `FastAPI`.
|
|
113
|
+
- [`Tanjun`](https://github.com/FasterSpeeding/Tanjun) - For the idea of using `typing.Annotated` and [dependency injection](https://arc.hypergonial.com/guides/dependency_injection/) in a command handler. `arc` also uses the same dependency injection library, [`Alluka`](https://github.com/FasterSpeeding/Alluka), under the hood.
|
|
114
|
+
- [`hikari-crescent`](https://github.com/hikari-crescent/hikari-crescent) The design of [hooks](https://arc.hypergonial.com/guides/hooks/) is largely inspired by `crescent`.
|
|
115
|
+
- [`FastAPI`](https://github.com/tiangolo/fastapi) - Some design ideas and most of the [documentation](https://arc.hypergonial.com/) [configuration](https://github.com/hypergonial/hikari-arc/blob/main/mkdocs.yml) derives from `FastAPI`.
|
|
111
116
|
|
|
112
117
|
## Links
|
|
113
118
|
|
|
@@ -41,10 +41,10 @@ bot = hikari.GatewayBot("TOKEN") # or hikari.RESTBot
|
|
|
41
41
|
client = arc.GatewayClient(bot) # or arc.RESTClient
|
|
42
42
|
|
|
43
43
|
@client.include
|
|
44
|
-
@arc.slash_command(
|
|
44
|
+
@arc.slash_command("hi", "Say hi!")
|
|
45
45
|
async def ping(
|
|
46
46
|
ctx: arc.GatewayContext,
|
|
47
|
-
user: arc.Option[hikari.User, arc.UserParams(
|
|
47
|
+
user: arc.Option[hikari.User, arc.UserParams("The user to say hi to.")]
|
|
48
48
|
) -> None:
|
|
49
49
|
await ctx.respond(f"Hey {user.mention}!")
|
|
50
50
|
|
|
@@ -65,9 +65,9 @@ See [Contributing](./CONTRIBUTING.md)
|
|
|
65
65
|
`arc` is in large part a combination of all the parts I like in other command handlers, with my own spin on it. The following projects have inspired me and aided me greatly in the design of this library:
|
|
66
66
|
|
|
67
67
|
- [`hikari-lightbulb`](https://github.com/tandemdude/hikari-lightbulb) - The library initially started as a reimagination of lightbulb, it inherits a similar project structure and terminology.
|
|
68
|
-
- [`Tanjun`](https://github.com/FasterSpeeding/Tanjun) - For the idea of using `typing.Annotated` and dependency injection in a command handler. `arc` also uses the same dependency injection library, [`Alluka`](https://github.com/FasterSpeeding/Alluka), under the hood.
|
|
69
|
-
- [`hikari-crescent`](https://github.com/hikari-crescent/hikari-crescent) The design of hooks is largely inspired by `crescent`.
|
|
70
|
-
- [`FastAPI`](https://github.com/tiangolo/fastapi) - Some design ideas and most of the documentation configuration derives from `FastAPI`.
|
|
68
|
+
- [`Tanjun`](https://github.com/FasterSpeeding/Tanjun) - For the idea of using `typing.Annotated` and [dependency injection](https://arc.hypergonial.com/guides/dependency_injection/) in a command handler. `arc` also uses the same dependency injection library, [`Alluka`](https://github.com/FasterSpeeding/Alluka), under the hood.
|
|
69
|
+
- [`hikari-crescent`](https://github.com/hikari-crescent/hikari-crescent) The design of [hooks](https://arc.hypergonial.com/guides/hooks/) is largely inspired by `crescent`.
|
|
70
|
+
- [`FastAPI`](https://github.com/tiangolo/fastapi) - Some design ideas and most of the [documentation](https://arc.hypergonial.com/) [configuration](https://github.com/hypergonial/hikari-arc/blob/main/mkdocs.yml) derives from `FastAPI`.
|
|
71
71
|
|
|
72
72
|
## Links
|
|
73
73
|
|
|
@@ -11,10 +11,20 @@ https://arc.hypergonial.com
|
|
|
11
11
|
from alluka import Client as Injector
|
|
12
12
|
from alluka import inject
|
|
13
13
|
|
|
14
|
-
from arc import abc, command
|
|
14
|
+
from arc import abc, command, utils
|
|
15
15
|
|
|
16
|
-
from .abc import HookResult, Option, with_hook, with_post_hook
|
|
17
|
-
from .client import
|
|
16
|
+
from .abc import HookResult, Option, OptionType, with_hook, with_post_hook
|
|
17
|
+
from .client import (
|
|
18
|
+
Client,
|
|
19
|
+
GatewayClient,
|
|
20
|
+
GatewayClientBase,
|
|
21
|
+
GatewayContext,
|
|
22
|
+
GatewayPlugin,
|
|
23
|
+
RESTClient,
|
|
24
|
+
RESTClientBase,
|
|
25
|
+
RESTContext,
|
|
26
|
+
RESTPlugin,
|
|
27
|
+
)
|
|
18
28
|
from .command import (
|
|
19
29
|
AttachmentParams,
|
|
20
30
|
BoolParams,
|
|
@@ -37,7 +47,18 @@ from .command import (
|
|
|
37
47
|
user_command,
|
|
38
48
|
)
|
|
39
49
|
from .context import AutocompleteData, AutodeferMode, Context, InteractionResponse
|
|
40
|
-
from .errors import
|
|
50
|
+
from .errors import (
|
|
51
|
+
ArcError,
|
|
52
|
+
AutocompleteError,
|
|
53
|
+
CommandInvokeError,
|
|
54
|
+
CommandPublishFailedError,
|
|
55
|
+
DMOnlyError,
|
|
56
|
+
GuildCommandPublishFailedError,
|
|
57
|
+
GuildOnlyError,
|
|
58
|
+
InvokerMissingPermissionsError,
|
|
59
|
+
NotOwnerError,
|
|
60
|
+
UnderCooldownError,
|
|
61
|
+
)
|
|
41
62
|
from .events import ArcEvent, CommandErrorEvent
|
|
42
63
|
from .extension import loader, unloader
|
|
43
64
|
from .internal.about import __author__, __author_email__, __license__, __maintainer__, __url__, __version__
|
|
@@ -50,7 +71,19 @@ from .locale import (
|
|
|
50
71
|
OptionLocaleRequest,
|
|
51
72
|
)
|
|
52
73
|
from .plugin import GatewayPluginBase, PluginBase, RESTPluginBase
|
|
53
|
-
from .utils import
|
|
74
|
+
from .utils import (
|
|
75
|
+
bot_has_permissions,
|
|
76
|
+
channel_limiter,
|
|
77
|
+
custom_limiter,
|
|
78
|
+
dm_only,
|
|
79
|
+
global_limiter,
|
|
80
|
+
guild_limiter,
|
|
81
|
+
guild_only,
|
|
82
|
+
has_permissions,
|
|
83
|
+
member_limiter,
|
|
84
|
+
owner_only,
|
|
85
|
+
user_limiter,
|
|
86
|
+
)
|
|
54
87
|
|
|
55
88
|
__all__ = (
|
|
56
89
|
"__version__",
|
|
@@ -86,11 +119,21 @@ __all__ = (
|
|
|
86
119
|
"slash_command",
|
|
87
120
|
"slash_subcommand",
|
|
88
121
|
"Client",
|
|
122
|
+
"GatewayClientBase",
|
|
123
|
+
"RESTClientBase",
|
|
89
124
|
"GatewayClient",
|
|
90
125
|
"RESTClient",
|
|
126
|
+
"OptionType",
|
|
91
127
|
"ArcError",
|
|
92
128
|
"AutocompleteError",
|
|
129
|
+
"UnderCooldownError",
|
|
130
|
+
"InvokerMissingPermissionsError",
|
|
131
|
+
"GuildOnlyError",
|
|
132
|
+
"NotOwnerError",
|
|
133
|
+
"DMOnlyError",
|
|
93
134
|
"CommandInvokeError",
|
|
135
|
+
"GuildCommandPublishFailedError",
|
|
136
|
+
"CommandPublishFailedError",
|
|
94
137
|
"PluginBase",
|
|
95
138
|
"RESTPluginBase",
|
|
96
139
|
"GatewayPluginBase",
|
|
@@ -111,6 +154,7 @@ __all__ = (
|
|
|
111
154
|
"CommandLocaleRequest",
|
|
112
155
|
"OptionLocaleRequest",
|
|
113
156
|
"abc",
|
|
157
|
+
"utils",
|
|
114
158
|
"command",
|
|
115
159
|
"with_hook",
|
|
116
160
|
"with_post_hook",
|
|
@@ -119,6 +163,12 @@ __all__ = (
|
|
|
119
163
|
"guild_only",
|
|
120
164
|
"has_permissions",
|
|
121
165
|
"owner_only",
|
|
166
|
+
"global_limiter",
|
|
167
|
+
"guild_limiter",
|
|
168
|
+
"channel_limiter",
|
|
169
|
+
"user_limiter",
|
|
170
|
+
"member_limiter",
|
|
171
|
+
"custom_limiter",
|
|
122
172
|
)
|
|
123
173
|
|
|
124
174
|
# MIT License
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from .client import Client
|
|
2
|
+
from .command import CallableCommandBase, CallableCommandProto, CommandBase, CommandProto
|
|
3
|
+
from .error_handler import HasErrorHandler
|
|
4
|
+
from .hookable import Hookable, HookResult, with_hook, with_post_hook
|
|
5
|
+
from .option import (
|
|
6
|
+
CommandOptionBase,
|
|
7
|
+
Option,
|
|
8
|
+
OptionBase,
|
|
9
|
+
OptionParams,
|
|
10
|
+
OptionType,
|
|
11
|
+
OptionWithChoices,
|
|
12
|
+
OptionWithChoicesParams,
|
|
13
|
+
)
|
|
14
|
+
from .plugin import PluginBase
|
|
15
|
+
|
|
16
|
+
__all__ = (
|
|
17
|
+
"HasErrorHandler",
|
|
18
|
+
"CommandBase",
|
|
19
|
+
"CommandProto",
|
|
20
|
+
"CallableCommandProto",
|
|
21
|
+
"CallableCommandBase",
|
|
22
|
+
"Option",
|
|
23
|
+
"OptionBase",
|
|
24
|
+
"OptionType",
|
|
25
|
+
"CommandOptionBase",
|
|
26
|
+
"OptionParams",
|
|
27
|
+
"OptionWithChoices",
|
|
28
|
+
"OptionWithChoicesParams",
|
|
29
|
+
"Client",
|
|
30
|
+
"PluginBase",
|
|
31
|
+
"Hookable",
|
|
32
|
+
"HookResult",
|
|
33
|
+
"with_hook",
|
|
34
|
+
"with_post_hook",
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# MIT License
|
|
38
|
+
#
|
|
39
|
+
# Copyright (c) 2023-present hypergonial
|
|
40
|
+
#
|
|
41
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
42
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
43
|
+
# in the Software without restriction, including without limitation the rights
|
|
44
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
45
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
46
|
+
# furnished to do so, subject to the following conditions:
|
|
47
|
+
#
|
|
48
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
49
|
+
# copies or substantial portions of the Software.
|
|
50
|
+
#
|
|
51
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
52
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
53
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
54
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
55
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
56
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
57
|
+
# SOFTWARE.
|
|
@@ -15,6 +15,7 @@ from contextlib import suppress
|
|
|
15
15
|
import alluka
|
|
16
16
|
import hikari
|
|
17
17
|
|
|
18
|
+
from arc.abc.command import _CommandSettings
|
|
18
19
|
from arc.abc.plugin import PluginBase
|
|
19
20
|
from arc.command.message import MessageCommand
|
|
20
21
|
from arc.command.slash import SlashCommand, SlashGroup, SlashSubCommand, SlashSubGroup
|
|
@@ -53,16 +54,28 @@ logger = logging.getLogger(__name__)
|
|
|
53
54
|
|
|
54
55
|
class Client(t.Generic[AppT], abc.ABC):
|
|
55
56
|
"""The abstract base class for an `arc` client.
|
|
56
|
-
See [`
|
|
57
|
+
See [`GatewayClientBase`][arc.client.GatewayClientBase] and [`RESTClientBase`][arc.client.RESTClientBase] for implementations.
|
|
57
58
|
|
|
58
59
|
Parameters
|
|
59
60
|
----------
|
|
60
61
|
app : AppT
|
|
61
62
|
The application this client is for.
|
|
62
|
-
default_enabled_guilds : t.Sequence[hikari.Snowflake] | None
|
|
63
|
-
The guilds that slash commands will be registered in by default
|
|
64
|
-
autosync : bool
|
|
65
|
-
Whether to automatically sync commands on startup
|
|
63
|
+
default_enabled_guilds : t.Sequence[hikari.Snowflake] | None
|
|
64
|
+
The guilds that slash commands will be registered in by default
|
|
65
|
+
autosync : bool
|
|
66
|
+
Whether to automatically sync commands on startup
|
|
67
|
+
autodefer : bool | AutodeferMode
|
|
68
|
+
Whether to automatically defer commands that take longer than 2 seconds to respond
|
|
69
|
+
This applies to all commands, and can be overridden on a per-command basis.
|
|
70
|
+
default_permissions : hikari.Permissions | hikari.UndefinedType
|
|
71
|
+
The default permissions for commands
|
|
72
|
+
This applies to all commands, and can be overridden on a per-command basis.
|
|
73
|
+
is_nsfw : bool
|
|
74
|
+
Whether to mark commands as NSFW
|
|
75
|
+
This applies to all commands, and can be overridden on a per-command basis.
|
|
76
|
+
is_dm_enabled : bool
|
|
77
|
+
Whether to enable commands in DMs
|
|
78
|
+
This applies to all commands, and can be overridden on a per-command basis.
|
|
66
79
|
"""
|
|
67
80
|
|
|
68
81
|
__slots__: t.Sequence[str] = (
|
|
@@ -86,20 +99,36 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
86
99
|
"_command_locale_provider",
|
|
87
100
|
"_option_locale_provider",
|
|
88
101
|
"_custom_locale_provider",
|
|
102
|
+
"_cmd_settings",
|
|
89
103
|
)
|
|
90
104
|
|
|
91
105
|
def __init__(
|
|
92
106
|
self,
|
|
93
107
|
app: AppT,
|
|
94
108
|
*,
|
|
95
|
-
default_enabled_guilds: t.Sequence[hikari.
|
|
109
|
+
default_enabled_guilds: t.Sequence[hikari.Snowflakeish | hikari.PartialGuild]
|
|
110
|
+
| hikari.UndefinedType = hikari.UNDEFINED,
|
|
96
111
|
autosync: bool = True,
|
|
112
|
+
autodefer: bool | AutodeferMode = True,
|
|
113
|
+
default_permissions: hikari.Permissions | hikari.UndefinedType = hikari.UNDEFINED,
|
|
114
|
+
is_nsfw: bool = False,
|
|
115
|
+
is_dm_enabled: bool = True,
|
|
97
116
|
provided_locales: t.Sequence[hikari.Locale] | None = None,
|
|
98
117
|
) -> None:
|
|
99
118
|
self._app = app
|
|
100
|
-
self._default_enabled_guilds =
|
|
119
|
+
self._default_enabled_guilds = (
|
|
120
|
+
tuple(hikari.Snowflake(i) for i in default_enabled_guilds)
|
|
121
|
+
if default_enabled_guilds is not hikari.UNDEFINED
|
|
122
|
+
else hikari.UNDEFINED
|
|
123
|
+
)
|
|
101
124
|
self._autosync = autosync
|
|
102
125
|
self._provided_locales: t.Sequence[hikari.Locale] | None = provided_locales
|
|
126
|
+
self._cmd_settings = _CommandSettings(
|
|
127
|
+
autodefer=AutodeferMode(autodefer),
|
|
128
|
+
default_permissions=default_permissions,
|
|
129
|
+
is_nsfw=is_nsfw,
|
|
130
|
+
is_dm_enabled=is_dm_enabled,
|
|
131
|
+
)
|
|
103
132
|
|
|
104
133
|
self._application: hikari.Application | None = None
|
|
105
134
|
self._slash_commands: dict[str, SlashCommandLike[te.Self]] = {}
|
|
@@ -127,6 +156,20 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
127
156
|
will return interaction response builders to be sent back to Discord, otherwise they will return None.
|
|
128
157
|
"""
|
|
129
158
|
|
|
159
|
+
@property
|
|
160
|
+
def _commands(self) -> t.Mapping[hikari.CommandType, t.Mapping[str, CommandBase[te.Self, t.Any]]]:
|
|
161
|
+
"""All top-level commands added to this client, categorized by command type.
|
|
162
|
+
|
|
163
|
+
!!! note
|
|
164
|
+
This does not include subcommands & subgroups due to implementation details, therefore
|
|
165
|
+
you should use [`Client.walk_commands()`][arc.abc.client.Client.walk_commands] instead.
|
|
166
|
+
"""
|
|
167
|
+
return {
|
|
168
|
+
hikari.CommandType.SLASH: self._slash_commands,
|
|
169
|
+
hikari.CommandType.MESSAGE: self._message_commands,
|
|
170
|
+
hikari.CommandType.USER: self._user_commands,
|
|
171
|
+
}
|
|
172
|
+
|
|
130
173
|
@property
|
|
131
174
|
def app(self) -> AppT:
|
|
132
175
|
"""The application this client is for."""
|
|
@@ -148,34 +191,10 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
148
191
|
return self._injector
|
|
149
192
|
|
|
150
193
|
@property
|
|
151
|
-
def default_enabled_guilds(self) -> t.Sequence[hikari.Snowflake] |
|
|
194
|
+
def default_enabled_guilds(self) -> t.Sequence[hikari.Snowflake] | hikari.UndefinedType:
|
|
152
195
|
"""The guilds that slash commands will be registered in by default."""
|
|
153
196
|
return self._default_enabled_guilds
|
|
154
197
|
|
|
155
|
-
@property
|
|
156
|
-
def commands(self) -> t.Mapping[hikari.CommandType, t.Mapping[str, CommandBase[te.Self, t.Any]]]:
|
|
157
|
-
"""All commands added to this client, categorized by command type."""
|
|
158
|
-
return {
|
|
159
|
-
hikari.CommandType.SLASH: self.slash_commands,
|
|
160
|
-
hikari.CommandType.MESSAGE: self._message_commands,
|
|
161
|
-
hikari.CommandType.USER: self._user_commands,
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
@property
|
|
165
|
-
def slash_commands(self) -> t.Mapping[str, SlashCommandLike[te.Self]]:
|
|
166
|
-
"""The slash commands added to this client. This only includes top-level commands and groups."""
|
|
167
|
-
return self._slash_commands
|
|
168
|
-
|
|
169
|
-
@property
|
|
170
|
-
def message_commands(self) -> t.Mapping[str, MessageCommand[te.Self]]:
|
|
171
|
-
"""The message commands added to this client."""
|
|
172
|
-
return self._message_commands
|
|
173
|
-
|
|
174
|
-
@property
|
|
175
|
-
def user_commands(self) -> t.Mapping[str, UserCommand[te.Self]]:
|
|
176
|
-
"""The user commands added to this client."""
|
|
177
|
-
return self._user_commands
|
|
178
|
-
|
|
179
198
|
@property
|
|
180
199
|
def plugins(self) -> t.Mapping[str, PluginBase[te.Self]]:
|
|
181
200
|
"""The plugins added to this client."""
|
|
@@ -289,11 +308,11 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
289
308
|
|
|
290
309
|
match interaction.command_type:
|
|
291
310
|
case hikari.CommandType.SLASH:
|
|
292
|
-
command = self.
|
|
311
|
+
command = self._slash_commands.get(interaction.command_name)
|
|
293
312
|
case hikari.CommandType.MESSAGE:
|
|
294
|
-
command = self.
|
|
313
|
+
command = self._message_commands.get(interaction.command_name)
|
|
295
314
|
case hikari.CommandType.USER:
|
|
296
|
-
command = self.
|
|
315
|
+
command = self._user_commands.get(interaction.command_name)
|
|
297
316
|
case _:
|
|
298
317
|
pass
|
|
299
318
|
|
|
@@ -343,7 +362,7 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
343
362
|
hikari.api.InteractionAutocompleteBuilder | None
|
|
344
363
|
The autocomplete builder to send back to Discord, if using a REST client.
|
|
345
364
|
"""
|
|
346
|
-
command = self.
|
|
365
|
+
command = self._slash_commands.get(interaction.command_name)
|
|
347
366
|
|
|
348
367
|
if command is None:
|
|
349
368
|
logger.warning(f"Received autocomplete interaction for unknown command '{interaction.command_name}'.")
|
|
@@ -351,6 +370,98 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
351
370
|
|
|
352
371
|
return await command._on_autocomplete(interaction)
|
|
353
372
|
|
|
373
|
+
@t.overload
|
|
374
|
+
def walk_commands(
|
|
375
|
+
self, command_type: t.Literal[hikari.CommandType.USER], *, callable_only: bool = False
|
|
376
|
+
) -> t.Iterator[UserCommand[te.Self]]:
|
|
377
|
+
...
|
|
378
|
+
|
|
379
|
+
@t.overload
|
|
380
|
+
def walk_commands(
|
|
381
|
+
self, command_type: t.Literal[hikari.CommandType.MESSAGE], *, callable_only: bool = False
|
|
382
|
+
) -> t.Iterator[MessageCommand[te.Self]]:
|
|
383
|
+
...
|
|
384
|
+
|
|
385
|
+
@t.overload
|
|
386
|
+
def walk_commands(
|
|
387
|
+
self, command_type: t.Literal[hikari.CommandType.SLASH], *, callable_only: t.Literal[False] = False
|
|
388
|
+
) -> t.Iterator[SlashCommand[te.Self] | SlashSubCommand[te.Self] | SlashGroup[te.Self] | SlashSubGroup[te.Self]]:
|
|
389
|
+
...
|
|
390
|
+
|
|
391
|
+
@t.overload
|
|
392
|
+
def walk_commands(
|
|
393
|
+
self, command_type: t.Literal[hikari.CommandType.SLASH], *, callable_only: t.Literal[True] = True
|
|
394
|
+
) -> t.Iterator[SlashCommand[te.Self] | SlashSubCommand[te.Self]]:
|
|
395
|
+
...
|
|
396
|
+
|
|
397
|
+
def walk_commands( # noqa: C901
|
|
398
|
+
self, command_type: hikari.CommandType, *, callable_only: bool = False
|
|
399
|
+
) -> t.Iterator[t.Any]:
|
|
400
|
+
"""Iterate over all commands of a certain type added to this plugin.
|
|
401
|
+
|
|
402
|
+
Parameters
|
|
403
|
+
----------
|
|
404
|
+
command_type : hikari.CommandType
|
|
405
|
+
The type of commands to return.
|
|
406
|
+
callable_only : bool
|
|
407
|
+
Whether to only return commands that are directly callable.
|
|
408
|
+
If True, command groups and subgroups will be skipped.
|
|
409
|
+
This is only applicable to slash commands.
|
|
410
|
+
|
|
411
|
+
Yields
|
|
412
|
+
------
|
|
413
|
+
CommandT[te.Self]
|
|
414
|
+
The next command that matches the given criteria.
|
|
415
|
+
|
|
416
|
+
Usage
|
|
417
|
+
-----
|
|
418
|
+
```py
|
|
419
|
+
for cmd in plugin.walk_commands(hikari.CommandType.SLASH):
|
|
420
|
+
print(cmd.name)
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
!!! tip
|
|
424
|
+
To iterate over all types of commands, you may use [`itertools.chain()`][itertools.chain]:
|
|
425
|
+
|
|
426
|
+
```py
|
|
427
|
+
import itertools
|
|
428
|
+
|
|
429
|
+
for cmd in itertools.chain(
|
|
430
|
+
plugin.walk_commands(hikari.CommandType.SLASH),
|
|
431
|
+
plugin.walk_commands(hikari.CommandType.MESSAGE),
|
|
432
|
+
plugin.walk_commands(hikari.CommandType.USER),
|
|
433
|
+
):
|
|
434
|
+
print(cmd.name)
|
|
435
|
+
```
|
|
436
|
+
"""
|
|
437
|
+
if hikari.CommandType.SLASH is command_type:
|
|
438
|
+
for command in self._slash_commands.values():
|
|
439
|
+
if isinstance(command, SlashCommand):
|
|
440
|
+
yield command
|
|
441
|
+
continue
|
|
442
|
+
|
|
443
|
+
if not callable_only:
|
|
444
|
+
yield command
|
|
445
|
+
|
|
446
|
+
for sub in command.children.values():
|
|
447
|
+
if isinstance(sub, SlashSubCommand):
|
|
448
|
+
yield sub
|
|
449
|
+
continue
|
|
450
|
+
|
|
451
|
+
if not callable_only:
|
|
452
|
+
yield sub
|
|
453
|
+
|
|
454
|
+
for subsub in sub.children.values():
|
|
455
|
+
yield subsub
|
|
456
|
+
|
|
457
|
+
elif hikari.CommandType.MESSAGE is command_type:
|
|
458
|
+
for command in self._message_commands.values():
|
|
459
|
+
yield command
|
|
460
|
+
|
|
461
|
+
elif hikari.CommandType.USER is command_type:
|
|
462
|
+
for command in self._user_commands.values():
|
|
463
|
+
yield command
|
|
464
|
+
|
|
354
465
|
@t.overload
|
|
355
466
|
def include(self) -> t.Callable[[CommandBase[te.Self, BuilderT]], CommandBase[te.Self, BuilderT]]:
|
|
356
467
|
...
|
|
@@ -394,7 +505,7 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
394
505
|
f"\nYou should use '{type(self).__name__}.add_plugin()' to add the entire plugin to the client."
|
|
395
506
|
)
|
|
396
507
|
|
|
397
|
-
if existing := self.
|
|
508
|
+
if existing := self._commands[command.command_type].get(command.name):
|
|
398
509
|
logger.warning(
|
|
399
510
|
f"Shadowing already registered command '{command.name}'. Did you define multiple commands with the same name?"
|
|
400
511
|
)
|
|
@@ -413,12 +524,12 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
413
524
|
name: str,
|
|
414
525
|
description: str = "No description provided.",
|
|
415
526
|
*,
|
|
416
|
-
guilds:
|
|
417
|
-
autodefer: bool | AutodeferMode =
|
|
418
|
-
is_dm_enabled: bool =
|
|
419
|
-
default_permissions: hikari.
|
|
420
|
-
name_localizations:
|
|
421
|
-
description_localizations:
|
|
527
|
+
guilds: t.Sequence[hikari.Snowflakeish | hikari.PartialGuild] | hikari.UndefinedType = hikari.UNDEFINED,
|
|
528
|
+
autodefer: bool | AutodeferMode | hikari.UndefinedType = hikari.UNDEFINED,
|
|
529
|
+
is_dm_enabled: bool | hikari.UndefinedType = hikari.UNDEFINED,
|
|
530
|
+
default_permissions: hikari.Permissions | hikari.UndefinedType = hikari.UNDEFINED,
|
|
531
|
+
name_localizations: t.Mapping[hikari.Locale, str] | None = None,
|
|
532
|
+
description_localizations: t.Mapping[hikari.Locale, str] | None = None,
|
|
422
533
|
is_nsfw: bool = False,
|
|
423
534
|
) -> SlashGroup[te.Self]:
|
|
424
535
|
"""Add a new slash command group to this client.
|
|
@@ -429,27 +540,30 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
429
540
|
The name of the slash command group.
|
|
430
541
|
description : str
|
|
431
542
|
The description of the slash command group.
|
|
432
|
-
guilds :
|
|
433
|
-
The guilds to register the slash command group in
|
|
434
|
-
autodefer : bool | AutodeferMode
|
|
543
|
+
guilds : t.Sequence[hikari.Snowflake] | hikari.UndefinedType
|
|
544
|
+
The guilds to register the slash command group in
|
|
545
|
+
autodefer : bool | AutodeferMode
|
|
435
546
|
If True, all commands in this group will automatically defer if it is taking longer than 2 seconds to respond.
|
|
436
547
|
This can be overridden on a per-subcommand basis.
|
|
437
|
-
is_dm_enabled : bool
|
|
438
|
-
Whether the slash command group is enabled in DMs
|
|
439
|
-
default_permissions : hikari.
|
|
440
|
-
The default permissions for the slash command group
|
|
441
|
-
name_localizations : dict[hikari.Locale, str]
|
|
442
|
-
The name of the slash command group in different locales
|
|
443
|
-
description_localizations : dict[hikari.Locale, str]
|
|
444
|
-
The description of the slash command group in different locales
|
|
445
|
-
is_nsfw : bool
|
|
446
|
-
Whether the slash command group is only usable in NSFW channels
|
|
548
|
+
is_dm_enabled : bool
|
|
549
|
+
Whether the slash command group is enabled in DMs
|
|
550
|
+
default_permissions : hikari.Permissions | hikari.UndefinedType
|
|
551
|
+
The default permissions for the slash command group
|
|
552
|
+
name_localizations : dict[hikari.Locale, str]
|
|
553
|
+
The name of the slash command group in different locales
|
|
554
|
+
description_localizations : dict[hikari.Locale, str]
|
|
555
|
+
The description of the slash command group in different locales
|
|
556
|
+
is_nsfw : bool
|
|
557
|
+
Whether the slash command group is only usable in NSFW channels
|
|
447
558
|
|
|
448
559
|
Returns
|
|
449
560
|
-------
|
|
450
561
|
SlashGroup[te.Self]
|
|
451
562
|
The slash command group that was created.
|
|
452
563
|
|
|
564
|
+
!!! note
|
|
565
|
+
Parameters left as `hikari.UNDEFINED` will be inherited from the parent client.
|
|
566
|
+
|
|
453
567
|
Usage
|
|
454
568
|
-----
|
|
455
569
|
```py
|
|
@@ -461,14 +575,13 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
461
575
|
await ctx.respond("Hello!")
|
|
462
576
|
```
|
|
463
577
|
"""
|
|
464
|
-
|
|
578
|
+
guild_ids = tuple(hikari.Snowflake(i) for i in guilds) if guilds is not hikari.UNDEFINED else hikari.UNDEFINED
|
|
465
579
|
|
|
466
|
-
group = SlashGroup(
|
|
580
|
+
group: SlashGroup[te.Self] = SlashGroup(
|
|
467
581
|
name=name,
|
|
468
582
|
description=description,
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
autodefer=AutodeferMode(autodefer),
|
|
583
|
+
guilds=guild_ids,
|
|
584
|
+
autodefer=AutodeferMode(autodefer) if isinstance(autodefer, bool) else autodefer,
|
|
472
585
|
is_dm_enabled=is_dm_enabled,
|
|
473
586
|
default_permissions=default_permissions,
|
|
474
587
|
name_localizations=name_localizations or {},
|
|
@@ -632,6 +745,10 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
632
745
|
await ctx.respond(f"❌ Something went wrong: {exception}")
|
|
633
746
|
```
|
|
634
747
|
|
|
748
|
+
!!! warning
|
|
749
|
+
Errors that cannot be handled by the error handler should be re-raised.
|
|
750
|
+
Otherwise tracebacks will not be printed to stderr.
|
|
751
|
+
|
|
635
752
|
Or, as a function:
|
|
636
753
|
|
|
637
754
|
```py
|
|
@@ -931,8 +1048,8 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
931
1048
|
----------
|
|
932
1049
|
dir_path : str
|
|
933
1050
|
The path to the directory to load extensions from.
|
|
934
|
-
recursive : bool
|
|
935
|
-
Whether to load extensions from subdirectories
|
|
1051
|
+
recursive : bool
|
|
1052
|
+
Whether to load extensions from subdirectories
|
|
936
1053
|
|
|
937
1054
|
Returns
|
|
938
1055
|
-------
|
|
@@ -1074,7 +1191,7 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
1074
1191
|
self._injector.set_type_dependency(type_, instance)
|
|
1075
1192
|
return self
|
|
1076
1193
|
|
|
1077
|
-
def get_type_dependency(self, type_: t.Type[T]) -> hikari.
|
|
1194
|
+
def get_type_dependency(self, type_: t.Type[T]) -> T | hikari.UndefinedType:
|
|
1078
1195
|
"""Get a type dependency for this client.
|
|
1079
1196
|
|
|
1080
1197
|
Parameters
|
|
@@ -1084,7 +1201,7 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
1084
1201
|
|
|
1085
1202
|
Returns
|
|
1086
1203
|
-------
|
|
1087
|
-
hikari.
|
|
1204
|
+
T | hikari.UndefinedType
|
|
1088
1205
|
The instance of the dependency, if it exists.
|
|
1089
1206
|
"""
|
|
1090
1207
|
return self._injector.get_type_dependency(type_, default=hikari.UNDEFINED)
|
|
@@ -1170,8 +1287,8 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
1170
1287
|
|
|
1171
1288
|
Parameters
|
|
1172
1289
|
----------
|
|
1173
|
-
guild : hikari.SnowflakeishOr[hikari.PartialGuild] | None
|
|
1174
|
-
The guild to purge commands from
|
|
1290
|
+
guild : hikari.SnowflakeishOr[hikari.PartialGuild] | None
|
|
1291
|
+
The guild to purge commands from
|
|
1175
1292
|
If a `guild` is not provided, this will purge global commands.
|
|
1176
1293
|
|
|
1177
1294
|
!!! warning
|
|
@@ -1191,3 +1308,26 @@ class Client(t.Generic[AppT], abc.ABC):
|
|
|
1191
1308
|
await self.rest.set_application_commands(self.application, [], guild_id)
|
|
1192
1309
|
else:
|
|
1193
1310
|
await self.rest.set_application_commands(self.application, [])
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
# MIT License
|
|
1314
|
+
#
|
|
1315
|
+
# Copyright (c) 2023-present hypergonial
|
|
1316
|
+
#
|
|
1317
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
1318
|
+
# of this software and associated documentation files (the "Software"), to deal
|
|
1319
|
+
# in the Software without restriction, including without limitation the rights
|
|
1320
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
1321
|
+
# copies of the Software, and to permit persons to whom the Software is
|
|
1322
|
+
# furnished to do so, subject to the following conditions:
|
|
1323
|
+
#
|
|
1324
|
+
# The above copyright notice and this permission notice shall be included in all
|
|
1325
|
+
# copies or substantial portions of the Software.
|
|
1326
|
+
#
|
|
1327
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
1328
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
1329
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
1330
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
1331
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
1332
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
1333
|
+
# SOFTWARE.
|