From c18971da5458f561d599d351688072e1c06611db Mon Sep 17 00:00:00 2001 From: Lonami Exo Date: Sun, 15 Apr 2018 11:18:26 +0200 Subject: [PATCH] Add a new section in the docs listing known RPC errors --- telethon_generator/generators/docs.py | 25 +++++++++++++++++++++++++ telethon_generator/parsers/errors.py | 13 +++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/telethon_generator/generators/docs.py b/telethon_generator/generators/docs.py index a55f7ad9..db488854 100755 --- a/telethon_generator/generators/docs.py +++ b/telethon_generator/generators/docs.py @@ -3,6 +3,7 @@ import functools import os import re import shutil +from collections import defaultdict from ..docs_writer import DocsWriter from ..parsers import TLObject @@ -277,6 +278,11 @@ def _write_html_pages(tlobjects, errors, layer, input_res, output_dir): for t, cs in type_to_constructors.items(): type_to_constructors[t] = list(sorted(cs, key=lambda c: c.name)) + method_causes_errors = defaultdict(list) + for error in errors: + for method in error.caused_by: + method_causes_errors[method].append(error) + # Since the output directory is needed everywhere apply it now create_path_for = functools.partial(get_create_path_for, output_dir) path_for_type = functools.partial(get_path_for_type, output_dir) @@ -389,6 +395,25 @@ def _write_html_pages(tlobjects, errors, layer, input_res, output_dir): else: docs.write_text('This type has no members.') + if tlobject.is_function: + docs.write_title('Known RPC errors') + errors = method_causes_errors[tlobject.fullname] + if not errors: + docs.write_text("This request can't cause any RPC error " + "as far as we know.") + else: + docs.write_text( + 'This request can cause {} known error{}:'.format( + len(errors), '' if len(errors) == 1 else 's' + )) + docs.begin_table(column_count=2) + for error in errors: + docs.add_row('{}'.format(error.name)) + docs.add_row('{}.'.format(error.description)) + docs.end_table() + docs.write_text('You can import these from ' + 'telethon.errors.') + # TODO Bit hacky, make everything like this? (prepending '../') depth = '../' * (2 if tlobject.namespace else 1) docs.add_script(src='prependPath = "{}";'.format(depth)) diff --git a/telethon_generator/parsers/errors.py b/telethon_generator/parsers/errors.py index 03c42a6d..d5e53eda 100644 --- a/telethon_generator/parsers/errors.py +++ b/telethon_generator/parsers/errors.py @@ -51,7 +51,7 @@ def _get_class_name(error_code): class Error: - def __init__(self, int_code, str_code, description): + def __init__(self, int_code, str_code, description, caused_by): # TODO Some errors have the same str_code but different int_code # Should these be split into different files or doesn't really matter? # Telegram isn't exactly consistent with returned errors anyway. @@ -60,6 +60,7 @@ class Error: self.subclass = _get_class_name(int_code) self.subclass_exists = int_code in KNOWN_BASE_CLASSES self.description = description + self.caused_by = list(sorted(caused_by)) self.has_captures = '_X' in str_code if self.has_captures: @@ -92,6 +93,7 @@ def parse_errors(json_file, descriptions_file): data = json.load(f) errors = defaultdict(set) + error_to_method = defaultdict(set) # PWRTelegram's API doesn't return all errors, which we do need here. # Add some special known-cases manually first. errors[420].update(( @@ -105,9 +107,11 @@ def parse_errors(json_file, descriptions_file): 'NETWORK_MIGRATE_X', 'USER_MIGRATE_X' )) for int_code, method_errors in data['result'].items(): - for error_list in method_errors.values(): + for method, error_list in method_errors.items(): for error in error_list: - errors[int(int_code)].add(re.sub('_\d+', '_X', error).upper()) + error = re.sub('_\d+', '_X', error).upper() + errors[int(int_code)].add(error) + error_to_method[error].add(method) # Some errors are in the human result, but not with a code. Assume 400 for error in data['human_result']: @@ -131,11 +135,12 @@ def parse_errors(json_file, descriptions_file): for str_code in sorted(error_set): description = telethon_descriptions.get( str_code, '\n'.join(data['human_result'].get( - str_code, ['No description known.'] + str_code, ['No description known'] )) ) yield Error( int_code=int_code, str_code=str_code, description=description, + caused_by=error_to_method[str_code] )