IDE-guided adjustments

This commit is contained in:
Davte 2020-04-06 22:20:17 +02:00
parent 76b7e50e52
commit 06d3569fbd
4 changed files with 38 additions and 29 deletions

View File

@ -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"

View File

@ -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(

View File

@ -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',
@ -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

View File

@ -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