diff --git a/setup.py b/setup.py index 45fae593..cec63880 100755 --- a/setup.py +++ b/setup.py @@ -16,6 +16,7 @@ import re import shutil from os import chdir from pathlib import Path +from subprocess import run from sys import argv from setuptools import find_packages, setup @@ -30,11 +31,11 @@ class TempWorkDir: def __enter__(self): self.original = Path('.') - chdir(Path(__file__).parent) + chdir(str(Path(__file__).parent)) return self def __exit__(self, *args): - chdir(self.original) + chdir(str(self.original)) GENERATOR_DIR = Path('telethon_generator') @@ -96,7 +97,7 @@ def generate(which): if ERRORS_OUT.is_file(): ERRORS_OUT.unlink() else: - with open(ERRORS_OUT, 'w', encoding='utf-8') as file: + with ERRORS_OUT.open('w') as file: generate_errors(errors, file) if 'docs' in which: @@ -104,7 +105,7 @@ def generate(which): print(action, 'documentation...') if clean: if DOCS_OUT.is_dir(): - shutil.rmtree(DOCS_OUT) + shutil.rmtree(str(DOCS_OUT)) else: generate_docs(tlobjects, methods, layer, DOCS_IN_RES, DOCS_OUT) @@ -154,18 +155,13 @@ def main(): print('Packaging for PyPi aborted, importing the module failed.') return - # Need python3.5 or higher, but Telethon is supposed to support 3.x - # Place it here since noone should be running ./setup.py pypi anyway - from subprocess import run - from shutil import rmtree - for x in ('build', 'dist', 'Telethon.egg-info'): - rmtree(x, ignore_errors=True) + shutil.rmtree(x, ignore_errors=True) run('python3 setup.py sdist', shell=True) run('python3 setup.py bdist_wheel', shell=True) run('twine upload dist/*', shell=True) for x in ('build', 'dist', 'Telethon.egg-info'): - rmtree(x, ignore_errors=True) + shutil.rmtree(x, ignore_errors=True) else: # e.g. install from GitHub diff --git a/telethon_generator/docswriter.py b/telethon_generator/docswriter.py index 1eb92e63..595fe931 100644 --- a/telethon_generator/docswriter.py +++ b/telethon_generator/docswriter.py @@ -54,7 +54,7 @@ class DocsWriter:
''', title=title, - rel_css=relative_css_path.rstrip('/'), + rel_css=str(relative_css_path).rstrip('/'), def_css=default_css ) @@ -278,10 +278,7 @@ class DocsWriter: # With block def __enter__(self): # Sanity check - parent = os.path.dirname(self.filename) - if parent: - os.makedirs(parent, exist_ok=True) - + self.filename.parent.mkdir(parents=True, exist_ok=True) self.handle = open(self.filename, 'w', encoding='utf-8') return self diff --git a/telethon_generator/generators/docs.py b/telethon_generator/generators/docs.py index d80ce86b..2c03b03f 100755 --- a/telethon_generator/generators/docs.py +++ b/telethon_generator/generators/docs.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 -import csv import functools import os import re import shutil from collections import defaultdict +from pathlib import Path from ..docswriter import DocsWriter from ..parsers import TLObject, Usability @@ -35,14 +35,14 @@ def get_import_code(tlobject): def _get_create_path_for(root, tlobject, make=True): """Creates and returns the path for the given TLObject at root.""" - out_dir = 'methods' if tlobject.is_function else 'constructors' + out_dir = root / ('methods' if tlobject.is_function else 'constructors') if tlobject.namespace: - out_dir = os.path.join(out_dir, tlobject.namespace) + out_dir /= tlobject.namespace - out_dir = os.path.join(root, out_dir) if make: - os.makedirs(out_dir, exist_ok=True) - return os.path.join(out_dir, _get_file_name(tlobject)) + out_dir.mkdir(parents=True, exist_ok=True) + + return out_dir / _get_file_name(tlobject) def _get_path_for_type(root, type_, relative_to='.'): @@ -55,15 +55,17 @@ def _get_path_for_type(root, type_, relative_to='.'): else: path = 'types/%s' % _get_file_name(type_) - return _get_relative_path(os.path.join(root, path), relative_to) + return _get_relative_path(root / path, relative_to) def _get_relative_path(destination, relative_to, folder=False): """Return the relative path to destination from relative_to.""" + relative_to = Path(relative_to) if not folder: - relative_to = os.path.dirname(relative_to) + relative_to = relative_to.parent - return os.path.relpath(destination, start=relative_to) + # TODO Use pathlib here + return Path(os.path.relpath(destination, start=relative_to)) def _find_title(html_file): @@ -83,7 +85,7 @@ def _build_menu(docs, filename, root, relative_main_index): filename = _get_relative_path(filename, root) docs.add_menu('API', relative_main_index) - items = filename.split('/') + items = str(filename).split('/') for i in range(len(items) - 1): item = items[i] link = '../' * (len(items) - (i + 2)) @@ -106,8 +108,8 @@ def _generate_index(folder, original_paths, root, BOT_INDEX = 'botindex.html' if not bots_index: - for item in os.listdir(folder): - if os.path.isdir(os.path.join(folder, item)): + for item in folder.iterdir(): + if item.is_dir(): namespaces.append(item) elif item not in (INDEX, BOT_INDEX): files.append(item) @@ -115,7 +117,7 @@ def _generate_index(folder, original_paths, root, # bots_index_paths should be a list of "namespace/method.html" # or "method.html" for item in bots_index_paths: - dirname = os.path.dirname(item) + dirname = item.parent if dirname and dirname not in namespaces: namespaces.append(dirname) elif not dirname and item not in (INDEX, BOT_INDEX): @@ -125,10 +127,10 @@ def _generate_index(folder, original_paths, root, for k, v in original_paths.items()} # Now that everything is setup, write the index.html file - filename = os.path.join(folder, BOT_INDEX if bots_index else INDEX) + filename = folder / (BOT_INDEX if bots_index else INDEX) with DocsWriter(filename, type_to_path=_get_path_for_type) as docs: # Title should be the current folder name - docs.write_head(folder.title(), + docs.write_head(str(folder).title(), relative_css_path=paths['css'], default_css=original_paths['default_css']) @@ -136,7 +138,9 @@ def _generate_index(folder, original_paths, root, _build_menu(docs, filename, root, relative_main_index=paths['index_all']) - docs.write_title(_get_relative_path(folder, root, folder=True).title()) + docs.write_title(str( + _get_relative_path(folder, root, folder=True)).title()) + if bots_index: docs.write_text('These are the methods that you may be able to ' 'use as a bot. Click here to ' @@ -153,24 +157,23 @@ def _generate_index(folder, original_paths, root, namespace_paths = [] if bots_index: for item in bots_index_paths: - if os.path.dirname(item) == namespace: - namespace_paths.append(os.path.basename(item)) - _generate_index(os.path.join(folder, namespace), + # TODO .name? or not + if item.parent.name == namespace: + namespace_paths.append(item.name) + _generate_index(folder / namespace, original_paths, root, bots_index, namespace_paths) if bots_index: - docs.add_row(namespace.title(), - link=os.path.join(namespace, BOT_INDEX)) + docs.add_row(namespace.title(), link=namespace / BOT_INDEX) else: - docs.add_row(namespace.title(), - link=os.path.join(namespace, INDEX)) + docs.add_row(namespace.title(), link=namespace / INDEX) docs.end_table() docs.write_title('Available items') docs.begin_table(2) - files = [(f, _find_title(os.path.join(folder, f))) for f in files] + files = [(f, _find_title(folder / f)) for f in files] files.sort(key=lambda t: t[1]) for file, title in files: @@ -250,9 +253,7 @@ def _write_html_pages(tlobjects, methods, layer, input_res, output_dir): 'index_methods': 'methods/index.html', 'index_constructors': 'constructors/index.html' } - original_paths = {k: os.path.join(output_dir, v) - for k, v in original_paths.items()} - + original_paths = {k: output_dir / v for k, v in original_paths.items()} original_paths['default_css'] = 'light' # docs..css, local path type_to_constructors = defaultdict(list) type_to_functions = defaultdict(list) @@ -443,16 +444,17 @@ def _write_html_pages(tlobjects, methods, layer, input_res, output_dir): temp = [] for item in bot_docs_paths: - temp.append(os.path.sep.join(item.split(os.path.sep)[2:])) + # TODO What? + temp.append(os.path.sep.join(str(item).split(os.path.sep)[2:])) bot_docs_paths = temp # Find all the available types (which are not the same as the constructors) # Each type has a list of constructors associated to it, hence is a map for t, cs in type_to_constructors.items(): filename = path_for_type(t) - out_dir = os.path.dirname(filename) + out_dir = filename.parent if out_dir: - os.makedirs(out_dir, exist_ok=True) + out_dir.mkdir(parents=True, exist_ok=True) # Since we don't have access to the full TLObject, split the type if '.' in t: @@ -570,10 +572,10 @@ def _write_html_pages(tlobjects, methods, layer, input_res, output_dir): # information that we have available, simply a file listing all the others # accessible by clicking on their title for folder in ['types', 'methods', 'constructors']: - _generate_index(os.path.join(output_dir, folder), original_paths, + _generate_index(output_dir / folder, original_paths, output_dir) - _generate_index(os.path.join(output_dir, 'methods'), original_paths, + _generate_index(output_dir / 'methods', original_paths, output_dir, True, bot_docs_paths) # Write the final core index, the main index for the rest of files @@ -596,8 +598,8 @@ def _write_html_pages(tlobjects, methods, layer, input_res, output_dir): methods = sorted(methods, key=lambda m: m.name) cs = sorted(cs, key=lambda c: c.name) - shutil.copy(os.path.join(input_res, '404.html'), original_paths['404']) - _copy_replace(os.path.join(input_res, 'core.html'), + shutil.copy(str(input_res / '404.html'), str(original_paths['404'])) + _copy_replace(input_res / 'core.html', original_paths['index_all'], { '{type_count}': len(types), '{method_count}': len(methods), @@ -630,10 +632,8 @@ def _write_html_pages(tlobjects, methods, layer, input_res, output_dir): type_urls = fmt(types, path_for_type) constructor_urls = fmt(cs, create_path_for) - os.makedirs(os.path.abspath(os.path.join( - original_paths['search.js'], os.path.pardir - )), exist_ok=True) - _copy_replace(os.path.join(input_res, 'js', 'search.js'), + original_paths['search.js'].parent.mkdir(parents=True, exist_ok=True) + _copy_replace(input_res / 'js/search.js', original_paths['search.js'], { '{request_names}': request_names, '{type_names}': type_names, @@ -647,13 +647,13 @@ def _write_html_pages(tlobjects, methods, layer, input_res, output_dir): def _copy_resources(res_dir, out_dir): for dirname, files in [('css', ['docs.light.css', 'docs.dark.css']), ('img', ['arrow.svg'])]: - dirpath = os.path.join(out_dir, dirname) - os.makedirs(dirpath, exist_ok=True) + dirpath = out_dir / dirname + dirpath.mkdir(parents=True, exist_ok=True) for file in files: - shutil.copy(os.path.join(res_dir, dirname, file), dirpath) + shutil.copy(str(res_dir / dirname / file), str(dirpath)) def generate_docs(tlobjects, methods, layer, input_res, output_dir): - os.makedirs(output_dir, exist_ok=True) + output_dir.mkdir(parents=True, exist_ok=True) _write_html_pages(tlobjects, methods, layer, input_res, output_dir) _copy_resources(input_res, output_dir) diff --git a/telethon_generator/generators/tlobject.py b/telethon_generator/generators/tlobject.py index 0bcd983d..8e58a1ba 100644 --- a/telethon_generator/generators/tlobject.py +++ b/telethon_generator/generators/tlobject.py @@ -48,11 +48,10 @@ PATCHED_TYPES = { def _write_modules( out_dir, depth, kind, namespace_tlobjects, type_constructors): # namespace_tlobjects: {'namespace', [TLObject]} - os.makedirs(out_dir, exist_ok=True) + out_dir.mkdir(parents=True, exist_ok=True) for ns, tlobjects in namespace_tlobjects.items(): - file = os.path.join(out_dir, '{}.py'.format(ns or '__init__')) - with open(file, 'w', encoding='utf-8') as f,\ - SourceBuilder(f) as builder: + file = out_dir / '{}.py'.format(ns or '__init__') + with file.open('w') as f, SourceBuilder(f) as builder: builder.writeln(AUTO_GEN_NOTICE) builder.writeln('from {}.tl.tlobject import TLObject', '.' * depth) @@ -635,11 +634,10 @@ def _write_arg_read_code(builder, arg, args, name): def _write_patched(out_dir, namespace_tlobjects): - os.makedirs(out_dir, exist_ok=True) + out_dir.mkdir(parents=True, exist_ok=True) for ns, tlobjects in namespace_tlobjects.items(): - file = os.path.join(out_dir, '{}.py'.format(ns or '__init__')) - with open(file, 'w', encoding='utf-8') as f,\ - SourceBuilder(f) as builder: + file = out_dir / '{}.py'.format(ns or '__init__') + with file.open('w') as f, SourceBuilder(f) as builder: builder.writeln(AUTO_GEN_NOTICE) builder.writeln('import struct') @@ -715,26 +713,24 @@ def generate_tlobjects(tlobjects, layer, import_depth, output_dir): if tlobject.fullname in PATCHED_TYPES: namespace_patched[tlobject.namespace].append(tlobject) - get_file = functools.partial(os.path.join, output_dir) - _write_modules(get_file('functions'), import_depth, 'TLRequest', + _write_modules(output_dir / 'functions', import_depth, 'TLRequest', namespace_functions, type_constructors) - _write_modules(get_file('types'), import_depth, 'TLObject', + _write_modules(output_dir / 'types', import_depth, 'TLObject', namespace_types, type_constructors) - _write_patched(get_file('patched'), namespace_patched) + _write_patched(output_dir / 'patched', namespace_patched) - filename = os.path.join(get_file('alltlobjects.py')) - with open(filename, 'w', encoding='utf-8') as file: + filename = output_dir / 'alltlobjects.py' + with filename.open('w') as file: with SourceBuilder(file) as builder: _write_all_tlobjects(tlobjects, layer, builder) def clean_tlobjects(output_dir): - get_file = functools.partial(os.path.join, output_dir) for d in ('functions', 'types'): - d = get_file(d) - if os.path.isdir(d): - shutil.rmtree(d) + d = output_dir / d + if d.is_dir(): + shutil.rmtree(str(d)) - tl = get_file('alltlobjects.py') - if os.path.isfile(tl): - os.remove(tl) + tl = output_dir / 'alltlobjects.py' + if tl.is_file(): + tl.unlink() diff --git a/telethon_generator/parsers/errors.py b/telethon_generator/parsers/errors.py index ed32531f..e583e844 100644 --- a/telethon_generator/parsers/errors.py +++ b/telethon_generator/parsers/errors.py @@ -57,7 +57,7 @@ def parse_errors(csv_file): Parses the input CSV file with columns (name, error codes, description) and yields `Error` instances as a result. """ - with open(csv_file, newline='') as f: + with csv_file.open(newline='') as f: f = csv.reader(f) next(f, None) # header for line, (name, codes, description) in enumerate(f, start=2): diff --git a/telethon_generator/parsers/methods.py b/telethon_generator/parsers/methods.py index fef06953..7911c07c 100644 --- a/telethon_generator/parsers/methods.py +++ b/telethon_generator/parsers/methods.py @@ -30,7 +30,7 @@ def parse_methods(csv_file, errors_dict): Parses the input CSV file with columns (method, usability, errors) and yields `MethodInfo` instances as a result. """ - with open(csv_file, newline='') as f: + with csv_file.open(newline='') as f: f = csv.reader(f) next(f, None) # header for line, (method, usability, errors) in enumerate(f, start=2): diff --git a/telethon_generator/parsers/tlobject/parser.py b/telethon_generator/parsers/tlobject/parser.py index 50333ef4..2134eef8 100644 --- a/telethon_generator/parsers/tlobject/parser.py +++ b/telethon_generator/parsers/tlobject/parser.py @@ -86,7 +86,7 @@ def parse_tl(file_path, layer, methods=None, ignored_ids=CORE_TYPES): obj_all = [] obj_by_name = {} obj_by_type = collections.defaultdict(list) - with open(file_path, 'r', encoding='utf-8') as file: + with file_path.open() as file: is_function = False for line in file: comment_index = line.find('//')