Merge branch 'dev-2.x' into add_rename_argument_decorator

This commit is contained in:
Egor 2019-08-15 16:48:35 +03:00 committed by GitHub
commit 95f83d7cef
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
45 changed files with 876 additions and 835 deletions

View file

@ -28,13 +28,13 @@ class CallbackData:
def __init__(self, prefix, *parts, sep=':'):
if not isinstance(prefix, str):
raise TypeError(f"Prefix must be instance of str not {type(prefix).__name__}")
elif not prefix:
raise ValueError('Prefix can\'t be empty')
elif sep in prefix:
raise ValueError(f"Separator '{sep}' can't be used in prefix")
elif not parts:
raise TypeError('Parts is not passed!')
raise TypeError(f'Prefix must be instance of str not {type(prefix).__name__}')
if not prefix:
raise ValueError("Prefix can't be empty")
if sep in prefix:
raise ValueError(f"Separator {sep!r} can't be used in prefix")
if not parts:
raise TypeError('Parts were not passed!')
self.prefix = prefix
self.sep = sep
@ -59,20 +59,20 @@ class CallbackData:
if args:
value = args.pop(0)
else:
raise ValueError(f"Value for '{part}' is not passed!")
raise ValueError(f'Value for {part!r} was not passed!')
if value is not None and not isinstance(value, str):
value = str(value)
if not value:
raise ValueError(f"Value for part {part} can't be empty!'")
elif self.sep in value:
raise ValueError(f"Symbol defined as separator can't be used in values of parts")
raise ValueError(f"Value for part {part!r} can't be empty!'")
if self.sep in value:
raise ValueError(f"Symbol {self.sep!r} is defined as the separator and can't be used in parts' values")
data.append(value)
if args or kwargs:
raise TypeError('Too many arguments is passed!')
raise TypeError('Too many arguments were passed!')
callback_data = self.sep.join(data)
if len(callback_data) > 64:
@ -106,30 +106,31 @@ class CallbackData:
"""
for key in config.keys():
if key not in self._part_names:
raise ValueError(f"Invalid field name '{key}'")
raise ValueError(f'Invalid field name {key!r}')
return CallbackDataFilter(self, config)
class CallbackDataFilter(Filter):
def __init__(self, factory: CallbackData, config: typing.Dict[str, str]):
self.config = config
self.factory = factory
@classmethod
def validate(cls, full_config: typing.Dict[str, typing.Any]):
raise ValueError('That filter can\'t be used in filters factory!')
raise ValueError("That filter can't be used in filters factory!")
async def check(self, query: types.CallbackQuery):
try:
data = self.factory.parse(query.data)
except ValueError:
return False
else:
for key, value in self.config.items():
if isinstance(value, (list, tuple, set)):
if data.get(key) not in value:
return False
else:
if value != data.get(key):
return False
return {'callback_data': data}
for key, value in self.config.items():
if isinstance(value, (list, tuple, set, frozenset)):
if data.get(key) not in value:
return False
else:
if data.get(key) != value:
return False
return {'callback_data': data}

View file

@ -15,7 +15,7 @@ from ..dispatcher.webhook import BOT_DISPATCHER_KEY, DEFAULT_ROUTE_NAME, Webhook
APP_EXECUTOR_KEY = 'APP_EXECUTOR'
def _setup_callbacks(executor, on_startup=None, on_shutdown=None):
def _setup_callbacks(executor: 'Executor', on_startup=None, on_shutdown=None):
if on_startup is not None:
executor.on_startup(on_startup)
if on_shutdown is not None:
@ -23,7 +23,7 @@ def _setup_callbacks(executor, on_startup=None, on_shutdown=None):
def start_polling(dispatcher, *, loop=None, skip_updates=False, reset_webhook=True,
on_startup=None, on_shutdown=None, timeout=20, fast=True):
on_startup=None, on_shutdown=None, timeout=20, relax=0.1, fast=True):
"""
Start bot in long-polling mode
@ -38,7 +38,7 @@ def start_polling(dispatcher, *, loop=None, skip_updates=False, reset_webhook=Tr
executor = Executor(dispatcher, skip_updates=skip_updates, loop=loop)
_setup_callbacks(executor, on_startup, on_shutdown)
executor.start_polling(reset_webhook=reset_webhook, timeout=timeout, fast=fast)
executor.start_polling(reset_webhook=reset_webhook, timeout=timeout, relax=relax, fast=fast)
def set_webhook(dispatcher: Dispatcher, webhook_path: str, *, loop: Optional[asyncio.AbstractEventLoop] = None,
@ -291,7 +291,7 @@ class Executor:
self.set_webhook(webhook_path=webhook_path, request_handler=request_handler, route_name=route_name)
self.run_app(**kwargs)
def start_polling(self, reset_webhook=None, timeout=20, fast=True):
def start_polling(self, reset_webhook=None, timeout=20, relax=0.1, fast=True):
"""
Start bot in long-polling mode
@ -303,7 +303,8 @@ class Executor:
try:
loop.run_until_complete(self._startup_polling())
loop.create_task(self.dispatcher.start_polling(reset_webhook=reset_webhook, timeout=timeout, fast=fast))
loop.create_task(self.dispatcher.start_polling(reset_webhook=reset_webhook, timeout=timeout,
relax=relax, fast=fast))
loop.run_forever()
except (KeyboardInterrupt, SystemExit):
# loop.stop()
@ -339,7 +340,7 @@ class Executor:
async def _skip_updates(self):
await self.dispatcher.reset_webhook(True)
await self.dispatcher.skip_updates()
log.warning(f"Updates are skipped successfully.")
log.warning(f'Updates were skipped successfully.')
async def _welcome(self):
user = await self.dispatcher.bot.me

View file

@ -120,15 +120,15 @@ class HelperMode(Helper):
"""
if mode == cls.SCREAMING_SNAKE_CASE:
return cls._screaming_snake_case(text)
elif mode == cls.snake_case:
if mode == cls.snake_case:
return cls._snake_case(text)
elif mode == cls.lowercase:
if mode == cls.lowercase:
return cls._snake_case(text).replace('_', '')
elif mode == cls.lowerCamelCase:
if mode == cls.lowerCamelCase:
return cls._camel_case(text)
elif mode == cls.CamelCase:
if mode == cls.CamelCase:
return cls._camel_case(text, True)
elif callable(mode):
if callable(mode):
return mode(text)
return text

View file

@ -31,7 +31,7 @@ T = TypeVar('T')
class ContextInstanceMixin:
def __init_subclass__(cls, **kwargs):
cls.__context_instance = contextvars.ContextVar('instance_' + cls.__name__)
cls.__context_instance = contextvars.ContextVar(f'instance_{cls.__name__}')
return cls
@classmethod
@ -43,5 +43,5 @@ class ContextInstanceMixin:
@classmethod
def set_current(cls: Type[T], value: T):
if not isinstance(value, cls):
raise TypeError(f"Value should be instance of '{cls.__name__}' not '{type(value).__name__}'")
raise TypeError(f'Value should be instance of {cls.__name__!r} not {type(value).__name__!r}')
cls.__context_instance.set(value)

View file

@ -52,14 +52,14 @@ def prepare_arg(value):
"""
if value is None:
return value
elif isinstance(value, (list, dict)) or hasattr(value, 'to_python'):
if isinstance(value, (list, dict)) or hasattr(value, 'to_python'):
return json.dumps(_normalize(value))
elif isinstance(value, datetime.timedelta):
if isinstance(value, datetime.timedelta):
now = datetime.datetime.now()
return int((now + value).timestamp())
elif isinstance(value, datetime.datetime):
if isinstance(value, datetime.datetime):
return round(value.timestamp())
elif isinstance(value, LazyProxy):
if isinstance(value, LazyProxy):
return str(value)
return value