Improving the design of existing Telegram classes and adding docstrings

This commit is contained in:
Leandro Toledo 2015-08-28 12:19:30 -03:00
parent ce58f72566
commit b20f5af1e1
7 changed files with 242 additions and 61 deletions

View file

@ -16,6 +16,7 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""A library that provides a Python interface to the Telegram Bot API"""
__author__ = 'leandrotoledodesouza@gmail.com'
__version__ = '2.7.1'

View file

@ -16,13 +16,14 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Base class for Telegram Objects"""
import json
from abc import ABCMeta, abstractmethod
class TelegramObject(object):
"""Base class for most telegram object"""
"""Base class for most telegram objects"""
__metaclass__ = ABCMeta
@ -34,11 +35,26 @@ class TelegramObject(object):
@staticmethod
def de_json(data):
"""
Args:
data (str):
Returns:
telegram.TelegramObject:
"""
raise NotImplementedError
def to_json(self):
"""
Returns:
str:
"""
return json.dumps(self.to_dict())
@abstractmethod
def to_dict(self):
"""
Returns:
dict:
"""
return None

View file

@ -1,4 +1,5 @@
#!/usr/bin/env python
# pylint: disable=E0611,E0213,E1102,C0103,E1101,W0613,R0913,R0904
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2015 Leandro Toledo de Souza <leandrotoeldodesouza@gmail.com>
@ -16,6 +17,7 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram Bot"""
import json
try:
@ -32,11 +34,27 @@ import logging
from telegram import (User, Message, Update, UserProfilePhotos, TelegramError,
ReplyMarkup, InputFile, TelegramObject, NullHandler)
h = NullHandler()
logging.getLogger(__name__).addHandler(h)
H = NullHandler()
logging.getLogger(__name__).addHandler(H)
class Bot(TelegramObject):
"""This object represents a Telegram Bot.
Attributes:
id (int):
first_name (str):
last_name (str):
username (str):
name (str):
Args:
token (str):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
base_url (Optional[str]):
"""
def __init__(self,
token,
@ -50,11 +68,17 @@ class Bot(TelegramObject):
self.bot = None
self.log = logging.getLogger(__name__)
self.logger = logging.getLogger(__name__)
def info(func):
"""
bla
"""
@functools.wraps(func)
def decorator(self, *args, **kwargs):
"""
bla
"""
if not self.bot:
self.getMe()
@ -65,36 +89,48 @@ class Bot(TelegramObject):
@property
@info
def id(self):
"""int: """
return self.bot.id
@property
@info
def first_name(self):
"""str: """
return self.bot.first_name
@property
@info
def last_name(self):
"""str: """
return self.bot.last_name
@property
@info
def username(self):
"""str: """
return self.bot.username
@property
def name(self):
"""str: """
return '@%s' % self.username
def log(func):
"""
Returns:
A telegram.Message instance representing the message posted.
"""
logger = logging.getLogger(func.__module__)
@functools.wraps(func)
def decorator(self, *args, **kwargs):
logger.debug('Entering: %s' % func.__name__)
"""
decorator
"""
logger.debug('Entering: %s', func.__name__)
result = func(self, *args, **kwargs)
logger.debug(result)
logger.debug('Exiting: %s' % func.__name__)
logger.debug('Exiting: %s', func.__name__)
return result
return decorator
@ -105,6 +141,9 @@ class Bot(TelegramObject):
"""
@functools.wraps(func)
def decorator(self, *args, **kwargs):
"""
decorator
"""
url, data = func(self, *args, **kwargs)
if kwargs.get('reply_to_message_id'):
@ -118,8 +157,8 @@ class Bot(TelegramObject):
else:
data['reply_markup'] = reply_markup
json_data = self._requestUrl(url, 'POST', data=data)
data = self._parseAndCheckTelegram(json_data)
json_data = Bot._requestUrl(url, 'POST', data=data)
data = Bot._parseAndCheckTelegram(json_data)
if data is True:
return data
@ -150,8 +189,7 @@ class Bot(TelegramObject):
chat_id,
text,
disable_web_page_preview=None,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send text messages.
Args:
@ -222,8 +260,7 @@ class Bot(TelegramObject):
chat_id,
photo,
caption=None,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send photos.
Args:
@ -265,8 +302,7 @@ class Bot(TelegramObject):
duration=None,
performer=None,
title=None,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send audio files, if you want Telegram clients to
display them in the music player. Your audio must be in an .mp3 format.
On success, the sent Message is returned. Bots can currently send audio
@ -321,8 +357,7 @@ class Bot(TelegramObject):
def sendDocument(self,
chat_id,
document,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send general files.
Args:
@ -355,8 +390,7 @@ class Bot(TelegramObject):
def sendSticker(self,
chat_id,
sticker,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send .webp stickers.
Args:
@ -391,8 +425,7 @@ class Bot(TelegramObject):
video,
duration=None,
caption=None,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send video files, Telegram clients support mp4
videos (other formats may be sent as telegram.Document).
@ -437,8 +470,7 @@ class Bot(TelegramObject):
chat_id,
voice,
duration=None,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send audio files, if you want Telegram clients to
display the file as a playable voice message. For this to work, your
audio must be in an .ogg file encoded with OPUS (other formats may be
@ -482,8 +514,7 @@ class Bot(TelegramObject):
chat_id,
latitude,
longitude,
reply_to_message_id=None,
reply_markup=None):
**kwargs):
"""Use this method to send point on the map.
Args:
@ -617,10 +648,10 @@ class Bot(TelegramObject):
data = self._parseAndCheckTelegram(json_data)
if data:
self.log.info(
'Getting updates: %s' % [u['update_id'] for u in data])
self.logger.info(
'Getting updates: %s', [u['update_id'] for u in data])
else:
self.log.info('No new updates found.')
self.logger.info('No new updates found.')
return [Update.de_json(x) for x in data]
@ -650,8 +681,8 @@ class Bot(TelegramObject):
return True
def _requestUrl(self,
url,
@staticmethod
def _requestUrl(url,
method,
data=None):
"""Request an URL.
@ -688,12 +719,12 @@ class Bot(TelegramObject):
url,
urlencode(data).encode()
).read()
except IOError as e:
raise TelegramError(str(e))
except HTTPError as e:
raise TelegramError(str(e))
except URLError as e:
raise TelegramError(str(e))
except IOError as e:
raise TelegramError(str(e))
if method == 'GET':
try:
@ -701,8 +732,8 @@ class Bot(TelegramObject):
except URLError as e:
raise TelegramError(str(e))
def _parseAndCheckTelegram(self,
json_data):
@staticmethod
def _parseAndCheckTelegram(json_data):
"""Try and parse the JSON returned from Telegram and return an empty
dictionary if there is any error.
@ -725,7 +756,15 @@ class Bot(TelegramObject):
return data['result']
@staticmethod
def de_json(data):
pass
def to_dict(self):
"""
Returns:
dict:
"""
data = {'id': self.id,
'username': self.username,
'first_name': self.username}

View file

@ -16,24 +16,63 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram ForceReply"""
from telegram import ReplyMarkup
class ForceReply(ReplyMarkup):
"""This object represents a Telegram ForceReply.
Attributes:
force_reply (bool):
selective (bool):
Args:
force_reply (bool):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
selective (Optional[bool]):
"""
def __init__(self,
force_reply=True,
selective=None):
self.force_reply = force_reply
self.selective = selective
**kwargs):
# Required
self.force_reply = bool(force_reply)
# Optionals
self.selective = bool(kwargs.get('selective', False))
@staticmethod
def de_json(data):
return ForceReply(force_reply=data.get('force_reply', None),
selective=data.get('selective', None))
"""
Args:
data (str):
Returns:
telegram.ForceReply:
"""
force_reply = dict()
# Required
force_reply['force_reply'] = data['force_reply']
# Optionals
force_reply['selective'] = data.get('selective', False)
return ForceReply(**force_reply)
def to_dict(self):
data = {'force_reply': self.force_reply}
"""
Returns:
dict:
"""
data = dict()
# Required
data['force_reply'] = self.force_reply
# Optionals
if self.selective:
data['selective'] = self.selective
return data

View file

@ -16,24 +16,64 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram
ReplyKeyboardHide"""
from telegram import ReplyMarkup
class ReplyKeyboardHide(ReplyMarkup):
"""This object represents a Telegram ReplyKeyboardHide.
Attributes:
hide_keyboard (bool):
selective (bool):
Args:
hide_keyboard (bool):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
selective (Optional[bool]):
"""
def __init__(self,
hide_keyboard=True,
selective=None):
self.hide_keyboard = hide_keyboard
self.selective = selective
**kwargs):
# Required
self.hide_keyboard = bool(hide_keyboard)
# Optionals
self.selective = bool(kwargs.get('selective', False))
@staticmethod
def de_json(data):
return ReplyKeyboardHide(hide_keyboard=data.get('hide_keyboard', None),
selective=data.get('selective', None))
"""
Args:
data (str):
Returns:
telegram.ReplyKeyboardHide:
"""
rkh = dict()
# Required
rkh['hide_keyboard'] = data['hide_keyboard']
# Optionals
rkh['selective'] = data.get('selective', False)
return ReplyKeyboardHide(**rkh)
def to_dict(self):
data = {'hide_keyboard': self.hide_keyboard}
"""
Returns:
dict:
"""
data = dict()
# Required
data['hide_keyboard'] = self.hide_keyboard
# Optionals
if self.selective:
data['selective'] = self.selective
return data

View file

@ -16,38 +16,76 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""This module contains a object that represents a Telegram
ReplyKeyboardMarkup"""
from telegram import ReplyMarkup
class ReplyKeyboardMarkup(ReplyMarkup):
"""This object represents a Telegram ReplyKeyboardMarkup.
Attributes:
keyboard (List[List[str]]):
resize_keyboard (bool):
one_time_keyboard (bool):
selective (bool):
Args:
keyboard (List[List[str]]):
**kwargs: Arbitrary keyword arguments.
Keyword Args:
resize_keyboard (Optional[bool]):
one_time_keyboard (Optional[bool]):
selective (Optional[bool]):
"""
def __init__(self,
keyboard,
resize_keyboard=None,
one_time_keyboard=None,
selective=None):
**kwargs):
# Required
self.keyboard = keyboard
self.resize_keyboard = resize_keyboard
self.one_time_keyboard = one_time_keyboard
self.selective = selective
# Optionals
self.resize_keyboard = bool(kwargs.get('resize_keyboard', False))
self.one_time_keyboard = bool(kwargs.get('one_time_keyboard', False))
self.selective = bool(kwargs.get('selective', False))
@staticmethod
def de_json(data):
return ReplyKeyboardMarkup(keyboard=data.get('keyboard', None),
resize_keyboard=data.get(
'resize_keyboard', None
),
one_time_keyboard=data.get(
'one_time_keyboard', None
),
selective=data.get('selective', None))
"""
Args:
data (str):
Returns:
telegram.ReplyKeyboardMarkup:
"""
rkm = dict()
# Required
rkm['keyboard'] = data['keyboard']
# Optionals
rkm['resize_keyboard'] = data.get('resize_keyboard', False)
rkm['one_time_keyboard'] = data.get('one_time_keyboard', False)
rkm['selective'] = data.get('selective', False)
return ReplyKeyboardMarkup(**rkm)
def to_dict(self):
data = {'keyboard': self.keyboard}
"""
Returns:
dict:
"""
data = dict()
# Required
data['keyboard'] = self.keyboard
# Optionals
if self.resize_keyboard:
data['resize_keyboard'] = self.resize_keyboard
if self.one_time_keyboard:
data['one_time_keyboard'] = self.one_time_keyboard
if self.selective:
data['selective'] = self.selective
return data

View file

@ -16,9 +16,17 @@
# You should have received a copy of the GNU Lesser Public License
# along with this program. If not, see [http://www.gnu.org/licenses/].
"""Base class for Telegram ReplyMarkup Objects"""
from telegram import TelegramObject
class ReplyMarkup(TelegramObject):
pass
"""Base class for Telegram ReplyMarkup Objects"""
@staticmethod
def de_json(data):
pass
def to_dict(self):
pass