telegrinder 0.1.dev158__py3-none-any.whl → 0.1.dev160__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.

Files changed (128) hide show
  1. telegrinder/__init__.py +4 -2
  2. telegrinder/api/__init__.py +0 -0
  3. telegrinder/api/abc.py +6 -4
  4. telegrinder/api/api.py +25 -11
  5. telegrinder/api/error.py +0 -0
  6. telegrinder/api/response.py +0 -0
  7. telegrinder/bot/__init__.py +0 -0
  8. telegrinder/bot/bot.py +0 -0
  9. telegrinder/bot/cute_types/__init__.py +0 -0
  10. telegrinder/bot/cute_types/base.py +100 -9
  11. telegrinder/bot/cute_types/callback_query.py +426 -37
  12. telegrinder/bot/cute_types/inline_query.py +44 -17
  13. telegrinder/bot/cute_types/message.py +2885 -117
  14. telegrinder/bot/cute_types/update.py +14 -7
  15. telegrinder/bot/cute_types/utils.py +542 -0
  16. telegrinder/bot/dispatch/__init__.py +0 -0
  17. telegrinder/bot/dispatch/abc.py +0 -0
  18. telegrinder/bot/dispatch/composition.py +0 -0
  19. telegrinder/bot/dispatch/context.py +0 -0
  20. telegrinder/bot/dispatch/dispatch.py +0 -0
  21. telegrinder/bot/dispatch/handler/__init__.py +0 -0
  22. telegrinder/bot/dispatch/handler/abc.py +0 -0
  23. telegrinder/bot/dispatch/handler/func.py +1 -1
  24. telegrinder/bot/dispatch/handler/message_reply.py +0 -0
  25. telegrinder/bot/dispatch/middleware/__init__.py +0 -0
  26. telegrinder/bot/dispatch/middleware/abc.py +0 -0
  27. telegrinder/bot/dispatch/process.py +0 -0
  28. telegrinder/bot/dispatch/return_manager/__init__.py +0 -0
  29. telegrinder/bot/dispatch/return_manager/abc.py +0 -0
  30. telegrinder/bot/dispatch/return_manager/callback_query.py +0 -0
  31. telegrinder/bot/dispatch/return_manager/inline_query.py +0 -0
  32. telegrinder/bot/dispatch/return_manager/message.py +0 -0
  33. telegrinder/bot/dispatch/view/__init__.py +0 -0
  34. telegrinder/bot/dispatch/view/abc.py +40 -29
  35. telegrinder/bot/dispatch/view/box.py +0 -0
  36. telegrinder/bot/dispatch/view/callback_query.py +0 -0
  37. telegrinder/bot/dispatch/view/inline_query.py +0 -0
  38. telegrinder/bot/dispatch/view/message.py +0 -0
  39. telegrinder/bot/dispatch/waiter_machine/__init__.py +0 -0
  40. telegrinder/bot/dispatch/waiter_machine/machine.py +0 -0
  41. telegrinder/bot/dispatch/waiter_machine/middleware.py +0 -0
  42. telegrinder/bot/dispatch/waiter_machine/short_state.py +0 -0
  43. telegrinder/bot/polling/__init__.py +0 -0
  44. telegrinder/bot/polling/abc.py +0 -0
  45. telegrinder/bot/polling/polling.py +7 -11
  46. telegrinder/bot/rules/__init__.py +0 -0
  47. telegrinder/bot/rules/abc.py +1 -1
  48. telegrinder/bot/rules/adapter/__init__.py +0 -0
  49. telegrinder/bot/rules/adapter/abc.py +0 -0
  50. telegrinder/bot/rules/adapter/errors.py +0 -0
  51. telegrinder/bot/rules/adapter/event.py +12 -6
  52. telegrinder/bot/rules/adapter/raw_update.py +0 -0
  53. telegrinder/bot/rules/callback_data.py +3 -11
  54. telegrinder/bot/rules/command.py +0 -0
  55. telegrinder/bot/rules/enum_text.py +0 -0
  56. telegrinder/bot/rules/func.py +0 -0
  57. telegrinder/bot/rules/fuzzy.py +0 -0
  58. telegrinder/bot/rules/inline.py +2 -1
  59. telegrinder/bot/rules/integer.py +0 -0
  60. telegrinder/bot/rules/is_from.py +0 -0
  61. telegrinder/bot/rules/markup.py +3 -1
  62. telegrinder/bot/rules/mention.py +0 -0
  63. telegrinder/bot/rules/message_entities.py +3 -1
  64. telegrinder/bot/rules/regex.py +1 -1
  65. telegrinder/bot/rules/rule_enum.py +0 -0
  66. telegrinder/bot/rules/start.py +0 -0
  67. telegrinder/bot/rules/text.py +0 -0
  68. telegrinder/bot/scenario/__init__.py +0 -0
  69. telegrinder/bot/scenario/abc.py +0 -0
  70. telegrinder/bot/scenario/checkbox.py +0 -0
  71. telegrinder/bot/scenario/choice.py +0 -0
  72. telegrinder/client/__init__.py +2 -2
  73. telegrinder/client/abc.py +35 -12
  74. telegrinder/client/aiohttp.py +35 -22
  75. telegrinder/model.py +70 -23
  76. telegrinder/modules.py +22 -12
  77. telegrinder/msgspec_json.py +0 -0
  78. telegrinder/msgspec_utils.py +30 -10
  79. telegrinder/node/__init__.py +0 -0
  80. telegrinder/node/attachment.py +0 -0
  81. telegrinder/node/base.py +0 -0
  82. telegrinder/node/composer.py +0 -0
  83. telegrinder/node/container.py +0 -0
  84. telegrinder/node/message.py +0 -0
  85. telegrinder/node/rule.py +0 -0
  86. telegrinder/node/source.py +0 -0
  87. telegrinder/node/text.py +0 -0
  88. telegrinder/node/tools/__init__.py +0 -0
  89. telegrinder/node/tools/generator.py +0 -0
  90. telegrinder/node/update.py +0 -0
  91. telegrinder/rules.py +0 -0
  92. telegrinder/tools/__init__.py +2 -30
  93. telegrinder/tools/buttons.py +19 -5
  94. telegrinder/tools/error_handler/__init__.py +2 -0
  95. telegrinder/tools/error_handler/abc.py +5 -1
  96. telegrinder/tools/error_handler/error.py +10 -0
  97. telegrinder/tools/error_handler/error_handler.py +100 -81
  98. telegrinder/tools/formatting/__init__.py +0 -0
  99. telegrinder/tools/formatting/html.py +0 -0
  100. telegrinder/tools/formatting/links.py +0 -0
  101. telegrinder/tools/formatting/spec_html_formats.py +0 -0
  102. telegrinder/tools/global_context/__init__.py +0 -0
  103. telegrinder/tools/global_context/abc.py +0 -0
  104. telegrinder/tools/global_context/global_context.py +65 -67
  105. telegrinder/tools/global_context/telegrinder_ctx.py +0 -0
  106. telegrinder/tools/i18n/__init__.py +0 -0
  107. telegrinder/tools/i18n/base.py +0 -0
  108. telegrinder/tools/i18n/middleware/__init__.py +0 -0
  109. telegrinder/tools/i18n/middleware/base.py +0 -0
  110. telegrinder/tools/i18n/simple.py +0 -0
  111. telegrinder/tools/kb_set/__init__.py +0 -0
  112. telegrinder/tools/kb_set/base.py +0 -0
  113. telegrinder/tools/kb_set/yaml.py +3 -3
  114. telegrinder/tools/keyboard.py +17 -26
  115. telegrinder/tools/loop_wrapper/__init__.py +0 -0
  116. telegrinder/tools/loop_wrapper/abc.py +0 -0
  117. telegrinder/tools/loop_wrapper/loop_wrapper.py +0 -0
  118. telegrinder/tools/magic.py +1 -1
  119. telegrinder/tools/parse_mode.py +0 -0
  120. telegrinder/types/__init__.py +0 -0
  121. telegrinder/types/enums.py +13 -9
  122. telegrinder/types/methods.py +783 -673
  123. telegrinder/types/objects.py +317 -163
  124. {telegrinder-0.1.dev158.dist-info → telegrinder-0.1.dev160.dist-info}/LICENSE +0 -0
  125. {telegrinder-0.1.dev158.dist-info → telegrinder-0.1.dev160.dist-info}/METADATA +9 -7
  126. {telegrinder-0.1.dev158.dist-info → telegrinder-0.1.dev160.dist-info}/RECORD +42 -41
  127. {telegrinder-0.1.dev158.dist-info → telegrinder-0.1.dev160.dist-info}/WHEEL +1 -1
  128. telegrinder/tools/inline_query.py +0 -684
@@ -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 match_exception(self, exception: BaseException) -> bool:
30
- for exc in self.exceptions:
31
- if isinstance(exc, type) and type(exception) == exc:
32
- return True
33
- if isinstance(exc, object) and type(exception) == type(exc):
34
- return True if not exc.args else exc.args == exception.args
35
- return False
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, typing.Any]:
44
+ ) -> Result[typing.Any, BaseException]:
44
45
  try:
45
- result = Ok(await handler(event, **magic_bundle(handler, ctx))) # type: ignore
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
- "Exception {!r} occurred while running handler {!r}. Matching "
49
- "exceptions it with exception that can be caught by the catcher {!r}...",
50
- exc.__class__.__name__,
51
- handler.__name__,
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
- result = Ok(
64
- await self.func(
65
- exc,
66
- **magic_bundle(
67
- self.func,
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
- else:
73
- logger.debug("Failed to match exception {!r}!", exc.__class__.__name__)
74
- result = Error(exc)
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, __catcher: Catcher[EventT] | None = None):
87
- self.catcher = __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 f"<ErrorHandler: {self.catcher!r}>"
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 catch(
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
- """Catch an exception while the handler is running.
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 in the catcher.
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
- ok_none = Ok(None)
128
-
129
- try:
130
- result = await self.catcher(handler, event, api, ctx)
131
- except BaseException as e:
132
- error_msg = "Exception {} was occurred during the running catcher {!r}.".format(
133
- repr(e.__class__.__name__)
134
- if not e.args
135
- else f"{e.__class__.__name__!r}: {str(e)!r}",
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 True if value_type is object else bool(msgspec_convert(value, value_type))
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", __name: str, *args) -> typing.Any:
48
- if self.is_root_attribute(__name) and __name in (
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(__name).unwrap()
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 {__name!r}."
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 {__name!r}.")
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 {__name!r}.")
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 {__name!r}.")
65
+ raise AttributeError(f"Unable to delete root attribute {name!r}.")
62
66
 
63
- return func(self, __name, *args) # type: ignore
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 self._storage.pop(ctx_name, None) is not None, f"Context {ctx_name!r} is not defined in storage."
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 self.__ctx_name__ == __value.__ctx_name__
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(self, variables: typing.Mapping[str, CtxValueT | CtxVariable[CtxValueT]]) -> None:
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(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__,
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -8,7 +8,7 @@ from telegrinder.tools.keyboard import InlineKeyboard, Keyboard
8
8
 
9
9
  from .base import KeyboardSetBase, KeyboardSetError
10
10
 
11
- PathLike = str | os.PathLike[str]
11
+ PathLike: typing.TypeAlias = str | os.PathLike[str]
12
12
 
13
13
 
14
14
  class KeyboardSetYAML(KeyboardSetBase):
@@ -27,7 +27,7 @@ class KeyboardSetYAML(KeyboardSetBase):
27
27
  encoding="UTF-8",
28
28
  ),
29
29
  yaml.Loader,
30
- )
30
+ )
31
31
  for name, hint in typing.get_type_hints(cls).items():
32
32
  g = re.match(r"(?:kb_|keyboard_)(.+)", name.lower())
33
33
  if not g:
@@ -47,7 +47,7 @@ class KeyboardSetYAML(KeyboardSetBase):
47
47
  "Keyboard should be dict with field buttons which must be a list, "
48
48
  "check documentation."
49
49
  )
50
-
50
+
51
51
  buttons = kb_config.pop("buttons")
52
52
  new_keyboard: Keyboard | InlineKeyboard = hint(**kb_config)
53
53
  for button in buttons: