Use relative imports always where possible

This commit is contained in:
Lonami Exo 2017-05-21 13:02:54 +02:00
parent ca80b05694
commit 63c89af983
17 changed files with 104 additions and 81 deletions

View File

@ -3,7 +3,7 @@ import os
import re import re
import sys import sys
import shutil import shutil
from docs.docs_writer import DocsWriter from .docs_writer import DocsWriter
# Small trick so importing telethon_generator works # Small trick so importing telethon_generator works
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

View File

@ -1,3 +1,4 @@
from .errors import * from .errors import *
from .telegram_client import TelegramClient from .telegram_client import TelegramClient
from .interactive_telegram_client import InteractiveTelegramClient from .interactive_telegram_client import InteractiveTelegramClient
from . import tl

View File

@ -1,5 +1,5 @@
import telethon.helpers as utils from .. import helpers as utils
from telethon.utils import BinaryReader, BinaryWriter from ..utils import BinaryReader, BinaryWriter
class AuthKey: class AuthKey:

View File

@ -1,7 +1,7 @@
import os import os
import telethon.helpers as utils from .. import helpers as utils
from telethon.utils import BinaryWriter from ..utils import BinaryWriter
class RSAServerKey: class RSAServerKey:

View File

@ -1,9 +1,10 @@
import shutil import shutil
from getpass import getpass from getpass import getpass
from telethon import RPCError, TelegramClient from . import TelegramClient
from telethon.tl.types import UpdateShortChatMessage, UpdateShortMessage from .errors import RPCError
from telethon.utils import get_display_name from .tl.types import UpdateShortChatMessage, UpdateShortMessage
from .utils import get_display_name
# Get the (current) number of lines in the terminal # Get the (current) number of lines in the terminal
cols, rows = shutil.get_terminal_size() cols, rows = shutil.get_terminal_size()

View File

@ -1,10 +1,10 @@
import os import os
import time import time
import telethon.helpers as utils from .. import helpers as utils
from telethon.crypto import AES, RSA, AuthKey, Factorizator from ..crypto import AES, RSA, AuthKey, Factorizator
from telethon.network import MtProtoPlainSender from ..network import MtProtoPlainSender
from telethon.utils import BinaryReader, BinaryWriter from ..utils import BinaryReader, BinaryWriter
def do_authentication(transport): def do_authentication(transport):

View File

@ -1,7 +1,7 @@
import random import random
import time import time
from telethon.utils import BinaryReader, BinaryWriter from ..utils import BinaryReader, BinaryWriter
class MtProtoPlainSender: class MtProtoPlainSender:

View File

@ -3,14 +3,15 @@ from datetime import timedelta
from threading import Event, RLock, Thread from threading import Event, RLock, Thread
from time import sleep, time from time import sleep, time
import telethon.helpers as utils from .. import helpers as utils
from telethon.crypto import AES from ..crypto import AES
from telethon.errors import * from ..errors import (BadMessageError, RPCError,
from telethon.tl.all_tlobjects import tlobjects InvalidDCError, ReadCancelledError)
from telethon.tl.functions.updates import GetStateRequest from ..tl.all_tlobjects import tlobjects
from telethon.tl.types import MsgsAck from ..tl.functions import PingRequest
from telethon.tl.functions import PingRequest from ..tl.functions.updates import GetStateRequest
from telethon.utils import BinaryReader, BinaryWriter from ..tl.types import MsgsAck
from ..utils import BinaryReader, BinaryWriter
import logging import logging
logging.getLogger(__name__).addHandler(logging.NullHandler()) logging.getLogger(__name__).addHandler(logging.NullHandler())

View File

@ -4,8 +4,8 @@ import time
from datetime import datetime, timedelta from datetime import datetime, timedelta
from threading import Event, Lock from threading import Event, Lock
from telethon.errors import ReadCancelledError from ..errors import ReadCancelledError
from telethon.utils import BinaryWriter from ..utils import BinaryWriter
class TcpClient: class TcpClient:

View File

@ -1,9 +1,9 @@
from binascii import crc32 from binascii import crc32
from datetime import timedelta from datetime import timedelta
from telethon.errors import * from ..errors import InvalidChecksumError
from telethon.network import TcpClient from ..network import TcpClient
from telethon.utils import BinaryWriter from ..utils import BinaryWriter
class TcpTransport: class TcpTransport:

View File

@ -1,5 +1,5 @@
from telethon.tl.types import (MessageEntityBold, MessageEntityCode, from ..tl.types import (MessageEntityBold, MessageEntityCode,
MessageEntityItalic, MessageEntityTextUrl) MessageEntityItalic, MessageEntityTextUrl)
def parse_message_entities(msg): def parse_message_entities(msg):

View File

@ -5,37 +5,36 @@ from mimetypes import guess_type
from os import listdir, path from os import listdir, path
# Import some externalized utilities to work with the Telegram types and more # Import some externalized utilities to work with the Telegram types and more
import telethon.helpers as utils from . import helpers as utils
import telethon.network.authenticator as authenticator from .errors import RPCError, InvalidDCError, InvalidParameterError
from telethon.errors import * from .network import authenticator, MtProtoSender, TcpTransport
from telethon.network import MtProtoSender, TcpTransport from .parser.markdown_parser import parse_message_entities
from telethon.parser.markdown_parser import parse_message_entities
# For sending and receiving requests # For sending and receiving requests
from telethon.tl import MTProtoRequest, Session from .tl import MTProtoRequest, Session
from telethon.tl.all_tlobjects import layer from .tl.all_tlobjects import layer
from telethon.tl.functions import InitConnectionRequest, InvokeWithLayerRequest from .tl.functions import InitConnectionRequest, InvokeWithLayerRequest
# The following is required to get the password salt # The following is required to get the password salt
from telethon.tl.functions.account import GetPasswordRequest from .tl.functions.account import GetPasswordRequest
from telethon.tl.functions.auth import (CheckPasswordRequest, LogOutRequest, from .tl.functions.auth import (CheckPasswordRequest, LogOutRequest,
SendCodeRequest, SignInRequest, SendCodeRequest, SignInRequest,
SignUpRequest) SignUpRequest)
from telethon.tl.functions.auth import ImportBotAuthorizationRequest from .tl.functions.auth import ImportBotAuthorizationRequest
from telethon.tl.functions.help import GetConfigRequest from .tl.functions.help import GetConfigRequest
from telethon.tl.functions.messages import ( from .tl.functions.messages import (
GetDialogsRequest, GetHistoryRequest, ReadHistoryRequest, SendMediaRequest, GetDialogsRequest, GetHistoryRequest, ReadHistoryRequest, SendMediaRequest,
SendMessageRequest) SendMessageRequest)
# The Requests and types that we'll be using # The Requests and types that we'll be using
from telethon.tl.functions.upload import ( from .tl.functions.upload import (
GetFileRequest, SaveBigFilePartRequest, SaveFilePartRequest) GetFileRequest, SaveBigFilePartRequest, SaveFilePartRequest)
# All the types we need to work with # All the types we need to work with
from telethon.tl.types import ( from .tl.types import (
ChatPhotoEmpty, DocumentAttributeAudio, DocumentAttributeFilename, ChatPhotoEmpty, DocumentAttributeAudio, DocumentAttributeFilename,
InputDocumentFileLocation, InputFile, InputFileBig, InputFileLocation, InputDocumentFileLocation, InputFile, InputFileBig, InputFileLocation,
InputMediaUploadedDocument, InputMediaUploadedPhoto, InputPeerEmpty, InputMediaUploadedDocument, InputMediaUploadedPhoto, InputPeerEmpty,
MessageMediaContact, MessageMediaDocument, MessageMediaPhoto, MessageMediaContact, MessageMediaDocument, MessageMediaPhoto,
UserProfilePhotoEmpty) UserProfilePhotoEmpty)
from telethon.utils import (find_user_or_chat, get_input_peer, from .utils import (find_user_or_chat, get_input_peer,
get_appropiate_part_size, get_extension) get_appropiate_part_size, get_extension)
class TelegramClient: class TelegramClient:

View File

@ -1,2 +1,2 @@
from telethon.tl.mtproto_request import MTProtoRequest from .mtproto_request import MTProtoRequest
from telethon.tl.session import Session from .session import Session

View File

@ -4,7 +4,7 @@ import random
import time import time
from os.path import isfile as file_exists from os.path import isfile as file_exists
import telethon.helpers as utils from .. import helpers as utils
class Session: class Session:

View File

@ -3,8 +3,8 @@ from datetime import datetime
from io import BufferedReader, BytesIO from io import BufferedReader, BytesIO
from struct import unpack from struct import unpack
from telethon.errors import * from ..errors import InvalidParameterError, TypeNotFoundError
from telethon.tl.all_tlobjects import tlobjects from ..tl.all_tlobjects import tlobjects
class BinaryReader: class BinaryReader:

View File

@ -4,7 +4,7 @@
after all, both are the same attribute, IDs.""" after all, both are the same attribute, IDs."""
from mimetypes import add_type, guess_extension from mimetypes import add_type, guess_extension
from telethon.tl.types import ( from ..tl.types import (
Channel, Chat, ChatPhoto, InputPeerChannel, InputPeerChat, InputPeerUser, Channel, Chat, ChatPhoto, InputPeerChannel, InputPeerChat, InputPeerUser,
MessageMediaDocument, MessageMediaPhoto, PeerChannel, PeerChat, PeerUser, MessageMediaDocument, MessageMediaPhoto, PeerChannel, PeerChat, PeerUser,
User, UserProfilePhoto) User, UserProfilePhoto)

View File

@ -12,6 +12,8 @@ except (ImportError, SystemError):
def get_output_path(normal_path): def get_output_path(normal_path):
return os.path.join('../telethon/tl', normal_path) return os.path.join('../telethon/tl', normal_path)
output_base_depth = 2 # telethon/tl/
class TLGenerator: class TLGenerator:
@staticmethod @staticmethod
@ -45,10 +47,22 @@ class TLGenerator:
# Step 1: Ensure that no object has the same name as a namespace # Step 1: Ensure that no object has the same name as a namespace
# We must check this because Python will complain if it sees a # We must check this because Python will complain if it sees a
# file and a directory with the same name, which happens for example with "updates" # file and a directory with the same name, which happens for example with "updates"
namespace_directories = set() #
# We distinguish between function and type namespaces since we
# will later need to perform a relative import for them to be used
function_namespaces = set()
type_namespaces = set()
for tlobject in tlobjects: for tlobject in tlobjects:
namespace_directories.add(tlobject.namespace) if tlobject.namespace:
if tlobject.is_function:
function_namespaces.add(tlobject.namespace)
else:
type_namespaces.add(tlobject.namespace)
# Merge both namespaces to easily check if any namespace exists,
# though we could also distinguish between types and functions
# here, it's not worth doing
namespace_directories = function_namespaces | type_namespaces
for tlobject in tlobjects: for tlobject in tlobjects:
if TLGenerator.get_file_name(tlobject, add_extension=False) \ if TLGenerator.get_file_name(tlobject, add_extension=False) \
in namespace_directories: in namespace_directories:
@ -67,7 +81,10 @@ class TLGenerator:
out_dir = get_output_path('functions' out_dir = get_output_path('functions'
if tlobject.is_function else 'types') if tlobject.is_function else 'types')
# Path depth to perform relative import
depth = output_base_depth
if tlobject.namespace: if tlobject.namespace:
depth += 1
out_dir = os.path.join(out_dir, tlobject.namespace) out_dir = os.path.join(out_dir, tlobject.namespace)
os.makedirs(out_dir, exist_ok=True) os.makedirs(out_dir, exist_ok=True)
@ -76,8 +93,8 @@ class TLGenerator:
init_py = os.path.join(out_dir, '__init__.py') init_py = os.path.join(out_dir, '__init__.py')
with open(init_py, 'a', encoding='utf-8') as file: with open(init_py, 'a', encoding='utf-8') as file:
with SourceBuilder(file) as builder: with SourceBuilder(file) as builder:
builder.writeln('from {} import {}'.format( builder.writeln('from .{} import {}'.format(
TLGenerator.get_full_file_name(tlobject), TLGenerator.get_file_name(tlobject, add_extension=False),
TLGenerator.get_class_name(tlobject))) TLGenerator.get_class_name(tlobject)))
# Create the file for this TLObject # Create the file for this TLObject
@ -89,8 +106,8 @@ class TLGenerator:
# Let's build the source code! # Let's build the source code!
with SourceBuilder(file) as builder: with SourceBuilder(file) as builder:
# Both types and functions inherit from MTProtoRequest so they all can be sent # Both types and functions inherit from MTProtoRequest so they all can be sent
builder.writeln( builder.writeln('from {}.tl.mtproto_request import MTProtoRequest'
'from telethon.tl.mtproto_request import MTProtoRequest') .format('.' * depth))
builder.writeln() builder.writeln()
builder.writeln() builder.writeln()
builder.writeln('class {}(MTProtoRequest):'.format( builder.writeln('class {}(MTProtoRequest):'.format(
@ -214,7 +231,18 @@ class TLGenerator:
builder.writeln('return {}'.format(str(tlobject))) builder.writeln('return {}'.format(str(tlobject)))
# builder.end_block() # There is no need to end the last block # builder.end_block() # There is no need to end the last block
# Step 3: Once all the objects have been generated, we can now group them in a single file # Step 3: Add the relative imports to the namespaces on __init__.py's
init_py = os.path.join(get_output_path('functions'), '__init__.py')
with open(init_py, 'a') as file:
file.write('from . import {}\n'
.format(', '.join(function_namespaces)))
init_py = os.path.join(get_output_path('types'), '__init__.py')
with open(init_py, 'a') as file:
file.write('from . import {}\n'
.format(', '.join(type_namespaces)))
# Step 4: Once all the objects have been generated, we can now group them in a single file
filename = os.path.join(get_output_path('all_tlobjects.py')) filename = os.path.join(get_output_path('all_tlobjects.py'))
with open(filename, 'w', encoding='utf-8') as file: with open(filename, 'w', encoding='utf-8') as file:
with SourceBuilder(file) as builder: with SourceBuilder(file) as builder:
@ -222,10 +250,7 @@ class TLGenerator:
'"""File generated by TLObjects\' generator. All changes will be ERASED"""') '"""File generated by TLObjects\' generator. All changes will be ERASED"""')
builder.writeln() builder.writeln()
# First add imports builder.writeln('from ..tl import types, functions')
for tlobject in tlobjects:
builder.writeln('import {}'.format(
TLGenerator.get_full_file_name(tlobject)))
builder.writeln() builder.writeln()
# Create a variable to indicate which layer this is # Create a variable to indicate which layer this is
@ -239,9 +264,18 @@ class TLGenerator:
# Fill the dictionary (0x1a2b3c4f: tl.full.type.path.Class) # Fill the dictionary (0x1a2b3c4f: tl.full.type.path.Class)
for tlobject in tlobjects: for tlobject in tlobjects:
builder.writeln('{}: {}.{},'.format( constructor = hex(tlobject.id)
hex(tlobject.id), TLGenerator.get_full_file_name( if len(constructor) != 10:
tlobject), TLGenerator.get_class_name(tlobject))) # Make it a nice length 10 so it fits well
constructor = '0x' + constructor[2:].zfill(8)
builder.write('{}: '.format(constructor))
builder.write('functions' if tlobject.is_function else 'types')
if tlobject.namespace:
builder.write('.' + tlobject.namespace)
builder.writeln('.{},'.format(
TLGenerator.get_class_name(tlobject)))
builder.current_indent -= 1 builder.current_indent -= 1
builder.writeln('}') builder.writeln('}')
@ -262,20 +296,7 @@ class TLGenerator:
return result return result
@staticmethod @staticmethod
def get_full_file_name(tlobject): def get_file_name(tlobject, add_extension=False):
"""Gets the full file name for the given TLObject (tl.type.full.path)"""
fullname = TLGenerator.get_file_name(tlobject, add_extension=False)
if tlobject.namespace:
fullname = '{}.{}'.format(tlobject.namespace, fullname)
if tlobject.is_function:
return 'telethon.tl.functions.{}'.format(fullname)
else:
return 'telethon.tl.types.{}'.format(fullname)
@staticmethod
def get_file_name(tlobject, add_extension):
"""Gets the file name in file_name_format.py for the given TLObject""" """Gets the file name in file_name_format.py for the given TLObject"""
# Courtesy of http://stackoverflow.com/a/1176023/4759433 # Courtesy of http://stackoverflow.com/a/1176023/4759433