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

@@ -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