mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-22 17:36:34 +03:00
Add Python type hints to attributes of TL types (#678)
This commit is contained in:
parent
751461f0f5
commit
935de0afbb
|
@ -1,2 +1,3 @@
|
||||||
pyaes
|
pyaes
|
||||||
rsa
|
rsa
|
||||||
|
typing
|
||||||
|
|
5
setup.py
5
setup.py
|
@ -13,7 +13,7 @@ Extra supported commands are:
|
||||||
|
|
||||||
# To use a consistent encoding
|
# To use a consistent encoding
|
||||||
from codecs import open
|
from codecs import open
|
||||||
from sys import argv
|
from sys import argv, version_info
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
@ -153,7 +153,8 @@ def main():
|
||||||
'telethon_generator/parser/tl_object.py',
|
'telethon_generator/parser/tl_object.py',
|
||||||
'telethon_generator/parser/tl_parser.py',
|
'telethon_generator/parser/tl_parser.py',
|
||||||
]),
|
]),
|
||||||
install_requires=['pyaes', 'rsa'],
|
install_requires=['pyaes', 'rsa',
|
||||||
|
'typing' if version_info < (3, 5) else ""],
|
||||||
extras_require={
|
extras_require={
|
||||||
'cryptg': ['cryptg'],
|
'cryptg': ['cryptg'],
|
||||||
'sqlalchemy': ['sqlalchemy']
|
'sqlalchemy': ['sqlalchemy']
|
||||||
|
|
|
@ -254,7 +254,7 @@ class TLArg:
|
||||||
|
|
||||||
self.generic_definition = generic_definition
|
self.generic_definition = generic_definition
|
||||||
|
|
||||||
def type_hint(self):
|
def doc_type_hint(self):
|
||||||
result = {
|
result = {
|
||||||
'int': 'int',
|
'int': 'int',
|
||||||
'long': 'int',
|
'long': 'int',
|
||||||
|
@ -272,6 +272,27 @@ class TLArg:
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def python_type_hint(self):
|
||||||
|
type = self.type
|
||||||
|
if '.' in type:
|
||||||
|
type = type.split('.')[1]
|
||||||
|
result = {
|
||||||
|
'int': 'int',
|
||||||
|
'long': 'int',
|
||||||
|
'int128': 'int',
|
||||||
|
'int256': 'int',
|
||||||
|
'string': 'str',
|
||||||
|
'date': 'Optional[datetime]', # None date = 0 timestamp
|
||||||
|
'bytes': 'bytes',
|
||||||
|
'true': 'bool',
|
||||||
|
}.get(type, "Type{}".format(type))
|
||||||
|
if self.is_vector:
|
||||||
|
result = 'List[{}]'.format(result)
|
||||||
|
if self.is_flag and type != 'date':
|
||||||
|
result = 'Optional[{}]'.format(result)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
# Find the real type representation by updating it as required
|
# Find the real type representation by updating it as required
|
||||||
real_type = self.type
|
real_type = self.type
|
||||||
|
|
|
@ -138,6 +138,7 @@ class TLGenerator:
|
||||||
builder.writeln(
|
builder.writeln(
|
||||||
'from {}.tl.tlobject import TLObject'.format('.' * depth)
|
'from {}.tl.tlobject import TLObject'.format('.' * depth)
|
||||||
)
|
)
|
||||||
|
builder.writeln('from typing import Optional, List, Union, TYPE_CHECKING')
|
||||||
|
|
||||||
# Add the relative imports to the namespaces,
|
# Add the relative imports to the namespaces,
|
||||||
# unless we already are in a namespace.
|
# unless we already are in a namespace.
|
||||||
|
@ -154,13 +155,81 @@ class TLGenerator:
|
||||||
# Import struct for the .__bytes__(self) serialization
|
# Import struct for the .__bytes__(self) serialization
|
||||||
builder.writeln('import struct')
|
builder.writeln('import struct')
|
||||||
|
|
||||||
|
tlobjects.sort(key=lambda x: x.name)
|
||||||
|
|
||||||
|
type_names = set()
|
||||||
|
type_defs = []
|
||||||
|
|
||||||
|
# Find all the types in this file and generate type definitions
|
||||||
|
# based on the types. The type definitions are written to the
|
||||||
|
# file at the end.
|
||||||
|
for t in tlobjects:
|
||||||
|
if not t.is_function:
|
||||||
|
type_name = t.result
|
||||||
|
if '.' in type_name:
|
||||||
|
type_name = type_name[type_name.rindex('.'):]
|
||||||
|
if type_name in type_names:
|
||||||
|
continue
|
||||||
|
type_names.add(type_name)
|
||||||
|
constructors = type_constructors[type_name]
|
||||||
|
if not constructors:
|
||||||
|
pass
|
||||||
|
elif len(constructors) == 1:
|
||||||
|
type_defs.append('Type{} = {}'.format(
|
||||||
|
type_name, constructors[0].class_name()))
|
||||||
|
else:
|
||||||
|
type_defs.append('Type{} = Union[{}]'.format(
|
||||||
|
type_name, ','.join(c.class_name()
|
||||||
|
for c in constructors)))
|
||||||
|
|
||||||
|
imports = {}
|
||||||
|
primitives = ('int', 'long', 'int128', 'int256', 'string',
|
||||||
|
'date', 'bytes', 'true')
|
||||||
|
# Find all the types in other files that are used in this file
|
||||||
|
# and generate the information required to import those types.
|
||||||
|
for t in tlobjects:
|
||||||
|
for arg in t.args:
|
||||||
|
name = arg.type
|
||||||
|
if not name or name in primitives:
|
||||||
|
continue
|
||||||
|
|
||||||
|
import_space = '{}.tl.types'.format('.' * depth)
|
||||||
|
if '.' in name:
|
||||||
|
namespace = name.split('.')[0]
|
||||||
|
name = name.split('.')[1]
|
||||||
|
import_space += '.{}'.format(namespace)
|
||||||
|
|
||||||
|
if name not in type_names:
|
||||||
|
type_names.add(name)
|
||||||
|
if name == 'date':
|
||||||
|
imports['datetime'] = ['datetime']
|
||||||
|
continue
|
||||||
|
elif not import_space in imports:
|
||||||
|
imports[import_space] = set()
|
||||||
|
imports[import_space].add('Type{}'.format(name))
|
||||||
|
|
||||||
|
# Add imports required for type checking.
|
||||||
|
builder.writeln('if TYPE_CHECKING:')
|
||||||
|
for namespace, names in imports.items():
|
||||||
|
builder.writeln('from {} import {}'.format(
|
||||||
|
namespace, ', '.join(names)))
|
||||||
|
else:
|
||||||
|
builder.writeln('pass')
|
||||||
|
builder.end_block()
|
||||||
|
|
||||||
# Generate the class for every TLObject
|
# Generate the class for every TLObject
|
||||||
for t in sorted(tlobjects, key=lambda x: x.name):
|
for t in tlobjects:
|
||||||
TLGenerator._write_source_code(
|
TLGenerator._write_source_code(
|
||||||
t, builder, depth, type_constructors
|
t, builder, depth, type_constructors
|
||||||
)
|
)
|
||||||
builder.current_indent = 0
|
builder.current_indent = 0
|
||||||
|
|
||||||
|
# Write the type definitions generated earlier.
|
||||||
|
builder.writeln('')
|
||||||
|
for line in type_defs:
|
||||||
|
builder.writeln(line)
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _write_source_code(tlobject, builder, depth, type_constructors):
|
def _write_source_code(tlobject, builder, depth, type_constructors):
|
||||||
"""Writes the source code corresponding to the given TLObject
|
"""Writes the source code corresponding to the given TLObject
|
||||||
|
@ -218,7 +287,7 @@ class TLGenerator:
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if not arg.flag_indicator:
|
if not arg.flag_indicator:
|
||||||
builder.writeln(':param {} {}:'.format(
|
builder.writeln(':param {} {}:'.format(
|
||||||
arg.type_hint(), arg.name
|
arg.doc_type_hint(), arg.name
|
||||||
))
|
))
|
||||||
builder.current_indent -= 1 # It will auto-indent (':')
|
builder.current_indent -= 1 # It will auto-indent (':')
|
||||||
|
|
||||||
|
@ -258,7 +327,8 @@ class TLGenerator:
|
||||||
|
|
||||||
for arg in args:
|
for arg in args:
|
||||||
if not arg.can_be_inferred:
|
if not arg.can_be_inferred:
|
||||||
builder.writeln('self.{0} = {0}'.format(arg.name))
|
builder.writeln('self.{0} = {0} # type: {1}'.format(
|
||||||
|
arg.name, arg.python_type_hint()))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Currently the only argument that can be
|
# Currently the only argument that can be
|
||||||
|
|
Loading…
Reference in New Issue
Block a user