Use setup.py to run tl_generator.py instead (plus some cleanup)

This commit is contained in:
Lonami Exo 2017-06-21 11:27:22 +02:00
parent a9a5c7e254
commit b0b814bdb9
3 changed files with 98 additions and 104 deletions

View File

@ -71,7 +71,7 @@ Installing Telethon manually
(`GitHub <https://github.com/ricmoo/pyaes>`_, `package index <https://pypi.python.org/pypi/pyaes>`_) (`GitHub <https://github.com/ricmoo/pyaes>`_, `package index <https://pypi.python.org/pypi/pyaes>`_)
2. Clone Telethon's GitHub repository: ``git clone https://github.com/LonamiWebs/Telethon.git`` 2. Clone Telethon's GitHub repository: ``git clone https://github.com/LonamiWebs/Telethon.git``
3. Enter the cloned repository: ``cd Telethon`` 3. Enter the cloned repository: ``cd Telethon``
4. Run the code generator: ``cd telethon_generator && python3 tl_generator.py`` 4. Run the code generator: ``python3 setup.py gen_tl``
5. Done! 5. Done!
Running Telethon Running Telethon
@ -232,7 +232,7 @@ Have you found a more updated version of the ``scheme.tl`` file? Those are great
as grabbing the as grabbing the
`latest version <https://github.com/telegramdesktop/tdesktop/blob/dev/Telegram/Resources/scheme.tl>`_ `latest version <https://github.com/telegramdesktop/tdesktop/blob/dev/Telegram/Resources/scheme.tl>`_
and replacing the one you can find in this same directory by the updated one. and replacing the one you can find in this same directory by the updated one.
Don't forget to run ``python3 tl_generator.py``. Don't forget to run ``python3 setup.py gen_tl``.
If the changes weren't too big, everything should still work the same way as it did before; but with extra features. If the changes weren't too big, everything should still work the same way as it did before; but with extra features.

125
setup.py
View File

@ -3,85 +3,94 @@
See: See:
https://packaging.python.org/en/latest/distributing.html https://packaging.python.org/en/latest/distributing.html
https://github.com/pypa/sampleproject https://github.com/pypa/sampleproject
Extra supported commands are:
* gen_tl, to generate the classes required for Telethon to run
* clean_tl, to clean these generated classes
""" """
# To use a consistent encoding # To use a consistent encoding
from codecs import open from codecs import open
from sys import argv
from os import path from os import path
# Always prefer setuptools over distutils # Always prefer setuptools over distutils
from setuptools import find_packages, setup from setuptools import find_packages, setup
from telethon import TelegramClient from telethon_generator.tl_generator import TLGenerator
try:
from telethon import TelegramClient
except ModuleNotFoundError:
TelegramClient = None
here = path.abspath(path.dirname(__file__))
# Get the long description from the README file if __name__ == '__main__':
with open(path.join(here, 'README.rst'), encoding='utf-8') as f: if len(argv) >= 2 and argv[1] == 'gen_tl':
long_description = f.read() generator = TLGenerator('telethon/tl')
if generator.tlobjects_exist():
print('Detected previous TLObjects. Cleaning...')
generator.clean_tlobjects()
setup( print('Generating TLObjects...')
name='Telethon', generator.generate_tlobjects(
'telethon_generator/scheme.tl', import_depth=2
)
print('Done.')
# Versions should comply with PEP440. elif len(argv) >= 2 and argv[1] == 'clean_tl':
version=TelegramClient.__version__, print('Cleaning...')
description="Python3 Telegram's client implementation with full access to its API", TLGenerator('telethon/tl').clean_tlobjects()
long_description=long_description, print('Done.')
# The project's main homepage. else:
url='https://github.com/LonamiWebs/Telethon', if not TelegramClient:
download_url='https://github.com/LonamiWebs/Telethon/releases', print('Run `python3', argv[0], 'gen_tl` first.')
quit()
# Author details here = path.abspath(path.dirname(__file__))
author='Lonami Exo',
author_email='totufals@hotmail.com',
# Choose your license # Get the long description from the README file
license='MIT', with open(path.join(here, 'README.rst'), encoding='utf-8') as f:
long_description = f.read()
# See https://pypi.python.org/pypi?%3Aaction=list_classifiers setup(
classifiers=[ name='Telethon',
# How mature is this project? Common values are
# 3 - Alpha
# 4 - Beta
# 5 - Production/Stable
'Development Status :: 3 - Alpha',
# Indicate who your project is intended for # Versions should comply with PEP440.
'Intended Audience :: Developers', version=TelegramClient.__version__,
'Topic :: Communications :: Chat', description="Full-featured Telegram client library for Python 3",
long_description=long_description,
# Pick your license as you wish (should match "license" above) url='https://github.com/LonamiWebs/Telethon',
'License :: OSI Approved :: MIT License', download_url='https://github.com/LonamiWebs/Telethon/releases',
# Specify the Python versions you support here. In particular, ensure author='Lonami Exo',
# that you indicate whether you support Python 2, Python 3 or both. author_email='totufals@hotmail.com',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6'
],
# What does your project relate to? license='MIT',
keywords='Telegram API chat client MTProto',
# You can just specify the packages manually here if your project is # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
# simple. Or you can use find_packages(). classifiers=[
packages=find_packages(exclude=[ # 3 - Alpha
'telethon_generator', 'telethon_tests', 'run_tests.py', # 4 - Beta
'try_telethon.py' # 5 - Production/Stable
]), 'Development Status :: 3 - Alpha',
# List run-time dependencies here. These will be installed by pip when 'Intended Audience :: Developers',
# your project is installed. 'Topic :: Communications :: Chat',
install_requires=['pyaes'],
# To provide executable scripts, use entry points in preference to the 'License :: OSI Approved :: MIT License',
# "scripts" keyword. Entry points provide cross-platform support and allow
# pip to create the appropriate form of executable for the target platform. 'Programming Language :: Python :: 3',
entry_points={ 'Programming Language :: Python :: 3.3',
'console_scripts': [ 'Programming Language :: Python :: 3.4',
'gen_tl = tl_generator:clean_and_generate', 'Programming Language :: Python :: 3.5',
], 'Programming Language :: Python :: 3.6'
}) ],
keywords='telegram api chat client library messaging mtproto',
packages=find_packages(exclude=[
'telethon_generator', 'telethon_tests', 'run_tests.py',
'try_telethon.py'
]),
install_requires=['pyaes']
)

73
telethon_generator/tl_generator.py Executable file → Normal file
View File

@ -1,51 +1,46 @@
#!/usr/bin/env python3
import os import os
import re import re
import shutil import shutil
from zlib import crc32 from zlib import crc32
from collections import defaultdict from collections import defaultdict
try: from .parser import SourceBuilder, TLParser
from .parser import SourceBuilder, TLParser
except (ImportError, SystemError):
from parser import SourceBuilder, TLParser
def get_output_path(normal_path):
return os.path.join('../telethon/tl', normal_path)
output_base_depth = 2 # telethon/tl/
class TLGenerator: class TLGenerator:
@staticmethod def __init__(self, output_dir):
def tlobjects_exist(): self.output_dir = output_dir
def _get_file(self, *paths):
return os.path.join(self.output_dir, *paths)
def _rm_if_exists(self, filename):
file = self._get_file(filename)
if os.path.exists(file):
if os.path.isdir(file):
shutil.rmtree(file)
else:
os.remove(file)
def tlobjects_exist(self):
"""Determines whether the TLObjects were previously """Determines whether the TLObjects were previously
generated (hence exist) or not generated (hence exist) or not
""" """
return os.path.isfile(get_output_path('all_tlobjects.py')) return os.path.isfile(self._get_file('all_tlobjects.py'))
@staticmethod def clean_tlobjects(self):
def clean_tlobjects():
"""Cleans the automatically generated TLObjects from disk""" """Cleans the automatically generated TLObjects from disk"""
if os.path.isdir(get_output_path('functions')): for name in ('functions', 'types', 'all_tlobjects.py'):
shutil.rmtree(get_output_path('functions')) self._rm_if_exists(name)
if os.path.isdir(get_output_path('types')): def generate_tlobjects(self, scheme_file, import_depth):
shutil.rmtree(get_output_path('types'))
if os.path.isfile(get_output_path('all_tlobjects.py')):
os.remove(get_output_path('all_tlobjects.py'))
@staticmethod
def generate_tlobjects(scheme_file):
"""Generates all the TLObjects from scheme.tl to """Generates all the TLObjects from scheme.tl to
tl/functions and tl/types tl/functions and tl/types
""" """
# First ensure that the required parent directories exist # First ensure that the required parent directories exist
os.makedirs(get_output_path('functions'), exist_ok=True) os.makedirs(self._get_file('functions'), exist_ok=True)
os.makedirs(get_output_path('types'), exist_ok=True) os.makedirs(self._get_file('types'), exist_ok=True)
# Step 0: Cache the parsed file on a tuple # Step 0: Cache the parsed file on a tuple
tlobjects = tuple(TLParser.parse_file(scheme_file)) tlobjects = tuple(TLParser.parse_file(scheme_file))
@ -91,11 +86,11 @@ class TLGenerator:
continue continue
# Determine the output directory and create it # Determine the output directory and create it
out_dir = get_output_path('functions' out_dir = self._get_file('functions'
if tlobject.is_function else 'types') if tlobject.is_function else 'types')
# Path depth to perform relative import # Path depth to perform relative import
depth = output_base_depth depth = import_depth
if tlobject.namespace: if tlobject.namespace:
depth += 1 depth += 1
out_dir = os.path.join(out_dir, tlobject.namespace) out_dir = os.path.join(out_dir, tlobject.namespace)
@ -121,19 +116,19 @@ class TLGenerator:
tlobject, builder, depth, type_constructors) tlobject, builder, depth, type_constructors)
# Step 3: Add the relative imports to the namespaces on __init__.py's # Step 3: Add the relative imports to the namespaces on __init__.py's
init_py = os.path.join(get_output_path('functions'), '__init__.py') init_py = self._get_file('functions', '__init__.py')
with open(init_py, 'a') as file: with open(init_py, 'a') as file:
file.write('from . import {}\n' file.write('from . import {}\n'
.format(', '.join(function_namespaces))) .format(', '.join(function_namespaces)))
init_py = os.path.join(get_output_path('types'), '__init__.py') init_py = self._get_file('types', '__init__.py')
with open(init_py, 'a') as file: with open(init_py, 'a') as file:
file.write('from . import {}\n' file.write('from . import {}\n'
.format(', '.join(type_namespaces))) .format(', '.join(type_namespaces)))
# Step 4: Once all the objects have been generated, # Step 4: Once all the objects have been generated,
# we can now group them in a single file # we can now group them in a single file
filename = os.path.join(get_output_path('all_tlobjects.py')) filename = os.path.join(self._get_file('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:
builder.writeln( builder.writeln(
@ -658,13 +653,3 @@ class TLGenerator:
builder.writeln('self.result = reader.tgread_vector()') builder.writeln('self.result = reader.tgread_vector()')
else: else:
builder.writeln('self.result = reader.tgread_object()') builder.writeln('self.result = reader.tgread_object()')
if __name__ == '__main__':
if TLGenerator.tlobjects_exist():
print('Detected previous TLObjects. Cleaning...')
TLGenerator.clean_tlobjects()
print('Generating TLObjects...')
TLGenerator.generate_tlobjects('scheme.tl')
print('Done.')