Skip to content

Commit b275253

Browse files
Tobias Hafnervogti
authored andcommitted
Add field number checks for required fields
1 parent 097ba52 commit b275253

File tree

7 files changed

+77
-69
lines changed

7 files changed

+77
-69
lines changed

doc-generator/config.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,24 +10,26 @@
1010
# This file must be inside the PROTO_DIR also specified in this config.
1111
RPC_DEFINITION_FILE = 'protointerface.proto'
1212

13-
# These fields must be present in the top level request message. If on of them is missing, the documentation will not
14-
# generate and an exception will be thrown.
13+
# These fields with their corresponding message number must be present in the top level request message. If on of them
14+
# is missing, the documentation will not generate and an exception will be thrown.
15+
# Fields are specified in the forma (field_name, field_number)
1516
REQUIRED_REQUEST_FIELDS = [
16-
'id',
17-
'dbms_version_request',
18-
'connection_request',
19-
'disconnect_request'
17+
('id', 1),
18+
('dbms_version_request', 2),
19+
('connection_request', 19),
20+
('disconnect_request', 21)
2021
]
2122

22-
# These fields must be present in the top level response message. If on of them is missing, the documentation will not
23-
# generate and an exception will be thrown.
23+
# These fields with their corresponding message number must be present in the top level request message. If on of them
24+
# is missing, the documentation will not generate and an exception will be thrown.
25+
# Fields are specified in the forma (field_name, field_number)
2426
REQUIRED_RESPONSE_FIELDS = [
25-
'id',
26-
'last',
27-
'error_response',
28-
'dbms_version_response',
29-
'connection_response',
30-
'disconnect_response'
27+
('id', 1),
28+
('last', 2),
29+
('error_response', 256),
30+
('dbms_version_response', 3),
31+
('connection_response', 12),
32+
('disconnect_response', 13)
3133
]
3234

3335
# The common suffix of all rpc request messages in the top level request message.
@@ -57,8 +59,7 @@
5759
DESCRIPTOR_SET_OUT = 'descriptor_set.bin'
5860

5961
# The directory from which the imports in the .proto files are resolved.
60-
IMPORT_BASE_DIR = '../' #../org/polypheny/prism'
61-
62+
IMPORT_BASE_DIR = '../' # ../org/polypheny/prism'
6263

6364
# ----------------------------------------------------------------------------------
6465
# DOCUMENTATION
@@ -68,4 +69,4 @@
6869
README_FILE = '../README.md'
6970

7071
# The directory in which the generated documentation should be put. The directory is created if it does not exist.
71-
OUTPUT_DIR = '../doc'
72+
OUTPUT_DIR = '../doc'

doc-generator/enums.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
import utils as utils
55
import proto_utils as putils
66

7-
def get_enums_from_file_descriptor(file_descriptor, repo_path, tree_ish):
7+
8+
def _get_enums_from_file_descriptor(file_descriptor, repo_path, tree_ish):
89
content = []
910
if not hasattr(file_descriptor, 'source_code_info'):
1011
print('ERROR: No source code info!')
@@ -48,6 +49,6 @@ def enums(repo_path, tree_ish):
4849
putils.compile_file(file_path)
4950
descriptor_set = putils.load_descriptor_set()
5051
for descriptor in descriptor_set.file:
51-
content.extend(get_enums_from_file_descriptor(descriptor, repo_path, tree_ish))
52+
content.extend(_get_enums_from_file_descriptor(descriptor, repo_path, tree_ish))
5253
putils.remove_descriptor_set()
5354
return ''.join(content)

doc-generator/files.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111

1212
def proto_files(repo_path, branch_name, directory=config.PROTO_DIR):
1313
file_names = putils.get_proto_file_names(directory)
14-
return generate_file_section(directory, file_names, repo_path, branch_name)
14+
return _generate_file_section(directory, file_names, repo_path, branch_name)
1515

1616

17-
def generate_file_section(directory, file_names, repo_path, tree_ish):
17+
def _generate_file_section(directory, file_names, repo_path, tree_ish):
1818
processed = []
1919
content = []
2020
short_directory = directory.replace("../", "", 1)
@@ -25,7 +25,7 @@ def generate_file_section(directory, file_names, repo_path, tree_ish):
2525
responses_file = file.replace(REQUESTS_SUFFIX, RESPONSES_SUFFIX)
2626
if responses_file in file_names:
2727
category = file.replace(REQUESTS_SUFFIX, '')
28-
description = get_file_description(directory, file)
28+
description = _get_file_description(directory, file)
2929
file_link = utils.generate_link(repo_path, tree_ish, file, short_directory)
3030
responses_file_link = utils.generate_link(repo_path, tree_ish, responses_file, short_directory)
3131
content.append(gen.generate_paired_file_entry(category, file, responses_file, description, file_link, responses_file_link))
@@ -36,14 +36,14 @@ def generate_file_section(directory, file_names, repo_path, tree_ish):
3636
raise FileExistsError(f"No matching responses file found for {file}.")
3737
elif not file.endswith(REQUESTS_SUFFIX) and not file.endswith(RESPONSES_SUFFIX):
3838
category = file.replace('.proto', '')
39-
description = get_file_description(directory, file)
39+
description = _get_file_description(directory, file)
4040
file_link = utils.generate_link(repo_path, tree_ish, file, short_directory)
4141
content.append(gen.generate_single_file_entry(category, file, description, file_link))
4242
processed.append(file)
4343
return ''.join(content)
4444

4545

46-
def get_file_description(directory, file_name):
46+
def _get_file_description(directory, file_name):
4747
path = os.path.join(directory, file_name)
4848
try:
4949
with open(path, 'r') as file:

doc-generator/generator.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,18 +165,18 @@ def generate_single_file_entry(category, file, description, file_link=None):
165165
return entry
166166

167167

168-
def create_directory(directory):
168+
def _create_directory(directory):
169169
if not os.path.exists(directory):
170170
os.makedirs(directory)
171171

172172

173-
def write_to_file(file, text):
173+
def _write_to_file(file, text):
174174
with open(file, 'w') as file:
175175
file.write(text)
176176

177177

178178
def main(repo_path, tree_ish):
179-
create_directory(config.OUTPUT_DIR)
179+
_create_directory(config.OUTPUT_DIR)
180180

181181
tasks = [
182182
generate_overview_doc,
@@ -186,7 +186,7 @@ def main(repo_path, tree_ish):
186186
for task in tasks:
187187
file, text = task(repo_path, tree_ish)
188188
path = os.path.join(config.OUTPUT_DIR, file)
189-
write_to_file(path, text)
189+
_write_to_file(path, text)
190190

191191

192192
if __name__ == '__main__':

doc-generator/messages.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import utils as utils
99

1010

11-
def get_messages_from_file_descriptor(file_descriptor, repo_path, tree_ish):
11+
def _get_messages_from_file_descriptor(file_descriptor, repo_path, tree_ish):
1212
content = []
1313
if not hasattr(file_descriptor, 'source_code_info'):
1414
print('ERROR: No source code info!')
@@ -46,6 +46,6 @@ def messages(repo_path, branch_name):
4646
putils.compile_file(file_path)
4747
descriptor_set = putils.load_descriptor_set()
4848
for descriptor in descriptor_set.file:
49-
content.extend(get_messages_from_file_descriptor(descriptor, repo_path, branch_name))
49+
content.extend(_get_messages_from_file_descriptor(descriptor, repo_path, branch_name))
5050
putils.remove_descriptor_set()
5151
return ''.join(content)

doc-generator/proto_utils.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import os
22
import subprocess
3-
import config
4-
from google.protobuf import descriptor_pb2
53

4+
from google.protobuf import descriptor_pb2
65

6+
import config
77

88

99
def get_proto_file_names(directory):
@@ -48,7 +48,7 @@ def get_description_for_location(source_code_info, path):
4848
return ''
4949

5050

51-
def get_source_from_span(span, file_path):
51+
def _get_source_from_span(span, file_path):
5252
start_line, start_column, length_in_chars = span
5353
length_in_chars -= 2
5454
end_position = start_column + length_in_chars
@@ -61,7 +61,7 @@ def get_source_from_span(span, file_path):
6161
if i < start_line:
6262
continue
6363
if i == start_line + 1:
64-
line = line[start_column:start_column+length_in_chars]
64+
line = line[start_column:start_column + length_in_chars]
6565
if current_char_count + len(line) >= end_position:
6666
segment += line[:end_position - current_char_count]
6767
break
@@ -75,7 +75,7 @@ def get_field_type(source_code_info, location_path, file_path):
7575
location_path.append(4)
7676
for location in source_code_info.location:
7777
if list(location.path) == location_path:
78-
return get_source_from_span(location.span, file_path)
78+
return _get_source_from_span(location.span, file_path)
7979
return ''
8080

8181

doc-generator/rpc.py

Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
import os
77
import config
88

9-
109
RPC_DEFINITION_FILE = os.path.join(config.PROTO_DIR, config.RPC_DEFINITION_FILE)
1110

11+
1212
def get_rpcs_from_sets(descriptor, matches, single_responses, single_requests, repo_path, tree_ish, request_path,
1313
response_path):
1414
content = []
@@ -22,13 +22,15 @@ def get_rpcs_from_sets(descriptor, matches, single_responses, single_requests, r
2222

2323
request_type = request[1].type_name.split('.')[-1]
2424
line = putils.get_line_number_for_location(descriptor.source_code_info, message_path)
25-
request_link = utils.generate_link(repo_path, tree_ish, os.path.basename(RPC_DEFINITION_FILE), short_directory, line)
25+
request_link = utils.generate_link(repo_path, tree_ish, os.path.basename(RPC_DEFINITION_FILE), short_directory,
26+
line)
2627
content.append(gen.generate_rpc_message(request_type, request[1].name, True, request_link))
2728

2829
response_type = response[1].type_name.split('.')[-1]
2930
message_path = [4, response_path, 2, response[0]]
3031
line = putils.get_line_number_for_location(descriptor.source_code_info, message_path)
31-
response_link = utils.generate_link(repo_path, tree_ish, os.path.basename(RPC_DEFINITION_FILE), short_directory, line)
32+
response_link = utils.generate_link(repo_path, tree_ish, os.path.basename(RPC_DEFINITION_FILE), short_directory,
33+
line)
3234
content.append(gen.generate_rpc_message(response_type, response[1].name, False, response_link))
3335

3436
for single_request in single_requests:
@@ -39,7 +41,8 @@ def get_rpcs_from_sets(descriptor, matches, single_responses, single_requests, r
3941

4042
request_type = single_request[1].type_name.split('.')[-1]
4143
line = putils.get_line_number_for_location(descriptor.source_code_info, message_path)
42-
request_link = utils.generate_link(repo_path, tree_ish, os.path.basename(RPC_DEFINITION_FILE), short_directory, line)
44+
request_link = utils.generate_link(repo_path, tree_ish, os.path.basename(RPC_DEFINITION_FILE), short_directory,
45+
line)
4346
content.append(gen.generate_rpc_message(request_type, single_request[1].name, False, request_link))
4447

4548
for single_response in single_responses:
@@ -50,7 +53,8 @@ def get_rpcs_from_sets(descriptor, matches, single_responses, single_requests, r
5053

5154
request_type = single_response[1].type_name.split('.')[-1]
5255
line = putils.get_line_number_for_location(descriptor.source_code_info, message_path)
53-
request_link = utils.generate_link(repo_path, tree_ish, os.path.basename(RPC_DEFINITION_FILE), short_directory, line)
56+
request_link = utils.generate_link(repo_path, tree_ish, os.path.basename(RPC_DEFINITION_FILE), short_directory,
57+
line)
5458
content.append(gen.generate_rpc_message(request_type, single_response[1].name, True, request_link))
5559

5660
return content
@@ -62,17 +66,17 @@ def rpc(repo_path, tree_ish):
6266
descriptor_set = putils.load_descriptor_set()
6367
for descriptor in descriptor_set.file:
6468
check_required_fields(descriptor)
65-
matches, single_responses, single_requests = get_rpc_sets_from_file_descriptor(descriptor)
66-
requests_path, _ = get_message_descriptor(descriptor, config.REQUESTS_MESSAGE_NAME)
67-
responses_path, _ = get_message_descriptor(descriptor, config.RESPONSES_MESSAGE_NAME)
69+
matches, single_responses, single_requests = _get_rpc_sets_from_file_descriptor(descriptor)
70+
requests_path, _ = _get_message_descriptor(descriptor, config.REQUESTS_MESSAGE_NAME)
71+
responses_path, _ = _get_message_descriptor(descriptor, config.RESPONSES_MESSAGE_NAME)
6872
content.extend(get_rpcs_from_sets(descriptor, matches, single_responses, single_requests, repo_path, tree_ish,
6973
requests_path, responses_path))
7074
return ''.join(content)
7175

7276

73-
def get_message_field_descriptors(file_descriptor, message_name):
77+
def _get_message_field_descriptors(file_descriptor, message_name):
7478
message_descriptors = []
75-
_, message_descriptor = get_message_descriptor(file_descriptor, message_name)
79+
_, message_descriptor = _get_message_descriptor(file_descriptor, message_name)
7680
if not message_descriptor:
7781
raise Exception(f'No message with name "{message_name}" found.')
7882
for field_id, field in enumerate(message_descriptor.field):
@@ -82,29 +86,29 @@ def get_message_field_descriptors(file_descriptor, message_name):
8286
return message_descriptors
8387

8488

85-
def get_message_descriptor(file_descriptor, message_name):
89+
def _get_message_descriptor(file_descriptor, message_name):
8690
for message_index, message in enumerate(file_descriptor.message_type):
8791
if message.name == message_name:
8892
return message_index, message
8993
return None
9094

9195

92-
def is_request_present(file_descriptor):
93-
return get_message_descriptor(file_descriptor, config.REQUESTS_MESSAGE_NAME) is not None
96+
def _is_request_present(file_descriptor):
97+
return _get_message_descriptor(file_descriptor, config.REQUESTS_MESSAGE_NAME) is not None
9498

9599

96-
def is_response_resent(file_descriptor):
97-
return get_message_descriptor(file_descriptor, config.RESPONSES_MESSAGE_NAME) is not None
100+
def _is_response_resent(file_descriptor):
101+
return _get_message_descriptor(file_descriptor, config.RESPONSES_MESSAGE_NAME) is not None
98102

99103

100-
def get_rpc_sets_from_file_descriptor(file_descriptor):
101-
if not is_request_present(file_descriptor):
104+
def _get_rpc_sets_from_file_descriptor(file_descriptor):
105+
if not _is_request_present(file_descriptor):
102106
raise Exception('Request message not present.')
103-
if not is_response_resent(file_descriptor):
107+
if not _is_response_resent(file_descriptor):
104108
raise Exception('Response message not present.')
105-
request_messages = get_message_field_descriptors(file_descriptor, config.REQUESTS_MESSAGE_NAME)
106-
response_messages = get_message_field_descriptors(file_descriptor, config.RESPONSES_MESSAGE_NAME)
107-
matches, leftover_requests, leftover_responses = get_matches(request_messages, response_messages)
109+
request_messages = _get_message_field_descriptors(file_descriptor, config.REQUESTS_MESSAGE_NAME)
110+
response_messages = _get_message_field_descriptors(file_descriptor, config.RESPONSES_MESSAGE_NAME)
111+
matches, leftover_requests, leftover_responses = _get_matches(request_messages, response_messages)
108112
for left_request in leftover_requests:
109113
if left_request[1].name.endswith(config.REQUESTS_MESSAGE_NAME):
110114
raise Exception(f'No matching response for {left_request.name}')
@@ -114,7 +118,7 @@ def get_rpc_sets_from_file_descriptor(file_descriptor):
114118
return matches, leftover_requests, leftover_responses
115119

116120

117-
def get_matches(requests, responses):
121+
def _get_matches(requests, responses):
118122
matches = []
119123
leftover_requests = []
120124
leftover_responses = responses.copy()
@@ -134,16 +138,18 @@ def get_matches(requests, responses):
134138

135139

136140
def check_required_fields(file_descriptor):
137-
_, request_descriptor = get_message_descriptor(file_descriptor, config.REQUESTS_MESSAGE_NAME)
138-
request_fields = [field.name for field in request_descriptor.field]
139-
for required_field in config.REQUIRED_REQUEST_FIELDS:
140-
if required_field in request_fields:
141-
continue
142-
raise Exception(f'Required field "{required_field}" not present in request message.')
141+
_, request_descriptor = _get_message_descriptor(file_descriptor, config.REQUESTS_MESSAGE_NAME)
142+
request_fields = {field.name: field.number for field in request_descriptor.field}
143+
_check_for_missing_fields(request_fields, config.REQUIRED_REQUEST_FIELDS)
143144

144-
_, response_descriptor = get_message_descriptor(file_descriptor, config.RESPONSES_MESSAGE_NAME)
145-
response_fields = [field.name for field in response_descriptor.field]
146-
for required_field in config.REQUIRED_RESPONSE_FIELDS:
147-
if required_field in response_fields:
148-
continue
149-
raise Exception(f'Required field "{required_field}" not present in response message.')
145+
_, response_descriptor = _get_message_descriptor(file_descriptor, config.RESPONSES_MESSAGE_NAME)
146+
response_fields = {field.name: field.number for field in response_descriptor.field}
147+
_check_for_missing_fields(response_fields, config.REQUIRED_RESPONSE_FIELDS)
148+
149+
150+
def _check_for_missing_fields(existing_fields, required_fields):
151+
for required_field_name, required_field_number in required_fields:
152+
if required_field_name not in existing_fields:
153+
raise Exception(f'Required field "{required_field_name}" not present in response message.')
154+
if existing_fields[required_field_name] != required_field_number:
155+
raise Exception(f'Required field "{required_field_name}" in response message has incorrect number. Expected {required_field_number}, got {existing_fields[required_field_name]}.')

0 commit comments

Comments
 (0)