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 sys
import shutil
from docs.docs_writer import DocsWriter
from .docs_writer import DocsWriter
# Small trick so importing telethon_generator works
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -12,6 +12,8 @@ except (ImportError, SystemError):
def get_output_path(normal_path):
return os.path.join('../telethon/tl', normal_path)
output_base_depth = 2 # telethon/tl/
class TLGenerator:
@staticmethod
@ -45,10 +47,22 @@ class TLGenerator:
# 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
# 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:
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:
if TLGenerator.get_file_name(tlobject, add_extension=False) \
in namespace_directories:
@ -67,7 +81,10 @@ class TLGenerator:
out_dir = get_output_path('functions'
if tlobject.is_function else 'types')
# Path depth to perform relative import
depth = output_base_depth
if tlobject.namespace:
depth += 1
out_dir = os.path.join(out_dir, tlobject.namespace)
os.makedirs(out_dir, exist_ok=True)
@ -76,8 +93,8 @@ class TLGenerator:
init_py = os.path.join(out_dir, '__init__.py')
with open(init_py, 'a', encoding='utf-8') as file:
with SourceBuilder(file) as builder:
builder.writeln('from {} import {}'.format(
TLGenerator.get_full_file_name(tlobject),
builder.writeln('from .{} import {}'.format(
TLGenerator.get_file_name(tlobject, add_extension=False),
TLGenerator.get_class_name(tlobject)))
# Create the file for this TLObject
@ -89,8 +106,8 @@ class TLGenerator:
# Let's build the source code!
with SourceBuilder(file) as builder:
# Both types and functions inherit from MTProtoRequest so they all can be sent
builder.writeln(
'from telethon.tl.mtproto_request import MTProtoRequest')
builder.writeln('from {}.tl.mtproto_request import MTProtoRequest'
.format('.' * depth))
builder.writeln()
builder.writeln()
builder.writeln('class {}(MTProtoRequest):'.format(
@ -214,7 +231,18 @@ class TLGenerator:
builder.writeln('return {}'.format(str(tlobject)))
# 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'))
with open(filename, 'w', encoding='utf-8') as file:
with SourceBuilder(file) as builder:
@ -222,10 +250,7 @@ class TLGenerator:
'"""File generated by TLObjects\' generator. All changes will be ERASED"""')
builder.writeln()
# First add imports
for tlobject in tlobjects:
builder.writeln('import {}'.format(
TLGenerator.get_full_file_name(tlobject)))
builder.writeln('from ..tl import types, functions')
builder.writeln()
# Create a variable to indicate which layer this is
@ -239,9 +264,18 @@ class TLGenerator:
# Fill the dictionary (0x1a2b3c4f: tl.full.type.path.Class)
for tlobject in tlobjects:
builder.writeln('{}: {}.{},'.format(
hex(tlobject.id), TLGenerator.get_full_file_name(
tlobject), TLGenerator.get_class_name(tlobject)))
constructor = hex(tlobject.id)
if len(constructor) != 10:
# 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.writeln('}')
@ -262,20 +296,7 @@ class TLGenerator:
return result
@staticmethod
def get_full_file_name(tlobject):
"""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):
def get_file_name(tlobject, add_extension=False):
"""Gets the file name in file_name_format.py for the given TLObject"""
# Courtesy of http://stackoverflow.com/a/1176023/4759433