neobuilder6 6.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. neobuilder6/__init__.py +5 -0
  2. neobuilder6/cli/__init__.py +0 -0
  3. neobuilder6/cli/neobuilder.py +48 -0
  4. neobuilder6/data/templates/dataclass.jinja2 +12 -0
  5. neobuilder6/data/templates/dataclass_module.jinja2 +34 -0
  6. neobuilder6/data/templates/grpc_receiver.jinja2 +21 -0
  7. neobuilder6/data/templates/grpc_sender.jinja2 +21 -0
  8. neobuilder6/data/templates/init.jinja2 +0 -0
  9. neobuilder6/data/templates/interface.jinja2 +22 -0
  10. neobuilder6/data/templates/macros/indentclude.jinja2 +2 -0
  11. neobuilder6/data/templates/package_aliases.jinja2 +10 -0
  12. neobuilder6/data/templates/parts/_enum_map.jinja2 +1 -0
  13. neobuilder6/data/templates/parts/_interface_method.jinja2 +2 -0
  14. neobuilder6/data/templates/parts/_interface_service.jinja2 +10 -0
  15. neobuilder6/data/templates/parts/_nested_messages.jinja2 +1 -0
  16. neobuilder6/data/templates/root_init.jinja2 +12 -0
  17. neobuilder6/descwrap/__init__.py +2 -0
  18. neobuilder6/descwrap/_field.py +188 -0
  19. neobuilder6/descwrap/_method.py +57 -0
  20. neobuilder6/generators/__init__.py +0 -0
  21. neobuilder6/generators/servicebuilders/__init__.py +27 -0
  22. neobuilder6/generators/servicebuilders/base.py +99 -0
  23. neobuilder6/generators/servicebuilders/grpc_receiver.py +92 -0
  24. neobuilder6/generators/servicebuilders/grpc_sender.py +65 -0
  25. neobuilder6/generators/servicebuilders/grpc_server.py +54 -0
  26. neobuilder6/generators/servicebuilders/implementation.py +49 -0
  27. neobuilder6/generators/servicebuilders/interface.py +84 -0
  28. neobuilder6/generators/symbols/__init__.py +4 -0
  29. neobuilder6/generators/symbols/common.py +68 -0
  30. neobuilder6/generators/symbols/dataclass.py +471 -0
  31. neobuilder6/generators/symbols/modules.py +232 -0
  32. neobuilder6/generators/symbols/service.py +139 -0
  33. neobuilder6/neobuilder/__init__.py +455 -0
  34. neobuilder6/neobuilder/render/__init__.py +66 -0
  35. neobuilder6/neobuilder/render/renderer.py +37 -0
  36. neobuilder6/structs/__init__.py +5 -0
  37. neobuilder6/structs/_base.py +3 -0
  38. neobuilder6/structs/protofile.py +20 -0
  39. neobuilder6/structs/pytype.py +91 -0
  40. neobuilder6-6.1.0.dist-info/METADATA +231 -0
  41. neobuilder6-6.1.0.dist-info/RECORD +45 -0
  42. neobuilder6-6.1.0.dist-info/WHEEL +5 -0
  43. neobuilder6-6.1.0.dist-info/entry_points.txt +3 -0
  44. neobuilder6-6.1.0.dist-info/licenses/LICENSE +22 -0
  45. neobuilder6-6.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,5 @@
1
+ __version__ = '6.1.0'
2
+
3
+ __author__ = 'Thordur Matthiasson <doddi79@gmail.com>'
4
+ __license__ = 'MIT License'
5
+ __copyright__ = 'Copyright 2026 - Thordur Matthiasson, Copyright 2019-2024 - CCP Games ehf'
File without changes
@@ -0,0 +1,48 @@
1
+ import argparse
2
+
3
+ from neobuilder6.neobuilder import NeoBuilder
4
+
5
+
6
+ def main():
7
+ parser = argparse.ArgumentParser(prog='neobuild',
8
+ description='Builds neobuf packages with protoplasm6.',
9
+ epilog=(f'Neobuilder6 v{NeoBuilder.neobuilder_version()} - '
10
+ f'Protoplasm6 v{NeoBuilder.protoplasm_version()}'))
11
+ version_group = parser.add_mutually_exclusive_group()
12
+ version_group.add_argument('-m', '--major', action="store_true",
13
+ help='Bump the major version number instead of the minor')
14
+ version_group.add_argument('-p', '--patch', action="store_true",
15
+ help='Bump the patch version number instead of the minor')
16
+ parser.add_argument('package', help='Package name')
17
+ parser.add_argument('protopath', help='Path to the root of the protobuf files (default="./proto")',
18
+ default='./proto', nargs='?')
19
+ parser.add_argument('-b', '--buildroot', help='Path to the root of the output build files (default="./build")',
20
+ default='./build', nargs='?')
21
+ parser.add_argument('-v', '--verbose', action="store_true",
22
+ help='Spits out DEBUG level logs')
23
+ parser.add_argument('-i', '--pyi', action=argparse.BooleanOptionalAction, default=True,
24
+ help='Builds *.pyi type stubs for the pb2 files as well (default=True, use --no-pyi to skip)')
25
+ parser.add_argument('--alias-imports', action=argparse.BooleanOptionalAction, default=True,
26
+ help='Alias imports everything in each proto package in the __init__.py of the '
27
+ 'corresponding Python package, e.g. so "from myshop.orders import *" works '
28
+ '(default=True, use --no-alias-imports to skip)')
29
+ parser.add_argument('-I', '--include', action='append', help="Optional additional proto paths to include (can be used multiple times)", default=[])
30
+
31
+ args = parser.parse_args()
32
+
33
+ n = NeoBuilder(
34
+ package=args.package,
35
+ protopath=args.protopath,
36
+ build_root=args.buildroot,
37
+ major=args.major,
38
+ patch=args.patch,
39
+ verbose=args.verbose,
40
+ include_pyi=args.pyi,
41
+ extra_includes=args.include,
42
+ alias_imports=args.alias_imports,
43
+ )
44
+ n.build()
45
+
46
+
47
+ if __name__ == '__main__':
48
+ main()
@@ -0,0 +1,12 @@
1
+ {% from 'macros/indentclude.jinja2' import indentclude with context %}
2
+ @dataclasses.dataclass
3
+ class {{ class_name }}(bases.DataclassBase):
4
+ __proto_cls__ = pb2.{{ proto_cls_name }}
5
+
6
+ {{ indentclude('parts/_nested_messages.jinja2', 4) }}
7
+
8
+ {{ indentclude('parts/_enum_map.jinja2', 4) }}
9
+
10
+ {% for pf in field_map %}
11
+ {{ pf }}
12
+ {% endfor %}
@@ -0,0 +1,34 @@
1
+ # Auto-Generated file - DO NOT EDIT!
2
+ # Source module: {{ module_full_name }}
3
+ # Generated at: {{ iso_timestamp }}
4
+ from __future__ import annotations
5
+ __all__ = [
6
+ {% for a in all_list %}
7
+ '{{ a }}',
8
+ {% endfor %}
9
+ ]
10
+ import dataclasses
11
+ import datetime
12
+ import enum
13
+ import typing
14
+ from protoplasm6.casting import dictators
15
+ from protoplasm6 import plasm
16
+ {{ imports }}
17
+ {{ proto_import }}
18
+
19
+ import logging
20
+ log = logging.getLogger(__name__)
21
+
22
+
23
+ {% if enum_list %}
24
+ {% for enum in enum_list %}
25
+ {{ enum }}
26
+
27
+ {% endfor %}
28
+ {% endif %}
29
+ {% if message_list %}
30
+ {% for msg in message_list %}
31
+ {{ msg }}
32
+
33
+ {% endfor -%}
34
+ {%- endif -%}
@@ -0,0 +1,21 @@
1
+ # Auto-Generated file - DO NOT EDIT!
2
+ # Source module: {{ module_full_name }}
3
+ # Generated at: {{ iso_timestamp }}
4
+ __all__ = [
5
+ {% for a in all_list %}
6
+ '{{ a }}',
7
+ {% endfor %}
8
+ ]
9
+ import datetime
10
+ import typing
11
+ from protoplasm6 import plasm
12
+ {{ imports }}
13
+ if typing.TYPE_CHECKING:
14
+ from grpc import ServicerContext
15
+ {{ api_import }}
16
+
17
+ import logging
18
+ log = logging.getLogger(__name__)
19
+
20
+
21
+ {{ services }}
@@ -0,0 +1,21 @@
1
+ # Auto-Generated file - DO NOT EDIT!
2
+ # Source module: {{ module_full_name }}
3
+ # Generated at: {{ iso_timestamp }}
4
+ from __future__ import annotations
5
+ __all__ = [
6
+ {% for a in all_list %}
7
+ '{{ a }}',
8
+ {% endfor %}
9
+ ]
10
+ import datetime
11
+ import typing
12
+ from protoplasm6 import plasm
13
+ {{ imports }}
14
+ if typing.TYPE_CHECKING:
15
+ from grpc import ChannelCredentials
16
+
17
+ import logging
18
+ log = logging.getLogger(__name__)
19
+
20
+
21
+ {{ services }}
File without changes
@@ -0,0 +1,22 @@
1
+ {% from 'macros/indentclude.jinja2' import indentclude with context %}
2
+ # Auto-Generated file - DO NOT EDIT!
3
+ # Source module: {{ module_full_name }}
4
+ # Generated at: {{ iso_timestamp }}
5
+ __all__ = [
6
+ {% for a in all_clause %}
7
+ '{{ a }}',
8
+ {% endfor %}
9
+ ]
10
+ import datetime
11
+ import typing
12
+ from protoplasm6 import plasm
13
+
14
+ {% for import_line in import_lines %}
15
+ {{ import_line }}
16
+ {% endfor %}
17
+
18
+ import logging
19
+ log = logging.getLogger(__name__)
20
+
21
+
22
+ {{ services }}
@@ -0,0 +1,2 @@
1
+ {%- macro _inc(file_name, this) -%}{% include file_name with context %}{% endmacro %}
2
+ {%- macro indentclude(file_name, spaces=4, this={}) -%}{{ _inc(file_name, this)|indent(spaces) }}{%- endmacro -%}
@@ -0,0 +1,10 @@
1
+ # Auto-Generated file - DO NOT EDIT!
2
+ # Proto package alias imports, i.e. everything in the `{{ proto_package }}` proto package
3
+ __all__ = [
4
+ {% for name in names %}
5
+ '{{ name }}',
6
+ {% endfor %}
7
+ ]
8
+ {% for module in modules %}
9
+ from {{ module }} import *
10
+ {% endfor %}
@@ -0,0 +1 @@
1
+ # ENUMS GO HERE...
@@ -0,0 +1,2 @@
1
+ def {{ this.method_under_name }}(self{{ this.input_params }}) -> {{ this.return_type_hint }}:
2
+ raise plasm.Unimplemented()
@@ -0,0 +1,10 @@
1
+ {% from 'macros/indentclude.jinja2' import indentclude with context %}
2
+ class {{ service_name }}Interface:
3
+ {% if is_grpc %}
4
+ __servicer_cls__ = {{ service_name }}GrpcServicer
5
+
6
+ {% endif %}
7
+ {% for method in method_list %}
8
+ {{ indentclude('parts/_interface_method.jinja2', (indent_spaces + 4), method) }}
9
+
10
+ {% endfor %}
@@ -0,0 +1 @@
1
+ # NESTED MESSAGES GO HERE...
@@ -0,0 +1,12 @@
1
+ __version__ = '{{ version }}'{% if version == '' %} # NO VERSION NUMBERS FOUND?!? :({% endif +%}
2
+ __protoplasm_version__ = '{{ protoplasm_version }}'
3
+ __neobuilder_version__ = '{{ neobuilder_version }}'
4
+
5
+
6
+ def load_symbols():
7
+ from {{ package_name }} import __everything__{% if alias_init %}
8
+
9
+
10
+
11
+ {{ alias_init }}
12
+ {%- endif %}
@@ -0,0 +1,2 @@
1
+ from ._field import *
2
+ from ._method import *
@@ -0,0 +1,188 @@
1
+ __all__ = [
2
+ 'FieldKind',
3
+ 'FieldDescriptorWrapper',
4
+ ]
5
+ import dataclasses
6
+ import enum
7
+ from typing import *
8
+ import keyword
9
+ from google.protobuf.json_format import descriptor
10
+ from google.protobuf import json_format
11
+ from neobuilder6.structs.pytype import *
12
+
13
+
14
+ class FieldKind(enum.IntFlag):
15
+ UNKNOWN = 0x0000
16
+ DATA_SCALAR = 0x0001
17
+ DATA_MESSAGE = 0x0002
18
+ DATA_ENUM = 0x0004
19
+
20
+ KIND_SINGLE = 0x0010
21
+ KIND_LIST = 0x0020
22
+ KIND_MAP = 0x0040
23
+
24
+ SPECIAL_TIMESTAMP = 0x00100
25
+ SPECIAL_BYTES = 0x00200
26
+ SPECIAL_LONG = 0x00400
27
+ SPECIAL_DURATION = 0x00800
28
+ SPECIAL_ANY = 0x01000
29
+ SPECIAL_EMPTY = 0x02000
30
+ SPECIAL_STRUCT = 0x04000
31
+ SPECIAL_VALUE = 0x08000
32
+ SPECIAL_LIST_VALUE = 0x10000
33
+ SPECIAL_NULL_VALUE = 0x20000
34
+
35
+ SPECIAL_KEYWORD = 0x10000000
36
+
37
+ # scalar
38
+ FIELD_SIMPLE = DATA_SCALAR | KIND_SINGLE
39
+ # Message
40
+ FIELD_MESSAGE = DATA_MESSAGE | KIND_SINGLE
41
+ # Enum
42
+ FIELD_ENUM = DATA_ENUM | KIND_SINGLE
43
+
44
+ # repeated scalar
45
+ FIELD_SIMPLE_LIST = DATA_SCALAR | KIND_LIST
46
+ # repeated Message
47
+ FIELD_MESSAGE_LIST = DATA_MESSAGE | KIND_LIST
48
+ # repeated Enum
49
+ FIELD_ENUM_LIST = DATA_ENUM | KIND_LIST
50
+
51
+ # map<scalar, scalar>
52
+ FIELD_SIMPLE_MAP = DATA_SCALAR | KIND_MAP
53
+ # map<scalar, Message>
54
+ FIELD_MESSAGE_MAP = DATA_MESSAGE | KIND_MAP
55
+ # map<scalar, Enum>
56
+ FIELD_ENUM_MAP = DATA_ENUM | KIND_MAP
57
+
58
+ FIELD_STRUCT_VALUES = SPECIAL_STRUCT | SPECIAL_VALUE | SPECIAL_LIST_VALUE | SPECIAL_NULL_VALUE
59
+
60
+ def __repr__(self) -> str:
61
+ return self.name or str(self.value)
62
+
63
+
64
+ @dataclasses.dataclass
65
+ class FieldDescriptorWrapper:
66
+ """This is a wrapper around Google's protobuf FieldDescriptor.
67
+
68
+ Its point is twofold.
69
+
70
+ 1. To mask complex lookups and evaluations behind a simpler facade to use
71
+ in the rest of the code.
72
+ 2. To abstract away the exact structure of Google's descriptor to guard
73
+ against future code changes, especially in internal parts that aren't
74
+ part of the official API.
75
+ """
76
+ real_descriptor: descriptor.FieldDescriptor = dataclasses.field(repr=False)
77
+
78
+ name: str = dataclasses.field(default='', init=False)
79
+
80
+ kind: FieldKind = dataclasses.field(default=FieldKind.UNKNOWN, init=False)
81
+
82
+ options: Optional[Any] = dataclasses.field(default=None, init=False, repr=False)
83
+
84
+ key_field: Optional[descriptor.FieldDescriptor] = dataclasses.field(default=None, init=False, repr=False)
85
+ value_field: Optional[descriptor.FieldDescriptor] = dataclasses.field(default=None, init=False, repr=False)
86
+ value_msg: Optional[descriptor.Descriptor] = dataclasses.field(default=None, init=False, repr=False)
87
+
88
+ py_type: PyType = dataclasses.field(default=PY_TYPE_MAP[ProtoType.UNKNOWN], init=False)
89
+ key_py_type: PyType = dataclasses.field(default=PY_TYPE_MAP[ProtoType.UNKNOWN], init=False)
90
+
91
+ is_proto_repeated: bool = dataclasses.field(default=False, init=False)
92
+
93
+ def __post_init__(self):
94
+ self.name = self.real_descriptor.name
95
+ self.is_proto_repeated = self.real_descriptor.is_repeated
96
+ self._check_field_kind()
97
+
98
+ def _load_options(self):
99
+ self.options = None
100
+ if self.real_descriptor.type == ProtoType.MESSAGE:
101
+ if self.real_descriptor.message_type.has_options:
102
+ self.options = self.real_descriptor.message_type.GetOptions()
103
+
104
+ def _check_field_kind(self):
105
+ self._load_options()
106
+
107
+ if self.options and self.options.map_entry: # Message that is a map...
108
+ self.key_field = self.real_descriptor.message_type.fields_by_name['key']
109
+ self.key_py_type = PY_TYPE_MAP[self.key_field.type]
110
+ self.value_field = self.real_descriptor.message_type.fields_by_name['value']
111
+ self.kind |= FieldKind.KIND_MAP
112
+ else:
113
+ self.value_field = self.real_descriptor
114
+ if self.is_proto_repeated:
115
+ self.kind |= FieldKind.KIND_LIST
116
+ else:
117
+ self.kind |= FieldKind.KIND_SINGLE
118
+
119
+ if self.value_field.type == ProtoType.MESSAGE: # Message
120
+ self.value_msg = self.value_field.message_type
121
+
122
+ if self.value_msg.full_name == 'google.protobuf.Timestamp':
123
+ self.kind |= FieldKind.DATA_SCALAR
124
+ self.kind |= FieldKind.SPECIAL_TIMESTAMP
125
+ elif self.value_msg.full_name == 'google.protobuf.Duration':
126
+ self.kind |= FieldKind.DATA_SCALAR
127
+ self.kind |= FieldKind.SPECIAL_DURATION
128
+ elif self.value_msg.full_name == 'google.protobuf.Any':
129
+ self.kind |= FieldKind.DATA_SCALAR
130
+ self.kind |= FieldKind.SPECIAL_ANY
131
+ elif self.value_msg.full_name == 'google.protobuf.Empty':
132
+ self.kind |= FieldKind.SPECIAL_EMPTY
133
+ elif self.value_msg.full_name == 'google.protobuf.Struct':
134
+ self.kind |= FieldKind.SPECIAL_STRUCT
135
+ elif self.value_msg.full_name == 'google.protobuf.Value':
136
+ self.kind |= FieldKind.SPECIAL_VALUE
137
+ elif self.value_msg.full_name == 'google.protobuf.ListValue':
138
+ self.kind |= FieldKind.SPECIAL_LIST_VALUE
139
+ elif self.value_msg.full_name == 'google.protobuf.NullValue':
140
+ self.kind |= FieldKind.SPECIAL_NULL_VALUE
141
+ else:
142
+ self.kind |= FieldKind.DATA_MESSAGE
143
+ elif self.value_field.type == ProtoType.ENUM: # Enum
144
+ self.kind |= FieldKind.DATA_ENUM
145
+
146
+ else: # Scalar
147
+ self.kind |= FieldKind.DATA_SCALAR
148
+
149
+ if self.value_field.type == ProtoType.BYTES:
150
+ self.kind |= FieldKind.SPECIAL_BYTES
151
+ else:
152
+ if self.value_field.cpp_type in json_format._INT64_TYPES:
153
+ self.kind |= FieldKind.SPECIAL_LONG
154
+
155
+ self.py_type = PY_TYPE_MAP[self.value_field.type]
156
+
157
+ if keyword.iskeyword(self.name):
158
+ self.kind |= FieldKind.SPECIAL_KEYWORD
159
+
160
+ @property
161
+ def camelcase_name(self) -> str:
162
+ return self.real_descriptor.camelcase_name
163
+
164
+ @property
165
+ def json_name(self) -> str:
166
+ return self.real_descriptor.json_name
167
+
168
+ @property
169
+ def default_value(self) -> Any:
170
+ return self.real_descriptor.default_value
171
+
172
+ @property
173
+ def full_name(self) -> Any:
174
+ return self.real_descriptor.full_name
175
+
176
+
177
+ # def main():
178
+ # fields = []
179
+ # from sandbox.test import RainbowMessage
180
+ # for f in RainbowMessage.DESCRIPTOR.fields:
181
+ # ff = FieldDescriptorWrapper(f)
182
+ # print(ff)
183
+ # fields.append(ff)
184
+ #
185
+ # # print(fields)
186
+ #
187
+ # if __name__ == '__main__':
188
+ # main()
@@ -0,0 +1,57 @@
1
+ __all__ = [
2
+ 'MethodDescriptorWrapper',
3
+ ]
4
+
5
+ import dataclasses
6
+
7
+ from neobuilder6.structs import *
8
+ from google.protobuf.json_format import descriptor
9
+ from protoplasm6.casting import castutils
10
+
11
+
12
+ @dataclasses.dataclass
13
+ class MethodDescriptorWrapper:
14
+ """This is a wrapper around Google's protobuf MethodDescriptor.
15
+
16
+ Its point is twofold.
17
+
18
+ 1. To mask complex lookups and evaluations behind a simpler facade to use
19
+ in the rest of the code.
20
+ 2. To abstract away the exact structure of Google's descriptor to guard
21
+ against future code changes, especially in internal parts that aren't
22
+ part of the official API.
23
+ """
24
+ real_descriptor: descriptor.MethodDescriptor = dataclasses.field(repr=False)
25
+
26
+ name: str = dataclasses.field(default='', init=False)
27
+ under_name: str = dataclasses.field(default='', init=False)
28
+
29
+ client_streaming: bool = False
30
+ server_streaming: bool = False
31
+
32
+ input_type: Optional[descriptor.Descriptor] = dataclasses.field(default=None, init=False, repr=False)
33
+ output_type: Optional[descriptor.Descriptor] = dataclasses.field(default=None, init=False, repr=False)
34
+
35
+ io_type: MethodIoType = dataclasses.field(default=MethodIoType._UNKNOWN, init=False)
36
+
37
+ service_descriptor: descriptor.ServiceDescriptor = dataclasses.field(default=None, init=False, repr=False)
38
+ file_descriptor: descriptor.FileDescriptor = dataclasses.field(default=None, init=False, repr=False)
39
+
40
+ def __post_init__(self):
41
+ self.name = self.real_descriptor.name
42
+ self.under_name = castutils.humps_to_under(self.name)
43
+ self.input_type = self.real_descriptor.input_type
44
+ self.output_type = self.real_descriptor.output_type
45
+ self.client_streaming = self.real_descriptor.client_streaming
46
+ self.server_streaming = self.real_descriptor.server_streaming
47
+ if self.client_streaming:
48
+ self.io_type |= MethodIoType._INPUT_STREAM
49
+ else:
50
+ self.io_type |= MethodIoType._INPUT_UNARY
51
+ if self.server_streaming:
52
+ self.io_type |= MethodIoType._OUTPUT_STREAM
53
+ else:
54
+ self.io_type |= MethodIoType._OUTPUT_UNARY
55
+
56
+ self.service_descriptor = self.real_descriptor.containing_service
57
+ self.file_descriptor = self.service_descriptor.file
File without changes
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+ from . import base
3
+ from batutils.tpu import strimp
4
+ import typing
5
+
6
+ import logging
7
+ log = logging.getLogger(__name__)
8
+
9
+ _CACHE = {}
10
+
11
+
12
+ def get_builder_module(implementation_name: str):
13
+ if implementation_name not in _CACHE:
14
+ _CACHE[implementation_name] = strimp.get_module(f'{__package__}.{implementation_name}', logger=log, reraise=True)
15
+ return _CACHE[implementation_name]
16
+
17
+
18
+ def get_module_builder(implementation_name: str) -> typing.Type[base.AbstractModuleBuilder]:
19
+ return getattr(get_builder_module(implementation_name), 'ModuleBuilder')
20
+
21
+
22
+ def get_service_builder(implementation_name: str) -> typing.Type[base.AbstractServiceBuilder]:
23
+ return getattr(get_builder_module(implementation_name), 'ServiceBuilder')
24
+
25
+
26
+ def get_method_builder(implementation_name: str) -> typing.Type[base.AbstractMethodBuilder]:
27
+ return getattr(get_builder_module(implementation_name), 'MethodBuilder')
@@ -0,0 +1,99 @@
1
+ from __future__ import annotations
2
+ from neobuilder6.generators.symbols import service as symbols_service
3
+ from neobuilder6.generators.symbols import modules
4
+ import datetime
5
+ from typing import *
6
+
7
+
8
+ class AbstractModuleBuilder(object):
9
+ builder_name = ''
10
+
11
+ def __init__(self, module: modules.ProtoModule):
12
+ self.module = module
13
+ self.indent_str = self.module.indent
14
+ self.service_joiner = '\n\n'
15
+
16
+ def get_template_context(self) -> Dict:
17
+ return {
18
+ 'module_full_name': self.module.get_module_full_name(),
19
+ 'iso_timestamp': datetime.datetime.now().isoformat(),
20
+ }
21
+
22
+ def render_top(self) -> str:
23
+ # TODO(thordurm@ccpgames.com) 2022-06-24: Remove... why?
24
+ return ('# Auto-Generated file - DO NOT EDIT!\n'
25
+ f'# Source module: {self.module.get_module_full_name()}\n'
26
+ f'# Generated at: {datetime.datetime.now().isoformat()}\n')
27
+
28
+ def render_service_list(self) -> List[str]:
29
+ return [svc.render(self.builder_name) for svc in self.module.service_map.values()]
30
+
31
+ def render_services(self) -> str:
32
+ return '\n'.join(self.render_service_list())
33
+
34
+ def get_render_filename(self) -> str:
35
+ raise NotImplementedError('AbstractModuleBuilder not implemented')
36
+
37
+ def render(self) -> str:
38
+ raise NotImplementedError('AbstractModuleBuilder not implemented')
39
+
40
+
41
+ class AbstractServiceBuilder(object):
42
+ builder_name = ''
43
+
44
+ def __init__(self, service: symbols_service.ProtoService, indent_level: int = 0):
45
+ self.service = service
46
+ self.indent_level = indent_level
47
+ self.indent_str = self.service.indent
48
+ self.base_indent = self.indent_str * indent_level
49
+
50
+ def get_template_context(self) -> Dict:
51
+ return {
52
+ 'is_grpc': self.service.module.is_grpc_file(),
53
+ 'service': self.service,
54
+ 'service_name': self.service.service_descriptor.name,
55
+ '_indent_level': self.indent_level,
56
+ '_indent_str': self.indent_str,
57
+ '_base_indent': self.base_indent,
58
+ 'method_list': [self.get_method_context(m) for m in self.service.method_map.values()],
59
+ 'indent_spaces': self.indent_level * 4,
60
+ }
61
+
62
+ def get_method_context(self, method: symbols_service.ProtoMethod) -> Dict[str, Any]:
63
+ return {
64
+ 'method': method,
65
+ }
66
+
67
+ def render_methods(self) -> str:
68
+ ____ = self.indent_str
69
+ i = self.base_indent
70
+ buf = []
71
+ if self.service.method_map:
72
+ buf.append(
73
+ '\n'.join([m.render(self.builder_name, self.indent_level + 1) for m in self.service.method_map.values()]))
74
+ else:
75
+ buf.append(f'{i}pass\n')
76
+ return ''.join(buf)
77
+
78
+ def render(self) -> str:
79
+ raise NotImplementedError('AbstractServiceBuilder not implemented')
80
+
81
+
82
+ class AbstractMethodBuilder(object):
83
+ def __init__(self, method: symbols_service.ProtoMethod, indent_level: int = 0):
84
+ self.method = method
85
+ self.indent_level = indent_level
86
+ self.indent_str = self.method.indent
87
+ self.base_indent = self.indent_str * indent_level
88
+
89
+ def get_template_context(self) -> Dict:
90
+ return {
91
+ 'method': self.method,
92
+ '_indent_level': self.indent_level,
93
+ '_indent_str': self.indent_str,
94
+ '_base_indent': self.base_indent,
95
+ 'indent_spaces': self.indent_level * 4,
96
+ }
97
+
98
+ def render(self) -> str:
99
+ raise NotImplementedError('AbstractServiceMethod not implemented')