Language-labelled commands are accepted only for selected language. /father uses selected language for commands
This commit is contained in:
parent
e6fdacd2f4
commit
cf6a2e1baa
@ -3,7 +3,7 @@
|
|||||||
Usage:
|
Usage:
|
||||||
```
|
```
|
||||||
import davtelepot
|
import davtelepot
|
||||||
my_bot = davtelepot.Bot.get('my_token', 'my_database.db')
|
my_bot = davtelepot.bot.Bot(token='my_token', database_url='my_database.db')
|
||||||
davtelepot.admin_tools.init(my_bot)
|
davtelepot.admin_tools.init(my_bot)
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
@ -1070,7 +1070,11 @@ def get_current_commands(bot: Bot, language: str = None) -> List[dict]:
|
|||||||
return sorted(
|
return sorted(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
'command': name,
|
'command': bot.get_message(
|
||||||
|
messages=information['language_labelled_commands'],
|
||||||
|
default_message=name,
|
||||||
|
language=language
|
||||||
|
),
|
||||||
'description': bot.get_message(
|
'description': bot.get_message(
|
||||||
messages=information['description'],
|
messages=information['description'],
|
||||||
language=language
|
language=language
|
||||||
|
@ -778,6 +778,19 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
).group(0) # Get the first group of characters matching pattern
|
).group(0) # Get the first group of characters matching pattern
|
||||||
if command in self.commands:
|
if command in self.commands:
|
||||||
replier = self.commands[command]['handler']
|
replier = self.commands[command]['handler']
|
||||||
|
elif command in [
|
||||||
|
description['language_labelled_commands'][language]
|
||||||
|
for c, description in self.commands.items()
|
||||||
|
if 'language_labelled_commands' in description
|
||||||
|
and language in description['language_labelled_commands']
|
||||||
|
]:
|
||||||
|
replier = [
|
||||||
|
description['handler']
|
||||||
|
for c, description in self.commands.items()
|
||||||
|
if 'language_labelled_commands' in description
|
||||||
|
and language in description['language_labelled_commands']
|
||||||
|
and command == description['language_labelled_commands'][language]
|
||||||
|
][0]
|
||||||
elif 'chat' in update and update['chat']['id'] > 0:
|
elif 'chat' in update and update['chat']['id'] > 0:
|
||||||
reply = dict(text=self.unknown_command_message)
|
reply = dict(text=self.unknown_command_message)
|
||||||
else: # Handle command aliases and text parsers
|
else: # Handle command aliases and text parsers
|
||||||
@ -2153,6 +2166,10 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
"""
|
"""
|
||||||
if language_labelled_commands is None:
|
if language_labelled_commands is None:
|
||||||
language_labelled_commands = dict()
|
language_labelled_commands = dict()
|
||||||
|
language_labelled_commands = {
|
||||||
|
key: val.strip('/').lower()
|
||||||
|
for key, val in language_labelled_commands.items()
|
||||||
|
}
|
||||||
# Handle language-labelled commands:
|
# Handle language-labelled commands:
|
||||||
# choose one main command and add others to `aliases`
|
# choose one main command and add others to `aliases`
|
||||||
if isinstance(command, dict) and len(command) > 0:
|
if isinstance(command, dict) and len(command) > 0:
|
||||||
@ -2166,18 +2183,12 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
break
|
break
|
||||||
if aliases is None:
|
if aliases is None:
|
||||||
aliases = []
|
aliases = []
|
||||||
aliases += [
|
|
||||||
alias
|
|
||||||
for alias in language_labelled_commands.values()
|
|
||||||
if alias != command
|
|
||||||
]
|
|
||||||
if not isinstance(command, str):
|
if not isinstance(command, str):
|
||||||
raise TypeError(f'Command `{command}` is not a string')
|
raise TypeError(f'Command `{command}` is not a string')
|
||||||
if isinstance(reply_keyboard_button, dict):
|
if isinstance(reply_keyboard_button, dict):
|
||||||
for button in reply_keyboard_button.values():
|
for button in reply_keyboard_button.values():
|
||||||
if button not in aliases:
|
if button not in aliases:
|
||||||
aliases.append(button)
|
aliases.append(button)
|
||||||
if aliases:
|
|
||||||
if not isinstance(aliases, list):
|
if not isinstance(aliases, list):
|
||||||
raise TypeError(f'Aliases is not a list: `{aliases}`')
|
raise TypeError(f'Aliases is not a list: `{aliases}`')
|
||||||
if not all(
|
if not all(
|
||||||
@ -2187,7 +2198,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
]
|
]
|
||||||
):
|
):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
f'Aliases {aliases} is not a list of strings string'
|
f'Aliases {aliases} is not a list of strings'
|
||||||
)
|
)
|
||||||
if isinstance(help_section, dict):
|
if isinstance(help_section, dict):
|
||||||
if 'authorization_level' not in help_section:
|
if 'authorization_level' not in help_section:
|
||||||
|
@ -98,7 +98,7 @@ def extract(text, starter=None, ender=None):
|
|||||||
|
|
||||||
|
|
||||||
def make_button(text=None, callback_data='',
|
def make_button(text=None, callback_data='',
|
||||||
prefix='', delimiter='|', data=[]):
|
prefix='', delimiter='|', data=None):
|
||||||
"""Return a Telegram bot API-compliant button.
|
"""Return a Telegram bot API-compliant button.
|
||||||
|
|
||||||
callback_data can be either a ready-to-use string or a
|
callback_data can be either a ready-to-use string or a
|
||||||
@ -107,6 +107,8 @@ def make_button(text=None, callback_data='',
|
|||||||
it gets truncated at the last delimiter before that limit.
|
it gets truncated at the last delimiter before that limit.
|
||||||
If absent, text is the same as callback_data.
|
If absent, text is the same as callback_data.
|
||||||
"""
|
"""
|
||||||
|
if data is None:
|
||||||
|
data = []
|
||||||
if len(data):
|
if len(data):
|
||||||
callback_data += delimiter.join(map(str, data))
|
callback_data += delimiter.join(map(str, data))
|
||||||
callback_data = "{p}{c}".format(
|
callback_data = "{p}{c}".format(
|
||||||
@ -170,7 +172,7 @@ async def async_get(url, mode='json', **kwargs):
|
|||||||
del kwargs['mode']
|
del kwargs['mode']
|
||||||
return await async_request(
|
return await async_request(
|
||||||
url,
|
url,
|
||||||
type='get',
|
method='get',
|
||||||
mode=mode,
|
mode=mode,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
@ -188,13 +190,13 @@ async def async_post(url, mode='html', **kwargs):
|
|||||||
"""
|
"""
|
||||||
return await async_request(
|
return await async_request(
|
||||||
url,
|
url,
|
||||||
type='post',
|
method='post',
|
||||||
mode=mode,
|
mode=mode,
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_request(url, type='get', mode='json', encoding=None, errors='strict',
|
async def async_request(url, method='get', mode='json', encoding=None, errors='strict',
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""Make an async html request.
|
"""Make an async html request.
|
||||||
|
|
||||||
@ -214,7 +216,7 @@ async def async_request(url, type='get', mode='json', encoding=None, errors='str
|
|||||||
async with aiohttp.ClientSession() as s:
|
async with aiohttp.ClientSession() as s:
|
||||||
async with (
|
async with (
|
||||||
s.get(url, timeout=30)
|
s.get(url, timeout=30)
|
||||||
if type == 'get'
|
if method == 'get'
|
||||||
else s.post(url, timeout=30, data=kwargs)
|
else s.post(url, timeout=30, data=kwargs)
|
||||||
) as r:
|
) as r:
|
||||||
if mode in ['html', 'json', 'string']:
|
if mode in ['html', 'json', 'string']:
|
||||||
@ -246,12 +248,14 @@ async def async_request(url, type='get', mode='json', encoding=None, errors='str
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def json_read(file_, default={}, encoding='utf-8', **kwargs):
|
def json_read(file_, default=None, encoding='utf-8', **kwargs):
|
||||||
"""Return json parsing of `file_`, or `default` if file does not exist.
|
"""Return json parsing of `file_`, or `default` if file does not exist.
|
||||||
|
|
||||||
`encoding` refers to how the file should be read.
|
`encoding` refers to how the file should be read.
|
||||||
`kwargs` will be passed to json.load()
|
`kwargs` will be passed to json.load()
|
||||||
"""
|
"""
|
||||||
|
if default is None:
|
||||||
|
default = {}
|
||||||
if not os.path.isfile(file_):
|
if not os.path.isfile(file_):
|
||||||
return default
|
return default
|
||||||
with open(file_, "r", encoding=encoding) as f:
|
with open(file_, "r", encoding=encoding) as f:
|
||||||
@ -268,7 +272,7 @@ def json_write(what, file_, encoding='utf-8', **kwargs):
|
|||||||
return json.dump(what, f, indent=4, **kwargs)
|
return json.dump(what, f, indent=4, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
def csv_read(file_, default=[], encoding='utf-8',
|
def csv_read(file_, default=None, encoding='utf-8',
|
||||||
delimiter=',', quotechar='"', **kwargs):
|
delimiter=',', quotechar='"', **kwargs):
|
||||||
"""Return csv parsing of `file_`, or `default` if file does not exist.
|
"""Return csv parsing of `file_`, or `default` if file does not exist.
|
||||||
|
|
||||||
@ -277,6 +281,8 @@ def csv_read(file_, default=[], encoding='utf-8',
|
|||||||
`quotechar` is the string delimiter.
|
`quotechar` is the string delimiter.
|
||||||
`kwargs` will be passed to csv.reader()
|
`kwargs` will be passed to csv.reader()
|
||||||
"""
|
"""
|
||||||
|
if default is None:
|
||||||
|
default = []
|
||||||
if not os.path.isfile(file_):
|
if not os.path.isfile(file_):
|
||||||
return default
|
return default
|
||||||
result = []
|
result = []
|
||||||
@ -299,7 +305,7 @@ def csv_read(file_, default=[], encoding='utf-8',
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def csv_write(info=[], file_='output.csv', encoding='utf-8',
|
def csv_write(info=None, file_='output.csv', encoding='utf-8',
|
||||||
delimiter=',', quotechar='"', **kwargs):
|
delimiter=',', quotechar='"', **kwargs):
|
||||||
"""Store `info` in CSV `file_`.
|
"""Store `info` in CSV `file_`.
|
||||||
|
|
||||||
@ -309,6 +315,8 @@ def csv_write(info=[], file_='output.csv', encoding='utf-8',
|
|||||||
`encoding` refers to how the file should be written.
|
`encoding` refers to how the file should be written.
|
||||||
`kwargs` will be passed to csv.writer()
|
`kwargs` will be passed to csv.writer()
|
||||||
"""
|
"""
|
||||||
|
if info is None:
|
||||||
|
info = []
|
||||||
assert (
|
assert (
|
||||||
type(info) is list
|
type(info) is list
|
||||||
and len(info) > 0
|
and len(info) > 0
|
||||||
@ -403,19 +411,19 @@ class MyOD(collections.OrderedDict):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def line_drawing_unordered_list(l):
|
def line_drawing_unordered_list(list_):
|
||||||
"""Draw an old-fashioned unordered list.
|
"""Draw an old-fashioned unordered list.
|
||||||
|
|
||||||
Unorderd list example
|
Unordered list example
|
||||||
├ An element
|
├ An element
|
||||||
├ Another element
|
├ Another element
|
||||||
└Last element
|
└Last element
|
||||||
"""
|
"""
|
||||||
result = ""
|
result = ""
|
||||||
if l:
|
if list_:
|
||||||
for x in l[:-1]:
|
for x in list_[:-1]:
|
||||||
result += "├ {}\n".format(x)
|
result += "├ {}\n".format(x)
|
||||||
result += "└ {}".format(l[-1])
|
result += "└ {}".format(list_[-1])
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@ -444,7 +452,7 @@ def datetime_to_str(d):
|
|||||||
return '{:%Y-%m-%d %H:%M:%S.%f}'.format(d)
|
return '{:%Y-%m-%d %H:%M:%S.%f}'.format(d)
|
||||||
|
|
||||||
|
|
||||||
class MyCounter():
|
class MyCounter:
|
||||||
"""Counter object, with a `lvl` method incrementing `n` property."""
|
"""Counter object, with a `lvl` method incrementing `n` property."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -523,7 +531,7 @@ def forwarded(by=None):
|
|||||||
Decorator: such decorated functions have effect only if update
|
Decorator: such decorated functions have effect only if update
|
||||||
is forwarded from someone (you can specify `by` whom).
|
is forwarded from someone (you can specify `by` whom).
|
||||||
"""
|
"""
|
||||||
def is_forwarded_by(update, by):
|
def is_forwarded_by(update):
|
||||||
if 'forward_from' not in update:
|
if 'forward_from' not in update:
|
||||||
return False
|
return False
|
||||||
if by and update['forward_from']['id'] != by:
|
if by and update['forward_from']['id'] != by:
|
||||||
@ -533,11 +541,11 @@ def forwarded(by=None):
|
|||||||
def decorator(view_func):
|
def decorator(view_func):
|
||||||
if asyncio.iscoroutinefunction(view_func):
|
if asyncio.iscoroutinefunction(view_func):
|
||||||
async def decorated(update):
|
async def decorated(update):
|
||||||
if is_forwarded_by(update, by):
|
if is_forwarded_by(update):
|
||||||
return await view_func(update)
|
return await view_func(update)
|
||||||
else:
|
else:
|
||||||
def decorated(update):
|
def decorated(update):
|
||||||
if is_forwarded_by(update, by):
|
if is_forwarded_by(update):
|
||||||
return view_func(update)
|
return view_func(update)
|
||||||
return decorated
|
return decorated
|
||||||
return decorator
|
return decorator
|
||||||
@ -549,7 +557,7 @@ def chat_selective(chat_id=None):
|
|||||||
Such decorated functions have effect only if update comes from
|
Such decorated functions have effect only if update comes from
|
||||||
a specific (if `chat_id` is given) or generic chat.
|
a specific (if `chat_id` is given) or generic chat.
|
||||||
"""
|
"""
|
||||||
def check_function(update, chat_id):
|
def check_function(update):
|
||||||
if 'chat' not in update:
|
if 'chat' not in update:
|
||||||
return False
|
return False
|
||||||
if chat_id:
|
if chat_id:
|
||||||
@ -560,17 +568,17 @@ def chat_selective(chat_id=None):
|
|||||||
def decorator(view_func):
|
def decorator(view_func):
|
||||||
if asyncio.iscoroutinefunction(view_func):
|
if asyncio.iscoroutinefunction(view_func):
|
||||||
async def decorated(update):
|
async def decorated(update):
|
||||||
if check_function(update, chat_id):
|
if check_function(update):
|
||||||
return await view_func(update)
|
return await view_func(update)
|
||||||
else:
|
else:
|
||||||
def decorated(update):
|
def decorated(update):
|
||||||
if check_function(update, chat_id):
|
if check_function(update):
|
||||||
return view_func(update)
|
return view_func(update)
|
||||||
return decorated
|
return decorated
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
async def sleep_until(when):
|
async def sleep_until(when: Union[datetime.datetime, datetime.timedelta]):
|
||||||
"""Sleep until now > `when`.
|
"""Sleep until now > `when`.
|
||||||
|
|
||||||
`when` could be a datetime.datetime or a datetime.timedelta instance.
|
`when` could be a datetime.datetime or a datetime.timedelta instance.
|
||||||
@ -587,6 +595,8 @@ async def sleep_until(when):
|
|||||||
delta = when - datetime.datetime.now()
|
delta = when - datetime.datetime.now()
|
||||||
elif isinstance(when, datetime.timedelta):
|
elif isinstance(when, datetime.timedelta):
|
||||||
delta = when
|
delta = when
|
||||||
|
else:
|
||||||
|
delta = datetime.timedelta(seconds=1)
|
||||||
if delta.days >= 0:
|
if delta.days >= 0:
|
||||||
await asyncio.sleep(
|
await asyncio.sleep(
|
||||||
delta.seconds
|
delta.seconds
|
||||||
@ -672,30 +682,40 @@ ARTICOLI[4] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Gettable():
|
class Gettable:
|
||||||
"""Gettable objects can be retrieved from memory without being duplicated.
|
"""Gettable objects can be retrieved from memory without being duplicated.
|
||||||
|
|
||||||
Key is the primary key.
|
Key is the primary key.
|
||||||
Use classmethod get to instantiate (or retrieve) Gettable objects.
|
Use class method get to instantiate (or retrieve) Gettable objects.
|
||||||
Assign SubClass.instances = {}, otherwise Gettable.instances will
|
Assign SubClass.instances = {}, otherwise Gettable.instances will
|
||||||
contain SubClass objects.
|
contain SubClass objects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
instances = {}
|
instances = {}
|
||||||
|
|
||||||
|
def __init__(self, *args, key=None, **kwargs):
|
||||||
|
if key is None:
|
||||||
|
key = args[0]
|
||||||
|
if key not in self.__class__.instances:
|
||||||
|
self.__class__.instances[key] = self
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get(cls, key, *args, **kwargs):
|
def get(cls, *args, key=None, **kwargs):
|
||||||
"""Instantiate and/or retrieve Gettable object.
|
"""Instantiate and/or retrieve Gettable object.
|
||||||
|
|
||||||
SubClass.instances is searched if exists.
|
SubClass.instances is searched if exists.
|
||||||
Gettable.instances is searched otherwise.
|
Gettable.instances is searched otherwise.
|
||||||
"""
|
"""
|
||||||
|
if key is None:
|
||||||
|
key = args[0]
|
||||||
|
else:
|
||||||
|
kwargs['key'] = key
|
||||||
if key not in cls.instances:
|
if key not in cls.instances:
|
||||||
cls.instances[key] = cls(key, *args, **kwargs)
|
cls.instances[key] = cls(*args, **kwargs)
|
||||||
return cls.instances[key]
|
return cls.instances[key]
|
||||||
|
|
||||||
|
|
||||||
class Confirmable():
|
class Confirmable:
|
||||||
"""Confirmable objects are provided with a confirm instance method.
|
"""Confirmable objects are provided with a confirm instance method.
|
||||||
|
|
||||||
It evaluates True if it was called within self._confirm_timedelta,
|
It evaluates True if it was called within self._confirm_timedelta,
|
||||||
@ -715,6 +735,7 @@ class Confirmable():
|
|||||||
confirm_timedelta = self.__class__.CONFIRM_TIMEDELTA
|
confirm_timedelta = self.__class__.CONFIRM_TIMEDELTA
|
||||||
elif type(confirm_timedelta) is int:
|
elif type(confirm_timedelta) is int:
|
||||||
confirm_timedelta = datetime.timedelta(seconds=confirm_timedelta)
|
confirm_timedelta = datetime.timedelta(seconds=confirm_timedelta)
|
||||||
|
self._confirm_timedelta = None
|
||||||
self.set_confirm_timedelta(confirm_timedelta)
|
self.set_confirm_timedelta(confirm_timedelta)
|
||||||
self._confirm_datetimes = {}
|
self._confirm_datetimes = {}
|
||||||
|
|
||||||
@ -756,18 +777,18 @@ class Confirmable():
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
class HasBot():
|
class HasBot:
|
||||||
"""Objects having a Bot subclass object as `.bot` attribute.
|
"""Objects having a Bot subclass object as `.bot` attribute.
|
||||||
|
|
||||||
HasBot objects have a .bot and .db properties for faster access.
|
HasBot objects have a .bot and .db properties for faster access.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
bot = None
|
_bot = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def bot(self):
|
def bot(self):
|
||||||
"""Class bot."""
|
"""Class bot."""
|
||||||
return self.__class__.bot
|
return self.__class__._bot
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def db(self):
|
def db(self):
|
||||||
@ -777,11 +798,11 @@ class HasBot():
|
|||||||
@classmethod
|
@classmethod
|
||||||
def set_bot(cls, bot):
|
def set_bot(cls, bot):
|
||||||
"""Change class bot."""
|
"""Change class bot."""
|
||||||
cls.bot = bot
|
cls._bot = bot
|
||||||
|
|
||||||
|
|
||||||
class CachedPage(Gettable):
|
class CachedPage(Gettable):
|
||||||
"""Cache a webpage and return it during CACHE_TIME, otherwise refresh.
|
"""Cache a web page and return it during CACHE_TIME, otherwise refresh.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
cached_page = CachedPage.get(
|
cached_page = CachedPage.get(
|
||||||
@ -815,6 +836,7 @@ class CachedPage(Gettable):
|
|||||||
self._page = None
|
self._page = None
|
||||||
self._last_update = datetime.datetime.now() - self.cache_time
|
self._last_update = datetime.datetime.now() - self.cache_time
|
||||||
self._async_get_kwargs = async_get_kwargs
|
self._async_get_kwargs = async_get_kwargs
|
||||||
|
super().__init__(key=url)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def url(self):
|
def url(self):
|
||||||
@ -847,7 +869,7 @@ class CachedPage(Gettable):
|
|||||||
return datetime.datetime.now() > self.last_update + self.cache_time
|
return datetime.datetime.now() > self.last_update + self.cache_time
|
||||||
|
|
||||||
async def refresh(self):
|
async def refresh(self):
|
||||||
"""Update cached webpage."""
|
"""Update cached web page."""
|
||||||
try:
|
try:
|
||||||
self._page = await async_get(self.url, **self.async_get_kwargs)
|
self._page = await async_get(self.url, **self.async_get_kwargs)
|
||||||
self._last_update = datetime.datetime.now()
|
self._last_update = datetime.datetime.now()
|
||||||
@ -861,10 +883,9 @@ class CachedPage(Gettable):
|
|||||||
exc_info=False
|
exc_info=False
|
||||||
) # Set exc_info=True to debug
|
) # Set exc_info=True to debug
|
||||||
return 1
|
return 1
|
||||||
return 1
|
|
||||||
|
|
||||||
async def get_page(self):
|
async def get_page(self):
|
||||||
"""Refresh if necessary and return webpage."""
|
"""Refresh if necessary and return web page."""
|
||||||
if self.is_old:
|
if self.is_old:
|
||||||
await self.refresh()
|
await self.refresh()
|
||||||
return self.page
|
return self.page
|
||||||
@ -878,14 +899,17 @@ class Confirmator(Gettable, Confirmable):
|
|||||||
def __init__(self, key, *args, confirm_timedelta=None):
|
def __init__(self, key, *args, confirm_timedelta=None):
|
||||||
"""Call Confirmable.__init__ passing `confirm_timedelta`."""
|
"""Call Confirmable.__init__ passing `confirm_timedelta`."""
|
||||||
Confirmable.__init__(self, confirm_timedelta)
|
Confirmable.__init__(self, confirm_timedelta)
|
||||||
|
Gettable.__init__(self, key=key, *args)
|
||||||
|
|
||||||
|
|
||||||
def get_cleaned_text(update, bot=None, replace=[], strip='/ @'):
|
def get_cleaned_text(update, bot=None, replace=None, strip='/ @'):
|
||||||
"""Clean `update`['text'] and return it.
|
"""Clean `update`['text'] and return it.
|
||||||
|
|
||||||
Strip `bot`.name and items to be `replace`d from the beginning of text.
|
Strip `bot`.name and items to be `replace`d from the beginning of text.
|
||||||
Strip `strip` characters from both ends.
|
Strip `strip` characters from both ends.
|
||||||
"""
|
"""
|
||||||
|
if replace is None:
|
||||||
|
replace = []
|
||||||
if bot is not None:
|
if bot is not None:
|
||||||
replace.append(
|
replace.append(
|
||||||
'@{.name}'.format(
|
'@{.name}'.format(
|
||||||
@ -1120,9 +1144,6 @@ WEEKDAY_NAMES_ENG = ["Monday", "Tuesday", "Wednesday", "Thursday",
|
|||||||
|
|
||||||
|
|
||||||
def _period_parser(text, result):
|
def _period_parser(text, result):
|
||||||
succeeded = False
|
|
||||||
if text in ('every', 'ogni',):
|
|
||||||
succeeded = True
|
|
||||||
if text.title() in WEEKDAY_NAMES_ITA + WEEKDAY_NAMES_ENG:
|
if text.title() in WEEKDAY_NAMES_ITA + WEEKDAY_NAMES_ENG:
|
||||||
day_code = (WEEKDAY_NAMES_ITA + WEEKDAY_NAMES_ENG).index(text.title())
|
day_code = (WEEKDAY_NAMES_ITA + WEEKDAY_NAMES_ENG).index(text.title())
|
||||||
if day_code > 6:
|
if day_code > 6:
|
||||||
@ -1196,7 +1217,8 @@ def parse_datetime_interval_string(text):
|
|||||||
parsers = []
|
parsers = []
|
||||||
result_text, result_datetime, result_timedelta = [], None, None
|
result_text, result_datetime, result_timedelta = [], None, None
|
||||||
is_quoted_text = False
|
is_quoted_text = False
|
||||||
text = re.sub('\s\s+', ' ', text) # Replace multiple spaces with single space character
|
# Replace multiple spaces with single space character
|
||||||
|
text = re.sub(r'\s\s+', ' ', text)
|
||||||
for word in text.split(' '):
|
for word in text.split(' '):
|
||||||
if word.count('"') % 2:
|
if word.count('"') % 2:
|
||||||
is_quoted_text = not is_quoted_text
|
is_quoted_text = not is_quoted_text
|
||||||
@ -1247,7 +1269,7 @@ def parse_datetime_interval_string(text):
|
|||||||
recurring_event = True
|
recurring_event = True
|
||||||
type_ = parser['type_']
|
type_ = parser['type_']
|
||||||
for result in parser['result']:
|
for result in parser['result']:
|
||||||
if not result['ok']:
|
if not isinstance(result, dict) or not result['ok']:
|
||||||
continue
|
continue
|
||||||
if recurring_event and 'weekly' in result and result['weekly']:
|
if recurring_event and 'weekly' in result and result['weekly']:
|
||||||
weekly = True
|
weekly = True
|
||||||
@ -1363,11 +1385,11 @@ def beautydt(dt):
|
|||||||
now = datetime.datetime.now()
|
now = datetime.datetime.now()
|
||||||
gap = dt - now
|
gap = dt - now
|
||||||
gap_days = (dt.date() - now.date()).days
|
gap_days = (dt.date() - now.date()).days
|
||||||
result = "{dt:alle %H:%M}".format(
|
result = "alle {dt:%H:%M}".format(
|
||||||
dt=dt
|
dt=dt
|
||||||
)
|
)
|
||||||
if abs(gap) < datetime.timedelta(minutes=30):
|
if abs(gap) < datetime.timedelta(minutes=30):
|
||||||
result += "{dt::%S}".format(dt=dt)
|
result += ":{dt:%S}".format(dt=dt)
|
||||||
if -2 <= gap_days <= 2:
|
if -2 <= gap_days <= 2:
|
||||||
result += " di {dg}".format(
|
result += " di {dg}".format(
|
||||||
dg=DAY_GAPS[gap_days]
|
dg=DAY_GAPS[gap_days]
|
||||||
@ -1493,16 +1515,16 @@ def get_line_by_content(text, key):
|
|||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def str_to_int(string):
|
def str_to_int(string_):
|
||||||
"""Cast str to int, ignoring non-numeric characters."""
|
"""Cast str to int, ignoring non-numeric characters."""
|
||||||
string = ''.join(
|
string_ = ''.join(
|
||||||
char
|
char
|
||||||
for char in string
|
for char in string_
|
||||||
if char.isnumeric()
|
if char.isnumeric()
|
||||||
)
|
)
|
||||||
if len(string) == 0:
|
if len(string_) == 0:
|
||||||
string = '0'
|
string_ = '0'
|
||||||
return int(string)
|
return int(string_)
|
||||||
|
|
||||||
|
|
||||||
def starting_with_or_similar_to(a, b):
|
def starting_with_or_similar_to(a, b):
|
||||||
@ -1581,18 +1603,21 @@ def make_inline_query_answer(answer):
|
|||||||
return answer
|
return answer
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyUnusedLocal
|
||||||
async def dummy_coroutine(*args, **kwargs):
|
async def dummy_coroutine(*args, **kwargs):
|
||||||
"""Accept everthing as argument and do nothing."""
|
"""Accept everything as argument and do nothing."""
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
async def send_csv_file(bot, chat_id, query, caption=None,
|
async def send_csv_file(bot, chat_id, query, caption=None,
|
||||||
file_name='File.csv', user_record=None, update=dict()):
|
file_name='File.csv', user_record=None, update=None):
|
||||||
"""Run a query on `bot` database and send result as CSV file to `chat_id`.
|
"""Run a query on `bot` database and send result as CSV file to `chat_id`.
|
||||||
|
|
||||||
Optional parameters `caption` and `file_name` may be passed to this
|
Optional parameters `caption` and `file_name` may be passed to this
|
||||||
function.
|
function.
|
||||||
"""
|
"""
|
||||||
|
if update is None:
|
||||||
|
update = dict()
|
||||||
try:
|
try:
|
||||||
with bot.db as db:
|
with bot.db as db:
|
||||||
record = db.query(
|
record = db.query(
|
||||||
@ -1627,7 +1652,7 @@ async def send_csv_file(bot, chat_id, query, caption=None,
|
|||||||
|
|
||||||
async def send_part_of_text_file(bot, chat_id, file_path, caption=None,
|
async def send_part_of_text_file(bot, chat_id, file_path, caption=None,
|
||||||
file_name='File.txt', user_record=None,
|
file_name='File.txt', user_record=None,
|
||||||
update=dict(),
|
update=None,
|
||||||
reversed_=True,
|
reversed_=True,
|
||||||
limit=None):
|
limit=None):
|
||||||
"""Send `lines` lines of text file via `bot` in `chat_id`.
|
"""Send `lines` lines of text file via `bot` in `chat_id`.
|
||||||
@ -1637,10 +1662,12 @@ async def send_part_of_text_file(bot, chat_id, file_path, caption=None,
|
|||||||
way to allow `reversed` files, but it is inefficient and requires a lot
|
way to allow `reversed` files, but it is inefficient and requires a lot
|
||||||
of memory.
|
of memory.
|
||||||
"""
|
"""
|
||||||
|
if update is None:
|
||||||
|
update = dict()
|
||||||
try:
|
try:
|
||||||
with open(file_path, 'r') as log_file:
|
with open(file_path, 'r') as log_file:
|
||||||
lines = log_file.readlines()
|
lines = log_file.readlines()
|
||||||
if reversed:
|
if reversed_:
|
||||||
lines = lines[::-1]
|
lines = lines[::-1]
|
||||||
if limit:
|
if limit:
|
||||||
lines = lines[:limit]
|
lines = lines[:limit]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user