diff --git a/README.rst b/README.rst index 9636df6b..88251354 100755 --- a/README.rst +++ b/README.rst @@ -71,7 +71,7 @@ Installing Telethon manually (`GitHub `_, `package index `_) 2. Clone Telethon's GitHub repository: ``git clone https://github.com/LonamiWebs/Telethon.git`` 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! Running Telethon @@ -232,7 +232,7 @@ Have you found a more updated version of the ``scheme.tl`` file? Those are great as grabbing the `latest version `_ 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. diff --git a/setup.py b/setup.py index dd755a32..86021e9c 100644 --- a/setup.py +++ b/setup.py @@ -3,85 +3,94 @@ See: https://packaging.python.org/en/latest/distributing.html 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 from codecs import open +from sys import argv from os import path # Always prefer setuptools over distutils 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 -with open(path.join(here, 'README.rst'), encoding='utf-8') as f: - long_description = f.read() +if __name__ == '__main__': + if len(argv) >= 2 and argv[1] == 'gen_tl': + generator = TLGenerator('telethon/tl') + if generator.tlobjects_exist(): + print('Detected previous TLObjects. Cleaning...') + generator.clean_tlobjects() -setup( - name='Telethon', + print('Generating TLObjects...') + generator.generate_tlobjects( + 'telethon_generator/scheme.tl', import_depth=2 + ) + print('Done.') - # Versions should comply with PEP440. - version=TelegramClient.__version__, - description="Python3 Telegram's client implementation with full access to its API", - long_description=long_description, + elif len(argv) >= 2 and argv[1] == 'clean_tl': + print('Cleaning...') + TLGenerator('telethon/tl').clean_tlobjects() + print('Done.') - # The project's main homepage. - url='https://github.com/LonamiWebs/Telethon', - download_url='https://github.com/LonamiWebs/Telethon/releases', + else: + if not TelegramClient: + print('Run `python3', argv[0], 'gen_tl` first.') + quit() - # Author details - author='Lonami Exo', - author_email='totufals@hotmail.com', + here = path.abspath(path.dirname(__file__)) - # Choose your license - license='MIT', + # Get the long description from the README file + 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 - classifiers=[ - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable - 'Development Status :: 3 - Alpha', + setup( + name='Telethon', - # Indicate who your project is intended for - 'Intended Audience :: Developers', - 'Topic :: Communications :: Chat', + # Versions should comply with PEP440. + version=TelegramClient.__version__, + description="Full-featured Telegram client library for Python 3", + long_description=long_description, - # Pick your license as you wish (should match "license" above) - 'License :: OSI Approved :: MIT License', + url='https://github.com/LonamiWebs/Telethon', + download_url='https://github.com/LonamiWebs/Telethon/releases', - # Specify the Python versions you support here. In particular, ensure - # that you indicate whether you support Python 2, Python 3 or both. - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', - 'Programming Language :: Python :: 3.4', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6' - ], + author='Lonami Exo', + author_email='totufals@hotmail.com', - # What does your project relate to? - keywords='Telegram API chat client MTProto', + license='MIT', - # You can just specify the packages manually here if your project is - # simple. Or you can use find_packages(). - packages=find_packages(exclude=[ - 'telethon_generator', 'telethon_tests', 'run_tests.py', - 'try_telethon.py' - ]), + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 3 - Alpha', - # List run-time dependencies here. These will be installed by pip when - # your project is installed. - install_requires=['pyaes'], + 'Intended Audience :: Developers', + 'Topic :: Communications :: Chat', - # To provide executable scripts, use entry points in preference to the - # "scripts" keyword. Entry points provide cross-platform support and allow - # pip to create the appropriate form of executable for the target platform. - entry_points={ - 'console_scripts': [ - 'gen_tl = tl_generator:clean_and_generate', - ], - }) + 'License :: OSI Approved :: MIT License', + + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', + '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'] + ) diff --git a/telethon_generator/tl_generator.py b/telethon_generator/tl_generator.py old mode 100755 new mode 100644 index 8ccc4d65..ae8fdb68 --- a/telethon_generator/tl_generator.py +++ b/telethon_generator/tl_generator.py @@ -1,51 +1,46 @@ -#!/usr/bin/env python3 import os import re import shutil from zlib import crc32 from collections import defaultdict -try: - 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/ +from .parser import SourceBuilder, TLParser class TLGenerator: - @staticmethod - def tlobjects_exist(): + def __init__(self, output_dir): + 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 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(): + def clean_tlobjects(self): """Cleans the automatically generated TLObjects from disk""" - if os.path.isdir(get_output_path('functions')): - shutil.rmtree(get_output_path('functions')) + for name in ('functions', 'types', 'all_tlobjects.py'): + self._rm_if_exists(name) - if os.path.isdir(get_output_path('types')): - 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): + def generate_tlobjects(self, scheme_file, import_depth): """Generates all the TLObjects from scheme.tl to tl/functions and tl/types """ # First ensure that the required parent directories exist - os.makedirs(get_output_path('functions'), exist_ok=True) - os.makedirs(get_output_path('types'), exist_ok=True) + os.makedirs(self._get_file('functions'), exist_ok=True) + os.makedirs(self._get_file('types'), exist_ok=True) # Step 0: Cache the parsed file on a tuple tlobjects = tuple(TLParser.parse_file(scheme_file)) @@ -91,11 +86,11 @@ class TLGenerator: continue # Determine the output directory and create it - out_dir = get_output_path('functions' - if tlobject.is_function else 'types') + out_dir = self._get_file('functions' + if tlobject.is_function else 'types') # Path depth to perform relative import - depth = output_base_depth + depth = import_depth if tlobject.namespace: depth += 1 out_dir = os.path.join(out_dir, tlobject.namespace) @@ -121,19 +116,19 @@ class TLGenerator: tlobject, builder, depth, type_constructors) # 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: file.write('from . import {}\n' .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: 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(self._get_file('all_tlobjects.py')) with open(filename, 'w', encoding='utf-8') as file: with SourceBuilder(file) as builder: builder.writeln( @@ -658,13 +653,3 @@ class TLGenerator: builder.writeln('self.result = reader.tgread_vector()') else: 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.')