Added native support for Python's datetime object

Now you can make up your Telegram Requests by using
the built-in `datetime` instead of manually parsing it
This commit is contained in:
Lonami 2016-09-11 10:35:02 +02:00
parent 5b4be5b85e
commit c11795f294
5 changed files with 32 additions and 14 deletions

View File

@ -130,8 +130,8 @@ class TLArg:
self.is_generic = False self.is_generic = False
else: else:
self.flag_indicator = False self.flag_indicator = False
self.type = type.lstrip('!') # Strip the exclamation mark always to have only the name
self.is_generic = type.startswith('!') self.is_generic = type.startswith('!')
self.type = type.lstrip('!') # Strip the exclamation mark always to have only the name
# The type may be a flag (flags.IDX?REAL_TYPE) # The type may be a flag (flags.IDX?REAL_TYPE)
# Note that «flags» is NOT the flags name; this is determined by a previous argument # Note that «flags» is NOT the flags name; this is determined by a previous argument
@ -148,6 +148,12 @@ class TLArg:
self.is_vector = True self.is_vector = True
self.type = vector_match.group(1) # Update the type to match the one inside the vector self.type = vector_match.group(1) # Update the type to match the one inside the vector
# The name may contain "date" in it, if this is the case and the type is "int",
# we can safely assume that this should be treated as a "date" object.
# Note that this is not a valid Telegram object, but it's easier to work with
if re.search(r'(\b|_)date\b', name) and self.type == 'int':
self.type = 'date'
self.generic_definition = generic_definition self.generic_definition = generic_definition
def __str__(self): def __str__(self):

View File

@ -148,10 +148,10 @@ class TelegramClient:
def get_dialogs(self, count=10, offset_date=None, offset_id=0, offset_peer=InputPeerEmpty()): def get_dialogs(self, count=10, offset_date=None, offset_id=0, offset_peer=InputPeerEmpty()):
"""Returns a tuple of lists ([dialogs], [displays], [input_peers]) with 'count' items each""" """Returns a tuple of lists ([dialogs], [displays], [input_peers]) with 'count' items each"""
r = self.invoke(GetDialogsRequest(offset_date=TelegramClient.get_tg_date(offset_date), r = self.invoke(GetDialogsRequest(offset_date=offset_date,
offset_id=offset_id, offset_id=offset_id,
offset_peer=offset_peer, offset_peer=offset_peer,
limit=count)) limit=count))
return (r.dialogs, return (r.dialogs,
[self.find_display_name(d.peer, r.users, r.chats) for d in r.dialogs], [self.find_display_name(d.peer, r.users, r.chats) for d in r.dialogs],
@ -188,7 +188,7 @@ class TelegramClient:
""" """
result = self.invoke(GetHistoryRequest(input_peer, result = self.invoke(GetHistoryRequest(input_peer,
limit=limit, limit=limit,
offset_date=self.get_tg_date(offset_date), offset_date=offset_date,
offset_id=offset_id, offset_id=offset_id,
max_id=max_id, max_id=max_id,
min_id=min_id, min_id=min_id,
@ -220,11 +220,6 @@ class TelegramClient:
# region Utilities # region Utilities
@staticmethod
def get_tg_date(datetime):
"""Parses a datetime Python object to Telegram's required integer Unix timestamp"""
return 0 if datetime is None else int(datetime.timestamp())
@staticmethod @staticmethod
def find_display_name(peer, users, chats): def find_display_name(peer, users, chats):
"""Searches the display name for peer in both users and chats. """Searches the display name for peer in both users and chats.

View File

@ -284,6 +284,9 @@ def write_onsend_code(builder, arg, args, name=None):
elif 'bytes' == arg.type: elif 'bytes' == arg.type:
builder.writeln('writer.write({})'.format(name)) builder.writeln('writer.write({})'.format(name))
elif 'date' == arg.type: # Custom format
builder.writeln('writer.tgwrite_date({})'.format(name))
else: else:
# Else it may be a custom type # Else it may be a custom type
builder.writeln('{}.on_send(writer)'.format(name)) builder.writeln('{}.on_send(writer)'.format(name))
@ -364,6 +367,9 @@ def write_onresponse_code(builder, arg, args, name=None):
elif 'bytes' == arg.type: elif 'bytes' == arg.type:
builder.writeln('{} = reader.tgread_bytes()'.format(name)) builder.writeln('{} = reader.tgread_bytes()'.format(name))
elif 'date' == arg.type: # Custom format
builder.writeln('{} = reader.tgread_date()'.format(name))
else: else:
# Else it may be a custom type # Else it may be a custom type
builder.writeln('{} = reader.tgread_object()'.format(name)) builder.writeln('{} = reader.tgread_object()'.format(name))

View File

@ -1,3 +1,4 @@
from datetime import datetime
from io import BytesIO, BufferedReader from io import BytesIO, BufferedReader
from tl.all_tlobjects import tlobjects from tl.all_tlobjects import tlobjects
from struct import unpack from struct import unpack
@ -95,6 +96,11 @@ class BinaryReader:
else: else:
raise ValueError('Invalid boolean code {}'.format(hex(value))) raise ValueError('Invalid boolean code {}'.format(hex(value)))
def tgread_date(self):
"""Reads and converts Unix time (used by Telegram) into a Python datetime object"""
value = self.read_int()
return None if value == 0 else datetime.fromtimestamp(value)
def tgread_object(self): def tgread_object(self):
"""Reads a Telegram object""" """Reads a Telegram object"""
constructor_id = self.read_int(signed=False) constructor_id = self.read_int(signed=False)

View File

@ -83,12 +83,17 @@ class BinaryWriter:
def tgwrite_string(self, string): def tgwrite_string(self, string):
"""Write a string by using Telegram guidelines""" """Write a string by using Telegram guidelines"""
return self.tgwrite_bytes(string.encode('utf-8')) self.tgwrite_bytes(string.encode('utf-8'))
def tgwrite_bool(self, boolean): def tgwrite_bool(self, boolean):
"""Write a boolean value by using Telegram guidelines""" """Write a boolean value by using Telegram guidelines"""
# boolTrue boolFalse # boolTrue boolFalse
return self.write_int(0x997275b5 if boolean else 0xbc799737, signed=False) self.write_int(0x997275b5 if boolean else 0xbc799737, signed=False)
def tgwrite_date(self, datetime):
"""Converts a Python datetime object into Unix time (used by Telegram) and writes it"""
value = 0 if datetime is None else int(datetime.timestamp())
self.write_int(value)
# endregion # endregion