EmbeddedProto 4.0.0b1__tar.gz
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.
- embeddedproto-4.0.0b1/EmbeddedProto/EmbeddedProto.py +122 -0
- embeddedproto-4.0.0b1/EmbeddedProto/Features.py +255 -0
- embeddedproto-4.0.0b1/EmbeddedProto/Field.py +1295 -0
- embeddedproto-4.0.0b1/EmbeddedProto/Oneof.py +74 -0
- embeddedproto-4.0.0b1/EmbeddedProto/ProtoFile.py +210 -0
- embeddedproto-4.0.0b1/EmbeddedProto/TypeDefinitions.py +367 -0
- embeddedproto-4.0.0b1/EmbeddedProto/__init__.py +0 -0
- embeddedproto-4.0.0b1/EmbeddedProto/__main__.py +28 -0
- embeddedproto-4.0.0b1/EmbeddedProto/config.py +173 -0
- embeddedproto-4.0.0b1/EmbeddedProto/custom_header.py +513 -0
- embeddedproto-4.0.0b1/EmbeddedProto/embedded_proto_options.proto +62 -0
- embeddedproto-4.0.0b1/EmbeddedProto/embedded_proto_options_pb2.py +37 -0
- embeddedproto-4.0.0b1/EmbeddedProto/field_options.py +344 -0
- embeddedproto-4.0.0b1/EmbeddedProto/main.py +316 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/BytesStringCallback.h +476 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/Defines.h +118 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/EmptyArray.h +81 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/Errors.h +53 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/FieldStringBytes.h +793 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/Fields.h +832 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/Functional.h +412 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/MessageCallback.h +688 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/MessageInterface.h +792 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/MessageSizeCalculator.h +109 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/MessageState.h +207 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/ReadBufferFixedSize.h +204 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/ReadBufferInterface.h +181 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/ReadBufferSection.h +232 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/RepeatedField.h +1053 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/RepeatedFieldCallback.h +432 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/RepeatedFieldFixedSize.h +367 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/Version.h +39 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/WireFormatter.h +852 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/WriteBufferFixedSize.h +114 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto/WriteBufferInterface.h +134 -0
- embeddedproto-4.0.0b1/EmbeddedProto/src/EmbeddedProto.h +55 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldBasic_Deserialize.h.jinja2 +26 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldBasic_GetSet.h.jinja2 +89 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldBytes_GetSet.h.jinja2 +86 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldEnum_Deserialize.h.jinja2 +50 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldEnum_GetSet.h.jinja2 +93 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldErrorRecursive_GetSet.h.jinja2 +29 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldMap_GetSet.h.jinja2 +203 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldMsg_Deserialize.h.jinja2 +44 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldMsg_GetSet.h.jinja2 +93 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldRepeated_GetSet.h.jinja2 +94 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/FieldString_GetSet.h.jinja2 +86 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/Field_DeserializePartial.h.jinja2 +33 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/Field_Serialize.h.jinja2 +112 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/Field_SerializePartial.h.jinja2 +119 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/Header.h.jinja2 +108 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/TypeDefEnum.h.jinja2 +45 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/TypeDefMsg.h.jinja2 +791 -0
- embeddedproto-4.0.0b1/EmbeddedProto/templates/TypeOneof.h.jinja2 +178 -0
- embeddedproto-4.0.0b1/EmbeddedProto/version.json +3 -0
- embeddedproto-4.0.0b1/EmbeddedProto.egg-info/PKG-INFO +141 -0
- embeddedproto-4.0.0b1/EmbeddedProto.egg-info/SOURCES.txt +67 -0
- embeddedproto-4.0.0b1/EmbeddedProto.egg-info/dependency_links.txt +1 -0
- embeddedproto-4.0.0b1/EmbeddedProto.egg-info/entry_points.txt +3 -0
- embeddedproto-4.0.0b1/EmbeddedProto.egg-info/requires.txt +5 -0
- embeddedproto-4.0.0b1/EmbeddedProto.egg-info/top_level.txt +1 -0
- embeddedproto-4.0.0b1/LICENSE +30 -0
- embeddedproto-4.0.0b1/LICENSES/GPL-3.0-only.txt +674 -0
- embeddedproto-4.0.0b1/LICENSES/LicenseRef-EmbeddedProto-Commercial.txt +12 -0
- embeddedproto-4.0.0b1/PKG-INFO +141 -0
- embeddedproto-4.0.0b1/README.md +123 -0
- embeddedproto-4.0.0b1/pyproject.toml +35 -0
- embeddedproto-4.0.0b1/setup.cfg +4 -0
- embeddedproto-4.0.0b1/setup.py +84 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2020-2026 Embedded AMS B.V. - All Rights Reserved
|
|
3
|
+
#
|
|
4
|
+
# This file is part of Embedded Proto.
|
|
5
|
+
#
|
|
6
|
+
# Embedded Proto is dual licensed. You may use it under the terms of the
|
|
7
|
+
# GNU General Public License version 3 (GPLv3) as published by the Free
|
|
8
|
+
# Software Foundation, or under a commercial license from Embedded AMS B.V.
|
|
9
|
+
#
|
|
10
|
+
# Under the GPLv3 you must release the source code of
|
|
11
|
+
# any product you distribute that includes Embedded Proto or code
|
|
12
|
+
# generated by it. A commercial license removes that obligation.
|
|
13
|
+
# See <https://embeddedproto.com/pricing/>.
|
|
14
|
+
#
|
|
15
|
+
# Embedded Proto is distributed WITHOUT ANY WARRANTY; without even the
|
|
16
|
+
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
17
|
+
# See the LICENSE file in the root of the repository for details.
|
|
18
|
+
#
|
|
19
|
+
# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-EmbeddedProto-Commercial
|
|
20
|
+
#
|
|
21
|
+
# Embedded AMS B.V., Hoorn, the Netherlands - info at EmbeddedProto dot com
|
|
22
|
+
#
|
|
23
|
+
|
|
24
|
+
import os
|
|
25
|
+
import shutil
|
|
26
|
+
import sys
|
|
27
|
+
import grpc_tools.protoc as protoc
|
|
28
|
+
from importlib import resources
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_well_known_types_location():
|
|
32
|
+
# Obtain the location of the Protobuf well known types, they are a resource
|
|
33
|
+
# to the grpc-tools package the file system.
|
|
34
|
+
file_name = (
|
|
35
|
+
resources.files("grpc_tools") / "_proto"
|
|
36
|
+
).resolve()
|
|
37
|
+
return str(file_name)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _run_license_command(argv):
|
|
41
|
+
# Configure / verify the license token without running a build. Imported
|
|
42
|
+
# lazily so the normal protoc path does not pay for it.
|
|
43
|
+
import argparse
|
|
44
|
+
from EmbeddedProto import custom_header
|
|
45
|
+
|
|
46
|
+
parser = argparse.ArgumentParser(
|
|
47
|
+
prog="embeddedproto",
|
|
48
|
+
description="Configure the EmbeddedProto license token and server URL.")
|
|
49
|
+
parser.add_argument("--set-token", metavar="TOKEN", default=None,
|
|
50
|
+
help="Store this build token in the user config.")
|
|
51
|
+
parser.add_argument("--server-url", metavar="URL", default=None,
|
|
52
|
+
help="Store this license server URL (must be https://).")
|
|
53
|
+
parser.add_argument("--check-license", action="store_true",
|
|
54
|
+
help="Verify the configured token against the server; write nothing.")
|
|
55
|
+
args = parser.parse_args(argv)
|
|
56
|
+
return custom_header.configure(token=args.set_token, server_url=args.server_url,
|
|
57
|
+
check_only=args.check_license)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_options_proto_location():
|
|
61
|
+
# Obtain the folder holding embedded_proto_options.proto, it ships with this package.
|
|
62
|
+
return str(resources.files("EmbeddedProto").resolve())
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_plugin_location(program):
|
|
66
|
+
# Obtain the path of the protoc-gen-eams plugin.
|
|
67
|
+
#
|
|
68
|
+
# protoc searches its plugins on PATH, and the folder holding the embeddedproto command is
|
|
69
|
+
# not always on it. A build system for instance may call the command by its full path
|
|
70
|
+
# without activating the virtual environment. Prefer the plugin installed next to the
|
|
71
|
+
# command, fall back to PATH, and leave the lookup to protoc when neither has it.
|
|
72
|
+
bin_dir = os.path.dirname(os.path.abspath(program))
|
|
73
|
+
return shutil.which("protoc-gen-eams", path=bin_dir) or shutil.which("protoc-gen-eams")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def build_protoc_argv(argv, program=sys.argv[0]):
|
|
77
|
+
# Turn the command line of embeddedproto into the one handed to protoc. The program is the
|
|
78
|
+
# path this command was started with, used to locate the plugin. It also becomes the first
|
|
79
|
+
# element of the result, protoc takes that element as its own name and skips it.
|
|
80
|
+
#
|
|
81
|
+
# The include paths for embedded_proto_options.proto and the Protobuf well known types
|
|
82
|
+
# (google/protobuf/descriptor.proto, imported by the options file) are always appended,
|
|
83
|
+
# so a user only lists the folders holding their own proto files. The flag
|
|
84
|
+
# --IncludeWellKnownTypes from earlier versions is accepted and ignored.
|
|
85
|
+
argv = [x for x in argv if x != "--IncludeWellKnownTypes"]
|
|
86
|
+
argv = argv + ["-I" + get_options_proto_location(), "-I" + get_well_known_types_location()]
|
|
87
|
+
|
|
88
|
+
# Check if a plugin is included
|
|
89
|
+
if not [x for x in argv if x.startswith("--plugin")]:
|
|
90
|
+
# If not add the EmbeddedProto plugin, by path when it can be found.
|
|
91
|
+
plugin = get_plugin_location(program)
|
|
92
|
+
argv.insert(0, "--plugin=protoc-gen-eams" + ("=" + plugin if plugin else ""))
|
|
93
|
+
|
|
94
|
+
return [program] + argv
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def run_protoc(argv=sys.argv):
|
|
98
|
+
# Remove the program name
|
|
99
|
+
program = argv.pop(0)
|
|
100
|
+
|
|
101
|
+
# License configuration sub-commands, handled before protoc. These let
|
|
102
|
+
# `embeddedproto --set-token <KEY> [--server-url <URL>]` and
|
|
103
|
+
# `embeddedproto --check-license` manage the user config without a build.
|
|
104
|
+
_license_flags = ("--set-token", "--server-url", "--check-license")
|
|
105
|
+
if any(arg == flag or arg.startswith(flag + "=")
|
|
106
|
+
for arg in argv for flag in _license_flags):
|
|
107
|
+
sys.exit(_run_license_command(argv))
|
|
108
|
+
|
|
109
|
+
# Check if the --cpp-src-location parameter is present
|
|
110
|
+
if "--cpp-src-location" in argv:
|
|
111
|
+
# Get the location of the src folder
|
|
112
|
+
src_location = str((resources.files("EmbeddedProto") / "src").resolve())
|
|
113
|
+
print(src_location)
|
|
114
|
+
# Exit the script after printing the source location
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
# Hand the exit code of protoc to the caller, so build scripts notice a failed generation.
|
|
118
|
+
sys.exit(protoc.main(build_protoc_argv(argv, program)))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
if __name__ == "__main__":
|
|
122
|
+
run_protoc(sys.argv)
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2020-2026 Embedded AMS B.V. - All Rights Reserved
|
|
3
|
+
#
|
|
4
|
+
# This file is part of Embedded Proto.
|
|
5
|
+
#
|
|
6
|
+
# Embedded Proto is dual licensed. You may use it under the terms of the
|
|
7
|
+
# GNU General Public License version 3 (GPLv3) as published by the Free
|
|
8
|
+
# Software Foundation, or under a commercial license from Embedded AMS B.V.
|
|
9
|
+
#
|
|
10
|
+
# Under the GPLv3 you must release the source code of
|
|
11
|
+
# any product you distribute that includes Embedded Proto or code
|
|
12
|
+
# generated by it. A commercial license removes that obligation.
|
|
13
|
+
# See <https://embeddedproto.com/pricing/>.
|
|
14
|
+
#
|
|
15
|
+
# Embedded Proto is distributed WITHOUT ANY WARRANTY; without even the
|
|
16
|
+
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
17
|
+
# See the LICENSE file in the root of the repository for details.
|
|
18
|
+
#
|
|
19
|
+
# SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-EmbeddedProto-Commercial
|
|
20
|
+
#
|
|
21
|
+
# Embedded AMS B.V., Hoorn, the Netherlands - info at EmbeddedProto dot com
|
|
22
|
+
#
|
|
23
|
+
|
|
24
|
+
# Protobuf editions feature-resolution layer.
|
|
25
|
+
#
|
|
26
|
+
# Protobuf editions (edition = "2023" / "2024") replace the proto2/proto3 syntax
|
|
27
|
+
# switch with per-element "features" that can be overridden at file -> message ->
|
|
28
|
+
# field / enum / oneof scope. The descriptor sent to a code generator carries only
|
|
29
|
+
# the *explicitly set* overrides; a non-C++ plugin must resolve the effective value
|
|
30
|
+
# itself by walking the scope chain and falling back to the edition's defaults.
|
|
31
|
+
#
|
|
32
|
+
# This module provides:
|
|
33
|
+
# * EditionProfile: per-edition default value of each feature + which feature
|
|
34
|
+
# fields are legal in that edition.
|
|
35
|
+
# * FeatureResolver: picks the profile for a file and resolves a feature for any
|
|
36
|
+
# scope (file / message / field) by merging explicit overrides over the
|
|
37
|
+
# defaults.
|
|
38
|
+
#
|
|
39
|
+
# Resolution only happens here; consuming the resolved values (changing generated
|
|
40
|
+
# code) is done by the individual feature tickets. ED-1 only introduces the layer.
|
|
41
|
+
|
|
42
|
+
# -----------------------------------------------------------------------------
|
|
43
|
+
# Edition numbers (mirror google.protobuf.descriptor_pb2.Edition).
|
|
44
|
+
|
|
45
|
+
EDITION_PROTO2 = 998
|
|
46
|
+
EDITION_PROTO3 = 999
|
|
47
|
+
EDITION_2023 = 1000
|
|
48
|
+
EDITION_2024 = 1001
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# -----------------------------------------------------------------------------
|
|
52
|
+
# Feature value constants (mirror the google.protobuf.FeatureSet enums). Using
|
|
53
|
+
# named constants keeps the consuming tickets readable instead of comparing magic
|
|
54
|
+
# numbers.
|
|
55
|
+
|
|
56
|
+
class FieldPresence:
|
|
57
|
+
EXPLICIT = 1
|
|
58
|
+
IMPLICIT = 2
|
|
59
|
+
LEGACY_REQUIRED = 3
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class EnumType:
|
|
63
|
+
OPEN = 1
|
|
64
|
+
CLOSED = 2
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class RepeatedFieldEncoding:
|
|
68
|
+
PACKED = 1
|
|
69
|
+
EXPANDED = 2
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class Utf8Validation:
|
|
73
|
+
VERIFY = 2
|
|
74
|
+
NONE = 3
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class MessageEncoding:
|
|
78
|
+
LENGTH_PREFIXED = 1
|
|
79
|
+
DELIMITED = 2
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
class JsonFormat:
|
|
83
|
+
ALLOW = 1
|
|
84
|
+
LEGACY_BEST_EFFORT = 2
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# The six core feature fields EmbeddedProto resolves. These are the fields on the
|
|
88
|
+
# google.protobuf.FeatureSet message that carry behavior for the wire format /
|
|
89
|
+
# code generation.
|
|
90
|
+
CORE_FEATURE_FIELDS = (
|
|
91
|
+
"field_presence",
|
|
92
|
+
"enum_type",
|
|
93
|
+
"repeated_field_encoding",
|
|
94
|
+
"utf8_validation",
|
|
95
|
+
"message_encoding",
|
|
96
|
+
"json_format",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# Edition 2024 added these feature fields. They are codegen / naming concerns with
|
|
100
|
+
# no runtime effect for EmbeddedProto, but they are only legal from edition 2024.
|
|
101
|
+
EDITION_2024_FEATURE_FIELDS = (
|
|
102
|
+
"enforce_naming_style",
|
|
103
|
+
"default_symbol_visibility",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# -----------------------------------------------------------------------------
|
|
108
|
+
|
|
109
|
+
class EditionProfile:
|
|
110
|
+
"""Holds, for a single edition, the default value of every core feature and
|
|
111
|
+
the set of feature fields that may be explicitly set in that edition."""
|
|
112
|
+
|
|
113
|
+
def __init__(self, edition, defaults, legal_features):
|
|
114
|
+
self.edition = edition
|
|
115
|
+
# A complete mapping of every core feature field to its default value for
|
|
116
|
+
# this edition.
|
|
117
|
+
self.defaults = dict(defaults)
|
|
118
|
+
# The names of feature fields that are allowed to be explicitly set.
|
|
119
|
+
self.legal_features = set(legal_features)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# The default value of each core feature per edition. Editions are cumulative:
|
|
123
|
+
# 2024 keeps the 2023 core defaults and only adds new (codegen-only) features.
|
|
124
|
+
_PROTO3_DEFAULTS = {
|
|
125
|
+
"field_presence": FieldPresence.IMPLICIT,
|
|
126
|
+
"enum_type": EnumType.OPEN,
|
|
127
|
+
"repeated_field_encoding": RepeatedFieldEncoding.PACKED,
|
|
128
|
+
"utf8_validation": Utf8Validation.VERIFY,
|
|
129
|
+
"message_encoding": MessageEncoding.LENGTH_PREFIXED,
|
|
130
|
+
"json_format": JsonFormat.ALLOW,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
_EDITION_2023_DEFAULTS = {
|
|
134
|
+
"field_presence": FieldPresence.EXPLICIT,
|
|
135
|
+
"enum_type": EnumType.OPEN,
|
|
136
|
+
"repeated_field_encoding": RepeatedFieldEncoding.PACKED,
|
|
137
|
+
"utf8_validation": Utf8Validation.VERIFY,
|
|
138
|
+
"message_encoding": MessageEncoding.LENGTH_PREFIXED,
|
|
139
|
+
"json_format": JsonFormat.ALLOW,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
# Edition 2024 inherits the 2023 core defaults unchanged.
|
|
143
|
+
_EDITION_2024_DEFAULTS = dict(_EDITION_2023_DEFAULTS)
|
|
144
|
+
|
|
145
|
+
PROFILES = {
|
|
146
|
+
EDITION_PROTO3: EditionProfile(EDITION_PROTO3, _PROTO3_DEFAULTS, CORE_FEATURE_FIELDS),
|
|
147
|
+
EDITION_2023: EditionProfile(EDITION_2023, _EDITION_2023_DEFAULTS, CORE_FEATURE_FIELDS),
|
|
148
|
+
EDITION_2024: EditionProfile(
|
|
149
|
+
EDITION_2024, _EDITION_2024_DEFAULTS,
|
|
150
|
+
tuple(CORE_FEATURE_FIELDS) + EDITION_2024_FEATURE_FIELDS),
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# -----------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
def detect_edition(file_descriptor):
|
|
157
|
+
"""Map a FileDescriptorProto onto an edition number understood by PROFILES.
|
|
158
|
+
proto2 is rejected upstream; an unknown/absent syntax is treated as proto3."""
|
|
159
|
+
syntax = file_descriptor.syntax
|
|
160
|
+
if "editions" == syntax:
|
|
161
|
+
return file_descriptor.edition
|
|
162
|
+
# proto3 (syntax == "proto3") and the default empty syntax map to the proto3
|
|
163
|
+
# profile so the existing generation path becomes a special case of the same
|
|
164
|
+
# machinery.
|
|
165
|
+
return EDITION_PROTO3
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _feature_set_of(options):
|
|
169
|
+
"""Return the FeatureSet sub-message of an *Options message, or None when the
|
|
170
|
+
options object does not carry a features field (older descriptor types)."""
|
|
171
|
+
if options is None:
|
|
172
|
+
return None
|
|
173
|
+
try:
|
|
174
|
+
return options.features
|
|
175
|
+
except AttributeError:
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
# -----------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
class FeatureResolver:
|
|
182
|
+
"""Resolves the effective value of each feature for a single proto file by
|
|
183
|
+
merging the explicitly set overrides over the edition defaults."""
|
|
184
|
+
|
|
185
|
+
def __init__(self, file_descriptor):
|
|
186
|
+
self.edition = detect_edition(file_descriptor)
|
|
187
|
+
if self.edition not in PROFILES:
|
|
188
|
+
raise Exception("Unsupported protobuf edition: " + str(self.edition))
|
|
189
|
+
self.profile = PROFILES[self.edition]
|
|
190
|
+
|
|
191
|
+
# Verify the file itself does not set a feature that is illegal in this
|
|
192
|
+
# edition, then compute the file-scope resolved feature set.
|
|
193
|
+
self._check_legality(file_descriptor.options, "file " + file_descriptor.name)
|
|
194
|
+
self.file_features = self._merge(self.profile.defaults, file_descriptor.options)
|
|
195
|
+
|
|
196
|
+
def _check_legality(self, options, scope_description):
|
|
197
|
+
"""Raise when an options object explicitly sets a feature field that is not
|
|
198
|
+
legal in this edition (e.g. a 2024-only feature used in a 2023 file)."""
|
|
199
|
+
feature_set = _feature_set_of(options)
|
|
200
|
+
if feature_set is None:
|
|
201
|
+
return
|
|
202
|
+
for field_descriptor, _value in feature_set.ListFields():
|
|
203
|
+
name = field_descriptor.name
|
|
204
|
+
if name not in self.profile.legal_features:
|
|
205
|
+
raise Exception(
|
|
206
|
+
"The feature '" + name + "' set on " + scope_description +
|
|
207
|
+
" is not supported in edition " + str(self.edition) + ".")
|
|
208
|
+
|
|
209
|
+
def _merge(self, base_features, options):
|
|
210
|
+
"""Return a new resolved feature dict: a copy of base_features with the
|
|
211
|
+
explicit overrides from options applied on top."""
|
|
212
|
+
result = dict(base_features)
|
|
213
|
+
feature_set = _feature_set_of(options)
|
|
214
|
+
if feature_set is not None:
|
|
215
|
+
for name in CORE_FEATURE_FIELDS:
|
|
216
|
+
if feature_set.HasField(name):
|
|
217
|
+
result[name] = getattr(feature_set, name)
|
|
218
|
+
return result
|
|
219
|
+
|
|
220
|
+
def merge(self, base_features, options, scope_description=""):
|
|
221
|
+
"""Public merge used to derive a child scope's resolved features from its
|
|
222
|
+
parent's. Also enforces edition legality of the explicit overrides."""
|
|
223
|
+
self._check_legality(options, scope_description)
|
|
224
|
+
return self._merge(base_features, options)
|
|
225
|
+
|
|
226
|
+
def resolve(self, *option_holders):
|
|
227
|
+
"""Resolve all core features from an ordered list of option holders given
|
|
228
|
+
outermost-first (e.g. file, enclosing message(s), field). Each holder is an
|
|
229
|
+
*Options message (or None). Returns a complete feature dict."""
|
|
230
|
+
result = dict(self.profile.defaults)
|
|
231
|
+
for options in option_holders:
|
|
232
|
+
result = self._merge(result, options)
|
|
233
|
+
return result
|
|
234
|
+
|
|
235
|
+
# -- typed accessors on a resolved feature dict ---------------------------
|
|
236
|
+
|
|
237
|
+
@staticmethod
|
|
238
|
+
def field_presence(resolved):
|
|
239
|
+
return resolved["field_presence"]
|
|
240
|
+
|
|
241
|
+
@staticmethod
|
|
242
|
+
def enum_type(resolved):
|
|
243
|
+
return resolved["enum_type"]
|
|
244
|
+
|
|
245
|
+
@staticmethod
|
|
246
|
+
def repeated_encoding(resolved):
|
|
247
|
+
return resolved["repeated_field_encoding"]
|
|
248
|
+
|
|
249
|
+
@staticmethod
|
|
250
|
+
def message_encoding(resolved):
|
|
251
|
+
return resolved["message_encoding"]
|
|
252
|
+
|
|
253
|
+
@staticmethod
|
|
254
|
+
def utf8_validation(resolved):
|
|
255
|
+
return resolved["utf8_validation"]
|