betterproto2-compiler 0.2.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. betterproto2_compiler/__init__.py +0 -0
  2. betterproto2_compiler/casing.py +140 -0
  3. betterproto2_compiler/compile/__init__.py +0 -0
  4. betterproto2_compiler/compile/importing.py +180 -0
  5. betterproto2_compiler/compile/naming.py +21 -0
  6. betterproto2_compiler/known_types/__init__.py +14 -0
  7. betterproto2_compiler/known_types/any.py +36 -0
  8. betterproto2_compiler/known_types/duration.py +25 -0
  9. betterproto2_compiler/known_types/timestamp.py +45 -0
  10. betterproto2_compiler/lib/__init__.py +0 -0
  11. betterproto2_compiler/lib/google/__init__.py +0 -0
  12. betterproto2_compiler/lib/google/protobuf/__init__.py +3338 -0
  13. betterproto2_compiler/lib/google/protobuf/compiler/__init__.py +235 -0
  14. betterproto2_compiler/lib/message_pool.py +3 -0
  15. betterproto2_compiler/plugin/__init__.py +3 -0
  16. betterproto2_compiler/plugin/__main__.py +3 -0
  17. betterproto2_compiler/plugin/compiler.py +70 -0
  18. betterproto2_compiler/plugin/main.py +47 -0
  19. betterproto2_compiler/plugin/models.py +643 -0
  20. betterproto2_compiler/plugin/module_validation.py +156 -0
  21. betterproto2_compiler/plugin/parser.py +272 -0
  22. betterproto2_compiler/plugin/plugin.bat +2 -0
  23. betterproto2_compiler/plugin/typing_compiler.py +163 -0
  24. betterproto2_compiler/py.typed +0 -0
  25. betterproto2_compiler/settings.py +9 -0
  26. betterproto2_compiler/templates/header.py.j2 +59 -0
  27. betterproto2_compiler/templates/template.py.j2 +258 -0
  28. betterproto2_compiler-0.2.0.dist-info/LICENSE.md +22 -0
  29. betterproto2_compiler-0.2.0.dist-info/METADATA +35 -0
  30. betterproto2_compiler-0.2.0.dist-info/RECORD +32 -0
  31. betterproto2_compiler-0.2.0.dist-info/WHEEL +4 -0
  32. betterproto2_compiler-0.2.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,235 @@
1
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
2
+ # sources: google/protobuf/compiler/plugin.proto
3
+ # plugin: python-betterproto2
4
+ # This file has been @generated
5
+
6
+ __all__ = (
7
+ "CodeGeneratorResponseFeature",
8
+ "CodeGeneratorRequest",
9
+ "CodeGeneratorResponse",
10
+ "CodeGeneratorResponseFile",
11
+ "Version",
12
+ )
13
+
14
+
15
+ from dataclasses import dataclass
16
+ from typing import (
17
+ List,
18
+ Optional,
19
+ )
20
+
21
+ import betterproto2
22
+
23
+ from ....message_pool import default_message_pool
24
+
25
+ betterproto2.check_compiler_version("0.2.0")
26
+
27
+
28
+ class CodeGeneratorResponseFeature(betterproto2.Enum):
29
+ """
30
+ Sync with code_generator.h.
31
+ """
32
+
33
+ FEATURE_NONE = 0
34
+
35
+ FEATURE_PROTO3_OPTIONAL = 1
36
+
37
+ FEATURE_SUPPORTS_EDITIONS = 2
38
+
39
+
40
+ @dataclass(eq=False, repr=False)
41
+ class CodeGeneratorRequest(betterproto2.Message):
42
+ """
43
+ An encoded CodeGeneratorRequest is written to the plugin's stdin.
44
+ """
45
+
46
+ file_to_generate: "List[str]" = betterproto2.field(1, betterproto2.TYPE_STRING, repeated=True)
47
+ """
48
+ The .proto files that were explicitly listed on the command-line. The
49
+ code generator should generate code only for these files. Each file's
50
+ descriptor will be included in proto_file, below.
51
+ """
52
+
53
+ parameter: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)
54
+ """
55
+ The generator parameter passed on the command-line.
56
+ """
57
+
58
+ proto_file: "List[__protobuf__.FileDescriptorProto]" = betterproto2.field(
59
+ 15, betterproto2.TYPE_MESSAGE, repeated=True
60
+ )
61
+ """
62
+ FileDescriptorProtos for all files in files_to_generate and everything
63
+ they import. The files will appear in topological order, so each file
64
+ appears before any file that imports it.
65
+
66
+ Note: the files listed in files_to_generate will include runtime-retention
67
+ options only, but all other files will include source-retention options.
68
+ The source_file_descriptors field below is available in case you need
69
+ source-retention options for files_to_generate.
70
+
71
+ protoc guarantees that all proto_files will be written after
72
+ the fields above, even though this is not technically guaranteed by the
73
+ protobuf wire format. This theoretically could allow a plugin to stream
74
+ in the FileDescriptorProtos and handle them one by one rather than read
75
+ the entire set into memory at once. However, as of this writing, this
76
+ is not similarly optimized on protoc's end -- it will store all fields in
77
+ memory at once before sending them to the plugin.
78
+
79
+ Type names of fields and extensions in the FileDescriptorProto are always
80
+ fully qualified.
81
+ """
82
+
83
+ source_file_descriptors: "List[__protobuf__.FileDescriptorProto]" = betterproto2.field(
84
+ 17, betterproto2.TYPE_MESSAGE, repeated=True
85
+ )
86
+ """
87
+ File descriptors with all options, including source-retention options.
88
+ These descriptors are only provided for the files listed in
89
+ files_to_generate.
90
+ """
91
+
92
+ compiler_version: "Optional[Version]" = betterproto2.field(3, betterproto2.TYPE_MESSAGE, optional=True)
93
+ """
94
+ The version number of protocol compiler.
95
+ """
96
+
97
+
98
+ default_message_pool.register_message("google.protobuf.compiler", "CodeGeneratorRequest", CodeGeneratorRequest)
99
+
100
+
101
+ @dataclass(eq=False, repr=False)
102
+ class CodeGeneratorResponse(betterproto2.Message):
103
+ """
104
+ The plugin writes an encoded CodeGeneratorResponse to stdout.
105
+ """
106
+
107
+ error: "str" = betterproto2.field(1, betterproto2.TYPE_STRING)
108
+ """
109
+ Error message. If non-empty, code generation failed. The plugin process
110
+ should exit with status code zero even if it reports an error in this way.
111
+
112
+ This should be used to indicate errors in .proto files which prevent the
113
+ code generator from generating correct code. Errors which indicate a
114
+ problem in protoc itself -- such as the input CodeGeneratorRequest being
115
+ unparseable -- should be reported by writing a message to stderr and
116
+ exiting with a non-zero status code.
117
+ """
118
+
119
+ supported_features: "int" = betterproto2.field(2, betterproto2.TYPE_UINT64)
120
+ """
121
+ A bitmask of supported features that the code generator supports.
122
+ This is a bitwise "or" of values from the Feature enum.
123
+ """
124
+
125
+ file: "List[CodeGeneratorResponseFile]" = betterproto2.field(15, betterproto2.TYPE_MESSAGE, repeated=True)
126
+
127
+
128
+ default_message_pool.register_message("google.protobuf.compiler", "CodeGeneratorResponse", CodeGeneratorResponse)
129
+
130
+
131
+ @dataclass(eq=False, repr=False)
132
+ class CodeGeneratorResponseFile(betterproto2.Message):
133
+ """
134
+ Represents a single generated file.
135
+ """
136
+
137
+ name: "str" = betterproto2.field(1, betterproto2.TYPE_STRING)
138
+ """
139
+ The file name, relative to the output directory. The name must not
140
+ contain "." or ".." components and must be relative, not be absolute (so,
141
+ the file cannot lie outside the output directory). "/" must be used as
142
+ the path separator, not "\".
143
+
144
+ If the name is omitted, the content will be appended to the previous
145
+ file. This allows the generator to break large files into small chunks,
146
+ and allows the generated text to be streamed back to protoc so that large
147
+ files need not reside completely in memory at one time. Note that as of
148
+ this writing protoc does not optimize for this -- it will read the entire
149
+ CodeGeneratorResponse before writing files to disk.
150
+ """
151
+
152
+ insertion_point: "str" = betterproto2.field(2, betterproto2.TYPE_STRING)
153
+ """
154
+ If non-empty, indicates that the named file should already exist, and the
155
+ content here is to be inserted into that file at a defined insertion
156
+ point. This feature allows a code generator to extend the output
157
+ produced by another code generator. The original generator may provide
158
+ insertion points by placing special annotations in the file that look
159
+ like:
160
+ @@protoc_insertion_point(NAME)
161
+ The annotation can have arbitrary text before and after it on the line,
162
+ which allows it to be placed in a comment. NAME should be replaced with
163
+ an identifier naming the point -- this is what other generators will use
164
+ as the insertion_point. Code inserted at this point will be placed
165
+ immediately above the line containing the insertion point (thus multiple
166
+ insertions to the same point will come out in the order they were added).
167
+ The double-@ is intended to make it unlikely that the generated code
168
+ could contain things that look like insertion points by accident.
169
+
170
+ For example, the C++ code generator places the following line in the
171
+ .pb.h files that it generates:
172
+ // @@protoc_insertion_point(namespace_scope)
173
+ This line appears within the scope of the file's package namespace, but
174
+ outside of any particular class. Another plugin can then specify the
175
+ insertion_point "namespace_scope" to generate additional classes or
176
+ other declarations that should be placed in this scope.
177
+
178
+ Note that if the line containing the insertion point begins with
179
+ whitespace, the same whitespace will be added to every line of the
180
+ inserted text. This is useful for languages like Python, where
181
+ indentation matters. In these languages, the insertion point comment
182
+ should be indented the same amount as any inserted code will need to be
183
+ in order to work correctly in that context.
184
+
185
+ The code generator that generates the initial file and the one which
186
+ inserts into it must both run as part of a single invocation of protoc.
187
+ Code generators are executed in the order in which they appear on the
188
+ command line.
189
+
190
+ If |insertion_point| is present, |name| must also be present.
191
+ """
192
+
193
+ content: "str" = betterproto2.field(15, betterproto2.TYPE_STRING)
194
+ """
195
+ The file contents.
196
+ """
197
+
198
+ generated_code_info: "Optional[__protobuf__.GeneratedCodeInfo]" = betterproto2.field(
199
+ 16, betterproto2.TYPE_MESSAGE, optional=True
200
+ )
201
+ """
202
+ Information describing the file content being inserted. If an insertion
203
+ point is used, this information will be appropriately offset and inserted
204
+ into the code generation metadata for the generated files.
205
+ """
206
+
207
+
208
+ default_message_pool.register_message(
209
+ "google.protobuf.compiler", "CodeGeneratorResponse.File", CodeGeneratorResponseFile
210
+ )
211
+
212
+
213
+ @dataclass(eq=False, repr=False)
214
+ class Version(betterproto2.Message):
215
+ """
216
+ The version number of protocol compiler.
217
+ """
218
+
219
+ major: "int" = betterproto2.field(1, betterproto2.TYPE_INT32)
220
+
221
+ minor: "int" = betterproto2.field(2, betterproto2.TYPE_INT32)
222
+
223
+ patch: "int" = betterproto2.field(3, betterproto2.TYPE_INT32)
224
+
225
+ suffix: "str" = betterproto2.field(4, betterproto2.TYPE_STRING)
226
+ """
227
+ A suffix for alpha, beta or rc release, e.g., "alpha-1", "rc2". It should
228
+ be empty for mainline stable releases.
229
+ """
230
+
231
+
232
+ default_message_pool.register_message("google.protobuf.compiler", "Version", Version)
233
+
234
+
235
+ from ... import protobuf as __protobuf__
@@ -0,0 +1,3 @@
1
+ import betterproto2
2
+
3
+ default_message_pool = betterproto2.MessagePool()
@@ -0,0 +1,3 @@
1
+ __all__ = ["main"]
2
+
3
+ from .main import main
@@ -0,0 +1,3 @@
1
+ from .main import main
2
+
3
+ main()
@@ -0,0 +1,70 @@
1
+ import os.path
2
+ import subprocess
3
+ import sys
4
+ from importlib import metadata
5
+
6
+ from .module_validation import ModuleValidator
7
+
8
+ try:
9
+ # betterproto[compiler] specific dependencies
10
+ import jinja2
11
+ except ImportError as err:
12
+ print(
13
+ "\033[31m"
14
+ f"Unable to import `{err.name}` from betterproto plugin! "
15
+ "Please ensure that you've installed betterproto as "
16
+ '`pip install "betterproto[compiler]"` so that compiler dependencies '
17
+ "are included."
18
+ "\033[0m",
19
+ )
20
+ raise SystemExit(1)
21
+
22
+ from .models import OutputTemplate
23
+
24
+
25
+ def outputfile_compiler(output_file: OutputTemplate) -> str:
26
+ templates_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "templates"))
27
+
28
+ version = metadata.version("betterproto2_compiler")
29
+
30
+ env = jinja2.Environment(
31
+ trim_blocks=True,
32
+ lstrip_blocks=True,
33
+ loader=jinja2.FileSystemLoader(templates_folder),
34
+ undefined=jinja2.StrictUndefined,
35
+ )
36
+ # Load the body first so we have a compleate list of imports needed.
37
+ body_template = env.get_template("template.py.j2")
38
+ header_template = env.get_template("header.py.j2")
39
+
40
+ code = body_template.render(output_file=output_file)
41
+ code = header_template.render(output_file=output_file, version=version) + "\n" + code
42
+
43
+ try:
44
+ # Sort imports, delete unused ones
45
+ code = subprocess.check_output(
46
+ ["ruff", "check", "--select", "I,F401,TCH005", "--fix", "--silent", "-"],
47
+ input=code,
48
+ encoding="utf-8",
49
+ )
50
+
51
+ # Format the code
52
+ code = subprocess.check_output(["ruff", "format", "-"], input=code, encoding="utf-8")
53
+ except subprocess.CalledProcessError:
54
+ with open("invalid-generated-code.py", "w") as f:
55
+ f.write(code)
56
+
57
+ raise SyntaxError(
58
+ f"Can't format the source code:\nThe invalid generated code has been written in `invalid-generated-code.py`"
59
+ )
60
+
61
+ # Validate the generated code.
62
+ validator = ModuleValidator(iter(code.splitlines()))
63
+ if not validator.validate():
64
+ message_builder = ["[WARNING]: Generated code has collisions in the module:"]
65
+ for collision, lines in validator.collisions.items():
66
+ message_builder.append(f' "{collision}" on lines:')
67
+ for num, line in lines:
68
+ message_builder.append(f" {num}:{line}")
69
+ print("\n".join(message_builder), file=sys.stderr)
70
+ return code
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env python
2
+
3
+ import os
4
+ import sys
5
+
6
+ from betterproto2_compiler.lib.google.protobuf.compiler import (
7
+ CodeGeneratorRequest,
8
+ )
9
+ from betterproto2_compiler.plugin.parser import generate_code
10
+
11
+
12
+ def main() -> None:
13
+ """The plugin's main entry point."""
14
+ # Read request message from stdin
15
+ data = sys.stdin.buffer.read()
16
+
17
+ # Parse request
18
+ request = CodeGeneratorRequest()
19
+ request.parse(data)
20
+
21
+ dump_file = os.getenv("BETTERPROTO_DUMP")
22
+ if dump_file:
23
+ dump_request(dump_file, request)
24
+
25
+ # Generate code
26
+ response = generate_code(request)
27
+
28
+ # Serialise response message
29
+ output = response.SerializeToString()
30
+
31
+ # Write to stdout
32
+ sys.stdout.buffer.write(output)
33
+
34
+
35
+ def dump_request(dump_file: str, request: CodeGeneratorRequest) -> None:
36
+ """
37
+ For developers: Supports running plugin.py standalone so its possible to debug it.
38
+ Run protoc (or generate.py) with BETTERPROTO_DUMP="yourfile.bin" to write the request to a file.
39
+ Then run plugin.py from your IDE in debugging mode, and redirect stdin to the file.
40
+ """
41
+ with open(str(dump_file), "wb") as fh:
42
+ sys.stderr.write(f"\033[31mWriting input from protoc to: {dump_file}\033[0m\n")
43
+ fh.write(request.SerializeToString())
44
+
45
+
46
+ if __name__ == "__main__":
47
+ main()