telegrinder 0.1.dev159__py3-none-any.whl → 0.1.dev161__py3-none-any.whl
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.
Potentially problematic release.
This version of telegrinder might be problematic. Click here for more details.
- telegrinder/__init__.py +4 -2
- telegrinder/api/__init__.py +0 -0
- telegrinder/api/abc.py +5 -0
- telegrinder/api/api.py +4 -4
- telegrinder/api/error.py +0 -0
- telegrinder/api/response.py +0 -0
- telegrinder/bot/__init__.py +0 -0
- telegrinder/bot/bot.py +0 -0
- telegrinder/bot/cute_types/__init__.py +0 -0
- telegrinder/bot/cute_types/base.py +0 -0
- telegrinder/bot/cute_types/callback_query.py +81 -85
- telegrinder/bot/cute_types/inline_query.py +36 -9
- telegrinder/bot/cute_types/message.py +524 -568
- telegrinder/bot/cute_types/update.py +0 -0
- telegrinder/bot/cute_types/utils.py +201 -453
- telegrinder/bot/dispatch/__init__.py +0 -0
- telegrinder/bot/dispatch/abc.py +0 -0
- telegrinder/bot/dispatch/composition.py +0 -0
- telegrinder/bot/dispatch/context.py +0 -0
- telegrinder/bot/dispatch/dispatch.py +0 -0
- telegrinder/bot/dispatch/handler/__init__.py +0 -0
- telegrinder/bot/dispatch/handler/abc.py +0 -0
- telegrinder/bot/dispatch/handler/func.py +1 -1
- telegrinder/bot/dispatch/handler/message_reply.py +0 -0
- telegrinder/bot/dispatch/middleware/__init__.py +0 -0
- telegrinder/bot/dispatch/middleware/abc.py +0 -0
- telegrinder/bot/dispatch/process.py +0 -0
- telegrinder/bot/dispatch/return_manager/__init__.py +0 -0
- telegrinder/bot/dispatch/return_manager/abc.py +0 -0
- telegrinder/bot/dispatch/return_manager/callback_query.py +0 -0
- telegrinder/bot/dispatch/return_manager/inline_query.py +0 -0
- telegrinder/bot/dispatch/return_manager/message.py +0 -0
- telegrinder/bot/dispatch/view/__init__.py +0 -0
- telegrinder/bot/dispatch/view/abc.py +20 -16
- telegrinder/bot/dispatch/view/box.py +0 -0
- telegrinder/bot/dispatch/view/callback_query.py +0 -0
- telegrinder/bot/dispatch/view/inline_query.py +0 -0
- telegrinder/bot/dispatch/view/message.py +0 -0
- telegrinder/bot/dispatch/waiter_machine/__init__.py +0 -0
- telegrinder/bot/dispatch/waiter_machine/machine.py +0 -0
- telegrinder/bot/dispatch/waiter_machine/middleware.py +0 -0
- telegrinder/bot/dispatch/waiter_machine/short_state.py +0 -0
- telegrinder/bot/polling/__init__.py +0 -0
- telegrinder/bot/polling/abc.py +0 -0
- telegrinder/bot/polling/polling.py +7 -11
- telegrinder/bot/rules/__init__.py +0 -0
- telegrinder/bot/rules/abc.py +1 -1
- telegrinder/bot/rules/adapter/__init__.py +0 -0
- telegrinder/bot/rules/adapter/abc.py +0 -0
- telegrinder/bot/rules/adapter/errors.py +0 -0
- telegrinder/bot/rules/adapter/event.py +0 -0
- telegrinder/bot/rules/adapter/raw_update.py +0 -0
- telegrinder/bot/rules/callback_data.py +3 -11
- telegrinder/bot/rules/command.py +0 -0
- telegrinder/bot/rules/enum_text.py +0 -0
- telegrinder/bot/rules/func.py +0 -0
- telegrinder/bot/rules/fuzzy.py +0 -0
- telegrinder/bot/rules/inline.py +2 -1
- telegrinder/bot/rules/integer.py +0 -0
- telegrinder/bot/rules/is_from.py +0 -0
- telegrinder/bot/rules/markup.py +3 -1
- telegrinder/bot/rules/mention.py +0 -0
- telegrinder/bot/rules/message_entities.py +3 -1
- telegrinder/bot/rules/regex.py +1 -1
- telegrinder/bot/rules/rule_enum.py +0 -0
- telegrinder/bot/rules/start.py +0 -0
- telegrinder/bot/rules/text.py +0 -0
- telegrinder/bot/scenario/__init__.py +2 -2
- telegrinder/bot/scenario/abc.py +0 -0
- telegrinder/bot/scenario/checkbox.py +9 -13
- telegrinder/bot/scenario/choice.py +2 -2
- telegrinder/client/__init__.py +0 -0
- telegrinder/client/abc.py +0 -0
- telegrinder/client/aiohttp.py +0 -0
- telegrinder/model.py +35 -36
- telegrinder/modules.py +21 -11
- telegrinder/msgspec_json.py +0 -0
- telegrinder/msgspec_utils.py +2 -2
- telegrinder/node/__init__.py +0 -0
- telegrinder/node/attachment.py +0 -0
- telegrinder/node/base.py +0 -0
- telegrinder/node/composer.py +0 -0
- telegrinder/node/container.py +0 -0
- telegrinder/node/message.py +0 -0
- telegrinder/node/rule.py +0 -0
- telegrinder/node/source.py +0 -0
- telegrinder/node/text.py +0 -0
- telegrinder/node/tools/__init__.py +0 -0
- telegrinder/node/tools/generator.py +0 -0
- telegrinder/node/update.py +0 -0
- telegrinder/rules.py +0 -0
- telegrinder/tools/__init__.py +2 -3
- telegrinder/tools/buttons.py +0 -0
- telegrinder/tools/error_handler/__init__.py +2 -0
- telegrinder/tools/error_handler/abc.py +5 -1
- telegrinder/tools/error_handler/error.py +10 -0
- telegrinder/tools/error_handler/error_handler.py +100 -81
- telegrinder/tools/formatting/__init__.py +0 -0
- telegrinder/tools/formatting/html.py +0 -0
- telegrinder/tools/formatting/links.py +0 -0
- telegrinder/tools/formatting/spec_html_formats.py +0 -0
- telegrinder/tools/global_context/__init__.py +0 -0
- telegrinder/tools/global_context/abc.py +0 -0
- telegrinder/tools/global_context/global_context.py +65 -67
- telegrinder/tools/global_context/telegrinder_ctx.py +0 -0
- telegrinder/tools/i18n/__init__.py +0 -0
- telegrinder/tools/i18n/base.py +0 -0
- telegrinder/tools/i18n/middleware/__init__.py +0 -0
- telegrinder/tools/i18n/middleware/base.py +0 -0
- telegrinder/tools/i18n/simple.py +0 -0
- telegrinder/tools/kb_set/__init__.py +0 -0
- telegrinder/tools/kb_set/base.py +0 -0
- telegrinder/tools/kb_set/yaml.py +3 -3
- telegrinder/tools/keyboard.py +17 -26
- telegrinder/tools/loop_wrapper/__init__.py +0 -0
- telegrinder/tools/loop_wrapper/abc.py +0 -0
- telegrinder/tools/loop_wrapper/loop_wrapper.py +0 -0
- telegrinder/tools/magic.py +1 -1
- telegrinder/tools/parse_mode.py +0 -0
- telegrinder/types/__init__.py +0 -0
- telegrinder/types/enums.py +2 -0
- telegrinder/types/methods.py +477 -526
- telegrinder/types/objects.py +209 -97
- {telegrinder-0.1.dev159.dist-info → telegrinder-0.1.dev161.dist-info}/LICENSE +0 -0
- {telegrinder-0.1.dev159.dist-info → telegrinder-0.1.dev161.dist-info}/METADATA +9 -8
- {telegrinder-0.1.dev159.dist-info → telegrinder-0.1.dev161.dist-info}/RECORD +38 -37
- {telegrinder-0.1.dev159.dist-info → telegrinder-0.1.dev161.dist-info}/WHEEL +1 -1
telegrinder/node/text.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
telegrinder/node/update.py
CHANGED
|
File without changes
|
telegrinder/rules.py
CHANGED
|
File without changes
|
telegrinder/tools/__init__.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from .buttons import BaseButton
|
|
2
|
-
from .error_handler import ABCErrorHandler, Catcher, ErrorHandler
|
|
2
|
+
from .error_handler import ABCErrorHandler, Catcher, CatcherError, ErrorHandler
|
|
3
3
|
from .formatting import (
|
|
4
4
|
BaseSpecFormat,
|
|
5
5
|
ChannelBoostLink,
|
|
@@ -62,7 +62,6 @@ from .keyboard import (
|
|
|
62
62
|
InlineKeyboard,
|
|
63
63
|
Keyboard,
|
|
64
64
|
RowButtons,
|
|
65
|
-
keyboard_remove,
|
|
66
65
|
)
|
|
67
66
|
from .loop_wrapper import ABCLoopWrapper, DelayedTask, LoopWrapper
|
|
68
67
|
from .magic import magic_bundle, resolve_arg_names
|
|
@@ -80,6 +79,7 @@ __all__ = (
|
|
|
80
79
|
"BaseSpecFormat",
|
|
81
80
|
"Button",
|
|
82
81
|
"Catcher",
|
|
82
|
+
"CatcherError",
|
|
83
83
|
"ChannelBoostLink",
|
|
84
84
|
"CtxVar",
|
|
85
85
|
"DelayedTask",
|
|
@@ -123,7 +123,6 @@ __all__ = (
|
|
|
123
123
|
"get_start_group_link",
|
|
124
124
|
"invite_chat_link",
|
|
125
125
|
"italic",
|
|
126
|
-
"keyboard_remove",
|
|
127
126
|
"link",
|
|
128
127
|
"magic_bundle",
|
|
129
128
|
"mention",
|
telegrinder/tools/buttons.py
CHANGED
|
File without changes
|
|
@@ -13,7 +13,11 @@ Handler = typing.Callable[typing.Concatenate[EventT, ...], typing.Awaitable[typi
|
|
|
13
13
|
|
|
14
14
|
class ABCErrorHandler(ABC, typing.Generic[EventT]):
|
|
15
15
|
@abstractmethod
|
|
16
|
-
def
|
|
16
|
+
def register_catcher(
|
|
17
|
+
self,
|
|
18
|
+
*args: typing.Any,
|
|
19
|
+
**kwargs: typing.Any,
|
|
20
|
+
) -> typing.Callable[[typing.Callable[..., typing.Any]], typing.Callable[..., typing.Any]]:
|
|
17
21
|
...
|
|
18
22
|
|
|
19
23
|
@abstractmethod
|
|
@@ -9,30 +9,31 @@ from telegrinder.modules import logger
|
|
|
9
9
|
from telegrinder.tools.magic import magic_bundle
|
|
10
10
|
|
|
11
11
|
from .abc import ABCErrorHandler, EventT, Handler
|
|
12
|
+
from .error import CatcherError
|
|
12
13
|
|
|
13
14
|
F = typing.TypeVar("F", bound="FuncCatcher")
|
|
14
15
|
ExceptionT = typing.TypeVar("ExceptionT", bound=BaseException, contravariant=True)
|
|
15
16
|
FuncCatcher = typing.Callable[typing.Concatenate[ExceptionT, ...], typing.Awaitable[typing.Any]]
|
|
16
17
|
|
|
17
18
|
|
|
18
|
-
@dataclasses.dataclass(frozen=True)
|
|
19
|
+
@dataclasses.dataclass(frozen=True, repr=False)
|
|
19
20
|
class Catcher(typing.Generic[EventT]):
|
|
20
|
-
func: FuncCatcher
|
|
21
|
+
func: FuncCatcher[BaseException]
|
|
21
22
|
_: dataclasses.KW_ONLY
|
|
22
23
|
exceptions: list[type[BaseException] | BaseException] = dataclasses.field(
|
|
23
|
-
default_factory=lambda: []
|
|
24
|
+
default_factory=lambda: [],
|
|
24
25
|
)
|
|
25
26
|
logging: bool = dataclasses.field(default=False)
|
|
26
27
|
raise_exception: bool = dataclasses.field(default=False)
|
|
27
28
|
ignore_errors: bool = dataclasses.field(default=False)
|
|
28
29
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
def __repr__(self) -> str:
|
|
31
|
+
return "<Catcher: function={!r}, logging={}, raise_exception={}, ignore_errors={}>".format(
|
|
32
|
+
self.func.__name__,
|
|
33
|
+
self.logging,
|
|
34
|
+
self.raise_exception,
|
|
35
|
+
self.ignore_errors,
|
|
36
|
+
)
|
|
36
37
|
|
|
37
38
|
async def __call__(
|
|
38
39
|
self,
|
|
@@ -40,66 +41,93 @@ class Catcher(typing.Generic[EventT]):
|
|
|
40
41
|
event: EventT,
|
|
41
42
|
api: ABCAPI,
|
|
42
43
|
ctx: Context,
|
|
43
|
-
) -> Result[typing.Any,
|
|
44
|
+
) -> Result[typing.Any, BaseException]:
|
|
44
45
|
try:
|
|
45
|
-
|
|
46
|
+
return Ok(await handler(event, **magic_bundle(handler, ctx))) # type: ignore
|
|
46
47
|
except BaseException as exc:
|
|
48
|
+
return await self.process_exception(api, event, ctx, exc, handler.__name__)
|
|
49
|
+
|
|
50
|
+
async def process_exception(
|
|
51
|
+
self,
|
|
52
|
+
api: ABCAPI,
|
|
53
|
+
event: EventT,
|
|
54
|
+
ctx: Context,
|
|
55
|
+
exception: BaseException,
|
|
56
|
+
handler_name: str,
|
|
57
|
+
) -> Result[typing.Any, BaseException]:
|
|
58
|
+
if self.match_exception(exception):
|
|
47
59
|
logger.debug(
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
self.func.__name__,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
if self.match_exception(exc):
|
|
56
|
-
logger.debug(
|
|
57
|
-
"Catcher {!r} caught an exception in handler {!r}, "
|
|
58
|
-
"running catcher...".format(
|
|
59
|
-
self.func.__name__,
|
|
60
|
-
handler.__name__,
|
|
61
|
-
)
|
|
60
|
+
"Catcher {!r} caught an exception in handler {!r}, "
|
|
61
|
+
"running catcher...".format(
|
|
62
|
+
self.func.__name__,
|
|
63
|
+
handler_name,
|
|
62
64
|
)
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
{"event": event, "api": api} | ctx # type: ignore
|
|
69
|
-
)
|
|
70
|
-
)
|
|
65
|
+
)
|
|
66
|
+
return Ok(
|
|
67
|
+
await self.func(
|
|
68
|
+
exception,
|
|
69
|
+
**magic_bundle(self.func, {"event": event, "api": api} | ctx), # type: ignore
|
|
71
70
|
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
logger.debug(
|
|
77
|
-
"Catcher {!r} {} with result: {!r}",
|
|
78
|
-
self.func.__name__,
|
|
79
|
-
"completed" if result else "failed",
|
|
80
|
-
result,
|
|
81
|
-
)
|
|
82
|
-
return result
|
|
71
|
+
)
|
|
72
|
+
logger.debug("Failed to match exception {!r}!", exception.__class__.__name__)
|
|
73
|
+
return Error(exception)
|
|
83
74
|
|
|
75
|
+
def match_exception(self, exception: BaseException) -> bool:
|
|
76
|
+
for exc in self.exceptions:
|
|
77
|
+
if isinstance(exc, type) and type(exception) == exc:
|
|
78
|
+
return True
|
|
79
|
+
if isinstance(exc, object) and type(exception) == type(exc):
|
|
80
|
+
return True if not exc.args else exc.args == exception.args
|
|
81
|
+
return False
|
|
82
|
+
|
|
84
83
|
|
|
85
84
|
class ErrorHandler(ABCErrorHandler[EventT]):
|
|
86
|
-
def __init__(self,
|
|
87
|
-
self.catcher =
|
|
85
|
+
def __init__(self, catcher: Catcher[EventT] | None = None, /) -> None:
|
|
86
|
+
self.catcher = catcher
|
|
88
87
|
|
|
89
88
|
def __repr__(self) -> str:
|
|
90
|
-
return
|
|
89
|
+
return (
|
|
90
|
+
"<ErrorHandler: exceptions_handled=[{}], catcher={!r}>".format(
|
|
91
|
+
", ".join(
|
|
92
|
+
e.__name__ if isinstance(e, type) else repr(e)
|
|
93
|
+
for e in self.catcher.exceptions
|
|
94
|
+
),
|
|
95
|
+
self.catcher,
|
|
96
|
+
)
|
|
97
|
+
if self.catcher is not None
|
|
98
|
+
else "<ErrorHandler: No catcher>"
|
|
99
|
+
)
|
|
91
100
|
|
|
92
|
-
def
|
|
101
|
+
async def __call__(
|
|
102
|
+
self,
|
|
103
|
+
handler: Handler[EventT],
|
|
104
|
+
event: EventT,
|
|
105
|
+
api: ABCAPI,
|
|
106
|
+
ctx: Context,
|
|
107
|
+
) -> Result[typing.Any, BaseException]:
|
|
108
|
+
assert self.catcher is not None
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
return await self.catcher(handler, event, api, ctx)
|
|
112
|
+
except BaseException as exc:
|
|
113
|
+
return Error(CatcherError(
|
|
114
|
+
exc,
|
|
115
|
+
"Exception {!r} was occurred during the running catcher {!r}.".format(
|
|
116
|
+
repr(exc), self.catcher.func.__name__
|
|
117
|
+
)
|
|
118
|
+
))
|
|
119
|
+
|
|
120
|
+
def register_catcher(
|
|
93
121
|
self,
|
|
94
122
|
*exceptions: type[BaseException] | BaseException,
|
|
95
123
|
logging: bool = False,
|
|
96
124
|
raise_exception: bool = False,
|
|
97
125
|
ignore_errors: bool = False,
|
|
98
126
|
):
|
|
99
|
-
"""
|
|
127
|
+
"""Register the catcher.
|
|
100
128
|
:param logging: Error logging in stderr.
|
|
101
129
|
:param raise_exception: Raise an exception if the catcher hasn't started.
|
|
102
|
-
:param ignore_errors: Ignore errors that may occur
|
|
130
|
+
:param ignore_errors: Ignore errors that may occur.
|
|
103
131
|
"""
|
|
104
132
|
|
|
105
133
|
def decorator(func: F) -> F:
|
|
@@ -113,6 +141,18 @@ class ErrorHandler(ABCErrorHandler[EventT]):
|
|
|
113
141
|
)
|
|
114
142
|
return func
|
|
115
143
|
return decorator
|
|
144
|
+
|
|
145
|
+
def process_catcher_error(self, error: CatcherError) -> Result[None, str]:
|
|
146
|
+
assert self.catcher is not None
|
|
147
|
+
|
|
148
|
+
if self.catcher.raise_exception:
|
|
149
|
+
raise error.exc from None
|
|
150
|
+
if not self.catcher.ignore_errors:
|
|
151
|
+
return Error(error.error)
|
|
152
|
+
if self.catcher.logging:
|
|
153
|
+
logger.error(error.error)
|
|
154
|
+
|
|
155
|
+
return Ok(None)
|
|
116
156
|
|
|
117
157
|
async def run(
|
|
118
158
|
self,
|
|
@@ -124,33 +164,12 @@ class ErrorHandler(ABCErrorHandler[EventT]):
|
|
|
124
164
|
if not self.catcher:
|
|
125
165
|
return Ok(await handler(event, **magic_bundle(handler, ctx))) # type: ignore
|
|
126
166
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
self.catcher.func.__name__,
|
|
137
|
-
)
|
|
138
|
-
result = ok_none
|
|
139
|
-
|
|
140
|
-
if not self.catcher.ignore_errors:
|
|
141
|
-
return Error(error_msg)
|
|
142
|
-
if self.catcher.logging:
|
|
143
|
-
logger.error(error_msg)
|
|
144
|
-
|
|
145
|
-
if self.catcher.raise_exception and not result:
|
|
146
|
-
return result
|
|
147
|
-
|
|
148
|
-
if self.catcher.logging and not result:
|
|
149
|
-
logger.error(
|
|
150
|
-
"Catcher {!r} failed with error: {!r}",
|
|
151
|
-
self.catcher.func.__name__,
|
|
152
|
-
result.error,
|
|
153
|
-
)
|
|
154
|
-
return ok_none
|
|
155
|
-
|
|
156
|
-
return result or ok_none
|
|
167
|
+
match await self(handler, event, api, ctx):
|
|
168
|
+
case Ok(_) as ok:
|
|
169
|
+
return ok
|
|
170
|
+
case Error(exc) as err:
|
|
171
|
+
if isinstance(exc, CatcherError):
|
|
172
|
+
return self.process_catcher_error(exc)
|
|
173
|
+
if self.catcher.ignore_errors:
|
|
174
|
+
return Ok(None)
|
|
175
|
+
return err
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -23,7 +23,11 @@ else:
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
def type_check(value: object, value_type: type[T]) -> typing.TypeGuard[T]:
|
|
26
|
-
return
|
|
26
|
+
return (
|
|
27
|
+
True
|
|
28
|
+
if value_type in (typing.Any, object)
|
|
29
|
+
else bool(msgspec_convert(value, value_type))
|
|
30
|
+
)
|
|
27
31
|
|
|
28
32
|
|
|
29
33
|
def is_dunder(name: str) -> bool:
|
|
@@ -44,23 +48,23 @@ def root_protection(func: F) -> F:
|
|
|
44
48
|
)
|
|
45
49
|
|
|
46
50
|
@wraps(func)
|
|
47
|
-
def wrapper(self: "GlobalContext",
|
|
48
|
-
if self.is_root_attribute(
|
|
51
|
+
def wrapper(self: "GlobalContext", name: str, /, *args) -> typing.Any:
|
|
52
|
+
if self.is_root_attribute(name) and name in (
|
|
49
53
|
self.__dict__ | self.__class__.__dict__
|
|
50
54
|
):
|
|
51
|
-
root_attr = self.get_root_attribute(
|
|
55
|
+
root_attr = self.get_root_attribute(name).unwrap()
|
|
52
56
|
if all((not root_attr.can_be_rewritten, not root_attr.can_be_read)):
|
|
53
57
|
raise AttributeError(
|
|
54
|
-
f"Unable to set, get, delete root attribute {
|
|
58
|
+
f"Unable to set, get, delete root attribute {name!r}."
|
|
55
59
|
)
|
|
56
60
|
if func.__name__ == "__setattr__" and not root_attr.can_be_rewritten:
|
|
57
|
-
raise AttributeError(f"Unable to set root attribute {
|
|
61
|
+
raise AttributeError(f"Unable to set root attribute {name!r}.")
|
|
58
62
|
if func.__name__ == "__getattr__" and not root_attr.can_be_read:
|
|
59
|
-
raise AttributeError(f"Unable to get root attribute {
|
|
63
|
+
raise AttributeError(f"Unable to get root attribute {name!r}.")
|
|
60
64
|
if func.__name__ == "__delattr__":
|
|
61
|
-
raise AttributeError(f"Unable to delete root attribute {
|
|
65
|
+
raise AttributeError(f"Unable to delete root attribute {name!r}.")
|
|
62
66
|
|
|
63
|
-
return func(self,
|
|
67
|
+
return func(self, name, *args) # type: ignore
|
|
64
68
|
|
|
65
69
|
return wrapper # type: ignore
|
|
66
70
|
|
|
@@ -77,7 +81,7 @@ def ctx_var(value: T, *, const: bool = False) -> T:
|
|
|
77
81
|
ctx.URL = '...' #: type checking error & exception 'TypeError'
|
|
78
82
|
```
|
|
79
83
|
"""
|
|
80
|
-
|
|
84
|
+
|
|
81
85
|
return typing.cast(T, CtxVar(value, const=const))
|
|
82
86
|
|
|
83
87
|
|
|
@@ -116,7 +120,9 @@ class Storage:
|
|
|
116
120
|
return Some(ctx) if ctx is not None else Nothing()
|
|
117
121
|
|
|
118
122
|
def delete(self, ctx_name: str) -> None:
|
|
119
|
-
assert
|
|
123
|
+
assert (
|
|
124
|
+
self._storage.pop(ctx_name, None) is not None
|
|
125
|
+
), f"Context {ctx_name!r} is not defined in storage."
|
|
120
126
|
|
|
121
127
|
|
|
122
128
|
@typing.dataclass_transform(
|
|
@@ -126,7 +132,7 @@ class Storage:
|
|
|
126
132
|
)
|
|
127
133
|
class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, GlobalCtxVar[CtxValueT]]):
|
|
128
134
|
"""GlobalContext.
|
|
129
|
-
|
|
135
|
+
|
|
130
136
|
```
|
|
131
137
|
ctx = GlobalContext()
|
|
132
138
|
ctx["client"] = Client()
|
|
@@ -136,7 +142,7 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
136
142
|
data = {"user": "root_user", "password": "secret_password"}
|
|
137
143
|
ctx.client.request(ctx.address + "/login", data)
|
|
138
144
|
"""
|
|
139
|
-
|
|
145
|
+
|
|
140
146
|
__ctx_name__: str | None
|
|
141
147
|
__storage__: typing.ClassVar[Storage] = Storage()
|
|
142
148
|
__root_attributes__: typing.ClassVar[tuple[RootAttr, ...]] = (
|
|
@@ -156,16 +162,13 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
156
162
|
if not issubclass(GlobalContext, cls):
|
|
157
163
|
defaults = {}
|
|
158
164
|
for name in cls.__annotations__:
|
|
159
|
-
if
|
|
160
|
-
name in cls.__dict__
|
|
161
|
-
and name not in cls.__root_attributes__
|
|
162
|
-
):
|
|
165
|
+
if name in cls.__dict__ and name not in cls.__root_attributes__:
|
|
163
166
|
defaults[name] = getattr(cls, name)
|
|
164
167
|
delattr(cls, name)
|
|
165
168
|
if isinstance(defaults[name], CtxVar) and defaults[name].const:
|
|
166
169
|
variables.pop(name, None)
|
|
167
|
-
|
|
168
|
-
variables = defaults | variables
|
|
170
|
+
|
|
171
|
+
variables = defaults | variables
|
|
169
172
|
|
|
170
173
|
ctx_name = getattr(cls, "__ctx_name__", ctx_name)
|
|
171
174
|
if ctx_name is None:
|
|
@@ -175,7 +178,7 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
175
178
|
else:
|
|
176
179
|
ctx = dict.__new__(cls, ctx_name)
|
|
177
180
|
cls.__storage__.set(ctx_name, ctx)
|
|
178
|
-
|
|
181
|
+
|
|
179
182
|
ctx.set_context_variables(variables)
|
|
180
183
|
return ctx # type: ignore
|
|
181
184
|
|
|
@@ -189,22 +192,25 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
189
192
|
|
|
190
193
|
if not hasattr(self, "__ctx_name__"):
|
|
191
194
|
self.__ctx_name__ = ctx_name
|
|
192
|
-
|
|
195
|
+
|
|
193
196
|
if variables and not self:
|
|
194
197
|
self.set_context_variables(variables)
|
|
195
|
-
|
|
198
|
+
|
|
196
199
|
def __repr__(self) -> str:
|
|
197
200
|
return "<{!r} -> ({})>".format(
|
|
198
201
|
f"{self.__class__.__name__}@{self.ctx_name}",
|
|
199
202
|
", ".join(repr(var) for var in self),
|
|
200
203
|
)
|
|
201
|
-
|
|
204
|
+
|
|
202
205
|
def __eq__(self, __value: "GlobalContext") -> bool:
|
|
203
206
|
"""Returns True if the names of context stores
|
|
204
207
|
that use self and __value instances are equivalent."""
|
|
205
208
|
|
|
206
|
-
return
|
|
207
|
-
|
|
209
|
+
return (
|
|
210
|
+
isinstance(__value, GlobalContext)
|
|
211
|
+
and self.__ctx_name__ == __value.__ctx_name__
|
|
212
|
+
)
|
|
213
|
+
|
|
208
214
|
def __setitem__(self, __name: str, __value: CtxValueT | CtxVariable[CtxValueT]):
|
|
209
215
|
if is_dunder(__name):
|
|
210
216
|
raise NameError("Cannot set a context variable with dunder name.")
|
|
@@ -217,7 +223,7 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
217
223
|
|
|
218
224
|
def __getitem__(self, __name: str) -> CtxValueT:
|
|
219
225
|
return self.get(__name).unwrap().value
|
|
220
|
-
|
|
226
|
+
|
|
221
227
|
def __delitem__(self, __name: str):
|
|
222
228
|
var = self.get(__name).unwrap()
|
|
223
229
|
if var.const:
|
|
@@ -263,9 +269,11 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
263
269
|
|
|
264
270
|
return name in cls.__root_attributes__
|
|
265
271
|
|
|
266
|
-
def set_context_variables(
|
|
272
|
+
def set_context_variables(
|
|
273
|
+
self, variables: typing.Mapping[str, CtxValueT | CtxVariable[CtxValueT]]
|
|
274
|
+
) -> None:
|
|
267
275
|
"""Set context variables from mapping."""
|
|
268
|
-
|
|
276
|
+
|
|
269
277
|
for name, var in variables.items():
|
|
270
278
|
self[name] = var
|
|
271
279
|
|
|
@@ -277,83 +285,74 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
277
285
|
if rattr.name == name:
|
|
278
286
|
return Some(rattr)
|
|
279
287
|
return Nothing()
|
|
280
|
-
|
|
288
|
+
|
|
281
289
|
def items(self) -> list[tuple[str, GlobalCtxVar[CtxValueT]]]:
|
|
282
290
|
"""Return context variables as set-like items."""
|
|
283
291
|
|
|
284
292
|
return list(dict.items(self))
|
|
285
|
-
|
|
293
|
+
|
|
286
294
|
def keys(self) -> list[str]:
|
|
287
295
|
"""Returns context variable names as keys."""
|
|
288
296
|
|
|
289
297
|
return list(dict.keys(self))
|
|
290
|
-
|
|
298
|
+
|
|
291
299
|
def values(self) -> list[GlobalCtxVar[CtxValueT]]:
|
|
292
300
|
"""Returns context variables as values."""
|
|
293
301
|
|
|
294
302
|
return list(dict.values(self))
|
|
295
|
-
|
|
303
|
+
|
|
296
304
|
def update(self, other: typing.Self) -> None:
|
|
297
305
|
"""Update context."""
|
|
298
306
|
|
|
299
307
|
dict.update(dict(other.items()))
|
|
300
|
-
|
|
308
|
+
|
|
301
309
|
def copy(self) -> typing.Self:
|
|
302
310
|
"""Copy context. Returns copied context without ctx_name."""
|
|
303
311
|
|
|
304
312
|
return self.__class__(**self.dict())
|
|
305
|
-
|
|
313
|
+
|
|
306
314
|
def dict(self) -> dict[str, GlobalCtxVar[CtxValueT]]:
|
|
307
315
|
"""Returns context as dict."""
|
|
308
316
|
|
|
309
317
|
return {name: deepcopy(var) for name, var in self.items()}
|
|
310
|
-
|
|
318
|
+
|
|
311
319
|
@typing.overload
|
|
312
|
-
def pop(self, var_name: str) -> Option[GlobalCtxVar[CtxValueT]]:
|
|
313
|
-
|
|
314
|
-
|
|
320
|
+
def pop(self, var_name: str) -> Option[GlobalCtxVar[CtxValueT]]: ...
|
|
321
|
+
|
|
315
322
|
@typing.overload
|
|
316
323
|
def pop(
|
|
317
324
|
self,
|
|
318
325
|
var_name: str,
|
|
319
326
|
var_value_type: type[T],
|
|
320
|
-
) -> Option[GlobalCtxVar[T]]:
|
|
321
|
-
|
|
322
|
-
|
|
327
|
+
) -> Option[GlobalCtxVar[T]]: ...
|
|
328
|
+
|
|
323
329
|
def pop(
|
|
324
|
-
self,
|
|
325
|
-
var_name: str,
|
|
326
|
-
var_value_type: type[T] = object
|
|
330
|
+
self, var_name: str, var_value_type: type[T] = object
|
|
327
331
|
) -> Option[GlobalCtxVar[T]]:
|
|
328
|
-
"""Pop context variable by name.
|
|
329
|
-
Returns Option[GlobalCtxVar[T]] object.
|
|
330
|
-
"""
|
|
332
|
+
"""Pop context variable by name."""
|
|
331
333
|
|
|
332
334
|
val = self.get(var_name, var_value_type)
|
|
333
335
|
if val:
|
|
334
336
|
del self[var_name]
|
|
335
337
|
return val
|
|
336
338
|
return Nothing()
|
|
337
|
-
|
|
339
|
+
|
|
338
340
|
@typing.overload
|
|
339
|
-
def get(self, var_name: str) -> Option[GlobalCtxVar[CtxValueT]]:
|
|
340
|
-
|
|
341
|
-
|
|
341
|
+
def get(self, var_name: str) -> Option[GlobalCtxVar[CtxValueT]]: ...
|
|
342
|
+
|
|
342
343
|
@typing.overload
|
|
343
344
|
def get(
|
|
344
345
|
self,
|
|
345
346
|
var_name: str,
|
|
346
347
|
var_value_type: type[T],
|
|
347
|
-
) -> Option[GlobalCtxVar[T]]:
|
|
348
|
-
|
|
349
|
-
|
|
348
|
+
) -> Option[GlobalCtxVar[T]]: ...
|
|
349
|
+
|
|
350
350
|
def get(
|
|
351
351
|
self,
|
|
352
352
|
var_name: str,
|
|
353
353
|
var_value_type: type[T] = object,
|
|
354
354
|
) -> Option[GlobalCtxVar[T]]:
|
|
355
|
-
"""Get context variable by name.
|
|
356
|
-
Returns `GlobalCtxVar[value_type]` object."""
|
|
355
|
+
"""Get context variable by name."""
|
|
357
356
|
|
|
358
357
|
generic_types = typing.get_args(get_orig_class(self))
|
|
359
358
|
if generic_types and var_value_type is object:
|
|
@@ -361,27 +360,27 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
361
360
|
var = dict.get(self, var_name)
|
|
362
361
|
if var is None:
|
|
363
362
|
return Nothing()
|
|
364
|
-
assert type_check(
|
|
365
|
-
|
|
366
|
-
|
|
363
|
+
assert type_check(
|
|
364
|
+
var.value, var_value_type
|
|
365
|
+
), "Context variable value type of {!r} does not correspond to the expected type {!r}.".format(
|
|
366
|
+
type(var.value).__name__,
|
|
367
|
+
(
|
|
367
368
|
getattr(var_value_type, "__name__")
|
|
368
369
|
if isinstance(var_value_type, type)
|
|
369
|
-
else repr(var_value_type)
|
|
370
|
-
)
|
|
370
|
+
else repr(var_value_type)
|
|
371
|
+
),
|
|
371
372
|
)
|
|
372
373
|
return Some(var)
|
|
373
374
|
|
|
374
375
|
@typing.overload
|
|
375
|
-
def get_value(self, var_name: str) -> Option[CtxValueT]:
|
|
376
|
-
...
|
|
376
|
+
def get_value(self, var_name: str) -> Option[CtxValueT]: ...
|
|
377
377
|
|
|
378
378
|
@typing.overload
|
|
379
379
|
def get_value(
|
|
380
380
|
self,
|
|
381
381
|
var_name: str,
|
|
382
382
|
var_value_type: type[T],
|
|
383
|
-
) -> Option[T]:
|
|
384
|
-
...
|
|
383
|
+
) -> Option[T]: ...
|
|
385
384
|
|
|
386
385
|
def get_value(
|
|
387
386
|
self,
|
|
@@ -398,8 +397,7 @@ class GlobalContext(ABCGlobalContext, typing.Generic[CtxValueT], dict[str, Globa
|
|
|
398
397
|
var = self.get(old_var_name).unwrap()
|
|
399
398
|
if var.const:
|
|
400
399
|
return Error(
|
|
401
|
-
f"Unable to rename variable {old_var_name!r}, "
|
|
402
|
-
"because it's a constant."
|
|
400
|
+
f"Unable to rename variable {old_var_name!r}, " "because it's a constant."
|
|
403
401
|
)
|
|
404
402
|
del self[old_var_name]
|
|
405
403
|
self[new_var_name] = var.value
|
|
File without changes
|
|
File without changes
|
telegrinder/tools/i18n/base.py
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
telegrinder/tools/i18n/simple.py
CHANGED
|
File without changes
|
|
File without changes
|
telegrinder/tools/kb_set/base.py
CHANGED
|
File without changes
|