IDE-guided adjustments
This commit is contained in:
parent
76b7e50e52
commit
06d3569fbd
@ -14,7 +14,7 @@ __author__ = "Davide Testa"
|
|||||||
__email__ = "davide@davte.it"
|
__email__ = "davide@davte.it"
|
||||||
__credits__ = ["Marco Origlia", "Nick Lee @Nickoala"]
|
__credits__ = ["Marco Origlia", "Nick Lee @Nickoala"]
|
||||||
__license__ = "GNU General Public License v3.0"
|
__license__ = "GNU General Public License v3.0"
|
||||||
__version__ = "2.4.14"
|
__version__ = "2.4.15"
|
||||||
__maintainer__ = "Davide Testa"
|
__maintainer__ = "Davide Testa"
|
||||||
__contact__ = "t.me/davte"
|
__contact__ = "t.me/davte"
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ from aiohttp import web
|
|||||||
class TelegramError(Exception):
|
class TelegramError(Exception):
|
||||||
"""Telegram API exceptions class."""
|
"""Telegram API exceptions class."""
|
||||||
|
|
||||||
def __init__(self, error_code=0, description=None, ok=False):
|
def __init__(self, error_code=0, description=None):
|
||||||
"""Get an error response and return corresponding Exception."""
|
"""Get an error response and return corresponding Exception."""
|
||||||
self._code = error_code
|
self._code = error_code
|
||||||
if description is None:
|
if description is None:
|
||||||
@ -38,7 +38,9 @@ class TelegramError(Exception):
|
|||||||
return f"Error {self.code}: {self._description}"
|
return f"Error {self.code}: {self._description}"
|
||||||
|
|
||||||
|
|
||||||
class TelegramBot(object):
|
# This class needs to mirror Telegram API, so camelCase method are needed
|
||||||
|
# noinspection PyPep8Naming
|
||||||
|
class TelegramBot:
|
||||||
"""Provide python method having the same signature as Telegram API methods.
|
"""Provide python method having the same signature as Telegram API methods.
|
||||||
|
|
||||||
All mirrored methods are camelCase.
|
All mirrored methods are camelCase.
|
||||||
@ -65,12 +67,13 @@ class TelegramBot(object):
|
|||||||
self._token = token
|
self._token = token
|
||||||
self.sessions = dict()
|
self.sessions = dict()
|
||||||
self._flood_wait = 0
|
self._flood_wait = 0
|
||||||
self.last_sending_time = dict(
|
self.last_sending_time = {
|
||||||
absolute=(
|
'absolute': (
|
||||||
datetime.datetime.now()
|
datetime.datetime.now()
|
||||||
- self.absolute_cooldown_timedelta
|
- self.absolute_cooldown_timedelta
|
||||||
)
|
),
|
||||||
)
|
0: [] # Each `telegram_id` key has a list of `datetime.datetime` as value
|
||||||
|
}
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def token(self):
|
def token(self):
|
||||||
@ -139,14 +142,16 @@ class TelegramBot(object):
|
|||||||
return response['result']
|
return response['result']
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def adapt_parameters(parameters, exclude=[]):
|
def adapt_parameters(parameters, exclude=None):
|
||||||
"""Build a aiohttp.FormData object from given `paramters`.
|
"""Build a aiohttp.FormData object from given `paramters`.
|
||||||
|
|
||||||
Exclude `self`, empty values and parameters in `exclude` list.
|
Exclude `self`, empty values and parameters in `exclude` list.
|
||||||
Cast integers to string to avoid TypeError during json serialization.
|
Cast integers to string to avoid TypeError during json serialization.
|
||||||
"""
|
"""
|
||||||
|
if exclude is None:
|
||||||
|
exclude = []
|
||||||
exclude.append('self')
|
exclude.append('self')
|
||||||
# quote_fields must be set to False, otherwise filenames cause troubles
|
# quote_fields must be set to False, otherwise some file names cause troubles
|
||||||
data = aiohttp.FormData(quote_fields=False)
|
data = aiohttp.FormData(quote_fields=False)
|
||||||
for key, value in parameters.items():
|
for key, value in parameters.items():
|
||||||
if not (key in exclude or value is None):
|
if not (key in exclude or value is None):
|
||||||
@ -260,13 +265,17 @@ class TelegramBot(object):
|
|||||||
self.last_sending_time['absolute'] = now()
|
self.last_sending_time['absolute'] = now()
|
||||||
return
|
return
|
||||||
|
|
||||||
async def api_request(self, method, parameters={}, exclude=[]):
|
async def api_request(self, method, parameters=None, exclude=None):
|
||||||
"""Return the result of a Telegram bot API request, or an Exception.
|
"""Return the result of a Telegram bot API request, or an Exception.
|
||||||
|
|
||||||
Opened sessions will be used more than one time (if appropriate) and
|
Opened sessions will be used more than one time (if appropriate) and
|
||||||
will be closed on `Bot.app.cleanup`.
|
will be closed on `Bot.app.cleanup`.
|
||||||
Result may be a Telegram API json response, None, or Exception.
|
Result may be a Telegram API json response, None, or Exception.
|
||||||
"""
|
"""
|
||||||
|
if exclude is None:
|
||||||
|
exclude = []
|
||||||
|
if parameters is None:
|
||||||
|
parameters = {}
|
||||||
response_object = None
|
response_object = None
|
||||||
session, session_must_be_closed = self.get_session(method)
|
session, session_must_be_closed = self.get_session(method)
|
||||||
# Prevent Telegram flood control for all methodsd having a `chat_id`
|
# Prevent Telegram flood control for all methodsd having a `chat_id`
|
||||||
@ -343,14 +352,6 @@ class TelegramBot(object):
|
|||||||
|
|
||||||
See https://core.telegram.org/bots/api#setwebhook for details.
|
See https://core.telegram.org/bots/api#setwebhook for details.
|
||||||
"""
|
"""
|
||||||
if url is None:
|
|
||||||
url = self.webhook_url
|
|
||||||
if allowed_updates is None:
|
|
||||||
allowed_updates = self.allowed_updates
|
|
||||||
if max_connections is None:
|
|
||||||
max_connections = self.max_connections
|
|
||||||
if certificate is None:
|
|
||||||
certificate = self.certificate
|
|
||||||
if type(certificate) is str:
|
if type(certificate) is str:
|
||||||
try:
|
try:
|
||||||
certificate = dict(
|
certificate = dict(
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Provide a simple Bot object, mirroring Telegram API methods.
|
"""Provide a simple Bot object, mirroring Telegram API methods.
|
||||||
|
|
||||||
camelCase methods mirror API directly, while snake_case ones act as middlewares
|
camelCase methods mirror API directly, while snake_case ones act as middleware
|
||||||
someway.
|
someway.
|
||||||
|
|
||||||
Usage
|
Usage
|
||||||
@ -58,6 +58,8 @@ from .utilities import (
|
|||||||
logging.getLogger('aiohttp').setLevel(logging.WARNING)
|
logging.getLogger('aiohttp').setLevel(logging.WARNING)
|
||||||
|
|
||||||
|
|
||||||
|
# Some methods are not implemented yet: that's the reason behind the following statement
|
||||||
|
# noinspection PyUnusedLocal,PyMethodMayBeStatic,PyMethodMayBeStatic
|
||||||
class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
||||||
"""Simple Bot object, providing methods corresponding to Telegram bot API.
|
"""Simple Bot object, providing methods corresponding to Telegram bot API.
|
||||||
|
|
||||||
@ -579,7 +581,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
break
|
break
|
||||||
if not results:
|
if not results:
|
||||||
results = self.default_inline_query_answer
|
results = self.default_inline_query_answer
|
||||||
if type(results) is dict and 'answer' in results:
|
if isinstance(results, dict) and 'answer' in results:
|
||||||
if 'switch_pm_text' in results:
|
if 'switch_pm_text' in results:
|
||||||
switch_pm_text = results['switch_pm_text']
|
switch_pm_text = results['switch_pm_text']
|
||||||
if 'switch_pm_parameter' in results:
|
if 'switch_pm_parameter' in results:
|
||||||
@ -1010,6 +1012,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
"but this handler does nothing yet."
|
"but this handler does nothing yet."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# noinspection SpellCheckingInspection
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def split_message_text(text, limit=None, parse_mode='HTML'):
|
def split_message_text(text, limit=None, parse_mode='HTML'):
|
||||||
r"""Split text if it hits telegram limits for text messages.
|
r"""Split text if it hits telegram limits for text messages.
|
||||||
@ -1076,7 +1079,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
method = self.send_voice
|
method = self.send_voice
|
||||||
if method is not None:
|
if method is not None:
|
||||||
return await method(update=update, *args, **kwargs)
|
return await method(update=update, *args, **kwargs)
|
||||||
raise Exception("Unsopported keyword arguments for `Bot().reply`.")
|
raise Exception("Unsupported keyword arguments for `Bot().reply`.")
|
||||||
|
|
||||||
async def send_message(self, chat_id=None, text=None,
|
async def send_message(self, chat_id=None, text=None,
|
||||||
parse_mode='HTML',
|
parse_mode='HTML',
|
||||||
@ -1121,7 +1124,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
return
|
return
|
||||||
parse_mode = str(parse_mode)
|
parse_mode = str(parse_mode)
|
||||||
if isinstance(text, dict) and chat_id > 0:
|
if isinstance(text, dict) and chat_id > 0:
|
||||||
if user_record is None :
|
if user_record is None:
|
||||||
user_record = self.db['users'].find_one(telegram_id=chat_id)
|
user_record = self.db['users'].find_one(telegram_id=chat_id)
|
||||||
text = self.get_message(
|
text = self.get_message(
|
||||||
update=update,
|
update=update,
|
||||||
@ -1255,7 +1258,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
Set `disable_notification` to True to avoid disturbing recipient.
|
Set `disable_notification` to True to avoid disturbing recipient.
|
||||||
Pass the `update` to be forwarded or its identifier (`from_chat_id` and
|
Pass the `update` to be forwarded or its identifier (`from_chat_id` and
|
||||||
`message_id`).
|
`message_id`).
|
||||||
@type message_id: int
|
|
||||||
"""
|
"""
|
||||||
if from_chat_id is None or message_id is None:
|
if from_chat_id is None or message_id is None:
|
||||||
message_identifier = self.get_message_identifier(update)
|
message_identifier = self.get_message_identifier(update)
|
||||||
@ -1669,7 +1671,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
set to True, use file_id (it is faster and recommended).
|
set to True, use file_id (it is faster and recommended).
|
||||||
`document_path` may contain `{path}`: it will be replaced by
|
`document_path` may contain `{path}`: it will be replaced by
|
||||||
`self.path`.
|
`self.path`.
|
||||||
`document_name` diplayed to Telegram may differ from actual document
|
`document_name` displayed to Telegram may differ from actual document
|
||||||
name if this parameter is set.
|
name if this parameter is set.
|
||||||
"""
|
"""
|
||||||
already_sent = False
|
already_sent = False
|
||||||
@ -1785,7 +1787,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
return sent_update
|
return sent_update
|
||||||
|
|
||||||
async def download_file(self, file_id,
|
async def download_file(self, file_id,
|
||||||
file_name=None, mime_type=None, path=None):
|
file_name=None, path=None):
|
||||||
"""Given a telegram `file_id`, download the related file.
|
"""Given a telegram `file_id`, download the related file.
|
||||||
|
|
||||||
Telegram may not preserve the original file name and MIME type: the
|
Telegram may not preserve the original file name and MIME type: the
|
||||||
@ -1998,7 +2000,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
|
|
||||||
Decorate command handlers like this:
|
Decorate command handlers like this:
|
||||||
```
|
```
|
||||||
@bot.command('/mycommand', ['Button'], True, "My command", 'user')
|
@bot.command('/my_command', ['Button'], True, "My command", 'user')
|
||||||
async def command_handler(bot, update, user_record):
|
async def command_handler(bot, update, user_record):
|
||||||
return "Result"
|
return "Result"
|
||||||
```
|
```
|
||||||
@ -2573,6 +2575,12 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
return
|
return
|
||||||
if allowed_updates is None:
|
if allowed_updates is None:
|
||||||
allowed_updates = []
|
allowed_updates = []
|
||||||
|
if certificate is None:
|
||||||
|
certificate = self.certificate
|
||||||
|
if max_connections is None:
|
||||||
|
max_connections = self.max_connections
|
||||||
|
if url is None:
|
||||||
|
url = self.webhook_url
|
||||||
webhook_was_set = await self.setWebhook(
|
webhook_was_set = await self.setWebhook(
|
||||||
url=url, certificate=certificate, max_connections=max_connections,
|
url=url, certificate=certificate, max_connections=max_connections,
|
||||||
allowed_updates=allowed_updates
|
allowed_updates=allowed_updates
|
||||||
|
@ -22,7 +22,7 @@ class ObjectWithDatabase(object):
|
|||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, database_url=None):
|
def __init__(self, database_url: str = None):
|
||||||
"""Instantiate object and open connection with database."""
|
"""Instantiate object and open connection with database."""
|
||||||
if database_url is None:
|
if database_url is None:
|
||||||
database_url = 'database.db'
|
database_url = 'database.db'
|
||||||
@ -41,12 +41,12 @@ class ObjectWithDatabase(object):
|
|||||||
logging.error(f"{e}")
|
logging.error(f"{e}")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def db_url(self):
|
def db_url(self) -> str:
|
||||||
"""Return complete path to database."""
|
"""Return complete path to database."""
|
||||||
return self._database_url
|
return self._database_url
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def db(self):
|
def db(self) -> dataset.Database:
|
||||||
"""Return the dataset.Database instance related to `self`."""
|
"""Return the dataset.Database instance related to `self`."""
|
||||||
return self._database
|
return self._database
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user