Merge remote-tracking branch 'upstream/dev-1.x' into dev-1.x

# Conflicts:
#	aiogram/types/user.py - update hashing in user type
This commit is contained in:
Suren Khorenyan 2018-03-15 20:46:34 +03:00
commit 19f67a2e99
24 changed files with 245 additions and 89 deletions

View file

@ -2,6 +2,7 @@ from . import base
from . import fields
from .animation import Animation
from .audio import Audio
from .auth_widget_data import AuthWidgetData
from .callback_game import CallbackGame
from .callback_query import CallbackQuery
from .chat import Chat, ChatActions, ChatType
@ -56,6 +57,7 @@ __all__ = (
'AllowedUpdates',
'Animation',
'Audio',
'AuthWidgetData',
'CallbackGame',
'CallbackQuery',
'Chat',

View file

@ -15,11 +15,3 @@ class Audio(base.TelegramObject, mixins.Downloadable):
title: base.String = fields.Field()
mime_type: base.String = fields.Field()
file_size: base.Integer = fields.Field()
def __hash__(self):
return hash(self.file_id) + \
self.duration + \
hash(self.performer) + \
hash(self.title) + \
hash(self.mime_type) + \
self.file_size

View file

@ -0,0 +1,47 @@
from aiohttp import web
from . import base
from . import fields
class AuthWidgetData(base.TelegramObject):
id: base.Integer = fields.Field()
first_name: base.String = fields.Field()
last_name: base.String = fields.Field()
username: base.String = fields.Field()
photo_url: base.String = fields.Field()
auth_date: base.String = fields.DateTimeField()
hash: base.String = fields.Field()
@classmethod
def parse(cls, request: web.Request) -> 'AuthWidgetData':
"""
Parse request as Telegram auth widget data.
:param request:
:return: :obj:`AuthWidgetData`
:raise :obj:`aiohttp.web.HTTPBadRequest`
"""
try:
query = dict(request.query)
query['id'] = int(query['id'])
query['auth_date'] = int(query['auth_date'])
widget = AuthWidgetData(**query)
except (ValueError, KeyError):
raise web.HTTPBadRequest(text='Invalid auth data')
else:
return widget
def validate(self):
return self.bot.check_auth_widget(self.to_python())
@property
def full_name(self):
result = self.first_name
if self.last_name:
result += ' '
result += self.last_name
return result
def __hash__(self):
return self.id

View file

@ -244,3 +244,28 @@ class TelegramObject(metaclass=MetaTelegramObject):
"""
for _, value in self:
yield value
def __hash__(self):
def _hash(obj):
buf = 0
if isinstance(obj, list):
for item in obj:
buf += _hash(item)
elif isinstance(obj, dict):
for dict_key, dict_value in obj.items():
buf += hash(dict_key) + _hash(dict_value)
else:
try:
buf += hash(obj)
except TypeError: # Skip unhashable objects
pass
return buf
result = 0
for key, value in sorted(self.values.items()):
result += hash(key) + _hash(value)
return result
def __eq__(self, other):
return isinstance(other, self.__class__) and hash(other) == hash(self)

View file

@ -56,3 +56,6 @@ class CallbackQuery(base.TelegramObject):
:rtype: :obj:`base.Boolean`"""
await self.bot.answer_callback_query(callback_query_id=self.id, text=text,
show_alert=show_alert, url=url, cache_time=cache_time)
def __hash__(self):
return hash(self.id)

View file

@ -28,6 +28,9 @@ class Chat(base.TelegramObject):
sticker_set_name: base.String = fields.Field()
can_set_sticker_set: base.Boolean = fields.Field()
def __hash__(self):
return self.id
@property
def full_name(self):
if self.type == ChatType.PRIVATE:

View file

@ -73,3 +73,6 @@ class ChatPhoto(base.TelegramObject):
async def get_big_file(self):
return await self.bot.get_file(self.big_file_id)
def __hash__(self):
return hash(self.small_file_id) + hash(self.big_file_id)

View file

@ -19,3 +19,6 @@ class Contact(base.TelegramObject):
if self.last_name is not None:
name += ' ' + self.last_name
return name
def __hash__(self):
return hash(self.phone_number)

View file

@ -181,7 +181,7 @@ class Message(base.TelegramObject):
return text
async def reply(self, text, parse_mode=None, disable_web_page_preview=None,
disable_notification=None, reply_markup=None, reply=False) -> 'Message':
disable_notification=None, reply_markup=None, reply=True) -> 'Message':
"""
Reply to this message
@ -630,6 +630,30 @@ class Message(base.TelegramObject):
"""
return await self.bot.delete_message(self.chat.id, self.message_id)
async def reply_sticker(self, sticker: typing.Union[base.InputFile, base.String],
disable_notification: typing.Union[base.Boolean, None] = None,
reply_markup=None, reply=True) -> 'Message':
"""
Use this method to send .webp stickers.
Source: https://core.telegram.org/bots/api#sendsticker
:param sticker: Sticker to send.
:type sticker: :obj:`typing.Union[base.InputFile, base.String]`
:param disable_notification: Sends the message silently. Users will receive a notification with no sound.
:type disable_notification: :obj:`typing.Union[base.Boolean, None]`
:param reply_markup: Additional interface options.
:type reply_markup: :obj:`typing.Union[types.InlineKeyboardMarkup,
types.ReplyKeyboardMarkup, types.ReplyKeyboardRemove, types.ForceReply, None]`
:param reply: fill 'reply_to_message_id'
:return: On success, the sent Message is returned.
:rtype: :obj:`types.Message`
"""
return await self.bot.send_sticker(chat_id=self.chat.id, sticker=sticker,
disable_notification=disable_notification,
reply_to_message_id=self.message_id if reply else None,
reply_markup=reply_markup)
async def pin(self, disable_notification: bool = False):
"""
Pin message

View file

@ -18,8 +18,8 @@ class MessageEntity(base.TelegramObject):
def _apply(self, text, func):
return text[:self.offset] + \
func(text[self.offset:self.offset + self.length]) + \
text[self.offset + self.length:]
func(text[self.offset:self.offset + self.length]) + \
text[self.offset + self.length:]
def apply_md(self, text):
"""

View file

@ -44,3 +44,6 @@ class Downloadable:
return self
else:
return await self.bot.get_file(self.file_id)
def __hash__(self):
return hash(self.file_id)

View file

@ -1,10 +1,11 @@
from . import base
from . import fields
from . import mixins
from .mask_position import MaskPosition
from .photo_size import PhotoSize
class Sticker(base.TelegramObject):
class Sticker(base.TelegramObject, mixins.Downloadable):
"""
This object represents a sticker.
@ -18,11 +19,3 @@ class Sticker(base.TelegramObject):
set_name: base.String = fields.Field()
mask_position: MaskPosition = fields.Field(base=MaskPosition)
file_size: base.Integer = fields.Field()
def __hash__(self):
return self.file_id
def __eq__(self, other):
if isinstance(other, type(self)):
return other.file_id == self.file_id
return self.file_id == other

View file

@ -79,10 +79,7 @@ class User(base.TelegramObject):
return await self.bot.get_user_profile_photos(self.id, offset, limit)
def __hash__(self):
return self.id + \
hash(self.is_bot) + \
hash(self.full_name) + \
(hash(self.username) if self.username else 0)
return self.id
def __int__(self):
return self.id

View file

@ -1,9 +1,10 @@
from . import base
from . import fields
from . import mixins
from .photo_size import PhotoSize
class Video(base.TelegramObject):
class Video(base.TelegramObject, mixins.Downloadable):
"""
This object represents a video file.
@ -16,11 +17,3 @@ class Video(base.TelegramObject):
thumb: PhotoSize = fields.Field(base=PhotoSize)
mime_type: base.String = fields.Field()
file_size: base.Integer = fields.Field()
def __hash__(self):
return self.file_id
def __eq__(self, other):
if isinstance(other, type(self)):
return other.file_id == self.file_id
return self.file_id == other

View file

@ -1,9 +1,10 @@
from . import base
from . import fields
from . import mixins
from .photo_size import PhotoSize
class VideoNote(base.TelegramObject):
class VideoNote(base.TelegramObject, mixins.Downloadable):
"""
This object represents a video message (available in Telegram apps as of v.4.0).
@ -14,11 +15,3 @@ class VideoNote(base.TelegramObject):
duration: base.Integer = fields.Field()
thumb: PhotoSize = fields.Field(base=PhotoSize)
file_size: base.Integer = fields.Field()
def __hash__(self):
return self.file_id
def __eq__(self, other):
if isinstance(other, type(self)):
return other.file_id == self.file_id
return self.file_id == other

View file

@ -1,8 +1,9 @@
from . import base
from . import fields
from . import mixins
class Voice(base.TelegramObject):
class Voice(base.TelegramObject, mixins.Downloadable):
"""
This object represents a voice note.
@ -12,11 +13,3 @@ class Voice(base.TelegramObject):
duration: base.Integer = fields.Field()
mime_type: base.String = fields.Field()
file_size: base.Integer = fields.Field()
def __hash__(self):
return self.file_id
def __eq__(self, other):
if isinstance(other, type(self)):
return other.file_id == self.file_id
return self.file_id == other