From 9b6bd309023c2733f603603d39e5c2bdc66a0f83 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sun, 29 Jan 2023 01:22:10 -0500 Subject: [PATCH 01/35] Support diffing syntax, import elements (#58) --- TODO.md | 4 +-- src/proto_file.py | 12 +++++-- src/proto_import.py | 66 ++++++++++++++++++++++++++++++++++++- src/proto_node.py | 4 +++ src/proto_string_literal.py | 3 ++ src/proto_syntax.py | 20 ++++++++++- test/BUILD.bazel | 9 +++++ test/proto_file_test.py | 11 +++++++ test/proto_import_test.py | 45 ++++++++++++++++++++++++- test/proto_syntax_test.py | 20 ++++++++++- 10 files changed, 186 insertions(+), 8 deletions(-) create mode 100644 test/proto_file_test.py diff --git a/TODO.md b/TODO.md index 932562d..99b3afb 100644 --- a/TODO.md +++ b/TODO.md @@ -60,8 +60,8 @@ - [x] Normalizing - [ ] Complete diffs - [ ] Proto file-level diffs - - [ ] Syntax changes - - [ ] Import changes + - [x] Syntax changes + - [x] Import changes - [ ] Package changes - [ ] Option changes - [ ] Enum-level diffs diff --git a/src/proto_file.py b/src/proto_file.py index d02291b..b208e36 100644 --- a/src/proto_file.py +++ b/src/proto_file.py @@ -1,5 +1,7 @@ +from typing import Optional + from src.proto_import import ProtoImport -from src.proto_node import ProtoNode +from src.proto_node import ProtoNode, ProtoNodeDiff from src.proto_option import ProtoOption from src.proto_package import ProtoPackage from src.proto_syntax import ProtoSyntax @@ -18,7 +20,7 @@ def imports(self) -> list[ProtoImport]: return [node for node in self.nodes if isinstance(node, ProtoImport)] @property - def package(self) -> ProtoPackage: + def package(self) -> Optional[ProtoPackage]: return next(node for node in self.nodes if isinstance(node, ProtoPackage)) @property @@ -36,3 +38,9 @@ def serialize(self) -> str: serialized_parts.append(node.serialize()) return "\n".join(serialized_parts) + + def diff(self, other: "ProtoFile") -> list[ProtoNodeDiff]: + diffs = [] + diffs.extend(ProtoSyntax.diff(self.syntax, other.syntax)) + diffs.extend(ProtoImport.diff(self.imports, other.imports)) + return [d for d in diffs if d is not None] diff --git a/src/proto_import.py b/src/proto_import.py index 1c03c02..dc00a32 100644 --- a/src/proto_import.py +++ b/src/proto_import.py @@ -1,6 +1,6 @@ from typing import Optional -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff from src.proto_string_literal import ProtoStringLiteral @@ -25,6 +25,13 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) + def __dict__(self) -> dict: + return { + "path": self.path.serialize(), + "weak": self.weak, + "public": self.public, + } + def normalize(self) -> "ProtoImport": return self @@ -68,3 +75,60 @@ def serialize(self) -> str: parts.append("public") parts.append(f"{self.path.serialize()};") return " ".join(parts) + + @staticmethod + def diff( + left: list["ProtoImport"], right: list["ProtoImport"] + ) -> list["ProtoNodeDiff"]: + diffs = [] + left_names = set(i.path for i in left) + right_names = set(i.path for i in right) + for name in left_names - right_names: + diffs.append(ProtoImportAdded(next(i for i in left if i.path == name))) + for name in right_names - left_names: + diffs.append(ProtoImportRemoved(next(i for i in right if i.path == name))) + for name in left_names & right_names: + left_import = next(i for i in left if i.path == name) + right_import = next(i for i in right if i.path == name) + if left_import.weak and not right_import.weak: + diffs.append(ProtoImportMadeWeak(right_import)) + if not left_import.weak and right_import.weak: + diffs.append(ProtoImportMadeNonWeak(right_import)) + if left_import.public and not right_import.public: + diffs.append(ProtoImportMadePublic(right_import)) + if not left_import.public and right_import.public: + diffs.append(ProtoImportMadeNonPublic(right_import)) + + return diffs + + +class ProtoImportAdded(ProtoNodeDiff): + def __init__(self, proto_import: ProtoImport): + self.proto_import = proto_import + + def __eq__(self, other: "ProtoImportAdded") -> bool: + return self.proto_import == other.proto_import + + +class ProtoImportRemoved(ProtoImportAdded): + pass + + +class ProtoImportMadeWeak(ProtoImportAdded): + pass + + +class ProtoImportMadeWeak(ProtoImportAdded): + pass + + +class ProtoImportMadeNonWeak(ProtoImportAdded): + pass + + +class ProtoImportMadePublic(ProtoImportAdded): + pass + + +class ProtoImportMadeNonPublic(ProtoImportAdded): + pass diff --git a/src/proto_node.py b/src/proto_node.py index de8685f..05310eb 100644 --- a/src/proto_node.py +++ b/src/proto_node.py @@ -26,3 +26,7 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) + + +class ProtoNodeDiff(abc.ABC): + pass diff --git a/src/proto_string_literal.py b/src/proto_string_literal.py index b9a4b64..7336b0f 100644 --- a/src/proto_string_literal.py +++ b/src/proto_string_literal.py @@ -19,6 +19,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) + def __hash__(self): + return hash(str(self)) + def normalize(self) -> "ProtoStringLiteral": return self diff --git a/src/proto_syntax.py b/src/proto_syntax.py index 7e00991..25109c7 100644 --- a/src/proto_syntax.py +++ b/src/proto_syntax.py @@ -1,7 +1,7 @@ from enum import Enum from typing import Optional -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff from src.proto_string_literal import ProtoStringLiteral @@ -23,6 +23,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) + def __dict__(self) -> dict: + return {"syntax": self.syntax.serialize()} + def normalize(self) -> "ProtoSyntax": return self @@ -50,3 +53,18 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: def serialize(self) -> str: return f"syntax = {self.syntax.serialize()};" + + @staticmethod + def diff(left: "ProtoSyntax", right: "ProtoSyntax") -> list["ProtoNodeDiff"]: + if left == right: + return [] + return [ProtoSyntaxChanged(left, right)] + + +class ProtoSyntaxChanged(ProtoNodeDiff): + def __init__(self, left: ProtoStringLiteral, right: ProtoStringLiteral): + self.left = left + self.right = right + + def __eq__(self, other: "ProtoSyntaxChanged") -> bool: + return self.left == other.left and self.right == other.right diff --git a/test/BUILD.bazel b/test/BUILD.bazel index ceea7c1..b538aae 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -103,6 +103,7 @@ py_test( srcs = ["proto_import_test.py"], deps = [ "//src:proto_import", + "//src:proto_string_literal", ], ) @@ -213,6 +214,14 @@ py_test( ], ) +py_test( + name = "proto_file_test", + srcs = ["proto_file_test.py"], + deps = [ + "//src:proto_file", + ], +) + sh_test( name = "parser_binary_test", srcs = ["parser_binary_test.sh"], diff --git a/test/proto_file_test.py b/test/proto_file_test.py new file mode 100644 index 0000000..1bbf1cd --- /dev/null +++ b/test/proto_file_test.py @@ -0,0 +1,11 @@ +import unittest + +from src.proto_file import ProtoFile + + +class ProtoFileTest(unittest.TestCase): + pass + + +if __name__ == "__main__": + unittest.main() diff --git a/test/proto_import_test.py b/test/proto_import_test.py index 0f74495..bf43205 100644 --- a/test/proto_import_test.py +++ b/test/proto_import_test.py @@ -1,7 +1,14 @@ import unittest from textwrap import dedent -from src.proto_import import ProtoImport +from src.proto_import import ( + ProtoImport, + ProtoImportAdded, + ProtoImportMadeNonWeak, + ProtoImportMadePublic, + ProtoImportRemoved, +) +from src.proto_string_literal import ProtoStringLiteral class ImportTest(unittest.TestCase): @@ -128,6 +135,42 @@ def test_public_mixed_imports(self): third_parsed_import.node.serialize(), 'import public "bat.proto";' ) + def test_diff_same_path_simple(self): + pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + pf2 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + self.assertEqual(ProtoImport.diff([pf1], [pf2]), []) + + def test_diff_added_path_simple(self): + pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + self.assertEqual(ProtoImport.diff([pf1], []), [ProtoImportAdded(pf1)]) + + def test_diff_removed_path_simple(self): + pf2 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + self.assertEqual(ProtoImport.diff([], [pf2]), [ProtoImportRemoved(pf2)]) + + def test_diff_different_path_simple(self): + pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + pf2 = ProtoImport(ProtoStringLiteral("path/to/some/other.proto")) + self.assertEqual( + ProtoImport.diff([pf1], [pf2]), + [ProtoImportAdded(pf1), ProtoImportRemoved(pf2)], + ) + + def test_diff_changed_optional_attributes(self): + pf1 = ProtoImport( + ProtoStringLiteral("path/to/some.proto"), weak=False, public=True + ) + pf2 = ProtoImport( + ProtoStringLiteral("path/to/some.proto"), weak=True, public=False + ) + self.assertEqual( + ProtoImport.diff([pf1], [pf2]), + [ + ProtoImportMadeNonWeak(pf2), + ProtoImportMadePublic(pf2), + ], + ) + if __name__ == "__main__": unittest.main() diff --git a/test/proto_syntax_test.py b/test/proto_syntax_test.py index 1d2aae7..6abfda1 100644 --- a/test/proto_syntax_test.py +++ b/test/proto_syntax_test.py @@ -1,7 +1,7 @@ import unittest from src.proto_string_literal import ProtoStringLiteral -from src.proto_syntax import ProtoSyntax, ProtoSyntaxType +from src.proto_syntax import ProtoSyntax, ProtoSyntaxChanged class SyntaxTest(unittest.TestCase): @@ -75,6 +75,24 @@ def test_syntax_malformed(self): with self.assertRaises(ValueError): ProtoSyntax.match("syntax = proton") + def test_diff_empty_same_syntax_returns_empty(self): + pf1 = ProtoSyntax(ProtoStringLiteral("proto3")) + pf2 = ProtoSyntax(ProtoStringLiteral("proto3")) + self.assertEqual(ProtoSyntax.diff(pf1, pf2), []) + + def test_diff_empty_different_syntax_returns_syntax_diff(self): + pf1 = ProtoSyntax(ProtoStringLiteral("proto3")) + pf2 = ProtoSyntax(ProtoStringLiteral("proto2")) + self.assertEqual( + ProtoSyntax.diff(pf1, pf2), + [ + ProtoSyntaxChanged( + ProtoSyntax(ProtoStringLiteral("proto3")), + ProtoSyntax(ProtoStringLiteral("proto2")), + ) + ], + ) + if __name__ == "__main__": unittest.main() From 8b6fd051c4b553b656bc8156e7f64469687d1375 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sun, 29 Jan 2023 01:41:47 -0500 Subject: [PATCH 02/35] Update README.md (#59) --- README.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5fec8d4..bd8333d 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,35 @@ This is a Python-based protobuf parser. It is intended to serve as a reference implementation and is _not_ production-ready. +![Build status](https://github.com/shaldengeki/py_proto/actions/workflows/main.yml/badge.svg) + +## Usage + +Right now, the primary way to use this as a library in your Bazelified Python code. + +Mount this repo in your Bazel workspace, then add `@py_proto//src:parser` as a dependency: +``` +py_library( + name = "your_python_code", + # ... + deps = [ + "@py_proto//src:parser", + ] +) +``` + +Then, in your Python code, use the parser: +```python +from src.parser import ParseError, Parser +with open("your.proto", "r") as proto_file: + parsed_proto = Parser.loads(proto_file.read()) + +print(parsed_proto.syntax) +``` + ## Development -We support building & running via Bazel. +We support building & running via Bazel. See the `TODO.md` for what's on the roadmap. ### Bazel From 2eb9b4a16af913024064ad6961312581fba8a372 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Fri, 10 Feb 2023 21:02:49 -0500 Subject: [PATCH 03/35] Support diffs of package changes (#60) --- TODO.md | 2 +- src/proto_file.py | 1 + src/proto_package.py | 37 ++++++++++++++++++++++++++++++- test/proto_package_test.py | 45 +++++++++++++++++++++++++++++++++++++- 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/TODO.md b/TODO.md index 99b3afb..a93cb74 100644 --- a/TODO.md +++ b/TODO.md @@ -62,7 +62,7 @@ - [ ] Proto file-level diffs - [x] Syntax changes - [x] Import changes - - [ ] Package changes + - [x] Package changes - [ ] Option changes - [ ] Enum-level diffs - [ ] Additions/removals diff --git a/src/proto_file.py b/src/proto_file.py index b208e36..01c53e2 100644 --- a/src/proto_file.py +++ b/src/proto_file.py @@ -43,4 +43,5 @@ def diff(self, other: "ProtoFile") -> list[ProtoNodeDiff]: diffs = [] diffs.extend(ProtoSyntax.diff(self.syntax, other.syntax)) diffs.extend(ProtoImport.diff(self.imports, other.imports)) + diffs.extend(ProtoPackage.diff(self.package, other.package)) return [d for d in diffs if d is not None] diff --git a/src/proto_package.py b/src/proto_package.py index d44d5ee..c4da2c0 100644 --- a/src/proto_package.py +++ b/src/proto_package.py @@ -1,6 +1,6 @@ from typing import Optional -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff class ProtoPackage(ProtoNode): @@ -48,3 +48,38 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: def serialize(self) -> str: return f"package {self.package};" + + @staticmethod + def diff(left: "ProtoPackage", right: "ProtoPackage") -> list["ProtoNodeDiff"]: + if left == right: + return [] + elif left is None and right is not None: + return [ProtoPackageAdded(right)] + elif left is not None and right is None: + return [ProtoPackageRemoved(left)] + return [ProtoPackageChanged(left, right)] + + +class ProtoPackageChanged(ProtoNodeDiff): + def __init__(self, left: str, right: str): + self.left = left + self.right = right + + def __eq__(self, other: "ProtoPackageChanged") -> bool: + return self.left == other.left and self.right == other.right + + +class ProtoPackageAdded(ProtoNodeDiff): + def __init__(self, left: str): + self.left = left + + def __eq__(self, other: "ProtoPackageAdded") -> bool: + return self.left == other.left + + +class ProtoPackageRemoved(ProtoNodeDiff): + def __init__(self, right: str): + self.right = right + + def __eq__(self, other: "ProtoPackageRemoved") -> bool: + return self.right == other.right diff --git a/test/proto_package_test.py b/test/proto_package_test.py index 491708f..0225c19 100644 --- a/test/proto_package_test.py +++ b/test/proto_package_test.py @@ -1,7 +1,12 @@ import unittest from textwrap import dedent -from src.proto_package import ProtoPackage +from src.proto_package import ( + ProtoPackage, + ProtoPackageAdded, + ProtoPackageChanged, + ProtoPackageRemoved, +) class PackageTest(unittest.TestCase): @@ -55,6 +60,44 @@ def test_package_malformed(self): with self.assertRaises(ValueError): ProtoPackage.match("packagefoo.bar;") + def test_diff_same_package_returns_empty(self): + pp1 = ProtoPackage("my.awesome.package") + pp2 = ProtoPackage("my.awesome.package") + self.assertEqual(ProtoPackage.diff(pp1, pp2), []) + + def test_diff_different_package_returns_package_diff(self): + pp1 = ProtoPackage("my.awesome.package") + pp2 = ProtoPackage("my.other.awesome.package") + self.assertEqual( + ProtoPackage.diff(pp1, pp2), + [ + ProtoPackageChanged( + ProtoPackage("my.awesome.package"), + ProtoPackage("my.other.awesome.package"), + ) + ], + ) + + def test_diff_package_added(self): + pp1 = None + pp2 = ProtoPackage("my.new.package") + self.assertEqual( + ProtoPackage.diff(pp1, pp2), + [ + ProtoPackageAdded(ProtoPackage("my.new.package")), + ], + ) + + def test_diff_package_removed(self): + pp1 = ProtoPackage("my.old.package") + pp2 = None + self.assertEqual( + ProtoPackage.diff(pp1, pp2), + [ + ProtoPackageRemoved(ProtoPackage("my.old.package")), + ], + ) + if __name__ == "__main__": unittest.main() From c00880e6d782b1d693fe3f42b6033dd79ef0b40b Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sat, 11 Feb 2023 01:32:44 -0500 Subject: [PATCH 04/35] Add support for proto option diffs (#61) --- TODO.md | 2 +- src/proto_identifier.py | 3 + src/proto_option.py | 90 ++++++++- src/proto_package.py | 6 +- test/proto_option_test.py | 376 ++++++++++++++++++++++++++++++++++++- test/proto_package_test.py | 8 +- 6 files changed, 475 insertions(+), 10 deletions(-) diff --git a/TODO.md b/TODO.md index a93cb74..0d937af 100644 --- a/TODO.md +++ b/TODO.md @@ -63,7 +63,7 @@ - [x] Syntax changes - [x] Import changes - [x] Package changes - - [ ] Option changes + - [x] Option changes - [ ] Enum-level diffs - [ ] Additions/removals - [ ] Option changes diff --git a/src/proto_identifier.py b/src/proto_identifier.py index 6dd6164..cc55aaf 100644 --- a/src/proto_identifier.py +++ b/src/proto_identifier.py @@ -20,6 +20,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) + def __hash__(self): + return hash(str(self)) + def normalize(self) -> "ProtoIdentifier": return self diff --git a/src/proto_option.py b/src/proto_option.py index 000a39c..e86e360 100644 --- a/src/proto_option.py +++ b/src/proto_option.py @@ -6,7 +6,7 @@ ProtoFullIdentifier, ProtoIdentifier, ) -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff class ProtoOption(ProtoNode): @@ -23,6 +23,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) + def __hash__(self): + return hash(str(self)) + def normalize(self) -> "ProtoOption": return self @@ -91,3 +94,88 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: def serialize(self) -> str: return f"option {self.name.serialize()} = {self.value.serialize()};" + + @staticmethod + def diff(left: "ProtoOption", right: "ProtoOption") -> list["ProtoNodeDiff"]: + if left is None and right is not None: + return [ProtoOptionAdded(right)] + elif left is not None and right is None: + return [ProtoOptionRemoved(left)] + elif left is None and right is None: + return [] + elif left.name != right.name: + return [] + elif left == right: + return [] + return [ProtoOptionValueChanged(left.name, left.value, right.value)] + + @staticmethod + def diff_sets( + left: list["ProtoOption"], right: list["ProtoOption"] + ) -> list["ProtoNodeDiff"]: + diffs = [] + left_names = set(o.name.identifier for o in left) + right_names = set(o.name.identifier for o in right) + for name in left_names - right_names: + diffs.append( + ProtoOptionAdded(next(i for i in left if i.name.identifier == name)) + ) + for name in right_names - left_names: + diffs.append( + ProtoOptionRemoved(next(i for i in right if i.name.identifier == name)) + ) + for name in left_names & right_names: + left_option = next(i for i in left if i.name.identifier == name) + right_option = next(i for i in right if i.name.identifier == name) + diffs.extend(ProtoOption.diff(left_option, right_option)) + + return diffs + + +class ProtoOptionValueChanged(ProtoNodeDiff): + def __init__(self, name: ProtoIdentifier, left: str, right: str): + self.name = name + self.left = left + self.right = right + + def __eq__(self, other: "ProtoOptionValueChanged") -> bool: + return ( + isinstance(other, ProtoOptionValueChanged) + and self.name == other.name + and self.left == other.left + and self.right == other.right + ) + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return str(self) + + +class ProtoOptionAdded(ProtoNodeDiff): + def __init__(self, left: str): + self.left = left + + def __eq__(self, other: "ProtoOptionAdded") -> bool: + return isinstance(other, ProtoOptionAdded) and self.left == other.left + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return str(self) + + +class ProtoOptionRemoved(ProtoNodeDiff): + def __init__(self, right: str): + self.right = right + + def __eq__(self, other: "ProtoOptionRemoved") -> bool: + return isinstance(other, ProtoOptionRemoved) and self.right == other.right + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return str(self) diff --git a/src/proto_package.py b/src/proto_package.py index c4da2c0..569ee2c 100644 --- a/src/proto_package.py +++ b/src/proto_package.py @@ -53,10 +53,10 @@ def serialize(self) -> str: def diff(left: "ProtoPackage", right: "ProtoPackage") -> list["ProtoNodeDiff"]: if left == right: return [] - elif left is None and right is not None: - return [ProtoPackageAdded(right)] elif left is not None and right is None: - return [ProtoPackageRemoved(left)] + return [ProtoPackageAdded(left)] + elif left is None and right is not None: + return [ProtoPackageRemoved(right)] return [ProtoPackageChanged(left, right)] diff --git a/test/proto_option_test.py b/test/proto_option_test.py index 6d353fc..caf20ed 100644 --- a/test/proto_option_test.py +++ b/test/proto_option_test.py @@ -5,11 +5,19 @@ from src.proto_float import ProtoFloat, ProtoFloatSign from src.proto_identifier import ProtoFullIdentifier, ProtoIdentifier from src.proto_int import ProtoInt, ProtoIntSign -from src.proto_option import ProtoOption +from src.proto_option import ( + ProtoOption, + ProtoOptionAdded, + ProtoOptionRemoved, + ProtoOptionValueChanged, +) from src.proto_string_literal import ProtoStringLiteral class OptionTest(unittest.TestCase): + + maxDiff = None + def test_string_option(self): string_option = ProtoOption.match("option foo = 'test value';") self.assertEqual(string_option.node.name, ProtoIdentifier("foo")) @@ -192,6 +200,372 @@ def test_float_option(self): ProtoConstant(ProtoFloat(float(120), ProtoFloatSign.NEGATIVE)), ) + def test_diff_same_option_returns_empty(self): + po1 = ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + po2 = ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + self.assertEqual(ProtoOption.diff(po1, po2), []) + + def test_diff_different_option_name_returns_empty(self): + po1 = ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + po2 = ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + self.assertEqual(ProtoOption.diff(po1, po2), []) + + def test_diff_different_option_value_returns_option_diff(self): + po1 = ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + po2 = ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("other value")), + ) + self.assertEqual( + ProtoOption.diff(po1, po2), + [ + ProtoOptionValueChanged( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ProtoConstant(ProtoStringLiteral("other value")), + ) + ], + ) + + def test_diff_option_added(self): + po1 = None + po2 = ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + self.assertEqual( + ProtoOption.diff(po1, po2), + [ + ProtoOptionAdded( + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + ), + ], + ) + + def test_diff_option_removed(self): + po1 = ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + po2 = None + self.assertEqual( + ProtoOption.diff(po1, po2), + [ + ProtoOptionRemoved( + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + ), + ], + ) + + def test_diff_sets_empty_returns_empty(self): + set1 = [] + set2 = [] + self.assertEqual(ProtoOption.diff_sets(set1, set2), []) + + def test_diff_sets_no_change(self): + set1 = [ + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ), + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ), + ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ), + ] + self.assertEqual(ProtoOption.diff_sets(set1, set1), []) + + def test_diff_sets_all_removed(self): + set1 = [] + set2 = [ + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ), + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ), + ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ), + ] + diff = ProtoOption.diff_sets(set1, set2) + + self.assertIn( + ProtoOptionRemoved( + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + ), + diff, + ) + self.assertIn( + ProtoOptionRemoved( + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ) + ), + diff, + ) + self.assertIn( + ProtoOptionRemoved( + ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ) + ), + diff, + ) + self.assertEqual(3, len(diff)) + + def test_diff_sets_all_added(self): + set1 = [ + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ), + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ), + ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ), + ] + set2 = [] + diff = ProtoOption.diff_sets(set1, set2) + + self.assertIn( + ProtoOptionAdded( + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + ), + diff, + ) + self.assertIn( + ProtoOptionAdded( + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ) + ), + diff, + ) + self.assertIn( + ProtoOptionAdded( + ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ) + ), + diff, + ) + self.assertEqual(3, len(diff)) + + def test_diff_sets_mutually_exclusive(self): + set1 = [ + ProtoOption( + ProtoIdentifier("some.custom.option.but.not.prior"), + ProtoConstant(ProtoStringLiteral("some value")), + ), + ProtoOption( + ProtoIdentifier("ruby_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ), + ProtoOption( + ProtoIdentifier("other.option.but.stil.not.prior"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ), + ] + set2 = [ + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ), + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ), + ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ), + ] + + diff = ProtoOption.diff_sets(set1, set2) + + self.assertIn( + ProtoOptionAdded( + ProtoOption( + ProtoIdentifier("some.custom.option.but.not.prior"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + ), + diff, + ) + self.assertIn( + ProtoOptionAdded( + ProtoOption( + ProtoIdentifier("other.option.but.stil.not.prior"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ) + ), + diff, + ) + + self.assertIn( + ProtoOptionAdded( + ProtoOption( + ProtoIdentifier("ruby_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ) + ), + diff, + ) + + self.assertIn( + ProtoOptionRemoved( + ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ) + ), + diff, + ) + + self.assertIn( + ProtoOptionRemoved( + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + ), + diff, + ) + + self.assertIn( + ProtoOptionRemoved( + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ) + ), + diff, + ) + + self.assertEqual(6, len(diff)) + + def test_diff_sets_overlap(self): + set1 = [ + ProtoOption( + ProtoIdentifier("some.custom.option.but.not.prior"), + ProtoConstant(ProtoStringLiteral("some value")), + ), + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.bat")), + ), + ProtoOption( + ProtoIdentifier("other.option.but.stil.not.prior"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ), + ] + set2 = [ + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ), + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ), + ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ), + ] + + diff = ProtoOption.diff_sets(set1, set2) + + self.assertIn( + ProtoOptionRemoved( + ProtoOption( + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + ), + diff, + ) + + self.assertIn( + ProtoOptionRemoved( + ProtoOption( + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ) + ), + diff, + ) + self.assertIn( + ProtoOptionAdded( + ProtoOption( + ProtoIdentifier("some.custom.option.but.not.prior"), + ProtoConstant(ProtoStringLiteral("some value")), + ) + ), + diff, + ) + self.assertIn( + ProtoOptionAdded( + ProtoOption( + ProtoIdentifier("other.option.but.stil.not.prior"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + ) + ), + diff, + ) + self.assertIn( + ProtoOptionValueChanged( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.bat")), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ), + diff, + ) + self.assertEqual(5, len(diff)) + if __name__ == "__main__": unittest.main() diff --git a/test/proto_package_test.py b/test/proto_package_test.py index 0225c19..b6707ba 100644 --- a/test/proto_package_test.py +++ b/test/proto_package_test.py @@ -79,8 +79,8 @@ def test_diff_different_package_returns_package_diff(self): ) def test_diff_package_added(self): - pp1 = None - pp2 = ProtoPackage("my.new.package") + pp1 = ProtoPackage("my.new.package") + pp2 = None self.assertEqual( ProtoPackage.diff(pp1, pp2), [ @@ -89,8 +89,8 @@ def test_diff_package_added(self): ) def test_diff_package_removed(self): - pp1 = ProtoPackage("my.old.package") - pp2 = None + pp1 = None + pp2 = ProtoPackage("my.old.package") self.assertEqual( ProtoPackage.diff(pp1, pp2), [ From c4191ab31217e30a26c39998da42eac4a0d054cd Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Mon, 13 Feb 2023 21:33:52 -0500 Subject: [PATCH 05/35] Support diffing enum additions & removals (#62) --- TODO.md | 4 +- src/BUILD.bazel | 1 + src/proto_enum.py | 151 ++++++++- src/proto_file.py | 9 +- src/proto_import.py | 2 +- test/proto_enum_test.py | 629 +++++++++++++++++++++++++++++++++++++- test/proto_import_test.py | 20 +- 7 files changed, 800 insertions(+), 16 deletions(-) diff --git a/TODO.md b/TODO.md index 0d937af..f149c01 100644 --- a/TODO.md +++ b/TODO.md @@ -59,13 +59,13 @@ - [ ] Diffs - [x] Normalizing - [ ] Complete diffs - - [ ] Proto file-level diffs + - [x] Proto file-level diffs - [x] Syntax changes - [x] Import changes - [x] Package changes - [x] Option changes - [ ] Enum-level diffs - - [ ] Additions/removals + - [x] Additions/removals - [ ] Option changes - [ ] Field changes - [ ] Value changes diff --git a/src/BUILD.bazel b/src/BUILD.bazel index ac1326a..062c592 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -219,6 +219,7 @@ py_library( srcs = ["proto_file.py"], visibility = ["//visibility:public"], deps = [ + ":proto_enum", ":proto_import", ":proto_node", ":proto_option", diff --git a/src/proto_enum.py b/src/proto_enum.py index ecb03fe..8643371 100644 --- a/src/proto_enum.py +++ b/src/proto_enum.py @@ -7,7 +7,7 @@ ) from src.proto_identifier import ProtoIdentifier from src.proto_int import ProtoInt, ProtoIntSign -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff from src.proto_option import ProtoOption from src.proto_reserved import ProtoReserved @@ -223,3 +223,152 @@ def serialize(self) -> str: + ["}"] ) return "\n".join(serialize_parts) + + @staticmethod + def diff(left: "ProtoEnum", right: "ProtoEnum") -> list["ProtoNodeDiff"]: + if left is None and right is not None: + return [ProtoEnumAdded(right)] + elif left is not None and right is None: + return [ProtoEnumRemoved(left)] + elif left is None and right is None: + return [] + elif left.name != right.name: + return [] + elif left == right: + return [] + # TODO: process the enum options and values. + return [] + + @staticmethod + def diff_sets( + left: list["ProtoEnum"], right: list["ProtoEnum"] + ) -> list["ProtoNodeDiff"]: + diffs = [] + left_names = set(o.name.identifier for o in left) + right_names = set(o.name.identifier for o in right) + for name in left_names - right_names: + diffs.append( + ProtoEnumAdded(next(i for i in left if i.name.identifier == name)) + ) + for name in right_names - left_names: + diffs.append( + ProtoEnumRemoved(next(i for i in right if i.name.identifier == name)) + ) + for name in left_names & right_names: + left_option = next(i for i in left if i.name.identifier == name) + right_option = next(i for i in right if i.name.identifier == name) + diffs.extend(ProtoEnum.diff(left_option, right_option)) + + return diffs + + +class ProtoEnumAdded(ProtoNodeDiff): + def __init__(self, enum: ProtoEnum): + self.enum = enum + + def __eq__(self, other: "ProtoEnumAdded") -> bool: + return isinstance(other, ProtoEnumAdded) and self.enum == other.enum + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return str(self) + + +class ProtoEnumRemoved(ProtoNodeDiff): + def __init__(self, enum: ProtoEnum): + self.enum = enum + + def __eq__(self, other: "ProtoEnumRemoved") -> bool: + return isinstance(other, ProtoEnumRemoved) and self.enum == other.enum + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return str(self) + + +class ProtoEnumValueAdded(ProtoNodeDiff): + def __init__(self, enum: "ProtoEnum", enum_value: "ProtoEnumValue"): + self.enum = enum + self.enum_value = enum_value + + def __eq__(self, other: "ProtoEnumValueAdded") -> bool: + return ( + isinstance(other, ProtoEnumValueAdded) + and self.enum == other.enum + and self.enum_value == other.enum_value + ) + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return str(self) + + +class ProtoEnumValueRemoved(ProtoNodeDiff): + def __init__(self, enum: "ProtoEnum", enum_value: "ProtoEnumValue"): + self.enum = enum + self.enum_value = enum_value + + def __eq__(self, other: "ProtoEnumValueRemoved") -> bool: + return ( + isinstance(other, ProtoEnumValueRemoved) + and self.enum == other.enum + and self.enum_value == other.enum_value + ) + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return str(self) + + +class ProtoEnumValueNameChanged(ProtoNodeDiff): + def __init__( + self, enum: ProtoEnum, enum_value: ProtoEnumValue, new_name: ProtoIdentifier + ): + self.enum = enum + self.enum_value = enum_value + self.new_name = new_name + + def __eq__(self, other: "ProtoEnumValueNameChanged") -> bool: + return ( + isinstance(other, ProtoEnumValueNameChanged) + and self.enum == other.enum + and self.enum_value == other.enum_value + and self.new_name == other.new_name + ) + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return str(self) + + +class ProtoEnumValueValueChanged(ProtoNodeDiff): + def __init__( + self, enum: ProtoEnum, enum_value: ProtoEnumValue, new_value: ProtoInt + ): + self.enum = enum + self.enum_value = enum_value + self.new_value = new_value + + def __eq__(self, other: "ProtoEnumValueNameChanged") -> bool: + return ( + isinstance(other, ProtoEnumValueNameChanged) + and self.enum == other.enum + and self.enum_value == other.enum_value + and self.new_value == other.new_value + ) + + def __str__(self) -> str: + return f"" + + def __repr__(self) -> str: + return str(self) diff --git a/src/proto_file.py b/src/proto_file.py index 01c53e2..2d41cb3 100644 --- a/src/proto_file.py +++ b/src/proto_file.py @@ -1,5 +1,6 @@ from typing import Optional +from src.proto_enum import ProtoEnum from src.proto_import import ProtoImport from src.proto_node import ProtoNode, ProtoNodeDiff from src.proto_option import ProtoOption @@ -27,6 +28,10 @@ def package(self) -> Optional[ProtoPackage]: def options(self) -> list[ProtoOption]: return [node for node in self.nodes if isinstance(node, ProtoOption)] + @property + def enums(self) -> list[ProtoEnum]: + return [node for node in self.nodes if isinstance(node, ProtoEnum)] + def serialize(self) -> str: serialized_parts = [self.syntax.serialize()] previous_type = self.syntax.__class__ @@ -42,6 +47,8 @@ def serialize(self) -> str: def diff(self, other: "ProtoFile") -> list[ProtoNodeDiff]: diffs = [] diffs.extend(ProtoSyntax.diff(self.syntax, other.syntax)) - diffs.extend(ProtoImport.diff(self.imports, other.imports)) + diffs.extend(ProtoImport.diff_sets(self.imports, other.imports)) diffs.extend(ProtoPackage.diff(self.package, other.package)) + diffs.extend(ProtoEnum.diff_sets(self.enums, other.enums)) + return [d for d in diffs if d is not None] diff --git a/src/proto_import.py b/src/proto_import.py index dc00a32..f3a5682 100644 --- a/src/proto_import.py +++ b/src/proto_import.py @@ -77,7 +77,7 @@ def serialize(self) -> str: return " ".join(parts) @staticmethod - def diff( + def diff_sets( left: list["ProtoImport"], right: list["ProtoImport"] ) -> list["ProtoNodeDiff"]: diffs = [] diff --git a/test/proto_enum_test.py b/test/proto_enum_test.py index 8bffd79..76fb369 100644 --- a/test/proto_enum_test.py +++ b/test/proto_enum_test.py @@ -4,7 +4,17 @@ from src.proto_bool import ProtoBool from src.proto_comment import ProtoMultiLineComment, ProtoSingleLineComment from src.proto_constant import ProtoConstant -from src.proto_enum import ProtoEnum, ProtoEnumValue, ProtoEnumValueOption +from src.proto_enum import ( + ProtoEnum, + ProtoEnumAdded, + ProtoEnumRemoved, + ProtoEnumValue, + ProtoEnumValueAdded, + ProtoEnumValueNameChanged, + ProtoEnumValueOption, + ProtoEnumValueRemoved, + ProtoEnumValueValueChanged, +) from src.proto_identifier import ProtoIdentifier from src.proto_int import ProtoInt, ProtoIntSign from src.proto_option import ProtoOption @@ -295,6 +305,623 @@ def test_enum_normalize_away_comments(self): ], ) + def test_diff_same_enum_returns_empty(self): + pe1 = ProtoEnum( + ProtoIdentifier("MyEnum"), + [], + ) + pe2 = ProtoEnum( + ProtoIdentifier("MyEnum"), + [], + ) + self.assertEqual(ProtoEnum.diff(pe1, pe2), []) + + def test_diff_different_enum_name_returns_empty(self): + pe1 = ProtoEnum( + ProtoIdentifier("MyEnum"), + [], + ) + pe2 = ProtoEnum( + ProtoIdentifier("OtherEnum"), + [], + ) + self.assertEqual(ProtoEnum.diff(pe1, pe2), []) + + # TODO: handle enum value diffs + # def test_diff_different_enum_value_name_returns_enum_diff(self): + # pe1 = ProtoEnum( + # ProtoIdentifier("MyEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + # ) + # ], + # ) + # pe2 = ProtoEnum( + # ProtoIdentifier("MyEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("ME_KNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + # ) + # ], + # ) + # self.assertEqual( + # ProtoEnum.diff(pe1, pe2), + # [ + # ProtoEnumValueNameChanged( + # pe1, + # pe1.nodes[0], + # ProtoIdentifier("ME_KNOWN"), + # ) + # ], + # ) + + # def test_diff_different_enum_value_value_returns_enum_diff(self): + # pe1 = ProtoEnum( + # ProtoIdentifier("MyEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + # ) + # ], + # ) + # pe2 = ProtoEnum( + # ProtoIdentifier("MyEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("ME_UNKNOWN"), ProtoInt(1, ProtoIntSign.POSITIVE) + # ) + # ], + # ) + # self.assertEqual( + # ProtoEnum.diff(pe1, pe2), + # [ + # ProtoEnumValueValueChanged( + # pe1, + # pe1.nodes[0], + # ProtoInt(1, ProtoIntSign.POSITIVE), + # ) + # ], + # ) + + def test_diff_enum_added(self): + pe1 = None + pe2 = ProtoEnum( + ProtoIdentifier("MyEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + ) + ], + ) + self.assertEqual( + ProtoEnum.diff(pe1, pe2), + [ + ProtoEnumAdded( + ProtoEnum( + ProtoIdentifier("MyEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("ME_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ) + ), + ], + ) + + def test_diff_option_removed(self): + pe1 = ProtoEnum( + ProtoIdentifier("MyEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + ) + ], + ) + pe2 = None + self.assertEqual( + ProtoEnum.diff(pe1, pe2), + [ + ProtoEnumRemoved( + ProtoEnum( + ProtoIdentifier("MyEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("ME_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ) + ), + ], + ) + + def test_diff_sets_empty_returns_empty(self): + set1 = [] + set2 = [] + self.assertEqual(ProtoEnum.diff_sets(set1, set2), []) + + def test_diff_sets_no_change(self): + set1 = [ + ProtoEnum( + ProtoIdentifier("FooEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("TagEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ] + self.assertEqual(ProtoEnum.diff_sets(set1, set1), []) + + def test_diff_sets_all_removed(self): + set1 = [] + set2 = [ + ProtoEnum( + ProtoIdentifier("FooEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("TagEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ] + diff = ProtoEnum.diff_sets(set1, set2) + + self.assertIn( + ProtoEnumRemoved( + ProtoEnum( + ProtoIdentifier("FooEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertIn( + ProtoEnumRemoved( + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertIn( + ProtoEnumRemoved( + ProtoEnum( + ProtoIdentifier("TagEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertEqual(3, len(diff)) + + def test_diff_sets_all_added(self): + set1 = [ + ProtoEnum( + ProtoIdentifier("FooEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("TagEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ] + set2 = [] + diff = ProtoEnum.diff_sets(set1, set2) + + self.assertIn( + ProtoEnumAdded( + ProtoEnum( + ProtoIdentifier("FooEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertIn( + ProtoEnumAdded( + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertIn( + ProtoEnumAdded( + ProtoEnum( + ProtoIdentifier("TagEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertEqual(3, len(diff)) + + def test_diff_sets_mutually_exclusive(self): + set1 = [ + ProtoEnum( + ProtoIdentifier("FooEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("TagEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ] + set2 = [ + ProtoEnum( + ProtoIdentifier("FooEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("BarEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("TagEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ] + + diff = ProtoEnum.diff_sets(set1, set2) + + self.assertIn( + ProtoEnumAdded( + ProtoEnum( + ProtoIdentifier("FooEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertIn( + ProtoEnumAdded( + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + + self.assertIn( + ProtoEnumAdded( + ProtoEnum( + ProtoIdentifier("TagEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + + self.assertIn( + ProtoEnumRemoved( + ProtoEnum( + ProtoIdentifier("FooEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + + self.assertIn( + ProtoEnumRemoved( + ProtoEnum( + ProtoIdentifier("BarEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + + self.assertIn( + ProtoEnumRemoved( + ProtoEnum( + ProtoIdentifier("TagEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + + self.assertEqual(6, len(diff)) + + # TODO: handle enum value diffs + # def test_diff_sets_overlap(self): + # set1 = [ + # ProtoEnum( + # ProtoIdentifier("FooEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("FE_UNKNOWN"), + # ProtoInt(0, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ProtoEnum( + # ProtoIdentifier("BarEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("BE_UNKNOWN"), + # ProtoInt(0, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ProtoEnum( + # ProtoIdentifier("TagEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("TE_UNKNOWN"), + # ProtoInt(0, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ] + # set2 = [ + # ProtoEnum( + # ProtoIdentifier("FooEnum2"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("FE_UNKNOWN2"), + # ProtoInt(0, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ProtoEnum( + # ProtoIdentifier("BarEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("BE_UNKNOWN2"), + # ProtoInt(1, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ProtoEnum( + # ProtoIdentifier("TagEnum2"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("TE_UNKNOWN2"), + # ProtoInt(0, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ] + + # diff = ProtoEnum.diff_sets(set1, set2) + + # self.assertIn( + # ProtoEnumRemoved( + # ProtoEnum( + # ProtoIdentifier("FooEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("FE_UNKNOWN"), + # ProtoInt(0, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ), + # diff, + # ) + + # self.assertIn( + # ProtoEnumRemoved( + # ProtoEnum( + # ProtoIdentifier("TagEnum"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("TE_UNKNOWN"), + # ProtoInt(0, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ), + # diff, + # ) + # self.assertIn( + # ProtoEnumAdded( + # ProtoEnum( + # ProtoIdentifier("FooEnum2"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("FE_UNKNOWN2"), + # ProtoInt(0, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ), + # diff, + # ) + # self.assertIn( + # ProtoEnumAdded( + # ProtoEnum( + # ProtoIdentifier("TagEnum2"), + # [ + # ProtoEnumValue( + # ProtoIdentifier("TE_UNKNOWN2"), + # ProtoInt(0, ProtoIntSign.POSITIVE), + # ) + # ], + # ), + # ), + # diff, + # ) + # self.assertIn( + # ProtoEnumValueRemoved( + # ProtoIdentifier("BarEnum"), + # ProtoEnumValue( + # ProtoIdentifier("BE_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + # ), + # ), + # diff, + # ) + # self.assertIn( + # ProtoEnumValueAdded( + # ProtoIdentifier("BarEnum"), + # ProtoEnumValue( + # ProtoIdentifier("BE_UNKNOWN2"), ProtoInt(1, ProtoIntSign.POSITIVE) + # ), + # ), + # diff, + # ) + # self.assertEqual(6, len(diff)) + if __name__ == "__main__": unittest.main() diff --git a/test/proto_import_test.py b/test/proto_import_test.py index bf43205..0ea8ffb 100644 --- a/test/proto_import_test.py +++ b/test/proto_import_test.py @@ -135,28 +135,28 @@ def test_public_mixed_imports(self): third_parsed_import.node.serialize(), 'import public "bat.proto";' ) - def test_diff_same_path_simple(self): + def test_diff_sets_same_path_simple(self): pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) pf2 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) - self.assertEqual(ProtoImport.diff([pf1], [pf2]), []) + self.assertEqual(ProtoImport.diff_sets([pf1], [pf2]), []) - def test_diff_added_path_simple(self): + def test_diff_sets_added_path_simple(self): pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) - self.assertEqual(ProtoImport.diff([pf1], []), [ProtoImportAdded(pf1)]) + self.assertEqual(ProtoImport.diff_sets([pf1], []), [ProtoImportAdded(pf1)]) - def test_diff_removed_path_simple(self): + def test_diff_sets_removed_path_simple(self): pf2 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) - self.assertEqual(ProtoImport.diff([], [pf2]), [ProtoImportRemoved(pf2)]) + self.assertEqual(ProtoImport.diff_sets([], [pf2]), [ProtoImportRemoved(pf2)]) - def test_diff_different_path_simple(self): + def test_diff_sets_different_path_simple(self): pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) pf2 = ProtoImport(ProtoStringLiteral("path/to/some/other.proto")) self.assertEqual( - ProtoImport.diff([pf1], [pf2]), + ProtoImport.diff_sets([pf1], [pf2]), [ProtoImportAdded(pf1), ProtoImportRemoved(pf2)], ) - def test_diff_changed_optional_attributes(self): + def test_diff_sets_changed_optional_attributes(self): pf1 = ProtoImport( ProtoStringLiteral("path/to/some.proto"), weak=False, public=True ) @@ -164,7 +164,7 @@ def test_diff_changed_optional_attributes(self): ProtoStringLiteral("path/to/some.proto"), weak=True, public=False ) self.assertEqual( - ProtoImport.diff([pf1], [pf2]), + ProtoImport.diff_sets([pf1], [pf2]), [ ProtoImportMadeNonWeak(pf2), ProtoImportMadePublic(pf2), From 14765b539ca41d15952c7b4f523eacf282c2dd74 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Mon, 13 Feb 2023 22:42:32 -0500 Subject: [PATCH 06/35] Support enum option, value, & value option diffs (#63) --- TODO.md | 8 +- src/proto_enum.py | 104 ++++++++--- src/proto_node.py | 6 +- src/proto_option.py | 9 - test/proto_enum_test.py | 390 ++++++++++++++++++++-------------------- 5 files changed, 281 insertions(+), 236 deletions(-) diff --git a/TODO.md b/TODO.md index f149c01..25185e5 100644 --- a/TODO.md +++ b/TODO.md @@ -66,10 +66,10 @@ - [x] Option changes - [ ] Enum-level diffs - [x] Additions/removals - - [ ] Option changes - - [ ] Field changes - - [ ] Value changes - - [ ] Option changes + - [x] Option changes + - [x] Field changes + - [x] Value changes + - [x] Option changes - [ ] Reserveds changes - [ ] Message-level diffs - [ ] Additions/removals diff --git a/src/proto_enum.py b/src/proto_enum.py index 8643371..2c65c77 100644 --- a/src/proto_enum.py +++ b/src/proto_enum.py @@ -62,6 +62,9 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) + def __hash__(self) -> str: + return hash(str(self)) + def normalize(self) -> "ProtoEnumValue": return ProtoEnumValue( self.identifier, @@ -131,13 +134,72 @@ def serialize(self) -> str: serialized_parts.append("]") return " ".join(serialized_parts) + ";" + @staticmethod + def diff( + enum: "ProtoEnum", left: "ProtoEnumValue", right: "ProtoEnumValue" + ) -> list["ProtoNodeDiff"]: + if left is None and right is not None: + return [ProtoEnumValueAdded(right)] + elif left is not None and right is None: + return [ProtoEnumValueRemoved(left)] + elif left is None and right is None: + return [] + elif left.identifier != right.identifier: + return [] + elif left == right: + return [] + diffs = [] + diffs.extend(ProtoOption.diff_sets(left.options, right.options)) + diffs.append(ProtoEnumValueValueChanged(enum, right, left.value)) + + return diffs + + @staticmethod + def diff_sets( + enum: "ProtoEnum", left: list["ProtoEnumValue"], right: list["ProtoEnumValue"] + ) -> list["ProtoNodeDiff"]: + diffs = [] + left_names = set(o.identifier.identifier for o in left) + left_values = set(int(o.value) for o in left) + right_names = set(o.identifier.identifier for o in right) + right_values = set(int(o.value) for o in right) + + for name in left_names - right_names: + # Check to see if this is a renamed field number. + left_value = next(i for i in left if i.identifier.identifier == name) + if int(left_value.value) in right_values: + # This is a renamed field number. + right_value = next( + i for i in right if int(i.value) == int(left_value.value) + ) + diffs.append( + ProtoEnumValueNameChanged(enum, right_value, left_value.identifier) + ) + else: + diffs.append(ProtoEnumValueAdded(enum, left_value)) + for name in right_names - left_names: + # Check to see if this is a renamed field number. + right_value = next(i for i in right if i.identifier.identifier == name) + if int(right_value.value) not in left_values: + diffs.append( + ProtoEnumValueRemoved( + enum, next(i for i in right if i.identifier.identifier == name) + ) + ) + for name in left_names & right_names: + left_enum_value = next(i for i in left if i.identifier.identifier == name) + right_enum_value = next(i for i in right if i.identifier.identifier == name) + diffs.extend(ProtoEnumValue.diff(enum, left_enum_value, right_enum_value)) + + return diffs + class ProtoEnum(ProtoNode): def __init__(self, name: ProtoIdentifier, nodes: list[ProtoNode]): self.name = name self.nodes = nodes - def __eq__(self, other) -> bool: + def __eq__(self, other: "ProtoEnum") -> bool: return self.name == other.name and self.nodes == other.nodes def __str__(self) -> str: @@ -216,6 +278,10 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: def options(self) -> list[ProtoOption]: return [node for node in self.nodes if isinstance(node, ProtoOption)] + @property + def values(self) -> list[ProtoEnumValue]: + return [node for node in self.nodes if isinstance(node, ProtoEnumValue)] + def serialize(self) -> str: serialize_parts = ( [f"enum {self.name.serialize()} {{"] @@ -236,8 +302,10 @@ def diff(left: "ProtoEnum", right: "ProtoEnum") -> list["ProtoNodeDiff"]: return [] elif left == right: return [] - # TODO: process the enum options and values. - return [] + diffs = [] + diffs.extend(ProtoOption.diff_sets(left.options, right.options)) + diffs.extend(ProtoEnumValue.diff_sets(left, left.values, right.values)) + return diffs @staticmethod def diff_sets( @@ -255,9 +323,9 @@ def diff_sets( ProtoEnumRemoved(next(i for i in right if i.name.identifier == name)) ) for name in left_names & right_names: - left_option = next(i for i in left if i.name.identifier == name) - right_option = next(i for i in right if i.name.identifier == name) - diffs.extend(ProtoEnum.diff(left_option, right_option)) + left_enum = next(i for i in left if i.name.identifier == name) + right_enum = next(i for i in right if i.name.identifier == name) + diffs.extend(ProtoEnum.diff(left_enum, right_enum)) return diffs @@ -272,9 +340,6 @@ def __eq__(self, other: "ProtoEnumAdded") -> bool: def __str__(self) -> str: return f"" - def __repr__(self) -> str: - return str(self) - class ProtoEnumRemoved(ProtoNodeDiff): def __init__(self, enum: ProtoEnum): @@ -286,9 +351,6 @@ def __eq__(self, other: "ProtoEnumRemoved") -> bool: def __str__(self) -> str: return f"" - def __repr__(self) -> str: - return str(self) - class ProtoEnumValueAdded(ProtoNodeDiff): def __init__(self, enum: "ProtoEnum", enum_value: "ProtoEnumValue"): @@ -305,9 +367,6 @@ def __eq__(self, other: "ProtoEnumValueAdded") -> bool: def __str__(self) -> str: return f"" - def __repr__(self) -> str: - return str(self) - class ProtoEnumValueRemoved(ProtoNodeDiff): def __init__(self, enum: "ProtoEnum", enum_value: "ProtoEnumValue"): @@ -324,9 +383,6 @@ def __eq__(self, other: "ProtoEnumValueRemoved") -> bool: def __str__(self) -> str: return f"" - def __repr__(self) -> str: - return str(self) - class ProtoEnumValueNameChanged(ProtoNodeDiff): def __init__( @@ -347,9 +403,6 @@ def __eq__(self, other: "ProtoEnumValueNameChanged") -> bool: def __str__(self) -> str: return f"" - def __repr__(self) -> str: - return str(self) - class ProtoEnumValueValueChanged(ProtoNodeDiff): def __init__( @@ -359,16 +412,13 @@ def __init__( self.enum_value = enum_value self.new_value = new_value - def __eq__(self, other: "ProtoEnumValueNameChanged") -> bool: + def __eq__(self, other: "ProtoEnumValueValueChanged") -> bool: return ( - isinstance(other, ProtoEnumValueNameChanged) + isinstance(other, ProtoEnumValueValueChanged) and self.enum == other.enum and self.enum_value == other.enum_value and self.new_value == other.new_value ) def __str__(self) -> str: - return f"" - - def __repr__(self) -> str: - return str(self) + return f"" diff --git a/src/proto_node.py b/src/proto_node.py index 05310eb..162fe74 100644 --- a/src/proto_node.py +++ b/src/proto_node.py @@ -29,4 +29,8 @@ def __repr__(self) -> str: class ProtoNodeDiff(abc.ABC): - pass + def __repr__(self) -> str: + return str(self) + + def __hash__(self) -> str: + return hash(str(self)) diff --git a/src/proto_option.py b/src/proto_option.py index e86e360..58c02cf 100644 --- a/src/proto_option.py +++ b/src/proto_option.py @@ -149,9 +149,6 @@ def __eq__(self, other: "ProtoOptionValueChanged") -> bool: def __str__(self) -> str: return f"" - def __repr__(self) -> str: - return str(self) - class ProtoOptionAdded(ProtoNodeDiff): def __init__(self, left: str): @@ -163,9 +160,6 @@ def __eq__(self, other: "ProtoOptionAdded") -> bool: def __str__(self) -> str: return f"" - def __repr__(self) -> str: - return str(self) - class ProtoOptionRemoved(ProtoNodeDiff): def __init__(self, right: str): @@ -176,6 +170,3 @@ def __eq__(self, other: "ProtoOptionRemoved") -> bool: def __str__(self) -> str: return f"" - - def __repr__(self) -> str: - return str(self) diff --git a/test/proto_enum_test.py b/test/proto_enum_test.py index 76fb369..3857d32 100644 --- a/test/proto_enum_test.py +++ b/test/proto_enum_test.py @@ -327,62 +327,63 @@ def test_diff_different_enum_name_returns_empty(self): ) self.assertEqual(ProtoEnum.diff(pe1, pe2), []) - # TODO: handle enum value diffs - # def test_diff_different_enum_value_name_returns_enum_diff(self): - # pe1 = ProtoEnum( - # ProtoIdentifier("MyEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) - # ) - # ], - # ) - # pe2 = ProtoEnum( - # ProtoIdentifier("MyEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("ME_KNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) - # ) - # ], - # ) - # self.assertEqual( - # ProtoEnum.diff(pe1, pe2), - # [ - # ProtoEnumValueNameChanged( - # pe1, - # pe1.nodes[0], - # ProtoIdentifier("ME_KNOWN"), - # ) - # ], - # ) - - # def test_diff_different_enum_value_value_returns_enum_diff(self): - # pe1 = ProtoEnum( - # ProtoIdentifier("MyEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) - # ) - # ], - # ) - # pe2 = ProtoEnum( - # ProtoIdentifier("MyEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("ME_UNKNOWN"), ProtoInt(1, ProtoIntSign.POSITIVE) - # ) - # ], - # ) - # self.assertEqual( - # ProtoEnum.diff(pe1, pe2), - # [ - # ProtoEnumValueValueChanged( - # pe1, - # pe1.nodes[0], - # ProtoInt(1, ProtoIntSign.POSITIVE), - # ) - # ], - # ) + def test_diff_different_enum_value_name_returns_enum_diff(self): + pe1 = ProtoEnum( + ProtoIdentifier("MyEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + ) + ], + ) + pe2 = ProtoEnum( + ProtoIdentifier("MyEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("ME_KNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + ) + ], + ) + self.assertEqual( + ProtoEnum.diff(pe1, pe2), + [ + ProtoEnumValueNameChanged( + pe1, + pe2.nodes[0], + ProtoIdentifier("ME_UNKNOWN"), + ) + ], + ) + + def test_diff_different_enum_value_value_returns_enum_diff(self): + pe1 = ProtoEnum( + ProtoIdentifier("MyEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + ) + ], + ) + pe2 = ProtoEnum( + ProtoIdentifier("MyEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("ME_UNKNOWN"), ProtoInt(1, ProtoIntSign.POSITIVE) + ) + ], + ) + + diff = ProtoEnum.diff(pe1, pe2) + + self.assertIn( + ProtoEnumValueValueChanged( + pe1, + pe2.values[0], + ProtoInt(0, ProtoIntSign.POSITIVE), + ), + diff, + ) + self.assertEqual(1, len(diff)) def test_diff_enum_added(self): pe1 = None @@ -782,145 +783,144 @@ def test_diff_sets_mutually_exclusive(self): self.assertEqual(6, len(diff)) - # TODO: handle enum value diffs - # def test_diff_sets_overlap(self): - # set1 = [ - # ProtoEnum( - # ProtoIdentifier("FooEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("FE_UNKNOWN"), - # ProtoInt(0, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ProtoEnum( - # ProtoIdentifier("BarEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("BE_UNKNOWN"), - # ProtoInt(0, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ProtoEnum( - # ProtoIdentifier("TagEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("TE_UNKNOWN"), - # ProtoInt(0, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ] - # set2 = [ - # ProtoEnum( - # ProtoIdentifier("FooEnum2"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("FE_UNKNOWN2"), - # ProtoInt(0, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ProtoEnum( - # ProtoIdentifier("BarEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("BE_UNKNOWN2"), - # ProtoInt(1, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ProtoEnum( - # ProtoIdentifier("TagEnum2"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("TE_UNKNOWN2"), - # ProtoInt(0, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ] - - # diff = ProtoEnum.diff_sets(set1, set2) - - # self.assertIn( - # ProtoEnumRemoved( - # ProtoEnum( - # ProtoIdentifier("FooEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("FE_UNKNOWN"), - # ProtoInt(0, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ), - # diff, - # ) - - # self.assertIn( - # ProtoEnumRemoved( - # ProtoEnum( - # ProtoIdentifier("TagEnum"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("TE_UNKNOWN"), - # ProtoInt(0, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ), - # diff, - # ) - # self.assertIn( - # ProtoEnumAdded( - # ProtoEnum( - # ProtoIdentifier("FooEnum2"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("FE_UNKNOWN2"), - # ProtoInt(0, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ), - # diff, - # ) - # self.assertIn( - # ProtoEnumAdded( - # ProtoEnum( - # ProtoIdentifier("TagEnum2"), - # [ - # ProtoEnumValue( - # ProtoIdentifier("TE_UNKNOWN2"), - # ProtoInt(0, ProtoIntSign.POSITIVE), - # ) - # ], - # ), - # ), - # diff, - # ) - # self.assertIn( - # ProtoEnumValueRemoved( - # ProtoIdentifier("BarEnum"), - # ProtoEnumValue( - # ProtoIdentifier("BE_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) - # ), - # ), - # diff, - # ) - # self.assertIn( - # ProtoEnumValueAdded( - # ProtoIdentifier("BarEnum"), - # ProtoEnumValue( - # ProtoIdentifier("BE_UNKNOWN2"), ProtoInt(1, ProtoIntSign.POSITIVE) - # ), - # ), - # diff, - # ) - # self.assertEqual(6, len(diff)) + def test_diff_sets_overlap(self): + set1 = [ + ProtoEnum( + ProtoIdentifier("FooEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("TagEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ] + set2 = [ + ProtoEnum( + ProtoIdentifier("FooEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnum( + ProtoIdentifier("TagEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ] + + diff = ProtoEnum.diff_sets(set1, set2) + + self.assertIn( + ProtoEnumRemoved( + ProtoEnum( + ProtoIdentifier("FooEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + + self.assertIn( + ProtoEnumRemoved( + ProtoEnum( + ProtoIdentifier("TagEnum2"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertIn( + ProtoEnumAdded( + ProtoEnum( + ProtoIdentifier("FooEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertIn( + ProtoEnumAdded( + ProtoEnum( + ProtoIdentifier("TagEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ), + diff, + ) + self.assertIn( + ProtoEnumValueNameChanged( + ProtoEnum( + ProtoIdentifier("BarEnum"), + [ + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), + ) + ], + ), + ProtoEnumValue( + ProtoIdentifier("BE_UNKNOWN2"), ProtoInt(0, ProtoIntSign.POSITIVE) + ), + ProtoIdentifier("BE_UNKNOWN"), + ), + diff, + ) + self.assertEqual(5, len(diff)) if __name__ == "__main__": From 5aa9cd790bda388d3838a14aca3247c57768556c Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Fri, 17 Feb 2023 19:22:26 -0500 Subject: [PATCH 07/35] Add support for emitting diffs for added & removed messages (#64) --- TODO.md | 14 +++- src/BUILD.bazel | 1 + src/proto_enum.py | 2 + src/proto_file.py | 6 ++ src/proto_message.py | 63 ++++++++++++++- test/proto_enum_test.py | 4 +- test/proto_message_test.py | 159 ++++++++++++++++++++++++++++++++++++- 7 files changed, 241 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index 25185e5..7922d51 100644 --- a/TODO.md +++ b/TODO.md @@ -72,8 +72,8 @@ - [x] Option changes - [ ] Reserveds changes - [ ] Message-level diffs - - [ ] Additions/removals - - [ ] Option changes + - [x] Additions/removals + - [x] Option changes - [ ] Field changes - [ ] Reserved changes - [ ] Nested enum changes @@ -85,3 +85,13 @@ - [ ] Additions/removals - [ ] Option changes - [ ] Backwards-compatibility check + - [ ] Scoping of diffs under containing objects + - [ ] Enum options under enums + - [ ] Enum value changes under enums + - [ ] Enum value option changes under enum values + - [ ] Enum reserved changes under enums + - [ ] Message option changes under messages + - [ ] Message field changes under messages + - [ ] Message reserved changes under messages + - [ ] Message nested enum changes under messages + - [ ] Message nested message changes under messages diff --git a/src/BUILD.bazel b/src/BUILD.bazel index 062c592..3774c4c 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -221,6 +221,7 @@ py_library( deps = [ ":proto_enum", ":proto_import", + ":proto_message", ":proto_node", ":proto_option", ":proto_package", diff --git a/src/proto_enum.py b/src/proto_enum.py index 2c65c77..47b658f 100644 --- a/src/proto_enum.py +++ b/src/proto_enum.py @@ -149,6 +149,7 @@ def diff( elif left == right: return [] diffs = [] + # TODO: scope these diffs under ProtoEnumValue diffs.extend(ProtoOption.diff_sets(left.options, right.options)) diffs.append(ProtoEnumValueValueChanged(enum, right, left.value)) @@ -303,6 +304,7 @@ def diff(left: "ProtoEnum", right: "ProtoEnum") -> list["ProtoNodeDiff"]: elif left == right: return [] diffs = [] + # TODO: scope these diffs under ProtoEnum diffs.extend(ProtoOption.diff_sets(left.options, right.options)) diffs.extend(ProtoEnumValue.diff_sets(left, left.values, right.values)) return diffs diff --git a/src/proto_file.py b/src/proto_file.py index 2d41cb3..4bfedb9 100644 --- a/src/proto_file.py +++ b/src/proto_file.py @@ -2,6 +2,7 @@ from src.proto_enum import ProtoEnum from src.proto_import import ProtoImport +from src.proto_message import ProtoMessage from src.proto_node import ProtoNode, ProtoNodeDiff from src.proto_option import ProtoOption from src.proto_package import ProtoPackage @@ -32,6 +33,10 @@ def options(self) -> list[ProtoOption]: def enums(self) -> list[ProtoEnum]: return [node for node in self.nodes if isinstance(node, ProtoEnum)] + @property + def messages(self) -> list[ProtoMessage]: + return [node for node in self.nodes if isinstance(node, ProtoMessage)] + def serialize(self) -> str: serialized_parts = [self.syntax.serialize()] previous_type = self.syntax.__class__ @@ -50,5 +55,6 @@ def diff(self, other: "ProtoFile") -> list[ProtoNodeDiff]: diffs.extend(ProtoImport.diff_sets(self.imports, other.imports)) diffs.extend(ProtoPackage.diff(self.package, other.package)) diffs.extend(ProtoEnum.diff_sets(self.enums, other.enums)) + diffs.extend(ProtoMessage.diff_sets(self.message, other.messages)) return [d for d in diffs if d is not None] diff --git a/src/proto_message.py b/src/proto_message.py index 3bb2b81..b2fb80c 100644 --- a/src/proto_message.py +++ b/src/proto_message.py @@ -20,7 +20,7 @@ ProtoMessageFieldOption, ProtoMessageFieldTypesEnum, ) -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff from src.proto_option import ProtoOption from src.proto_reserved import ProtoReserved @@ -461,3 +461,64 @@ def serialize(self) -> str: + ["}"] ) return "\n".join(serialize_parts) + + @staticmethod + def diff(left: "ProtoMessage", right: "ProtoMessage") -> list["ProtoNodeDiff"]: + if left is None and right is not None: + return [ProtoMessageAdded(right)] + elif left is not None and right is None: + return [ProtoMessageRemoved(left)] + elif left is None and right is None: + return [] + elif left.name != right.name: + return [] + elif left == right: + return [] + diffs = [] + diffs.extend(ProtoOption.diff_sets(left.options, right.options)) + # diffs.extend(ProtoMessageValue.diff_sets(left, left.values, right.values)) + return diffs + + @staticmethod + def diff_sets( + left: list["ProtoMessage"], right: list["ProtoMessage"] + ) -> list["ProtoNodeDiff"]: + diffs = [] + left_names = set(o.name.identifier for o in left) + right_names = set(o.name.identifier for o in right) + for name in left_names - right_names: + diffs.append( + ProtoMessageAdded(next(i for i in left if i.name.identifier == name)) + ) + for name in right_names - left_names: + diffs.append( + ProtoMessageRemoved(next(i for i in right if i.name.identifier == name)) + ) + for name in left_names & right_names: + left_enum = next(i for i in left if i.name.identifier == name) + right_enum = next(i for i in right if i.name.identifier == name) + diffs.extend(ProtoMessage.diff(left_enum, right_enum)) + + return diffs + + +class ProtoMessageAdded(ProtoNodeDiff): + def __init__(self, message: ProtoMessage): + self.message = message + + def __eq__(self, other: "ProtoMessageAdded") -> bool: + return isinstance(other, ProtoMessageAdded) and self.message == other.message + + def __str__(self) -> str: + return f"" + + +class ProtoMessageRemoved(ProtoNodeDiff): + def __init__(self, message: ProtoMessage): + self.message = message + + def __eq__(self, other: "ProtoMessageRemoved") -> bool: + return isinstance(other, ProtoMessageRemoved) and self.message == other.message + + def __str__(self) -> str: + return f"" diff --git a/test/proto_enum_test.py b/test/proto_enum_test.py index 3857d32..4687151 100644 --- a/test/proto_enum_test.py +++ b/test/proto_enum_test.py @@ -9,10 +9,8 @@ ProtoEnumAdded, ProtoEnumRemoved, ProtoEnumValue, - ProtoEnumValueAdded, ProtoEnumValueNameChanged, ProtoEnumValueOption, - ProtoEnumValueRemoved, ProtoEnumValueValueChanged, ) from src.proto_identifier import ProtoIdentifier @@ -412,7 +410,7 @@ def test_diff_enum_added(self): ], ) - def test_diff_option_removed(self): + def test_diff_enum_removed(self): pe1 = ProtoEnum( ProtoIdentifier("MyEnum"), [ diff --git a/test/proto_message_test.py b/test/proto_message_test.py index 2dc0878..19195a9 100644 --- a/test/proto_message_test.py +++ b/test/proto_message_test.py @@ -18,6 +18,8 @@ ProtoMapKeyTypesEnum, ProtoMapValueTypesEnum, ProtoMessage, + ProtoMessageAdded, + ProtoMessageRemoved, ProtoOneOf, ) from src.proto_message_field import ( @@ -70,7 +72,7 @@ def test_message_all_features(self): ProtoIdentifier("(foo.bar).baz"), ProtoConstant(ProtoStringLiteral("bat")), ), - ProtoEnum( + ProtoMessage( ProtoIdentifier("MyEnum"), [ ProtoEnumValue( @@ -293,7 +295,7 @@ def test_message_nested_enum(self): ProtoMessage( ProtoIdentifier("FooMessage"), [ - ProtoEnum( + ProtoMessage( ProtoIdentifier("MyEnum"), [ ProtoEnumValue( @@ -762,6 +764,159 @@ def test_message_normalizes_away_comments(self): ], ) + def test_diff_same_message_returns_empty(self): + pm1 = ProtoMessage( + ProtoIdentifier("MyMessage"), + [], + ) + pm2 = ProtoMessage( + ProtoIdentifier("MyMessage"), + [], + ) + self.assertEqual(ProtoMessage.diff(pm1, pm2), []) + + def test_diff_different_message_name_returns_empty(self): + pm1 = ProtoMessage( + ProtoIdentifier("MyMessage"), + [], + ) + pm2 = ProtoMessage( + ProtoIdentifier("OtherMessage"), + [], + ) + self.assertEqual(ProtoMessage.diff(pm1, pm2), []) + + def test_diff_enum_added(self): + pm1 = None + pm2 = ProtoMessage(ProtoIdentifier("MyMessage"), []) + self.assertEqual( + ProtoMessage.diff(pm1, pm2), + [ + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("MyMessage"), [])), + ], + ) + + def test_diff_message_removed(self): + pm1 = ProtoMessage(ProtoIdentifier("MyMessage"), []) + pm2 = None + self.assertEqual( + ProtoMessage.diff(pm1, pm2), + [ + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("MyMessage"), [])), + ], + ) + + def test_diff_sets_empty_returns_empty(self): + set1 = [] + set2 = [] + self.assertEqual(ProtoMessage.diff_sets(set1, set2), []) + + def test_diff_sets_no_change_returns_empty(self): + set1 = [ + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), + ] + self.assertEqual(ProtoMessage.diff_sets(set1, set1), []) + + def test_diff_sets_all_removed(self): + set1 = [] + set2 = [ + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), + ] + diff = ProtoMessage.diff_sets(set1, set2) + self.assertIn( + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff + ) + self.assertIn( + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BarMessage"), [])), diff + ) + self.assertIn( + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff + ) + self.assertEqual(3, len(diff)) + + def test_diff_sets_all_added(self): + set1 = [ + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), + ] + set2 = [] + + diff = ProtoMessage.diff_sets(set1, set2) + self.assertIn( + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff + ) + self.assertIn( + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BarMessage"), [])), diff + ) + self.assertIn( + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff + ) + self.assertEqual(3, len(diff)) + + def test_diff_sets_mutually_exclusive(self): + set1 = [ + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), + ] + set2 = [ + ProtoMessage(ProtoIdentifier("FooMessage2"), []), + ProtoMessage(ProtoIdentifier("BarMessage2"), []), + ProtoMessage(ProtoIdentifier("BazMessage2"), []), + ] + diff = ProtoMessage.diff_sets(set1, set2) + self.assertIn( + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff + ) + self.assertIn( + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BarMessage"), [])), diff + ) + self.assertIn( + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff + ) + self.assertIn( + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage2"), [])), diff + ) + self.assertIn( + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BarMessage2"), [])), diff + ) + self.assertIn( + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage2"), [])), diff + ) + self.assertEqual(6, len(diff)) + + def test_diff_sets_overlap(self): + + set1 = [ + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), + ] + set2 = [ + ProtoMessage(ProtoIdentifier("FooMessage2"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage2"), []), + ] + diff = ProtoMessage.diff_sets(set1, set2) + self.assertIn( + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff + ) + self.assertIn( + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff + ) + self.assertIn( + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage2"), [])), diff + ) + self.assertIn( + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage2"), [])), diff + ) + self.assertEqual(4, len(diff)) + if __name__ == "__main__": unittest.main() From 6f7e85eae660ce353b363b40caf6ab357e0c4557 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Fri, 17 Feb 2023 19:29:14 -0500 Subject: [PATCH 08/35] Add todo for perf & iterators (#65) --- TODO.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/TODO.md b/TODO.md index 7922d51..ca4a7e7 100644 --- a/TODO.md +++ b/TODO.md @@ -95,3 +95,7 @@ - [ ] Message reserved changes under messages - [ ] Message nested enum changes under messages - [ ] Message nested message changes under messages +- [ ] (Perf) use iterators + - [ ] In parsing + - [ ] In properties +- [ ] Remove Proto* and proto_ from everything From b2aa495dcd83a224248f1ee1597c240b61805ee3 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Fri, 17 Feb 2023 20:00:36 -0500 Subject: [PATCH 09/35] Add compatibility checker binary, and shell test (#67) --- src/BUILD.bazel | 19 +++++++++++ src/compatibility_checker.py | 40 +++++++++++++++++++++++ src/proto_file.py | 7 ++-- test/BUILD.bazel | 9 +++++ test/compatibility_checker_binary_test.sh | 4 +++ test/resources/single_message.proto | 3 ++ 6 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 src/compatibility_checker.py create mode 100755 test/compatibility_checker_binary_test.sh create mode 100644 test/resources/single_message.proto diff --git a/src/BUILD.bazel b/src/BUILD.bazel index 3774c4c..892c9a3 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -254,3 +254,22 @@ py_binary( visibility = ["//visibility:public"], deps = [":parser"], ) + +py_library( + name = "compatibility_checker", + srcs = ["compatibility_checker.py"], + visibility = ["//visibility:public"], + deps = [ + ":parser", + ":proto_file", + ":proto_node", + ], +) + +py_binary( + name = "compatibility_checker_binary", + srcs = ["compatibility_checker.py"], + main = "compatibility_checker.py", + visibility = ["//visibility:public"], + deps = [":compatibility_checker"], +) diff --git a/src/compatibility_checker.py b/src/compatibility_checker.py new file mode 100644 index 0000000..8971f72 --- /dev/null +++ b/src/compatibility_checker.py @@ -0,0 +1,40 @@ +import sys +from dataclasses import dataclass +from typing import Type + +from src.parser import Parser +from src.proto_file import ProtoFile +from src.proto_message import ProtoMessageAdded +from src.proto_node import ProtoNodeDiff + + +@dataclass +class CompatibilityChecker: + allowed_diff_types: list[Type[ProtoNodeDiff]] + + def check_compatibility(self, left: ProtoFile, right: ProtoFile): + for diff in left.diff(right): + if diff.__class__ in self.allowed_diff_types: + continue + yield diff + + +def main() -> int: + with open(sys.argv[1], "r") as proto_file: + left = Parser.loads(proto_file.read()) + + with open(sys.argv[2], "r") as proto_file: + right = Parser.loads(proto_file.read()) + + violations = list( + CompatibilityChecker([ProtoMessageAdded]).check_compatibility(left, right) + ) + if violations: + print(f"Violations: {violations}") + return 1 + + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/proto_file.py b/src/proto_file.py index 4bfedb9..f70a210 100644 --- a/src/proto_file.py +++ b/src/proto_file.py @@ -23,7 +23,10 @@ def imports(self) -> list[ProtoImport]: @property def package(self) -> Optional[ProtoPackage]: - return next(node for node in self.nodes if isinstance(node, ProtoPackage)) + try: + return next(node for node in self.nodes if isinstance(node, ProtoPackage)) + except StopIteration: + return None @property def options(self) -> list[ProtoOption]: @@ -55,6 +58,6 @@ def diff(self, other: "ProtoFile") -> list[ProtoNodeDiff]: diffs.extend(ProtoImport.diff_sets(self.imports, other.imports)) diffs.extend(ProtoPackage.diff(self.package, other.package)) diffs.extend(ProtoEnum.diff_sets(self.enums, other.enums)) - diffs.extend(ProtoMessage.diff_sets(self.message, other.messages)) + diffs.extend(ProtoMessage.diff_sets(self.messages, other.messages)) return [d for d in diffs if d is not None] diff --git a/test/BUILD.bazel b/test/BUILD.bazel index b538aae..a2954d7 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -231,3 +231,12 @@ sh_test( "@com_google_protobuf//:all_proto", ], ) + +sh_test( + name = "compatibility_checker_binary_test", + srcs = ["compatibility_checker_binary_test.sh"], + data = [ + "//src:compatibility_checker_binary", + "//test/resources:all_protos", + ], +) diff --git a/test/compatibility_checker_binary_test.sh b/test/compatibility_checker_binary_test.sh new file mode 100755 index 0000000..0f01063 --- /dev/null +++ b/test/compatibility_checker_binary_test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euxo pipefail + +./src/compatibility_checker_binary ./test/resources/single_message.proto ./test/resources/empty.proto diff --git a/test/resources/single_message.proto b/test/resources/single_message.proto new file mode 100644 index 0000000..4b3d2f1 --- /dev/null +++ b/test/resources/single_message.proto @@ -0,0 +1,3 @@ +syntax = "proto3"; + +message MyMessage {} From cea35c7bcf11987bd9a2e45ceff2e5cfefaf2057 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sat, 18 Feb 2023 03:14:06 -0500 Subject: [PATCH 10/35] Fix all the mypy typing errors, and turn on mypy precommit (#68) --- .pre-commit-config.yaml | 8 +- src/parser.py | 28 ++++--- src/proto_bool.py | 11 ++- src/proto_comment.py | 26 +++++-- src/proto_constant.py | 61 ++++++++------- src/proto_enum.py | 149 ++++++++++++++++++------------------ src/proto_extend.py | 7 +- src/proto_extensions.py | 3 +- src/proto_file.py | 8 +- src/proto_float.py | 13 +++- src/proto_identifier.py | 46 +++++++---- src/proto_import.py | 15 ++-- src/proto_int.py | 13 +++- src/proto_message.py | 115 +++++++++++++++++----------- src/proto_message_field.py | 64 ++++++++++------ src/proto_node.py | 2 +- src/proto_option.py | 83 ++++++++++++-------- src/proto_package.py | 28 ++++--- src/proto_range.py | 11 ++- src/proto_reserved.py | 20 +++-- src/proto_service.py | 8 +- src/proto_string_literal.py | 9 ++- src/proto_syntax.py | 21 +++-- test/proto_message_test.py | 4 +- 24 files changed, 455 insertions(+), 298 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ab36cc1..d256485 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -23,7 +23,7 @@ repos: rev: "12f5442f51377b10b26651ad745206bbe1500ad6" hooks: - id: bazel-buildifier - # - repo: https://github.com/pre-commit/mirrors-mypy - # rev: v0.991 - # hooks: - # - id: mypy + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.991 + hooks: + - id: mypy diff --git a/src/parser.py b/src/parser.py index 043097a..75b9de9 100644 --- a/src/parser.py +++ b/src/parser.py @@ -1,12 +1,17 @@ import sys +from typing import Sequence -from src.proto_comment import ProtoMultiLineComment, ProtoSingleLineComment +from src.proto_comment import ( + ProtoComment, + ProtoMultiLineComment, + ProtoSingleLineComment, +) from src.proto_enum import ProtoEnum from src.proto_extend import ProtoExtend from src.proto_file import ProtoFile from src.proto_import import ProtoImport from src.proto_message import ProtoMessage -from src.proto_node import ParsedProtoNode +from src.proto_node import ParsedProtoNode, ProtoNode from src.proto_option import ProtoOption from src.proto_package import ProtoPackage from src.proto_service import ProtoService @@ -20,7 +25,7 @@ class ParseError(ValueError): class Parser: @staticmethod def parse_partial_content(partial_proto_content: str) -> ParsedProtoNode: - node_types = [ + node_types: list[type[ProtoNode]] = [ ProtoImport, ProtoMessage, ProtoPackage, @@ -30,7 +35,7 @@ def parse_partial_content(partial_proto_content: str) -> ParsedProtoNode: ProtoService, ProtoSingleLineComment, ProtoMultiLineComment, - ] # type: list[type[ProtoImport] | type[ProtoMessage] | type[ProtoPackage] | type[ProtoOption] | type[ProtoEnum] | type[ProtoExtend]] + ] for node_type in node_types: try: match_result = node_type.match(partial_proto_content) @@ -45,7 +50,7 @@ def parse_partial_content(partial_proto_content: str) -> ParsedProtoNode: @staticmethod def parse_syntax_and_preceding_comments( proto_content: str, - ) -> tuple[ProtoSyntax, list[ProtoSingleLineComment | ProtoMultiLineComment], str]: + ) -> tuple[ProtoSyntax, Sequence[ProtoComment], str]: # First, parse any preceding comments. parsed_tree = [] while True: @@ -63,13 +68,13 @@ def parse_syntax_and_preceding_comments( # Next, parse syntax. try: - match_result = ProtoSyntax.match(proto_content.strip()) + syntax_match = ProtoSyntax.match(proto_content.strip()) except (ValueError, IndexError, TypeError): raise ParseError(f"Proto doesn't have parseable syntax:\n{proto_content}") - if match_result is None: + if syntax_match is None: raise ParseError(f"Proto doesn't have parseable syntax:\n{proto_content}") - syntax = match_result.node - proto_content = match_result.remaining_source.strip() + syntax = syntax_match.node + proto_content = syntax_match.remaining_source.strip() return syntax, parsed_tree, proto_content @@ -78,16 +83,17 @@ def loads(proto_content: str) -> ProtoFile: syntax, parsed_tree, proto_content = Parser.parse_syntax_and_preceding_comments( proto_content ) + new_tree: list[ProtoNode] = list(parsed_tree) while proto_content: # Remove empty statements. if proto_content.startswith(";"): proto_content = proto_content[1:].strip() continue match_result = Parser.parse_partial_content(proto_content) - parsed_tree.append(match_result.node) + new_tree.append(match_result.node) proto_content = match_result.remaining_source.strip() - return ProtoFile(syntax, parsed_tree) + return ProtoFile(syntax, new_tree) if __name__ == "__main__": diff --git a/src/proto_bool.py b/src/proto_bool.py index ef8867a..4704aa1 100644 --- a/src/proto_bool.py +++ b/src/proto_bool.py @@ -4,6 +4,11 @@ from src.proto_node import ParsedProtoNode, ProtoNode +class ParsedProtoBoolNode(ParsedProtoNode): + node: "ProtoBool" + remaining_source: str + + class ProtoBool(ProtoNode): def __init__(self, value: bool): self.value = value @@ -24,15 +29,15 @@ def normalize(self) -> "ProtoBool": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoBoolNode"]: if proto_source.startswith("true") and ( len(proto_source) == 4 or proto_source[4] not in ProtoFullIdentifier.ALL ): - return ParsedProtoNode(ProtoBool(True), proto_source[4:].strip()) + return ParsedProtoBoolNode(ProtoBool(True), proto_source[4:].strip()) elif proto_source.startswith("false") and ( len(proto_source) == 5 or proto_source[5] not in ProtoFullIdentifier.ALL ): - return ParsedProtoNode(ProtoBool(False), proto_source[5:].strip()) + return ParsedProtoBoolNode(ProtoBool(False), proto_source[5:].strip()) return None def serialize(self) -> str: diff --git a/src/proto_comment.py b/src/proto_comment.py index 989803c..8d726ed 100644 --- a/src/proto_comment.py +++ b/src/proto_comment.py @@ -1,10 +1,14 @@ import abc from typing import Optional -from src.proto_identifier import ProtoFullIdentifier from src.proto_node import ParsedProtoNode, ProtoNode +class ParsedProtoCommentNode(ParsedProtoNode): + node: "ProtoComment" + remaining_source: str + + class ProtoComment(ProtoNode): def __init__(self, value: str): self.value = value @@ -22,19 +26,24 @@ def normalize(self) -> Optional["ProtoComment"]: return None @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoCommentNode"]: return None def serialize(self) -> str: return "" +class ParsedProtoSingleLineCommentNode(ParsedProtoCommentNode): + node: "ProtoSingleLineComment" + remaining_source: str + + class ProtoSingleLineComment(ProtoComment): def __str__(self) -> str: return f"" @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoSingleLineCommentNode"]: if not proto_source.startswith("//"): return None @@ -42,7 +51,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: newline_pos = proto_source.find("\n") if newline_pos == -1: newline_pos = len(proto_source) - return ParsedProtoNode( + return ParsedProtoSingleLineCommentNode( ProtoSingleLineComment(proto_source[:newline_pos]), proto_source[newline_pos + 1 :], ) @@ -51,12 +60,17 @@ def serialize(self) -> str: return f"//{self.value}" +class ParsedProtoMultiLineCommentNode(ParsedProtoCommentNode): + node: "ProtoMultiLineComment" + remaining_source: str + + class ProtoMultiLineComment(ProtoComment): def __str__(self) -> str: return f"" @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoMultiLineCommentNode"]: if not proto_source.startswith("/*"): return None @@ -64,7 +78,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: close_comment_pos = proto_source.find("*/") if close_comment_pos == -1: return None - return ParsedProtoNode( + return ParsedProtoMultiLineCommentNode( ProtoMultiLineComment(proto_source[:close_comment_pos]), proto_source[close_comment_pos + 2 :], ) diff --git a/src/proto_constant.py b/src/proto_constant.py index 03ed8e9..e95fda6 100644 --- a/src/proto_constant.py +++ b/src/proto_constant.py @@ -12,6 +12,11 @@ ) +class ParsedProtoConstantNode(ParsedProtoNode): + node: "ProtoConstant" + remaining_source: str + + class ProtoConstant(ProtoNode): def __init__( self, @@ -32,10 +37,10 @@ def normalize(self) -> "ProtoConstant": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoConstantNode"]: match = ProtoBool.match(proto_source) if match is not None: - return ParsedProtoNode( + return ParsedProtoConstantNode( ProtoConstant(match.node), match.remaining_source.strip(), ) @@ -43,41 +48,41 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: sign = ProtoIntSign.POSITIVE if proto_source.startswith("+") or proto_source.startswith("-"): sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - match = ProtoInt.match(proto_source[1:]) + proto_int_match = ProtoInt.match(proto_source[1:]) else: - match = ProtoInt.match(proto_source) - if match is not None: - match.node.sign = sign - return ParsedProtoNode( - ProtoConstant(match.node), - match.remaining_source.strip(), + proto_int_match = ProtoInt.match(proto_source) + if proto_int_match is not None: + proto_int_match.node.sign = sign + return ParsedProtoConstantNode( + ProtoConstant(proto_int_match.node), + proto_int_match.remaining_source.strip(), ) - sign = ProtoFloatSign.POSITIVE + float_sign = ProtoFloatSign.POSITIVE if proto_source.startswith("+") or proto_source.startswith("-"): - sign = next(x for x in ProtoFloatSign if x.value == proto_source[0]) - match = ProtoFloat.match(proto_source[1:]) + float_sign = next(x for x in ProtoFloatSign if x.value == proto_source[0]) + float_match = ProtoFloat.match(proto_source[1:]) else: - match = ProtoFloat.match(proto_source) - if match is not None: - match.node.sign = sign - return ParsedProtoNode( - ProtoConstant(match.node), - match.remaining_source.strip(), + float_match = ProtoFloat.match(proto_source) + if float_match is not None: + float_match.node.sign = float_sign + return ParsedProtoConstantNode( + ProtoConstant(float_match.node), + float_match.remaining_source.strip(), ) - match = ProtoFullIdentifier.match(proto_source) - if match is not None: - return ParsedProtoNode( - ProtoConstant(match.node), - match.remaining_source.strip(), + identifier_match = ProtoFullIdentifier.match(proto_source) + if identifier_match is not None: + return ParsedProtoConstantNode( + ProtoConstant(identifier_match.node), + identifier_match.remaining_source.strip(), ) - match = ProtoStringLiteral.match(proto_source) - if match is not None: - return ParsedProtoNode( - ProtoConstant(match.node), - match.remaining_source.strip(), + string_literal_match = ProtoStringLiteral.match(proto_source) + if string_literal_match is not None: + return ParsedProtoConstantNode( + ProtoConstant(string_literal_match.node), + string_literal_match.remaining_source.strip(), ) return None diff --git a/src/proto_enum.py b/src/proto_enum.py index 47b658f..e461efb 100644 --- a/src/proto_enum.py +++ b/src/proto_enum.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Sequence from src.proto_comment import ( ProtoComment, @@ -8,24 +8,26 @@ from src.proto_identifier import ProtoIdentifier from src.proto_int import ProtoInt, ProtoIntSign from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff -from src.proto_option import ProtoOption +from src.proto_option import ParsedProtoOptionNode, ProtoOption, ProtoOptionDiff from src.proto_reserved import ProtoReserved -class ProtoEnumValueOption(ProtoOption): - def __eq__(self, other) -> bool: - return super().__eq__(other) +class ParsedProtoEnumValueOptionNode(ParsedProtoOptionNode): + node: "ProtoEnumValueOption" + remaining_source: str + +class ProtoEnumValueOption(ProtoOption): def __str__(self) -> str: return f"<{self.__class__.__name__} name={self.name}, value={self.value}>" @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoEnumValueOptionNode"]: test_source = "option " + proto_source.strip() + ";" match = ProtoOption.match(test_source) if match is None: return None - return ParsedProtoNode( + return ParsedProtoEnumValueOptionNode( cls(match.node.name, match.node.value), match.remaining_source.strip(), ) @@ -34,6 +36,11 @@ def serialize(self) -> str: return f"{self.name.serialize()} = {self.value.serialize()}" +class ParsedProtoEnumValueNode(ParsedProtoNode): + node: "ProtoEnumValue" + remaining_source: str + + class ProtoEnumValue(ProtoNode): def __init__( self, @@ -62,18 +69,18 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) - def __hash__(self) -> str: + def __hash__(self) -> int: return hash(str(self)) def normalize(self) -> "ProtoEnumValue": return ProtoEnumValue( self.identifier, self.value, - sorted(self.options, key=lambda o: o.name), + sorted(self.options, key=lambda o: str(o.name)), ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoEnumValueNode"]: match = ProtoIdentifier.match(proto_source) if match is None: raise ValueError(f"Proto has invalid enum value name: {proto_source}") @@ -91,19 +98,19 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: sign = ProtoIntSign.POSITIVE if proto_source.startswith("-"): sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - match = ProtoInt.match(proto_source[1:]) + int_match = ProtoInt.match(proto_source[1:]) else: - match = ProtoInt.match(proto_source) - if match is None: + int_match = ProtoInt.match(proto_source) + if int_match is None: raise ValueError( f"Proto has invalid enum value, expecting int: {proto_source}" ) - match.node.sign = sign - enum_value = match.node - proto_source = match.remaining_source.strip() + int_match.node.sign = sign + enum_value = int_match.node + proto_source = int_match.remaining_source.strip() - options = [] + options: list[ProtoEnumValueOption] = [] if proto_source.startswith("["): proto_source = proto_source[1:].strip() end_bracket = proto_source.find("]") @@ -112,15 +119,17 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: f"Proto has invalid enum value option syntax, cannot find ]: {proto_source}" ) for option_part in proto_source[:end_bracket].strip().split(","): - match = ProtoEnumValueOption.match(option_part.strip()) - if match is None: + proto_enum_value_option_match = ProtoEnumValueOption.match( + option_part.strip() + ) + if proto_enum_value_option_match is None: raise ValueError( f"Proto has invalid enum value option syntax: {proto_source}" ) - options.append(match.node) + options.append(proto_enum_value_option_match.node) proto_source = proto_source[end_bracket + 1 :].strip() - return ParsedProtoNode( + return ParsedProtoEnumValueNode( ProtoEnumValue(enum_value_name, enum_value, options), proto_source.strip() ) @@ -137,7 +146,7 @@ def serialize(self) -> str: @staticmethod def diff( enum: "ProtoEnum", left: "ProtoEnumValue", right: "ProtoEnumValue" - ) -> list["ProtoNodeDiff"]: + ) -> Sequence["ProtoNodeDiff"]: if left is None and right is not None: return [ProtoEnumValueAdded(right)] elif left is not None and right is None: @@ -148,9 +157,9 @@ def diff( return [] elif left == right: return [] - diffs = [] + diffs: list["ProtoNodeDiff"] = [] # TODO: scope these diffs under ProtoEnumValue - diffs.extend(ProtoOption.diff_sets(left.options, right.options)) + diffs.extend(ProtoEnumValueOption.diff_sets(left.options, right.options)) diffs.append(ProtoEnumValueValueChanged(enum, right, left.value)) return diffs @@ -159,7 +168,7 @@ def diff( def diff_sets( enum: "ProtoEnum", left: list["ProtoEnumValue"], right: list["ProtoEnumValue"] ) -> list["ProtoNodeDiff"]: - diffs = [] + diffs: list[ProtoNodeDiff] = [] left_names = set(o.identifier.identifier for o in left) left_values = set(int(o.value) for o in left) right_names = set(o.identifier.identifier for o in right) @@ -200,8 +209,12 @@ def __init__(self, name: ProtoIdentifier, nodes: list[ProtoNode]): self.name = name self.nodes = nodes - def __eq__(self, other: "ProtoEnum") -> bool: - return self.name == other.name and self.nodes == other.nodes + def __eq__(self, other: object) -> bool: + return ( + isinstance(other, ProtoEnum) + and self.name == other.name + and self.nodes == other.nodes + ) def __str__(self) -> str: return f"" @@ -220,13 +233,14 @@ def normalize(self) -> "ProtoEnum": @staticmethod def parse_partial_content(partial_enum_content: str) -> ParsedProtoNode: - for node_type in ( + supported_types: list[type[ProtoNode]] = [ ProtoSingleLineComment, ProtoMultiLineComment, ProtoOption, ProtoReserved, ProtoEnumValue, - ): + ] + for node_type in supported_types: try: match_result = node_type.match(partial_enum_content) except (ValueError, IndexError, TypeError): @@ -303,7 +317,7 @@ def diff(left: "ProtoEnum", right: "ProtoEnum") -> list["ProtoNodeDiff"]: return [] elif left == right: return [] - diffs = [] + diffs: list[ProtoNodeDiff] = [] # TODO: scope these diffs under ProtoEnum diffs.extend(ProtoOption.diff_sets(left.options, right.options)) diffs.extend(ProtoEnumValue.diff_sets(left, left.values, right.values)) @@ -313,7 +327,7 @@ def diff(left: "ProtoEnum", right: "ProtoEnum") -> list["ProtoNodeDiff"]: def diff_sets( left: list["ProtoEnum"], right: list["ProtoEnum"] ) -> list["ProtoNodeDiff"]: - diffs = [] + diffs: list[ProtoNodeDiff] = [] left_names = set(o.name.identifier for o in left) right_names = set(o.name.identifier for o in right) for name in left_names - right_names: @@ -332,73 +346,62 @@ def diff_sets( return diffs -class ProtoEnumAdded(ProtoNodeDiff): +class ProtoEnumDiff(ProtoNodeDiff): def __init__(self, enum: ProtoEnum): self.enum = enum - def __eq__(self, other: "ProtoEnumAdded") -> bool: - return isinstance(other, ProtoEnumAdded) and self.enum == other.enum + def __eq__(self, other: object) -> bool: + return isinstance(other, ProtoEnumDiff) and self.enum == other.enum def __str__(self) -> str: - return f"" + return f"<{self.__class__.__name__} enum={self.enum}>" -class ProtoEnumRemoved(ProtoNodeDiff): - def __init__(self, enum: ProtoEnum): - self.enum = enum +class ProtoEnumAdded(ProtoEnumDiff): + pass - def __eq__(self, other: "ProtoEnumRemoved") -> bool: - return isinstance(other, ProtoEnumRemoved) and self.enum == other.enum - def __str__(self) -> str: - return f"" +class ProtoEnumRemoved(ProtoEnumDiff): + pass -class ProtoEnumValueAdded(ProtoNodeDiff): +class ProtoEnumValueDiff(ProtoEnumDiff): def __init__(self, enum: "ProtoEnum", enum_value: "ProtoEnumValue"): - self.enum = enum + super().__init__(enum) self.enum_value = enum_value - def __eq__(self, other: "ProtoEnumValueAdded") -> bool: + def __eq__(self, other: object) -> bool: return ( - isinstance(other, ProtoEnumValueAdded) - and self.enum == other.enum + super().__eq__(other) + and isinstance(other, ProtoEnumValueDiff) and self.enum_value == other.enum_value ) def __str__(self) -> str: - return f"" + return ( + f"<{self.__class__.__name__} enum={self.enum} enum_value={self.enum_value}>" + ) -class ProtoEnumValueRemoved(ProtoNodeDiff): - def __init__(self, enum: "ProtoEnum", enum_value: "ProtoEnumValue"): - self.enum = enum - self.enum_value = enum_value +class ProtoEnumValueAdded(ProtoEnumValueDiff): + pass - def __eq__(self, other: "ProtoEnumValueRemoved") -> bool: - return ( - isinstance(other, ProtoEnumValueRemoved) - and self.enum == other.enum - and self.enum_value == other.enum_value - ) - def __str__(self) -> str: - return f"" +class ProtoEnumValueRemoved(ProtoEnumValueDiff): + pass -class ProtoEnumValueNameChanged(ProtoNodeDiff): +class ProtoEnumValueNameChanged(ProtoEnumValueDiff): def __init__( self, enum: ProtoEnum, enum_value: ProtoEnumValue, new_name: ProtoIdentifier ): - self.enum = enum - self.enum_value = enum_value + super().__init__(enum, enum_value) self.new_name = new_name - def __eq__(self, other: "ProtoEnumValueNameChanged") -> bool: + def __eq__(self, other: object) -> bool: return ( - isinstance(other, ProtoEnumValueNameChanged) - and self.enum == other.enum - and self.enum_value == other.enum_value + super().__eq__(other) + and isinstance(other, ProtoEnumValueNameChanged) and self.new_name == other.new_name ) @@ -406,19 +409,17 @@ def __str__(self) -> str: return f"" -class ProtoEnumValueValueChanged(ProtoNodeDiff): +class ProtoEnumValueValueChanged(ProtoEnumValueDiff): def __init__( self, enum: ProtoEnum, enum_value: ProtoEnumValue, new_value: ProtoInt ): - self.enum = enum - self.enum_value = enum_value + super().__init__(enum, enum_value) self.new_value = new_value - def __eq__(self, other: "ProtoEnumValueValueChanged") -> bool: + def __eq__(self, other: object) -> bool: return ( - isinstance(other, ProtoEnumValueValueChanged) - and self.enum == other.enum - and self.enum_value == other.enum_value + super().__eq__(other) + and isinstance(other, ProtoEnumValueValueChanged) and self.new_value == other.new_value ) diff --git a/src/proto_extend.py b/src/proto_extend.py index aff1a39..cb563a3 100644 --- a/src/proto_extend.py +++ b/src/proto_extend.py @@ -30,16 +30,17 @@ def normalize(self) -> "ProtoExtend": ) return ProtoExtend( name=self.name, - nodes=sorted(non_comment_nodes, key=lambda f: int(f.number)), + nodes=sorted(non_comment_nodes, key=lambda f: str(f)), ) @staticmethod def parse_partial_content(partial_content: str) -> ParsedProtoNode: - for node_type in ( + supported_types: list[type[ProtoNode]] = [ ProtoSingleLineComment, ProtoMultiLineComment, ProtoMessageField, - ): + ] + for node_type in supported_types: try: match_result = node_type.match(partial_content) except (ValueError, IndexError, TypeError): diff --git a/src/proto_extensions.py b/src/proto_extensions.py index 2008bff..e4fb2f3 100644 --- a/src/proto_extensions.py +++ b/src/proto_extensions.py @@ -25,8 +25,7 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoExtensions": # sort the ranges. return ProtoExtensions( - sorted(self.ranges, key=lambda r: r.min), - self.quote_type, + sorted(self.ranges, key=lambda r: int(r.min)), ) @classmethod diff --git a/src/proto_file.py b/src/proto_file.py index f70a210..adcd7f8 100644 --- a/src/proto_file.py +++ b/src/proto_file.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Sequence from src.proto_enum import ProtoEnum from src.proto_import import ProtoImport @@ -42,7 +42,7 @@ def messages(self) -> list[ProtoMessage]: def serialize(self) -> str: serialized_parts = [self.syntax.serialize()] - previous_type = self.syntax.__class__ + previous_type: type[ProtoNode] = self.syntax.__class__ for node in self.nodes: # Attempt to group up lines of the same type. if node.__class__ != previous_type: @@ -52,8 +52,8 @@ def serialize(self) -> str: return "\n".join(serialized_parts) - def diff(self, other: "ProtoFile") -> list[ProtoNodeDiff]: - diffs = [] + def diff(self, other: "ProtoFile") -> Sequence[ProtoNodeDiff]: + diffs: list[ProtoNodeDiff] = [] diffs.extend(ProtoSyntax.diff(self.syntax, other.syntax)) diffs.extend(ProtoImport.diff_sets(self.imports, other.imports)) diffs.extend(ProtoPackage.diff(self.package, other.package)) diff --git a/src/proto_float.py b/src/proto_float.py index 65913ce..a139b11 100644 --- a/src/proto_float.py +++ b/src/proto_float.py @@ -11,6 +11,11 @@ class ProtoFloatSign(Enum): NEGATIVE = "-" +class ParsedProtoFloatNode(ParsedProtoNode): + node: "ProtoFloat" + remaining_source: str + + class ProtoFloat(ProtoNode): SIGNS = set("+-") DIGITS = ProtoInt.DECIMAL @@ -38,14 +43,14 @@ def normalize(self) -> "ProtoFloat": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoFloatNode"]: if proto_source.startswith("inf"): proto_source = proto_source[3:] if proto_source and proto_source[0] in ProtoIdentifier.ALL: raise ValueError( f"Proto has invalid float, invalid post-inf character: {proto_source}" ) - return ParsedProtoNode( + return ParsedProtoFloatNode( ProtoFloat(float("inf"), ProtoFloatSign.POSITIVE), proto_source.strip() ) @@ -55,7 +60,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: raise ValueError( f"Proto has invalid float, invalid post-nan character: {proto_source}" ) - return ParsedProtoNode( + return ParsedProtoFloatNode( ProtoFloat(float("nan"), ProtoFloatSign.POSITIVE), proto_source.strip() ) @@ -107,7 +112,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: base *= pow(10, sign * int(proto_source[: i + 1])) proto_source = proto_source[i + 1 :] - return ParsedProtoNode( + return ParsedProtoFloatNode( ProtoFloat(base, ProtoFloatSign.POSITIVE), proto_source.strip() ) diff --git a/src/proto_identifier.py b/src/proto_identifier.py index cc55aaf..ee5368b 100644 --- a/src/proto_identifier.py +++ b/src/proto_identifier.py @@ -3,6 +3,21 @@ from src.proto_node import ParsedProtoNode, ProtoNode +class ParsedProtoIdentifierNode(ParsedProtoNode): + node: "ProtoIdentifier" + remaining_source: str + + +class ParsedProtoFullIdentifierNode(ParsedProtoIdentifierNode): + node: "ProtoFullIdentifier" + remaining_source: str + + +class ParsedProtoEnumOrMessageIdentifierNode(ParsedProtoIdentifierNode): + node: "ProtoEnumOrMessageIdentifier" + remaining_source: str + + class ProtoIdentifier(ProtoNode): ALPHABETICAL = set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz") STARTING = ALPHABETICAL | set("_") @@ -27,16 +42,16 @@ def normalize(self) -> "ProtoIdentifier": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoIdentifierNode"]: if proto_source[0] not in ProtoIdentifier.STARTING: return None for i, c in enumerate(proto_source): if c not in ProtoIdentifier.ALL: - return ParsedProtoNode( + return ParsedProtoIdentifierNode( ProtoIdentifier(proto_source[:i]), proto_source[i:] ) - return ParsedProtoNode(ProtoIdentifier(proto_source), "") + return ParsedProtoIdentifierNode(ProtoIdentifier(proto_source), "") def serialize(self) -> str: return self.identifier @@ -47,7 +62,7 @@ class ProtoFullIdentifier(ProtoIdentifier): ALL = ProtoIdentifier.ALL | set(".") @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoFullIdentifierNode"]: if proto_source[0] not in ProtoFullIdentifier.STARTING: return None @@ -61,7 +76,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: f"Proto source has invalid identifier, expecting alphanumeric after .: {proto_source}" ) identifier_parts.append(proto_source[last_part_start:i]) - return ParsedProtoNode( + return ParsedProtoFullIdentifierNode( ProtoFullIdentifier(".".join(identifier_parts)), proto_source[i:] ) elif c == ".": @@ -74,7 +89,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: f"Proto source has invalid identifier, expecting alphanumeric after .: {proto_source}" ) identifier_parts.append(proto_source[last_part_start:]) - return ParsedProtoNode(ProtoFullIdentifier(".".join(identifier_parts)), "") + return ParsedProtoFullIdentifierNode( + ProtoFullIdentifier(".".join(identifier_parts)), "" + ) class ProtoEnumOrMessageIdentifier(ProtoIdentifier): @@ -82,19 +99,22 @@ class ProtoEnumOrMessageIdentifier(ProtoIdentifier): ALL = ProtoIdentifier.ALL | set(".") @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, proto_source: str + ) -> Optional["ParsedProtoEnumOrMessageIdentifierNode"]: if proto_source[0] == ".": matched_source = proto_source[1:] else: matched_source = proto_source - match = ProtoFullIdentifier.match(matched_source) - if match is not None: - match = ParsedProtoNode( - ProtoEnumOrMessageIdentifier(match.node.identifier), - match.remaining_source, + identifier_match = ProtoFullIdentifier.match(matched_source) + if identifier_match is not None: + match = ParsedProtoEnumOrMessageIdentifierNode( + ProtoEnumOrMessageIdentifier(identifier_match.node.identifier), + identifier_match.remaining_source, ) if proto_source[0] == ".": match.node.identifier = "." + match.node.identifier - return match + return match + return identifier_match diff --git a/src/proto_import.py b/src/proto_import.py index f3a5682..dc67721 100644 --- a/src/proto_import.py +++ b/src/proto_import.py @@ -25,7 +25,7 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) - def __dict__(self) -> dict: + def __dict__(self): return { "path": self.path.serialize(), "weak": self.weak, @@ -80,7 +80,7 @@ def serialize(self) -> str: def diff_sets( left: list["ProtoImport"], right: list["ProtoImport"] ) -> list["ProtoNodeDiff"]: - diffs = [] + diffs: list[ProtoNodeDiff] = [] left_names = set(i.path for i in left) right_names = set(i.path for i in right) for name in left_names - right_names: @@ -106,8 +106,11 @@ class ProtoImportAdded(ProtoNodeDiff): def __init__(self, proto_import: ProtoImport): self.proto_import = proto_import - def __eq__(self, other: "ProtoImportAdded") -> bool: - return self.proto_import == other.proto_import + def __eq__(self, other: object) -> bool: + return ( + isinstance(other, ProtoImportAdded) + and self.proto_import == other.proto_import + ) class ProtoImportRemoved(ProtoImportAdded): @@ -118,10 +121,6 @@ class ProtoImportMadeWeak(ProtoImportAdded): pass -class ProtoImportMadeWeak(ProtoImportAdded): - pass - - class ProtoImportMadeNonWeak(ProtoImportAdded): pass diff --git a/src/proto_int.py b/src/proto_int.py index dd1e01e..67aa7ba 100644 --- a/src/proto_int.py +++ b/src/proto_int.py @@ -10,6 +10,11 @@ class ProtoIntSign(Enum): NEGATIVE = "-" +class ParsedProtoIntNode(ParsedProtoNode): + node: "ProtoInt" + remaining_source: str + + class ProtoInt(ProtoNode): OCTAL = set("01234567") DECIMAL = OCTAL | set("89") @@ -38,7 +43,7 @@ def normalize(self) -> "ProtoInt": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoIntNode"]: if proto_source[0] not in ProtoInt.DECIMAL: return None @@ -58,7 +63,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: value = int(f"0x{proto_source[:i + 1]}", 16) except ValueError: raise ValueError(f"Proto has invalid hex: {proto_source}") - return ParsedProtoNode( + return ParsedProtoIntNode( ProtoInt(value, ProtoIntSign.POSITIVE), proto_source[i + 1 :].strip(), ) @@ -74,7 +79,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: value = int(f"0{proto_source[:i + 1]}", 8) except ValueError: raise ValueError(f"Proto has invalid octal: {proto_source}") - return ParsedProtoNode( + return ParsedProtoIntNode( ProtoInt(value, ProtoIntSign.POSITIVE), proto_source[i + 1 :].strip(), ) @@ -91,7 +96,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: except ValueError: return None - return ParsedProtoNode( + return ParsedProtoIntNode( ProtoInt(value, ProtoIntSign.POSITIVE), proto_source[i + 1 :].strip(), ) diff --git a/src/proto_message.py b/src/proto_message.py index b2fb80c..191e127 100644 --- a/src/proto_message.py +++ b/src/proto_message.py @@ -1,7 +1,9 @@ from enum import Enum -from typing import Optional +from typing import Optional, Sequence from src.proto_comment import ( + ParsedProtoMultiLineCommentNode, + ParsedProtoSingleLineCommentNode, ProtoComment, ProtoMultiLineComment, ProtoSingleLineComment, @@ -16,19 +18,33 @@ ) from src.proto_int import ProtoInt from src.proto_message_field import ( + ParsedProtoMessageFieldNode, ProtoMessageField, ProtoMessageFieldOption, ProtoMessageFieldTypesEnum, ) from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff -from src.proto_option import ProtoOption +from src.proto_option import ParsedProtoOptionNode, ProtoOption from src.proto_reserved import ProtoReserved -ProtoOneOfNodeTypes = ProtoOption | ProtoMessageField +ProtoOneOfNodeTypes = ( + ProtoOption | ProtoMessageField | ProtoSingleLineComment | ProtoMultiLineComment +) +ProtoParsedOneOfNodeTypes = ( + ParsedProtoOptionNode + | ParsedProtoMessageFieldNode + | ParsedProtoSingleLineCommentNode + | ParsedProtoMultiLineCommentNode +) + + +class ParsedProtoOneOfNode(ParsedProtoNode): + node: "ProtoOneOf" + remaining_source: str class ProtoOneOf(ProtoNode): - def __init__(self, name: ProtoIdentifier, nodes: list[ProtoOneOfNodeTypes]): + def __init__(self, name: ProtoIdentifier, nodes: Sequence[ProtoOneOfNodeTypes]): self.name = name self.nodes = nodes @@ -71,13 +87,14 @@ def normalize(self) -> "ProtoOneOf": ) @staticmethod - def parse_partial_content(partial_oneof_content: str) -> ParsedProtoNode: - for node_type in ( + def parse_partial_content(partial_oneof_content: str) -> ProtoParsedOneOfNodeTypes: + supported_types: list[type[ProtoOneOfNodeTypes]] = [ ProtoMessageField, ProtoOption, ProtoSingleLineComment, ProtoMultiLineComment, - ): + ] + for node_type in supported_types: try: match_result = node_type.match(partial_oneof_content) except (ValueError, IndexError, TypeError): @@ -91,7 +108,7 @@ def parse_partial_content(partial_oneof_content: str) -> ParsedProtoNode: ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoOneOfNode"]: if not proto_source.startswith("oneof "): return None @@ -127,7 +144,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: parsed_tree.append(match_result.node) proto_source = match_result.remaining_source.strip() - return ParsedProtoNode(ProtoOneOf(oneof_name, nodes=parsed_tree), proto_source) + return ParsedProtoOneOfNode( + ProtoOneOf(oneof_name, nodes=parsed_tree), proto_source + ) @property def options(self) -> list[ProtoOption]: @@ -167,7 +186,7 @@ def __init__( value_type: ProtoMapValueTypesEnum, name: ProtoIdentifier, number: ProtoInt, - enum_or_message_type_name: Optional[ProtoFullIdentifier] = None, + enum_or_message_type_name: Optional[ProtoEnumOrMessageIdentifier] = None, options: Optional[list[ProtoMessageFieldOption]] = None, ): self.key_type = key_type @@ -256,22 +275,22 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: proto_source = proto_source[1:].strip() # Try to match the map field's name. - match = ProtoIdentifier.match(proto_source) - if match is None: + identifier_match = ProtoIdentifier.match(proto_source) + if identifier_match is None: return None - name = match.node - proto_source = match.remaining_source.strip() + name = identifier_match.node + proto_source = identifier_match.remaining_source.strip() if not proto_source.startswith("="): return None proto_source = proto_source[1:].strip() # Try to match the map field number. - match = ProtoInt.match(proto_source) - if match is None: + int_match = ProtoInt.match(proto_source) + if int_match is None: return None - number = match.node - proto_source = match.remaining_source.strip() + number = int_match.node + proto_source = int_match.remaining_source.strip() # Try to match map field options, if any. options = [] @@ -283,12 +302,14 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: f"Proto has invalid map field option syntax, cannot find ]: {proto_source}" ) for option_part in proto_source[:end_bracket].strip().split(","): - match = ProtoMessageFieldOption.match(option_part.strip()) - if match is None: + message_field_option_match = ProtoMessageFieldOption.match( + option_part.strip() + ) + if message_field_option_match is None: raise ValueError( f"Proto has invalid map field option syntax: {proto_source}" ) - options.append(match.node) + options.append(message_field_option_match.node) proto_source = proto_source[end_bracket + 1 :].strip() if not proto_source.startswith(";"): @@ -310,6 +331,10 @@ def serialize(self) -> str: ] if self.value_type == ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE: + if self.enum_or_message_type_name is None: + raise ValueError( + f"Enum or message type name was not set for: {str(self)}" + ) serialized_parts.append(f"{self.enum_or_message_type_name.serialize()}>") else: serialized_parts.append(f"{self.value_type.value}>") @@ -331,7 +356,7 @@ def serialize(self) -> str: class ProtoMessage(ProtoNode): - def __init__(self, name: ProtoIdentifier, nodes: list[ProtoNode]): + def __init__(self, name: ProtoIdentifier, nodes: Sequence[ProtoNode]): self.name = name self.nodes = nodes @@ -353,20 +378,19 @@ def normalize(self) -> "ProtoMessage": enums = [] messages = [] fields = [] + oneofs = [] reserveds = [] for node in non_comment_nodes: if isinstance(node, ProtoOption): options.append(node.normalize()) elif isinstance(node, ProtoEnum): - options.append(node.normalize()) + enums.append(node.normalize()) elif isinstance(node, ProtoMessage): messages.append(node.normalize()) - elif ( - isinstance(node, ProtoMessageField) - or isinstance(node, ProtoOneOf) - or isinstance(node, ProtoMap) - ): + elif isinstance(node, ProtoMessageField) or isinstance(node, ProtoMap): fields.append(node.normalize()) + elif isinstance(node, ProtoOneOf): + oneofs.append(node.normalize()) elif isinstance(node, ProtoReserved): reserveds.append(node.normalize()) else: @@ -379,7 +403,8 @@ def normalize(self) -> "ProtoMessage": + sorted(enums, key=lambda e: str(e)) + sorted(messages, key=lambda m: str(m)) + sorted(fields, key=lambda f: int(f.number)) - + sorted(reserveds, key=lambda r: (r.min, r.max)) + + sorted(oneofs, key=lambda o: str(o)) + + sorted(reserveds, key=lambda r: int(r.min)) ) return ProtoMessage( @@ -389,7 +414,7 @@ def normalize(self) -> "ProtoMessage": @staticmethod def parse_partial_content(partial_message_content: str) -> ParsedProtoNode: - for node_type in ( + supported_types: list[type[ProtoNode]] = [ ProtoSingleLineComment, ProtoMultiLineComment, ProtoEnum, @@ -401,7 +426,8 @@ def parse_partial_content(partial_message_content: str) -> ParsedProtoNode: ProtoMessageField, ProtoOneOf, ProtoMap, - ): + ] + for node_type in supported_types: try: match_result = node_type.match(partial_message_content) except (ValueError, IndexError, TypeError): @@ -463,7 +489,7 @@ def serialize(self) -> str: return "\n".join(serialize_parts) @staticmethod - def diff(left: "ProtoMessage", right: "ProtoMessage") -> list["ProtoNodeDiff"]: + def diff(left: "ProtoMessage", right: "ProtoMessage") -> Sequence["ProtoNodeDiff"]: if left is None and right is not None: return [ProtoMessageAdded(right)] elif left is not None and right is None: @@ -482,8 +508,8 @@ def diff(left: "ProtoMessage", right: "ProtoMessage") -> list["ProtoNodeDiff"]: @staticmethod def diff_sets( left: list["ProtoMessage"], right: list["ProtoMessage"] - ) -> list["ProtoNodeDiff"]: - diffs = [] + ) -> Sequence["ProtoNodeDiff"]: + diffs: list[ProtoNodeDiff] = [] left_names = set(o.name.identifier for o in left) right_names = set(o.name.identifier for o in right) for name in left_names - right_names: @@ -502,23 +528,22 @@ def diff_sets( return diffs -class ProtoMessageAdded(ProtoNodeDiff): +class ProtoMessageDiff(ProtoNodeDiff): def __init__(self, message: ProtoMessage): self.message = message - def __eq__(self, other: "ProtoMessageAdded") -> bool: - return isinstance(other, ProtoMessageAdded) and self.message == other.message + def __eq__(self, other: object) -> bool: + return isinstance(other, ProtoMessageDiff) and self.message == other.message def __str__(self) -> str: - return f"" + return f"<{self.__class__.__name__} message={self.message}>" -class ProtoMessageRemoved(ProtoNodeDiff): - def __init__(self, message: ProtoMessage): - self.message = message +class ProtoMessageAdded(ProtoMessageDiff): + def __eq__(self, other: object) -> bool: + return super().__eq__(other) and isinstance(other, ProtoMessageAdded) - def __eq__(self, other: "ProtoMessageRemoved") -> bool: - return isinstance(other, ProtoMessageRemoved) and self.message == other.message - def __str__(self) -> str: - return f"" +class ProtoMessageRemoved(ProtoMessageDiff): + def __eq__(self, other: object) -> bool: + return super().__eq__(other) and isinstance(other, ProtoMessageRemoved) diff --git a/src/proto_message_field.py b/src/proto_message_field.py index b2cbba0..97f75ce 100644 --- a/src/proto_message_field.py +++ b/src/proto_message_field.py @@ -1,18 +1,27 @@ from enum import Enum from typing import Optional -from src.proto_enum import ProtoEnumValueOption -from src.proto_identifier import ( - ProtoEnumOrMessageIdentifier, - ProtoFullIdentifier, - ProtoIdentifier, -) +from src.proto_enum import ParsedProtoEnumValueOptionNode, ProtoEnumValueOption +from src.proto_identifier import ProtoEnumOrMessageIdentifier, ProtoIdentifier from src.proto_int import ProtoInt from src.proto_node import ParsedProtoNode, ProtoNode +class ParsedProtoMessageFieldOptionNode(ParsedProtoEnumValueOptionNode): + node: "ProtoMessageFieldOption" + remaining_source: str + + class ProtoMessageFieldOption(ProtoEnumValueOption): - pass + @classmethod + def match(cls, proto_source: str) -> Optional["ParsedProtoMessageFieldOptionNode"]: + match = super().match(proto_source) + if match is None: + return None + return ParsedProtoMessageFieldOptionNode( + match.node, + match.remaining_source.strip(), + ) class ProtoMessageFieldTypesEnum(Enum): @@ -34,6 +43,11 @@ class ProtoMessageFieldTypesEnum(Enum): ENUM_OR_MESSAGE = "enum_or_message" +class ParsedProtoMessageFieldNode(ParsedProtoNode): + node: "ProtoMessageField" + remaining_source: str + + class ProtoMessageField(ProtoNode): def __init__( self, @@ -42,7 +56,7 @@ def __init__( number: ProtoInt, repeated: bool = False, optional: bool = False, - enum_or_message_type_name: Optional[ProtoFullIdentifier] = None, + enum_or_message_type_name: Optional[ProtoEnumOrMessageIdentifier] = None, options: Optional[list[ProtoMessageFieldOption]] = None, ): self.type = type @@ -88,11 +102,11 @@ def normalize(self) -> "ProtoMessageField": repeated=self.repeated, optional=self.optional, enum_or_message_type_name=self.enum_or_message_type_name, - options=sorted(self.options, key=lambda o: o.name), + options=sorted(self.options, key=lambda o: str(o.name)), ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoMessageFieldNode"]: # First, try to match the optional repeated. repeated = False if proto_source.startswith("repeated "): @@ -130,22 +144,22 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: proto_source = match.remaining_source.strip() # Match the field name. - match = ProtoIdentifier.match(proto_source) - if match is None: + identifier_match = ProtoIdentifier.match(proto_source) + if identifier_match is None: return None - name = match.node - proto_source = match.remaining_source.strip() + name = identifier_match.node + proto_source = identifier_match.remaining_source.strip() if not proto_source.startswith("= "): return None proto_source = proto_source[2:].strip() # Match the field number. - match = ProtoInt.match(proto_source) - if match is None: + int_match = ProtoInt.match(proto_source) + if int_match is None: return None - number = match.node - proto_source = match.remaining_source.strip() + number = int_match.node + proto_source = int_match.remaining_source.strip() options = [] if proto_source.startswith("["): @@ -156,12 +170,14 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: f"Proto has invalid message field option syntax, cannot find ]: {proto_source}" ) for option_part in proto_source[:end_bracket].strip().split(","): - match = ProtoMessageFieldOption.match(option_part.strip()) - if match is None: + message_field_option_match = ProtoMessageFieldOption.match( + option_part.strip() + ) + if message_field_option_match is None: raise ValueError( f"Proto has invalid message field option syntax: {proto_source}" ) - options.append(match.node) + options.append(message_field_option_match.node) proto_source = proto_source[end_bracket + 1 :].strip() if not proto_source.startswith(";"): @@ -169,7 +185,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: f"Proto has invalid message field syntax, missing ending ;:{proto_source}" ) - return ParsedProtoNode( + return ParsedProtoMessageFieldNode( ProtoMessageField( matched_type, name, @@ -188,6 +204,10 @@ def serialize(self) -> str: serialized_parts.append("repeated") if self.type == ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE: + if self.enum_or_message_type_name is None: + raise ValueError( + f"Enum or message type name was not set for: {str(self)}" + ) serialized_parts.append(self.enum_or_message_type_name.serialize()) else: serialized_parts.append(self.type.value) diff --git a/src/proto_node.py b/src/proto_node.py index 162fe74..37c36e8 100644 --- a/src/proto_node.py +++ b/src/proto_node.py @@ -32,5 +32,5 @@ class ProtoNodeDiff(abc.ABC): def __repr__(self) -> str: return str(self) - def __hash__(self) -> str: + def __hash__(self) -> int: return hash(str(self)) diff --git a/src/proto_option.py b/src/proto_option.py index 58c02cf..a780351 100644 --- a/src/proto_option.py +++ b/src/proto_option.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Sequence from src.proto_constant import ProtoConstant from src.proto_identifier import ( @@ -9,6 +9,11 @@ from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff +class ParsedProtoOptionNode(ParsedProtoNode): + node: "ProtoOption" + remaining_source: str + + class ProtoOption(ProtoNode): def __init__(self, name: ProtoIdentifier, value: ProtoConstant): self.name = name @@ -30,7 +35,7 @@ def normalize(self) -> "ProtoOption": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoOptionNode"]: if not proto_source.startswith("option "): return None proto_source = proto_source[7:] @@ -39,27 +44,32 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: if proto_source.startswith("("): proto_source = proto_source[1:] match = ProtoFullIdentifier.match(proto_source) - if not match or not match.remaining_source.startswith(")"): + if match is None or not match.remaining_source.startswith(")"): # This might be a regular identifier. - match = ProtoIdentifier.match(proto_source) - if not match or not match.remaining_source.startswith(")"): + identifier_match = ProtoIdentifier.match(proto_source) + if ( + not identifier_match + or not identifier_match.remaining_source.startswith(")") + ): raise ValueError( f"Proto has invalid option when expecting ): {proto_source}" ) - name_parts.append(ProtoIdentifier(f"({match.node.identifier})")) + name_parts.append( + ProtoIdentifier(f"({identifier_match.node.identifier})") + ) + proto_source = identifier_match.remaining_source[1:] else: name_parts.append(ProtoFullIdentifier(f"({match.node.identifier})")) - - proto_source = match.remaining_source[1:] + proto_source = match.remaining_source[1:] while True: - match = ProtoEnumOrMessageIdentifier.match(proto_source) - if match is None: - match = ProtoIdentifier.match(proto_source) - if match is None: + identifier_match = ProtoEnumOrMessageIdentifier.match(proto_source) + if identifier_match is None: + identifier_match = ProtoIdentifier.match(proto_source) + if identifier_match is None: break - name_parts.append(match.node) - proto_source = match.remaining_source + name_parts.append(identifier_match.node) + proto_source = identifier_match.remaining_source proto_source = proto_source.strip() if not proto_source.startswith("="): @@ -67,27 +77,28 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: f"Proto has invalid option when expecting =: {proto_source}" ) proto_source = proto_source[1:].strip() - match = ProtoConstant.match(proto_source) - if not match: + constant_match = ProtoConstant.match(proto_source) + if constant_match is None: raise ValueError( f"Proto has invalid option when expecting constant: {proto_source}" ) - proto_source = match.remaining_source - if not match.remaining_source.startswith(";"): + proto_source = constant_match.remaining_source + if not constant_match.remaining_source.startswith(";"): raise ValueError( f"Proto has invalid option when expecting ;: {proto_source}" ) + identifier: ProtoFullIdentifier | ProtoIdentifier if len(name_parts) > 1: identifier = ProtoFullIdentifier("".join(x.identifier for x in name_parts)) else: identifier = ProtoIdentifier(name_parts[0].identifier) - return ParsedProtoNode( + return ParsedProtoOptionNode( ProtoOption( name=identifier, - value=match.node, + value=constant_match.node, ), proto_source[1:], ) @@ -96,7 +107,7 @@ def serialize(self) -> str: return f"option {self.name.serialize()} = {self.value.serialize()};" @staticmethod - def diff(left: "ProtoOption", right: "ProtoOption") -> list["ProtoNodeDiff"]: + def diff(left: "ProtoOption", right: "ProtoOption") -> Sequence["ProtoOptionDiff"]: if left is None and right is not None: return [ProtoOptionAdded(right)] elif left is not None and right is None: @@ -111,9 +122,9 @@ def diff(left: "ProtoOption", right: "ProtoOption") -> list["ProtoNodeDiff"]: @staticmethod def diff_sets( - left: list["ProtoOption"], right: list["ProtoOption"] - ) -> list["ProtoNodeDiff"]: - diffs = [] + left: Sequence["ProtoOption"], right: Sequence["ProtoOption"] + ) -> list["ProtoOptionDiff"]: + diffs: list[ProtoOptionDiff] = [] left_names = set(o.name.identifier for o in left) right_names = set(o.name.identifier for o in right) for name in left_names - right_names: @@ -132,13 +143,19 @@ def diff_sets( return diffs -class ProtoOptionValueChanged(ProtoNodeDiff): - def __init__(self, name: ProtoIdentifier, left: str, right: str): +class ProtoOptionDiff(ProtoNodeDiff): + pass + + +class ProtoOptionValueChanged(ProtoOptionDiff): + def __init__( + self, name: ProtoIdentifier, left: ProtoConstant, right: ProtoConstant + ): self.name = name self.left = left self.right = right - def __eq__(self, other: "ProtoOptionValueChanged") -> bool: + def __eq__(self, other: object) -> bool: return ( isinstance(other, ProtoOptionValueChanged) and self.name == other.name @@ -150,22 +167,22 @@ def __str__(self) -> str: return f"" -class ProtoOptionAdded(ProtoNodeDiff): - def __init__(self, left: str): +class ProtoOptionAdded(ProtoOptionDiff): + def __init__(self, left: ProtoOption): self.left = left - def __eq__(self, other: "ProtoOptionAdded") -> bool: + def __eq__(self, other: object) -> bool: return isinstance(other, ProtoOptionAdded) and self.left == other.left def __str__(self) -> str: return f"" -class ProtoOptionRemoved(ProtoNodeDiff): - def __init__(self, right: str): +class ProtoOptionRemoved(ProtoOptionDiff): + def __init__(self, right: ProtoOption): self.right = right - def __eq__(self, other: "ProtoOptionRemoved") -> bool: + def __eq__(self, other: object) -> bool: return isinstance(other, ProtoOptionRemoved) and self.right == other.right def __str__(self) -> str: diff --git a/src/proto_package.py b/src/proto_package.py index 569ee2c..7559cd6 100644 --- a/src/proto_package.py +++ b/src/proto_package.py @@ -50,36 +50,44 @@ def serialize(self) -> str: return f"package {self.package};" @staticmethod - def diff(left: "ProtoPackage", right: "ProtoPackage") -> list["ProtoNodeDiff"]: + def diff( + left: Optional["ProtoPackage"], right: Optional["ProtoPackage"] + ) -> list["ProtoNodeDiff"]: if left == right: return [] elif left is not None and right is None: return [ProtoPackageAdded(left)] elif left is None and right is not None: return [ProtoPackageRemoved(right)] + + assert left is not None and right is not None return [ProtoPackageChanged(left, right)] class ProtoPackageChanged(ProtoNodeDiff): - def __init__(self, left: str, right: str): + def __init__(self, left: ProtoPackage, right: ProtoPackage): self.left = left self.right = right - def __eq__(self, other: "ProtoPackageChanged") -> bool: - return self.left == other.left and self.right == other.right + def __eq__(self, other: object) -> bool: + return ( + isinstance(other, ProtoPackageChanged) + and self.left == other.left + and self.right == other.right + ) class ProtoPackageAdded(ProtoNodeDiff): - def __init__(self, left: str): + def __init__(self, left: ProtoPackage): self.left = left - def __eq__(self, other: "ProtoPackageAdded") -> bool: - return self.left == other.left + def __eq__(self, other: object) -> bool: + return isinstance(other, ProtoPackageAdded) and self.left == other.left class ProtoPackageRemoved(ProtoNodeDiff): - def __init__(self, right: str): + def __init__(self, right: ProtoPackage): self.right = right - def __eq__(self, other: "ProtoPackageRemoved") -> bool: - return self.right == other.right + def __eq__(self, other: object) -> bool: + return isinstance(other, ProtoPackageRemoved) and self.right == other.right diff --git a/src/proto_range.py b/src/proto_range.py index 2162f79..4f716c3 100644 --- a/src/proto_range.py +++ b/src/proto_range.py @@ -5,6 +5,11 @@ from src.proto_node import ParsedProtoNode, ProtoNode +class ParsedProtoRangeNode(ParsedProtoNode): + node: "ProtoRange" + remaining_source: str + + class ProtoRangeEnum(Enum): MAX = "max" @@ -35,7 +40,7 @@ def normalize(self) -> "ProtoRange": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoRangeNode"]: sign = ProtoIntSign.POSITIVE if proto_source.startswith("-") and proto_source != "-": sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) @@ -53,7 +58,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: if proto_source.startswith("to "): proto_source = proto_source[3:] if proto_source.startswith("max"): - return ParsedProtoNode( + return ParsedProtoRangeNode( ProtoRange(min, ProtoRangeEnum.MAX), proto_source[3:].strip(), ) @@ -72,7 +77,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: max = match.node proto_source = match.remaining_source - return ParsedProtoNode(ProtoRange(min, max), proto_source.strip()) + return ParsedProtoRangeNode(ProtoRange(min, max), proto_source.strip()) def serialize(self) -> str: if self.max is not None: diff --git a/src/proto_reserved.py b/src/proto_reserved.py index 24b40f0..9a9c40f 100644 --- a/src/proto_reserved.py +++ b/src/proto_reserved.py @@ -49,11 +49,18 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoReserved": # sort the ranges. return ProtoReserved( - sorted(self.ranges, key=lambda r: r.min), - sorted(self.fields), + sorted(self.ranges, key=lambda r: int(r.min)), + sorted(self.fields, key=lambda f: str(f)), self.quote_type, ) + @property + def min(self) -> str | int: + if self.ranges: + return int(min(self.ranges, key=lambda r: int(r.min)).min) + else: + return str(min(self.fields, key=lambda f: str(f))) + @classmethod def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("reserved "): @@ -74,10 +81,10 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: ) if proto_source[0] == ",": proto_source = proto_source[1:].strip() - match = ProtoRange.match(proto_source) - if match is not None: - ranges.append(match.node) - proto_source = match.remaining_source + range_match = ProtoRange.match(proto_source) + if range_match is not None: + ranges.append(range_match.node) + proto_source = range_match.remaining_source else: # Maybe this is a field identifier. quote_types = [ @@ -116,6 +123,7 @@ def serialize(self) -> str: + ", ".join( f"{self.quote_type.value}{f.serialize()}{self.quote_type.value}" for f in self.fields + if self.quote_type is not None ), ] return " ".join(serialize_parts) + ";" diff --git a/src/proto_service.py b/src/proto_service.py index ec00cd3..76ec889 100644 --- a/src/proto_service.py +++ b/src/proto_service.py @@ -142,10 +142,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: proto_source = proto_source[1:].strip() # Try to parse options. - options = [] + options: list[ProtoOption] = [] if proto_source.startswith("{"): proto_source = proto_source[1:].strip() - options = [] while proto_source: # Remove empty statements. if proto_source.startswith(";"): @@ -232,12 +231,13 @@ def normalize(self) -> "ProtoService": @staticmethod def parse_partial_content(partial_service_content: str) -> ParsedProtoNode: - for node_type in ( + supported_types: list[type[ProtoNode]] = [ ProtoOption, ProtoServiceRPC, ProtoSingleLineComment, ProtoMultiLineComment, - ): + ] + for node_type in supported_types: try: match_result = node_type.match(partial_service_content) except (ValueError, IndexError, TypeError): diff --git a/src/proto_string_literal.py b/src/proto_string_literal.py index 7336b0f..9ca0339 100644 --- a/src/proto_string_literal.py +++ b/src/proto_string_literal.py @@ -3,6 +3,11 @@ from src.proto_node import ParsedProtoNode, ProtoNode +class ParsedProtoStringLiteralNode(ParsedProtoNode): + node: "ProtoStringLiteral" + remaining_source: str + + class ProtoStringLiteral(ProtoNode): QUOTES = ['"', "'"] @@ -26,7 +31,7 @@ def normalize(self) -> "ProtoStringLiteral": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoStringLiteralNode"]: if not any(proto_source.startswith(c) for c in ProtoStringLiteral.QUOTES): return None escaped = False @@ -36,7 +41,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: escaped = True continue if c == starting_quote and not escaped: - return ParsedProtoNode( + return ParsedProtoStringLiteralNode( ProtoStringLiteral(proto_source[1 : i + 1], quote=starting_quote), proto_source[i + 2 :].strip(), ) diff --git a/src/proto_syntax.py b/src/proto_syntax.py index 25109c7..0d1496a 100644 --- a/src/proto_syntax.py +++ b/src/proto_syntax.py @@ -5,6 +5,11 @@ from src.proto_string_literal import ProtoStringLiteral +class ParsedProtoSyntaxNode(ParsedProtoNode): + node: "ProtoSyntax" + remaining_source: str + + class ProtoSyntaxType(Enum): PROTO2 = "proto2" PROTO3 = "proto3" @@ -23,14 +28,14 @@ def __str__(self) -> str: def __repr__(self) -> str: return str(self) - def __dict__(self) -> dict: + def __dict__(self): return {"syntax": self.syntax.serialize()} def normalize(self) -> "ProtoSyntax": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match(cls, proto_source: str) -> Optional["ParsedProtoSyntaxNode"]: if not proto_source.startswith("syntax = "): return None proto_source = proto_source[9:] @@ -46,7 +51,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: f"Proto has unknown syntax type: {match.node.value}, must be one of: {[proto_type.name for proto_type in ProtoSyntaxType]}" ) - return ParsedProtoNode( + return ParsedProtoSyntaxNode( ProtoSyntax(match.node), match.remaining_source.strip(), ) @@ -62,9 +67,13 @@ def diff(left: "ProtoSyntax", right: "ProtoSyntax") -> list["ProtoNodeDiff"]: class ProtoSyntaxChanged(ProtoNodeDiff): - def __init__(self, left: ProtoStringLiteral, right: ProtoStringLiteral): + def __init__(self, left: ProtoSyntax, right: ProtoSyntax): self.left = left self.right = right - def __eq__(self, other: "ProtoSyntaxChanged") -> bool: - return self.left == other.left and self.right == other.right + def __eq__(self, other: object) -> bool: + return ( + isinstance(other, ProtoSyntaxChanged) + and self.left == other.left + and self.right == other.right + ) diff --git a/test/proto_message_test.py b/test/proto_message_test.py index 19195a9..0812498 100644 --- a/test/proto_message_test.py +++ b/test/proto_message_test.py @@ -72,7 +72,7 @@ def test_message_all_features(self): ProtoIdentifier("(foo.bar).baz"), ProtoConstant(ProtoStringLiteral("bat")), ), - ProtoMessage( + ProtoEnum( ProtoIdentifier("MyEnum"), [ ProtoEnumValue( @@ -295,7 +295,7 @@ def test_message_nested_enum(self): ProtoMessage( ProtoIdentifier("FooMessage"), [ - ProtoMessage( + ProtoEnum( ProtoIdentifier("MyEnum"), [ ProtoEnumValue( From 0e0dd543df5be1db357478ca2842cdf7331387f8 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sat, 18 Feb 2023 22:40:31 -0500 Subject: [PATCH 11/35] [wip] start adding message field diffs (#66) --- TODO.md | 1 + src/parser.py | 6 +- src/proto_bool.py | 15 +- src/proto_comment.py | 19 +- src/proto_constant.py | 34 +- src/proto_enum.py | 51 ++- src/proto_extend.py | 24 +- src/proto_extensions.py | 13 +- src/proto_float.py | 15 +- src/proto_identifier.py | 26 +- src/proto_import.py | 16 +- src/proto_int.py | 13 +- src/proto_message.py | 158 ++++++-- src/proto_message_field.py | 29 +- src/proto_node.py | 7 +- src/proto_option.py | 46 ++- src/proto_package.py | 9 +- src/proto_range.py | 30 +- src/proto_reserved.py | 27 +- src/proto_service.py | 50 ++- src/proto_string_literal.py | 11 +- src/proto_syntax.py | 11 +- test/parser_test.py | 194 ++++++---- test/proto_bool_test.py | 20 +- test/proto_comment_test.py | 28 +- test/proto_constant_test.py | 155 ++++---- test/proto_enum_test.py | 548 ++++++++++++++++++---------- test/proto_extend_test.py | 32 +- test/proto_extensions_test.py | 14 +- test/proto_float_test.py | 64 ++-- test/proto_identifier_test.py | 93 ++--- test/proto_import_test.py | 74 ++-- test/proto_int_test.py | 24 +- test/proto_message_field_test.py | 60 +-- test/proto_message_test.py | 583 +++++++++++++++++++----------- test/proto_option_test.py | 389 +++++++++++--------- test/proto_package_test.py | 55 +-- test/proto_range_test.py | 32 +- test/proto_reserved_test.py | 20 +- test/proto_service_test.py | 197 ++++++---- test/proto_string_literal_test.py | 26 +- test/proto_syntax_test.py | 64 ++-- 42 files changed, 2079 insertions(+), 1204 deletions(-) diff --git a/TODO.md b/TODO.md index ca4a7e7..e738ea0 100644 --- a/TODO.md +++ b/TODO.md @@ -85,6 +85,7 @@ - [ ] Additions/removals - [ ] Option changes - [ ] Backwards-compatibility check + - [ ] __eq__ should enforce parent equality - [ ] Scoping of diffs under containing objects - [ ] Enum options under enums - [ ] Enum value changes under enums diff --git a/src/parser.py b/src/parser.py index 75b9de9..62a4723 100644 --- a/src/parser.py +++ b/src/parser.py @@ -38,7 +38,7 @@ def parse_partial_content(partial_proto_content: str) -> ParsedProtoNode: ] for node_type in node_types: try: - match_result = node_type.match(partial_proto_content) + match_result = node_type.match(None, partial_proto_content) except (ValueError, IndexError, TypeError): raise ParseError( f"Could not parse proto content:\n{partial_proto_content}" @@ -56,7 +56,7 @@ def parse_syntax_and_preceding_comments( while True: for node_type in [ProtoSingleLineComment, ProtoMultiLineComment]: try: - match_result = node_type.match(proto_content) + match_result = node_type.match(None, proto_content) except (ValueError, IndexError, TypeError): raise ParseError(f"Could not parse proto content:\n{proto_content}") if match_result is not None: @@ -68,7 +68,7 @@ def parse_syntax_and_preceding_comments( # Next, parse syntax. try: - syntax_match = ProtoSyntax.match(proto_content.strip()) + syntax_match = ProtoSyntax.match(None, proto_content.strip()) except (ValueError, IndexError, TypeError): raise ParseError(f"Proto doesn't have parseable syntax:\n{proto_content}") if syntax_match is None: diff --git a/src/proto_bool.py b/src/proto_bool.py index 4704aa1..879f0ff 100644 --- a/src/proto_bool.py +++ b/src/proto_bool.py @@ -10,7 +10,8 @@ class ParsedProtoBoolNode(ParsedProtoNode): class ProtoBool(ProtoNode): - def __init__(self, value: bool): + def __init__(self, parent: Optional[ProtoNode], value: bool): + super().__init__(parent) self.value = value def __bool__(self) -> bool: @@ -29,15 +30,21 @@ def normalize(self) -> "ProtoBool": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoBoolNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoBoolNode"]: if proto_source.startswith("true") and ( len(proto_source) == 4 or proto_source[4] not in ProtoFullIdentifier.ALL ): - return ParsedProtoBoolNode(ProtoBool(True), proto_source[4:].strip()) + return ParsedProtoBoolNode( + ProtoBool(parent, True), proto_source[4:].strip() + ) elif proto_source.startswith("false") and ( len(proto_source) == 5 or proto_source[5] not in ProtoFullIdentifier.ALL ): - return ParsedProtoBoolNode(ProtoBool(False), proto_source[5:].strip()) + return ParsedProtoBoolNode( + ProtoBool(parent, False), proto_source[5:].strip() + ) return None def serialize(self) -> str: diff --git a/src/proto_comment.py b/src/proto_comment.py index 8d726ed..d3d6db7 100644 --- a/src/proto_comment.py +++ b/src/proto_comment.py @@ -10,7 +10,8 @@ class ParsedProtoCommentNode(ParsedProtoNode): class ProtoComment(ProtoNode): - def __init__(self, value: str): + def __init__(self, parent: Optional[ProtoNode], value: str): + super().__init__(parent) self.value = value def __eq__(self, other) -> bool: @@ -26,7 +27,9 @@ def normalize(self) -> Optional["ProtoComment"]: return None @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoCommentNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoCommentNode"]: return None def serialize(self) -> str: @@ -43,7 +46,9 @@ def __str__(self) -> str: return f"" @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoSingleLineCommentNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoSingleLineCommentNode"]: if not proto_source.startswith("//"): return None @@ -52,7 +57,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoSingleLineCommentNode" if newline_pos == -1: newline_pos = len(proto_source) return ParsedProtoSingleLineCommentNode( - ProtoSingleLineComment(proto_source[:newline_pos]), + ProtoSingleLineComment(parent, proto_source[:newline_pos]), proto_source[newline_pos + 1 :], ) @@ -70,7 +75,9 @@ def __str__(self) -> str: return f"" @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoMultiLineCommentNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoMultiLineCommentNode"]: if not proto_source.startswith("/*"): return None @@ -79,7 +86,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoMultiLineCommentNode"] if close_comment_pos == -1: return None return ParsedProtoMultiLineCommentNode( - ProtoMultiLineComment(proto_source[:close_comment_pos]), + ProtoMultiLineComment(parent, proto_source[:close_comment_pos]), proto_source[close_comment_pos + 2 :], ) diff --git a/src/proto_constant.py b/src/proto_constant.py index e95fda6..10cb623 100644 --- a/src/proto_constant.py +++ b/src/proto_constant.py @@ -20,9 +20,12 @@ class ParsedProtoConstantNode(ParsedProtoNode): class ProtoConstant(ProtoNode): def __init__( self, + parent: Optional[ProtoNode], value: ProtoConstantTypes, ): + super().__init__(parent) self.value = value + self.value.parent = self def __eq__(self, other) -> bool: return self.value == other.value @@ -37,51 +40,56 @@ def normalize(self) -> "ProtoConstant": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoConstantNode"]: - match = ProtoBool.match(proto_source) + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoConstantNode"]: + match = ProtoBool.match(None, proto_source) if match is not None: + proto_constant = ProtoConstant(parent, match.node) return ParsedProtoConstantNode( - ProtoConstant(match.node), + proto_constant, match.remaining_source.strip(), ) sign = ProtoIntSign.POSITIVE if proto_source.startswith("+") or proto_source.startswith("-"): sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - proto_int_match = ProtoInt.match(proto_source[1:]) + proto_int_match = ProtoInt.match(None, proto_source[1:]) else: - proto_int_match = ProtoInt.match(proto_source) + proto_int_match = ProtoInt.match(None, proto_source) if proto_int_match is not None: + proto_constant = ProtoConstant(parent, proto_int_match.node) proto_int_match.node.sign = sign return ParsedProtoConstantNode( - ProtoConstant(proto_int_match.node), + proto_constant, proto_int_match.remaining_source.strip(), ) float_sign = ProtoFloatSign.POSITIVE if proto_source.startswith("+") or proto_source.startswith("-"): float_sign = next(x for x in ProtoFloatSign if x.value == proto_source[0]) - float_match = ProtoFloat.match(proto_source[1:]) + float_match = ProtoFloat.match(None, proto_source[1:]) else: - float_match = ProtoFloat.match(proto_source) + float_match = ProtoFloat.match(None, proto_source) if float_match is not None: + proto_constant = ProtoConstant(parent, float_match.node) float_match.node.sign = float_sign return ParsedProtoConstantNode( - ProtoConstant(float_match.node), + proto_constant, float_match.remaining_source.strip(), ) - identifier_match = ProtoFullIdentifier.match(proto_source) + identifier_match = ProtoFullIdentifier.match(None, proto_source) if identifier_match is not None: return ParsedProtoConstantNode( - ProtoConstant(identifier_match.node), + ProtoConstant(parent, identifier_match.node), identifier_match.remaining_source.strip(), ) - string_literal_match = ProtoStringLiteral.match(proto_source) + string_literal_match = ProtoStringLiteral.match(None, proto_source) if string_literal_match is not None: return ParsedProtoConstantNode( - ProtoConstant(string_literal_match.node), + ProtoConstant(parent, string_literal_match.node), string_literal_match.remaining_source.strip(), ) diff --git a/src/proto_enum.py b/src/proto_enum.py index e461efb..a5e1f47 100644 --- a/src/proto_enum.py +++ b/src/proto_enum.py @@ -22,13 +22,15 @@ def __str__(self) -> str: return f"<{self.__class__.__name__} name={self.name}, value={self.value}>" @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoEnumValueOptionNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoEnumValueOptionNode"]: test_source = "option " + proto_source.strip() + ";" - match = ProtoOption.match(test_source) + match = ProtoOption.match(None, test_source) if match is None: return None return ParsedProtoEnumValueOptionNode( - cls(match.node.name, match.node.value), + cls(parent, match.node.name, match.node.value), match.remaining_source.strip(), ) @@ -44,17 +46,23 @@ class ParsedProtoEnumValueNode(ParsedProtoNode): class ProtoEnumValue(ProtoNode): def __init__( self, + parent: Optional[ProtoNode], identifier: ProtoIdentifier, value: ProtoInt, options: Optional[list[ProtoEnumValueOption]] = None, ): + super().__init__(parent) self.identifier = identifier + self.identifier.parent = self self.value = value + self.value.parent = self if options is None: self.options = [] else: self.options = options + for option in self.options: + option.parent = self def __eq__(self, other) -> bool: return ( @@ -74,14 +82,17 @@ def __hash__(self) -> int: def normalize(self) -> "ProtoEnumValue": return ProtoEnumValue( + self.parent, self.identifier, self.value, sorted(self.options, key=lambda o: str(o.name)), ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoEnumValueNode"]: - match = ProtoIdentifier.match(proto_source) + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoEnumValueNode"]: + match = ProtoIdentifier.match(None, proto_source) if match is None: raise ValueError(f"Proto has invalid enum value name: {proto_source}") @@ -98,9 +109,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoEnumValueNode"]: sign = ProtoIntSign.POSITIVE if proto_source.startswith("-"): sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - int_match = ProtoInt.match(proto_source[1:]) + int_match = ProtoInt.match(None, proto_source[1:]) else: - int_match = ProtoInt.match(proto_source) + int_match = ProtoInt.match(None, proto_source) if int_match is None: raise ValueError( f"Proto has invalid enum value, expecting int: {proto_source}" @@ -120,7 +131,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoEnumValueNode"]: ) for option_part in proto_source[:end_bracket].strip().split(","): proto_enum_value_option_match = ProtoEnumValueOption.match( - option_part.strip() + None, option_part.strip() ) if proto_enum_value_option_match is None: raise ValueError( @@ -130,7 +141,8 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoEnumValueNode"]: proto_source = proto_source[end_bracket + 1 :].strip() return ParsedProtoEnumValueNode( - ProtoEnumValue(enum_value_name, enum_value, options), proto_source.strip() + ProtoEnumValue(parent, enum_value_name, enum_value, options), + proto_source.strip(), ) def serialize(self) -> str: @@ -205,9 +217,15 @@ def diff_sets( class ProtoEnum(ProtoNode): - def __init__(self, name: ProtoIdentifier, nodes: list[ProtoNode]): + def __init__( + self, parent: Optional[ProtoNode], name: ProtoIdentifier, nodes: list[ProtoNode] + ): + super().__init__(parent) self.name = name + self.name.parent = self self.nodes = nodes + for option in self.options: + option.parent = self def __eq__(self, other: object) -> bool: return ( @@ -227,6 +245,7 @@ def normalize(self) -> "ProtoEnum": lambda n1: not isinstance(n1, ProtoComment), self.nodes ) return ProtoEnum( + self.parent, self.name, sorted(non_comment_nodes, key=lambda n: str(n.normalize())), ) @@ -242,7 +261,7 @@ def parse_partial_content(partial_enum_content: str) -> ParsedProtoNode: ] for node_type in supported_types: try: - match_result = node_type.match(partial_enum_content) + match_result = node_type.match(None, partial_enum_content) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial enum content:\n{partial_enum_content}" @@ -254,12 +273,14 @@ def parse_partial_content(partial_enum_content: str) -> ParsedProtoNode: ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("enum "): return None proto_source = proto_source[5:] - match = ProtoIdentifier.match(proto_source) + match = ProtoIdentifier.match(None, proto_source) if match is None: raise ValueError(f"Proto has invalid enum name: {proto_source}") @@ -287,7 +308,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: parsed_tree.append(match_result.node) proto_source = match_result.remaining_source.strip() - return ParsedProtoNode(ProtoEnum(enum_name, nodes=parsed_tree), proto_source) + return ParsedProtoNode( + ProtoEnum(parent, enum_name, nodes=parsed_tree), proto_source + ) @property def options(self) -> list[ProtoOption]: diff --git a/src/proto_extend.py b/src/proto_extend.py index cb563a3..8585fdb 100644 --- a/src/proto_extend.py +++ b/src/proto_extend.py @@ -11,9 +11,18 @@ class ProtoExtend(ProtoNode): - def __init__(self, name: ProtoEnumOrMessageIdentifier, nodes: list[ProtoNode]): + def __init__( + self, + parent: Optional[ProtoNode], + name: ProtoEnumOrMessageIdentifier, + nodes: list[ProtoNode], + ): + super().__init__(parent) self.name = name + self.name.parent = self self.nodes = nodes + for node in self.nodes: + node.parent = self def __eq__(self, other) -> bool: return self.name == other.name and self.nodes == other.nodes @@ -29,6 +38,7 @@ def normalize(self) -> "ProtoExtend": lambda n: not isinstance(n, ProtoComment), self.nodes ) return ProtoExtend( + self.parent, name=self.name, nodes=sorted(non_comment_nodes, key=lambda f: str(f)), ) @@ -42,7 +52,7 @@ def parse_partial_content(partial_content: str) -> ParsedProtoNode: ] for node_type in supported_types: try: - match_result = node_type.match(partial_content) + match_result = node_type.match(None, partial_content) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial extend content:\n{partial_content}" @@ -52,12 +62,14 @@ def parse_partial_content(partial_content: str) -> ParsedProtoNode: raise ValueError(f"Could not parse partial extend content:\n{partial_content}") @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("extend "): return None proto_source = proto_source[7:] - match = ProtoEnumOrMessageIdentifier.match(proto_source) + match = ProtoEnumOrMessageIdentifier.match(None, proto_source) if match is None: raise ValueError(f"Proto extend has invalid message name: {proto_source}") @@ -85,7 +97,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: parsed_tree.append(match_result.node) proto_source = match_result.remaining_source.strip() - return ParsedProtoNode(ProtoExtend(name, nodes=parsed_tree), proto_source) + return ParsedProtoNode( + ProtoExtend(parent, name, nodes=parsed_tree), proto_source + ) def serialize(self) -> str: serialize_parts = ( diff --git a/src/proto_extensions.py b/src/proto_extensions.py index e4fb2f3..c8cf998 100644 --- a/src/proto_extensions.py +++ b/src/proto_extensions.py @@ -9,9 +9,13 @@ class ProtoExtensions(ProtoNode): def __init__( self, + parent: Optional[ProtoNode], ranges: list[ProtoRange], ): + super().__init__(parent) self.ranges = ranges + for range in self.ranges: + range.parent = self def __eq__(self, other) -> bool: return self.ranges == other.ranges @@ -25,11 +29,14 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoExtensions": # sort the ranges. return ProtoExtensions( + self.parent, sorted(self.ranges, key=lambda r: int(r.min)), ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("extensions "): return None @@ -46,13 +53,13 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: ) if proto_source[0] == ",": proto_source = proto_source[1:].strip() - match = ProtoRange.match(proto_source) + match = ProtoRange.match(None, proto_source) if match is None: return None ranges.append(match.node) proto_source = match.remaining_source - return ParsedProtoNode(ProtoExtensions(ranges), proto_source.strip()) + return ParsedProtoNode(ProtoExtensions(parent, ranges), proto_source.strip()) def serialize(self) -> str: serialize_parts = ["extensions", ", ".join(r.serialize() for r in self.ranges)] diff --git a/src/proto_float.py b/src/proto_float.py index a139b11..d86b22d 100644 --- a/src/proto_float.py +++ b/src/proto_float.py @@ -22,7 +22,8 @@ class ProtoFloat(ProtoNode): DECIMAL = DIGITS | set(".") EXPONENTIAL = set("eE") - def __init__(self, value: float, sign: ProtoFloatSign): + def __init__(self, parent: Optional[ProtoNode], value: float, sign: ProtoFloatSign): + super().__init__(parent) self.value = value self.sign = sign @@ -43,7 +44,9 @@ def normalize(self) -> "ProtoFloat": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoFloatNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoFloatNode"]: if proto_source.startswith("inf"): proto_source = proto_source[3:] if proto_source and proto_source[0] in ProtoIdentifier.ALL: @@ -51,7 +54,8 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoFloatNode"]: f"Proto has invalid float, invalid post-inf character: {proto_source}" ) return ParsedProtoFloatNode( - ProtoFloat(float("inf"), ProtoFloatSign.POSITIVE), proto_source.strip() + ProtoFloat(parent, float("inf"), ProtoFloatSign.POSITIVE), + proto_source.strip(), ) if proto_source.startswith("nan"): @@ -61,7 +65,8 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoFloatNode"]: f"Proto has invalid float, invalid post-nan character: {proto_source}" ) return ParsedProtoFloatNode( - ProtoFloat(float("nan"), ProtoFloatSign.POSITIVE), proto_source.strip() + ProtoFloat(parent, float("nan"), ProtoFloatSign.POSITIVE), + proto_source.strip(), ) if not proto_source[0] in ProtoFloat.DECIMAL: @@ -113,7 +118,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoFloatNode"]: proto_source = proto_source[i + 1 :] return ParsedProtoFloatNode( - ProtoFloat(base, ProtoFloatSign.POSITIVE), proto_source.strip() + ProtoFloat(parent, base, ProtoFloatSign.POSITIVE), proto_source.strip() ) def serialize(self) -> str: diff --git a/src/proto_identifier.py b/src/proto_identifier.py index ee5368b..114c684 100644 --- a/src/proto_identifier.py +++ b/src/proto_identifier.py @@ -23,7 +23,8 @@ class ProtoIdentifier(ProtoNode): STARTING = ALPHABETICAL | set("_") ALL = STARTING | set("0123456789_") - def __init__(self, identifier: str): + def __init__(self, parent: Optional[ProtoNode], identifier: str): + super().__init__(parent) self.identifier = identifier def __eq__(self, other) -> bool: @@ -42,16 +43,18 @@ def normalize(self) -> "ProtoIdentifier": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoIdentifierNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoIdentifierNode"]: if proto_source[0] not in ProtoIdentifier.STARTING: return None for i, c in enumerate(proto_source): if c not in ProtoIdentifier.ALL: return ParsedProtoIdentifierNode( - ProtoIdentifier(proto_source[:i]), proto_source[i:] + ProtoIdentifier(parent, proto_source[:i]), proto_source[i:] ) - return ParsedProtoIdentifierNode(ProtoIdentifier(proto_source), "") + return ParsedProtoIdentifierNode(ProtoIdentifier(parent, proto_source), "") def serialize(self) -> str: return self.identifier @@ -62,7 +65,9 @@ class ProtoFullIdentifier(ProtoIdentifier): ALL = ProtoIdentifier.ALL | set(".") @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoFullIdentifierNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoFullIdentifierNode"]: if proto_source[0] not in ProtoFullIdentifier.STARTING: return None @@ -77,7 +82,8 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoFullIdentifierNode"]: ) identifier_parts.append(proto_source[last_part_start:i]) return ParsedProtoFullIdentifierNode( - ProtoFullIdentifier(".".join(identifier_parts)), proto_source[i:] + ProtoFullIdentifier(parent, ".".join(identifier_parts)), + proto_source[i:], ) elif c == ".": identifier_parts.append(proto_source[last_part_start:i]) @@ -90,7 +96,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoFullIdentifierNode"]: ) identifier_parts.append(proto_source[last_part_start:]) return ParsedProtoFullIdentifierNode( - ProtoFullIdentifier(".".join(identifier_parts)), "" + ProtoFullIdentifier(parent, ".".join(identifier_parts)), "" ) @@ -100,17 +106,17 @@ class ProtoEnumOrMessageIdentifier(ProtoIdentifier): @classmethod def match( - cls, proto_source: str + cls, parent: Optional[ProtoNode], proto_source: str ) -> Optional["ParsedProtoEnumOrMessageIdentifierNode"]: if proto_source[0] == ".": matched_source = proto_source[1:] else: matched_source = proto_source - identifier_match = ProtoFullIdentifier.match(matched_source) + identifier_match = ProtoFullIdentifier.match(parent, matched_source) if identifier_match is not None: match = ParsedProtoEnumOrMessageIdentifierNode( - ProtoEnumOrMessageIdentifier(identifier_match.node.identifier), + ProtoEnumOrMessageIdentifier(parent, identifier_match.node.identifier), identifier_match.remaining_source, ) diff --git a/src/proto_import.py b/src/proto_import.py index dc67721..fdd0ba9 100644 --- a/src/proto_import.py +++ b/src/proto_import.py @@ -6,9 +6,15 @@ class ProtoImport(ProtoNode): def __init__( - self, path: ProtoStringLiteral, weak: bool = False, public: bool = False + self, + parent: Optional[ProtoNode], + path: ProtoStringLiteral, + weak: bool = False, + public: bool = False, ): + super().__init__(parent) self.path = path + self.path.parent = self self.weak = weak self.public = public @@ -36,7 +42,9 @@ def normalize(self) -> "ProtoImport": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("import "): return None proto_source = proto_source[7:] @@ -53,7 +61,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: public = True proto_source = proto_source[7:] - match = ProtoStringLiteral.match(proto_source) + match = ProtoStringLiteral.match(None, proto_source) if match is None: raise ValueError(f"Proto has invalid import syntax: {proto_source}") @@ -63,7 +71,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: ) return ParsedProtoNode( - ProtoImport(match.node, weak=weak, public=public), + ProtoImport(parent, match.node, weak=weak, public=public), match.remaining_source[1:].strip(), ) diff --git a/src/proto_int.py b/src/proto_int.py index 67aa7ba..480817f 100644 --- a/src/proto_int.py +++ b/src/proto_int.py @@ -20,7 +20,8 @@ class ProtoInt(ProtoNode): DECIMAL = OCTAL | set("89") HEX = DECIMAL | set("ABCDEFabcdef") - def __init__(self, value: int, sign: ProtoIntSign): + def __init__(self, parent: Optional[ProtoNode], value: int, sign: ProtoIntSign): + super().__init__(parent) self.value = value self.sign = sign @@ -43,7 +44,9 @@ def normalize(self) -> "ProtoInt": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoIntNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoIntNode"]: if proto_source[0] not in ProtoInt.DECIMAL: return None @@ -64,7 +67,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoIntNode"]: except ValueError: raise ValueError(f"Proto has invalid hex: {proto_source}") return ParsedProtoIntNode( - ProtoInt(value, ProtoIntSign.POSITIVE), + ProtoInt(parent, value, ProtoIntSign.POSITIVE), proto_source[i + 1 :].strip(), ) else: @@ -80,7 +83,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoIntNode"]: except ValueError: raise ValueError(f"Proto has invalid octal: {proto_source}") return ParsedProtoIntNode( - ProtoInt(value, ProtoIntSign.POSITIVE), + ProtoInt(parent, value, ProtoIntSign.POSITIVE), proto_source[i + 1 :].strip(), ) else: @@ -97,7 +100,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoIntNode"]: return None return ParsedProtoIntNode( - ProtoInt(value, ProtoIntSign.POSITIVE), + ProtoInt(parent, value, ProtoIntSign.POSITIVE), proto_source[i + 1 :].strip(), ) diff --git a/src/proto_message.py b/src/proto_message.py index 191e127..bf82578 100644 --- a/src/proto_message.py +++ b/src/proto_message.py @@ -11,11 +11,7 @@ from src.proto_enum import ProtoEnum from src.proto_extend import ProtoExtend from src.proto_extensions import ProtoExtensions -from src.proto_identifier import ( - ProtoEnumOrMessageIdentifier, - ProtoFullIdentifier, - ProtoIdentifier, -) +from src.proto_identifier import ProtoEnumOrMessageIdentifier, ProtoIdentifier from src.proto_int import ProtoInt from src.proto_message_field import ( ParsedProtoMessageFieldNode, @@ -44,9 +40,18 @@ class ParsedProtoOneOfNode(ParsedProtoNode): class ProtoOneOf(ProtoNode): - def __init__(self, name: ProtoIdentifier, nodes: Sequence[ProtoOneOfNodeTypes]): + def __init__( + self, + parent: Optional[ProtoNode], + name: ProtoIdentifier, + nodes: Sequence[ProtoOneOfNodeTypes], + ): + super().__init__(parent) self.name = name + self.name.parent = self self.nodes = nodes + for node in self.nodes: + node.parent = self def __eq__(self, other) -> bool: return self.name == other.name and self.nodes == other.nodes @@ -82,7 +87,8 @@ def normalize(self) -> "ProtoOneOf": ) + sorted(fields, key=lambda f: int(f.number)) return ProtoOneOf( - self.name, + parent=self.parent, + name=self.name, nodes=sorted_nodes_for_normalizing, ) @@ -96,7 +102,7 @@ def parse_partial_content(partial_oneof_content: str) -> ProtoParsedOneOfNodeTyp ] for node_type in supported_types: try: - match_result = node_type.match(partial_oneof_content) + match_result = node_type.match(None, partial_oneof_content) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial oneof content:\n{partial_oneof_content}" @@ -108,13 +114,15 @@ def parse_partial_content(partial_oneof_content: str) -> ProtoParsedOneOfNodeTyp ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoOneOfNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoOneOfNode"]: if not proto_source.startswith("oneof "): return None proto_source = proto_source[6:].strip() - match = ProtoIdentifier.match(proto_source) + match = ProtoIdentifier.match(None, proto_source) if match is None: raise ValueError( f"Proto has invalid syntax, expecting identifier for oneof: {proto_source}" @@ -145,7 +153,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoOneOfNode"]: proto_source = match_result.remaining_source.strip() return ParsedProtoOneOfNode( - ProtoOneOf(oneof_name, nodes=parsed_tree), proto_source + ProtoOneOf(parent, oneof_name, nodes=parsed_tree), proto_source ) @property @@ -182,6 +190,7 @@ class ProtoMapKeyTypesEnum(Enum): class ProtoMap(ProtoNode): def __init__( self, + parent: Optional[ProtoNode], key_type: ProtoMapKeyTypesEnum, value_type: ProtoMapValueTypesEnum, name: ProtoIdentifier, @@ -189,15 +198,22 @@ def __init__( enum_or_message_type_name: Optional[ProtoEnumOrMessageIdentifier] = None, options: Optional[list[ProtoMessageFieldOption]] = None, ): + super().__init__(parent) self.key_type = key_type self.value_type = value_type self.name = name + self.name.parent = self self.number = number + self.number.parent = self self.enum_or_message_type_name = enum_or_message_type_name + if self.enum_or_message_type_name is not None: + self.enum_or_message_type_name.parent = self if options is None: options = [] self.options = options + for option in self.options: + option.parent = self def __eq__(self, other) -> bool: return ( @@ -217,6 +233,7 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoMap": return ProtoMap( + parent=self.parent, key_type=self.key_type, value_type=self.value_type, name=self.name, @@ -226,7 +243,9 @@ def normalize(self) -> "ProtoMap": ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if proto_source.startswith("map "): proto_source = proto_source[4:].strip() elif proto_source.startswith("map<"): @@ -263,7 +282,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: enum_or_message_type_name = None if value_type is None: # See if this is an enum or message type. - match = ProtoEnumOrMessageIdentifier.match(proto_source) + match = ProtoEnumOrMessageIdentifier.match(None, proto_source) if match is None: return None value_type = ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE @@ -275,7 +294,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: proto_source = proto_source[1:].strip() # Try to match the map field's name. - identifier_match = ProtoIdentifier.match(proto_source) + identifier_match = ProtoIdentifier.match(None, proto_source) if identifier_match is None: return None name = identifier_match.node @@ -286,7 +305,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: proto_source = proto_source[1:].strip() # Try to match the map field number. - int_match = ProtoInt.match(proto_source) + int_match = ProtoInt.match(None, proto_source) if int_match is None: return None number = int_match.node @@ -303,7 +322,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: ) for option_part in proto_source[:end_bracket].strip().split(","): message_field_option_match = ProtoMessageFieldOption.match( - option_part.strip() + None, option_part.strip() ) if message_field_option_match is None: raise ValueError( @@ -319,7 +338,13 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: return ParsedProtoNode( ProtoMap( - key_type, value_type, name, number, enum_or_message_type_name, options + parent, + key_type, + value_type, + name, + number, + enum_or_message_type_name, + options, ), proto_source[1:].strip(), ) @@ -354,11 +379,85 @@ def serialize(self) -> str: return " ".join(serialized_parts) + ";" + @staticmethod + def diff( + parent: Optional[ProtoNode], left: "ProtoMap", right: "ProtoMap" + ) -> list["ProtoNodeDiff"]: + if left is None and right is not None: + return [ProtoMapAdded(parent, right)] + elif left is not None and right is None: + return [ProtoMapRemoved(parent, left)] + elif left is None and right is None: + return [] + elif left.name != right.name: + return [] + elif left == right: + return [] + diffs: list["ProtoNodeDiff"] = [] + return diffs + + @staticmethod + def diff_sets( + parent: Optional[ProtoNode], left: list["ProtoMap"], right: list["ProtoMap"] + ) -> Sequence["ProtoNodeDiff"]: + diffs: list[ProtoNodeDiff] = [] + left_names = set(o.name.identifier for o in left) + right_names = set(o.name.identifier for o in right) + for name in left_names - right_names: + diffs.append( + ProtoMapAdded( + parent, next(i for i in left if i.name.identifier == name) + ) + ) + for name in right_names - left_names: + diffs.append( + ProtoMapRemoved( + parent, next(i for i in right if i.name.identifier == name) + ) + ) + for name in left_names & right_names: + left_enum = next(i for i in left if i.name.identifier == name) + right_enum = next(i for i in right if i.name.identifier == name) + diffs.extend(ProtoMap.diff(parent, left_enum, right_enum)) + + return diffs + + +class ProtoMapDiff(ProtoNodeDiff): + def __init__(self, parent: Optional[ProtoNode], map: ProtoMap): + self.parent = parent + self.map = map + + def __eq__(self, other: object) -> bool: + return isinstance(other, ProtoMapDiff) and self.map == other.map + + def __str__(self) -> str: + return f"<{self.__class__.__name__} parent={self.parent} map={self.map}>" + + +class ProtoMapAdded(ProtoMapDiff): + def __eq__(self, other: object) -> bool: + return super().__eq__(other) and isinstance(other, ProtoMapAdded) + + +class ProtoMapRemoved(ProtoMapDiff): + def __eq__(self, other: object) -> bool: + return super().__eq__(other) and isinstance(other, ProtoMapRemoved) + class ProtoMessage(ProtoNode): - def __init__(self, name: ProtoIdentifier, nodes: Sequence[ProtoNode]): + def __init__( + self, + parent: Optional[ProtoNode], + name: ProtoIdentifier, + nodes: Sequence[ProtoNode], + ): + super().__init__(parent) self.name = name + self.name.parent = self self.nodes = nodes + for node in self.nodes: + node.parent = self def __eq__(self, other) -> bool: return self.name == other.name and self.nodes == other.nodes @@ -408,6 +507,7 @@ def normalize(self) -> "ProtoMessage": ) return ProtoMessage( + parent=self.parent, name=self.name, nodes=sorted_nodes_for_normalizing, ) @@ -429,7 +529,7 @@ def parse_partial_content(partial_message_content: str) -> ParsedProtoNode: ] for node_type in supported_types: try: - match_result = node_type.match(partial_message_content) + match_result = node_type.match(None, partial_message_content) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial message content:\n{partial_message_content}" @@ -441,12 +541,14 @@ def parse_partial_content(partial_message_content: str) -> ParsedProtoNode: ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("message "): return None proto_source = proto_source[8:] - match = ProtoIdentifier.match(proto_source) + match = ProtoIdentifier.match(None, proto_source) if match is None: raise ValueError(f"Proto has invalid message name: {proto_source}") @@ -474,12 +576,18 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: parsed_tree.append(match_result.node) proto_source = match_result.remaining_source.strip() - return ParsedProtoNode(ProtoMessage(enum_name, nodes=parsed_tree), proto_source) + return ParsedProtoNode( + ProtoMessage(parent, enum_name, nodes=parsed_tree), proto_source + ) @property def options(self) -> list[ProtoOption]: return [node for node in self.nodes if isinstance(node, ProtoOption)] + @property + def maps(self) -> list[ProtoMap]: + return [node for node in self.nodes if isinstance(node, ProtoMap)] + def serialize(self) -> str: serialize_parts = ( [f"message {self.name.serialize()} {{"] @@ -500,9 +608,11 @@ def diff(left: "ProtoMessage", right: "ProtoMessage") -> Sequence["ProtoNodeDiff return [] elif left == right: return [] - diffs = [] + diffs: list[ProtoNodeDiff] = [] diffs.extend(ProtoOption.diff_sets(left.options, right.options)) - # diffs.extend(ProtoMessageValue.diff_sets(left, left.values, right.values)) + # diffs.extend(ProtoOneOf.diff_sets(left, left.oneofs, right.oneofs)) + diffs.extend(ProtoMap.diff_sets(left, left.maps, right.maps)) + # diffs.extend(ProtoMessageField.diff_sets(left, left.message_fields, right.message_fields)) return diffs @staticmethod diff --git a/src/proto_message_field.py b/src/proto_message_field.py index 97f75ce..390cef8 100644 --- a/src/proto_message_field.py +++ b/src/proto_message_field.py @@ -14,10 +14,13 @@ class ParsedProtoMessageFieldOptionNode(ParsedProtoEnumValueOptionNode): class ProtoMessageFieldOption(ProtoEnumValueOption): @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoMessageFieldOptionNode"]: - match = super().match(proto_source) + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoMessageFieldOptionNode"]: + match = super().match(parent, proto_source) if match is None: return None + return ParsedProtoMessageFieldOptionNode( match.node, match.remaining_source.strip(), @@ -51,6 +54,7 @@ class ParsedProtoMessageFieldNode(ParsedProtoNode): class ProtoMessageField(ProtoNode): def __init__( self, + parent: Optional[ProtoNode], type: ProtoMessageFieldTypesEnum, name: ProtoIdentifier, number: ProtoInt, @@ -59,9 +63,12 @@ def __init__( enum_or_message_type_name: Optional[ProtoEnumOrMessageIdentifier] = None, options: Optional[list[ProtoMessageFieldOption]] = None, ): + super().__init__(parent) self.type = type self.name = name + self.name.parent = self self.number = number + self.number.parent = self # Only allow one of repeated or optional to be true. if repeated and optional: @@ -72,10 +79,14 @@ def __init__( self.repeated = repeated self.optional = optional self.enum_or_message_type_name = enum_or_message_type_name + if self.enum_or_message_type_name is not None: + self.enum_or_message_type_name.parent = self if options is None: options = [] self.options = options + for option in self.options: + option.parent = self def __eq__(self, other) -> bool: return ( @@ -96,6 +107,7 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoMessageField": return ProtoMessageField( + parent=self.parent, type=self.type, name=self.name, number=self.number, @@ -106,7 +118,9 @@ def normalize(self) -> "ProtoMessageField": ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoMessageFieldNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoMessageFieldNode"]: # First, try to match the optional repeated. repeated = False if proto_source.startswith("repeated "): @@ -136,7 +150,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoMessageFieldNode"]: enum_or_message_type_name = None if matched_type is None: # See if this is an enum or message type. - match = ProtoEnumOrMessageIdentifier.match(proto_source) + match = ProtoEnumOrMessageIdentifier.match(None, proto_source) if match is None: return None matched_type = ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE @@ -144,7 +158,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoMessageFieldNode"]: proto_source = match.remaining_source.strip() # Match the field name. - identifier_match = ProtoIdentifier.match(proto_source) + identifier_match = ProtoIdentifier.match(None, proto_source) if identifier_match is None: return None name = identifier_match.node @@ -155,7 +169,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoMessageFieldNode"]: proto_source = proto_source[2:].strip() # Match the field number. - int_match = ProtoInt.match(proto_source) + int_match = ProtoInt.match(None, proto_source) if int_match is None: return None number = int_match.node @@ -171,7 +185,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoMessageFieldNode"]: ) for option_part in proto_source[:end_bracket].strip().split(","): message_field_option_match = ProtoMessageFieldOption.match( - option_part.strip() + None, option_part.strip() ) if message_field_option_match is None: raise ValueError( @@ -187,6 +201,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoMessageFieldNode"]: return ParsedProtoMessageFieldNode( ProtoMessageField( + parent, matched_type, name, number, diff --git a/src/proto_node.py b/src/proto_node.py index 37c36e8..8d10bb4 100644 --- a/src/proto_node.py +++ b/src/proto_node.py @@ -5,9 +5,14 @@ class ProtoNode(abc.ABC): @classmethod @abc.abstractmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional["ProtoNode"], proto_source: str + ) -> Optional["ParsedProtoNode"]: raise NotImplementedError + def __init__(self, parent: Optional["ProtoNode"]): + self.parent = parent + @abc.abstractmethod def serialize(self) -> str: raise NotImplementedError diff --git a/src/proto_option.py b/src/proto_option.py index a780351..312dcac 100644 --- a/src/proto_option.py +++ b/src/proto_option.py @@ -15,9 +15,14 @@ class ParsedProtoOptionNode(ParsedProtoNode): class ProtoOption(ProtoNode): - def __init__(self, name: ProtoIdentifier, value: ProtoConstant): + def __init__( + self, parent: Optional[ProtoNode], name: ProtoIdentifier, value: ProtoConstant + ): + super().__init__(parent) self.name = name + self.name.parent = self self.value = value + self.value.parent = self def __eq__(self, other) -> bool: return self.name == other.name and self.value == other.value @@ -35,7 +40,9 @@ def normalize(self) -> "ProtoOption": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoOptionNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoOptionNode"]: if not proto_source.startswith("option "): return None proto_source = proto_source[7:] @@ -43,10 +50,10 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoOptionNode"]: name_parts = [] if proto_source.startswith("("): proto_source = proto_source[1:] - match = ProtoFullIdentifier.match(proto_source) + match = ProtoFullIdentifier.match(None, proto_source) if match is None or not match.remaining_source.startswith(")"): # This might be a regular identifier. - identifier_match = ProtoIdentifier.match(proto_source) + identifier_match = ProtoIdentifier.match(None, proto_source) if ( not identifier_match or not identifier_match.remaining_source.startswith(")") @@ -55,17 +62,19 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoOptionNode"]: f"Proto has invalid option when expecting ): {proto_source}" ) name_parts.append( - ProtoIdentifier(f"({identifier_match.node.identifier})") + ProtoIdentifier(None, f"({identifier_match.node.identifier})") ) proto_source = identifier_match.remaining_source[1:] else: - name_parts.append(ProtoFullIdentifier(f"({match.node.identifier})")) + name_parts.append( + ProtoFullIdentifier(None, f"({match.node.identifier})") + ) proto_source = match.remaining_source[1:] while True: - identifier_match = ProtoEnumOrMessageIdentifier.match(proto_source) + identifier_match = ProtoEnumOrMessageIdentifier.match(None, proto_source) if identifier_match is None: - identifier_match = ProtoIdentifier.match(proto_source) + identifier_match = ProtoIdentifier.match(None, proto_source) if identifier_match is None: break name_parts.append(identifier_match.node) @@ -77,7 +86,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoOptionNode"]: f"Proto has invalid option when expecting =: {proto_source}" ) proto_source = proto_source[1:].strip() - constant_match = ProtoConstant.match(proto_source) + constant_match = ProtoConstant.match(None, proto_source) if constant_match is None: raise ValueError( f"Proto has invalid option when expecting constant: {proto_source}" @@ -91,15 +100,22 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoOptionNode"]: identifier: ProtoFullIdentifier | ProtoIdentifier if len(name_parts) > 1: - identifier = ProtoFullIdentifier("".join(x.identifier for x in name_parts)) + identifier = ProtoFullIdentifier( + None, "".join(x.identifier for x in name_parts) + ) else: - identifier = ProtoIdentifier(name_parts[0].identifier) + identifier = ProtoIdentifier(None, name_parts[0].identifier) + + proto_option = ProtoOption( + parent, + name=identifier, + value=constant_match.node, + ) + identifier.parent = proto_option + constant_match.node.parent = proto_option return ParsedProtoOptionNode( - ProtoOption( - name=identifier, - value=constant_match.node, - ), + proto_option, proto_source[1:], ) diff --git a/src/proto_package.py b/src/proto_package.py index 7559cd6..d6d714a 100644 --- a/src/proto_package.py +++ b/src/proto_package.py @@ -4,7 +4,8 @@ class ProtoPackage(ProtoNode): - def __init__(self, package: str): + def __init__(self, parent: Optional[ProtoNode], package: str): + super().__init__(parent) self.package = package def __eq__(self, other) -> bool: @@ -20,7 +21,9 @@ def normalize(self) -> "ProtoPackage": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("package"): return None @@ -44,7 +47,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: if package.startswith(".") or package.endswith("."): raise ValueError(f"Proto has invalid package: {package}") - return ParsedProtoNode(ProtoPackage(package), proto_source.strip()) + return ParsedProtoNode(ProtoPackage(parent, package), proto_source.strip()) def serialize(self) -> str: return f"package {self.package};" diff --git a/src/proto_range.py b/src/proto_range.py index 4f716c3..b55b279 100644 --- a/src/proto_range.py +++ b/src/proto_range.py @@ -15,7 +15,13 @@ class ProtoRangeEnum(Enum): class ProtoRange(ProtoNode): - def __init__(self, min: ProtoInt, max: Optional[ProtoInt | ProtoRangeEnum] = None): + def __init__( + self, + parent: Optional[ProtoNode], + min: ProtoInt, + max: Optional[ProtoInt | ProtoRangeEnum] = None, + ): + super().__init__(parent) self.min = min if ( @@ -40,13 +46,15 @@ def normalize(self) -> "ProtoRange": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoRangeNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoRangeNode"]: sign = ProtoIntSign.POSITIVE if proto_source.startswith("-") and proto_source != "-": sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - match = ProtoInt.match(proto_source[1:]) + match = ProtoInt.match(None, proto_source[1:]) else: - match = ProtoInt.match(proto_source) + match = ProtoInt.match(None, proto_source) if match is None: return None @@ -58,17 +66,19 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoRangeNode"]: if proto_source.startswith("to "): proto_source = proto_source[3:] if proto_source.startswith("max"): + proto_range = ProtoRange(parent, min, ProtoRangeEnum.MAX) + min.parent = proto_range return ParsedProtoRangeNode( - ProtoRange(min, ProtoRangeEnum.MAX), + proto_range, proto_source[3:].strip(), ) else: sign = ProtoIntSign.POSITIVE if proto_source.startswith("-"): sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - match = ProtoInt.match(proto_source[1:]) + match = ProtoInt.match(None, proto_source[1:]) else: - match = ProtoInt.match(proto_source) + match = ProtoInt.match(None, proto_source) if match is None: raise ValueError( f"Proto source has invalid range, expecting int for max: {proto_source}" @@ -77,7 +87,11 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoRangeNode"]: max = match.node proto_source = match.remaining_source - return ParsedProtoRangeNode(ProtoRange(min, max), proto_source.strip()) + proto_range = ProtoRange(parent, min, max) + min.parent = proto_range + if isinstance(max, ProtoNode): + max.parent = proto_range + return ParsedProtoRangeNode(proto_range, proto_source.strip()) def serialize(self) -> str: if self.max is not None: diff --git a/src/proto_reserved.py b/src/proto_reserved.py index 9a9c40f..06b146b 100644 --- a/src/proto_reserved.py +++ b/src/proto_reserved.py @@ -14,12 +14,14 @@ class ProtoReservedFieldQuoteEnum(Enum): class ProtoReserved(ProtoNode): def __init__( self, + parent: Optional[ProtoNode], ranges: Optional[list[ProtoRange]] = None, fields: Optional[list[ProtoIdentifier]] = None, quote_type: Optional[ ProtoReservedFieldQuoteEnum ] = ProtoReservedFieldQuoteEnum.DOUBLE, ): + super().__init__(parent) if (not ranges and not fields) or (ranges and fields): raise ValueError( "Exactly one of ranges or fields must be set in a ProtoReserved" @@ -30,11 +32,17 @@ def __init__( if quote_type is None: raise ValueError("Quote type must be specified when reserving fields") + self.ranges = ranges + for range in self.ranges: + range.parent = self + if fields is None: fields = [] - self.ranges = ranges self.fields = fields + for field in self.fields: + field.parent = self + self.quote_type = quote_type def __eq__(self, other) -> bool: @@ -49,9 +57,10 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoReserved": # sort the ranges. return ProtoReserved( - sorted(self.ranges, key=lambda r: int(r.min)), - sorted(self.fields, key=lambda f: str(f)), - self.quote_type, + parent=self.parent, + ranges=sorted(self.ranges, key=lambda r: int(r.min)), + fields=sorted(self.fields, key=lambda f: str(f)), + quote_type=self.quote_type, ) @property @@ -62,7 +71,9 @@ def min(self) -> str | int: return str(min(self.fields, key=lambda f: str(f))) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("reserved "): return None @@ -81,7 +92,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: ) if proto_source[0] == ",": proto_source = proto_source[1:].strip() - range_match = ProtoRange.match(proto_source) + range_match = ProtoRange.match(None, proto_source) if range_match is not None: ranges.append(range_match.node) proto_source = range_match.remaining_source @@ -98,7 +109,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: ) quote_type = quote_types[0] proto_source = proto_source[1:] - match = ProtoIdentifier.match(proto_source) + match = ProtoIdentifier.match(None, proto_source) if match is None: raise ValueError( f"Proto source has invalid reserved syntax, expecting field identifier: {proto_source}" @@ -113,7 +124,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: proto_source = proto_source[1:].strip() return ParsedProtoNode( - ProtoReserved(ranges, fields, quote_type), proto_source.strip() + ProtoReserved(parent, ranges, fields, quote_type), proto_source.strip() ) def serialize(self) -> str: diff --git a/src/proto_service.py b/src/proto_service.py index 76ec889..8ca62d4 100644 --- a/src/proto_service.py +++ b/src/proto_service.py @@ -13,6 +13,7 @@ class ProtoServiceRPC(ProtoNode): def __init__( self, + parent: Optional[ProtoNode], name: ProtoIdentifier, request_type: ProtoEnumOrMessageIdentifier, response_type: ProtoEnumOrMessageIdentifier, @@ -20,15 +21,21 @@ def __init__( response_stream: bool = False, options: Optional[list[ProtoOption]] = None, ): + super().__init__(parent) self.name = name + self.name.parent = self self.request_type = request_type + self.request_type.parent = self self.response_type = response_type + self.response_type.parent = self self.request_stream = request_stream self.response_stream = response_stream if options is None: options = [] self.options = options + for option in self.options: + option.parent = self def __eq__(self, other) -> bool: return ( @@ -48,6 +55,7 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoServiceRPC": return ProtoServiceRPC( + parent=self.parent, name=self.name, request_type=self.request_type, response_type=self.response_type, @@ -57,13 +65,15 @@ def normalize(self) -> "ProtoServiceRPC": ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("rpc "): return None proto_source = proto_source[4:].strip() # Match the RPC name. - name_match = ProtoIdentifier.match(proto_source) + name_match = ProtoIdentifier.match(None, proto_source) if name_match is None: return None name = name_match.node @@ -74,7 +84,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: proto_source = proto_source[1:].strip() # Try to parse the request type. - stream_or_request_name_match = ProtoEnumOrMessageIdentifier.match(proto_source) + stream_or_request_name_match = ProtoEnumOrMessageIdentifier.match( + None, proto_source + ) if stream_or_request_name_match is None: return None @@ -85,7 +97,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: elif stream_or_request_name_match.node.identifier == "stream": # Try matching the request name. potential_request_name_match = ProtoEnumOrMessageIdentifier.match( - stream_or_request_name_match.remaining_source.strip() + None, stream_or_request_name_match.remaining_source.strip() ) if potential_request_name_match is None: # No further name. @@ -112,7 +124,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: proto_source = proto_source[1:].strip() # Try to parse the response type. - stream_or_response_name_match = ProtoEnumOrMessageIdentifier.match(proto_source) + stream_or_response_name_match = ProtoEnumOrMessageIdentifier.match( + None, proto_source + ) if stream_or_response_name_match is None: return None @@ -123,7 +137,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: elif stream_or_response_name_match.node.identifier == "stream": # Try matching the response name. potential_response_name_match = ProtoEnumOrMessageIdentifier.match( - stream_or_response_name_match.remaining_source.strip() + None, stream_or_response_name_match.remaining_source.strip() ) if potential_response_name_match is None: # No further name. @@ -155,7 +169,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: proto_source = proto_source[1:].strip() break - option_match = ProtoOption.match(proto_source) + option_match = ProtoOption.match(None, proto_source) if option_match is None: return None options.append(option_match.node) @@ -167,6 +181,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: return ParsedProtoNode( ProtoServiceRPC( + parent, name, request_name, response_name, @@ -207,9 +222,15 @@ def serialize(self) -> str: class ProtoService(ProtoNode): - def __init__(self, name: ProtoIdentifier, nodes: list[ProtoNode]): + def __init__( + self, parent: Optional[ProtoNode], name: ProtoIdentifier, nodes: list[ProtoNode] + ): + super().__init__(parent) self.name = name + self.name.parent = self self.nodes = nodes + for node in self.nodes: + node.parent = self def __eq__(self, other) -> bool: return self.name == other.name and self.nodes == other.nodes @@ -225,6 +246,7 @@ def normalize(self) -> "ProtoService": lambda n: not isinstance(n, ProtoComment), self.nodes ) return ProtoService( + parent=self.parent, name=self.name, nodes=sorted(non_comment_nodes, key=lambda n: str(n.normalize())), ) @@ -239,7 +261,7 @@ def parse_partial_content(partial_service_content: str) -> ParsedProtoNode: ] for node_type in supported_types: try: - match_result = node_type.match(partial_service_content) + match_result = node_type.match(None, partial_service_content) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial service content:\n{partial_service_content}" @@ -251,12 +273,14 @@ def parse_partial_content(partial_service_content: str) -> ParsedProtoNode: ) @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("service "): return None proto_source = proto_source[8:] - match = ProtoIdentifier.match(proto_source) + match = ProtoIdentifier.match(None, proto_source) if match is None: raise ValueError(f"Proto has invalid service name: {proto_source}") @@ -284,7 +308,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoNode"]: parsed_tree.append(match_result.node) proto_source = match_result.remaining_source.strip() - return ParsedProtoNode(ProtoService(enum_name, nodes=parsed_tree), proto_source) + return ParsedProtoNode( + ProtoService(parent, enum_name, nodes=parsed_tree), proto_source + ) @property def options(self) -> list[ProtoOption]: diff --git a/src/proto_string_literal.py b/src/proto_string_literal.py index 9ca0339..1d98b57 100644 --- a/src/proto_string_literal.py +++ b/src/proto_string_literal.py @@ -11,7 +11,8 @@ class ParsedProtoStringLiteralNode(ParsedProtoNode): class ProtoStringLiteral(ProtoNode): QUOTES = ['"', "'"] - def __init__(self, val: str, quote: str = QUOTES[0]): + def __init__(self, parent: Optional[ProtoNode], val: str, quote: str = QUOTES[0]): + super().__init__(parent) self.value = val self.quote = quote @@ -31,7 +32,9 @@ def normalize(self) -> "ProtoStringLiteral": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoStringLiteralNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoStringLiteralNode"]: if not any(proto_source.startswith(c) for c in ProtoStringLiteral.QUOTES): return None escaped = False @@ -42,7 +45,9 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoStringLiteralNode"]: continue if c == starting_quote and not escaped: return ParsedProtoStringLiteralNode( - ProtoStringLiteral(proto_source[1 : i + 1], quote=starting_quote), + ProtoStringLiteral( + parent, proto_source[1 : i + 1], quote=starting_quote + ), proto_source[i + 2 :].strip(), ) escaped = False diff --git a/src/proto_syntax.py b/src/proto_syntax.py index 0d1496a..3e2220c 100644 --- a/src/proto_syntax.py +++ b/src/proto_syntax.py @@ -16,7 +16,8 @@ class ProtoSyntaxType(Enum): class ProtoSyntax(ProtoNode): - def __init__(self, syntax: ProtoStringLiteral): + def __init__(self, parent: Optional[ProtoNode], syntax: ProtoStringLiteral): + super().__init__(parent) self.syntax = syntax def __eq__(self, other) -> bool: @@ -35,11 +36,13 @@ def normalize(self) -> "ProtoSyntax": return self @classmethod - def match(cls, proto_source: str) -> Optional["ParsedProtoSyntaxNode"]: + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoSyntaxNode"]: if not proto_source.startswith("syntax = "): return None proto_source = proto_source[9:] - match = ProtoStringLiteral.match(proto_source) + match = ProtoStringLiteral.match(None, proto_source) if match is None: raise ValueError(f"Proto has invalid syntax syntax: {proto_source}") if not match.remaining_source.startswith(";"): @@ -52,7 +55,7 @@ def match(cls, proto_source: str) -> Optional["ParsedProtoSyntaxNode"]: ) return ParsedProtoSyntaxNode( - ProtoSyntax(match.node), + ProtoSyntax(parent, match.node), match.remaining_source.strip(), ) diff --git a/test/parser_test.py b/test/parser_test.py index 7f42e1a..a9859c3 100644 --- a/test/parser_test.py +++ b/test/parser_test.py @@ -103,44 +103,54 @@ def test_parser(self): self.assertEqual( proto_file.imports, [ - ProtoImport(ProtoStringLiteral("foo.proto"), public=True), - ProtoImport(ProtoStringLiteral("bar/baz.proto"), weak=True), - ProtoImport(ProtoStringLiteral("bat.proto")), + ProtoImport(None, ProtoStringLiteral(None, "foo.proto"), public=True), + ProtoImport(None, ProtoStringLiteral(None, "bar/baz.proto"), weak=True), + ProtoImport(None, ProtoStringLiteral(None, "bat.proto")), ], ) self.assertEqual( proto_file.options, [ ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("my.test.package")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "my.test.package")), ), ProtoOption( - ProtoIdentifier("(fully.qualified).option"), - ProtoConstant(ProtoFloat(3.14159265, ProtoFloatSign.POSITIVE)), + None, + ProtoIdentifier(None, "(fully.qualified).option"), + ProtoConstant( + None, ProtoFloat(None, 3.14159265, ProtoFloatSign.POSITIVE) + ), ), ], ) self.assertIn( ProtoEnum( - ProtoIdentifier("MyAwesomeEnum"), + None, + ProtoIdentifier(None, "MyAwesomeEnum"), [ ProtoOption( - ProtoIdentifier("allow_alias"), ProtoConstant(ProtoBool(True)) + None, + ProtoIdentifier(None, "allow_alias"), + ProtoConstant(None, ProtoBool(None, True)), ), ProtoEnumValue( - ProtoIdentifier("MAE_UNSPECIFIED"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "MAE_UNSPECIFIED"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), [], ), ProtoEnumValue( - ProtoIdentifier("MAE_STARTED"), - ProtoInt(1, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "MAE_STARTED"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), [], ), ProtoEnumValue( - ProtoIdentifier("MAE_RUNNING"), - ProtoInt(2, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "MAE_RUNNING"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), [], ), ], @@ -149,89 +159,113 @@ def test_parser(self): ) self.assertIn( ProtoMessage( - ProtoIdentifier("MyAwesomeMessage"), + None, + ProtoIdentifier(None, "MyAwesomeMessage"), [ ProtoOption( - ProtoIdentifier("(bar).baz"), - ProtoConstant(ProtoFloat(1.2, ProtoFloatSign.POSITIVE)), + None, + ProtoFullIdentifier(None, "(bar).baz"), + ProtoConstant( + None, ProtoFloat(None, 1.2, ProtoFloatSign.POSITIVE) + ), ), ProtoEnum( - ProtoIdentifier("MyNestedEnum"), + None, + ProtoIdentifier(None, "MyNestedEnum"), [ ProtoEnumValue( - ProtoIdentifier("MNE_UNDEFINED"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "MNE_UNDEFINED"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - ProtoIdentifier("MNE_NEGATIVE"), - ProtoInt(1, ProtoIntSign.NEGATIVE), + None, + ProtoIdentifier(None, "MNE_NEGATIVE"), + ProtoInt(None, 1, ProtoIntSign.NEGATIVE), ), ProtoEnumValue( - ProtoIdentifier("MNE_POSITIVE"), - ProtoInt(2, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "MNE_POSITIVE"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), ), ], ), - ProtoMessage(ProtoIdentifier("MyNestedMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "MyNestedMessage"), []), ProtoReserved( + None, ranges=[ ProtoRange( - ProtoInt(1, ProtoIntSign.POSITIVE), - ProtoInt(3, ProtoIntSign.POSITIVE), + None, + ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), ) - ] + ], ), - ProtoReserved(fields=[ProtoIdentifier("yay")]), - ProtoSingleLineComment(" testing nested comment"), + ProtoReserved(None, fields=[ProtoIdentifier(None, "yay")]), + ProtoSingleLineComment(None, " testing nested comment"), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("field_one"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "field_one"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), True, ), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("field_two"), - ProtoInt(2, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "field_two"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), False, False, - ProtoIdentifier("MyNestedMessage"), + ProtoIdentifier(None, "MyNestedMessage"), [ ProtoMessageFieldOption( - ProtoFullIdentifier("bar.baz"), - ProtoConstant(ProtoBool(True)), + None, + ProtoFullIdentifier(None, "bar.baz"), + ProtoConstant(None, ProtoBool(None, True)), ) ], ), - ProtoExtensions([ProtoRange(8, ProtoRangeEnum.MAX)]), + ProtoExtensions(None, [ProtoRange(None, 8, ProtoRangeEnum.MAX)]), ProtoOneOf( - ProtoIdentifier("foo"), + None, + ProtoIdentifier(None, "foo"), [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "name"), + ProtoInt(None, 4, ProtoIntSign.POSITIVE), ), ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant( + None, ProtoStringLiteral(None, "com.example.foo") + ), ), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("sub_message"), - ProtoInt(9, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "sub_message"), + ProtoInt(None, 9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier("SubMessage"), + ProtoFullIdentifier(None, "SubMessage"), [ ProtoMessageFieldOption( - ProtoIdentifier("(bar.baz).bat"), - ProtoConstant(ProtoStringLiteral("bat")), + None, + ProtoIdentifier(None, "(bar.baz).bat"), + ProtoConstant( + None, ProtoStringLiteral(None, "bat") + ), ), ProtoMessageFieldOption( - ProtoIdentifier("baz.bat"), + None, + ProtoIdentifier(None, "baz.bat"), ProtoConstant( - ProtoInt(100, ProtoIntSign.NEGATIVE) + None, + ProtoInt(None, 100, ProtoIntSign.NEGATIVE), ), ), ], @@ -239,11 +273,12 @@ def test_parser(self): ], ), ProtoMap( + None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("my_map"), - ProtoInt(10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier("NestedMessage"), + ProtoIdentifier(None, "my_map"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier(None, "NestedMessage"), [], ), ], @@ -253,38 +288,47 @@ def test_parser(self): self.assertIn( ProtoService( - ProtoIdentifier("MyGreatService"), + None, + ProtoIdentifier(None, "MyGreatService"), [ ProtoOption( - ProtoIdentifier("(foo.bar).baz"), - ProtoConstant(ProtoStringLiteral("bat")), + None, + ProtoIdentifier(None, "(foo.bar).baz"), + ProtoConstant(None, ProtoStringLiteral(None, "bat")), ), ProtoServiceRPC( - ProtoIdentifier("OneRPC"), - ProtoEnumOrMessageIdentifier("OneRPCRequest"), - ProtoEnumOrMessageIdentifier("OneRPCResponse"), + None, + ProtoIdentifier(None, "OneRPC"), + ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), ), ProtoServiceRPC( - ProtoIdentifier("TwoRPC"), - ProtoEnumOrMessageIdentifier("TwoRPCRequest"), - ProtoEnumOrMessageIdentifier("TwoRPCResponse"), + None, + ProtoIdentifier(None, "TwoRPC"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), False, True, ), ProtoServiceRPC( - ProtoIdentifier("ThreeRPC"), - ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), + None, + ProtoIdentifier(None, "ThreeRPC"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), False, False, [ ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant( + None, ProtoStringLiteral(None, "com.example.foo") + ), ), ProtoOption( - ProtoFullIdentifier("(foo.bar).baz"), - ProtoConstant(ProtoBool(False)), + None, + ProtoFullIdentifier(None, "(foo.bar).baz"), + ProtoConstant(None, ProtoBool(None, False)), ), ], ), @@ -295,14 +339,16 @@ def test_parser(self): self.assertIn( ProtoExtend( - ProtoIdentifier("SomeExtendableMessage"), + None, + ProtoIdentifier(None, "SomeExtendableMessage"), [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("some_extendable_field"), - 1, + ProtoIdentifier(None, "some_extendable_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), - ProtoSingleLineComment(" yay"), + ProtoSingleLineComment(None, " yay"), ], ), proto_file.nodes, diff --git a/test/proto_bool_test.py b/test/proto_bool_test.py index cc3a035..7611d75 100644 --- a/test/proto_bool_test.py +++ b/test/proto_bool_test.py @@ -5,18 +5,18 @@ class BoolTest(unittest.TestCase): def test_true(self): - self.assertEqual(ProtoBool.match("true").node.value, True) - self.assertIsNone(ProtoBool.match("True")) - self.assertIsNone(ProtoBool.match("truee")) - self.assertIsNone(ProtoBool.match("true_true")) - self.assertIsNone(ProtoBool.match("true.false")) + self.assertEqual(ProtoBool.match(None, "true").node.value, True) + self.assertIsNone(ProtoBool.match(None, "True")) + self.assertIsNone(ProtoBool.match(None, "truee")) + self.assertIsNone(ProtoBool.match(None, "true_true")) + self.assertIsNone(ProtoBool.match(None, "true.false")) def test_false(self): - self.assertEqual(ProtoBool.match("false").node.value, False) - self.assertIsNone(ProtoBool.match("False")) - self.assertIsNone(ProtoBool.match("falsee")) - self.assertIsNone(ProtoBool.match("false_false")) - self.assertIsNone(ProtoBool.match("false.true")) + self.assertEqual(ProtoBool.match(None, "false").node.value, False) + self.assertIsNone(ProtoBool.match(None, "False")) + self.assertIsNone(ProtoBool.match(None, "falsee")) + self.assertIsNone(ProtoBool.match(None, "false_false")) + self.assertIsNone(ProtoBool.match(None, "false.true")) if __name__ == "__main__": diff --git a/test/proto_comment_test.py b/test/proto_comment_test.py index 95a37e9..5d3a705 100644 --- a/test/proto_comment_test.py +++ b/test/proto_comment_test.py @@ -5,42 +5,46 @@ class ProtoSingleLineCommentTest(unittest.TestCase): def test_matches_normal_comment(self): - node = ProtoSingleLineComment.match("// hello there, this is a comment").node + node = ProtoSingleLineComment.match( + None, "// hello there, this is a comment" + ).node self.assertEqual(node.value, " hello there, this is a comment") self.assertEqual(node.serialize(), "// hello there, this is a comment") self.assertIsNone(node.normalize()) def test_matches_without_space(self): - node = ProtoSingleLineComment.match("//comment without space").node + node = ProtoSingleLineComment.match(None, "//comment without space").node self.assertEqual(node.value, "comment without space") self.assertEqual(node.serialize(), "//comment without space") self.assertIsNone(node.normalize()) def test_does_not_match_multiple_lines(self): - node = ProtoSingleLineComment.match("//line one\nbut not this").node + node = ProtoSingleLineComment.match(None, "//line one\nbut not this").node self.assertEqual(node.value, "line one") self.assertEqual(node.serialize(), "//line one") self.assertIsNone(node.normalize()) def test_does_not_match_single_slash(self): self.assertIsNone( - ProtoSingleLineComment.match("/hello there, this is a comment") + ProtoSingleLineComment.match(None, "/hello there, this is a comment") ) self.assertIsNone( - ProtoSingleLineComment.match("/ /hello there, this is a comment") + ProtoSingleLineComment.match(None, "/ /hello there, this is a comment") ) class ProtoMultiLineCommentTest(unittest.TestCase): def test_matches_single_line_comment(self): - node = ProtoMultiLineComment.match("/* hello there, this is a comment */").node + node = ProtoMultiLineComment.match( + None, "/* hello there, this is a comment */" + ).node self.assertEqual(node.value, " hello there, this is a comment ") self.assertEqual(node.serialize(), "/* hello there, this is a comment */") self.assertIsNone(node.normalize()) def test_matches_multi_line_comment(self): node = ProtoMultiLineComment.match( - "/* hello there,\nthis is a \nmulti-line comment */" + None, "/* hello there,\nthis is a \nmulti-line comment */" ).node self.assertEqual(node.value, " hello there,\nthis is a \nmulti-line comment ") self.assertEqual( @@ -51,25 +55,25 @@ def test_matches_multi_line_comment(self): def test_does_not_match_unclosed_comment(self): self.assertIsNone( ProtoMultiLineComment.match( - "/* hello there, this\n /is an unclosed\n*multiple-line comment/" + None, "/* hello there, this\n /is an unclosed\n*multiple-line comment/" ) ) def test_matches_without_space(self): - node = ProtoMultiLineComment.match("/*comment without space*/").node + node = ProtoMultiLineComment.match(None, "/*comment without space*/").node self.assertEqual(node.value, "comment without space") self.assertEqual(node.serialize(), "/*comment without space*/") self.assertIsNone(node.normalize()) def test_does_not_match_partial_opening(self): self.assertIsNone( - ProtoMultiLineComment.match("/hello there, this is a comment*/") + ProtoMultiLineComment.match(None, "/hello there, this is a comment*/") ) self.assertIsNone( - ProtoMultiLineComment.match("*/hello there, this is a comment*/") + ProtoMultiLineComment.match(None, "*/hello there, this is a comment*/") ) self.assertIsNone( - ProtoMultiLineComment.match("*hello there, this is a comment*/") + ProtoMultiLineComment.match(None, "*hello there, this is a comment*/") ) diff --git a/test/proto_constant_test.py b/test/proto_constant_test.py index 2717fa4..3367770 100644 --- a/test/proto_constant_test.py +++ b/test/proto_constant_test.py @@ -12,151 +12,174 @@ class ConstantTest(unittest.TestCase): # constant = fullIdent | ( [ "-" | "+" ] intLit ) | ( [ "-" | "+" ] floatLit ) | strLit | boolLit def test_ident(self): - self.assertEqual(ProtoConstant.match("a").node.value, ProtoIdentifier("a")) - self.assertEqual(ProtoConstant.match("a0").node.value, ProtoIdentifier("a0")) - self.assertEqual(ProtoConstant.match("a_").node.value, ProtoIdentifier("a_")) - self.assertEqual(ProtoConstant.match("aa").node.value, ProtoIdentifier("aa")) - self.assertEqual(ProtoConstant.match("ab").node.value, ProtoIdentifier("ab")) self.assertEqual( - ProtoConstant.match("a0b_f_aj").node.value, ProtoIdentifier("a0b_f_aj") + ProtoConstant.match(None, "a").node.value, ProtoIdentifier(None, "a") ) self.assertEqual( - ProtoConstant.match("a.bar").node.value, ProtoIdentifier("a.bar") + ProtoConstant.match(None, "a0").node.value, ProtoIdentifier(None, "a0") ) self.assertEqual( - ProtoConstant.match("a.bar.baz").node.value, ProtoIdentifier("a.bar.baz") + ProtoConstant.match(None, "a_").node.value, ProtoIdentifier(None, "a_") + ) + self.assertEqual( + ProtoConstant.match(None, "aa").node.value, ProtoIdentifier(None, "aa") + ) + self.assertEqual( + ProtoConstant.match(None, "ab").node.value, ProtoIdentifier(None, "ab") + ) + self.assertEqual( + ProtoConstant.match(None, "a0b_f_aj").node.value, + ProtoIdentifier(None, "a0b_f_aj"), + ) + self.assertEqual( + ProtoConstant.match(None, "a.bar").node.value, + ProtoIdentifier(None, "a.bar"), + ) + self.assertEqual( + ProtoConstant.match(None, "a.bar.baz").node.value, + ProtoIdentifier(None, "a.bar.baz"), ) def test_str(self): self.assertEqual( - ProtoConstant.match("'a'").node.value, ProtoStringLiteral("a", quote="'") + ProtoConstant.match(None, "'a'").node.value, + ProtoStringLiteral(None, "a", quote="'"), ) self.assertEqual( - ProtoConstant.match("'.a'").node.value, ProtoStringLiteral(".a", quote="'") + ProtoConstant.match(None, "'.a'").node.value, + ProtoStringLiteral(None, ".a", quote="'"), ) self.assertEqual( - ProtoConstant.match('"a"').node.value, ProtoStringLiteral("a", quote='"') + ProtoConstant.match(None, '"a"').node.value, + ProtoStringLiteral(None, "a", quote='"'), ) def test_bool(self): - self.assertEqual(ProtoConstant.match("true").node.value, ProtoBool(True)) - self.assertEqual(ProtoConstant.match("false").node.value, ProtoBool(False)) + self.assertEqual( + ProtoConstant.match(None, "true").node.value, ProtoBool(None, True) + ) + self.assertEqual( + ProtoConstant.match(None, "false").node.value, ProtoBool(None, False) + ) def test_int(self): self.assertEqual( - ProtoConstant.match("1").node.value, ProtoInt(1, ProtoIntSign.POSITIVE) + ProtoConstant.match(None, "1").node.value, + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("158912938471293847").node.value, - ProtoInt(158912938471293847, ProtoIntSign.POSITIVE), + ProtoConstant.match(None, "158912938471293847").node.value, + ProtoInt(None, 158912938471293847, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("+1").node.value, ProtoInt(1, ProtoIntSign.POSITIVE) + ProtoConstant.match(None, "+1").node.value, + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("+158912938471293847").node.value, - ProtoInt(158912938471293847, ProtoIntSign.POSITIVE), + ProtoConstant.match(None, "+158912938471293847").node.value, + ProtoInt(None, 158912938471293847, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("-1").node.value, ProtoInt(1, ProtoIntSign.NEGATIVE) + ProtoConstant.match(None, "-1").node.value, + ProtoInt(None, 1, ProtoIntSign.NEGATIVE), ) self.assertEqual( - ProtoConstant.match("-248713857").node.value, - ProtoInt(248713857, ProtoIntSign.NEGATIVE), + ProtoConstant.match(None, "-248713857").node.value, + ProtoInt(None, 248713857, ProtoIntSign.NEGATIVE), ) # Octal self.assertEqual( - ProtoConstant.match("072342").node.value, - ProtoInt(0o72342, ProtoIntSign.POSITIVE), + ProtoConstant.match(None, "072342").node.value, + ProtoInt(None, 0o72342, ProtoIntSign.POSITIVE), ) with self.assertRaises(ValueError): - ProtoConstant.match("072942") + ProtoConstant.match(None, "072942") # Hex self.assertEqual( - ProtoConstant.match("0x72342").node.value, - ProtoInt(0x72342, ProtoIntSign.POSITIVE), + ProtoConstant.match(None, "0x72342").node.value, + ProtoInt(None, 0x72342, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("0x7A3d2").node.value, - ProtoInt(0x7A3D2, ProtoIntSign.POSITIVE), + ProtoConstant.match(None, "0x7A3d2").node.value, + ProtoInt(None, 0x7A3D2, ProtoIntSign.POSITIVE), ) with self.assertRaises(ValueError): - ProtoConstant.match("0x72G42") + ProtoConstant.match(None, "0x72G42") def test_float(self): self.assertEqual( - ProtoConstant.match("2834.235928").node.value, - ProtoFloat(2834.235928, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834.235928").node.value, + ProtoFloat(None, 2834.235928, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834.e2").node.value, - ProtoFloat(283400, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834.e2").node.value, + ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834e2").node.value, - ProtoFloat(283400, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834e2").node.value, + ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834.e0").node.value, - ProtoFloat(2834, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834.e0").node.value, + ProtoFloat(None, 2834, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834e0").node.value, - ProtoFloat(2834, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834e0").node.value, + ProtoFloat(None, 2834, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834.E3").node.value, - ProtoFloat(2834000, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834.E3").node.value, + ProtoFloat(None, 2834000, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834E3").node.value, - ProtoFloat(2834000, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834E3").node.value, + ProtoFloat(None, 2834000, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834.e+2").node.value, - ProtoFloat(283400, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834.e+2").node.value, + ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834e+2").node.value, - ProtoFloat(283400, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834e+2").node.value, + ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834.e-2").node.value, - ProtoFloat(28.34, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834.e-2").node.value, + ProtoFloat(None, 28.34, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("2834e-2").node.value, - ProtoFloat(28.34, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "2834e-2").node.value, + ProtoFloat(None, 28.34, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(".0").node.value, - ProtoFloat(0.0, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, ".0").node.value, + ProtoFloat(None, 0.0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(".0e-1").node.value, - ProtoFloat(0.00, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, ".0e-1").node.value, + ProtoFloat(None, 0.00, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(".0E1").node.value, - ProtoFloat(0, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, ".0E1").node.value, + ProtoFloat(None, 0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(".0E2").node.value, - ProtoFloat(0, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, ".0E2").node.value, + ProtoFloat(None, 0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(".3265").node.value, - ProtoFloat(0.3265, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, ".3265").node.value, + ProtoFloat(None, 0.3265, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(".3265e1").node.value, - ProtoFloat(3.265, ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, ".3265e1").node.value, + ProtoFloat(None, 3.265, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match("inf").node.value, - ProtoFloat(float("inf"), ProtoFloatSign.POSITIVE), + ProtoConstant.match(None, "inf").node.value, + ProtoFloat(None, float("inf"), ProtoFloatSign.POSITIVE), ) diff --git a/test/proto_enum_test.py b/test/proto_enum_test.py index 4687151..1efafc7 100644 --- a/test/proto_enum_test.py +++ b/test/proto_enum_test.py @@ -26,6 +26,7 @@ class EnumTest(unittest.TestCase): def test_enum_all_features(self): parsed_enum_multiple_values = ProtoEnum.match( + None, dedent( """ enum FooEnum { @@ -43,60 +44,81 @@ def test_enum_all_features(self): FE_VALTWO = 2; } """.strip() - ) + ), ) self.assertEqual( parsed_enum_multiple_values.node.nodes, [ ProtoReserved( + None, [ - ProtoRange(ProtoInt(1, ProtoIntSign.POSITIVE)), - ProtoRange(ProtoInt(2, ProtoIntSign.POSITIVE)), + ProtoRange(None, ProtoInt(None, 1, ProtoIntSign.POSITIVE)), + ProtoRange(None, ProtoInt(None, 2, ProtoIntSign.POSITIVE)), ProtoRange( - ProtoInt(5, ProtoIntSign.POSITIVE), + None, + ProtoInt(None, 5, ProtoIntSign.POSITIVE), ProtoRangeEnum.MAX, ), - ] + ], ), ProtoEnumValue( - ProtoIdentifier("FE_NEGATIVE"), - ProtoInt(1, ProtoIntSign.NEGATIVE), + None, + ProtoIdentifier(None, "FE_NEGATIVE"), + ProtoInt(None, 1, ProtoIntSign.NEGATIVE), [ ProtoEnumValueOption( - ProtoIdentifier("foo"), ProtoConstant(ProtoBool(False)) + None, + ProtoIdentifier(None, "foo"), + ProtoConstant(None, ProtoBool(None, False)), ) ], ), ProtoEnumValue( - ProtoIdentifier("FE_UNDEFINED"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_UNDEFINED"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), - ProtoSingleLineComment(" single-line comment"), + ProtoSingleLineComment(None, " single-line comment"), ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foobar")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foobar")), ), ProtoMultiLineComment( - "\n multiple\n line\n comment\n " + None, + "\n multiple\n line\n comment\n ", ), ProtoEnumValue( - ProtoIdentifier("FE_VALONE"), - ProtoInt(1, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_VALONE"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), [ ProtoEnumValueOption( - ProtoIdentifier("(bar.baz).bat"), - ProtoConstant(ProtoStringLiteral("bat")), + None, + ProtoIdentifier(None, "(bar.baz).bat"), + ProtoConstant(None, ProtoStringLiteral(None, "bat")), ), ProtoEnumValueOption( - ProtoIdentifier("baz.bat"), - ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), + None, + ProtoIdentifier(None, "baz.bat"), + ProtoConstant( + None, ProtoInt(None, 100, ProtoIntSign.NEGATIVE) + ), ), ], ), ProtoReserved( - [], [ProtoIdentifier("FE_RESERVED"), ProtoIdentifier("FE_OLD")] + None, + [], + [ + ProtoIdentifier(None, "FE_RESERVED"), + ProtoIdentifier(None, "FE_OLD"), + ], ), ProtoEnumValue( - ProtoIdentifier("FE_VALTWO"), ProtoInt(2, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_VALTWO"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), ), ], ) @@ -125,24 +147,26 @@ def test_enum_all_features(self): ) def test_empty_enum(self): - parsed_empty_enum = ProtoEnum.match("""enum FooEnum {}""") + parsed_empty_enum = ProtoEnum.match(None, """enum FooEnum {}""") self.assertIsNotNone(parsed_empty_enum) - self.assertEqual(parsed_empty_enum.node.name, ProtoIdentifier("FooEnum")) + self.assertEqual(parsed_empty_enum.node.name, ProtoIdentifier(None, "FooEnum")) parsed_spaced_enum = ProtoEnum.match( + None, dedent( """ enum FooEnum { } """.strip() - ) + ), ) self.assertIsNotNone(parsed_spaced_enum) - self.assertEqual(parsed_spaced_enum.node.name, ProtoIdentifier("FooEnum")) + self.assertEqual(parsed_spaced_enum.node.name, ProtoIdentifier(None, "FooEnum")) def test_enum_empty_statements(self): empty_statement_enum = ProtoEnum.match( + None, dedent( """ enum FooEnum { @@ -150,13 +174,16 @@ def test_enum_empty_statements(self): ; } """.strip() - ) + ), ) self.assertIsNotNone(empty_statement_enum) - self.assertEqual(empty_statement_enum.node.name, ProtoIdentifier("FooEnum")) + self.assertEqual( + empty_statement_enum.node.name, ProtoIdentifier(None, "FooEnum") + ) def test_enum_optionals(self): parsed_enum_with_optionals = ProtoEnum.match( + None, dedent( """ enum FooEnum { @@ -164,46 +191,52 @@ def test_enum_optionals(self): option (foo.bar).baz = false; } """.strip() - ) + ), ) self.assertIsNotNone( parsed_enum_with_optionals.node.options, [ ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foobar")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foobar")), ), ProtoOption( - ProtoIdentifier("(foo.bar).baz"), - ProtoConstant(ProtoBool(False)), + None, + ProtoIdentifier(None, "(foo.bar).baz"), + ProtoConstant(None, ProtoBool(None, False)), ), ], ) self.assertEqual( - parsed_enum_with_optionals.node.name, ProtoIdentifier("FooEnum") + parsed_enum_with_optionals.node.name, ProtoIdentifier(None, "FooEnum") ) def test_enum_single_value(self): parsed_enum_single_value = ProtoEnum.match( + None, dedent( """ enum FooEnum { FE_UNDEFINED = 0; } """.strip() - ) + ), ) self.assertEqual( parsed_enum_single_value.node.nodes, [ ProtoEnumValue( - ProtoIdentifier("FE_UNDEFINED"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_UNDEFINED"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ) def test_enum_multiple_values(self): parsed_enum_multiple_values = ProtoEnum.match( + None, dedent( """ enum FooEnum { @@ -213,28 +246,37 @@ def test_enum_multiple_values(self): FE_VALTWO = 2; } """.strip() - ) + ), ) self.assertEqual( parsed_enum_multiple_values.node.nodes, [ ProtoEnumValue( - ProtoIdentifier("FE_NEGATIVE"), ProtoInt(1, ProtoIntSign.NEGATIVE) + None, + ProtoIdentifier(None, "FE_NEGATIVE"), + ProtoInt(None, 1, ProtoIntSign.NEGATIVE), ), ProtoEnumValue( - ProtoIdentifier("FE_UNDEFINED"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_UNDEFINED"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - ProtoIdentifier("FE_VALONE"), ProtoInt(1, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_VALONE"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - ProtoIdentifier("FE_VALTWO"), ProtoInt(2, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_VALTWO"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), ), ], ) def test_enum_comments(self): parsed_enum_multiple_values = ProtoEnum.match( + None, dedent( """ enum FooEnum { @@ -246,32 +288,42 @@ def test_enum_comments(self): FE_VALTWO = 2; } """.strip() - ) + ), ) self.assertEqual( parsed_enum_multiple_values.node.nodes, [ ProtoEnumValue( - ProtoIdentifier("FE_NEGATIVE"), ProtoInt(1, ProtoIntSign.NEGATIVE) + None, + ProtoIdentifier(None, "FE_NEGATIVE"), + ProtoInt(None, 1, ProtoIntSign.NEGATIVE), ), - ProtoSingleLineComment(" test single-line comment"), + ProtoSingleLineComment(None, " test single-line comment"), ProtoEnumValue( - ProtoIdentifier("FE_UNDEFINED"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_UNDEFINED"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), ProtoMultiLineComment( - " test multiple\n FE_UNUSED = 200;\n line comment " + None, + " test multiple\n FE_UNUSED = 200;\n line comment ", ), ProtoEnumValue( - ProtoIdentifier("FE_VALONE"), ProtoInt(1, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_VALONE"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - ProtoIdentifier("FE_VALTWO"), ProtoInt(2, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_VALTWO"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), ), ], ) def test_enum_normalize_away_comments(self): parsed_enum_multiple_values = ProtoEnum.match( + None, dedent( """ enum FooEnum { @@ -283,62 +335,80 @@ def test_enum_normalize_away_comments(self): FE_VALTWO = 2; } """.strip() - ) + ), ).node.normalize() self.assertEqual( parsed_enum_multiple_values.nodes, [ ProtoEnumValue( - ProtoIdentifier("FE_NEGATIVE"), ProtoInt(1, ProtoIntSign.NEGATIVE) + None, + ProtoIdentifier(None, "FE_NEGATIVE"), + ProtoInt(None, 1, ProtoIntSign.NEGATIVE), ), ProtoEnumValue( - ProtoIdentifier("FE_UNDEFINED"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_UNDEFINED"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - ProtoIdentifier("FE_VALONE"), ProtoInt(1, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_VALONE"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - ProtoIdentifier("FE_VALTWO"), ProtoInt(2, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "FE_VALTWO"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), ), ], ) def test_diff_same_enum_returns_empty(self): pe1 = ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [], ) pe2 = ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [], ) self.assertEqual(ProtoEnum.diff(pe1, pe2), []) def test_diff_different_enum_name_returns_empty(self): pe1 = ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [], ) pe2 = ProtoEnum( - ProtoIdentifier("OtherEnum"), + None, + ProtoIdentifier(None, "OtherEnum"), [], ) self.assertEqual(ProtoEnum.diff(pe1, pe2), []) def test_diff_different_enum_value_name_returns_enum_diff(self): pe1 = ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "ME_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ) pe2 = ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_KNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "ME_KNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ) @@ -348,25 +418,31 @@ def test_diff_different_enum_value_name_returns_enum_diff(self): ProtoEnumValueNameChanged( pe1, pe2.nodes[0], - ProtoIdentifier("ME_UNKNOWN"), + ProtoIdentifier(None, "ME_UNKNOWN"), ) ], ) def test_diff_different_enum_value_value_returns_enum_diff(self): pe1 = ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "ME_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ) pe2 = ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_UNKNOWN"), ProtoInt(1, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "ME_UNKNOWN"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ) ], ) @@ -377,7 +453,7 @@ def test_diff_different_enum_value_value_returns_enum_diff(self): ProtoEnumValueValueChanged( pe1, pe2.values[0], - ProtoInt(0, ProtoIntSign.POSITIVE), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), diff, ) @@ -386,10 +462,13 @@ def test_diff_different_enum_value_value_returns_enum_diff(self): def test_diff_enum_added(self): pe1 = None pe2 = ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "ME_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ) @@ -398,11 +477,13 @@ def test_diff_enum_added(self): [ ProtoEnumAdded( ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "ME_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ) @@ -412,10 +493,13 @@ def test_diff_enum_added(self): def test_diff_enum_removed(self): pe1 = ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_UNKNOWN"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "ME_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ) @@ -425,11 +509,13 @@ def test_diff_enum_removed(self): [ ProtoEnumRemoved( ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "ME_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ) @@ -445,29 +531,35 @@ def test_diff_sets_empty_returns_empty(self): def test_diff_sets_no_change(self): set1 = [ ProtoEnum( - ProtoIdentifier("FooEnum"), + None, + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("TagEnum"), + None, + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -478,29 +570,35 @@ def test_diff_sets_all_removed(self): set1 = [] set2 = [ ProtoEnum( - ProtoIdentifier("FooEnum"), + None, + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("TagEnum"), + None, + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -510,11 +608,13 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - ProtoIdentifier("FooEnum"), + None, + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -524,11 +624,13 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -538,11 +640,13 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - ProtoIdentifier("TagEnum"), + None, + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -554,29 +658,35 @@ def test_diff_sets_all_removed(self): def test_diff_sets_all_added(self): set1 = [ ProtoEnum( - ProtoIdentifier("FooEnum"), + None, + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("TagEnum"), + None, + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -587,11 +697,13 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - ProtoIdentifier("FooEnum"), + None, + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -601,11 +713,13 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -615,11 +729,13 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - ProtoIdentifier("TagEnum"), + None, + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -631,58 +747,70 @@ def test_diff_sets_all_added(self): def test_diff_sets_mutually_exclusive(self): set1 = [ ProtoEnum( - ProtoIdentifier("FooEnum"), + None, + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("TagEnum"), + None, + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ] set2 = [ ProtoEnum( - ProtoIdentifier("FooEnum2"), + None, + ProtoIdentifier(None, "FooEnum2"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("BarEnum2"), + None, + ProtoIdentifier(None, "BarEnum2"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("TagEnum2"), + None, + ProtoIdentifier(None, "TagEnum2"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -693,11 +821,13 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - ProtoIdentifier("FooEnum"), + None, + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -707,11 +837,13 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -722,11 +854,13 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - ProtoIdentifier("TagEnum"), + None, + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -737,11 +871,13 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - ProtoIdentifier("FooEnum2"), + None, + ProtoIdentifier(None, "FooEnum2"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -752,11 +888,13 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - ProtoIdentifier("BarEnum2"), + None, + ProtoIdentifier(None, "BarEnum2"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -767,11 +905,13 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - ProtoIdentifier("TagEnum2"), + None, + ProtoIdentifier(None, "TagEnum2"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -784,58 +924,70 @@ def test_diff_sets_mutually_exclusive(self): def test_diff_sets_overlap(self): set1 = [ ProtoEnum( - ProtoIdentifier("FooEnum"), + None, + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("TagEnum"), + None, + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ] set2 = [ ProtoEnum( - ProtoIdentifier("FooEnum2"), + None, + ProtoIdentifier(None, "FooEnum2"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - ProtoIdentifier("TagEnum2"), + None, + ProtoIdentifier(None, "TagEnum2"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -846,11 +998,13 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - ProtoIdentifier("FooEnum2"), + None, + ProtoIdentifier(None, "FooEnum2"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -861,11 +1015,13 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - ProtoIdentifier("TagEnum2"), + None, + ProtoIdentifier(None, "TagEnum2"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN2"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -875,11 +1031,13 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - ProtoIdentifier("FooEnum"), + None, + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( - ProtoIdentifier("FE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -889,11 +1047,13 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - ProtoIdentifier("TagEnum"), + None, + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( - ProtoIdentifier("TE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), @@ -903,18 +1063,22 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumValueNameChanged( ProtoEnum( - ProtoIdentifier("BarEnum"), + None, + ProtoIdentifier(None, "BarEnum"), [ ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnumValue( - ProtoIdentifier("BE_UNKNOWN2"), ProtoInt(0, ProtoIntSign.POSITIVE) + None, + ProtoIdentifier(None, "BE_UNKNOWN2"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), - ProtoIdentifier("BE_UNKNOWN"), + ProtoIdentifier(None, "BE_UNKNOWN"), ), diff, ) diff --git a/test/proto_extend_test.py b/test/proto_extend_test.py index 41d54fc..b77170b 100644 --- a/test/proto_extend_test.py +++ b/test/proto_extend_test.py @@ -11,43 +11,47 @@ class ExtendTest(unittest.TestCase): maxDiff = None def test_empty_extend(self): - parsed_empty_extend = ProtoExtend.match("""extend FooMessage {}""") + parsed_empty_extend = ProtoExtend.match(None, """extend FooMessage {}""") self.assertIsNotNone(parsed_empty_extend) self.assertEqual( - parsed_empty_extend.node.name, ProtoEnumOrMessageIdentifier("FooMessage") + parsed_empty_extend.node.name, + ProtoEnumOrMessageIdentifier(None, "FooMessage"), ) self.assertEqual(parsed_empty_extend.node.serialize(), "extend FooMessage {\n}") parsed_spaced_extend = ProtoExtend.match( + None, dedent( """ extend FooMessage { } """.strip() - ) + ), ) self.assertIsNotNone(parsed_spaced_extend) self.assertEqual( - parsed_spaced_extend.node.name, ProtoEnumOrMessageIdentifier("FooMessage") + parsed_spaced_extend.node.name, + ProtoEnumOrMessageIdentifier(None, "FooMessage"), ) self.assertEqual( parsed_spaced_extend.node.serialize(), "extend FooMessage {\n}" ) parsed_scoped_extend = ProtoExtend.match( + None, dedent( """ extend google.protobuf.FooMessage { } """.strip() - ) + ), ) self.assertIsNotNone(parsed_scoped_extend) self.assertEqual( parsed_scoped_extend.node.name, - ProtoEnumOrMessageIdentifier("google.protobuf.FooMessage"), + ProtoEnumOrMessageIdentifier(None, "google.protobuf.FooMessage"), ) self.assertEqual( parsed_scoped_extend.node.serialize(), @@ -56,6 +60,7 @@ def test_empty_extend(self): def test_extend_empty_statements(self): empty_statement_message = ProtoExtend.match( + None, dedent( """ extend FooMessage { @@ -63,12 +68,12 @@ def test_extend_empty_statements(self): ; } """.strip() - ) + ), ) self.assertIsNotNone(empty_statement_message) self.assertEqual( empty_statement_message.node.name, - ProtoEnumOrMessageIdentifier("FooMessage"), + ProtoEnumOrMessageIdentifier(None, "FooMessage"), ) self.assertEqual( empty_statement_message.node.serialize(), "extend FooMessage {\n}" @@ -76,23 +81,26 @@ def test_extend_empty_statements(self): def test_extend_simple_field(self): parsed_extend_with_single_field = ProtoExtend.match( + None, dedent( """ extend FooMessage { string single_field = 1; } """.strip() - ) + ), ) self.assertEqual( parsed_extend_with_single_field.node, ProtoExtend( - ProtoEnumOrMessageIdentifier("FooMessage"), + None, + ProtoEnumOrMessageIdentifier(None, "FooMessage"), [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("single_field"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "single_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ) ], ), diff --git a/test/proto_extensions_test.py b/test/proto_extensions_test.py index 2e846a2..86f64c4 100644 --- a/test/proto_extensions_test.py +++ b/test/proto_extensions_test.py @@ -6,27 +6,29 @@ class ExtensionsTest(unittest.TestCase): def test_extension_single_int(self): self.assertEqual( - ProtoExtensions.match("extensions 21;").node.serialize(), "extensions 21;" + ProtoExtensions.match(None, "extensions 21;").node.serialize(), + "extensions 21;", ) self.assertEqual( - ProtoExtensions.match("extensions -1;").node.serialize(), "extensions -1;" + ProtoExtensions.match(None, "extensions -1;").node.serialize(), + "extensions -1;", ) def test_extension_multiple_ints(self): self.assertEqual( - ProtoExtensions.match("extensions 1, 5, 2, 42;").node.serialize(), + ProtoExtensions.match(None, "extensions 1, 5, 2, 42;").node.serialize(), "extensions 1, 5, 2, 42;", ) def test_extension_with_max(self): self.assertEqual( - ProtoExtensions.match("extensions 8 to max;").node.serialize(), + ProtoExtensions.match(None, "extensions 8 to max;").node.serialize(), "extensions 8 to max;", ) def test_extension_cannot_have_strings(self): - self.assertIsNone(ProtoExtensions.match("extensions 1, 'foo';")) - self.assertIsNone(ProtoExtensions.match("extensions 'bar';")) + self.assertIsNone(ProtoExtensions.match(None, "extensions 1, 'foo';")) + self.assertIsNone(ProtoExtensions.match(None, "extensions 'bar';")) if __name__ == "__main__": diff --git a/test/proto_float_test.py b/test/proto_float_test.py index fa3fde7..28eb34e 100644 --- a/test/proto_float_test.py +++ b/test/proto_float_test.py @@ -6,78 +6,88 @@ class FloatTest(unittest.TestCase): def test_float(self): self.assertEqual( - ProtoFloat.match("2834.235928").node, - ProtoFloat(2834.235928, ProtoFloatSign.POSITIVE), + ProtoFloat.match(None, "2834.235928").node, + ProtoFloat(None, 2834.235928, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(".0").node, ProtoFloat(0.0, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, ".0").node, + ProtoFloat(None, 0.0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(".3265").node, ProtoFloat(0.3265, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, ".3265").node, + ProtoFloat(None, 0.3265, ProtoFloatSign.POSITIVE), ) def test_inf(self): self.assertEqual( - ProtoFloat.match("inf").node, - ProtoFloat(float("inf"), ProtoFloatSign.POSITIVE), + ProtoFloat.match(None, "inf").node, + ProtoFloat(None, float("inf"), ProtoFloatSign.POSITIVE), ) def test_nan(self): - match = ProtoFloat.match("nan") + match = ProtoFloat.match(None, "nan") self.assertNotEqual(match.node.value, match.node.value) self.assertEqual(match.remaining_source, "") self.assertEqual(match.node.sign, ProtoFloatSign.POSITIVE) def test_exponential_positive(self): self.assertEqual( - ProtoFloat.match("2834.e2").node, - ProtoFloat(283400, ProtoFloatSign.POSITIVE), + ProtoFloat.match(None, "2834.e2").node, + ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match("2834e2").node, ProtoFloat(283400, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, "2834e2").node, + ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match("2834.e0").node, ProtoFloat(2834, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, "2834.e0").node, + ProtoFloat(None, 2834, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match("2834e0").node, ProtoFloat(2834, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, "2834e0").node, + ProtoFloat(None, 2834, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match("2834.E3").node, - ProtoFloat(2834000, ProtoFloatSign.POSITIVE), + ProtoFloat.match(None, "2834.E3").node, + ProtoFloat(None, 2834000, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match("2834E3").node, - ProtoFloat(2834000, ProtoFloatSign.POSITIVE), + ProtoFloat.match(None, "2834E3").node, + ProtoFloat(None, 2834000, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match("2834.e+2").node, - ProtoFloat(283400, ProtoFloatSign.POSITIVE), + ProtoFloat.match(None, "2834.e+2").node, + ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match("2834e+2").node, - ProtoFloat(283400, ProtoFloatSign.POSITIVE), + ProtoFloat.match(None, "2834e+2").node, + ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(".0E1").node, ProtoFloat(0, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, ".0E1").node, + ProtoFloat(None, 0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(".0E2").node, ProtoFloat(0, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, ".0E2").node, + ProtoFloat(None, 0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(".3265e1").node, ProtoFloat(3.265, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, ".3265e1").node, + ProtoFloat(None, 3.265, ProtoFloatSign.POSITIVE), ) def test_exponential_negative(self): self.assertEqual( - ProtoFloat.match("2834.e-2").node, - ProtoFloat(28.34, ProtoFloatSign.POSITIVE), + ProtoFloat.match(None, "2834.e-2").node, + ProtoFloat(None, 28.34, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match("2834e-2").node, ProtoFloat(28.34, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, "2834e-2").node, + ProtoFloat(None, 28.34, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(".0e-1").node, ProtoFloat(0.00, ProtoFloatSign.POSITIVE) + ProtoFloat.match(None, ".0e-1").node, + ProtoFloat(None, 0.00, ProtoFloatSign.POSITIVE), ) diff --git a/test/proto_identifier_test.py b/test/proto_identifier_test.py index e174296..d1f44d3 100644 --- a/test/proto_identifier_test.py +++ b/test/proto_identifier_test.py @@ -10,88 +10,99 @@ class IdentifierTest(unittest.TestCase): def test_ident(self): - self.assertEqual(ProtoIdentifier.match("a").node.identifier, "a") - self.assertEqual(ProtoIdentifier.match("a0").node.identifier, "a0") - self.assertEqual(ProtoIdentifier.match("a_").node.identifier, "a_") - self.assertEqual(ProtoIdentifier.match("aa").node.identifier, "aa") - self.assertEqual(ProtoIdentifier.match("ab").node.identifier, "ab") - self.assertEqual(ProtoIdentifier.match("a0b_f_aj").node.identifier, "a0b_f_aj") + self.assertEqual(ProtoIdentifier.match(None, "a").node.identifier, "a") + self.assertEqual(ProtoIdentifier.match(None, "a0").node.identifier, "a0") + self.assertEqual(ProtoIdentifier.match(None, "a_").node.identifier, "a_") + self.assertEqual(ProtoIdentifier.match(None, "aa").node.identifier, "aa") + self.assertEqual(ProtoIdentifier.match(None, "ab").node.identifier, "ab") + self.assertEqual( + ProtoIdentifier.match(None, "a0b_f_aj").node.identifier, "a0b_f_aj" + ) def test_ident_no_leading_letter(self): - self.assertIsNone(ProtoIdentifier.match("0")) - self.assertIsNone(ProtoIdentifier.match("0abc_ab")) - self.assertIsNone(ProtoIdentifier.match("0_ab_0a_a0")) - self.assertIsNone(ProtoIdentifier.match(" ")) - self.assertIsNone(ProtoIdentifier.match(" abc")) - self.assertIsNone(ProtoIdentifier.match("\nabc")) - self.assertIsNone(ProtoIdentifier.match("\n abc")) - self.assertIsNone(ProtoIdentifier.match("\tabc")) - self.assertIsNone(ProtoIdentifier.match("\n\tabc")) - self.assertIsNone(ProtoIdentifier.match("\t\nabc")) - self.assertIsNone(ProtoIdentifier.match("\t\n abc")) - self.assertIsNone(ProtoIdentifier.match(".a")) - self.assertIsNone(ProtoIdentifier.match(" .a")) - self.assertIsNone(ProtoIdentifier.match(".")) - self.assertIsNone(ProtoIdentifier.match(".0")) + self.assertIsNone(ProtoIdentifier.match(None, "0")) + self.assertIsNone(ProtoIdentifier.match(None, "0abc_ab")) + self.assertIsNone(ProtoIdentifier.match(None, "0_ab_0a_a0")) + self.assertIsNone(ProtoIdentifier.match(None, " ")) + self.assertIsNone(ProtoIdentifier.match(None, " abc")) + self.assertIsNone(ProtoIdentifier.match(None, "\nabc")) + self.assertIsNone(ProtoIdentifier.match(None, "\n abc")) + self.assertIsNone(ProtoIdentifier.match(None, "\tabc")) + self.assertIsNone(ProtoIdentifier.match(None, "\n\tabc")) + self.assertIsNone(ProtoIdentifier.match(None, "\t\nabc")) + self.assertIsNone(ProtoIdentifier.match(None, "\t\n abc")) + self.assertIsNone(ProtoIdentifier.match(None, ".a")) + self.assertIsNone(ProtoIdentifier.match(None, " .a")) + self.assertIsNone(ProtoIdentifier.match(None, ".")) + self.assertIsNone(ProtoIdentifier.match(None, ".0")) def test_full_ident(self): - self.assertEqual(ProtoFullIdentifier.match("a").node.identifier, "a") - self.assertEqual(ProtoFullIdentifier.match("a.bar").node.identifier, "a.bar") + self.assertEqual(ProtoFullIdentifier.match(None, "a").node.identifier, "a") + self.assertEqual( + ProtoFullIdentifier.match(None, "a.bar").node.identifier, "a.bar" + ) self.assertEqual( - ProtoFullIdentifier.match("a.bar.baz").node.identifier, "a.bar.baz" + ProtoFullIdentifier.match(None, "a.bar.baz").node.identifier, "a.bar.baz" ) self.assertEqual( - ProtoFullIdentifier.match("a.bar.b0").node.identifier, "a.bar.b0" + ProtoFullIdentifier.match(None, "a.bar.b0").node.identifier, "a.bar.b0" ) self.assertEqual( - ProtoFullIdentifier.match("a.bar.b0.c_2a").node.identifier, "a.bar.b0.c_2a" + ProtoFullIdentifier.match(None, "a.bar.b0.c_2a").node.identifier, + "a.bar.b0.c_2a", ) def test_full_ident_invalid_periods(self): with self.assertRaises(ValueError): - ProtoFullIdentifier.match("a.") + ProtoFullIdentifier.match(None, "a.") with self.assertRaises(ValueError): - ProtoFullIdentifier.match("a.bar.") + ProtoFullIdentifier.match(None, "a.bar.") with self.assertRaises(ValueError): - ProtoFullIdentifier.match("a..") + ProtoFullIdentifier.match(None, "a..") def test_message_type(self): - self.assertEqual(ProtoEnumOrMessageIdentifier.match("a").node.identifier, "a") - self.assertEqual(ProtoEnumOrMessageIdentifier.match(".a").node.identifier, ".a") self.assertEqual( - ProtoEnumOrMessageIdentifier.match(".a.bar").node.identifier, ".a.bar" + ProtoEnumOrMessageIdentifier.match(None, "a").node.identifier, "a" + ) + self.assertEqual( + ProtoEnumOrMessageIdentifier.match(None, ".a").node.identifier, ".a" + ) + self.assertEqual( + ProtoEnumOrMessageIdentifier.match(None, ".a.bar").node.identifier, ".a.bar" ) self.assertEqual( - ProtoEnumOrMessageIdentifier.match("a.bar").node.identifier, "a.bar" + ProtoEnumOrMessageIdentifier.match(None, "a.bar").node.identifier, "a.bar" ) def test_identifier_serialize(self): - self.assertEqual(ProtoIdentifier.match("a").node.serialize(), "a") - self.assertEqual(ProtoIdentifier.match("a0").node.serialize(), "a0") + self.assertEqual(ProtoIdentifier.match(None, "a").node.serialize(), "a") + self.assertEqual(ProtoIdentifier.match(None, "a0").node.serialize(), "a0") self.assertEqual( - ProtoIdentifier.match("a_").node.serialize(), + ProtoIdentifier.match(None, "a_").node.serialize(), "a_", ) self.assertEqual( - ProtoIdentifier.match("a0_foo_ba0_0baz").node.serialize(), + ProtoIdentifier.match(None, "a0_foo_ba0_0baz").node.serialize(), "a0_foo_ba0_0baz", ) self.assertEqual( - ProtoFullIdentifier.match("a.bar").node.serialize(), + ProtoFullIdentifier.match(None, "a.bar").node.serialize(), "a.bar", ) self.assertEqual( - ProtoFullIdentifier.match("a.bar_baz.foo0").node.serialize(), + ProtoFullIdentifier.match(None, "a.bar_baz.foo0").node.serialize(), "a.bar_baz.foo0", ) self.assertEqual( - ProtoEnumOrMessageIdentifier.match(".a").node.serialize(), + ProtoEnumOrMessageIdentifier.match(None, ".a").node.serialize(), ".a", ) self.assertEqual( - ProtoEnumOrMessageIdentifier.match(".a.bar0_baz.foo").node.serialize(), + ProtoEnumOrMessageIdentifier.match( + None, ".a.bar0_baz.foo" + ).node.serialize(), ".a.bar0_baz.foo", ) diff --git a/test/proto_import_test.py b/test/proto_import_test.py index 0ea8ffb..994ec22 100644 --- a/test/proto_import_test.py +++ b/test/proto_import_test.py @@ -13,14 +13,14 @@ class ImportTest(unittest.TestCase): def test_bare_import(self): - double_quote_import = ProtoImport.match('import "foo.proto";') + double_quote_import = ProtoImport.match(None, 'import "foo.proto";') self.assertEqual(double_quote_import.node.path.value, "foo.proto") self.assertEqual(double_quote_import.node.weak, False) self.assertEqual(double_quote_import.node.public, False) self.assertEqual(double_quote_import.node.serialize(), 'import "foo.proto";') self.assertEqual(double_quote_import.remaining_source, "") - single_quote_import = ProtoImport.match("import 'foo.proto';") + single_quote_import = ProtoImport.match(None, "import 'foo.proto';") self.assertEqual(single_quote_import.node.path.value, "foo.proto") self.assertEqual(single_quote_import.node.weak, False) self.assertEqual(single_quote_import.node.public, False) @@ -29,29 +29,29 @@ def test_bare_import(self): def test_import_missing_semicolon(self): with self.assertRaises(ValueError): - ProtoImport.match('import "foo.proto"') + ProtoImport.match(None, 'import "foo.proto"') def test_import_missing_starting_quote(self): with self.assertRaises(ValueError): - ProtoImport.match('import foo.proto";') + ProtoImport.match(None, 'import foo.proto";') with self.assertRaises(ValueError): - ProtoImport.match("import foo.proto';") + ProtoImport.match(None, "import foo.proto';") def test_import_missing_ending_quote(self): with self.assertRaises(ValueError): - ProtoImport.match('import "foo.proto;') + ProtoImport.match(None, 'import "foo.proto;') with self.assertRaises(ValueError): - ProtoImport.match("import 'foo.proto;") + ProtoImport.match(None, "import 'foo.proto;") def test_weak_import(self): - double_quote_import = ProtoImport.match('import weak "foo.proto";') + double_quote_import = ProtoImport.match(None, 'import weak "foo.proto";') self.assertEqual(double_quote_import.node.weak, True) self.assertEqual( double_quote_import.node.serialize(), 'import weak "foo.proto";' ) - double_quote_import = ProtoImport.match("import weak 'foo.proto';") + double_quote_import = ProtoImport.match(None, "import weak 'foo.proto';") self.assertEqual(double_quote_import.node.weak, True) self.assertEqual( double_quote_import.node.serialize(), "import weak 'foo.proto';" @@ -59,40 +59,45 @@ def test_weak_import(self): def test_weak_typoed_import(self): with self.assertRaises(ValueError): - ProtoImport.match('import weac "foo.proto";') + ProtoImport.match(None, 'import weac "foo.proto";') def test_weak_mixed_imports(self): first_parsed_import = ProtoImport.match( + None, dedent( """import "foo.proto"; import weak "bar/baz.proto"; import "bat.proto";""" - ) + ), ) self.assertEqual(first_parsed_import.node.path.value, "foo.proto") self.assertEqual(first_parsed_import.node.weak, False) self.assertEqual(first_parsed_import.node.serialize(), 'import "foo.proto";') - second_parsed_import = ProtoImport.match(first_parsed_import.remaining_source) + second_parsed_import = ProtoImport.match( + None, first_parsed_import.remaining_source + ) self.assertEqual(second_parsed_import.node.path.value, "bar/baz.proto") self.assertEqual(second_parsed_import.node.weak, True) self.assertEqual( second_parsed_import.node.serialize(), 'import weak "bar/baz.proto";' ) - third_parsed_import = ProtoImport.match(second_parsed_import.remaining_source) + third_parsed_import = ProtoImport.match( + None, second_parsed_import.remaining_source + ) self.assertEqual(third_parsed_import.node.path.value, "bat.proto") self.assertEqual(third_parsed_import.node.weak, False) self.assertEqual(third_parsed_import.node.serialize(), 'import "bat.proto";') def test_public_import(self): - double_quote_import = ProtoImport.match('import public "foo.proto";') + double_quote_import = ProtoImport.match(None, 'import public "foo.proto";') self.assertEqual(double_quote_import.node.public, True) self.assertEqual( double_quote_import.node.serialize(), 'import public "foo.proto";' ) - single_quote_import = ProtoImport.match("import public 'foo.proto';") + single_quote_import = ProtoImport.match(None, "import public 'foo.proto';") self.assertEqual(single_quote_import.node.public, True) self.assertEqual( single_quote_import.node.serialize(), "import public 'foo.proto';" @@ -100,35 +105,40 @@ def test_public_import(self): def test_public_typoed_import(self): with self.assertRaises(ValueError): - ProtoImport.match('import publik "foo.proto";') + ProtoImport.match(None, 'import publik "foo.proto";') def test_public_weak_mutually_exclusive(self): with self.assertRaises(ValueError): - ProtoImport.match('import weak public "foo.proto";') + ProtoImport.match(None, 'import weak public "foo.proto";') with self.assertRaises(ValueError): - ProtoImport.match('import public weak "foo.proto";') + ProtoImport.match(None, 'import public weak "foo.proto";') def test_public_mixed_imports(self): first_parsed_import = ProtoImport.match( + None, dedent( """import "foo.proto"; import public "bar/baz.proto"; import public "bat.proto";""" - ) + ), ) self.assertEqual(first_parsed_import.node.path.value, "foo.proto") self.assertEqual(first_parsed_import.node.public, False) self.assertEqual(first_parsed_import.node.serialize(), 'import "foo.proto";') - second_parsed_import = ProtoImport.match(first_parsed_import.remaining_source) + second_parsed_import = ProtoImport.match( + None, first_parsed_import.remaining_source + ) self.assertEqual(second_parsed_import.node.path.value, "bar/baz.proto") self.assertEqual(second_parsed_import.node.public, True) self.assertEqual( second_parsed_import.node.serialize(), 'import public "bar/baz.proto";' ) - third_parsed_import = ProtoImport.match(second_parsed_import.remaining_source) + third_parsed_import = ProtoImport.match( + None, second_parsed_import.remaining_source + ) self.assertEqual(third_parsed_import.node.path.value, "bat.proto") self.assertEqual(third_parsed_import.node.public, True) self.assertEqual( @@ -136,21 +146,21 @@ def test_public_mixed_imports(self): ) def test_diff_sets_same_path_simple(self): - pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) - pf2 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + pf1 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) + pf2 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) self.assertEqual(ProtoImport.diff_sets([pf1], [pf2]), []) def test_diff_sets_added_path_simple(self): - pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + pf1 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) self.assertEqual(ProtoImport.diff_sets([pf1], []), [ProtoImportAdded(pf1)]) def test_diff_sets_removed_path_simple(self): - pf2 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + pf2 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) self.assertEqual(ProtoImport.diff_sets([], [pf2]), [ProtoImportRemoved(pf2)]) def test_diff_sets_different_path_simple(self): - pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) - pf2 = ProtoImport(ProtoStringLiteral("path/to/some/other.proto")) + pf1 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) + pf2 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some/other.proto")) self.assertEqual( ProtoImport.diff_sets([pf1], [pf2]), [ProtoImportAdded(pf1), ProtoImportRemoved(pf2)], @@ -158,10 +168,16 @@ def test_diff_sets_different_path_simple(self): def test_diff_sets_changed_optional_attributes(self): pf1 = ProtoImport( - ProtoStringLiteral("path/to/some.proto"), weak=False, public=True + None, + ProtoStringLiteral(None, "path/to/some.proto"), + weak=False, + public=True, ) pf2 = ProtoImport( - ProtoStringLiteral("path/to/some.proto"), weak=True, public=False + None, + ProtoStringLiteral(None, "path/to/some.proto"), + weak=True, + public=False, ) self.assertEqual( ProtoImport.diff_sets([pf1], [pf2]), diff --git a/test/proto_int_test.py b/test/proto_int_test.py index 3293d5e..0aaf7f7 100644 --- a/test/proto_int_test.py +++ b/test/proto_int_test.py @@ -5,31 +5,33 @@ class IntTest(unittest.TestCase): def test_int(self): - self.assertEqual(ProtoInt.match("1").node, ProtoInt(1, ProtoIntSign.POSITIVE)) self.assertEqual( - ProtoInt.match("158912938471293847").node, - ProtoInt(158912938471293847, ProtoIntSign.POSITIVE), + ProtoInt.match(None, "1").node, ProtoInt(None, 1, ProtoIntSign.POSITIVE) + ) + self.assertEqual( + ProtoInt.match(None, "158912938471293847").node, + ProtoInt(None, 158912938471293847, ProtoIntSign.POSITIVE), ) def test_octal(self): self.assertEqual( - ProtoInt.match("072342").node, - ProtoInt(0o72342, ProtoIntSign.POSITIVE), + ProtoInt.match(None, "072342").node, + ProtoInt(None, 0o72342, ProtoIntSign.POSITIVE), ) with self.assertRaises(ValueError): - ProtoInt.match("072942") + ProtoInt.match(None, "072942") def test_hex(self): self.assertEqual( - ProtoInt.match("0x72342").node, - ProtoInt(0x72342, ProtoIntSign.POSITIVE), + ProtoInt.match(None, "0x72342").node, + ProtoInt(None, 0x72342, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoInt.match("0x7A3d2").node, - ProtoInt(0x7A3D2, ProtoIntSign.POSITIVE), + ProtoInt.match(None, "0x7A3d2").node, + ProtoInt(None, 0x7A3D2, ProtoIntSign.POSITIVE), ) with self.assertRaises(ValueError): - ProtoInt.match("0x72G42") + ProtoInt.match(None, "0x72G42") if __name__ == "__main__": diff --git a/test/proto_message_field_test.py b/test/proto_message_field_test.py index 8692322..eb64ca3 100644 --- a/test/proto_message_field_test.py +++ b/test/proto_message_field_test.py @@ -13,13 +13,14 @@ class MessageFieldTest(unittest.TestCase): maxDiff = None def test_field_optional_default_false(self): - string_field = ProtoMessageField.match("string single_field = 1;") + string_field = ProtoMessageField.match(None, "string single_field = 1;") self.assertEqual( string_field.node, ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("single_field"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "single_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), False, False, ), @@ -27,14 +28,15 @@ def test_field_optional_default_false(self): def test_field_optional_set(self): string_field = ProtoMessageField.match( - "optional string single_field = 1;".strip() + None, "optional string single_field = 1;".strip() ) self.assertEqual( string_field.node, ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("single_field"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "single_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), False, True, ), @@ -43,77 +45,85 @@ def test_field_optional_set(self): def test_field_cannot_have_repeated_and_optional(self): with self.assertRaises(ValueError): ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("single_field"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "single_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), True, True, ) def test_message_field_starts_with_underscore(self): - parsed_undescored_field = ProtoMessageField.match("string _test_field = 1;") + parsed_undescored_field = ProtoMessageField.match( + None, "string _test_field = 1;" + ) self.assertEqual( parsed_undescored_field.node, ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("_test_field"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "_test_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), ) parsed_double_undescored_field = ProtoMessageField.match( - "bool __test_field = 1;" + None, "bool __test_field = 1;" ) self.assertEqual( parsed_double_undescored_field.node, ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("__test_field"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "__test_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), ) def test_field_repeated(self): parsed_message_with_repeated_field_simple = ProtoMessageField.match( - "repeated bool repeated_field = 3;" + None, "repeated bool repeated_field = 3;" ) self.assertEqual( parsed_message_with_repeated_field_simple.node, ProtoMessageField( + None, ProtoMessageFieldTypesEnum.BOOL, - ProtoIdentifier("repeated_field"), - ProtoInt(3, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "repeated_field"), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), True, ), ) def test_field_enum_or_message(self): parsed_message_with_repeated_field_simple = ProtoMessageField.match( - "foo.SomeEnumOrMessage enum_or_message_field = 1;" + None, "foo.SomeEnumOrMessage enum_or_message_field = 1;" ) self.assertEqual( parsed_message_with_repeated_field_simple.node, ProtoMessageField( + None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("enum_or_message_field"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "enum_or_message_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier("foo.SomeEnumOrMessage"), + ProtoFullIdentifier(None, "foo.SomeEnumOrMessage"), ), ) def test_field_starts_with_period(self): parsed_field_with_type_starting_with_period = ProtoMessageField.match( - ".google.proto.FooType enum_or_message_field = 1;" + None, ".google.proto.FooType enum_or_message_field = 1;" ) self.assertEqual( parsed_field_with_type_starting_with_period.node, ProtoMessageField( + None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("enum_or_message_field"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "enum_or_message_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), False, False, - ProtoEnumOrMessageIdentifier(".google.proto.FooType"), + ProtoEnumOrMessageIdentifier(None, ".google.proto.FooType"), ), ) diff --git a/test/proto_message_test.py b/test/proto_message_test.py index 0812498..3153c72 100644 --- a/test/proto_message_test.py +++ b/test/proto_message_test.py @@ -38,6 +38,7 @@ class MessageTest(unittest.TestCase): def test_message_all_features(self): parsed_message_multiple_fields = ProtoMessage.match( + None, dedent( """ message FooMessage { @@ -63,125 +64,158 @@ def test_message_all_features(self): extensions 8 to max; } """.strip() - ) + ), ) self.assertEqual( parsed_message_multiple_fields.node.nodes, [ ProtoOption( - ProtoIdentifier("(foo.bar).baz"), - ProtoConstant(ProtoStringLiteral("bat")), + None, + ProtoIdentifier(None, "(foo.bar).baz"), + ProtoConstant(None, ProtoStringLiteral(None, "bat")), ), ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_UNDEFINED"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "ME_UNDEFINED"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - ProtoIdentifier("ME_VALONE"), - ProtoInt(1, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "ME_VALONE"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - ProtoIdentifier("ME_VALTWO"), - ProtoInt(2, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "ME_VALTWO"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), ), ], ), - ProtoMessage(ProtoIdentifier("NestedMessage"), []), - ProtoReserved(fields=[ProtoIdentifier("a")]), + ProtoMessage(None, ProtoIdentifier(None, "NestedMessage"), []), + ProtoReserved(None, fields=[ProtoIdentifier(None, "a")]), ProtoReserved( + None, ranges=[ ProtoRange( - ProtoInt(1, ProtoIntSign.POSITIVE), - ProtoInt(3, ProtoIntSign.POSITIVE), + None, + ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), ) - ] + ], ), - ProtoSingleLineComment(" single-line comment"), + ProtoSingleLineComment(None, " single-line comment"), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("some_field"), - ProtoInt(4, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "some_field"), + ProtoInt(None, 4, ProtoIntSign.POSITIVE), True, False, None, [ ProtoMessageFieldOption( - ProtoIdentifier("(bar.baz).bat"), - ProtoConstant(ProtoStringLiteral("bat")), + None, + ProtoIdentifier(None, "(bar.baz).bat"), + ProtoConstant(None, ProtoStringLiteral(None, "bat")), ), ProtoMessageFieldOption( - ProtoIdentifier("baz.bat"), - ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), + None, + ProtoIdentifier(None, "baz.bat"), + ProtoConstant( + None, ProtoInt(None, 100, ProtoIntSign.NEGATIVE) + ), ), ], ), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.BOOL, - ProtoIdentifier("some_bool_field"), - ProtoInt(5, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "some_bool_field"), + ProtoInt(None, 5, ProtoIntSign.POSITIVE), ), ProtoOneOf( - ProtoIdentifier("one_of_field"), + None, + ProtoIdentifier(None, "one_of_field"), [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "name"), + ProtoInt(None, 4, ProtoIntSign.POSITIVE), ), ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant( + None, ProtoStringLiteral(None, "com.example.foo") + ), ), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("sub_message"), - ProtoInt(9, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "sub_message"), + ProtoInt(None, 9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier("SubMessage"), + ProtoFullIdentifier(None, "SubMessage"), [ ProtoMessageFieldOption( - ProtoIdentifier("(bar.baz).bat"), - ProtoConstant(ProtoStringLiteral("bat")), + None, + ProtoIdentifier(None, "(bar.baz).bat"), + ProtoConstant( + None, ProtoStringLiteral(None, "bat") + ), ), ProtoMessageFieldOption( - ProtoIdentifier("baz.bat"), - ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), + None, + ProtoIdentifier(None, "baz.bat"), + ProtoConstant( + None, ProtoInt(None, 100, ProtoIntSign.NEGATIVE) + ), ), ], ), ], ), ProtoMap( + None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("my_map"), - ProtoInt(10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier("NestedMessage"), + ProtoIdentifier(None, "my_map"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier(None, "NestedMessage"), [], ), ProtoMap( + None, # map string_map = 11 [ java_package = "com.example.foo", baz.bat = 48 ]; ProtoMapKeyTypesEnum.STRING, ProtoMapValueTypesEnum.STRING, - ProtoIdentifier("string_map"), - ProtoInt(11, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "string_map"), + ProtoInt(None, 11, ProtoIntSign.POSITIVE), None, [ ProtoMessageFieldOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant( + None, ProtoStringLiteral(None, "com.example.foo") + ), ), ProtoMessageFieldOption( - ProtoFullIdentifier("baz.bat"), - ProtoConstant(ProtoInt(48, ProtoIntSign.POSITIVE)), + None, + ProtoFullIdentifier(None, "baz.bat"), + ProtoConstant( + None, ProtoInt(None, 48, ProtoIntSign.POSITIVE) + ), ), ], ), - ProtoExtensions([ProtoRange(8, ProtoRangeEnum.MAX)]), + ProtoExtensions(None, [ProtoRange(None, 8, ProtoRangeEnum.MAX)]), ], ) self.assertEqual( @@ -216,24 +250,30 @@ def test_message_all_features(self): ) def test_empty_message(self): - parsed_empty_message = ProtoMessage.match("""message FooMessage {}""") + parsed_empty_message = ProtoMessage.match(None, """message FooMessage {}""") self.assertIsNotNone(parsed_empty_message) - self.assertEqual(parsed_empty_message.node.name, ProtoIdentifier("FooMessage")) + self.assertEqual( + parsed_empty_message.node.name, ProtoIdentifier(None, "FooMessage") + ) parsed_spaced_message = ProtoMessage.match( + None, dedent( """ message FooMessage { } """.strip() - ) + ), ) self.assertIsNotNone(parsed_spaced_message) - self.assertEqual(parsed_spaced_message.node.name, ProtoIdentifier("FooMessage")) + self.assertEqual( + parsed_spaced_message.node.name, ProtoIdentifier(None, "FooMessage") + ) def test_message_empty_statements(self): empty_statement_message = ProtoMessage.match( + None, dedent( """ message FooMessage { @@ -241,15 +281,16 @@ def test_message_empty_statements(self): ; } """.strip() - ) + ), ) self.assertIsNotNone(empty_statement_message) self.assertEqual( - empty_statement_message.node.name, ProtoIdentifier("FooMessage") + empty_statement_message.node.name, ProtoIdentifier(None, "FooMessage") ) def test_message_optionals(self): parsed_message_with_optionals = ProtoMessage.match( + None, dedent( """ message FooMessage { @@ -257,27 +298,30 @@ def test_message_optionals(self): option (foo.bar).baz = false; } """.strip() - ) + ), ) self.assertIsNotNone( parsed_message_with_optionals.node.options, [ ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foobar")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foobar")), ), ProtoOption( - ProtoIdentifier("(foo.bar).baz"), - ProtoConstant(ProtoBool(False)), + None, + ProtoIdentifier(None, "(foo.bar).baz"), + ProtoConstant(None, ProtoBool(None, False)), ), ], ) self.assertEqual( - parsed_message_with_optionals.node.name, ProtoIdentifier("FooMessage") + parsed_message_with_optionals.node.name, ProtoIdentifier(None, "FooMessage") ) def test_message_nested_enum(self): parsed_message_with_enum = ProtoMessage.match( + None, dedent( """ message FooMessage { @@ -288,27 +332,32 @@ def test_message_nested_enum(self): } } """.strip() - ) + ), ) self.assertEqual( parsed_message_with_enum.node, ProtoMessage( - ProtoIdentifier("FooMessage"), + None, + ProtoIdentifier(None, "FooMessage"), [ ProtoEnum( - ProtoIdentifier("MyEnum"), + None, + ProtoIdentifier(None, "MyEnum"), [ ProtoEnumValue( - ProtoIdentifier("ME_UNDEFINED"), - ProtoInt(0, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "ME_UNDEFINED"), + ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - ProtoIdentifier("ME_NEGATIVE"), - ProtoInt(1, ProtoIntSign.NEGATIVE), + None, + ProtoIdentifier(None, "ME_NEGATIVE"), + ProtoInt(None, 1, ProtoIntSign.NEGATIVE), ), ProtoEnumValue( - ProtoIdentifier("ME_VALONE"), - ProtoInt(1, ProtoIntSign.POSITIVE), + None, + ProtoIdentifier(None, "ME_VALONE"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), ], ) @@ -318,26 +367,29 @@ def test_message_nested_enum(self): def test_message_nested_message(self): parsed_message_with_enum = ProtoMessage.match( + None, dedent( """ message FooMessage { message NestedMessage {} } """.strip() - ) + ), ) self.assertEqual( parsed_message_with_enum.node, ProtoMessage( - ProtoIdentifier("FooMessage"), + None, + ProtoIdentifier(None, "FooMessage"), [ - ProtoMessage(ProtoIdentifier("NestedMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "NestedMessage"), []), ], ), ) def test_message_reserved_single_field(self): parsed_message_with_reserved_single_field = ProtoMessage.match( + None, dedent( """ message FooMessage { @@ -345,31 +397,36 @@ def test_message_reserved_single_field(self): reserved "foo", "barBaz"; } """.strip() - ) + ), ) self.assertEqual( parsed_message_with_reserved_single_field.node, ProtoMessage( - ProtoIdentifier("FooMessage"), + None, + ProtoIdentifier(None, "FooMessage"), [ ProtoReserved( + None, ranges=[ - ProtoRange(ProtoInt(38, ProtoIntSign.POSITIVE)), + ProtoRange(None, ProtoInt(None, 38, ProtoIntSign.POSITIVE)), ProtoRange( - ProtoInt(48, ProtoIntSign.POSITIVE), - ProtoInt(100, ProtoIntSign.POSITIVE), + None, + ProtoInt(None, 48, ProtoIntSign.POSITIVE), + ProtoInt(None, 100, ProtoIntSign.POSITIVE), ), ProtoRange( - ProtoInt(72, ProtoIntSign.POSITIVE), + None, + ProtoInt(None, 72, ProtoIntSign.POSITIVE), ProtoRangeEnum.MAX, ), - ] + ], ), ProtoReserved( + None, fields=[ - ProtoIdentifier("foo"), - ProtoIdentifier("barBaz"), - ] + ProtoIdentifier(None, "foo"), + ProtoIdentifier(None, "barBaz"), + ], ), ], ), @@ -377,81 +434,93 @@ def test_message_reserved_single_field(self): def test_message_simple_field(self): parsed_message_with_single_field_simple = ProtoMessage.match( + None, dedent( """ message FooMessage { string single_field = 1; } """.strip() - ) + ), ) self.assertEqual( parsed_message_with_single_field_simple.node, ProtoMessage( - ProtoIdentifier("FooMessage"), + None, + ProtoIdentifier(None, "FooMessage"), [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("single_field"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "single_field"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ) ], ), ) def test_oneof_empty(self): - parsed_oneof_empty = ProtoOneOf.match(dedent("oneof one_of_field {}".strip())) + parsed_oneof_empty = ProtoOneOf.match( + None, dedent("oneof one_of_field {}".strip()) + ) self.assertEqual( parsed_oneof_empty.node, ProtoOneOf( - ProtoIdentifier("one_of_field"), + None, + ProtoIdentifier(None, "one_of_field"), [], ), ) def test_oneof_empty_statements(self): parsed_oneof_empty = ProtoOneOf.match( + None, dedent( """oneof one_of_field { ; ; }""".strip() - ) + ), ) self.assertEqual( parsed_oneof_empty.node, ProtoOneOf( - ProtoIdentifier("one_of_field"), + None, + ProtoIdentifier(None, "one_of_field"), [], ), ) def test_oneof_basic_fields(self): parsed_oneof_basic_fields = ProtoOneOf.match( + None, dedent( """oneof one_of_field { string name = 4; SubMessage sub_message = 9; }""".strip() - ) + ), ) self.assertEqual( parsed_oneof_basic_fields.node, ProtoOneOf( - ProtoIdentifier("one_of_field"), + None, + ProtoIdentifier(None, "one_of_field"), [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "name"), + ProtoInt(None, 4, ProtoIntSign.POSITIVE), ), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("sub_message"), - ProtoInt(9, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "sub_message"), + ProtoInt(None, 9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier("SubMessage"), + ProtoFullIdentifier(None, "SubMessage"), [], ), ], @@ -460,20 +529,25 @@ def test_oneof_basic_fields(self): def test_oneof_options(self): parsed_oneof_options = ProtoOneOf.match( + None, dedent( """oneof one_of_field { option java_package = "com.example.foo"; }""".strip() - ) + ), ) self.assertEqual( parsed_oneof_options.node, ProtoOneOf( - ProtoIdentifier("one_of_field"), + None, + ProtoIdentifier(None, "one_of_field"), [ ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant( + None, ProtoStringLiteral(None, "com.example.foo") + ), ), ], ), @@ -481,32 +555,39 @@ def test_oneof_options(self): def test_oneof_field_option(self): parsed_oneof_field_option = ProtoOneOf.match( + None, dedent( """oneof one_of_field { string name = 4 [ (bar.baz).bat = "bat", baz.bat = -100 ]; }""".strip() - ) + ), ) self.assertEqual( parsed_oneof_field_option.node, ProtoOneOf( - ProtoIdentifier("one_of_field"), + None, + ProtoIdentifier(None, "one_of_field"), [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "name"), + ProtoInt(None, 4, ProtoIntSign.POSITIVE), False, False, None, [ ProtoMessageFieldOption( - ProtoIdentifier("(bar.baz).bat"), - ProtoConstant(ProtoStringLiteral("bat")), + None, + ProtoIdentifier(None, "(bar.baz).bat"), + ProtoConstant(None, ProtoStringLiteral(None, "bat")), ), ProtoMessageFieldOption( - ProtoIdentifier("baz.bat"), - ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), + None, + ProtoIdentifier(None, "baz.bat"), + ProtoConstant( + None, ProtoInt(None, 100, ProtoIntSign.NEGATIVE) + ), ), ], ) @@ -516,32 +597,36 @@ def test_oneof_field_option(self): def test_oneof_with_comment(self): parsed_oneof_with_comment = ProtoOneOf.match( + None, dedent( """oneof one_of_field { string name = 4; // single-line comment! SubMessage sub_message = 9; }""".strip() - ) + ), ) self.assertEqual( parsed_oneof_with_comment.node, ProtoOneOf( - ProtoIdentifier("one_of_field"), + None, + ProtoIdentifier(None, "one_of_field"), [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "name"), + ProtoInt(None, 4, ProtoIntSign.POSITIVE), ), - ProtoSingleLineComment(" single-line comment!"), + ProtoSingleLineComment(None, " single-line comment!"), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("sub_message"), - ProtoInt(9, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "sub_message"), + ProtoInt(None, 9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier("SubMessage"), + ProtoFullIdentifier(None, "SubMessage"), [], ), ], @@ -550,101 +635,116 @@ def test_oneof_with_comment(self): def test_oneof_normalize_removes_comment(self): normalized_oneof = ProtoOneOf.match( + None, dedent( """oneof one_of_field { string name = 4; // single-line comment! SubMessage sub_message = 9; }""".strip() - ) + ), ).node.normalize() self.assertEqual( normalized_oneof.nodes, [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "name"), + ProtoInt(None, 4, ProtoIntSign.POSITIVE), ), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("sub_message"), - ProtoInt(9, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "sub_message"), + ProtoInt(None, 9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier("SubMessage"), + ProtoFullIdentifier(None, "SubMessage"), [], ), ], ) def test_simple_map(self): - parsed_map_simple = ProtoMap.match("map my_map = 10;") + parsed_map_simple = ProtoMap.match( + None, "map my_map = 10;" + ) self.assertEqual( parsed_map_simple.node, ProtoMap( + None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("my_map"), - ProtoInt(10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier("NestedMessage"), + ProtoIdentifier(None, "my_map"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier(None, "NestedMessage"), [], ), ) def test_map_without_spaces(self): - map_without_spaces = ProtoMap.match("map my_map = 10;") + map_without_spaces = ProtoMap.match( + None, "map my_map = 10;" + ) self.assertEqual( map_without_spaces.node, ProtoMap( + None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("my_map"), - ProtoInt(10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier("NestedMessage"), + ProtoIdentifier(None, "my_map"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier(None, "NestedMessage"), [], ), ) def test_map_with_options(self): parsed_map_simple = ProtoMap.match( - "map my_map = 10 [ java_package = 'com.example.foo', baz.bat = 48 ];" + None, + "map my_map = 10 [ java_package = 'com.example.foo', baz.bat = 48 ];", ) self.assertEqual(parsed_map_simple.node.key_type, ProtoMapKeyTypesEnum.SFIXED64) self.assertEqual( parsed_map_simple.node.value_type, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE ) - self.assertEqual(parsed_map_simple.node.name, ProtoIdentifier("my_map")) + self.assertEqual(parsed_map_simple.node.name, ProtoIdentifier(None, "my_map")) self.assertEqual( - parsed_map_simple.node.number, ProtoInt(10, ProtoIntSign.POSITIVE) + parsed_map_simple.node.number, ProtoInt(None, 10, ProtoIntSign.POSITIVE) ) self.assertEqual( parsed_map_simple.node.enum_or_message_type_name, - ProtoEnumOrMessageIdentifier("NestedMessage"), + ProtoEnumOrMessageIdentifier(None, "NestedMessage"), ) self.assertEqual( parsed_map_simple.node.options, [ ProtoMessageFieldOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "com.example.foo")), ), ProtoMessageFieldOption( - ProtoFullIdentifier("baz.bat"), - ProtoConstant(ProtoInt(48, ProtoIntSign.POSITIVE)), + None, + ProtoFullIdentifier(None, "baz.bat"), + ProtoConstant(None, ProtoInt(None, 48, ProtoIntSign.POSITIVE)), ), ], ) def test_map_message_value(self): - parsed_map_simple = ProtoMap.match("map string_map = 11;") + parsed_map_simple = ProtoMap.match( + None, "map string_map = 11;" + ) self.assertEqual( parsed_map_simple.node, ProtoMap( + None, ProtoMapKeyTypesEnum.STRING, ProtoMapValueTypesEnum.STRING, - ProtoIdentifier("string_map"), - ProtoInt(11, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "string_map"), + ProtoInt(None, 11, ProtoIntSign.POSITIVE), None, [], ), @@ -652,6 +752,7 @@ def test_map_message_value(self): def test_message_parses_comments(self): parsed_comments = ProtoMessage.match( + None, dedent( """ message MyMessage { @@ -666,35 +767,40 @@ def test_message_parses_comments(self): string baz = 3; } """.strip() - ) + ), ) self.assertEqual( parsed_comments.node.nodes, [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("foo"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "foo"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), - ProtoSingleLineComment(" single-line comment!"), + ProtoSingleLineComment(None, " single-line comment!"), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.BOOL, - ProtoIdentifier("bar"), - ProtoInt(2, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "bar"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), ), ProtoMultiLineComment( - "\n multiple\n line\n comment!\n " + None, + "\n multiple\n line\n comment!\n ", ), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("baz"), - ProtoInt(3, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "baz"), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), ), ], ) def test_message_extends(self): parsed_extends = ProtoMessage.match( + None, dedent( """ message MyMessage { @@ -704,21 +810,26 @@ def test_message_extends(self): } } """.strip() - ) + ), ) self.assertEqual( parsed_extends.node.nodes, [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("foo"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "foo"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), ProtoExtend( - ProtoEnumOrMessageIdentifier("SomeOtherMessage"), + None, + ProtoEnumOrMessageIdentifier(None, "SomeOtherMessage"), [ ProtoMessageField( - ProtoMessageFieldTypesEnum.STRING, ProtoIdentifier("foo"), 2 + None, + ProtoMessageFieldTypesEnum.STRING, + ProtoIdentifier(None, "foo"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), ) ], ), @@ -727,6 +838,7 @@ def test_message_extends(self): def test_message_normalizes_away_comments(self): parsed_comments = ProtoMessage.match( + None, dedent( """ message MyMessage { @@ -741,68 +853,79 @@ def test_message_normalizes_away_comments(self): string baz = 3; } """.strip() - ) + ), ).node.normalize() self.assertEqual( parsed_comments.nodes, [ ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("foo"), - ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "foo"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.BOOL, - ProtoIdentifier("bar"), - ProtoInt(2, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "bar"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), ), ProtoMessageField( + None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("baz"), - ProtoInt(3, ProtoIntSign.POSITIVE), + ProtoIdentifier(None, "baz"), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), ), ], ) def test_diff_same_message_returns_empty(self): pm1 = ProtoMessage( - ProtoIdentifier("MyMessage"), + None, + ProtoIdentifier(None, "MyMessage"), [], ) pm2 = ProtoMessage( - ProtoIdentifier("MyMessage"), + None, + ProtoIdentifier(None, "MyMessage"), [], ) self.assertEqual(ProtoMessage.diff(pm1, pm2), []) def test_diff_different_message_name_returns_empty(self): pm1 = ProtoMessage( - ProtoIdentifier("MyMessage"), + None, + ProtoIdentifier(None, "MyMessage"), [], ) pm2 = ProtoMessage( - ProtoIdentifier("OtherMessage"), + None, + ProtoIdentifier(None, "OtherMessage"), [], ) self.assertEqual(ProtoMessage.diff(pm1, pm2), []) def test_diff_enum_added(self): pm1 = None - pm2 = ProtoMessage(ProtoIdentifier("MyMessage"), []) + pm2 = ProtoMessage(None, ProtoIdentifier(None, "MyMessage"), []) self.assertEqual( ProtoMessage.diff(pm1, pm2), [ - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("MyMessage"), [])), + ProtoMessageAdded( + ProtoMessage(None, ProtoIdentifier(None, "MyMessage"), []) + ), ], ) def test_diff_message_removed(self): - pm1 = ProtoMessage(ProtoIdentifier("MyMessage"), []) + pm1 = ProtoMessage(None, ProtoIdentifier(None, "MyMessage"), []) pm2 = None self.assertEqual( ProtoMessage.diff(pm1, pm2), [ - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("MyMessage"), [])), + ProtoMessageRemoved( + ProtoMessage(None, ProtoIdentifier(None, "MyMessage"), []) + ), ], ) @@ -813,107 +936,155 @@ def test_diff_sets_empty_returns_empty(self): def test_diff_sets_no_change_returns_empty(self): set1 = [ - ProtoMessage(ProtoIdentifier("FooMessage"), []), - ProtoMessage(ProtoIdentifier("BarMessage"), []), - ProtoMessage(ProtoIdentifier("BazMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), ] self.assertEqual(ProtoMessage.diff_sets(set1, set1), []) def test_diff_sets_all_removed(self): set1 = [] set2 = [ - ProtoMessage(ProtoIdentifier("FooMessage"), []), - ProtoMessage(ProtoIdentifier("BarMessage"), []), - ProtoMessage(ProtoIdentifier("BazMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), ] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff + ProtoMessageRemoved( + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) + ), + diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BarMessage"), [])), diff + ProtoMessageRemoved( + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []) + ), + diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff + ProtoMessageRemoved( + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) + ), + diff, ) self.assertEqual(3, len(diff)) def test_diff_sets_all_added(self): set1 = [ - ProtoMessage(ProtoIdentifier("FooMessage"), []), - ProtoMessage(ProtoIdentifier("BarMessage"), []), - ProtoMessage(ProtoIdentifier("BazMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), ] set2 = [] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff + ProtoMessageAdded( + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) + ), + diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BarMessage"), [])), diff + ProtoMessageAdded( + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []) + ), + diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff + ProtoMessageAdded( + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) + ), + diff, ) self.assertEqual(3, len(diff)) def test_diff_sets_mutually_exclusive(self): set1 = [ - ProtoMessage(ProtoIdentifier("FooMessage"), []), - ProtoMessage(ProtoIdentifier("BarMessage"), []), - ProtoMessage(ProtoIdentifier("BazMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), ] set2 = [ - ProtoMessage(ProtoIdentifier("FooMessage2"), []), - ProtoMessage(ProtoIdentifier("BarMessage2"), []), - ProtoMessage(ProtoIdentifier("BazMessage2"), []), + ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []), + ProtoMessage(None, ProtoIdentifier(None, "BarMessage2"), []), + ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []), ] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff + ProtoMessageAdded( + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) + ), + diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BarMessage"), [])), diff + ProtoMessageAdded( + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []) + ), + diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff + ProtoMessageAdded( + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) + ), + diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage2"), [])), diff + ProtoMessageRemoved( + ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []) + ), + diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BarMessage2"), [])), diff + ProtoMessageRemoved( + ProtoMessage(None, ProtoIdentifier(None, "BarMessage2"), []) + ), + diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage2"), [])), diff + ProtoMessageRemoved( + ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []) + ), + diff, ) self.assertEqual(6, len(diff)) def test_diff_sets_overlap(self): set1 = [ - ProtoMessage(ProtoIdentifier("FooMessage"), []), - ProtoMessage(ProtoIdentifier("BarMessage"), []), - ProtoMessage(ProtoIdentifier("BazMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), ] set2 = [ - ProtoMessage(ProtoIdentifier("FooMessage2"), []), - ProtoMessage(ProtoIdentifier("BarMessage"), []), - ProtoMessage(ProtoIdentifier("BazMessage2"), []), + ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []), + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), + ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []), ] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff + ProtoMessageAdded( + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) + ), + diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff + ProtoMessageAdded( + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) + ), + diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage2"), [])), diff + ProtoMessageRemoved( + ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []) + ), + diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage2"), [])), diff + ProtoMessageRemoved( + ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []) + ), + diff, ) self.assertEqual(4, len(diff)) diff --git a/test/proto_option_test.py b/test/proto_option_test.py index caf20ed..b1f4ff1 100644 --- a/test/proto_option_test.py +++ b/test/proto_option_test.py @@ -19,225 +19,245 @@ class OptionTest(unittest.TestCase): maxDiff = None def test_string_option(self): - string_option = ProtoOption.match("option foo = 'test value';") - self.assertEqual(string_option.node.name, ProtoIdentifier("foo")) + string_option = ProtoOption.match(None, "option foo = 'test value';") + self.assertEqual(string_option.node.name, ProtoIdentifier(None, "foo")) self.assertEqual( - string_option.node.value.value, ProtoStringLiteral("test value") + string_option.node.value.value, ProtoStringLiteral(None, "test value") ) self.assertEqual(string_option.remaining_source, "") - string_option = ProtoOption.match('option foo = "test value";') - self.assertEqual(string_option.node.name, ProtoIdentifier("foo")) + string_option = ProtoOption.match(None, 'option foo = "test value";') + self.assertEqual(string_option.node.name, ProtoIdentifier(None, "foo")) self.assertEqual( - string_option.node.value.value, ProtoStringLiteral("test value") + string_option.node.value.value, ProtoStringLiteral(None, "test value") ) self.assertEqual(string_option.remaining_source, "") def test_packaged_name(self): - packaged_option = ProtoOption.match("option foo.bar.baz = 'test value';") - self.assertEqual(packaged_option.node.name, ProtoFullIdentifier("foo.bar.baz")) + packaged_option = ProtoOption.match(None, "option foo.bar.baz = 'test value';") self.assertEqual( - packaged_option.node.value.value, ProtoStringLiteral("test value") + packaged_option.node.name, ProtoFullIdentifier(None, "foo.bar.baz") + ) + self.assertEqual( + packaged_option.node.value.value, ProtoStringLiteral(None, "test value") ) def test_parenthesized_name(self): - parenthesized_option = ProtoOption.match("option (foo) = 'test value';") - self.assertEqual(parenthesized_option.node.name, ProtoIdentifier("(foo)")) + parenthesized_option = ProtoOption.match(None, "option (foo) = 'test value';") + self.assertEqual(parenthesized_option.node.name, ProtoIdentifier(None, "(foo)")) self.assertEqual( - parenthesized_option.node.value.value, ProtoStringLiteral("test value") + parenthesized_option.node.value.value, + ProtoStringLiteral(None, "test value"), ) fully_qualified_name_option = ProtoOption.match( - "option (foo).bar.baz = 'test value';" + None, "option (foo).bar.baz = 'test value';" ) self.assertEqual( - fully_qualified_name_option.node.name, ProtoFullIdentifier("(foo).bar.baz") + fully_qualified_name_option.node.name, + ProtoFullIdentifier(None, "(foo).bar.baz"), ) self.assertEqual( fully_qualified_name_option.node.value.value, - ProtoStringLiteral("test value"), + ProtoStringLiteral(None, "test value"), ) def test_string_option_missing_semicolon(self): with self.assertRaises(ValueError): - ProtoOption.match("option foo = 'test value'") + ProtoOption.match(None, "option foo = 'test value'") with self.assertRaises(ValueError): - ProtoOption.match('option foo = "test value"') + ProtoOption.match(None, 'option foo = "test value"') def test_string_option_missing_quote(self): with self.assertRaises(ValueError): - ProtoOption.match("option foo = test value;") + ProtoOption.match(None, "option foo = test value;") with self.assertRaises(ValueError): - ProtoOption.match("option foo = 'test value;") + ProtoOption.match(None, "option foo = 'test value;") with self.assertRaises(ValueError): - ProtoOption.match('option foo = "test value;') + ProtoOption.match(None, 'option foo = "test value;') with self.assertRaises(ValueError): - ProtoOption.match("option foo = test value';") + ProtoOption.match(None, "option foo = test value';") with self.assertRaises(ValueError): - ProtoOption.match('option foo = test value";') + ProtoOption.match(None, 'option foo = test value";') with self.assertRaises(ValueError): - ProtoOption.match("option foo = 'test value\";") + ProtoOption.match(None, "option foo = 'test value\";") with self.assertRaises(ValueError): - ProtoOption.match("option foo = \"test value';") + ProtoOption.match(None, "option foo = \"test value';") def test_identifier_option(self): - identifier_option = ProtoOption.match("option foo = test_identifier;") - self.assertEqual(identifier_option.node.name, ProtoIdentifier("foo")) + identifier_option = ProtoOption.match(None, "option foo = test_identifier;") + self.assertEqual(identifier_option.node.name, ProtoIdentifier(None, "foo")) self.assertEqual( identifier_option.node.value, - ProtoConstant(ProtoIdentifier("test_identifier")), + ProtoConstant(None, ProtoIdentifier(None, "test_identifier")), ) self.assertEqual(identifier_option.remaining_source, "") - identifier_option = ProtoOption.match("option bar = foo.bar.baz;") - self.assertEqual(identifier_option.node.name, ProtoIdentifier("bar")) + identifier_option = ProtoOption.match(None, "option bar = foo.bar.baz;") + self.assertEqual(identifier_option.node.name, ProtoIdentifier(None, "bar")) self.assertEqual( identifier_option.node.value, - ProtoConstant(ProtoFullIdentifier("foo.bar.baz")), + ProtoConstant(None, ProtoFullIdentifier(None, "foo.bar.baz")), ) self.assertEqual(identifier_option.remaining_source, "") def test_int_option(self): - int_option = ProtoOption.match("option foo = 0;") - self.assertEqual(int_option.node.name, ProtoIdentifier("foo")) + int_option = ProtoOption.match(None, "option foo = 0;") + self.assertEqual(int_option.node.name, ProtoIdentifier(None, "foo")) self.assertEqual( - int_option.node.value, ProtoConstant(ProtoInt(0, ProtoIntSign.POSITIVE)) + int_option.node.value, + ProtoConstant(None, ProtoInt(None, 0, ProtoIntSign.POSITIVE)), ) self.assertEqual(int_option.remaining_source, "") - int_option = ProtoOption.match("option foo = 12345;") - self.assertEqual(int_option.node.name, ProtoIdentifier("foo")) + int_option = ProtoOption.match(None, "option foo = 12345;") + self.assertEqual(int_option.node.name, ProtoIdentifier(None, "foo")) self.assertEqual( - int_option.node.value, ProtoConstant(ProtoInt(12345, ProtoIntSign.POSITIVE)) + int_option.node.value, + ProtoConstant(None, ProtoInt(None, 12345, ProtoIntSign.POSITIVE)), ) self.assertEqual(int_option.remaining_source, "") - int_option = ProtoOption.match("option foo = +42;") - self.assertEqual(int_option.node.name, ProtoIdentifier("foo")) + int_option = ProtoOption.match(None, "option foo = +42;") + self.assertEqual(int_option.node.name, ProtoIdentifier(None, "foo")) self.assertEqual( - int_option.node.value, ProtoConstant(ProtoInt(42, ProtoIntSign.POSITIVE)) + int_option.node.value, + ProtoConstant(None, ProtoInt(None, 42, ProtoIntSign.POSITIVE)), ) self.assertEqual(int_option.remaining_source, "") - int_option = ProtoOption.match("option foo = -12;") - self.assertEqual(int_option.node.name, ProtoIdentifier("foo")) + int_option = ProtoOption.match(None, "option foo = -12;") + self.assertEqual(int_option.node.name, ProtoIdentifier(None, "foo")) self.assertEqual( - int_option.node.value, ProtoConstant(ProtoInt(12, ProtoIntSign.NEGATIVE)) + int_option.node.value, + ProtoConstant(None, ProtoInt(None, 12, ProtoIntSign.NEGATIVE)), ) self.assertEqual(int_option.remaining_source, "") def test_float_option(self): - float_option = ProtoOption.match("option foo = inf;") + float_option = ProtoOption.match(None, "option foo = inf;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float("inf"), ProtoFloatSign.POSITIVE)), + ProtoConstant( + None, ProtoFloat(None, float("inf"), ProtoFloatSign.POSITIVE) + ), ) - float_option = ProtoOption.match("option foo = nan;") + float_option = ProtoOption.match(None, "option foo = nan;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float("nan"), ProtoFloatSign.POSITIVE)), + ProtoConstant( + None, ProtoFloat(None, float("nan"), ProtoFloatSign.POSITIVE) + ), ) - float_option = ProtoOption.match("option foo = 12.1;") + float_option = ProtoOption.match(None, "option foo = 12.1;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float(12.1), ProtoFloatSign.POSITIVE)), + ProtoConstant(None, ProtoFloat(None, float(12.1), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match("option foo = .1;") + float_option = ProtoOption.match(None, "option foo = .1;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float(0.1), ProtoFloatSign.POSITIVE)), + ProtoConstant(None, ProtoFloat(None, float(0.1), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match("option foo = .1e3;") + float_option = ProtoOption.match(None, "option foo = .1e3;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float(100), ProtoFloatSign.POSITIVE)), + ProtoConstant(None, ProtoFloat(None, float(100), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match("option foo = +12.1;") + float_option = ProtoOption.match(None, "option foo = +12.1;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float(12.1), ProtoFloatSign.POSITIVE)), + ProtoConstant(None, ProtoFloat(None, float(12.1), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match("option foo = +.1;") + float_option = ProtoOption.match(None, "option foo = +.1;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float(0.1), ProtoFloatSign.POSITIVE)), + ProtoConstant(None, ProtoFloat(None, float(0.1), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match("option foo = +.1e2;") + float_option = ProtoOption.match(None, "option foo = +.1e2;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float(10), ProtoFloatSign.POSITIVE)), + ProtoConstant(None, ProtoFloat(None, float(10), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match("option foo = +.1e-2;") + float_option = ProtoOption.match(None, "option foo = +.1e-2;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float(0.001), ProtoFloatSign.POSITIVE)), + ProtoConstant( + None, ProtoFloat(None, float(0.001), ProtoFloatSign.POSITIVE) + ), ) - float_option = ProtoOption.match("option foo = -.1e0;") + float_option = ProtoOption.match(None, "option foo = -.1e0;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float(0.1), ProtoFloatSign.NEGATIVE)), + ProtoConstant(None, ProtoFloat(None, float(0.1), ProtoFloatSign.NEGATIVE)), ) - float_option = ProtoOption.match("option foo = -12E+1;") + float_option = ProtoOption.match(None, "option foo = -12E+1;") self.assertEqual( float_option.node.value, - ProtoConstant(ProtoFloat(float(120), ProtoFloatSign.NEGATIVE)), + ProtoConstant(None, ProtoFloat(None, float(120), ProtoFloatSign.NEGATIVE)), ) def test_diff_same_option_returns_empty(self): po1 = ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) po2 = ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) self.assertEqual(ProtoOption.diff(po1, po2), []) def test_diff_different_option_name_returns_empty(self): po1 = ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) po2 = ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) self.assertEqual(ProtoOption.diff(po1, po2), []) def test_diff_different_option_value_returns_option_diff(self): po1 = ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) po2 = ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("other value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "other value")), ) self.assertEqual( ProtoOption.diff(po1, po2), [ ProtoOptionValueChanged( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), - ProtoConstant(ProtoStringLiteral("other value")), + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoConstant(None, ProtoStringLiteral(None, "other value")), ) ], ) @@ -245,16 +265,18 @@ def test_diff_different_option_value_returns_option_diff(self): def test_diff_option_added(self): po1 = None po2 = ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) self.assertEqual( ProtoOption.diff(po1, po2), [ ProtoOptionAdded( ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) ), ], @@ -262,8 +284,9 @@ def test_diff_option_added(self): def test_diff_option_removed(self): po1 = ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) po2 = None self.assertEqual( @@ -271,8 +294,9 @@ def test_diff_option_removed(self): [ ProtoOptionRemoved( ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) ), ], @@ -286,16 +310,19 @@ def test_diff_sets_empty_returns_empty(self): def test_diff_sets_no_change(self): set1 = [ ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] self.assertEqual(ProtoOption.diff_sets(set1, set1), []) @@ -304,16 +331,19 @@ def test_diff_sets_all_removed(self): set1 = [] set2 = [ ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] diff = ProtoOption.diff_sets(set1, set2) @@ -321,8 +351,9 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) ), diff, @@ -330,8 +361,9 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ) ), diff, @@ -339,8 +371,9 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -350,16 +383,19 @@ def test_diff_sets_all_removed(self): def test_diff_sets_all_added(self): set1 = [ ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] set2 = [] @@ -368,8 +404,9 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoOptionAdded( ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) ), diff, @@ -377,8 +414,9 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoOptionAdded( ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ) ), diff, @@ -386,8 +424,9 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoOptionAdded( ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -397,30 +436,36 @@ def test_diff_sets_all_added(self): def test_diff_sets_mutually_exclusive(self): set1 = [ ProtoOption( - ProtoIdentifier("some.custom.option.but.not.prior"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option.but.not.prior"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( - ProtoIdentifier("ruby_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "ruby_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), ProtoOption( - ProtoIdentifier("other.option.but.stil.not.prior"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option.but.stil.not.prior"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] set2 = [ ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] @@ -429,8 +474,9 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionAdded( ProtoOption( - ProtoIdentifier("some.custom.option.but.not.prior"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option.but.not.prior"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) ), diff, @@ -438,8 +484,9 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionAdded( ProtoOption( - ProtoIdentifier("other.option.but.stil.not.prior"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option.but.stil.not.prior"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -448,8 +495,9 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionAdded( ProtoOption( - ProtoIdentifier("ruby_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "ruby_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ) ), diff, @@ -458,8 +506,9 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -468,8 +517,9 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) ), diff, @@ -478,8 +528,9 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ) ), diff, @@ -490,30 +541,36 @@ def test_diff_sets_mutually_exclusive(self): def test_diff_sets_overlap(self): set1 = [ ProtoOption( - ProtoIdentifier("some.custom.option.but.not.prior"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option.but.not.prior"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.bat")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.bat")), ), ProtoOption( - ProtoIdentifier("other.option.but.stil.not.prior"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option.but.stil.not.prior"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] set2 = [ ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] @@ -522,8 +579,9 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - ProtoIdentifier("some.custom.option"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) ), diff, @@ -532,8 +590,9 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - ProtoIdentifier("other.option"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -541,8 +600,9 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoOptionAdded( ProtoOption( - ProtoIdentifier("some.custom.option.but.not.prior"), - ProtoConstant(ProtoStringLiteral("some value")), + None, + ProtoIdentifier(None, "some.custom.option.but.not.prior"), + ProtoConstant(None, ProtoStringLiteral(None, "some value")), ) ), diff, @@ -550,17 +610,18 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoOptionAdded( ProtoOption( - ProtoIdentifier("other.option.but.stil.not.prior"), - ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), + None, + ProtoIdentifier(None, "other.option.but.stil.not.prior"), + ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ) ), diff, ) self.assertIn( ProtoOptionValueChanged( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("foo.bar.bat")), - ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.bat")), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), diff, ) diff --git a/test/proto_package_test.py b/test/proto_package_test.py index b6707ba..20289a9 100644 --- a/test/proto_package_test.py +++ b/test/proto_package_test.py @@ -11,90 +11,93 @@ class PackageTest(unittest.TestCase): def test_correct_package(self): - self.assertEqual(ProtoPackage.match("package foo;").node.package, "foo") - self.assertEqual(ProtoPackage.match("package foo.bar;").node.package, "foo.bar") + self.assertEqual(ProtoPackage.match(None, "package foo;").node.package, "foo") self.assertEqual( - ProtoPackage.match("package foo.bar.baz;").node.package, "foo.bar.baz" + ProtoPackage.match(None, "package foo.bar;").node.package, "foo.bar" + ) + self.assertEqual( + ProtoPackage.match(None, "package foo.bar.baz;").node.package, "foo.bar.baz" ) def test_package_serialize(self): self.assertEqual( - ProtoPackage.match("package foo;").node.serialize(), "package foo;" + ProtoPackage.match(None, "package foo;").node.serialize(), "package foo;" ) self.assertEqual( - ProtoPackage.match("package foo.bar;").node.serialize(), "package foo.bar;" + ProtoPackage.match(None, "package foo.bar;").node.serialize(), + "package foo.bar;", ) self.assertEqual( - ProtoPackage.match("package foo.bar.baz;").node.serialize(), + ProtoPackage.match(None, "package foo.bar.baz;").node.serialize(), "package foo.bar.baz;", ) def test_package_malformed(self): with self.assertRaises(ValueError): - ProtoPackage.match("package") + ProtoPackage.match(None, "package") with self.assertRaises(ValueError): - ProtoPackage.match("package;") + ProtoPackage.match(None, "package;") with self.assertRaises(ValueError): - ProtoPackage.match("package ") + ProtoPackage.match(None, "package ") with self.assertRaises(ValueError): - ProtoPackage.match("package ;") + ProtoPackage.match(None, "package ;") with self.assertRaises(ValueError): - ProtoPackage.match("packagefoo") + ProtoPackage.match(None, "packagefoo") with self.assertRaises(ValueError): - ProtoPackage.match("package foo.") + ProtoPackage.match(None, "package foo.") with self.assertRaises(ValueError): - ProtoPackage.match("packagefoo.") + ProtoPackage.match(None, "packagefoo.") with self.assertRaises(ValueError): - ProtoPackage.match("package foo.;") + ProtoPackage.match(None, "package foo.;") with self.assertRaises(ValueError): - ProtoPackage.match("package foo.bar") + ProtoPackage.match(None, "package foo.bar") with self.assertRaises(ValueError): - ProtoPackage.match("packagefoo.bar;") + ProtoPackage.match(None, "packagefoo.bar;") def test_diff_same_package_returns_empty(self): - pp1 = ProtoPackage("my.awesome.package") - pp2 = ProtoPackage("my.awesome.package") + pp1 = ProtoPackage(None, "my.awesome.package") + pp2 = ProtoPackage(None, "my.awesome.package") self.assertEqual(ProtoPackage.diff(pp1, pp2), []) def test_diff_different_package_returns_package_diff(self): - pp1 = ProtoPackage("my.awesome.package") - pp2 = ProtoPackage("my.other.awesome.package") + pp1 = ProtoPackage(None, "my.awesome.package") + pp2 = ProtoPackage(None, "my.other.awesome.package") self.assertEqual( ProtoPackage.diff(pp1, pp2), [ ProtoPackageChanged( - ProtoPackage("my.awesome.package"), - ProtoPackage("my.other.awesome.package"), + ProtoPackage(None, "my.awesome.package"), + ProtoPackage(None, "my.other.awesome.package"), ) ], ) def test_diff_package_added(self): - pp1 = ProtoPackage("my.new.package") + pp1 = ProtoPackage(None, "my.new.package") pp2 = None self.assertEqual( ProtoPackage.diff(pp1, pp2), [ - ProtoPackageAdded(ProtoPackage("my.new.package")), + ProtoPackageAdded(ProtoPackage(None, "my.new.package")), ], ) def test_diff_package_removed(self): pp1 = None - pp2 = ProtoPackage("my.old.package") + pp2 = ProtoPackage(None, "my.old.package") self.assertEqual( ProtoPackage.diff(pp1, pp2), [ - ProtoPackageRemoved(ProtoPackage("my.old.package")), + ProtoPackageRemoved(ProtoPackage(None, "my.old.package")), ], ) diff --git a/test/proto_range_test.py b/test/proto_range_test.py index ce78433..24f90a5 100644 --- a/test/proto_range_test.py +++ b/test/proto_range_test.py @@ -5,38 +5,42 @@ class RangeTest(unittest.TestCase): def test_range_single_int(self): - self.assertEqual(ProtoRange.match("42").node.serialize(), "42") - self.assertEqual(ProtoRange.match("-1").node.serialize(), "-1") + self.assertEqual(ProtoRange.match(None, "42").node.serialize(), "42") + self.assertEqual(ProtoRange.match(None, "-1").node.serialize(), "-1") def test_range_invalid_non_ints(self): - self.assertIsNone(ProtoRange.match("42.5")) - self.assertIsNone(ProtoRange.match("a")) - self.assertIsNone(ProtoRange.match("-")) + self.assertIsNone(ProtoRange.match(None, "42.5")) + self.assertIsNone(ProtoRange.match(None, "a")) + self.assertIsNone(ProtoRange.match(None, "-")) def test_range_int_range(self): - self.assertEqual(ProtoRange.match("1 to 1").node.serialize(), "1 to 1") - self.assertEqual(ProtoRange.match("1 to 7").node.serialize(), "1 to 7") - self.assertEqual(ProtoRange.match("-100 to -5").node.serialize(), "-100 to -5") + self.assertEqual(ProtoRange.match(None, "1 to 1").node.serialize(), "1 to 1") + self.assertEqual(ProtoRange.match(None, "1 to 7").node.serialize(), "1 to 7") + self.assertEqual( + ProtoRange.match(None, "-100 to -5").node.serialize(), "-100 to -5" + ) def test_range_invalid_range(self): with self.assertRaises(ValueError): - ProtoRange.match("8 to 2") + ProtoRange.match(None, "8 to 2") with self.assertRaises(ValueError): - ProtoRange.match("3 to 0") + ProtoRange.match(None, "3 to 0") with self.assertRaises(ValueError): - ProtoRange.match("1 to -1") + ProtoRange.match(None, "1 to -1") def test_range_invalid_range_non_int(self): with self.assertRaises(ValueError): - ProtoRange.match("1 to c") + ProtoRange.match(None, "1 to c") with self.assertRaises(ValueError): - ProtoRange.match("1 to -bc3") + ProtoRange.match(None, "1 to -bc3") def test_range_max(self): - self.assertEqual(ProtoRange.match("7 to max").node.serialize(), "7 to max") + self.assertEqual( + ProtoRange.match(None, "7 to max").node.serialize(), "7 to max" + ) if __name__ == "__main__": diff --git a/test/proto_reserved_test.py b/test/proto_reserved_test.py index 0232905..f7d1c8b 100644 --- a/test/proto_reserved_test.py +++ b/test/proto_reserved_test.py @@ -7,45 +7,47 @@ class ReservedTest(unittest.TestCase): def test_reserved_single_int(self): self.assertEqual( - ProtoReserved.match("reserved 21;").node.serialize(), "reserved 21;" + ProtoReserved.match(None, "reserved 21;").node.serialize(), "reserved 21;" ) self.assertEqual( - ProtoReserved.match("reserved -1;").node.serialize(), "reserved -1;" + ProtoReserved.match(None, "reserved -1;").node.serialize(), "reserved -1;" ) def test_reserved_multiple_ints(self): self.assertEqual( - ProtoReserved.match("reserved 1, 5, 2, 42;").node.serialize(), + ProtoReserved.match(None, "reserved 1, 5, 2, 42;").node.serialize(), "reserved 1, 5, 2, 42;", ) def test_reserved_range_max(self): self.assertEqual( - ProtoReserved.match("reserved 8 to max;").node.serialize(), + ProtoReserved.match(None, "reserved 8 to max;").node.serialize(), "reserved 8 to max;", ) def test_reserved_single_string_field(self): self.assertEqual( - ProtoReserved.match("reserved 'foo';").node.serialize(), "reserved 'foo';" + ProtoReserved.match(None, "reserved 'foo';").node.serialize(), + "reserved 'foo';", ) self.assertEqual( - ProtoReserved.match('reserved "foo";').node.serialize(), 'reserved "foo";' + ProtoReserved.match(None, 'reserved "foo";').node.serialize(), + 'reserved "foo";', ) def test_reserved_multiple_string_fields(self): self.assertEqual( - ProtoReserved.match("reserved 'foo', 'bar';").node.serialize(), + ProtoReserved.match(None, "reserved 'foo', 'bar';").node.serialize(), "reserved 'foo', 'bar';", ) self.assertEqual( - ProtoReserved.match('reserved "foo", "bar", "baz";').node.serialize(), + ProtoReserved.match(None, 'reserved "foo", "bar", "baz";').node.serialize(), 'reserved "foo", "bar", "baz";', ) def test_reserved_cannot_have_ints_and_strings(self): with self.assertRaises(ValueError): - ProtoReserved.match("reserved 1, 'foo';") + ProtoReserved.match(None, "reserved 1, 'foo';") if __name__ == "__main__": diff --git a/test/proto_service_test.py b/test/proto_service_test.py index f294e02..b99a242 100644 --- a/test/proto_service_test.py +++ b/test/proto_service_test.py @@ -20,6 +20,7 @@ class ServiceTest(unittest.TestCase): def test_service_all_features(self): test_service_all_features = ProtoService.match( + None, dedent( """ service FooService { @@ -35,47 +36,57 @@ def test_service_all_features(self): rpc ThreeRPC (ThreeRPCRequest) returns (ThreeRPCResponse) { option java_package = "com.example.foo"; option (foo.bar).baz = false; } } """.strip() - ) + ), ) self.assertEqual( test_service_all_features.node, ProtoService( - ProtoIdentifier("FooService"), + None, + ProtoIdentifier(None, "FooService"), [ ProtoOption( - ProtoIdentifier("(foo.bar).baz"), - ProtoConstant(ProtoStringLiteral("bat")), + None, + ProtoIdentifier(None, "(foo.bar).baz"), + ProtoConstant(None, ProtoStringLiteral(None, "bat")), ), - ProtoSingleLineComment(" single-line comment!"), + ProtoSingleLineComment(None, " single-line comment!"), ProtoServiceRPC( - ProtoIdentifier("OneRPC"), - ProtoEnumOrMessageIdentifier("OneRPCRequest"), - ProtoEnumOrMessageIdentifier("OneRPCResponse"), + None, + ProtoIdentifier(None, "OneRPC"), + ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), ), ProtoServiceRPC( - ProtoIdentifier("TwoRPC"), - ProtoEnumOrMessageIdentifier("TwoRPCRequest"), - ProtoEnumOrMessageIdentifier("TwoRPCResponse"), + None, + ProtoIdentifier(None, "TwoRPC"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), False, True, ), ProtoMultiLineComment( - "\n multiple\n line\n comment\n " + None, + "\n multiple\n line\n comment\n ", ), ProtoServiceRPC( - ProtoIdentifier("ThreeRPC"), - ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), + None, + ProtoIdentifier(None, "ThreeRPC"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), False, False, [ ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant( + None, ProtoStringLiteral(None, "com.example.foo") + ), ), ProtoOption( - ProtoFullIdentifier("(foo.bar).baz"), - ProtoConstant(ProtoBool(False)), + None, + ProtoFullIdentifier(None, "(foo.bar).baz"), + ProtoConstant(None, ProtoBool(None, False)), ), ], ), @@ -103,26 +114,31 @@ def test_service_all_features(self): ) def test_service_empty(self): - parsed_empty_service = ProtoService.match("""service FooService {}""") + parsed_empty_service = ProtoService.match(None, """service FooService {}""") self.assertIsNotNone(parsed_empty_service) - self.assertEqual(parsed_empty_service.node.name, ProtoIdentifier("FooService")) + self.assertEqual( + parsed_empty_service.node.name, ProtoIdentifier(None, "FooService") + ) parsed_spaced_service = ProtoService.match( + None, dedent( """ service FooService { } """.strip() - ) + ), ) self.assertIsNotNone(parsed_spaced_service) self.assertEqual( - parsed_spaced_service.node, ProtoService(ProtoIdentifier("FooService"), []) + parsed_spaced_service.node, + ProtoService(None, ProtoIdentifier(None, "FooService"), []), ) def test_service_empty_statements(self): empty_statement_service = ProtoService.match( + None, dedent( """ service FooService { @@ -130,36 +146,39 @@ def test_service_empty_statements(self): ; } """.strip() - ) + ), ) self.assertIsNotNone(empty_statement_service) self.assertEqual( empty_statement_service.node, - ProtoService(ProtoIdentifier("FooService"), []), + ProtoService(None, ProtoIdentifier(None, "FooService"), []), ) def test_service_option(self): service_with_options = ProtoService.match( + None, dedent( """ service FooService { option (foo.bar).baz = "bat"; } """.strip() - ) + ), ) self.assertEqual( service_with_options.node.nodes, [ ProtoOption( - ProtoIdentifier("(foo.bar).baz"), - ProtoConstant(ProtoStringLiteral("bat")), + None, + ProtoIdentifier(None, "(foo.bar).baz"), + ProtoConstant(None, ProtoStringLiteral(None, "bat")), ) ], ) def test_service_rpc_basic(self): service_with_options = ProtoService.match( + None, dedent( """ service FooService { @@ -168,31 +187,35 @@ def test_service_rpc_basic(self): rpc ThreeRPC (ThreeRPCRequest) returns (ThreeRPCResponse); } """.strip() - ) + ), ) self.assertEqual( service_with_options.node.nodes, [ ProtoServiceRPC( - ProtoIdentifier("OneRPC"), - ProtoEnumOrMessageIdentifier("OneRPCRequest"), - ProtoEnumOrMessageIdentifier("OneRPCResponse"), + None, + ProtoIdentifier(None, "OneRPC"), + ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), ), ProtoServiceRPC( - ProtoIdentifier("TwoRPC"), - ProtoEnumOrMessageIdentifier("TwoRPCRequest"), - ProtoEnumOrMessageIdentifier("TwoRPCResponse"), + None, + ProtoIdentifier(None, "TwoRPC"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), ), ProtoServiceRPC( - ProtoIdentifier("ThreeRPC"), - ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), + None, + ProtoIdentifier(None, "ThreeRPC"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), ), ], ) def test_service_rpc_stream(self): service_with_options = ProtoService.match( + None, dedent( """ service FooService { @@ -200,22 +223,24 @@ def test_service_rpc_stream(self): rpc TwoRPC (TwoRPCRequest) returns (stream TwoRPCResponse); } """.strip() - ) + ), ) self.assertEqual( service_with_options.node.nodes, [ ProtoServiceRPC( - ProtoIdentifier("OneRPC"), - ProtoEnumOrMessageIdentifier("OneRPCRequest"), - ProtoEnumOrMessageIdentifier("OneRPCResponse"), + None, + ProtoIdentifier(None, "OneRPC"), + ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), True, False, ), ProtoServiceRPC( - ProtoIdentifier("TwoRPC"), - ProtoEnumOrMessageIdentifier("TwoRPCRequest"), - ProtoEnumOrMessageIdentifier("TwoRPCResponse"), + None, + ProtoIdentifier(None, "TwoRPC"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), False, True, ), @@ -224,6 +249,7 @@ def test_service_rpc_stream(self): def test_service_rpc_options(self): service_with_options = ProtoService.match( + None, dedent( """ service FooService { @@ -231,30 +257,36 @@ def test_service_rpc_options(self): rpc TwoRPC (TwoRPCRequest) returns (TwoRPCResponse) { option java_package = "com.example.foo"; option (foo.bar).baz = false; } } """.strip() - ) + ), ) self.assertEqual( service_with_options.node.nodes, [ ProtoServiceRPC( - ProtoIdentifier("OneRPC"), - ProtoEnumOrMessageIdentifier("OneRPCRequest"), - ProtoEnumOrMessageIdentifier("OneRPCResponse"), + None, + ProtoIdentifier(None, "OneRPC"), + ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), ), ProtoServiceRPC( - ProtoIdentifier("TwoRPC"), - ProtoEnumOrMessageIdentifier("TwoRPCRequest"), - ProtoEnumOrMessageIdentifier("TwoRPCResponse"), + None, + ProtoIdentifier(None, "TwoRPC"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), False, False, [ ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant( + None, ProtoStringLiteral(None, "com.example.foo") + ), ), ProtoOption( - ProtoFullIdentifier("(foo.bar).baz"), - ProtoConstant(ProtoBool(False)), + None, + ProtoFullIdentifier(None, "(foo.bar).baz"), + ProtoConstant(None, ProtoBool(None, False)), ), ], ), @@ -263,6 +295,7 @@ def test_service_rpc_options(self): def test_service_parses_comments(self): service_with_comments = ProtoService.match( + None, dedent( """ service FooService { @@ -277,35 +310,40 @@ def test_service_parses_comments(self): rpc ThreeRPC (ThreeRPCRequest) returns (ThreeRPCResponse); } """.strip() - ) + ), ) self.assertEqual( service_with_comments.node.nodes, [ ProtoServiceRPC( - ProtoIdentifier("OneRPC"), - ProtoEnumOrMessageIdentifier("OneRPCRequest"), - ProtoEnumOrMessageIdentifier("OneRPCResponse"), + None, + ProtoIdentifier(None, "OneRPC"), + ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), ), - ProtoSingleLineComment(" single-line comment!"), + ProtoSingleLineComment(None, " single-line comment!"), ProtoServiceRPC( - ProtoIdentifier("TwoRPC"), - ProtoEnumOrMessageIdentifier("TwoRPCRequest"), - ProtoEnumOrMessageIdentifier("TwoRPCResponse"), + None, + ProtoIdentifier(None, "TwoRPC"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), ), ProtoMultiLineComment( - "\n multiple\n line\n comment\n " + None, + "\n multiple\n line\n comment\n ", ), ProtoServiceRPC( - ProtoIdentifier("ThreeRPC"), - ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), + None, + ProtoIdentifier(None, "ThreeRPC"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), ), ], ) def test_service_normalize_removes_comments(self): normalized_service = ProtoService.match( + None, dedent( """ service FooService { @@ -320,25 +358,28 @@ def test_service_normalize_removes_comments(self): rpc ThreeRPC (ThreeRPCRequest) returns (ThreeRPCResponse); } """.strip() - ) + ), ).node.normalize() self.assertEqual( normalized_service.nodes, [ ProtoServiceRPC( - ProtoIdentifier("OneRPC"), - ProtoEnumOrMessageIdentifier("OneRPCRequest"), - ProtoEnumOrMessageIdentifier("OneRPCResponse"), + None, + ProtoIdentifier(None, "OneRPC"), + ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), ), ProtoServiceRPC( - ProtoIdentifier("ThreeRPC"), - ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), + None, + ProtoIdentifier(None, "ThreeRPC"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), ), ProtoServiceRPC( - ProtoIdentifier("TwoRPC"), - ProtoEnumOrMessageIdentifier("TwoRPCRequest"), - ProtoEnumOrMessageIdentifier("TwoRPCResponse"), + None, + ProtoIdentifier(None, "TwoRPC"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), + ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), ), ], ) diff --git a/test/proto_string_literal_test.py b/test/proto_string_literal_test.py index 73ad4dc..b3bb303 100644 --- a/test/proto_string_literal_test.py +++ b/test/proto_string_literal_test.py @@ -5,33 +5,33 @@ class StringLiteralTest(unittest.TestCase): def test_correct_syntax(self): - parsed_single_quote = ProtoStringLiteral.match("""'foo'""") + parsed_single_quote = ProtoStringLiteral.match(None, """'foo'""") self.assertEqual(parsed_single_quote.node.value, "foo") self.assertEqual(parsed_single_quote.remaining_source, "") self.assertEqual(parsed_single_quote.node.serialize(), "'foo'") - parsed_double_quote = ProtoStringLiteral.match("""\"foo\"""") + parsed_double_quote = ProtoStringLiteral.match(None, """\"foo\"""") self.assertEqual(parsed_double_quote.node.value, "foo") self.assertEqual(parsed_double_quote.remaining_source, "") self.assertEqual(parsed_double_quote.node.serialize(), '"foo"') def test_remaining_source(self): - parsed_single_quote = ProtoStringLiteral.match("""'foo'\nbar baz""") + parsed_single_quote = ProtoStringLiteral.match(None, """'foo'\nbar baz""") self.assertEqual(parsed_single_quote.remaining_source, "bar baz") - parsed_double_quote = ProtoStringLiteral.match("""\"foo\"\"foobar\"""") + parsed_double_quote = ProtoStringLiteral.match(None, """\"foo\"\"foobar\"""") self.assertEqual(parsed_double_quote.remaining_source, '"foobar"') def test_missing_quote(self): - self.assertIsNone(ProtoStringLiteral.match("""'foo""")) - self.assertIsNone(ProtoStringLiteral.match("""foo'""")) - self.assertIsNone(ProtoStringLiteral.match("""\"foo""")) - self.assertIsNone(ProtoStringLiteral.match("""foo\"""")) - self.assertIsNone(ProtoStringLiteral.match("""'foo\"""")) - self.assertIsNone(ProtoStringLiteral.match("""\"foo'""")) + self.assertIsNone(ProtoStringLiteral.match(None, """'foo""")) + self.assertIsNone(ProtoStringLiteral.match(None, """foo'""")) + self.assertIsNone(ProtoStringLiteral.match(None, """\"foo""")) + self.assertIsNone(ProtoStringLiteral.match(None, """foo\"""")) + self.assertIsNone(ProtoStringLiteral.match(None, """'foo\"""")) + self.assertIsNone(ProtoStringLiteral.match(None, """\"foo'""")) def test_escaped_quote(self): - self.assertIsNone(ProtoStringLiteral.match("""'foo\\'""")) - self.assertIsNone(ProtoStringLiteral.match("""\"foo\\\"""")) - parsed_escaped_quote = ProtoStringLiteral.match("""\"foo\\\"barbaz\"""") + self.assertIsNone(ProtoStringLiteral.match(None, """'foo\\'""")) + self.assertIsNone(ProtoStringLiteral.match(None, """\"foo\\\"""")) + parsed_escaped_quote = ProtoStringLiteral.match(None, """\"foo\\\"barbaz\"""") self.assertEqual(parsed_escaped_quote.node.value, 'foo\\"barbaz') self.assertEqual(parsed_escaped_quote.remaining_source, "") self.assertEqual(parsed_escaped_quote.node.serialize(), '"foo\\"barbaz"') diff --git a/test/proto_syntax_test.py b/test/proto_syntax_test.py index 6abfda1..d0e4a3f 100644 --- a/test/proto_syntax_test.py +++ b/test/proto_syntax_test.py @@ -7,88 +7,88 @@ class SyntaxTest(unittest.TestCase): def test_correct_syntax(self): self.assertEqual( - ProtoSyntax.match("syntax = 'proto3';").node.syntax.value, "proto3" + ProtoSyntax.match(None, "syntax = 'proto3';").node.syntax.value, "proto3" ) self.assertEqual( - ProtoSyntax.match('syntax = "proto3";').node.syntax.value, "proto3" + ProtoSyntax.match(None, 'syntax = "proto3";').node.syntax.value, "proto3" ) self.assertEqual( - ProtoSyntax.match("syntax = 'proto2';").node.syntax.value, "proto2" + ProtoSyntax.match(None, "syntax = 'proto2';").node.syntax.value, "proto2" ) self.assertEqual( - ProtoSyntax.match('syntax = "proto2";').node.syntax.value, "proto2" + ProtoSyntax.match(None, 'syntax = "proto2";').node.syntax.value, "proto2" ) def test_serialize(self): self.assertEqual( - ProtoSyntax.match("syntax = 'proto3';").node.serialize(), + ProtoSyntax.match(None, "syntax = 'proto3';").node.serialize(), "syntax = 'proto3';", ) self.assertEqual( - ProtoSyntax.match('syntax = "proto3";').node.serialize(), + ProtoSyntax.match(None, 'syntax = "proto3";').node.serialize(), 'syntax = "proto3";', ) self.assertEqual( - ProtoSyntax.match("syntax = 'proto2';").node.serialize(), + ProtoSyntax.match(None, "syntax = 'proto2';").node.serialize(), "syntax = 'proto2';", ) self.assertEqual( - ProtoSyntax.match('syntax = "proto2";').node.serialize(), + ProtoSyntax.match(None, 'syntax = "proto2";').node.serialize(), 'syntax = "proto2";', ) def test_syntax_not_present(self): - self.assertIsNone(ProtoSyntax.match("")) - self.assertIsNone(ProtoSyntax.match('import "foo.proto";')) + self.assertIsNone(ProtoSyntax.match(None, "")) + self.assertIsNone(ProtoSyntax.match(None, 'import "foo.proto";')) def test_syntax_malformed(self): with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = 'proto3'") + ProtoSyntax.match(None, "syntax = 'proto3'") with self.assertRaises(ValueError): - ProtoSyntax.match('syntax = "proto3"') + ProtoSyntax.match(None, 'syntax = "proto3"') with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = 'proto2'") + ProtoSyntax.match(None, "syntax = 'proto2'") with self.assertRaises(ValueError): - ProtoSyntax.match('syntax = "proto2"') + ProtoSyntax.match(None, 'syntax = "proto2"') with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = proto3") + ProtoSyntax.match(None, "syntax = proto3") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = proto3;") + ProtoSyntax.match(None, "syntax = proto3;") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = 'proto3") + ProtoSyntax.match(None, "syntax = 'proto3") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = 'proto3;") + ProtoSyntax.match(None, "syntax = 'proto3;") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = proto3'") + ProtoSyntax.match(None, "syntax = proto3'") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = proto3';") + ProtoSyntax.match(None, "syntax = proto3';") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = 'proton';") + ProtoSyntax.match(None, "syntax = 'proton';") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = 'proton'") + ProtoSyntax.match(None, "syntax = 'proton'") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = 'proton") + ProtoSyntax.match(None, "syntax = 'proton") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = proton';") + ProtoSyntax.match(None, "syntax = proton';") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = proton'") + ProtoSyntax.match(None, "syntax = proton'") with self.assertRaises(ValueError): - ProtoSyntax.match("syntax = proton") + ProtoSyntax.match(None, "syntax = proton") def test_diff_empty_same_syntax_returns_empty(self): - pf1 = ProtoSyntax(ProtoStringLiteral("proto3")) - pf2 = ProtoSyntax(ProtoStringLiteral("proto3")) + pf1 = ProtoSyntax(None, ProtoStringLiteral(None, "proto3")) + pf2 = ProtoSyntax(None, ProtoStringLiteral(None, "proto3")) self.assertEqual(ProtoSyntax.diff(pf1, pf2), []) def test_diff_empty_different_syntax_returns_syntax_diff(self): - pf1 = ProtoSyntax(ProtoStringLiteral("proto3")) - pf2 = ProtoSyntax(ProtoStringLiteral("proto2")) + pf1 = ProtoSyntax(None, ProtoStringLiteral(None, "proto3")) + pf2 = ProtoSyntax(None, ProtoStringLiteral(None, "proto2")) self.assertEqual( ProtoSyntax.diff(pf1, pf2), [ ProtoSyntaxChanged( - ProtoSyntax(ProtoStringLiteral("proto3")), - ProtoSyntax(ProtoStringLiteral("proto2")), + ProtoSyntax(None, ProtoStringLiteral(None, "proto3")), + ProtoSyntax(None, ProtoStringLiteral(None, "proto2")), ) ], ) From 1d4c1e7e1bcd06ada6b97a255d554c7edb1e2f67 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sat, 18 Feb 2023 23:08:20 -0500 Subject: [PATCH 12/35] Pull proto_map, proto_oneof out of proto_message (#69) --- src/BUILD.bazel | 29 +++ src/proto_map.py | 283 ++++++++++++++++++++++++ src/proto_message.py | 438 +------------------------------------ src/proto_oneof.py | 159 ++++++++++++++ test/BUILD.bazel | 25 ++- test/parser_test.py | 9 +- test/proto_extend_test.py | 2 +- test/proto_map_test.py | 100 +++++++++ test/proto_message_test.py | 4 +- 9 files changed, 605 insertions(+), 444 deletions(-) create mode 100644 src/proto_map.py create mode 100644 src/proto_oneof.py create mode 100644 test/proto_map_test.py diff --git a/src/BUILD.bazel b/src/BUILD.bazel index 892c9a3..899a7d5 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -173,12 +173,41 @@ py_library( ":proto_extend", ":proto_extensions", ":proto_identifier", + ":proto_map", + ":proto_message_field", ":proto_node", + ":proto_oneof", ":proto_option", ":proto_reserved", ], ) +py_library( + name = "proto_oneof", + srcs = ["proto_oneof.py"], + visibility = ["//visibility:public"], + deps = [ + ":proto_comment", + ":proto_identifier", + ":proto_map", + ":proto_message_field", + ":proto_node", + ":proto_option", + ], +) + +py_library( + name = "proto_map", + srcs = ["proto_map.py"], + visibility = ["//visibility:public"], + deps = [ + ":proto_identifier", + ":proto_int", + ":proto_message_field", + ":proto_node", + ], +) + py_library( name = "proto_enum", srcs = ["proto_enum.py"], diff --git a/src/proto_map.py b/src/proto_map.py new file mode 100644 index 0000000..9d73594 --- /dev/null +++ b/src/proto_map.py @@ -0,0 +1,283 @@ +from enum import Enum +from typing import Optional, Sequence + +from src.proto_identifier import ProtoEnumOrMessageIdentifier, ProtoIdentifier +from src.proto_int import ProtoInt +from src.proto_message_field import ProtoMessageFieldOption, ProtoMessageFieldTypesEnum +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff + + +class ProtoMapKeyTypesEnum(Enum): + INT32 = "int32" + INT64 = "int64" + UINT32 = "uint32" + UINT64 = "uint64" + SINT32 = "sint32" + SINT64 = "sint64" + FIXED32 = "fixed32" + FIXED64 = "fixed64" + SFIXED32 = "sfixed32" + SFIXED64 = "sfixed64" + BOOL = "bool" + STRING = "string" + + +ProtoMapValueTypesEnum = ProtoMessageFieldTypesEnum + + +class ProtoMap(ProtoNode): + def __init__( + self, + parent: Optional[ProtoNode], + key_type: ProtoMapKeyTypesEnum, + value_type: ProtoMapValueTypesEnum, + name: ProtoIdentifier, + number: ProtoInt, + enum_or_message_type_name: Optional[ProtoEnumOrMessageIdentifier] = None, + options: Optional[list[ProtoMessageFieldOption]] = None, + ): + super().__init__(parent) + self.key_type = key_type + self.value_type = value_type + self.name = name + self.name.parent = self + self.number = number + self.number.parent = self + self.enum_or_message_type_name = enum_or_message_type_name + if self.enum_or_message_type_name is not None: + self.enum_or_message_type_name.parent = self + + if options is None: + options = [] + self.options = options + for option in self.options: + option.parent = self + + def __eq__(self, other) -> bool: + return ( + self.key_type == other.key_type + and self.value_type == other.value_type + and self.name == other.name + and self.number == other.number + and self.enum_or_message_type_name == other.enum_or_message_type_name + and self.options == other.options + ) + + def __str__(self) -> str: + return f"<{self.__class__.__name__} key_type={self.key_type} value_type={self.value_type} name={self.name} number={self.number} enum_or_message_type_name={self.enum_or_message_type_name} options={self.options}>" + + def __repr__(self) -> str: + return str(self) + + def normalize(self) -> "ProtoMap": + return ProtoMap( + parent=self.parent, + key_type=self.key_type, + value_type=self.value_type, + name=self.name, + number=self.number, + enum_or_message_type_name=self.enum_or_message_type_name, + options=sorted(self.options, key=lambda o: str(o.normalize())), + ) + + @classmethod + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoNode"]: + if proto_source.startswith("map "): + proto_source = proto_source[4:].strip() + elif proto_source.startswith("map<"): + proto_source = proto_source[3:].strip() + else: + return None + + # Try to match the map key type. + proto_source = proto_source[1:].strip() + key_type = None + for potential_key_type in ProtoMapKeyTypesEnum: + if proto_source.startswith(potential_key_type.value): + key_type = potential_key_type + proto_source = proto_source[len(potential_key_type.value) :].strip() + break + if key_type is None: + return None + + if not proto_source.startswith(","): + return None + proto_source = proto_source[1:].strip() + + # Next, try to match the map value type. + value_type: Optional[ProtoMapValueTypesEnum] = None + for potential_value_type in ProtoMapValueTypesEnum: + if potential_value_type == ProtoMapValueTypesEnum.ENUM_OR_MESSAGE: + # This is special-cased below. + break + if proto_source.startswith(potential_value_type.value): + value_type = potential_value_type + proto_source = proto_source[len(potential_value_type.value) :].strip() + + # If this is an enum or message type, try to match a name. + enum_or_message_type_name = None + if value_type is None: + # See if this is an enum or message type. + match = ProtoEnumOrMessageIdentifier.match(None, proto_source) + if match is None: + return None + value_type = ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE + enum_or_message_type_name = match.node + proto_source = match.remaining_source.strip() + + if not proto_source.startswith(">"): + return None + proto_source = proto_source[1:].strip() + + # Try to match the map field's name. + identifier_match = ProtoIdentifier.match(None, proto_source) + if identifier_match is None: + return None + name = identifier_match.node + proto_source = identifier_match.remaining_source.strip() + + if not proto_source.startswith("="): + return None + proto_source = proto_source[1:].strip() + + # Try to match the map field number. + int_match = ProtoInt.match(None, proto_source) + if int_match is None: + return None + number = int_match.node + proto_source = int_match.remaining_source.strip() + + # Try to match map field options, if any. + options = [] + if proto_source.startswith("["): + proto_source = proto_source[1:].strip() + end_bracket = proto_source.find("]") + if end_bracket == -1: + raise ValueError( + f"Proto has invalid map field option syntax, cannot find ]: {proto_source}" + ) + for option_part in proto_source[:end_bracket].strip().split(","): + message_field_option_match = ProtoMessageFieldOption.match( + None, option_part.strip() + ) + if message_field_option_match is None: + raise ValueError( + f"Proto has invalid map field option syntax: {proto_source}" + ) + options.append(message_field_option_match.node) + proto_source = proto_source[end_bracket + 1 :].strip() + + if not proto_source.startswith(";"): + raise ValueError( + f"Proto has invalid map field syntax, missing ending ;:{proto_source}" + ) + + return ParsedProtoNode( + ProtoMap( + parent, + key_type, + value_type, + name, + number, + enum_or_message_type_name, + options, + ), + proto_source[1:].strip(), + ) + + def serialize(self) -> str: + serialized_parts = [ + f"map", + f"<{self.key_type.value},", + ] + + if self.value_type == ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE: + if self.enum_or_message_type_name is None: + raise ValueError( + f"Enum or message type name was not set for: {str(self)}" + ) + serialized_parts.append(f"{self.enum_or_message_type_name.serialize()}>") + else: + serialized_parts.append(f"{self.value_type.value}>") + + serialized_parts = serialized_parts + [ + self.name.serialize(), + "=", + self.number.serialize(), + ] + + if self.options: + serialized_parts.append("[") + serialized_parts.append( + ", ".join(option.serialize() for option in self.options) + ) + serialized_parts.append("]") + + return " ".join(serialized_parts) + ";" + + @staticmethod + def diff( + parent: Optional[ProtoNode], left: "ProtoMap", right: "ProtoMap" + ) -> list["ProtoNodeDiff"]: + if left is None and right is not None: + return [ProtoMapAdded(parent, right)] + elif left is not None and right is None: + return [ProtoMapRemoved(parent, left)] + elif left is None and right is None: + return [] + elif left.name != right.name: + return [] + elif left == right: + return [] + diffs: list["ProtoNodeDiff"] = [] + return diffs + + @staticmethod + def diff_sets( + parent: Optional[ProtoNode], left: list["ProtoMap"], right: list["ProtoMap"] + ) -> Sequence["ProtoNodeDiff"]: + diffs: list[ProtoNodeDiff] = [] + left_names = set(o.name.identifier for o in left) + right_names = set(o.name.identifier for o in right) + for name in left_names - right_names: + diffs.append( + ProtoMapAdded( + parent, next(i for i in left if i.name.identifier == name) + ) + ) + for name in right_names - left_names: + diffs.append( + ProtoMapRemoved( + parent, next(i for i in right if i.name.identifier == name) + ) + ) + for name in left_names & right_names: + left_enum = next(i for i in left if i.name.identifier == name) + right_enum = next(i for i in right if i.name.identifier == name) + diffs.extend(ProtoMap.diff(parent, left_enum, right_enum)) + + return diffs + + +class ProtoMapDiff(ProtoNodeDiff): + def __init__(self, parent: Optional[ProtoNode], map: ProtoMap): + self.parent = parent + self.map = map + + def __eq__(self, other: object) -> bool: + return isinstance(other, ProtoMapDiff) and self.map == other.map + + def __str__(self) -> str: + return f"<{self.__class__.__name__} parent={self.parent} map={self.map}>" + + +class ProtoMapAdded(ProtoMapDiff): + def __eq__(self, other: object) -> bool: + return super().__eq__(other) and isinstance(other, ProtoMapAdded) + + +class ProtoMapRemoved(ProtoMapDiff): + def __eq__(self, other: object) -> bool: + return super().__eq__(other) and isinstance(other, ProtoMapRemoved) diff --git a/src/proto_message.py b/src/proto_message.py index bf82578..8c084c9 100644 --- a/src/proto_message.py +++ b/src/proto_message.py @@ -1,9 +1,6 @@ -from enum import Enum from typing import Optional, Sequence from src.proto_comment import ( - ParsedProtoMultiLineCommentNode, - ParsedProtoSingleLineCommentNode, ProtoComment, ProtoMultiLineComment, ProtoSingleLineComment, @@ -11,439 +8,14 @@ from src.proto_enum import ProtoEnum from src.proto_extend import ProtoExtend from src.proto_extensions import ProtoExtensions -from src.proto_identifier import ProtoEnumOrMessageIdentifier, ProtoIdentifier -from src.proto_int import ProtoInt -from src.proto_message_field import ( - ParsedProtoMessageFieldNode, - ProtoMessageField, - ProtoMessageFieldOption, - ProtoMessageFieldTypesEnum, -) +from src.proto_identifier import ProtoIdentifier +from src.proto_map import ProtoMap +from src.proto_message_field import ProtoMessageField from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff -from src.proto_option import ParsedProtoOptionNode, ProtoOption +from src.proto_oneof import ProtoOneOf +from src.proto_option import ProtoOption from src.proto_reserved import ProtoReserved -ProtoOneOfNodeTypes = ( - ProtoOption | ProtoMessageField | ProtoSingleLineComment | ProtoMultiLineComment -) -ProtoParsedOneOfNodeTypes = ( - ParsedProtoOptionNode - | ParsedProtoMessageFieldNode - | ParsedProtoSingleLineCommentNode - | ParsedProtoMultiLineCommentNode -) - - -class ParsedProtoOneOfNode(ParsedProtoNode): - node: "ProtoOneOf" - remaining_source: str - - -class ProtoOneOf(ProtoNode): - def __init__( - self, - parent: Optional[ProtoNode], - name: ProtoIdentifier, - nodes: Sequence[ProtoOneOfNodeTypes], - ): - super().__init__(parent) - self.name = name - self.name.parent = self - self.nodes = nodes - for node in self.nodes: - node.parent = self - - def __eq__(self, other) -> bool: - return self.name == other.name and self.nodes == other.nodes - - def __str__(self) -> str: - return f"<{self.__class__.__name__} name={self.name}, nodes={self.nodes}>" - - def __repr__(self) -> str: - return str(self) - - def normalize(self) -> "ProtoOneOf": - non_comment_nodes = filter( - lambda n: not isinstance(n, ProtoComment), self.nodes - ) - options = [] - fields = [] - for node in non_comment_nodes: - if isinstance(node, ProtoOption): - options.append(node.normalize()) - elif ( - isinstance(node, ProtoMessageField) - or isinstance(node, ProtoOneOf) - or isinstance(node, ProtoMap) - ): - fields.append(node.normalize()) - else: - raise ValueError( - f"Can't sort message {self} node for normalizing: {node}" - ) - - sorted_nodes_for_normalizing = sorted( - options, key=lambda o: str(o.normalize()) - ) + sorted(fields, key=lambda f: int(f.number)) - - return ProtoOneOf( - parent=self.parent, - name=self.name, - nodes=sorted_nodes_for_normalizing, - ) - - @staticmethod - def parse_partial_content(partial_oneof_content: str) -> ProtoParsedOneOfNodeTypes: - supported_types: list[type[ProtoOneOfNodeTypes]] = [ - ProtoMessageField, - ProtoOption, - ProtoSingleLineComment, - ProtoMultiLineComment, - ] - for node_type in supported_types: - try: - match_result = node_type.match(None, partial_oneof_content) - except (ValueError, IndexError, TypeError): - raise ValueError( - f"Could not parse partial oneof content:\n{partial_oneof_content}" - ) - if match_result is not None: - return match_result - raise ValueError( - f"Could not parse partial oneof content:\n{partial_oneof_content}" - ) - - @classmethod - def match( - cls, parent: Optional[ProtoNode], proto_source: str - ) -> Optional["ParsedProtoOneOfNode"]: - if not proto_source.startswith("oneof "): - return None - - proto_source = proto_source[6:].strip() - - match = ProtoIdentifier.match(None, proto_source) - if match is None: - raise ValueError( - f"Proto has invalid syntax, expecting identifier for oneof: {proto_source}" - ) - - oneof_name = match.node - proto_source = match.remaining_source.strip() - - if not proto_source.startswith("{"): - raise ValueError( - f"Proto has invalid syntax, expecting opening curly brace: {proto_source}" - ) - - proto_source = proto_source[1:].strip() - parsed_tree = [] - while proto_source: - # Remove empty statements. - if proto_source.startswith(";"): - proto_source = proto_source[1:].strip() - continue - - if proto_source.startswith("}"): - proto_source = proto_source[1:].strip() - break - - match_result = ProtoOneOf.parse_partial_content(proto_source) - parsed_tree.append(match_result.node) - proto_source = match_result.remaining_source.strip() - - return ParsedProtoOneOfNode( - ProtoOneOf(parent, oneof_name, nodes=parsed_tree), proto_source - ) - - @property - def options(self) -> list[ProtoOption]: - return [node for node in self.nodes if isinstance(node, ProtoOption)] - - def serialize(self) -> str: - serialize_parts = ( - [f"oneof {self.name.serialize()} {{"] - + [n.serialize() for n in self.nodes] - + ["}"] - ) - return "\n".join(serialize_parts) - - -class ProtoMapKeyTypesEnum(Enum): - INT32 = "int32" - INT64 = "int64" - UINT32 = "uint32" - UINT64 = "uint64" - SINT32 = "sint32" - SINT64 = "sint64" - FIXED32 = "fixed32" - FIXED64 = "fixed64" - SFIXED32 = "sfixed32" - SFIXED64 = "sfixed64" - BOOL = "bool" - STRING = "string" - - -ProtoMapValueTypesEnum = ProtoMessageFieldTypesEnum - - -class ProtoMap(ProtoNode): - def __init__( - self, - parent: Optional[ProtoNode], - key_type: ProtoMapKeyTypesEnum, - value_type: ProtoMapValueTypesEnum, - name: ProtoIdentifier, - number: ProtoInt, - enum_or_message_type_name: Optional[ProtoEnumOrMessageIdentifier] = None, - options: Optional[list[ProtoMessageFieldOption]] = None, - ): - super().__init__(parent) - self.key_type = key_type - self.value_type = value_type - self.name = name - self.name.parent = self - self.number = number - self.number.parent = self - self.enum_or_message_type_name = enum_or_message_type_name - if self.enum_or_message_type_name is not None: - self.enum_or_message_type_name.parent = self - - if options is None: - options = [] - self.options = options - for option in self.options: - option.parent = self - - def __eq__(self, other) -> bool: - return ( - self.key_type == other.key_type - and self.value_type == other.value_type - and self.name == other.name - and self.number == other.number - and self.enum_or_message_type_name == other.enum_or_message_type_name - and self.options == other.options - ) - - def __str__(self) -> str: - return f"<{self.__class__.__name__} key_type={self.key_type} value_type={self.value_type} name={self.name} number={self.number} enum_or_message_type_name={self.enum_or_message_type_name} options={self.options}>" - - def __repr__(self) -> str: - return str(self) - - def normalize(self) -> "ProtoMap": - return ProtoMap( - parent=self.parent, - key_type=self.key_type, - value_type=self.value_type, - name=self.name, - number=self.number, - enum_or_message_type_name=self.enum_or_message_type_name, - options=sorted(self.options, key=lambda o: str(o.normalize())), - ) - - @classmethod - def match( - cls, parent: Optional[ProtoNode], proto_source: str - ) -> Optional["ParsedProtoNode"]: - if proto_source.startswith("map "): - proto_source = proto_source[4:].strip() - elif proto_source.startswith("map<"): - proto_source = proto_source[3:].strip() - else: - return None - - # Try to match the map key type. - proto_source = proto_source[1:].strip() - key_type = None - for potential_key_type in ProtoMapKeyTypesEnum: - if proto_source.startswith(potential_key_type.value): - key_type = potential_key_type - proto_source = proto_source[len(potential_key_type.value) :].strip() - break - if key_type is None: - return None - - if not proto_source.startswith(","): - return None - proto_source = proto_source[1:].strip() - - # Next, try to match the map value type. - value_type: Optional[ProtoMapValueTypesEnum] = None - for potential_value_type in ProtoMapValueTypesEnum: - if potential_value_type == ProtoMapValueTypesEnum.ENUM_OR_MESSAGE: - # This is special-cased below. - break - if proto_source.startswith(potential_value_type.value): - value_type = potential_value_type - proto_source = proto_source[len(potential_value_type.value) :].strip() - - # If this is an enum or message type, try to match a name. - enum_or_message_type_name = None - if value_type is None: - # See if this is an enum or message type. - match = ProtoEnumOrMessageIdentifier.match(None, proto_source) - if match is None: - return None - value_type = ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE - enum_or_message_type_name = match.node - proto_source = match.remaining_source.strip() - - if not proto_source.startswith(">"): - return None - proto_source = proto_source[1:].strip() - - # Try to match the map field's name. - identifier_match = ProtoIdentifier.match(None, proto_source) - if identifier_match is None: - return None - name = identifier_match.node - proto_source = identifier_match.remaining_source.strip() - - if not proto_source.startswith("="): - return None - proto_source = proto_source[1:].strip() - - # Try to match the map field number. - int_match = ProtoInt.match(None, proto_source) - if int_match is None: - return None - number = int_match.node - proto_source = int_match.remaining_source.strip() - - # Try to match map field options, if any. - options = [] - if proto_source.startswith("["): - proto_source = proto_source[1:].strip() - end_bracket = proto_source.find("]") - if end_bracket == -1: - raise ValueError( - f"Proto has invalid map field option syntax, cannot find ]: {proto_source}" - ) - for option_part in proto_source[:end_bracket].strip().split(","): - message_field_option_match = ProtoMessageFieldOption.match( - None, option_part.strip() - ) - if message_field_option_match is None: - raise ValueError( - f"Proto has invalid map field option syntax: {proto_source}" - ) - options.append(message_field_option_match.node) - proto_source = proto_source[end_bracket + 1 :].strip() - - if not proto_source.startswith(";"): - raise ValueError( - f"Proto has invalid map field syntax, missing ending ;:{proto_source}" - ) - - return ParsedProtoNode( - ProtoMap( - parent, - key_type, - value_type, - name, - number, - enum_or_message_type_name, - options, - ), - proto_source[1:].strip(), - ) - - def serialize(self) -> str: - serialized_parts = [ - f"map", - f"<{self.key_type.value},", - ] - - if self.value_type == ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE: - if self.enum_or_message_type_name is None: - raise ValueError( - f"Enum or message type name was not set for: {str(self)}" - ) - serialized_parts.append(f"{self.enum_or_message_type_name.serialize()}>") - else: - serialized_parts.append(f"{self.value_type.value}>") - - serialized_parts = serialized_parts + [ - self.name.serialize(), - "=", - self.number.serialize(), - ] - - if self.options: - serialized_parts.append("[") - serialized_parts.append( - ", ".join(option.serialize() for option in self.options) - ) - serialized_parts.append("]") - - return " ".join(serialized_parts) + ";" - - @staticmethod - def diff( - parent: Optional[ProtoNode], left: "ProtoMap", right: "ProtoMap" - ) -> list["ProtoNodeDiff"]: - if left is None and right is not None: - return [ProtoMapAdded(parent, right)] - elif left is not None and right is None: - return [ProtoMapRemoved(parent, left)] - elif left is None and right is None: - return [] - elif left.name != right.name: - return [] - elif left == right: - return [] - diffs: list["ProtoNodeDiff"] = [] - return diffs - - @staticmethod - def diff_sets( - parent: Optional[ProtoNode], left: list["ProtoMap"], right: list["ProtoMap"] - ) -> Sequence["ProtoNodeDiff"]: - diffs: list[ProtoNodeDiff] = [] - left_names = set(o.name.identifier for o in left) - right_names = set(o.name.identifier for o in right) - for name in left_names - right_names: - diffs.append( - ProtoMapAdded( - parent, next(i for i in left if i.name.identifier == name) - ) - ) - for name in right_names - left_names: - diffs.append( - ProtoMapRemoved( - parent, next(i for i in right if i.name.identifier == name) - ) - ) - for name in left_names & right_names: - left_enum = next(i for i in left if i.name.identifier == name) - right_enum = next(i for i in right if i.name.identifier == name) - diffs.extend(ProtoMap.diff(parent, left_enum, right_enum)) - - return diffs - - -class ProtoMapDiff(ProtoNodeDiff): - def __init__(self, parent: Optional[ProtoNode], map: ProtoMap): - self.parent = parent - self.map = map - - def __eq__(self, other: object) -> bool: - return isinstance(other, ProtoMapDiff) and self.map == other.map - - def __str__(self) -> str: - return f"<{self.__class__.__name__} parent={self.parent} map={self.map}>" - - -class ProtoMapAdded(ProtoMapDiff): - def __eq__(self, other: object) -> bool: - return super().__eq__(other) and isinstance(other, ProtoMapAdded) - - -class ProtoMapRemoved(ProtoMapDiff): - def __eq__(self, other: object) -> bool: - return super().__eq__(other) and isinstance(other, ProtoMapRemoved) - class ProtoMessage(ProtoNode): def __init__( diff --git a/src/proto_oneof.py b/src/proto_oneof.py new file mode 100644 index 0000000..5780710 --- /dev/null +++ b/src/proto_oneof.py @@ -0,0 +1,159 @@ +from typing import Optional, Sequence + +from src.proto_comment import ( + ParsedProtoMultiLineCommentNode, + ParsedProtoSingleLineCommentNode, + ProtoComment, + ProtoMultiLineComment, + ProtoSingleLineComment, +) +from src.proto_identifier import ProtoIdentifier +from src.proto_map import ProtoMap +from src.proto_message_field import ParsedProtoMessageFieldNode, ProtoMessageField +from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_option import ParsedProtoOptionNode, ProtoOption + +ProtoOneOfNodeTypes = ( + ProtoOption | ProtoMessageField | ProtoSingleLineComment | ProtoMultiLineComment +) +ProtoParsedOneOfNodeTypes = ( + ParsedProtoOptionNode + | ParsedProtoMessageFieldNode + | ParsedProtoSingleLineCommentNode + | ParsedProtoMultiLineCommentNode +) + + +class ParsedProtoOneOfNode(ParsedProtoNode): + node: "ProtoOneOf" + remaining_source: str + + +class ProtoOneOf(ProtoNode): + def __init__( + self, + parent: Optional[ProtoNode], + name: ProtoIdentifier, + nodes: Sequence[ProtoOneOfNodeTypes], + ): + super().__init__(parent) + self.name = name + self.name.parent = self + self.nodes = nodes + for node in self.nodes: + node.parent = self + + def __eq__(self, other) -> bool: + return self.name == other.name and self.nodes == other.nodes + + def __str__(self) -> str: + return f"<{self.__class__.__name__} name={self.name}, nodes={self.nodes}>" + + def __repr__(self) -> str: + return str(self) + + def normalize(self) -> "ProtoOneOf": + non_comment_nodes = filter( + lambda n: not isinstance(n, ProtoComment), self.nodes + ) + options = [] + fields = [] + for node in non_comment_nodes: + if isinstance(node, ProtoOption): + options.append(node.normalize()) + elif ( + isinstance(node, ProtoMessageField) + or isinstance(node, ProtoOneOf) + or isinstance(node, ProtoMap) + ): + fields.append(node.normalize()) + else: + raise ValueError( + f"Can't sort message {self} node for normalizing: {node}" + ) + + sorted_nodes_for_normalizing = sorted( + options, key=lambda o: str(o.normalize()) + ) + sorted(fields, key=lambda f: int(f.number)) + + return ProtoOneOf( + parent=self.parent, + name=self.name, + nodes=sorted_nodes_for_normalizing, + ) + + @staticmethod + def parse_partial_content(partial_oneof_content: str) -> ProtoParsedOneOfNodeTypes: + supported_types: list[type[ProtoOneOfNodeTypes]] = [ + ProtoMessageField, + ProtoOption, + ProtoSingleLineComment, + ProtoMultiLineComment, + ] + for node_type in supported_types: + try: + match_result = node_type.match(None, partial_oneof_content) + except (ValueError, IndexError, TypeError): + raise ValueError( + f"Could not parse partial oneof content:\n{partial_oneof_content}" + ) + if match_result is not None: + return match_result + raise ValueError( + f"Could not parse partial oneof content:\n{partial_oneof_content}" + ) + + @classmethod + def match( + cls, parent: Optional[ProtoNode], proto_source: str + ) -> Optional["ParsedProtoOneOfNode"]: + if not proto_source.startswith("oneof "): + return None + + proto_source = proto_source[6:].strip() + + match = ProtoIdentifier.match(None, proto_source) + if match is None: + raise ValueError( + f"Proto has invalid syntax, expecting identifier for oneof: {proto_source}" + ) + + oneof_name = match.node + proto_source = match.remaining_source.strip() + + if not proto_source.startswith("{"): + raise ValueError( + f"Proto has invalid syntax, expecting opening curly brace: {proto_source}" + ) + + proto_source = proto_source[1:].strip() + parsed_tree = [] + while proto_source: + # Remove empty statements. + if proto_source.startswith(";"): + proto_source = proto_source[1:].strip() + continue + + if proto_source.startswith("}"): + proto_source = proto_source[1:].strip() + break + + match_result = ProtoOneOf.parse_partial_content(proto_source) + parsed_tree.append(match_result.node) + proto_source = match_result.remaining_source.strip() + + return ParsedProtoOneOfNode( + ProtoOneOf(parent, oneof_name, nodes=parsed_tree), proto_source + ) + + @property + def options(self) -> list[ProtoOption]: + return [node for node in self.nodes if isinstance(node, ProtoOption)] + + def serialize(self) -> str: + serialize_parts = ( + [f"oneof {self.name.serialize()} {{"] + + [n.serialize() for n in self.nodes] + + ["}"] + ) + return "\n".join(serialize_parts) diff --git a/test/BUILD.bazel b/test/BUILD.bazel index a2954d7..f89b45f 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -125,6 +125,26 @@ py_test( ], ) +py_test( + name = "proto_map_test", + srcs = ["proto_map_test.py"], + deps = [ + "//src:proto_bool", + "//src:proto_comment", + "//src:proto_constant", + "//src:proto_enum", + "//src:proto_extend", + "//src:proto_extensions", + "//src:proto_identifier", + "//src:proto_int", + "//src:proto_map", + "//src:proto_message_field", + "//src:proto_option", + "//src:proto_reserved", + "//src:proto_string_literal", + ], +) + py_test( name = "proto_message_test", srcs = ["proto_message_test.py"], @@ -137,6 +157,7 @@ py_test( "//src:proto_extensions", "//src:proto_identifier", "//src:proto_int", + "//src:proto_map", "//src:proto_message", "//src:proto_option", "//src:proto_reserved", @@ -151,7 +172,7 @@ py_test( "//src:proto_extend", "//src:proto_identifier", "//src:proto_int", - "//src:proto_message", + "//src:proto_message_field", ], ) @@ -206,7 +227,9 @@ py_test( "//src:proto_identifier", "//src:proto_import", "//src:proto_int", + "//src:proto_map", "//src:proto_message", + "//src:proto_message_field", "//src:proto_option", "//src:proto_service", "//src:proto_string_literal", diff --git a/test/parser_test.py b/test/parser_test.py index a9859c3..e5704bd 100644 --- a/test/parser_test.py +++ b/test/parser_test.py @@ -16,15 +16,12 @@ ) from src.proto_import import ProtoImport from src.proto_int import ProtoInt, ProtoIntSign -from src.proto_message import ( - ProtoMap, - ProtoMapKeyTypesEnum, - ProtoMapValueTypesEnum, - ProtoMessage, +from src.proto_map import ProtoMap, ProtoMapKeyTypesEnum, ProtoMapValueTypesEnum +from src.proto_message import ProtoMessage, ProtoOneOf +from src.proto_message_field import ( ProtoMessageField, ProtoMessageFieldOption, ProtoMessageFieldTypesEnum, - ProtoOneOf, ) from src.proto_option import ProtoOption from src.proto_range import ProtoRange, ProtoRangeEnum diff --git a/test/proto_extend_test.py b/test/proto_extend_test.py index b77170b..0bec941 100644 --- a/test/proto_extend_test.py +++ b/test/proto_extend_test.py @@ -4,7 +4,7 @@ from src.proto_extend import ProtoExtend from src.proto_identifier import ProtoEnumOrMessageIdentifier, ProtoIdentifier from src.proto_int import ProtoInt, ProtoIntSign -from src.proto_message import ProtoMessageField, ProtoMessageFieldTypesEnum +from src.proto_message_field import ProtoMessageField, ProtoMessageFieldTypesEnum class ExtendTest(unittest.TestCase): diff --git a/test/proto_map_test.py b/test/proto_map_test.py new file mode 100644 index 0000000..f45d214 --- /dev/null +++ b/test/proto_map_test.py @@ -0,0 +1,100 @@ +import unittest + +from src.proto_constant import ProtoConstant +from src.proto_identifier import ( + ProtoEnumOrMessageIdentifier, + ProtoFullIdentifier, + ProtoIdentifier, +) +from src.proto_int import ProtoInt, ProtoIntSign +from src.proto_map import ProtoMap, ProtoMapKeyTypesEnum, ProtoMapValueTypesEnum +from src.proto_message_field import ProtoMessageFieldOption +from src.proto_string_literal import ProtoStringLiteral + + +class MapTest(unittest.TestCase): + maxDiff = None + + def test_simple_map(self): + parsed_map_simple = ProtoMap.match( + None, "map my_map = 10;" + ) + self.assertEqual( + parsed_map_simple.node, + ProtoMap( + None, + ProtoMapKeyTypesEnum.SFIXED64, + ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, + ProtoIdentifier(None, "my_map"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + [], + ), + ) + + def test_map_without_spaces(self): + map_without_spaces = ProtoMap.match( + None, "map my_map = 10;" + ) + self.assertEqual( + map_without_spaces.node, + ProtoMap( + None, + ProtoMapKeyTypesEnum.SFIXED64, + ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, + ProtoIdentifier(None, "my_map"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + [], + ), + ) + + def test_map_with_options(self): + parsed_map_simple = ProtoMap.match( + None, + "map my_map = 10 [ java_package = 'com.example.foo', baz.bat = 48 ];", + ) + self.assertEqual(parsed_map_simple.node.key_type, ProtoMapKeyTypesEnum.SFIXED64) + self.assertEqual( + parsed_map_simple.node.value_type, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE + ) + self.assertEqual(parsed_map_simple.node.name, ProtoIdentifier(None, "my_map")) + self.assertEqual( + parsed_map_simple.node.number, ProtoInt(None, 10, ProtoIntSign.POSITIVE) + ) + self.assertEqual( + parsed_map_simple.node.enum_or_message_type_name, + ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + ) + self.assertEqual( + parsed_map_simple.node.options, + [ + ProtoMessageFieldOption( + None, + ProtoIdentifier(None, "java_package"), + ProtoConstant(None, ProtoStringLiteral(None, "com.example.foo")), + ), + ProtoMessageFieldOption( + None, + ProtoFullIdentifier(None, "baz.bat"), + ProtoConstant(None, ProtoInt(None, 48, ProtoIntSign.POSITIVE)), + ), + ], + ) + + def test_map_message_value(self): + parsed_map_simple = ProtoMap.match( + None, "map string_map = 11;" + ) + self.assertEqual( + parsed_map_simple.node, + ProtoMap( + None, + ProtoMapKeyTypesEnum.STRING, + ProtoMapValueTypesEnum.STRING, + ProtoIdentifier(None, "string_map"), + ProtoInt(None, 11, ProtoIntSign.POSITIVE), + None, + [], + ), + ) diff --git a/test/proto_message_test.py b/test/proto_message_test.py index 3153c72..2a62886 100644 --- a/test/proto_message_test.py +++ b/test/proto_message_test.py @@ -13,10 +13,8 @@ ProtoIdentifier, ) from src.proto_int import ProtoInt, ProtoIntSign +from src.proto_map import ProtoMap, ProtoMapKeyTypesEnum, ProtoMapValueTypesEnum from src.proto_message import ( - ProtoMap, - ProtoMapKeyTypesEnum, - ProtoMapValueTypesEnum, ProtoMessage, ProtoMessageAdded, ProtoMessageRemoved, From fcc4a3d7ee77bb2a89cb3a4ec975eed636e9c80b Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sat, 18 Feb 2023 23:10:42 -0500 Subject: [PATCH 13/35] Pin bazel version to 6.0.0 (#70) --- .bazelversion | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bazelversion diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000..09b254e --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +6.0.0 From a7eecbd497d11a168bf383c2f4e3068441b78fa1 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sun, 19 Feb 2023 19:52:55 -0500 Subject: [PATCH 14/35] Pull binaries into src.util (#71) --- README.md | 2 +- src/BUILD.bazel | 47 +------------------ src/util/BUILD.bazel | 46 ++++++++++++++++++ src/{ => util}/compatibility_checker.py | 2 +- src/{ => util}/parser.py | 0 test/BUILD.bazel | 43 ----------------- test/compatibility_checker_binary_test.sh | 4 -- test/util/BUILD.bazel | 44 +++++++++++++++++ .../util/compatibility_checker_binary_test.sh | 4 ++ test/{ => util}/parser_binary_test.sh | 4 +- test/{ => util}/parser_test.py | 2 +- 11 files changed, 100 insertions(+), 98 deletions(-) create mode 100644 src/util/BUILD.bazel rename src/{ => util}/compatibility_checker.py (96%) rename src/{ => util}/parser.py (100%) delete mode 100755 test/compatibility_checker_binary_test.sh create mode 100644 test/util/BUILD.bazel create mode 100755 test/util/compatibility_checker_binary_test.sh rename test/{ => util}/parser_binary_test.sh (80%) rename test/{ => util}/parser_test.py (99%) diff --git a/README.md b/README.md index bd8333d..b6e911f 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ py_library( Then, in your Python code, use the parser: ```python -from src.parser import ParseError, Parser +from src.util.parser import ParseError, Parser with open("your.proto", "r") as proto_file: parsed_proto = Parser.loads(proto_file.read()) diff --git a/src/BUILD.bazel b/src/BUILD.bazel index 899a7d5..13dfe8f 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -1,4 +1,4 @@ -load("@rules_python//python:defs.bzl", "py_binary", "py_library") +load("@rules_python//python:defs.bzl", "py_library") py_library( name = "proto_node", @@ -257,48 +257,3 @@ py_library( ":proto_syntax", ], ) - -py_library( - name = "parser", - srcs = ["parser.py"], - visibility = ["//visibility:public"], - deps = [ - ":proto_enum", - ":proto_extend", - ":proto_file", - ":proto_import", - ":proto_message", - ":proto_node", - ":proto_option", - ":proto_package", - ":proto_service", - ":proto_syntax", - ], -) - -py_binary( - name = "parser_binary", - srcs = ["parser.py"], - main = "parser.py", - visibility = ["//visibility:public"], - deps = [":parser"], -) - -py_library( - name = "compatibility_checker", - srcs = ["compatibility_checker.py"], - visibility = ["//visibility:public"], - deps = [ - ":parser", - ":proto_file", - ":proto_node", - ], -) - -py_binary( - name = "compatibility_checker_binary", - srcs = ["compatibility_checker.py"], - main = "compatibility_checker.py", - visibility = ["//visibility:public"], - deps = [":compatibility_checker"], -) diff --git a/src/util/BUILD.bazel b/src/util/BUILD.bazel new file mode 100644 index 0000000..827decd --- /dev/null +++ b/src/util/BUILD.bazel @@ -0,0 +1,46 @@ +load("@rules_python//python:defs.bzl", "py_binary", "py_library") + +py_library( + name = "parser", + srcs = ["parser.py"], + visibility = ["//visibility:public"], + deps = [ + "//src:proto_enum", + "//src:proto_extend", + "//src:proto_file", + "//src:proto_import", + "//src:proto_message", + "//src:proto_node", + "//src:proto_option", + "//src:proto_package", + "//src:proto_service", + "//src:proto_syntax", + ], +) + +py_binary( + name = "parser_binary", + srcs = ["parser.py"], + main = "parser.py", + visibility = ["//visibility:public"], + deps = [":parser"], +) + +py_library( + name = "compatibility_checker", + srcs = ["compatibility_checker.py"], + visibility = ["//visibility:public"], + deps = [ + ":parser", + "//src:proto_file", + "//src:proto_node", + ], +) + +py_binary( + name = "compatibility_checker_binary", + srcs = ["compatibility_checker.py"], + main = "compatibility_checker.py", + visibility = ["//visibility:public"], + deps = [":compatibility_checker"], +) diff --git a/src/compatibility_checker.py b/src/util/compatibility_checker.py similarity index 96% rename from src/compatibility_checker.py rename to src/util/compatibility_checker.py index 8971f72..beb2199 100644 --- a/src/compatibility_checker.py +++ b/src/util/compatibility_checker.py @@ -2,10 +2,10 @@ from dataclasses import dataclass from typing import Type -from src.parser import Parser from src.proto_file import ProtoFile from src.proto_message import ProtoMessageAdded from src.proto_node import ProtoNodeDiff +from src.util.parser import Parser @dataclass diff --git a/src/parser.py b/src/util/parser.py similarity index 100% rename from src/parser.py rename to src/util/parser.py diff --git a/test/BUILD.bazel b/test/BUILD.bazel index f89b45f..47cd15a 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -213,30 +213,6 @@ py_test( ], ) -py_test( - name = "parser_test", - srcs = ["parser_test.py"], - deps = [ - "//src:parser", - "//src:proto_comment", - "//src:proto_constant", - "//src:proto_enum", - "//src:proto_extend", - "//src:proto_extensions", - "//src:proto_float", - "//src:proto_identifier", - "//src:proto_import", - "//src:proto_int", - "//src:proto_map", - "//src:proto_message", - "//src:proto_message_field", - "//src:proto_option", - "//src:proto_service", - "//src:proto_string_literal", - "//src:proto_syntax", - ], -) - py_test( name = "proto_file_test", srcs = ["proto_file_test.py"], @@ -244,22 +220,3 @@ py_test( "//src:proto_file", ], ) - -sh_test( - name = "parser_binary_test", - srcs = ["parser_binary_test.sh"], - data = [ - "//src:parser_binary", - "//test/resources:all_protos", - "@com_google_protobuf//:all_proto", - ], -) - -sh_test( - name = "compatibility_checker_binary_test", - srcs = ["compatibility_checker_binary_test.sh"], - data = [ - "//src:compatibility_checker_binary", - "//test/resources:all_protos", - ], -) diff --git a/test/compatibility_checker_binary_test.sh b/test/compatibility_checker_binary_test.sh deleted file mode 100755 index 0f01063..0000000 --- a/test/compatibility_checker_binary_test.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash -set -euxo pipefail - -./src/compatibility_checker_binary ./test/resources/single_message.proto ./test/resources/empty.proto diff --git a/test/util/BUILD.bazel b/test/util/BUILD.bazel new file mode 100644 index 0000000..5e57fb2 --- /dev/null +++ b/test/util/BUILD.bazel @@ -0,0 +1,44 @@ +load("@rules_python//python:defs.bzl", "py_test") + +py_test( + name = "parser_test", + srcs = ["parser_test.py"], + deps = [ + "//src:proto_comment", + "//src:proto_constant", + "//src:proto_enum", + "//src:proto_extend", + "//src:proto_extensions", + "//src:proto_float", + "//src:proto_identifier", + "//src:proto_import", + "//src:proto_int", + "//src:proto_map", + "//src:proto_message", + "//src:proto_message_field", + "//src:proto_option", + "//src:proto_service", + "//src:proto_string_literal", + "//src:proto_syntax", + "//src/util:parser", + ], +) + +sh_test( + name = "parser_binary_test", + srcs = ["parser_binary_test.sh"], + data = [ + "//src/util:parser_binary", + "//test/resources:all_protos", + "@com_google_protobuf//:all_proto", + ], +) + +sh_test( + name = "compatibility_checker_binary_test", + srcs = ["compatibility_checker_binary_test.sh"], + data = [ + "//src/util:compatibility_checker_binary", + "//test/resources:all_protos", + ], +) diff --git a/test/util/compatibility_checker_binary_test.sh b/test/util/compatibility_checker_binary_test.sh new file mode 100755 index 0000000..da18716 --- /dev/null +++ b/test/util/compatibility_checker_binary_test.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +set -euxo pipefail + +./src/util/compatibility_checker_binary ./test/resources/single_message.proto ./test/resources/empty.proto diff --git a/test/parser_binary_test.sh b/test/util/parser_binary_test.sh similarity index 80% rename from test/parser_binary_test.sh rename to test/util/parser_binary_test.sh index d3885ef..b0a817d 100755 --- a/test/parser_binary_test.sh +++ b/test/util/parser_binary_test.sh @@ -5,12 +5,12 @@ echo "Local protos:" LOCAL_PROTOS=$(find ./test/resources -name "*.proto" | sort) for f in $LOCAL_PROTOS; do echo $f - ./src/parser_binary $f > /dev/null + ./src/util/parser_binary $f > /dev/null done echo "Google protos:" GOOGLE_PROTOS=$(find ./external/com_google_protobuf/src/google/protobuf -name "*.proto" | xargs grep --files-without-match "proto2" | sort) for f in $GOOGLE_PROTOS; do echo $f - ./src/parser_binary $f > /dev/null + ./src/util/parser_binary $f > /dev/null done diff --git a/test/parser_test.py b/test/util/parser_test.py similarity index 99% rename from test/parser_test.py rename to test/util/parser_test.py index e5704bd..08c9470 100644 --- a/test/parser_test.py +++ b/test/util/parser_test.py @@ -1,7 +1,6 @@ import unittest from textwrap import dedent -from src.parser import ParseError, Parser from src.proto_bool import ProtoBool from src.proto_comment import ProtoSingleLineComment from src.proto_constant import ProtoConstant @@ -29,6 +28,7 @@ from src.proto_service import ProtoService, ProtoServiceRPC from src.proto_string_literal import ProtoStringLiteral from src.proto_syntax import ProtoSyntaxType +from src.util.parser import ParseError, Parser class IntTest(unittest.TestCase): From 809a684c370ecce64a127cea4c2b9f3dc3e62239 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Mon, 20 Feb 2023 18:58:34 -0500 Subject: [PATCH 15/35] In messages, support diffing message field changes (#72) - Change semantics around enum value diffs: we no longer support "value has changed number" diffs. Instead, we emit one EnumValueRemoved at the prior number, and one EnumValueAdded at the new number. - Follow same semantics for message field diffs - We used to pass left/right into diff methods. To make the meaning unambiguous, we change this to before/after, and correct a _ton_ of places we were using this inconsistently. --- TODO.md | 2 +- src/proto_enum.py | 118 ++++---- src/proto_import.py | 36 +-- src/proto_map.py | 42 +-- src/proto_message.py | 58 ++-- src/proto_message_field.py | 102 ++++++- src/proto_option.py | 70 ++--- src/proto_package.py | 38 +-- src/proto_syntax.py | 16 +- src/util/compatibility_checker.py | 10 +- test/proto_enum_test.py | 41 +-- test/proto_message_field_test.py | 277 +++++++++++++++++- test/proto_message_test.py | 28 +- test/proto_option_test.py | 34 +-- test/proto_package_test.py | 12 +- .../util/compatibility_checker_binary_test.sh | 2 +- 16 files changed, 633 insertions(+), 253 deletions(-) diff --git a/TODO.md b/TODO.md index e738ea0..0ade4bf 100644 --- a/TODO.md +++ b/TODO.md @@ -74,7 +74,7 @@ - [ ] Message-level diffs - [x] Additions/removals - [x] Option changes - - [ ] Field changes + - [x] Field changes - [ ] Reserved changes - [ ] Nested enum changes - [ ] Nested message changes diff --git a/src/proto_enum.py b/src/proto_enum.py index a5e1f47..c1f682c 100644 --- a/src/proto_enum.py +++ b/src/proto_enum.py @@ -157,61 +157,49 @@ def serialize(self) -> str: @staticmethod def diff( - enum: "ProtoEnum", left: "ProtoEnumValue", right: "ProtoEnumValue" + enum: "ProtoEnum", + before: Optional["ProtoEnumValue"], + after: Optional["ProtoEnumValue"], ) -> Sequence["ProtoNodeDiff"]: - if left is None and right is not None: - return [ProtoEnumValueAdded(right)] - elif left is not None and right is None: - return [ProtoEnumValueRemoved(left)] - elif left is None and right is None: - return [] - elif left.identifier != right.identifier: - return [] - elif left == right: - return [] diffs: list["ProtoNodeDiff"] = [] # TODO: scope these diffs under ProtoEnumValue - diffs.extend(ProtoEnumValueOption.diff_sets(left.options, right.options)) - diffs.append(ProtoEnumValueValueChanged(enum, right, left.value)) + if before is None or after is None: + if after is not None: + diffs.append(ProtoEnumValueAdded(enum, after)) + elif before is not None: + diffs.append(ProtoEnumValueRemoved(enum, before)) + else: + if before.identifier != after.identifier: + diffs.append(ProtoEnumValueNameChanged(enum, before, after.identifier)) + else: + raise ValueError( + f"Don't know how to handle diff between enums whose names aren't identical: {before}, {after}" + ) + diffs.extend(ProtoEnumValueOption.diff_sets(before.options, after.options)) return diffs @staticmethod def diff_sets( - enum: "ProtoEnum", left: list["ProtoEnumValue"], right: list["ProtoEnumValue"] + enum: "ProtoEnum", before: list["ProtoEnumValue"], after: list["ProtoEnumValue"] ) -> list["ProtoNodeDiff"]: diffs: list[ProtoNodeDiff] = [] - left_names = set(o.identifier.identifier for o in left) - left_values = set(int(o.value) for o in left) - right_names = set(o.identifier.identifier for o in right) - right_values = set(int(o.value) for o in right) - - for name in left_names - right_names: - # Check to see if this is a renamed field number. - left_value = next(i for i in left if i.identifier.identifier == name) - if int(left_value.value) in right_values: - # This is a renamed field number. - right_value = next( - i for i in right if int(i.value) == int(left_value.value) - ) - diffs.append( - ProtoEnumValueNameChanged(enum, right_value, left_value.identifier) - ) - else: - diffs.append(ProtoEnumValueAdded(enum, left_value)) - for name in right_names - left_names: - # Check to see if this is a renamed field number. - right_value = next(i for i in right if i.identifier.identifier == name) - if int(right_value.value) not in left_values: - diffs.append( - ProtoEnumValueRemoved( - enum, next(i for i in right if i.identifier.identifier == name) - ) + + before_number_to_enum_values = {int(mf.value): mf for mf in before} + after_number_to_enum_values = {int(mf.value): mf for mf in after} + all_numbers = sorted( + set(before_number_to_enum_values.keys()).union( + set(after_number_to_enum_values.keys()) + ) + ) + for number in all_numbers: + diffs.extend( + ProtoEnumValue.diff( + enum, + before_number_to_enum_values.get(number, None), + after_number_to_enum_values.get(number, None), ) - for name in left_names & right_names: - left_enum_value = next(i for i in left if i.identifier.identifier == name) - right_enum_value = next(i for i in right if i.identifier.identifier == name) - diffs.extend(ProtoEnumValue.diff(enum, left_enum_value, right_enum_value)) + ) return diffs @@ -329,42 +317,42 @@ def serialize(self) -> str: return "\n".join(serialize_parts) @staticmethod - def diff(left: "ProtoEnum", right: "ProtoEnum") -> list["ProtoNodeDiff"]: - if left is None and right is not None: - return [ProtoEnumAdded(right)] - elif left is not None and right is None: - return [ProtoEnumRemoved(left)] - elif left is None and right is None: + def diff(before: "ProtoEnum", after: "ProtoEnum") -> list["ProtoNodeDiff"]: + if before is None and after is not None: + return [ProtoEnumAdded(after)] + elif before is not None and after is None: + return [ProtoEnumRemoved(before)] + elif before is None and after is None: return [] - elif left.name != right.name: + elif before.name != after.name: return [] - elif left == right: + elif before == after: return [] diffs: list[ProtoNodeDiff] = [] # TODO: scope these diffs under ProtoEnum - diffs.extend(ProtoOption.diff_sets(left.options, right.options)) - diffs.extend(ProtoEnumValue.diff_sets(left, left.values, right.values)) + diffs.extend(ProtoOption.diff_sets(before.options, after.options)) + diffs.extend(ProtoEnumValue.diff_sets(before, before.values, after.values)) return diffs @staticmethod def diff_sets( - left: list["ProtoEnum"], right: list["ProtoEnum"] + before: list["ProtoEnum"], after: list["ProtoEnum"] ) -> list["ProtoNodeDiff"]: diffs: list[ProtoNodeDiff] = [] - left_names = set(o.name.identifier for o in left) - right_names = set(o.name.identifier for o in right) - for name in left_names - right_names: + before_names = set(o.name.identifier for o in before) + after_names = set(o.name.identifier for o in after) + for name in before_names - after_names: diffs.append( - ProtoEnumAdded(next(i for i in left if i.name.identifier == name)) + ProtoEnumRemoved(next(i for i in before if i.name.identifier == name)) ) - for name in right_names - left_names: + for name in after_names - before_names: diffs.append( - ProtoEnumRemoved(next(i for i in right if i.name.identifier == name)) + ProtoEnumAdded(next(i for i in after if i.name.identifier == name)) ) - for name in left_names & right_names: - left_enum = next(i for i in left if i.name.identifier == name) - right_enum = next(i for i in right if i.name.identifier == name) - diffs.extend(ProtoEnum.diff(left_enum, right_enum)) + for name in before_names & after_names: + before_enum = next(i for i in before if i.name.identifier == name) + after_enum = next(i for i in after if i.name.identifier == name) + diffs.extend(ProtoEnum.diff(before_enum, after_enum)) return diffs diff --git a/src/proto_import.py b/src/proto_import.py index fdd0ba9..4cda9a3 100644 --- a/src/proto_import.py +++ b/src/proto_import.py @@ -86,26 +86,26 @@ def serialize(self) -> str: @staticmethod def diff_sets( - left: list["ProtoImport"], right: list["ProtoImport"] + before: list["ProtoImport"], after: list["ProtoImport"] ) -> list["ProtoNodeDiff"]: diffs: list[ProtoNodeDiff] = [] - left_names = set(i.path for i in left) - right_names = set(i.path for i in right) - for name in left_names - right_names: - diffs.append(ProtoImportAdded(next(i for i in left if i.path == name))) - for name in right_names - left_names: - diffs.append(ProtoImportRemoved(next(i for i in right if i.path == name))) - for name in left_names & right_names: - left_import = next(i for i in left if i.path == name) - right_import = next(i for i in right if i.path == name) - if left_import.weak and not right_import.weak: - diffs.append(ProtoImportMadeWeak(right_import)) - if not left_import.weak and right_import.weak: - diffs.append(ProtoImportMadeNonWeak(right_import)) - if left_import.public and not right_import.public: - diffs.append(ProtoImportMadePublic(right_import)) - if not left_import.public and right_import.public: - diffs.append(ProtoImportMadeNonPublic(right_import)) + before_names = set(i.path for i in before) + after_names = set(i.path for i in after) + for name in before_names - after_names: + diffs.append(ProtoImportRemoved(next(i for i in before if i.path == name))) + for name in after_names - before_names: + diffs.append(ProtoImportAdded(next(i for i in after if i.path == name))) + for name in before_names & after_names: + before_import = next(i for i in before if i.path == name) + after_import = next(i for i in after if i.path == name) + if before_import.weak and not after_import.weak: + diffs.append(ProtoImportMadeNonWeak(after_import)) + elif not before_import.weak and after_import.weak: + diffs.append(ProtoImportMadeWeak(after_import)) + if before_import.public and not after_import.public: + diffs.append(ProtoImportMadeNonPublic(after_import)) + elif not before_import.public and after_import.public: + diffs.append(ProtoImportMadePublic(after_import)) return diffs diff --git a/src/proto_map.py b/src/proto_map.py index 9d73594..129b46b 100644 --- a/src/proto_map.py +++ b/src/proto_map.py @@ -219,44 +219,44 @@ def serialize(self) -> str: @staticmethod def diff( - parent: Optional[ProtoNode], left: "ProtoMap", right: "ProtoMap" + parent: Optional[ProtoNode], before: "ProtoMap", after: "ProtoMap" ) -> list["ProtoNodeDiff"]: - if left is None and right is not None: - return [ProtoMapAdded(parent, right)] - elif left is not None and right is None: - return [ProtoMapRemoved(parent, left)] - elif left is None and right is None: + if before is None and after is not None: + return [ProtoMapAdded(parent, after)] + elif before is not None and after is None: + return [ProtoMapRemoved(parent, before)] + elif before is None and after is None: return [] - elif left.name != right.name: + elif before.name != after.name: return [] - elif left == right: + elif before == after: return [] diffs: list["ProtoNodeDiff"] = [] return diffs @staticmethod def diff_sets( - parent: Optional[ProtoNode], left: list["ProtoMap"], right: list["ProtoMap"] + parent: Optional[ProtoNode], before: list["ProtoMap"], after: list["ProtoMap"] ) -> Sequence["ProtoNodeDiff"]: diffs: list[ProtoNodeDiff] = [] - left_names = set(o.name.identifier for o in left) - right_names = set(o.name.identifier for o in right) - for name in left_names - right_names: + before_names = set(o.name.identifier for o in before) + after_names = set(o.name.identifier for o in after) + for name in before_names - after_names: diffs.append( - ProtoMapAdded( - parent, next(i for i in left if i.name.identifier == name) + ProtoMapRemoved( + parent, next(i for i in before if i.name.identifier == name) ) ) - for name in right_names - left_names: + for name in after_names - before_names: diffs.append( - ProtoMapRemoved( - parent, next(i for i in right if i.name.identifier == name) + ProtoMapAdded( + parent, next(i for i in after if i.name.identifier == name) ) ) - for name in left_names & right_names: - left_enum = next(i for i in left if i.name.identifier == name) - right_enum = next(i for i in right if i.name.identifier == name) - diffs.extend(ProtoMap.diff(parent, left_enum, right_enum)) + for name in before_names & after_names: + before_enum = next(i for i in before if i.name.identifier == name) + after_enum = next(i for i in after if i.name.identifier == name) + diffs.extend(ProtoMap.diff(parent, before_enum, after_enum)) return diffs diff --git a/src/proto_message.py b/src/proto_message.py index 8c084c9..01277a7 100644 --- a/src/proto_message.py +++ b/src/proto_message.py @@ -160,6 +160,10 @@ def options(self) -> list[ProtoOption]: def maps(self) -> list[ProtoMap]: return [node for node in self.nodes if isinstance(node, ProtoMap)] + @property + def message_fields(self) -> list[ProtoMessageField]: + return [node for node in self.nodes if isinstance(node, ProtoMessageField)] + def serialize(self) -> str: serialize_parts = ( [f"message {self.name.serialize()} {{"] @@ -169,43 +173,51 @@ def serialize(self) -> str: return "\n".join(serialize_parts) @staticmethod - def diff(left: "ProtoMessage", right: "ProtoMessage") -> Sequence["ProtoNodeDiff"]: - if left is None and right is not None: - return [ProtoMessageAdded(right)] - elif left is not None and right is None: - return [ProtoMessageRemoved(left)] - elif left is None and right is None: + def diff( + before: "ProtoMessage", after: "ProtoMessage" + ) -> Sequence["ProtoNodeDiff"]: + if before is None and after is not None: + return [ProtoMessageAdded(after)] + elif before is not None and after is None: + return [ProtoMessageRemoved(before)] + elif before is None and after is None: return [] - elif left.name != right.name: + elif before.name != after.name: return [] - elif left == right: + elif before == after: return [] diffs: list[ProtoNodeDiff] = [] - diffs.extend(ProtoOption.diff_sets(left.options, right.options)) - # diffs.extend(ProtoOneOf.diff_sets(left, left.oneofs, right.oneofs)) - diffs.extend(ProtoMap.diff_sets(left, left.maps, right.maps)) - # diffs.extend(ProtoMessageField.diff_sets(left, left.message_fields, right.message_fields)) + diffs.extend(ProtoOption.diff_sets(before.options, after.options)) + # diffs.extend(ProtoOneOf.diff_sets(before, before.oneofs, after.oneofs)) + diffs.extend(ProtoMap.diff_sets(before, before.maps, after.maps)) + diffs.extend( + ProtoMessageField.diff_sets( + before, before.message_fields, after.message_fields + ) + ) return diffs @staticmethod def diff_sets( - left: list["ProtoMessage"], right: list["ProtoMessage"] + before: list["ProtoMessage"], after: list["ProtoMessage"] ) -> Sequence["ProtoNodeDiff"]: diffs: list[ProtoNodeDiff] = [] - left_names = set(o.name.identifier for o in left) - right_names = set(o.name.identifier for o in right) - for name in left_names - right_names: + before_names = set(o.name.identifier for o in before) + after_names = set(o.name.identifier for o in after) + for name in before_names - after_names: diffs.append( - ProtoMessageAdded(next(i for i in left if i.name.identifier == name)) + ProtoMessageRemoved( + next(i for i in before if i.name.identifier == name) + ) ) - for name in right_names - left_names: + for name in after_names - before_names: diffs.append( - ProtoMessageRemoved(next(i for i in right if i.name.identifier == name)) + ProtoMessageAdded(next(i for i in after if i.name.identifier == name)) ) - for name in left_names & right_names: - left_enum = next(i for i in left if i.name.identifier == name) - right_enum = next(i for i in right if i.name.identifier == name) - diffs.extend(ProtoMessage.diff(left_enum, right_enum)) + for name in before_names & after_names: + before_enum = next(i for i in before if i.name.identifier == name) + after_enum = next(i for i in after if i.name.identifier == name) + diffs.extend(ProtoMessage.diff(before_enum, after_enum)) return diffs diff --git a/src/proto_message_field.py b/src/proto_message_field.py index 390cef8..aa5c7c2 100644 --- a/src/proto_message_field.py +++ b/src/proto_message_field.py @@ -1,10 +1,10 @@ from enum import Enum -from typing import Optional +from typing import Optional, Sequence from src.proto_enum import ParsedProtoEnumValueOptionNode, ProtoEnumValueOption from src.proto_identifier import ProtoEnumOrMessageIdentifier, ProtoIdentifier from src.proto_int import ProtoInt -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff class ParsedProtoMessageFieldOptionNode(ParsedProtoEnumValueOptionNode): @@ -241,3 +241,101 @@ def serialize(self) -> str: serialized_parts.append("]") return " ".join(serialized_parts) + ";" + + @staticmethod + def diff( + parent: "ProtoNode", + before: Optional["ProtoMessageField"], + after: Optional["ProtoMessageField"], + ) -> Sequence["ProtoNodeDiff"]: + # TODO: scope these diffs under ProtoMessageField + diffs: list["ProtoNodeDiff"] = [] + if before is None or after is None: + if after is not None: + diffs.append(ProtoMessageFieldAdded(parent, after)) + elif before is not None: + diffs.append(ProtoMessageFieldRemoved(parent, before)) + else: + if before.name != after.name: + diffs.append(ProtoMessageFieldNameChanged(parent, before, after.name)) + if before.number != after.number: + raise ValueError( + f"Don't know how to handle diff between message fields whose names are identical: {before}, {after}" + ) + diffs.extend( + ProtoMessageFieldOption.diff_sets(before.options, after.options) + ) + return diffs + + @staticmethod + def diff_sets( + parent: "ProtoNode", + before: list["ProtoMessageField"], + after: list["ProtoMessageField"], + ) -> list["ProtoNodeDiff"]: + diffs: list[ProtoNodeDiff] = [] + + before_number_to_fields = {int(mf.number): mf for mf in before} + after_number_to_fields = {int(mf.number): mf for mf in after} + all_numbers = sorted( + set(before_number_to_fields.keys()).union( + set(after_number_to_fields.keys()) + ) + ) + for number in all_numbers: + diffs.extend( + ProtoMessageField.diff( + parent, + before_number_to_fields.get(number, None), + after_number_to_fields.get(number, None), + ) + ) + + return diffs + + +class ProtoMessageFieldDiff(ProtoNodeDiff): + def __init__(self, message: "ProtoNode", message_field: "ProtoMessageField"): + super().__init__() + self.message = message + self.message_field = message_field + + def __eq__(self, other: object) -> bool: + return ( + super().__eq__(other) + and isinstance(other, ProtoMessageFieldDiff) + and self.message == other.message + and self.message_field == other.message_field + ) + + def __str__(self) -> str: + return f"<{self.__class__.__name__} message={self.message} message_field={self.message_field}>" + + +class ProtoMessageFieldAdded(ProtoMessageFieldDiff): + pass + + +class ProtoMessageFieldRemoved(ProtoMessageFieldDiff): + pass + + +class ProtoMessageFieldNameChanged(ProtoMessageFieldDiff): + def __init__( + self, + message: ProtoNode, + message_field: ProtoMessageField, + new_name: ProtoIdentifier, + ): + super().__init__(message, message_field) + self.new_name = new_name + + def __eq__(self, other: object) -> bool: + return ( + super().__eq__(other) + and isinstance(other, ProtoMessageFieldNameChanged) + and self.new_name == other.new_name + ) + + def __str__(self) -> str: + return f"" diff --git a/src/proto_option.py b/src/proto_option.py index 312dcac..4090378 100644 --- a/src/proto_option.py +++ b/src/proto_option.py @@ -123,38 +123,40 @@ def serialize(self) -> str: return f"option {self.name.serialize()} = {self.value.serialize()};" @staticmethod - def diff(left: "ProtoOption", right: "ProtoOption") -> Sequence["ProtoOptionDiff"]: - if left is None and right is not None: - return [ProtoOptionAdded(right)] - elif left is not None and right is None: - return [ProtoOptionRemoved(left)] - elif left is None and right is None: + def diff( + before: "ProtoOption", after: "ProtoOption" + ) -> Sequence["ProtoOptionDiff"]: + if before is None and after is not None: + return [ProtoOptionAdded(after)] + elif before is not None and after is None: + return [ProtoOptionRemoved(before)] + elif before is None and after is None: return [] - elif left.name != right.name: + elif before.name != after.name: return [] - elif left == right: + elif before == after: return [] - return [ProtoOptionValueChanged(left.name, left.value, right.value)] + return [ProtoOptionValueChanged(before.name, before.value, after.value)] @staticmethod def diff_sets( - left: Sequence["ProtoOption"], right: Sequence["ProtoOption"] + before: Sequence["ProtoOption"], after: Sequence["ProtoOption"] ) -> list["ProtoOptionDiff"]: diffs: list[ProtoOptionDiff] = [] - left_names = set(o.name.identifier for o in left) - right_names = set(o.name.identifier for o in right) - for name in left_names - right_names: + before_names = set(o.name.identifier for o in before) + after_names = set(o.name.identifier for o in after) + for name in before_names - after_names: diffs.append( - ProtoOptionAdded(next(i for i in left if i.name.identifier == name)) + ProtoOptionRemoved(next(i for i in before if i.name.identifier == name)) ) - for name in right_names - left_names: + for name in after_names - before_names: diffs.append( - ProtoOptionRemoved(next(i for i in right if i.name.identifier == name)) + ProtoOptionAdded(next(i for i in after if i.name.identifier == name)) ) - for name in left_names & right_names: - left_option = next(i for i in left if i.name.identifier == name) - right_option = next(i for i in right if i.name.identifier == name) - diffs.extend(ProtoOption.diff(left_option, right_option)) + for name in before_names & after_names: + before_option = next(i for i in before if i.name.identifier == name) + after_option = next(i for i in after if i.name.identifier == name) + diffs.extend(ProtoOption.diff(before_option, after_option)) return diffs @@ -165,41 +167,41 @@ class ProtoOptionDiff(ProtoNodeDiff): class ProtoOptionValueChanged(ProtoOptionDiff): def __init__( - self, name: ProtoIdentifier, left: ProtoConstant, right: ProtoConstant + self, name: ProtoIdentifier, before: ProtoConstant, after: ProtoConstant ): self.name = name - self.left = left - self.right = right + self.before = before + self.after = after def __eq__(self, other: object) -> bool: return ( isinstance(other, ProtoOptionValueChanged) and self.name == other.name - and self.left == other.left - and self.right == other.right + and self.before == other.before + and self.after == other.after ) def __str__(self) -> str: - return f"" + return f"" class ProtoOptionAdded(ProtoOptionDiff): - def __init__(self, left: ProtoOption): - self.left = left + def __init__(self, before: ProtoOption): + self.before = before def __eq__(self, other: object) -> bool: - return isinstance(other, ProtoOptionAdded) and self.left == other.left + return isinstance(other, ProtoOptionAdded) and self.before == other.before def __str__(self) -> str: - return f"" + return f"" class ProtoOptionRemoved(ProtoOptionDiff): - def __init__(self, right: ProtoOption): - self.right = right + def __init__(self, after: ProtoOption): + self.after = after def __eq__(self, other: object) -> bool: - return isinstance(other, ProtoOptionRemoved) and self.right == other.right + return isinstance(other, ProtoOptionRemoved) and self.after == other.after def __str__(self) -> str: - return f"" + return f"" diff --git a/src/proto_package.py b/src/proto_package.py index d6d714a..f460d30 100644 --- a/src/proto_package.py +++ b/src/proto_package.py @@ -54,43 +54,43 @@ def serialize(self) -> str: @staticmethod def diff( - left: Optional["ProtoPackage"], right: Optional["ProtoPackage"] + before: Optional["ProtoPackage"], after: Optional["ProtoPackage"] ) -> list["ProtoNodeDiff"]: - if left == right: + if before == after: return [] - elif left is not None and right is None: - return [ProtoPackageAdded(left)] - elif left is None and right is not None: - return [ProtoPackageRemoved(right)] + elif before is not None and after is None: + return [ProtoPackageRemoved(before)] + elif before is None and after is not None: + return [ProtoPackageAdded(after)] - assert left is not None and right is not None - return [ProtoPackageChanged(left, right)] + assert before is not None and after is not None + return [ProtoPackageChanged(before, after)] class ProtoPackageChanged(ProtoNodeDiff): - def __init__(self, left: ProtoPackage, right: ProtoPackage): - self.left = left - self.right = right + def __init__(self, before: ProtoPackage, after: ProtoPackage): + self.before = before + self.after = after def __eq__(self, other: object) -> bool: return ( isinstance(other, ProtoPackageChanged) - and self.left == other.left - and self.right == other.right + and self.before == other.before + and self.after == other.after ) class ProtoPackageAdded(ProtoNodeDiff): - def __init__(self, left: ProtoPackage): - self.left = left + def __init__(self, after: ProtoPackage): + self.after = after def __eq__(self, other: object) -> bool: - return isinstance(other, ProtoPackageAdded) and self.left == other.left + return isinstance(other, ProtoPackageAdded) and self.after == other.after class ProtoPackageRemoved(ProtoNodeDiff): - def __init__(self, right: ProtoPackage): - self.right = right + def __init__(self, before: ProtoPackage): + self.before = before def __eq__(self, other: object) -> bool: - return isinstance(other, ProtoPackageRemoved) and self.right == other.right + return isinstance(other, ProtoPackageRemoved) and self.before == other.before diff --git a/src/proto_syntax.py b/src/proto_syntax.py index 3e2220c..13bc3c4 100644 --- a/src/proto_syntax.py +++ b/src/proto_syntax.py @@ -63,20 +63,20 @@ def serialize(self) -> str: return f"syntax = {self.syntax.serialize()};" @staticmethod - def diff(left: "ProtoSyntax", right: "ProtoSyntax") -> list["ProtoNodeDiff"]: - if left == right: + def diff(before: "ProtoSyntax", after: "ProtoSyntax") -> list["ProtoNodeDiff"]: + if before == after: return [] - return [ProtoSyntaxChanged(left, right)] + return [ProtoSyntaxChanged(before, after)] class ProtoSyntaxChanged(ProtoNodeDiff): - def __init__(self, left: ProtoSyntax, right: ProtoSyntax): - self.left = left - self.right = right + def __init__(self, before: ProtoSyntax, after: ProtoSyntax): + self.before = before + self.after = after def __eq__(self, other: object) -> bool: return ( isinstance(other, ProtoSyntaxChanged) - and self.left == other.left - and self.right == other.right + and self.before == other.before + and self.after == other.after ) diff --git a/src/util/compatibility_checker.py b/src/util/compatibility_checker.py index beb2199..45b16f5 100644 --- a/src/util/compatibility_checker.py +++ b/src/util/compatibility_checker.py @@ -12,8 +12,8 @@ class CompatibilityChecker: allowed_diff_types: list[Type[ProtoNodeDiff]] - def check_compatibility(self, left: ProtoFile, right: ProtoFile): - for diff in left.diff(right): + def check_compatibility(self, before: ProtoFile, after: ProtoFile): + for diff in before.diff(after): if diff.__class__ in self.allowed_diff_types: continue yield diff @@ -21,13 +21,13 @@ def check_compatibility(self, left: ProtoFile, right: ProtoFile): def main() -> int: with open(sys.argv[1], "r") as proto_file: - left = Parser.loads(proto_file.read()) + before = Parser.loads(proto_file.read()) with open(sys.argv[2], "r") as proto_file: - right = Parser.loads(proto_file.read()) + after = Parser.loads(proto_file.read()) violations = list( - CompatibilityChecker([ProtoMessageAdded]).check_compatibility(left, right) + CompatibilityChecker([ProtoMessageAdded]).check_compatibility(before, after) ) if violations: print(f"Violations: {violations}") diff --git a/test/proto_enum_test.py b/test/proto_enum_test.py index 1efafc7..095bad5 100644 --- a/test/proto_enum_test.py +++ b/test/proto_enum_test.py @@ -9,9 +9,10 @@ ProtoEnumAdded, ProtoEnumRemoved, ProtoEnumValue, + ProtoEnumValueAdded, ProtoEnumValueNameChanged, ProtoEnumValueOption, - ProtoEnumValueValueChanged, + ProtoEnumValueRemoved, ) from src.proto_identifier import ProtoIdentifier from src.proto_int import ProtoInt, ProtoIntSign @@ -413,14 +414,14 @@ def test_diff_different_enum_value_name_returns_enum_diff(self): ], ) self.assertEqual( - ProtoEnum.diff(pe1, pe2), [ ProtoEnumValueNameChanged( pe1, - pe2.nodes[0], - ProtoIdentifier(None, "ME_UNKNOWN"), + pe1.nodes[0], + ProtoIdentifier(None, "ME_KNOWN"), ) ], + ProtoEnum.diff(pe1, pe2), ) def test_diff_different_enum_value_value_returns_enum_diff(self): @@ -450,14 +451,20 @@ def test_diff_different_enum_value_value_returns_enum_diff(self): diff = ProtoEnum.diff(pe1, pe2) self.assertIn( - ProtoEnumValueValueChanged( + ProtoEnumValueRemoved( + pe1, + pe1.values[0], + ), + diff, + ) + self.assertIn( + ProtoEnumValueAdded( pe1, pe2.values[0], - ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), diff, ) - self.assertEqual(1, len(diff)) + self.assertEqual(2, len(diff)) def test_diff_enum_added(self): pe1 = None @@ -999,11 +1006,11 @@ def test_diff_sets_overlap(self): ProtoEnumRemoved( ProtoEnum( None, - ProtoIdentifier(None, "FooEnum2"), + ProtoIdentifier(None, "FooEnum"), [ ProtoEnumValue( None, - ProtoIdentifier(None, "FE_UNKNOWN2"), + ProtoIdentifier(None, "FE_UNKNOWN"), ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], @@ -1016,11 +1023,11 @@ def test_diff_sets_overlap(self): ProtoEnumRemoved( ProtoEnum( None, - ProtoIdentifier(None, "TagEnum2"), + ProtoIdentifier(None, "TagEnum"), [ ProtoEnumValue( None, - ProtoIdentifier(None, "TE_UNKNOWN2"), + ProtoIdentifier(None, "TE_UNKNOWN"), ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], @@ -1032,11 +1039,11 @@ def test_diff_sets_overlap(self): ProtoEnumAdded( ProtoEnum( None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier(None, "FooEnum2"), [ ProtoEnumValue( None, - ProtoIdentifier(None, "FE_UNKNOWN"), + ProtoIdentifier(None, "FE_UNKNOWN2"), ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], @@ -1048,11 +1055,11 @@ def test_diff_sets_overlap(self): ProtoEnumAdded( ProtoEnum( None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier(None, "TagEnum2"), [ ProtoEnumValue( None, - ProtoIdentifier(None, "TE_UNKNOWN"), + ProtoIdentifier(None, "TE_UNKNOWN2"), ProtoInt(None, 0, ProtoIntSign.POSITIVE), ) ], @@ -1075,10 +1082,10 @@ def test_diff_sets_overlap(self): ), ProtoEnumValue( None, - ProtoIdentifier(None, "BE_UNKNOWN2"), + ProtoIdentifier(None, "BE_UNKNOWN"), ProtoInt(None, 0, ProtoIntSign.POSITIVE), ), - ProtoIdentifier(None, "BE_UNKNOWN"), + ProtoIdentifier(None, "BE_UNKNOWN2"), ), diff, ) diff --git a/test/proto_message_field_test.py b/test/proto_message_field_test.py index eb64ca3..513e1f8 100644 --- a/test/proto_message_field_test.py +++ b/test/proto_message_field_test.py @@ -6,7 +6,13 @@ ProtoIdentifier, ) from src.proto_int import ProtoInt, ProtoIntSign -from src.proto_message_field import ProtoMessageField, ProtoMessageFieldTypesEnum +from src.proto_message_field import ( + ProtoMessageField, + ProtoMessageFieldAdded, + ProtoMessageFieldNameChanged, + ProtoMessageFieldRemoved, + ProtoMessageFieldTypesEnum, +) class MessageFieldTest(unittest.TestCase): @@ -73,7 +79,7 @@ def test_message_field_starts_with_underscore(self): parsed_double_undescored_field.node, ProtoMessageField( None, - ProtoMessageFieldTypesEnum.STRING, + ProtoMessageFieldTypesEnum.BOOL, ProtoIdentifier(None, "__test_field"), ProtoInt(None, 1, ProtoIntSign.POSITIVE), ), @@ -127,3 +133,270 @@ def test_field_starts_with_period(self): ProtoEnumOrMessageIdentifier(None, ".google.proto.FooType"), ), ) + + def test_diff_same_field_returns_empty(self): + pmf1 = ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "my_message_field"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ) + pmf2 = ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "my_message_field"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ) + self.assertEqual(ProtoMessageField.diff(None, pmf1, pmf2), []) + + def test_diff_different_field_name_same_number_returns_field_diff(self): + pmf1 = ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "foo"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ) + pmf2 = ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "bar"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ) + self.assertEqual( + [ + ProtoMessageFieldNameChanged( + None, + pmf1, + pmf2.name, + ) + ], + ProtoMessageField.diff(None, pmf1, pmf2), + ) + + def test_diff_field_removed(self): + pmf1 = ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "foo"), + ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ) + pmf2 = None + self.assertEqual( + [ + ProtoMessageFieldRemoved(None, pmf1), + ], + ProtoMessageField.diff(None, pmf1, pmf2), + ) + + def test_diff_sets_empty_returns_empty(self): + set1 = [] + set2 = [] + self.assertEqual(ProtoMessageField.diff_sets(None, set1, set2), []) + + def test_diff_sets_no_change(self): + set1 = [ + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "foo"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "bar"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "baz"), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ), + ] + self.assertEqual([], ProtoMessageField.diff_sets(None, set1, set1)) + + def test_diff_sets_all_removed(self): + set1 = [] + set2 = [ + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "foo"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "bar"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "baz"), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ), + ] + diff = ProtoMessageField.diff_sets(None, set1, set2) + + for pmf in set2: + self.assertIn( + ProtoMessageFieldRemoved(None, pmf), + diff, + ) + self.assertEqual(3, len(diff)) + + def test_diff_sets_all_added(self): + set1 = [ + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "foo"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "bar"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "baz"), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ), + ] + set2 = [] + diff = ProtoMessageField.diff_sets(None, set1, set2) + + for pmf in set1: + self.assertIn( + ProtoMessageFieldAdded(None, pmf), + diff, + ) + + self.assertEqual(3, len(diff)) + + def test_diff_sets_mutually_exclusive(self): + set1 = [ + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "foo"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "bar"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "baz"), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ), + ] + set2 = [ + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "foo2"), + ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "bar2"), + ProtoInt(None, 5, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "baz2"), + ProtoInt(None, 6, ProtoIntSign.POSITIVE), + ), + ] + + diff = ProtoMessageField.diff_sets(None, set1, set2) + + for pmf in set1: + self.assertIn( + ProtoMessageFieldAdded(None, pmf), + diff, + ) + + for pmf in set2: + self.assertIn( + ProtoMessageFieldRemoved(None, pmf), + diff, + ) + + self.assertEqual(6, len(diff)) + + def test_diff_sets_overlap(self): + set1 = [ + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "foo"), + ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "bar"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "baz"), + ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ), + ] + set2 = [ + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "foo2"), + ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "bar"), + ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + None, + ProtoMessageFieldTypesEnum.FLOAT, + ProtoIdentifier(None, "baz2"), + ProtoInt(None, 6, ProtoIntSign.POSITIVE), + ), + ] + + diff = ProtoMessageField.diff_sets(None, set1, set2) + + self.assertIn( + ProtoMessageFieldRemoved(None, set1[0]), + diff, + ) + + self.assertIn( + ProtoMessageFieldRemoved(None, set1[2]), + diff, + ) + self.assertIn( + ProtoMessageFieldAdded(None, set2[0]), + diff, + ) + self.assertIn( + ProtoMessageFieldAdded(None, set2[2]), + diff, + ) + + self.assertEqual(4, len(diff)) diff --git a/test/proto_message_test.py b/test/proto_message_test.py index 2a62886..9e0f684 100644 --- a/test/proto_message_test.py +++ b/test/proto_message_test.py @@ -941,12 +941,12 @@ def test_diff_sets_no_change_returns_empty(self): self.assertEqual(ProtoMessage.diff_sets(set1, set1), []) def test_diff_sets_all_removed(self): - set1 = [] - set2 = [ + set1 = [ ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), ] + set2 = [] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( ProtoMessageRemoved( @@ -969,12 +969,12 @@ def test_diff_sets_all_removed(self): self.assertEqual(3, len(diff)) def test_diff_sets_all_added(self): - set1 = [ + set1 = [] + set2 = [ ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), ] - set2 = [] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( @@ -1011,37 +1011,37 @@ def test_diff_sets_mutually_exclusive(self): diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) + ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []) ), diff, ) self.assertIn( ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []) + ProtoMessage(None, ProtoIdentifier(None, "BarMessage2"), []) ), diff, ) self.assertIn( ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) + ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []) ), diff, ) self.assertIn( ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []) + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) ), diff, ) self.assertIn( ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "BarMessage2"), []) + ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []) ), diff, ) self.assertIn( ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []) + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) ), diff, ) @@ -1062,25 +1062,25 @@ def test_diff_sets_overlap(self): diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) + ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []) ), diff, ) self.assertIn( ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) + ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []) ), diff, ) self.assertIn( ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []) + ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) ), diff, ) self.assertIn( ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []) + ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) ), diff, ) diff --git a/test/proto_option_test.py b/test/proto_option_test.py index b1f4ff1..b4f52fc 100644 --- a/test/proto_option_test.py +++ b/test/proto_option_test.py @@ -328,8 +328,7 @@ def test_diff_sets_no_change(self): self.assertEqual(ProtoOption.diff_sets(set1, set1), []) def test_diff_sets_all_removed(self): - set1 = [] - set2 = [ + set1 = [ ProtoOption( None, ProtoIdentifier(None, "some.custom.option"), @@ -346,6 +345,7 @@ def test_diff_sets_all_removed(self): ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] + set2 = [] diff = ProtoOption.diff_sets(set1, set2) self.assertIn( @@ -381,7 +381,8 @@ def test_diff_sets_all_removed(self): self.assertEqual(3, len(diff)) def test_diff_sets_all_added(self): - set1 = [ + set1 = [] + set2 = [ ProtoOption( None, ProtoIdentifier(None, "some.custom.option"), @@ -398,7 +399,6 @@ def test_diff_sets_all_added(self): ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] - set2 = [] diff = ProtoOption.diff_sets(set1, set2) self.assertIn( @@ -437,34 +437,34 @@ def test_diff_sets_mutually_exclusive(self): set1 = [ ProtoOption( None, - ProtoIdentifier(None, "some.custom.option.but.not.prior"), + ProtoIdentifier(None, "some.custom.option"), ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( None, - ProtoIdentifier(None, "ruby_package"), + ProtoIdentifier(None, "java_package"), ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), ProtoOption( None, - ProtoIdentifier(None, "other.option.but.stil.not.prior"), + ProtoIdentifier(None, "other.option"), ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] set2 = [ ProtoOption( None, - ProtoIdentifier(None, "some.custom.option"), + ProtoIdentifier(None, "some.custom.option.but.not.prior"), ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( None, - ProtoIdentifier(None, "java_package"), + ProtoIdentifier(None, "ruby_package"), ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), ProtoOption( None, - ProtoIdentifier(None, "other.option"), + ProtoIdentifier(None, "other.option.but.stil.not.prior"), ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] @@ -542,34 +542,34 @@ def test_diff_sets_overlap(self): set1 = [ ProtoOption( None, - ProtoIdentifier(None, "some.custom.option.but.not.prior"), + ProtoIdentifier(None, "some.custom.option"), ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( None, ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.bat")), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), ), ProtoOption( None, - ProtoIdentifier(None, "other.option.but.stil.not.prior"), + ProtoIdentifier(None, "other.option"), ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] set2 = [ ProtoOption( None, - ProtoIdentifier(None, "some.custom.option"), + ProtoIdentifier(None, "some.custom.option.but.not.prior"), ProtoConstant(None, ProtoStringLiteral(None, "some value")), ), ProtoOption( None, ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.bat")), ), ProtoOption( None, - ProtoIdentifier(None, "other.option"), + ProtoIdentifier(None, "other.option.but.stil.not.prior"), ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), ), ] @@ -620,8 +620,8 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoOptionValueChanged( ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.bat")), ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.bat")), ), diff, ) diff --git a/test/proto_package_test.py b/test/proto_package_test.py index 20289a9..611dd37 100644 --- a/test/proto_package_test.py +++ b/test/proto_package_test.py @@ -82,23 +82,23 @@ def test_diff_different_package_returns_package_diff(self): ) def test_diff_package_added(self): - pp1 = ProtoPackage(None, "my.new.package") - pp2 = None + pp1 = None + pp2 = ProtoPackage(None, "my.new.package") self.assertEqual( - ProtoPackage.diff(pp1, pp2), [ ProtoPackageAdded(ProtoPackage(None, "my.new.package")), ], + ProtoPackage.diff(pp1, pp2), ) def test_diff_package_removed(self): - pp1 = None - pp2 = ProtoPackage(None, "my.old.package") + pp1 = ProtoPackage(None, "my.old.package") + pp2 = None self.assertEqual( - ProtoPackage.diff(pp1, pp2), [ ProtoPackageRemoved(ProtoPackage(None, "my.old.package")), ], + ProtoPackage.diff(pp1, pp2), ) diff --git a/test/util/compatibility_checker_binary_test.sh b/test/util/compatibility_checker_binary_test.sh index da18716..63cd61f 100755 --- a/test/util/compatibility_checker_binary_test.sh +++ b/test/util/compatibility_checker_binary_test.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -euxo pipefail -./src/util/compatibility_checker_binary ./test/resources/single_message.proto ./test/resources/empty.proto +./src/util/compatibility_checker_binary ./test/resources/empty.proto ./test/resources/single_message.proto From ec5bc9d109fffa0c985874c055d2bf22e7c4ba7e Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Mon, 20 Feb 2023 19:01:41 -0500 Subject: [PATCH 16/35] Fix target names in readme (#73) --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6e911f..5e98825 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ This is a Python-based protobuf parser. It is intended to serve as a reference i Right now, the primary way to use this as a library in your Bazelified Python code. -Mount this repo in your Bazel workspace, then add `@py_proto//src:parser` as a dependency: +Mount this repo in your Bazel workspace, then add `@py_proto//src/util:parser` as a dependency: ``` py_library( name = "your_python_code", # ... deps = [ - "@py_proto//src:parser", + "@py_proto//src/util:parser", ] ) ``` From b04dd94014130f66a6d894d766ae0f33a7bf3f5d Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Mon, 20 Feb 2023 19:08:47 -0500 Subject: [PATCH 17/35] Actually run two test suites that were accidentally off (#74) --- test/proto_map_test.py | 4 ++++ test/proto_message_field_test.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/test/proto_map_test.py b/test/proto_map_test.py index f45d214..b67c424 100644 --- a/test/proto_map_test.py +++ b/test/proto_map_test.py @@ -98,3 +98,7 @@ def test_map_message_value(self): [], ), ) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/proto_message_field_test.py b/test/proto_message_field_test.py index 513e1f8..26c82e6 100644 --- a/test/proto_message_field_test.py +++ b/test/proto_message_field_test.py @@ -400,3 +400,7 @@ def test_diff_sets_overlap(self): ) self.assertEqual(4, len(diff)) + + +if __name__ == "__main__": + unittest.main() From 062c2c98783a9e69ec47db55169725967f0770e7 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Mon, 20 Feb 2023 22:32:41 -0500 Subject: [PATCH 18/35] Simplify API, by making parent an optional argument in ProtoNode (#75) --- src/proto_bool.py | 10 +- src/proto_comment.py | 16 +- src/proto_constant.py | 38 +-- src/proto_enum.py | 52 +-- src/proto_extend.py | 15 +- src/proto_extensions.py | 17 +- src/proto_float.py | 17 +- src/proto_identifier.py | 30 +- src/proto_import.py | 11 +- src/proto_int.py | 12 +- src/proto_map.py | 29 +- src/proto_message.py | 15 +- src/proto_message_field.py | 37 +- src/proto_node.py | 6 +- src/proto_oneof.py | 15 +- src/proto_option.py | 30 +- src/proto_package.py | 10 +- src/proto_range.py | 19 +- src/proto_reserved.py | 16 +- src/proto_service.py | 55 ++- src/proto_string_literal.py | 8 +- src/proto_syntax.py | 12 +- src/util/parser.py | 6 +- test/proto_bool_test.py | 20 +- test/proto_comment_test.py | 28 +- test/proto_constant_test.py | 164 ++++----- test/proto_enum_test.py | 545 +++++++++++------------------- test/proto_extend_test.py | 22 +- test/proto_extensions_test.py | 12 +- test/proto_float_test.py | 74 ++-- test/proto_identifier_test.py | 92 +++-- test/proto_import_test.py | 66 ++-- test/proto_int_test.py | 24 +- test/proto_map_test.py | 48 +-- test/proto_message_field_test.py | 190 +++++------ test/proto_message_test.py | 523 ++++++++++------------------ test/proto_option_test.py | 383 +++++++++------------ test/proto_package_test.py | 54 ++- test/proto_range_test.py | 32 +- test/proto_reserved_test.py | 18 +- test/proto_service_test.py | 174 ++++------ test/proto_string_literal_test.py | 26 +- test/proto_syntax_test.py | 64 ++-- test/util/parser_test.py | 193 ++++------- 44 files changed, 1365 insertions(+), 1863 deletions(-) diff --git a/src/proto_bool.py b/src/proto_bool.py index 879f0ff..d61d5a0 100644 --- a/src/proto_bool.py +++ b/src/proto_bool.py @@ -10,8 +10,8 @@ class ParsedProtoBoolNode(ParsedProtoNode): class ProtoBool(ProtoNode): - def __init__(self, parent: Optional[ProtoNode], value: bool): - super().__init__(parent) + def __init__(self, value: bool, *args, **kwargs): + super().__init__(*args, **kwargs) self.value = value def __bool__(self) -> bool: @@ -31,19 +31,19 @@ def normalize(self) -> "ProtoBool": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoBoolNode"]: if proto_source.startswith("true") and ( len(proto_source) == 4 or proto_source[4] not in ProtoFullIdentifier.ALL ): return ParsedProtoBoolNode( - ProtoBool(parent, True), proto_source[4:].strip() + ProtoBool(value=True, parent=parent), proto_source[4:].strip() ) elif proto_source.startswith("false") and ( len(proto_source) == 5 or proto_source[5] not in ProtoFullIdentifier.ALL ): return ParsedProtoBoolNode( - ProtoBool(parent, False), proto_source[5:].strip() + ProtoBool(value=False, parent=parent), proto_source[5:].strip() ) return None diff --git a/src/proto_comment.py b/src/proto_comment.py index d3d6db7..bf7b3d7 100644 --- a/src/proto_comment.py +++ b/src/proto_comment.py @@ -10,8 +10,8 @@ class ParsedProtoCommentNode(ParsedProtoNode): class ProtoComment(ProtoNode): - def __init__(self, parent: Optional[ProtoNode], value: str): - super().__init__(parent) + def __init__(self, value: str, *args, **kwargs): + super().__init__(*args, **kwargs) self.value = value def __eq__(self, other) -> bool: @@ -28,7 +28,7 @@ def normalize(self) -> Optional["ProtoComment"]: @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoCommentNode"]: return None @@ -47,7 +47,7 @@ def __str__(self) -> str: @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoSingleLineCommentNode"]: if not proto_source.startswith("//"): return None @@ -57,7 +57,7 @@ def match( if newline_pos == -1: newline_pos = len(proto_source) return ParsedProtoSingleLineCommentNode( - ProtoSingleLineComment(parent, proto_source[:newline_pos]), + ProtoSingleLineComment(value=proto_source[:newline_pos], parent=parent), proto_source[newline_pos + 1 :], ) @@ -76,7 +76,7 @@ def __str__(self) -> str: @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoMultiLineCommentNode"]: if not proto_source.startswith("/*"): return None @@ -86,7 +86,9 @@ def match( if close_comment_pos == -1: return None return ParsedProtoMultiLineCommentNode( - ProtoMultiLineComment(parent, proto_source[:close_comment_pos]), + ProtoMultiLineComment( + value=proto_source[:close_comment_pos], parent=parent + ), proto_source[close_comment_pos + 2 :], ) diff --git a/src/proto_constant.py b/src/proto_constant.py index 10cb623..464d6ae 100644 --- a/src/proto_constant.py +++ b/src/proto_constant.py @@ -18,12 +18,8 @@ class ParsedProtoConstantNode(ParsedProtoNode): class ProtoConstant(ProtoNode): - def __init__( - self, - parent: Optional[ProtoNode], - value: ProtoConstantTypes, - ): - super().__init__(parent) + def __init__(self, value: ProtoConstantTypes, *args, **kwargs): + super().__init__(*args, **kwargs) self.value = value self.value.parent = self @@ -41,11 +37,11 @@ def normalize(self) -> "ProtoConstant": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoConstantNode"]: - match = ProtoBool.match(None, proto_source) + match = ProtoBool.match(proto_source=proto_source) if match is not None: - proto_constant = ProtoConstant(parent, match.node) + proto_constant = ProtoConstant(value=match.node, parent=parent) return ParsedProtoConstantNode( proto_constant, match.remaining_source.strip(), @@ -54,11 +50,11 @@ def match( sign = ProtoIntSign.POSITIVE if proto_source.startswith("+") or proto_source.startswith("-"): sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - proto_int_match = ProtoInt.match(None, proto_source[1:]) + proto_int_match = ProtoInt.match(proto_source=proto_source[1:]) else: - proto_int_match = ProtoInt.match(None, proto_source) + proto_int_match = ProtoInt.match(proto_source=proto_source) if proto_int_match is not None: - proto_constant = ProtoConstant(parent, proto_int_match.node) + proto_constant = ProtoConstant(value=proto_int_match.node, parent=parent) proto_int_match.node.sign = sign return ParsedProtoConstantNode( proto_constant, @@ -68,28 +64,32 @@ def match( float_sign = ProtoFloatSign.POSITIVE if proto_source.startswith("+") or proto_source.startswith("-"): float_sign = next(x for x in ProtoFloatSign if x.value == proto_source[0]) - float_match = ProtoFloat.match(None, proto_source[1:]) + float_match = ProtoFloat.match(proto_source=proto_source[1:]) else: - float_match = ProtoFloat.match(None, proto_source) + float_match = ProtoFloat.match(proto_source=proto_source) if float_match is not None: - proto_constant = ProtoConstant(parent, float_match.node) + proto_constant = ProtoConstant(value=float_match.node, parent=parent) float_match.node.sign = float_sign return ParsedProtoConstantNode( proto_constant, float_match.remaining_source.strip(), ) - identifier_match = ProtoFullIdentifier.match(None, proto_source) + identifier_match = ProtoFullIdentifier.match( + proto_source=proto_source, parent=None + ) if identifier_match is not None: return ParsedProtoConstantNode( - ProtoConstant(parent, identifier_match.node), + ProtoConstant(value=identifier_match.node, parent=parent), identifier_match.remaining_source.strip(), ) - string_literal_match = ProtoStringLiteral.match(None, proto_source) + string_literal_match = ProtoStringLiteral.match( + proto_source=proto_source, parent=None + ) if string_literal_match is not None: return ParsedProtoConstantNode( - ProtoConstant(parent, string_literal_match.node), + ProtoConstant(value=string_literal_match.node, parent=parent), string_literal_match.remaining_source.strip(), ) diff --git a/src/proto_enum.py b/src/proto_enum.py index c1f682c..b427221 100644 --- a/src/proto_enum.py +++ b/src/proto_enum.py @@ -23,14 +23,14 @@ def __str__(self) -> str: @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoEnumValueOptionNode"]: test_source = "option " + proto_source.strip() + ";" - match = ProtoOption.match(None, test_source) + match = ProtoOption.match(proto_source=test_source) if match is None: return None return ParsedProtoEnumValueOptionNode( - cls(parent, match.node.name, match.node.value), + cls(name=match.node.name, value=match.node.value, parent=parent), match.remaining_source.strip(), ) @@ -46,12 +46,13 @@ class ParsedProtoEnumValueNode(ParsedProtoNode): class ProtoEnumValue(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], identifier: ProtoIdentifier, value: ProtoInt, options: Optional[list[ProtoEnumValueOption]] = None, + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.identifier = identifier self.identifier.parent = self self.value = value @@ -82,17 +83,17 @@ def __hash__(self) -> int: def normalize(self) -> "ProtoEnumValue": return ProtoEnumValue( - self.parent, self.identifier, self.value, sorted(self.options, key=lambda o: str(o.name)), + parent=self.parent, ) @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoEnumValueNode"]: - match = ProtoIdentifier.match(None, proto_source) + match = ProtoIdentifier.match(proto_source=proto_source) if match is None: raise ValueError(f"Proto has invalid enum value name: {proto_source}") @@ -109,9 +110,9 @@ def match( sign = ProtoIntSign.POSITIVE if proto_source.startswith("-"): sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - int_match = ProtoInt.match(None, proto_source[1:]) + int_match = ProtoInt.match(proto_source=proto_source[1:]) else: - int_match = ProtoInt.match(None, proto_source) + int_match = ProtoInt.match(proto_source=proto_source) if int_match is None: raise ValueError( f"Proto has invalid enum value, expecting int: {proto_source}" @@ -131,7 +132,7 @@ def match( ) for option_part in proto_source[:end_bracket].strip().split(","): proto_enum_value_option_match = ProtoEnumValueOption.match( - None, option_part.strip() + proto_source=option_part.strip(), parent=None ) if proto_enum_value_option_match is None: raise ValueError( @@ -141,7 +142,12 @@ def match( proto_source = proto_source[end_bracket + 1 :].strip() return ParsedProtoEnumValueNode( - ProtoEnumValue(parent, enum_value_name, enum_value, options), + ProtoEnumValue( + identifier=enum_value_name, + value=enum_value, + options=options, + parent=parent, + ), proto_source.strip(), ) @@ -205,10 +211,8 @@ def diff_sets( class ProtoEnum(ProtoNode): - def __init__( - self, parent: Optional[ProtoNode], name: ProtoIdentifier, nodes: list[ProtoNode] - ): - super().__init__(parent) + def __init__(self, name: ProtoIdentifier, nodes: list[ProtoNode], *args, **kwargs): + super().__init__(*args, **kwargs) self.name = name self.name.parent = self self.nodes = nodes @@ -233,9 +237,9 @@ def normalize(self) -> "ProtoEnum": lambda n1: not isinstance(n1, ProtoComment), self.nodes ) return ProtoEnum( - self.parent, - self.name, - sorted(non_comment_nodes, key=lambda n: str(n.normalize())), + name=self.name, + nodes=sorted(non_comment_nodes, key=lambda n: str(n.normalize())), + parent=self.parent, ) @staticmethod @@ -249,7 +253,9 @@ def parse_partial_content(partial_enum_content: str) -> ParsedProtoNode: ] for node_type in supported_types: try: - match_result = node_type.match(None, partial_enum_content) + match_result = node_type.match( + proto_source=partial_enum_content, parent=None + ) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial enum content:\n{partial_enum_content}" @@ -262,13 +268,13 @@ def parse_partial_content(partial_enum_content: str) -> ParsedProtoNode: @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("enum "): return None proto_source = proto_source[5:] - match = ProtoIdentifier.match(None, proto_source) + match = ProtoIdentifier.match(proto_source=proto_source) if match is None: raise ValueError(f"Proto has invalid enum name: {proto_source}") @@ -297,7 +303,7 @@ def match( proto_source = match_result.remaining_source.strip() return ParsedProtoNode( - ProtoEnum(parent, enum_name, nodes=parsed_tree), proto_source + ProtoEnum(name=enum_name, nodes=parsed_tree, parent=parent), proto_source ) @property diff --git a/src/proto_extend.py b/src/proto_extend.py index 8585fdb..ece3e23 100644 --- a/src/proto_extend.py +++ b/src/proto_extend.py @@ -13,11 +13,12 @@ class ProtoExtend(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], name: ProtoEnumOrMessageIdentifier, nodes: list[ProtoNode], + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.name = name self.name.parent = self self.nodes = nodes @@ -38,9 +39,9 @@ def normalize(self) -> "ProtoExtend": lambda n: not isinstance(n, ProtoComment), self.nodes ) return ProtoExtend( - self.parent, name=self.name, nodes=sorted(non_comment_nodes, key=lambda f: str(f)), + parent=self.parent, ) @staticmethod @@ -52,7 +53,7 @@ def parse_partial_content(partial_content: str) -> ParsedProtoNode: ] for node_type in supported_types: try: - match_result = node_type.match(None, partial_content) + match_result = node_type.match(partial_content) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial extend content:\n{partial_content}" @@ -63,13 +64,13 @@ def parse_partial_content(partial_content: str) -> ParsedProtoNode: @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("extend "): return None proto_source = proto_source[7:] - match = ProtoEnumOrMessageIdentifier.match(None, proto_source) + match = ProtoEnumOrMessageIdentifier.match(proto_source) if match is None: raise ValueError(f"Proto extend has invalid message name: {proto_source}") @@ -98,7 +99,7 @@ def match( proto_source = match_result.remaining_source.strip() return ParsedProtoNode( - ProtoExtend(parent, name, nodes=parsed_tree), proto_source + ProtoExtend(name=name, nodes=parsed_tree, parent=parent), proto_source ) def serialize(self) -> str: diff --git a/src/proto_extensions.py b/src/proto_extensions.py index c8cf998..39ad012 100644 --- a/src/proto_extensions.py +++ b/src/proto_extensions.py @@ -9,10 +9,11 @@ class ProtoExtensions(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], ranges: list[ProtoRange], + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.ranges = ranges for range in self.ranges: range.parent = self @@ -29,13 +30,13 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoExtensions": # sort the ranges. return ProtoExtensions( - self.parent, - sorted(self.ranges, key=lambda r: int(r.min)), + ranges=sorted(self.ranges, key=lambda r: int(r.min)), + parent=self.parent, ) @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("extensions "): return None @@ -53,13 +54,15 @@ def match( ) if proto_source[0] == ",": proto_source = proto_source[1:].strip() - match = ProtoRange.match(None, proto_source) + match = ProtoRange.match(proto_source) if match is None: return None ranges.append(match.node) proto_source = match.remaining_source - return ParsedProtoNode(ProtoExtensions(parent, ranges), proto_source.strip()) + return ParsedProtoNode( + ProtoExtensions(ranges=ranges, parent=parent), proto_source.strip() + ) def serialize(self) -> str: serialize_parts = ["extensions", ", ".join(r.serialize() for r in self.ranges)] diff --git a/src/proto_float.py b/src/proto_float.py index d86b22d..f1abca1 100644 --- a/src/proto_float.py +++ b/src/proto_float.py @@ -22,8 +22,8 @@ class ProtoFloat(ProtoNode): DECIMAL = DIGITS | set(".") EXPONENTIAL = set("eE") - def __init__(self, parent: Optional[ProtoNode], value: float, sign: ProtoFloatSign): - super().__init__(parent) + def __init__(self, value: float, sign: ProtoFloatSign, *args, **kwargs): + super().__init__(*args, **kwargs) self.value = value self.sign = sign @@ -45,7 +45,7 @@ def normalize(self) -> "ProtoFloat": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoFloatNode"]: if proto_source.startswith("inf"): proto_source = proto_source[3:] @@ -54,7 +54,9 @@ def match( f"Proto has invalid float, invalid post-inf character: {proto_source}" ) return ParsedProtoFloatNode( - ProtoFloat(parent, float("inf"), ProtoFloatSign.POSITIVE), + ProtoFloat( + value=float("inf"), sign=ProtoFloatSign.POSITIVE, parent=parent + ), proto_source.strip(), ) @@ -65,7 +67,9 @@ def match( f"Proto has invalid float, invalid post-nan character: {proto_source}" ) return ParsedProtoFloatNode( - ProtoFloat(parent, float("nan"), ProtoFloatSign.POSITIVE), + ProtoFloat( + value=float("nan"), sign=ProtoFloatSign.POSITIVE, parent=parent + ), proto_source.strip(), ) @@ -118,7 +122,8 @@ def match( proto_source = proto_source[i + 1 :] return ParsedProtoFloatNode( - ProtoFloat(parent, base, ProtoFloatSign.POSITIVE), proto_source.strip() + ProtoFloat(value=base, sign=ProtoFloatSign.POSITIVE, parent=parent), + proto_source.strip(), ) def serialize(self) -> str: diff --git a/src/proto_identifier.py b/src/proto_identifier.py index 114c684..dbc93b5 100644 --- a/src/proto_identifier.py +++ b/src/proto_identifier.py @@ -23,8 +23,8 @@ class ProtoIdentifier(ProtoNode): STARTING = ALPHABETICAL | set("_") ALL = STARTING | set("0123456789_") - def __init__(self, parent: Optional[ProtoNode], identifier: str): - super().__init__(parent) + def __init__(self, identifier: str, *args, **kwargs): + super().__init__(*args, **kwargs) self.identifier = identifier def __eq__(self, other) -> bool: @@ -44,7 +44,7 @@ def normalize(self) -> "ProtoIdentifier": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoIdentifierNode"]: if proto_source[0] not in ProtoIdentifier.STARTING: return None @@ -52,9 +52,12 @@ def match( for i, c in enumerate(proto_source): if c not in ProtoIdentifier.ALL: return ParsedProtoIdentifierNode( - ProtoIdentifier(parent, proto_source[:i]), proto_source[i:] + ProtoIdentifier(identifier=proto_source[:i], parent=parent), + proto_source[i:], ) - return ParsedProtoIdentifierNode(ProtoIdentifier(parent, proto_source), "") + return ParsedProtoIdentifierNode( + ProtoIdentifier(identifier=proto_source, parent=parent), "" + ) def serialize(self) -> str: return self.identifier @@ -66,7 +69,7 @@ class ProtoFullIdentifier(ProtoIdentifier): @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoFullIdentifierNode"]: if proto_source[0] not in ProtoFullIdentifier.STARTING: return None @@ -82,7 +85,9 @@ def match( ) identifier_parts.append(proto_source[last_part_start:i]) return ParsedProtoFullIdentifierNode( - ProtoFullIdentifier(parent, ".".join(identifier_parts)), + ProtoFullIdentifier( + identifier=".".join(identifier_parts), parent=parent + ), proto_source[i:], ) elif c == ".": @@ -96,7 +101,8 @@ def match( ) identifier_parts.append(proto_source[last_part_start:]) return ParsedProtoFullIdentifierNode( - ProtoFullIdentifier(parent, ".".join(identifier_parts)), "" + ProtoFullIdentifier(identifier=".".join(identifier_parts), parent=parent), + "", ) @@ -106,17 +112,19 @@ class ProtoEnumOrMessageIdentifier(ProtoIdentifier): @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoEnumOrMessageIdentifierNode"]: if proto_source[0] == ".": matched_source = proto_source[1:] else: matched_source = proto_source - identifier_match = ProtoFullIdentifier.match(parent, matched_source) + identifier_match = ProtoFullIdentifier.match(matched_source, parent=parent) if identifier_match is not None: match = ParsedProtoEnumOrMessageIdentifierNode( - ProtoEnumOrMessageIdentifier(parent, identifier_match.node.identifier), + ProtoEnumOrMessageIdentifier( + identifier=identifier_match.node.identifier, parent=parent + ), identifier_match.remaining_source, ) diff --git a/src/proto_import.py b/src/proto_import.py index 4cda9a3..31a1fb6 100644 --- a/src/proto_import.py +++ b/src/proto_import.py @@ -7,12 +7,13 @@ class ProtoImport(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], path: ProtoStringLiteral, weak: bool = False, public: bool = False, + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.path = path self.path.parent = self self.weak = weak @@ -43,7 +44,7 @@ def normalize(self) -> "ProtoImport": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("import "): return None @@ -61,7 +62,7 @@ def match( public = True proto_source = proto_source[7:] - match = ProtoStringLiteral.match(None, proto_source) + match = ProtoStringLiteral.match(proto_source) if match is None: raise ValueError(f"Proto has invalid import syntax: {proto_source}") @@ -71,7 +72,7 @@ def match( ) return ParsedProtoNode( - ProtoImport(parent, match.node, weak=weak, public=public), + ProtoImport(path=match.node, weak=weak, public=public, parent=parent), match.remaining_source[1:].strip(), ) diff --git a/src/proto_int.py b/src/proto_int.py index 480817f..8bae791 100644 --- a/src/proto_int.py +++ b/src/proto_int.py @@ -20,8 +20,8 @@ class ProtoInt(ProtoNode): DECIMAL = OCTAL | set("89") HEX = DECIMAL | set("ABCDEFabcdef") - def __init__(self, parent: Optional[ProtoNode], value: int, sign: ProtoIntSign): - super().__init__(parent) + def __init__(self, value: int, sign: ProtoIntSign, *args, **kwargs): + super().__init__(*args, **kwargs) self.value = value self.sign = sign @@ -45,7 +45,7 @@ def normalize(self) -> "ProtoInt": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoIntNode"]: if proto_source[0] not in ProtoInt.DECIMAL: return None @@ -67,7 +67,7 @@ def match( except ValueError: raise ValueError(f"Proto has invalid hex: {proto_source}") return ParsedProtoIntNode( - ProtoInt(parent, value, ProtoIntSign.POSITIVE), + ProtoInt(value=value, sign=ProtoIntSign.POSITIVE, parent=parent), proto_source[i + 1 :].strip(), ) else: @@ -83,7 +83,7 @@ def match( except ValueError: raise ValueError(f"Proto has invalid octal: {proto_source}") return ParsedProtoIntNode( - ProtoInt(parent, value, ProtoIntSign.POSITIVE), + ProtoInt(value=value, sign=ProtoIntSign.POSITIVE, parent=parent), proto_source[i + 1 :].strip(), ) else: @@ -100,7 +100,7 @@ def match( return None return ParsedProtoIntNode( - ProtoInt(parent, value, ProtoIntSign.POSITIVE), + ProtoInt(value=value, sign=ProtoIntSign.POSITIVE, parent=parent), proto_source[i + 1 :].strip(), ) diff --git a/src/proto_map.py b/src/proto_map.py index 129b46b..20070f9 100644 --- a/src/proto_map.py +++ b/src/proto_map.py @@ -28,15 +28,16 @@ class ProtoMapKeyTypesEnum(Enum): class ProtoMap(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], key_type: ProtoMapKeyTypesEnum, value_type: ProtoMapValueTypesEnum, name: ProtoIdentifier, number: ProtoInt, enum_or_message_type_name: Optional[ProtoEnumOrMessageIdentifier] = None, options: Optional[list[ProtoMessageFieldOption]] = None, + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.key_type = key_type self.value_type = value_type self.name = name @@ -82,7 +83,7 @@ def normalize(self) -> "ProtoMap": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if proto_source.startswith("map "): proto_source = proto_source[4:].strip() @@ -120,7 +121,7 @@ def match( enum_or_message_type_name = None if value_type is None: # See if this is an enum or message type. - match = ProtoEnumOrMessageIdentifier.match(None, proto_source) + match = ProtoEnumOrMessageIdentifier.match(proto_source) if match is None: return None value_type = ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE @@ -132,7 +133,7 @@ def match( proto_source = proto_source[1:].strip() # Try to match the map field's name. - identifier_match = ProtoIdentifier.match(None, proto_source) + identifier_match = ProtoIdentifier.match(proto_source) if identifier_match is None: return None name = identifier_match.node @@ -143,7 +144,7 @@ def match( proto_source = proto_source[1:].strip() # Try to match the map field number. - int_match = ProtoInt.match(None, proto_source) + int_match = ProtoInt.match(proto_source) if int_match is None: return None number = int_match.node @@ -160,7 +161,7 @@ def match( ) for option_part in proto_source[:end_bracket].strip().split(","): message_field_option_match = ProtoMessageFieldOption.match( - None, option_part.strip() + option_part.strip() ) if message_field_option_match is None: raise ValueError( @@ -176,13 +177,13 @@ def match( return ParsedProtoNode( ProtoMap( - parent, - key_type, - value_type, - name, - number, - enum_or_message_type_name, - options, + key_type=key_type, + value_type=value_type, + name=name, + number=number, + enum_or_message_type_name=enum_or_message_type_name, + options=options, + parent=parent, ), proto_source[1:].strip(), ) diff --git a/src/proto_message.py b/src/proto_message.py index 01277a7..5cc85be 100644 --- a/src/proto_message.py +++ b/src/proto_message.py @@ -20,11 +20,12 @@ class ProtoMessage(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], name: ProtoIdentifier, nodes: Sequence[ProtoNode], + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.name = name self.name.parent = self self.nodes = nodes @@ -79,9 +80,9 @@ def normalize(self) -> "ProtoMessage": ) return ProtoMessage( - parent=self.parent, name=self.name, nodes=sorted_nodes_for_normalizing, + parent=self.parent, ) @staticmethod @@ -101,7 +102,7 @@ def parse_partial_content(partial_message_content: str) -> ParsedProtoNode: ] for node_type in supported_types: try: - match_result = node_type.match(None, partial_message_content) + match_result = node_type.match(partial_message_content) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial message content:\n{partial_message_content}" @@ -114,13 +115,13 @@ def parse_partial_content(partial_message_content: str) -> ParsedProtoNode: @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("message "): return None proto_source = proto_source[8:] - match = ProtoIdentifier.match(None, proto_source) + match = ProtoIdentifier.match(proto_source) if match is None: raise ValueError(f"Proto has invalid message name: {proto_source}") @@ -149,7 +150,7 @@ def match( proto_source = match_result.remaining_source.strip() return ParsedProtoNode( - ProtoMessage(parent, enum_name, nodes=parsed_tree), proto_source + ProtoMessage(name=enum_name, nodes=parsed_tree, parent=parent), proto_source ) @property diff --git a/src/proto_message_field.py b/src/proto_message_field.py index aa5c7c2..2c3c749 100644 --- a/src/proto_message_field.py +++ b/src/proto_message_field.py @@ -15,9 +15,9 @@ class ParsedProtoMessageFieldOptionNode(ParsedProtoEnumValueOptionNode): class ProtoMessageFieldOption(ProtoEnumValueOption): @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoMessageFieldOptionNode"]: - match = super().match(parent, proto_source) + match = super().match(proto_source=proto_source, parent=parent) if match is None: return None @@ -54,7 +54,6 @@ class ParsedProtoMessageFieldNode(ParsedProtoNode): class ProtoMessageField(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], type: ProtoMessageFieldTypesEnum, name: ProtoIdentifier, number: ProtoInt, @@ -62,8 +61,10 @@ def __init__( optional: bool = False, enum_or_message_type_name: Optional[ProtoEnumOrMessageIdentifier] = None, options: Optional[list[ProtoMessageFieldOption]] = None, + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.type = type self.name = name self.name.parent = self @@ -107,7 +108,6 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoMessageField": return ProtoMessageField( - parent=self.parent, type=self.type, name=self.name, number=self.number, @@ -115,11 +115,12 @@ def normalize(self) -> "ProtoMessageField": optional=self.optional, enum_or_message_type_name=self.enum_or_message_type_name, options=sorted(self.options, key=lambda o: str(o.name)), + parent=self.parent, ) @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoMessageFieldNode"]: # First, try to match the optional repeated. repeated = False @@ -150,7 +151,7 @@ def match( enum_or_message_type_name = None if matched_type is None: # See if this is an enum or message type. - match = ProtoEnumOrMessageIdentifier.match(None, proto_source) + match = ProtoEnumOrMessageIdentifier.match(proto_source) if match is None: return None matched_type = ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE @@ -158,7 +159,7 @@ def match( proto_source = match.remaining_source.strip() # Match the field name. - identifier_match = ProtoIdentifier.match(None, proto_source) + identifier_match = ProtoIdentifier.match(proto_source) if identifier_match is None: return None name = identifier_match.node @@ -169,7 +170,7 @@ def match( proto_source = proto_source[2:].strip() # Match the field number. - int_match = ProtoInt.match(None, proto_source) + int_match = ProtoInt.match(proto_source) if int_match is None: return None number = int_match.node @@ -185,7 +186,7 @@ def match( ) for option_part in proto_source[:end_bracket].strip().split(","): message_field_option_match = ProtoMessageFieldOption.match( - None, option_part.strip() + option_part.strip() ) if message_field_option_match is None: raise ValueError( @@ -201,14 +202,14 @@ def match( return ParsedProtoMessageFieldNode( ProtoMessageField( - parent, - matched_type, - name, - number, - repeated, - optional, - enum_or_message_type_name, - options, + type=matched_type, + name=name, + number=number, + repeated=repeated, + optional=optional, + enum_or_message_type_name=enum_or_message_type_name, + options=options, + parent=parent, ), proto_source[1:].strip(), ) diff --git a/src/proto_node.py b/src/proto_node.py index 8d10bb4..5647cb6 100644 --- a/src/proto_node.py +++ b/src/proto_node.py @@ -6,11 +6,13 @@ class ProtoNode(abc.ABC): @classmethod @abc.abstractmethod def match( - cls, parent: Optional["ProtoNode"], proto_source: str + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, ) -> Optional["ParsedProtoNode"]: raise NotImplementedError - def __init__(self, parent: Optional["ProtoNode"]): + def __init__(self, parent: Optional["ProtoNode"] = None): self.parent = parent @abc.abstractmethod diff --git a/src/proto_oneof.py b/src/proto_oneof.py index 5780710..5e225ab 100644 --- a/src/proto_oneof.py +++ b/src/proto_oneof.py @@ -32,11 +32,12 @@ class ParsedProtoOneOfNode(ParsedProtoNode): class ProtoOneOf(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], name: ProtoIdentifier, nodes: Sequence[ProtoOneOfNodeTypes], + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.name = name self.name.parent = self self.nodes = nodes @@ -77,9 +78,9 @@ def normalize(self) -> "ProtoOneOf": ) + sorted(fields, key=lambda f: int(f.number)) return ProtoOneOf( - parent=self.parent, name=self.name, nodes=sorted_nodes_for_normalizing, + parent=self.parent, ) @staticmethod @@ -92,7 +93,7 @@ def parse_partial_content(partial_oneof_content: str) -> ProtoParsedOneOfNodeTyp ] for node_type in supported_types: try: - match_result = node_type.match(None, partial_oneof_content) + match_result = node_type.match(partial_oneof_content) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial oneof content:\n{partial_oneof_content}" @@ -105,14 +106,14 @@ def parse_partial_content(partial_oneof_content: str) -> ProtoParsedOneOfNodeTyp @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoOneOfNode"]: if not proto_source.startswith("oneof "): return None proto_source = proto_source[6:].strip() - match = ProtoIdentifier.match(None, proto_source) + match = ProtoIdentifier.match(proto_source) if match is None: raise ValueError( f"Proto has invalid syntax, expecting identifier for oneof: {proto_source}" @@ -143,7 +144,7 @@ def match( proto_source = match_result.remaining_source.strip() return ParsedProtoOneOfNode( - ProtoOneOf(parent, oneof_name, nodes=parsed_tree), proto_source + ProtoOneOf(name=oneof_name, nodes=parsed_tree, parent=parent), proto_source ) @property diff --git a/src/proto_option.py b/src/proto_option.py index 4090378..2d07312 100644 --- a/src/proto_option.py +++ b/src/proto_option.py @@ -15,10 +15,8 @@ class ParsedProtoOptionNode(ParsedProtoNode): class ProtoOption(ProtoNode): - def __init__( - self, parent: Optional[ProtoNode], name: ProtoIdentifier, value: ProtoConstant - ): - super().__init__(parent) + def __init__(self, name: ProtoIdentifier, value: ProtoConstant, *args, **kwargs): + super().__init__(*args, **kwargs) self.name = name self.name.parent = self self.value = value @@ -41,7 +39,7 @@ def normalize(self) -> "ProtoOption": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoOptionNode"]: if not proto_source.startswith("option "): return None @@ -50,10 +48,10 @@ def match( name_parts = [] if proto_source.startswith("("): proto_source = proto_source[1:] - match = ProtoFullIdentifier.match(None, proto_source) + match = ProtoFullIdentifier.match(proto_source) if match is None or not match.remaining_source.startswith(")"): # This might be a regular identifier. - identifier_match = ProtoIdentifier.match(None, proto_source) + identifier_match = ProtoIdentifier.match(proto_source) if ( not identifier_match or not identifier_match.remaining_source.startswith(")") @@ -62,19 +60,21 @@ def match( f"Proto has invalid option when expecting ): {proto_source}" ) name_parts.append( - ProtoIdentifier(None, f"({identifier_match.node.identifier})") + ProtoIdentifier(identifier=f"({identifier_match.node.identifier})") ) proto_source = identifier_match.remaining_source[1:] else: name_parts.append( - ProtoFullIdentifier(None, f"({match.node.identifier})") + ProtoFullIdentifier(identifier=f"({match.node.identifier})") ) proto_source = match.remaining_source[1:] while True: - identifier_match = ProtoEnumOrMessageIdentifier.match(None, proto_source) + identifier_match = ProtoEnumOrMessageIdentifier.match( + proto_source=proto_source + ) if identifier_match is None: - identifier_match = ProtoIdentifier.match(None, proto_source) + identifier_match = ProtoIdentifier.match(proto_source=proto_source) if identifier_match is None: break name_parts.append(identifier_match.node) @@ -86,7 +86,7 @@ def match( f"Proto has invalid option when expecting =: {proto_source}" ) proto_source = proto_source[1:].strip() - constant_match = ProtoConstant.match(None, proto_source) + constant_match = ProtoConstant.match(proto_source) if constant_match is None: raise ValueError( f"Proto has invalid option when expecting constant: {proto_source}" @@ -101,15 +101,15 @@ def match( identifier: ProtoFullIdentifier | ProtoIdentifier if len(name_parts) > 1: identifier = ProtoFullIdentifier( - None, "".join(x.identifier for x in name_parts) + identifier="".join(x.identifier for x in name_parts) ) else: - identifier = ProtoIdentifier(None, name_parts[0].identifier) + identifier = ProtoIdentifier(identifier=name_parts[0].identifier) proto_option = ProtoOption( - parent, name=identifier, value=constant_match.node, + parent=parent, ) identifier.parent = proto_option constant_match.node.parent = proto_option diff --git a/src/proto_package.py b/src/proto_package.py index f460d30..64eb120 100644 --- a/src/proto_package.py +++ b/src/proto_package.py @@ -4,8 +4,8 @@ class ProtoPackage(ProtoNode): - def __init__(self, parent: Optional[ProtoNode], package: str): - super().__init__(parent) + def __init__(self, package: str, *args, **kwargs): + super().__init__(*args, **kwargs) self.package = package def __eq__(self, other) -> bool: @@ -22,7 +22,7 @@ def normalize(self) -> "ProtoPackage": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("package"): return None @@ -47,7 +47,9 @@ def match( if package.startswith(".") or package.endswith("."): raise ValueError(f"Proto has invalid package: {package}") - return ParsedProtoNode(ProtoPackage(parent, package), proto_source.strip()) + return ParsedProtoNode( + ProtoPackage(package=package, parent=parent), proto_source.strip() + ) def serialize(self) -> str: return f"package {self.package};" diff --git a/src/proto_range.py b/src/proto_range.py index b55b279..ce035f9 100644 --- a/src/proto_range.py +++ b/src/proto_range.py @@ -17,11 +17,12 @@ class ProtoRangeEnum(Enum): class ProtoRange(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], min: ProtoInt, max: Optional[ProtoInt | ProtoRangeEnum] = None, + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.min = min if ( @@ -47,14 +48,14 @@ def normalize(self) -> "ProtoRange": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoRangeNode"]: sign = ProtoIntSign.POSITIVE if proto_source.startswith("-") and proto_source != "-": sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - match = ProtoInt.match(None, proto_source[1:]) + match = ProtoInt.match(proto_source[1:]) else: - match = ProtoInt.match(None, proto_source) + match = ProtoInt.match(proto_source) if match is None: return None @@ -66,7 +67,7 @@ def match( if proto_source.startswith("to "): proto_source = proto_source[3:] if proto_source.startswith("max"): - proto_range = ProtoRange(parent, min, ProtoRangeEnum.MAX) + proto_range = ProtoRange(min=min, max=ProtoRangeEnum.MAX, parent=parent) min.parent = proto_range return ParsedProtoRangeNode( proto_range, @@ -76,9 +77,9 @@ def match( sign = ProtoIntSign.POSITIVE if proto_source.startswith("-"): sign = next(x for x in ProtoIntSign if x.value == proto_source[0]) - match = ProtoInt.match(None, proto_source[1:]) + match = ProtoInt.match(proto_source[1:]) else: - match = ProtoInt.match(None, proto_source) + match = ProtoInt.match(proto_source) if match is None: raise ValueError( f"Proto source has invalid range, expecting int for max: {proto_source}" @@ -87,7 +88,7 @@ def match( max = match.node proto_source = match.remaining_source - proto_range = ProtoRange(parent, min, max) + proto_range = ProtoRange(min=min, max=max, parent=parent) min.parent = proto_range if isinstance(max, ProtoNode): max.parent = proto_range diff --git a/src/proto_reserved.py b/src/proto_reserved.py index 06b146b..374123c 100644 --- a/src/proto_reserved.py +++ b/src/proto_reserved.py @@ -14,14 +14,15 @@ class ProtoReservedFieldQuoteEnum(Enum): class ProtoReserved(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], ranges: Optional[list[ProtoRange]] = None, fields: Optional[list[ProtoIdentifier]] = None, quote_type: Optional[ ProtoReservedFieldQuoteEnum ] = ProtoReservedFieldQuoteEnum.DOUBLE, + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) if (not ranges and not fields) or (ranges and fields): raise ValueError( "Exactly one of ranges or fields must be set in a ProtoReserved" @@ -72,7 +73,7 @@ def min(self) -> str | int: @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("reserved "): return None @@ -92,7 +93,7 @@ def match( ) if proto_source[0] == ",": proto_source = proto_source[1:].strip() - range_match = ProtoRange.match(None, proto_source) + range_match = ProtoRange.match(proto_source) if range_match is not None: ranges.append(range_match.node) proto_source = range_match.remaining_source @@ -109,7 +110,7 @@ def match( ) quote_type = quote_types[0] proto_source = proto_source[1:] - match = ProtoIdentifier.match(None, proto_source) + match = ProtoIdentifier.match(proto_source) if match is None: raise ValueError( f"Proto source has invalid reserved syntax, expecting field identifier: {proto_source}" @@ -124,7 +125,10 @@ def match( proto_source = proto_source[1:].strip() return ParsedProtoNode( - ProtoReserved(parent, ranges, fields, quote_type), proto_source.strip() + ProtoReserved( + ranges=ranges, fields=fields, quote_type=quote_type, parent=parent + ), + proto_source.strip(), ) def serialize(self) -> str: diff --git a/src/proto_service.py b/src/proto_service.py index 8ca62d4..d408849 100644 --- a/src/proto_service.py +++ b/src/proto_service.py @@ -13,15 +13,16 @@ class ProtoServiceRPC(ProtoNode): def __init__( self, - parent: Optional[ProtoNode], name: ProtoIdentifier, request_type: ProtoEnumOrMessageIdentifier, response_type: ProtoEnumOrMessageIdentifier, request_stream: bool = False, response_stream: bool = False, options: Optional[list[ProtoOption]] = None, + *args, + **kwargs, ): - super().__init__(parent) + super().__init__(*args, **kwargs) self.name = name self.name.parent = self self.request_type = request_type @@ -55,25 +56,25 @@ def __repr__(self) -> str: def normalize(self) -> "ProtoServiceRPC": return ProtoServiceRPC( - parent=self.parent, name=self.name, request_type=self.request_type, response_type=self.response_type, request_stream=self.request_stream, response_stream=self.response_stream, options=sorted(self.options, key=lambda o: str(o.normalize())), + parent=self.parent, ) @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("rpc "): return None proto_source = proto_source[4:].strip() # Match the RPC name. - name_match = ProtoIdentifier.match(None, proto_source) + name_match = ProtoIdentifier.match(proto_source) if name_match is None: return None name = name_match.node @@ -84,9 +85,7 @@ def match( proto_source = proto_source[1:].strip() # Try to parse the request type. - stream_or_request_name_match = ProtoEnumOrMessageIdentifier.match( - None, proto_source - ) + stream_or_request_name_match = ProtoEnumOrMessageIdentifier.match(proto_source) if stream_or_request_name_match is None: return None @@ -97,7 +96,7 @@ def match( elif stream_or_request_name_match.node.identifier == "stream": # Try matching the request name. potential_request_name_match = ProtoEnumOrMessageIdentifier.match( - None, stream_or_request_name_match.remaining_source.strip() + stream_or_request_name_match.remaining_source.strip() ) if potential_request_name_match is None: # No further name. @@ -124,9 +123,7 @@ def match( proto_source = proto_source[1:].strip() # Try to parse the response type. - stream_or_response_name_match = ProtoEnumOrMessageIdentifier.match( - None, proto_source - ) + stream_or_response_name_match = ProtoEnumOrMessageIdentifier.match(proto_source) if stream_or_response_name_match is None: return None @@ -137,7 +134,7 @@ def match( elif stream_or_response_name_match.node.identifier == "stream": # Try matching the response name. potential_response_name_match = ProtoEnumOrMessageIdentifier.match( - None, stream_or_response_name_match.remaining_source.strip() + stream_or_response_name_match.remaining_source.strip() ) if potential_response_name_match is None: # No further name. @@ -169,7 +166,7 @@ def match( proto_source = proto_source[1:].strip() break - option_match = ProtoOption.match(None, proto_source) + option_match = ProtoOption.match(proto_source) if option_match is None: return None options.append(option_match.node) @@ -181,13 +178,13 @@ def match( return ParsedProtoNode( ProtoServiceRPC( - parent, - name, - request_name, - response_name, - request_stream, - response_stream, - options, + name=name, + request_type=request_name, + response_type=response_name, + request_stream=request_stream, + response_stream=response_stream, + options=options, + parent=parent, ), proto_source.strip(), ) @@ -222,10 +219,8 @@ def serialize(self) -> str: class ProtoService(ProtoNode): - def __init__( - self, parent: Optional[ProtoNode], name: ProtoIdentifier, nodes: list[ProtoNode] - ): - super().__init__(parent) + def __init__(self, name: ProtoIdentifier, nodes: list[ProtoNode], *args, **kwargs): + super().__init__(*args, **kwargs) self.name = name self.name.parent = self self.nodes = nodes @@ -246,9 +241,9 @@ def normalize(self) -> "ProtoService": lambda n: not isinstance(n, ProtoComment), self.nodes ) return ProtoService( - parent=self.parent, name=self.name, nodes=sorted(non_comment_nodes, key=lambda n: str(n.normalize())), + parent=self.parent, ) @staticmethod @@ -261,7 +256,7 @@ def parse_partial_content(partial_service_content: str) -> ParsedProtoNode: ] for node_type in supported_types: try: - match_result = node_type.match(None, partial_service_content) + match_result = node_type.match(partial_service_content) except (ValueError, IndexError, TypeError): raise ValueError( f"Could not parse partial service content:\n{partial_service_content}" @@ -274,13 +269,13 @@ def parse_partial_content(partial_service_content: str) -> ParsedProtoNode: @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoNode"]: if not proto_source.startswith("service "): return None proto_source = proto_source[8:] - match = ProtoIdentifier.match(None, proto_source) + match = ProtoIdentifier.match(proto_source) if match is None: raise ValueError(f"Proto has invalid service name: {proto_source}") @@ -309,7 +304,7 @@ def match( proto_source = match_result.remaining_source.strip() return ParsedProtoNode( - ProtoService(parent, enum_name, nodes=parsed_tree), proto_source + ProtoService(name=enum_name, nodes=parsed_tree, parent=parent), proto_source ) @property diff --git a/src/proto_string_literal.py b/src/proto_string_literal.py index 1d98b57..1941cf4 100644 --- a/src/proto_string_literal.py +++ b/src/proto_string_literal.py @@ -11,8 +11,8 @@ class ParsedProtoStringLiteralNode(ParsedProtoNode): class ProtoStringLiteral(ProtoNode): QUOTES = ['"', "'"] - def __init__(self, parent: Optional[ProtoNode], val: str, quote: str = QUOTES[0]): - super().__init__(parent) + def __init__(self, val: str, quote: str = QUOTES[0], *args, **kwargs): + super().__init__(*args, **kwargs) self.value = val self.quote = quote @@ -33,7 +33,7 @@ def normalize(self) -> "ProtoStringLiteral": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoStringLiteralNode"]: if not any(proto_source.startswith(c) for c in ProtoStringLiteral.QUOTES): return None @@ -46,7 +46,7 @@ def match( if c == starting_quote and not escaped: return ParsedProtoStringLiteralNode( ProtoStringLiteral( - parent, proto_source[1 : i + 1], quote=starting_quote + val=proto_source[1 : i + 1], quote=starting_quote, parent=parent ), proto_source[i + 2 :].strip(), ) diff --git a/src/proto_syntax.py b/src/proto_syntax.py index 13bc3c4..fe301bf 100644 --- a/src/proto_syntax.py +++ b/src/proto_syntax.py @@ -16,8 +16,8 @@ class ProtoSyntaxType(Enum): class ProtoSyntax(ProtoNode): - def __init__(self, parent: Optional[ProtoNode], syntax: ProtoStringLiteral): - super().__init__(parent) + def __init__(self, syntax: ProtoStringLiteral, *args, **kwargs): + super().__init__(*args, **kwargs) self.syntax = syntax def __eq__(self, other) -> bool: @@ -37,25 +37,25 @@ def normalize(self) -> "ProtoSyntax": @classmethod def match( - cls, parent: Optional[ProtoNode], proto_source: str + cls, proto_source: str, parent: Optional[ProtoNode] = None ) -> Optional["ParsedProtoSyntaxNode"]: if not proto_source.startswith("syntax = "): return None proto_source = proto_source[9:] - match = ProtoStringLiteral.match(None, proto_source) + match = ProtoStringLiteral.match(proto_source) if match is None: raise ValueError(f"Proto has invalid syntax syntax: {proto_source}") if not match.remaining_source.startswith(";"): raise ValueError(f"Proto has invalid syntax: {proto_source}") try: - syntax_type = ProtoSyntaxType[match.node.value.upper()] + ProtoSyntaxType[match.node.value.upper()] except KeyError: raise ValueError( f"Proto has unknown syntax type: {match.node.value}, must be one of: {[proto_type.name for proto_type in ProtoSyntaxType]}" ) return ParsedProtoSyntaxNode( - ProtoSyntax(parent, match.node), + ProtoSyntax(syntax=match.node, parent=parent), match.remaining_source.strip(), ) diff --git a/src/util/parser.py b/src/util/parser.py index 62a4723..75b9de9 100644 --- a/src/util/parser.py +++ b/src/util/parser.py @@ -38,7 +38,7 @@ def parse_partial_content(partial_proto_content: str) -> ParsedProtoNode: ] for node_type in node_types: try: - match_result = node_type.match(None, partial_proto_content) + match_result = node_type.match(partial_proto_content) except (ValueError, IndexError, TypeError): raise ParseError( f"Could not parse proto content:\n{partial_proto_content}" @@ -56,7 +56,7 @@ def parse_syntax_and_preceding_comments( while True: for node_type in [ProtoSingleLineComment, ProtoMultiLineComment]: try: - match_result = node_type.match(None, proto_content) + match_result = node_type.match(proto_content) except (ValueError, IndexError, TypeError): raise ParseError(f"Could not parse proto content:\n{proto_content}") if match_result is not None: @@ -68,7 +68,7 @@ def parse_syntax_and_preceding_comments( # Next, parse syntax. try: - syntax_match = ProtoSyntax.match(None, proto_content.strip()) + syntax_match = ProtoSyntax.match(proto_content.strip()) except (ValueError, IndexError, TypeError): raise ParseError(f"Proto doesn't have parseable syntax:\n{proto_content}") if syntax_match is None: diff --git a/test/proto_bool_test.py b/test/proto_bool_test.py index 7611d75..cc3a035 100644 --- a/test/proto_bool_test.py +++ b/test/proto_bool_test.py @@ -5,18 +5,18 @@ class BoolTest(unittest.TestCase): def test_true(self): - self.assertEqual(ProtoBool.match(None, "true").node.value, True) - self.assertIsNone(ProtoBool.match(None, "True")) - self.assertIsNone(ProtoBool.match(None, "truee")) - self.assertIsNone(ProtoBool.match(None, "true_true")) - self.assertIsNone(ProtoBool.match(None, "true.false")) + self.assertEqual(ProtoBool.match("true").node.value, True) + self.assertIsNone(ProtoBool.match("True")) + self.assertIsNone(ProtoBool.match("truee")) + self.assertIsNone(ProtoBool.match("true_true")) + self.assertIsNone(ProtoBool.match("true.false")) def test_false(self): - self.assertEqual(ProtoBool.match(None, "false").node.value, False) - self.assertIsNone(ProtoBool.match(None, "False")) - self.assertIsNone(ProtoBool.match(None, "falsee")) - self.assertIsNone(ProtoBool.match(None, "false_false")) - self.assertIsNone(ProtoBool.match(None, "false.true")) + self.assertEqual(ProtoBool.match("false").node.value, False) + self.assertIsNone(ProtoBool.match("False")) + self.assertIsNone(ProtoBool.match("falsee")) + self.assertIsNone(ProtoBool.match("false_false")) + self.assertIsNone(ProtoBool.match("false.true")) if __name__ == "__main__": diff --git a/test/proto_comment_test.py b/test/proto_comment_test.py index 5d3a705..95a37e9 100644 --- a/test/proto_comment_test.py +++ b/test/proto_comment_test.py @@ -5,46 +5,42 @@ class ProtoSingleLineCommentTest(unittest.TestCase): def test_matches_normal_comment(self): - node = ProtoSingleLineComment.match( - None, "// hello there, this is a comment" - ).node + node = ProtoSingleLineComment.match("// hello there, this is a comment").node self.assertEqual(node.value, " hello there, this is a comment") self.assertEqual(node.serialize(), "// hello there, this is a comment") self.assertIsNone(node.normalize()) def test_matches_without_space(self): - node = ProtoSingleLineComment.match(None, "//comment without space").node + node = ProtoSingleLineComment.match("//comment without space").node self.assertEqual(node.value, "comment without space") self.assertEqual(node.serialize(), "//comment without space") self.assertIsNone(node.normalize()) def test_does_not_match_multiple_lines(self): - node = ProtoSingleLineComment.match(None, "//line one\nbut not this").node + node = ProtoSingleLineComment.match("//line one\nbut not this").node self.assertEqual(node.value, "line one") self.assertEqual(node.serialize(), "//line one") self.assertIsNone(node.normalize()) def test_does_not_match_single_slash(self): self.assertIsNone( - ProtoSingleLineComment.match(None, "/hello there, this is a comment") + ProtoSingleLineComment.match("/hello there, this is a comment") ) self.assertIsNone( - ProtoSingleLineComment.match(None, "/ /hello there, this is a comment") + ProtoSingleLineComment.match("/ /hello there, this is a comment") ) class ProtoMultiLineCommentTest(unittest.TestCase): def test_matches_single_line_comment(self): - node = ProtoMultiLineComment.match( - None, "/* hello there, this is a comment */" - ).node + node = ProtoMultiLineComment.match("/* hello there, this is a comment */").node self.assertEqual(node.value, " hello there, this is a comment ") self.assertEqual(node.serialize(), "/* hello there, this is a comment */") self.assertIsNone(node.normalize()) def test_matches_multi_line_comment(self): node = ProtoMultiLineComment.match( - None, "/* hello there,\nthis is a \nmulti-line comment */" + "/* hello there,\nthis is a \nmulti-line comment */" ).node self.assertEqual(node.value, " hello there,\nthis is a \nmulti-line comment ") self.assertEqual( @@ -55,25 +51,25 @@ def test_matches_multi_line_comment(self): def test_does_not_match_unclosed_comment(self): self.assertIsNone( ProtoMultiLineComment.match( - None, "/* hello there, this\n /is an unclosed\n*multiple-line comment/" + "/* hello there, this\n /is an unclosed\n*multiple-line comment/" ) ) def test_matches_without_space(self): - node = ProtoMultiLineComment.match(None, "/*comment without space*/").node + node = ProtoMultiLineComment.match("/*comment without space*/").node self.assertEqual(node.value, "comment without space") self.assertEqual(node.serialize(), "/*comment without space*/") self.assertIsNone(node.normalize()) def test_does_not_match_partial_opening(self): self.assertIsNone( - ProtoMultiLineComment.match(None, "/hello there, this is a comment*/") + ProtoMultiLineComment.match("/hello there, this is a comment*/") ) self.assertIsNone( - ProtoMultiLineComment.match(None, "*/hello there, this is a comment*/") + ProtoMultiLineComment.match("*/hello there, this is a comment*/") ) self.assertIsNone( - ProtoMultiLineComment.match(None, "*hello there, this is a comment*/") + ProtoMultiLineComment.match("*hello there, this is a comment*/") ) diff --git a/test/proto_constant_test.py b/test/proto_constant_test.py index 3367770..fc3fd49 100644 --- a/test/proto_constant_test.py +++ b/test/proto_constant_test.py @@ -12,174 +12,160 @@ class ConstantTest(unittest.TestCase): # constant = fullIdent | ( [ "-" | "+" ] intLit ) | ( [ "-" | "+" ] floatLit ) | strLit | boolLit def test_ident(self): + self.assertEqual(ProtoConstant.match("a").node.value, ProtoIdentifier("a")) + self.assertEqual(ProtoConstant.match("a0").node.value, ProtoIdentifier("a0")) + self.assertEqual(ProtoConstant.match("a_").node.value, ProtoIdentifier("a_")) + self.assertEqual(ProtoConstant.match("aa").node.value, ProtoIdentifier("aa")) + self.assertEqual(ProtoConstant.match("ab").node.value, ProtoIdentifier("ab")) self.assertEqual( - ProtoConstant.match(None, "a").node.value, ProtoIdentifier(None, "a") + ProtoConstant.match("a0b_f_aj").node.value, + ProtoIdentifier("a0b_f_aj"), ) self.assertEqual( - ProtoConstant.match(None, "a0").node.value, ProtoIdentifier(None, "a0") + ProtoConstant.match("a.bar").node.value, + ProtoIdentifier("a.bar"), ) self.assertEqual( - ProtoConstant.match(None, "a_").node.value, ProtoIdentifier(None, "a_") - ) - self.assertEqual( - ProtoConstant.match(None, "aa").node.value, ProtoIdentifier(None, "aa") - ) - self.assertEqual( - ProtoConstant.match(None, "ab").node.value, ProtoIdentifier(None, "ab") - ) - self.assertEqual( - ProtoConstant.match(None, "a0b_f_aj").node.value, - ProtoIdentifier(None, "a0b_f_aj"), - ) - self.assertEqual( - ProtoConstant.match(None, "a.bar").node.value, - ProtoIdentifier(None, "a.bar"), - ) - self.assertEqual( - ProtoConstant.match(None, "a.bar.baz").node.value, - ProtoIdentifier(None, "a.bar.baz"), + ProtoConstant.match("a.bar.baz").node.value, + ProtoIdentifier("a.bar.baz"), ) def test_str(self): self.assertEqual( - ProtoConstant.match(None, "'a'").node.value, - ProtoStringLiteral(None, "a", quote="'"), + ProtoConstant.match("'a'").node.value, + ProtoStringLiteral("a", quote="'"), ) self.assertEqual( - ProtoConstant.match(None, "'.a'").node.value, - ProtoStringLiteral(None, ".a", quote="'"), + ProtoConstant.match("'.a'").node.value, + ProtoStringLiteral(".a", quote="'"), ) self.assertEqual( - ProtoConstant.match(None, '"a"').node.value, - ProtoStringLiteral(None, "a", quote='"'), + ProtoConstant.match('"a"').node.value, + ProtoStringLiteral("a", quote='"'), ) def test_bool(self): - self.assertEqual( - ProtoConstant.match(None, "true").node.value, ProtoBool(None, True) - ) - self.assertEqual( - ProtoConstant.match(None, "false").node.value, ProtoBool(None, False) - ) + self.assertEqual(ProtoConstant.match("true").node.value, ProtoBool(True)) + self.assertEqual(ProtoConstant.match("false").node.value, ProtoBool(False)) def test_int(self): self.assertEqual( - ProtoConstant.match(None, "1").node.value, - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoConstant.match("1").node.value, + ProtoInt(1, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "158912938471293847").node.value, - ProtoInt(None, 158912938471293847, ProtoIntSign.POSITIVE), + ProtoConstant.match("158912938471293847").node.value, + ProtoInt(158912938471293847, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "+1").node.value, - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoConstant.match("+1").node.value, + ProtoInt(1, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "+158912938471293847").node.value, - ProtoInt(None, 158912938471293847, ProtoIntSign.POSITIVE), + ProtoConstant.match("+158912938471293847").node.value, + ProtoInt(158912938471293847, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "-1").node.value, - ProtoInt(None, 1, ProtoIntSign.NEGATIVE), + ProtoConstant.match("-1").node.value, + ProtoInt(1, ProtoIntSign.NEGATIVE), ) self.assertEqual( - ProtoConstant.match(None, "-248713857").node.value, - ProtoInt(None, 248713857, ProtoIntSign.NEGATIVE), + ProtoConstant.match("-248713857").node.value, + ProtoInt(248713857, ProtoIntSign.NEGATIVE), ) # Octal self.assertEqual( - ProtoConstant.match(None, "072342").node.value, - ProtoInt(None, 0o72342, ProtoIntSign.POSITIVE), + ProtoConstant.match("072342").node.value, + ProtoInt(0o72342, ProtoIntSign.POSITIVE), ) with self.assertRaises(ValueError): - ProtoConstant.match(None, "072942") + ProtoConstant.match("072942") # Hex self.assertEqual( - ProtoConstant.match(None, "0x72342").node.value, - ProtoInt(None, 0x72342, ProtoIntSign.POSITIVE), + ProtoConstant.match("0x72342").node.value, + ProtoInt(0x72342, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "0x7A3d2").node.value, - ProtoInt(None, 0x7A3D2, ProtoIntSign.POSITIVE), + ProtoConstant.match("0x7A3d2").node.value, + ProtoInt(0x7A3D2, ProtoIntSign.POSITIVE), ) with self.assertRaises(ValueError): - ProtoConstant.match(None, "0x72G42") + ProtoConstant.match("0x72G42") def test_float(self): self.assertEqual( - ProtoConstant.match(None, "2834.235928").node.value, - ProtoFloat(None, 2834.235928, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834.235928").node.value, + ProtoFloat(2834.235928, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834.e2").node.value, - ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834.e2").node.value, + ProtoFloat(283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834e2").node.value, - ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834e2").node.value, + ProtoFloat(283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834.e0").node.value, - ProtoFloat(None, 2834, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834.e0").node.value, + ProtoFloat(2834, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834e0").node.value, - ProtoFloat(None, 2834, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834e0").node.value, + ProtoFloat(2834, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834.E3").node.value, - ProtoFloat(None, 2834000, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834.E3").node.value, + ProtoFloat(2834000, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834E3").node.value, - ProtoFloat(None, 2834000, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834E3").node.value, + ProtoFloat(2834000, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834.e+2").node.value, - ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834.e+2").node.value, + ProtoFloat(283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834e+2").node.value, - ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834e+2").node.value, + ProtoFloat(283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834.e-2").node.value, - ProtoFloat(None, 28.34, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834.e-2").node.value, + ProtoFloat(28.34, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "2834e-2").node.value, - ProtoFloat(None, 28.34, ProtoFloatSign.POSITIVE), + ProtoConstant.match("2834e-2").node.value, + ProtoFloat(28.34, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, ".0").node.value, - ProtoFloat(None, 0.0, ProtoFloatSign.POSITIVE), + ProtoConstant.match(".0").node.value, + ProtoFloat(0.0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, ".0e-1").node.value, - ProtoFloat(None, 0.00, ProtoFloatSign.POSITIVE), + ProtoConstant.match(".0e-1").node.value, + ProtoFloat(0.00, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, ".0E1").node.value, - ProtoFloat(None, 0, ProtoFloatSign.POSITIVE), + ProtoConstant.match(".0E1").node.value, + ProtoFloat(0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, ".0E2").node.value, - ProtoFloat(None, 0, ProtoFloatSign.POSITIVE), + ProtoConstant.match(".0E2").node.value, + ProtoFloat(0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, ".3265").node.value, - ProtoFloat(None, 0.3265, ProtoFloatSign.POSITIVE), + ProtoConstant.match(".3265").node.value, + ProtoFloat(0.3265, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, ".3265e1").node.value, - ProtoFloat(None, 3.265, ProtoFloatSign.POSITIVE), + ProtoConstant.match(".3265e1").node.value, + ProtoFloat(3.265, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoConstant.match(None, "inf").node.value, - ProtoFloat(None, float("inf"), ProtoFloatSign.POSITIVE), + ProtoConstant.match("inf").node.value, + ProtoFloat(float("inf"), ProtoFloatSign.POSITIVE), ) diff --git a/test/proto_enum_test.py b/test/proto_enum_test.py index 095bad5..237aabc 100644 --- a/test/proto_enum_test.py +++ b/test/proto_enum_test.py @@ -27,7 +27,6 @@ class EnumTest(unittest.TestCase): def test_enum_all_features(self): parsed_enum_multiple_values = ProtoEnum.match( - None, dedent( """ enum FooEnum { @@ -51,75 +50,61 @@ def test_enum_all_features(self): parsed_enum_multiple_values.node.nodes, [ ProtoReserved( - None, [ - ProtoRange(None, ProtoInt(None, 1, ProtoIntSign.POSITIVE)), - ProtoRange(None, ProtoInt(None, 2, ProtoIntSign.POSITIVE)), + ProtoRange(ProtoInt(1, ProtoIntSign.POSITIVE)), + ProtoRange(ProtoInt(2, ProtoIntSign.POSITIVE)), ProtoRange( - None, - ProtoInt(None, 5, ProtoIntSign.POSITIVE), + ProtoInt(5, ProtoIntSign.POSITIVE), ProtoRangeEnum.MAX, ), ], ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_NEGATIVE"), - ProtoInt(None, 1, ProtoIntSign.NEGATIVE), + ProtoIdentifier("FE_NEGATIVE"), + ProtoInt(1, ProtoIntSign.NEGATIVE), [ ProtoEnumValueOption( - None, - ProtoIdentifier(None, "foo"), - ProtoConstant(None, ProtoBool(None, False)), + ProtoIdentifier("foo"), + ProtoConstant(ProtoBool(False)), ) ], ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNDEFINED"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNDEFINED"), + ProtoInt(0, ProtoIntSign.POSITIVE), ), - ProtoSingleLineComment(None, " single-line comment"), + ProtoSingleLineComment(" single-line comment"), ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foobar")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foobar")), ), ProtoMultiLineComment( - None, "\n multiple\n line\n comment\n ", ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_VALONE"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_VALONE"), + ProtoInt(1, ProtoIntSign.POSITIVE), [ ProtoEnumValueOption( - None, - ProtoIdentifier(None, "(bar.baz).bat"), - ProtoConstant(None, ProtoStringLiteral(None, "bat")), + ProtoIdentifier("(bar.baz).bat"), + ProtoConstant(ProtoStringLiteral("bat")), ), ProtoEnumValueOption( - None, - ProtoIdentifier(None, "baz.bat"), - ProtoConstant( - None, ProtoInt(None, 100, ProtoIntSign.NEGATIVE) - ), + ProtoIdentifier("baz.bat"), + ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), ), ], ), ProtoReserved( - None, [], [ - ProtoIdentifier(None, "FE_RESERVED"), - ProtoIdentifier(None, "FE_OLD"), + ProtoIdentifier("FE_RESERVED"), + ProtoIdentifier("FE_OLD"), ], ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_VALTWO"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_VALTWO"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ], ) @@ -148,12 +133,11 @@ def test_enum_all_features(self): ) def test_empty_enum(self): - parsed_empty_enum = ProtoEnum.match(None, """enum FooEnum {}""") + parsed_empty_enum = ProtoEnum.match("""enum FooEnum {}""") self.assertIsNotNone(parsed_empty_enum) - self.assertEqual(parsed_empty_enum.node.name, ProtoIdentifier(None, "FooEnum")) + self.assertEqual(parsed_empty_enum.node.name, ProtoIdentifier("FooEnum")) parsed_spaced_enum = ProtoEnum.match( - None, dedent( """ enum FooEnum { @@ -163,11 +147,10 @@ def test_empty_enum(self): ), ) self.assertIsNotNone(parsed_spaced_enum) - self.assertEqual(parsed_spaced_enum.node.name, ProtoIdentifier(None, "FooEnum")) + self.assertEqual(parsed_spaced_enum.node.name, ProtoIdentifier("FooEnum")) def test_enum_empty_statements(self): empty_statement_enum = ProtoEnum.match( - None, dedent( """ enum FooEnum { @@ -178,13 +161,10 @@ def test_enum_empty_statements(self): ), ) self.assertIsNotNone(empty_statement_enum) - self.assertEqual( - empty_statement_enum.node.name, ProtoIdentifier(None, "FooEnum") - ) + self.assertEqual(empty_statement_enum.node.name, ProtoIdentifier("FooEnum")) def test_enum_optionals(self): parsed_enum_with_optionals = ProtoEnum.match( - None, dedent( """ enum FooEnum { @@ -198,24 +178,21 @@ def test_enum_optionals(self): parsed_enum_with_optionals.node.options, [ ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foobar")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foobar")), ), ProtoOption( - None, - ProtoIdentifier(None, "(foo.bar).baz"), - ProtoConstant(None, ProtoBool(None, False)), + ProtoIdentifier("(foo.bar).baz"), + ProtoConstant(ProtoBool(False)), ), ], ) self.assertEqual( - parsed_enum_with_optionals.node.name, ProtoIdentifier(None, "FooEnum") + parsed_enum_with_optionals.node.name, ProtoIdentifier("FooEnum") ) def test_enum_single_value(self): parsed_enum_single_value = ProtoEnum.match( - None, dedent( """ enum FooEnum { @@ -228,16 +205,14 @@ def test_enum_single_value(self): parsed_enum_single_value.node.nodes, [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNDEFINED"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNDEFINED"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ) def test_enum_multiple_values(self): parsed_enum_multiple_values = ProtoEnum.match( - None, dedent( """ enum FooEnum { @@ -253,31 +228,26 @@ def test_enum_multiple_values(self): parsed_enum_multiple_values.node.nodes, [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_NEGATIVE"), - ProtoInt(None, 1, ProtoIntSign.NEGATIVE), + ProtoIdentifier("FE_NEGATIVE"), + ProtoInt(1, ProtoIntSign.NEGATIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNDEFINED"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNDEFINED"), + ProtoInt(0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_VALONE"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_VALONE"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_VALTWO"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_VALTWO"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ], ) def test_enum_comments(self): parsed_enum_multiple_values = ProtoEnum.match( - None, dedent( """ enum FooEnum { @@ -295,36 +265,30 @@ def test_enum_comments(self): parsed_enum_multiple_values.node.nodes, [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_NEGATIVE"), - ProtoInt(None, 1, ProtoIntSign.NEGATIVE), + ProtoIdentifier("FE_NEGATIVE"), + ProtoInt(1, ProtoIntSign.NEGATIVE), ), - ProtoSingleLineComment(None, " test single-line comment"), + ProtoSingleLineComment(" test single-line comment"), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNDEFINED"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNDEFINED"), + ProtoInt(0, ProtoIntSign.POSITIVE), ), ProtoMultiLineComment( - None, " test multiple\n FE_UNUSED = 200;\n line comment ", ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_VALONE"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_VALONE"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_VALTWO"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_VALTWO"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ], ) def test_enum_normalize_away_comments(self): parsed_enum_multiple_values = ProtoEnum.match( - None, dedent( """ enum FooEnum { @@ -342,74 +306,62 @@ def test_enum_normalize_away_comments(self): parsed_enum_multiple_values.nodes, [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_NEGATIVE"), - ProtoInt(None, 1, ProtoIntSign.NEGATIVE), + ProtoIdentifier("FE_NEGATIVE"), + ProtoInt(1, ProtoIntSign.NEGATIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNDEFINED"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNDEFINED"), + ProtoInt(0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_VALONE"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_VALONE"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_VALTWO"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_VALTWO"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ], ) def test_diff_same_enum_returns_empty(self): pe1 = ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [], ) pe2 = ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [], ) self.assertEqual(ProtoEnum.diff(pe1, pe2), []) def test_diff_different_enum_name_returns_empty(self): pe1 = ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [], ) pe2 = ProtoEnum( - None, - ProtoIdentifier(None, "OtherEnum"), + ProtoIdentifier("OtherEnum"), [], ) self.assertEqual(ProtoEnum.diff(pe1, pe2), []) def test_diff_different_enum_value_name_returns_enum_diff(self): pe1 = ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ) pe2 = ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_KNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_KNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ) @@ -418,7 +370,7 @@ def test_diff_different_enum_value_name_returns_enum_diff(self): ProtoEnumValueNameChanged( pe1, pe1.nodes[0], - ProtoIdentifier(None, "ME_KNOWN"), + ProtoIdentifier("ME_KNOWN"), ) ], ProtoEnum.diff(pe1, pe2), @@ -426,24 +378,20 @@ def test_diff_different_enum_value_name_returns_enum_diff(self): def test_diff_different_enum_value_value_returns_enum_diff(self): pe1 = ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ) pe2 = ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_UNKNOWN"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_UNKNOWN"), + ProtoInt(1, ProtoIntSign.POSITIVE), ) ], ) @@ -469,13 +417,11 @@ def test_diff_different_enum_value_value_returns_enum_diff(self): def test_diff_enum_added(self): pe1 = None pe2 = ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ) @@ -484,13 +430,11 @@ def test_diff_enum_added(self): [ ProtoEnumAdded( ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ) @@ -500,13 +444,11 @@ def test_diff_enum_added(self): def test_diff_enum_removed(self): pe1 = ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ) @@ -516,13 +458,11 @@ def test_diff_enum_removed(self): [ ProtoEnumRemoved( ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ) @@ -538,35 +478,29 @@ def test_diff_sets_empty_returns_empty(self): def test_diff_sets_no_change(self): set1 = [ ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier("FooEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier("TagEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -577,35 +511,29 @@ def test_diff_sets_all_removed(self): set1 = [] set2 = [ ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier("FooEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier("TagEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -615,13 +543,11 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier("FooEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -631,13 +557,11 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -647,13 +571,11 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier("TagEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -665,35 +587,29 @@ def test_diff_sets_all_removed(self): def test_diff_sets_all_added(self): set1 = [ ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier("FooEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier("TagEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -704,13 +620,11 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier("FooEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -720,13 +634,11 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -736,13 +648,11 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier("TagEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -754,70 +664,58 @@ def test_diff_sets_all_added(self): def test_diff_sets_mutually_exclusive(self): set1 = [ ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier("FooEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier("TagEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ] set2 = [ ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum2"), + ProtoIdentifier("FooEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum2"), + ProtoIdentifier("BarEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum2"), + ProtoIdentifier("TagEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -828,13 +726,11 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier("FooEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -844,13 +740,11 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -861,13 +755,11 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier("TagEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -878,13 +770,11 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum2"), + ProtoIdentifier("FooEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -895,13 +785,11 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum2"), + ProtoIdentifier("BarEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -912,13 +800,11 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum2"), + ProtoIdentifier("TagEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -931,70 +817,58 @@ def test_diff_sets_mutually_exclusive(self): def test_diff_sets_overlap(self): set1 = [ ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier("FooEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier("TagEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ] set2 = [ ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum2"), + ProtoIdentifier("FooEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum2"), + ProtoIdentifier("TagEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -1005,13 +879,11 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum"), + ProtoIdentifier("FooEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -1022,13 +894,11 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumRemoved( ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum"), + ProtoIdentifier("TagEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -1038,13 +908,11 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - None, - ProtoIdentifier(None, "FooEnum2"), + ProtoIdentifier("FooEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "FE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("FE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -1054,13 +922,11 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumAdded( ProtoEnum( - None, - ProtoIdentifier(None, "TagEnum2"), + ProtoIdentifier("TagEnum2"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "TE_UNKNOWN2"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("TE_UNKNOWN2"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), @@ -1070,22 +936,19 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumValueNameChanged( ProtoEnum( - None, - ProtoIdentifier(None, "BarEnum"), + ProtoIdentifier("BarEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ) ], ), ProtoEnumValue( - None, - ProtoIdentifier(None, "BE_UNKNOWN"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("BE_UNKNOWN"), + ProtoInt(0, ProtoIntSign.POSITIVE), ), - ProtoIdentifier(None, "BE_UNKNOWN2"), + ProtoIdentifier("BE_UNKNOWN2"), ), diff, ) diff --git a/test/proto_extend_test.py b/test/proto_extend_test.py index 0bec941..176281a 100644 --- a/test/proto_extend_test.py +++ b/test/proto_extend_test.py @@ -11,16 +11,15 @@ class ExtendTest(unittest.TestCase): maxDiff = None def test_empty_extend(self): - parsed_empty_extend = ProtoExtend.match(None, """extend FooMessage {}""") + parsed_empty_extend = ProtoExtend.match("""extend FooMessage {}""") self.assertIsNotNone(parsed_empty_extend) self.assertEqual( parsed_empty_extend.node.name, - ProtoEnumOrMessageIdentifier(None, "FooMessage"), + ProtoEnumOrMessageIdentifier("FooMessage"), ) self.assertEqual(parsed_empty_extend.node.serialize(), "extend FooMessage {\n}") parsed_spaced_extend = ProtoExtend.match( - None, dedent( """ extend FooMessage { @@ -32,14 +31,13 @@ def test_empty_extend(self): self.assertIsNotNone(parsed_spaced_extend) self.assertEqual( parsed_spaced_extend.node.name, - ProtoEnumOrMessageIdentifier(None, "FooMessage"), + ProtoEnumOrMessageIdentifier("FooMessage"), ) self.assertEqual( parsed_spaced_extend.node.serialize(), "extend FooMessage {\n}" ) parsed_scoped_extend = ProtoExtend.match( - None, dedent( """ extend google.protobuf.FooMessage { @@ -51,7 +49,7 @@ def test_empty_extend(self): self.assertIsNotNone(parsed_scoped_extend) self.assertEqual( parsed_scoped_extend.node.name, - ProtoEnumOrMessageIdentifier(None, "google.protobuf.FooMessage"), + ProtoEnumOrMessageIdentifier("google.protobuf.FooMessage"), ) self.assertEqual( parsed_scoped_extend.node.serialize(), @@ -60,7 +58,6 @@ def test_empty_extend(self): def test_extend_empty_statements(self): empty_statement_message = ProtoExtend.match( - None, dedent( """ extend FooMessage { @@ -73,7 +70,7 @@ def test_extend_empty_statements(self): self.assertIsNotNone(empty_statement_message) self.assertEqual( empty_statement_message.node.name, - ProtoEnumOrMessageIdentifier(None, "FooMessage"), + ProtoEnumOrMessageIdentifier("FooMessage"), ) self.assertEqual( empty_statement_message.node.serialize(), "extend FooMessage {\n}" @@ -81,7 +78,6 @@ def test_extend_empty_statements(self): def test_extend_simple_field(self): parsed_extend_with_single_field = ProtoExtend.match( - None, dedent( """ extend FooMessage { @@ -93,14 +89,12 @@ def test_extend_simple_field(self): self.assertEqual( parsed_extend_with_single_field.node, ProtoExtend( - None, - ProtoEnumOrMessageIdentifier(None, "FooMessage"), + ProtoEnumOrMessageIdentifier("FooMessage"), [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "single_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("single_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), ) ], ), diff --git a/test/proto_extensions_test.py b/test/proto_extensions_test.py index 86f64c4..50f0723 100644 --- a/test/proto_extensions_test.py +++ b/test/proto_extensions_test.py @@ -6,29 +6,29 @@ class ExtensionsTest(unittest.TestCase): def test_extension_single_int(self): self.assertEqual( - ProtoExtensions.match(None, "extensions 21;").node.serialize(), + ProtoExtensions.match("extensions 21;").node.serialize(), "extensions 21;", ) self.assertEqual( - ProtoExtensions.match(None, "extensions -1;").node.serialize(), + ProtoExtensions.match("extensions -1;").node.serialize(), "extensions -1;", ) def test_extension_multiple_ints(self): self.assertEqual( - ProtoExtensions.match(None, "extensions 1, 5, 2, 42;").node.serialize(), + ProtoExtensions.match("extensions 1, 5, 2, 42;").node.serialize(), "extensions 1, 5, 2, 42;", ) def test_extension_with_max(self): self.assertEqual( - ProtoExtensions.match(None, "extensions 8 to max;").node.serialize(), + ProtoExtensions.match("extensions 8 to max;").node.serialize(), "extensions 8 to max;", ) def test_extension_cannot_have_strings(self): - self.assertIsNone(ProtoExtensions.match(None, "extensions 1, 'foo';")) - self.assertIsNone(ProtoExtensions.match(None, "extensions 'bar';")) + self.assertIsNone(ProtoExtensions.match("extensions 1, 'foo';")) + self.assertIsNone(ProtoExtensions.match("extensions 'bar';")) if __name__ == "__main__": diff --git a/test/proto_float_test.py b/test/proto_float_test.py index 28eb34e..ecdbe22 100644 --- a/test/proto_float_test.py +++ b/test/proto_float_test.py @@ -6,88 +6,88 @@ class FloatTest(unittest.TestCase): def test_float(self): self.assertEqual( - ProtoFloat.match(None, "2834.235928").node, - ProtoFloat(None, 2834.235928, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834.235928").node, + ProtoFloat(2834.235928, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, ".0").node, - ProtoFloat(None, 0.0, ProtoFloatSign.POSITIVE), + ProtoFloat.match(".0").node, + ProtoFloat(0.0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, ".3265").node, - ProtoFloat(None, 0.3265, ProtoFloatSign.POSITIVE), + ProtoFloat.match(".3265").node, + ProtoFloat(0.3265, ProtoFloatSign.POSITIVE), ) def test_inf(self): self.assertEqual( - ProtoFloat.match(None, "inf").node, - ProtoFloat(None, float("inf"), ProtoFloatSign.POSITIVE), + ProtoFloat.match("inf").node, + ProtoFloat(float("inf"), ProtoFloatSign.POSITIVE), ) def test_nan(self): - match = ProtoFloat.match(None, "nan") + match = ProtoFloat.match("nan") self.assertNotEqual(match.node.value, match.node.value) self.assertEqual(match.remaining_source, "") self.assertEqual(match.node.sign, ProtoFloatSign.POSITIVE) def test_exponential_positive(self): self.assertEqual( - ProtoFloat.match(None, "2834.e2").node, - ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834.e2").node, + ProtoFloat(283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, "2834e2").node, - ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834e2").node, + ProtoFloat(283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, "2834.e0").node, - ProtoFloat(None, 2834, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834.e0").node, + ProtoFloat(2834, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, "2834e0").node, - ProtoFloat(None, 2834, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834e0").node, + ProtoFloat(2834, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, "2834.E3").node, - ProtoFloat(None, 2834000, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834.E3").node, + ProtoFloat(2834000, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, "2834E3").node, - ProtoFloat(None, 2834000, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834E3").node, + ProtoFloat(2834000, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, "2834.e+2").node, - ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834.e+2").node, + ProtoFloat(283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, "2834e+2").node, - ProtoFloat(None, 283400, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834e+2").node, + ProtoFloat(283400, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, ".0E1").node, - ProtoFloat(None, 0, ProtoFloatSign.POSITIVE), + ProtoFloat.match(".0E1").node, + ProtoFloat(0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, ".0E2").node, - ProtoFloat(None, 0, ProtoFloatSign.POSITIVE), + ProtoFloat.match(".0E2").node, + ProtoFloat(0, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, ".3265e1").node, - ProtoFloat(None, 3.265, ProtoFloatSign.POSITIVE), + ProtoFloat.match(".3265e1").node, + ProtoFloat(3.265, ProtoFloatSign.POSITIVE), ) def test_exponential_negative(self): self.assertEqual( - ProtoFloat.match(None, "2834.e-2").node, - ProtoFloat(None, 28.34, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834.e-2").node, + ProtoFloat(28.34, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, "2834e-2").node, - ProtoFloat(None, 28.34, ProtoFloatSign.POSITIVE), + ProtoFloat.match("2834e-2").node, + ProtoFloat(28.34, ProtoFloatSign.POSITIVE), ) self.assertEqual( - ProtoFloat.match(None, ".0e-1").node, - ProtoFloat(None, 0.00, ProtoFloatSign.POSITIVE), + ProtoFloat.match(".0e-1").node, + ProtoFloat(0.00, ProtoFloatSign.POSITIVE), ) diff --git a/test/proto_identifier_test.py b/test/proto_identifier_test.py index d1f44d3..dd5435f 100644 --- a/test/proto_identifier_test.py +++ b/test/proto_identifier_test.py @@ -10,99 +10,89 @@ class IdentifierTest(unittest.TestCase): def test_ident(self): - self.assertEqual(ProtoIdentifier.match(None, "a").node.identifier, "a") - self.assertEqual(ProtoIdentifier.match(None, "a0").node.identifier, "a0") - self.assertEqual(ProtoIdentifier.match(None, "a_").node.identifier, "a_") - self.assertEqual(ProtoIdentifier.match(None, "aa").node.identifier, "aa") - self.assertEqual(ProtoIdentifier.match(None, "ab").node.identifier, "ab") - self.assertEqual( - ProtoIdentifier.match(None, "a0b_f_aj").node.identifier, "a0b_f_aj" - ) + self.assertEqual(ProtoIdentifier.match("a").node.identifier, "a") + self.assertEqual(ProtoIdentifier.match("a0").node.identifier, "a0") + self.assertEqual(ProtoIdentifier.match("a_").node.identifier, "a_") + self.assertEqual(ProtoIdentifier.match("aa").node.identifier, "aa") + self.assertEqual(ProtoIdentifier.match("ab").node.identifier, "ab") + self.assertEqual(ProtoIdentifier.match("a0b_f_aj").node.identifier, "a0b_f_aj") def test_ident_no_leading_letter(self): - self.assertIsNone(ProtoIdentifier.match(None, "0")) - self.assertIsNone(ProtoIdentifier.match(None, "0abc_ab")) - self.assertIsNone(ProtoIdentifier.match(None, "0_ab_0a_a0")) - self.assertIsNone(ProtoIdentifier.match(None, " ")) - self.assertIsNone(ProtoIdentifier.match(None, " abc")) - self.assertIsNone(ProtoIdentifier.match(None, "\nabc")) - self.assertIsNone(ProtoIdentifier.match(None, "\n abc")) - self.assertIsNone(ProtoIdentifier.match(None, "\tabc")) - self.assertIsNone(ProtoIdentifier.match(None, "\n\tabc")) - self.assertIsNone(ProtoIdentifier.match(None, "\t\nabc")) - self.assertIsNone(ProtoIdentifier.match(None, "\t\n abc")) - self.assertIsNone(ProtoIdentifier.match(None, ".a")) - self.assertIsNone(ProtoIdentifier.match(None, " .a")) - self.assertIsNone(ProtoIdentifier.match(None, ".")) - self.assertIsNone(ProtoIdentifier.match(None, ".0")) + self.assertIsNone(ProtoIdentifier.match("0")) + self.assertIsNone(ProtoIdentifier.match("0abc_ab")) + self.assertIsNone(ProtoIdentifier.match("0_ab_0a_a0")) + self.assertIsNone(ProtoIdentifier.match(" ")) + self.assertIsNone(ProtoIdentifier.match(" abc")) + self.assertIsNone(ProtoIdentifier.match("\nabc")) + self.assertIsNone(ProtoIdentifier.match("\n abc")) + self.assertIsNone(ProtoIdentifier.match("\tabc")) + self.assertIsNone(ProtoIdentifier.match("\n\tabc")) + self.assertIsNone(ProtoIdentifier.match("\t\nabc")) + self.assertIsNone(ProtoIdentifier.match("\t\n abc")) + self.assertIsNone(ProtoIdentifier.match(".a")) + self.assertIsNone(ProtoIdentifier.match(" .a")) + self.assertIsNone(ProtoIdentifier.match(".")) + self.assertIsNone(ProtoIdentifier.match(".0")) def test_full_ident(self): - self.assertEqual(ProtoFullIdentifier.match(None, "a").node.identifier, "a") - self.assertEqual( - ProtoFullIdentifier.match(None, "a.bar").node.identifier, "a.bar" - ) + self.assertEqual(ProtoFullIdentifier.match("a").node.identifier, "a") + self.assertEqual(ProtoFullIdentifier.match("a.bar").node.identifier, "a.bar") self.assertEqual( - ProtoFullIdentifier.match(None, "a.bar.baz").node.identifier, "a.bar.baz" + ProtoFullIdentifier.match("a.bar.baz").node.identifier, "a.bar.baz" ) self.assertEqual( - ProtoFullIdentifier.match(None, "a.bar.b0").node.identifier, "a.bar.b0" + ProtoFullIdentifier.match("a.bar.b0").node.identifier, "a.bar.b0" ) self.assertEqual( - ProtoFullIdentifier.match(None, "a.bar.b0.c_2a").node.identifier, + ProtoFullIdentifier.match("a.bar.b0.c_2a").node.identifier, "a.bar.b0.c_2a", ) def test_full_ident_invalid_periods(self): with self.assertRaises(ValueError): - ProtoFullIdentifier.match(None, "a.") + ProtoFullIdentifier.match("a.") with self.assertRaises(ValueError): - ProtoFullIdentifier.match(None, "a.bar.") + ProtoFullIdentifier.match("a.bar.") with self.assertRaises(ValueError): - ProtoFullIdentifier.match(None, "a..") + ProtoFullIdentifier.match("a..") def test_message_type(self): + self.assertEqual(ProtoEnumOrMessageIdentifier.match("a").node.identifier, "a") + self.assertEqual(ProtoEnumOrMessageIdentifier.match(".a").node.identifier, ".a") self.assertEqual( - ProtoEnumOrMessageIdentifier.match(None, "a").node.identifier, "a" - ) - self.assertEqual( - ProtoEnumOrMessageIdentifier.match(None, ".a").node.identifier, ".a" - ) - self.assertEqual( - ProtoEnumOrMessageIdentifier.match(None, ".a.bar").node.identifier, ".a.bar" + ProtoEnumOrMessageIdentifier.match(".a.bar").node.identifier, ".a.bar" ) self.assertEqual( - ProtoEnumOrMessageIdentifier.match(None, "a.bar").node.identifier, "a.bar" + ProtoEnumOrMessageIdentifier.match("a.bar").node.identifier, "a.bar" ) def test_identifier_serialize(self): - self.assertEqual(ProtoIdentifier.match(None, "a").node.serialize(), "a") - self.assertEqual(ProtoIdentifier.match(None, "a0").node.serialize(), "a0") + self.assertEqual(ProtoIdentifier.match("a").node.serialize(), "a") + self.assertEqual(ProtoIdentifier.match("a0").node.serialize(), "a0") self.assertEqual( - ProtoIdentifier.match(None, "a_").node.serialize(), + ProtoIdentifier.match("a_").node.serialize(), "a_", ) self.assertEqual( - ProtoIdentifier.match(None, "a0_foo_ba0_0baz").node.serialize(), + ProtoIdentifier.match("a0_foo_ba0_0baz").node.serialize(), "a0_foo_ba0_0baz", ) self.assertEqual( - ProtoFullIdentifier.match(None, "a.bar").node.serialize(), + ProtoFullIdentifier.match("a.bar").node.serialize(), "a.bar", ) self.assertEqual( - ProtoFullIdentifier.match(None, "a.bar_baz.foo0").node.serialize(), + ProtoFullIdentifier.match("a.bar_baz.foo0").node.serialize(), "a.bar_baz.foo0", ) self.assertEqual( - ProtoEnumOrMessageIdentifier.match(None, ".a").node.serialize(), + ProtoEnumOrMessageIdentifier.match(".a").node.serialize(), ".a", ) self.assertEqual( - ProtoEnumOrMessageIdentifier.match( - None, ".a.bar0_baz.foo" - ).node.serialize(), + ProtoEnumOrMessageIdentifier.match(".a.bar0_baz.foo").node.serialize(), ".a.bar0_baz.foo", ) diff --git a/test/proto_import_test.py b/test/proto_import_test.py index 994ec22..8806d8f 100644 --- a/test/proto_import_test.py +++ b/test/proto_import_test.py @@ -13,14 +13,14 @@ class ImportTest(unittest.TestCase): def test_bare_import(self): - double_quote_import = ProtoImport.match(None, 'import "foo.proto";') + double_quote_import = ProtoImport.match('import "foo.proto";') self.assertEqual(double_quote_import.node.path.value, "foo.proto") self.assertEqual(double_quote_import.node.weak, False) self.assertEqual(double_quote_import.node.public, False) self.assertEqual(double_quote_import.node.serialize(), 'import "foo.proto";') self.assertEqual(double_quote_import.remaining_source, "") - single_quote_import = ProtoImport.match(None, "import 'foo.proto';") + single_quote_import = ProtoImport.match("import 'foo.proto';") self.assertEqual(single_quote_import.node.path.value, "foo.proto") self.assertEqual(single_quote_import.node.weak, False) self.assertEqual(single_quote_import.node.public, False) @@ -29,29 +29,29 @@ def test_bare_import(self): def test_import_missing_semicolon(self): with self.assertRaises(ValueError): - ProtoImport.match(None, 'import "foo.proto"') + ProtoImport.match('import "foo.proto"') def test_import_missing_starting_quote(self): with self.assertRaises(ValueError): - ProtoImport.match(None, 'import foo.proto";') + ProtoImport.match('import foo.proto";') with self.assertRaises(ValueError): - ProtoImport.match(None, "import foo.proto';") + ProtoImport.match("import foo.proto';") def test_import_missing_ending_quote(self): with self.assertRaises(ValueError): - ProtoImport.match(None, 'import "foo.proto;') + ProtoImport.match('import "foo.proto;') with self.assertRaises(ValueError): - ProtoImport.match(None, "import 'foo.proto;") + ProtoImport.match("import 'foo.proto;") def test_weak_import(self): - double_quote_import = ProtoImport.match(None, 'import weak "foo.proto";') + double_quote_import = ProtoImport.match('import weak "foo.proto";') self.assertEqual(double_quote_import.node.weak, True) self.assertEqual( double_quote_import.node.serialize(), 'import weak "foo.proto";' ) - double_quote_import = ProtoImport.match(None, "import weak 'foo.proto';") + double_quote_import = ProtoImport.match("import weak 'foo.proto';") self.assertEqual(double_quote_import.node.weak, True) self.assertEqual( double_quote_import.node.serialize(), "import weak 'foo.proto';" @@ -59,11 +59,10 @@ def test_weak_import(self): def test_weak_typoed_import(self): with self.assertRaises(ValueError): - ProtoImport.match(None, 'import weac "foo.proto";') + ProtoImport.match('import weac "foo.proto";') def test_weak_mixed_imports(self): first_parsed_import = ProtoImport.match( - None, dedent( """import "foo.proto"; import weak "bar/baz.proto"; @@ -74,30 +73,26 @@ def test_weak_mixed_imports(self): self.assertEqual(first_parsed_import.node.weak, False) self.assertEqual(first_parsed_import.node.serialize(), 'import "foo.proto";') - second_parsed_import = ProtoImport.match( - None, first_parsed_import.remaining_source - ) + second_parsed_import = ProtoImport.match(first_parsed_import.remaining_source) self.assertEqual(second_parsed_import.node.path.value, "bar/baz.proto") self.assertEqual(second_parsed_import.node.weak, True) self.assertEqual( second_parsed_import.node.serialize(), 'import weak "bar/baz.proto";' ) - third_parsed_import = ProtoImport.match( - None, second_parsed_import.remaining_source - ) + third_parsed_import = ProtoImport.match(second_parsed_import.remaining_source) self.assertEqual(third_parsed_import.node.path.value, "bat.proto") self.assertEqual(third_parsed_import.node.weak, False) self.assertEqual(third_parsed_import.node.serialize(), 'import "bat.proto";') def test_public_import(self): - double_quote_import = ProtoImport.match(None, 'import public "foo.proto";') + double_quote_import = ProtoImport.match('import public "foo.proto";') self.assertEqual(double_quote_import.node.public, True) self.assertEqual( double_quote_import.node.serialize(), 'import public "foo.proto";' ) - single_quote_import = ProtoImport.match(None, "import public 'foo.proto';") + single_quote_import = ProtoImport.match("import public 'foo.proto';") self.assertEqual(single_quote_import.node.public, True) self.assertEqual( single_quote_import.node.serialize(), "import public 'foo.proto';" @@ -105,18 +100,17 @@ def test_public_import(self): def test_public_typoed_import(self): with self.assertRaises(ValueError): - ProtoImport.match(None, 'import publik "foo.proto";') + ProtoImport.match('import publik "foo.proto";') def test_public_weak_mutually_exclusive(self): with self.assertRaises(ValueError): - ProtoImport.match(None, 'import weak public "foo.proto";') + ProtoImport.match('import weak public "foo.proto";') with self.assertRaises(ValueError): - ProtoImport.match(None, 'import public weak "foo.proto";') + ProtoImport.match('import public weak "foo.proto";') def test_public_mixed_imports(self): first_parsed_import = ProtoImport.match( - None, dedent( """import "foo.proto"; import public "bar/baz.proto"; @@ -127,18 +121,14 @@ def test_public_mixed_imports(self): self.assertEqual(first_parsed_import.node.public, False) self.assertEqual(first_parsed_import.node.serialize(), 'import "foo.proto";') - second_parsed_import = ProtoImport.match( - None, first_parsed_import.remaining_source - ) + second_parsed_import = ProtoImport.match(first_parsed_import.remaining_source) self.assertEqual(second_parsed_import.node.path.value, "bar/baz.proto") self.assertEqual(second_parsed_import.node.public, True) self.assertEqual( second_parsed_import.node.serialize(), 'import public "bar/baz.proto";' ) - third_parsed_import = ProtoImport.match( - None, second_parsed_import.remaining_source - ) + third_parsed_import = ProtoImport.match(second_parsed_import.remaining_source) self.assertEqual(third_parsed_import.node.path.value, "bat.proto") self.assertEqual(third_parsed_import.node.public, True) self.assertEqual( @@ -146,21 +136,21 @@ def test_public_mixed_imports(self): ) def test_diff_sets_same_path_simple(self): - pf1 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) - pf2 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) + pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + pf2 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) self.assertEqual(ProtoImport.diff_sets([pf1], [pf2]), []) def test_diff_sets_added_path_simple(self): - pf1 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) + pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) self.assertEqual(ProtoImport.diff_sets([pf1], []), [ProtoImportAdded(pf1)]) def test_diff_sets_removed_path_simple(self): - pf2 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) + pf2 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) self.assertEqual(ProtoImport.diff_sets([], [pf2]), [ProtoImportRemoved(pf2)]) def test_diff_sets_different_path_simple(self): - pf1 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some.proto")) - pf2 = ProtoImport(None, ProtoStringLiteral(None, "path/to/some/other.proto")) + pf1 = ProtoImport(ProtoStringLiteral("path/to/some.proto")) + pf2 = ProtoImport(ProtoStringLiteral("path/to/some/other.proto")) self.assertEqual( ProtoImport.diff_sets([pf1], [pf2]), [ProtoImportAdded(pf1), ProtoImportRemoved(pf2)], @@ -168,14 +158,12 @@ def test_diff_sets_different_path_simple(self): def test_diff_sets_changed_optional_attributes(self): pf1 = ProtoImport( - None, - ProtoStringLiteral(None, "path/to/some.proto"), + ProtoStringLiteral("path/to/some.proto"), weak=False, public=True, ) pf2 = ProtoImport( - None, - ProtoStringLiteral(None, "path/to/some.proto"), + ProtoStringLiteral("path/to/some.proto"), weak=True, public=False, ) diff --git a/test/proto_int_test.py b/test/proto_int_test.py index 0aaf7f7..3293d5e 100644 --- a/test/proto_int_test.py +++ b/test/proto_int_test.py @@ -5,33 +5,31 @@ class IntTest(unittest.TestCase): def test_int(self): + self.assertEqual(ProtoInt.match("1").node, ProtoInt(1, ProtoIntSign.POSITIVE)) self.assertEqual( - ProtoInt.match(None, "1").node, ProtoInt(None, 1, ProtoIntSign.POSITIVE) - ) - self.assertEqual( - ProtoInt.match(None, "158912938471293847").node, - ProtoInt(None, 158912938471293847, ProtoIntSign.POSITIVE), + ProtoInt.match("158912938471293847").node, + ProtoInt(158912938471293847, ProtoIntSign.POSITIVE), ) def test_octal(self): self.assertEqual( - ProtoInt.match(None, "072342").node, - ProtoInt(None, 0o72342, ProtoIntSign.POSITIVE), + ProtoInt.match("072342").node, + ProtoInt(0o72342, ProtoIntSign.POSITIVE), ) with self.assertRaises(ValueError): - ProtoInt.match(None, "072942") + ProtoInt.match("072942") def test_hex(self): self.assertEqual( - ProtoInt.match(None, "0x72342").node, - ProtoInt(None, 0x72342, ProtoIntSign.POSITIVE), + ProtoInt.match("0x72342").node, + ProtoInt(0x72342, ProtoIntSign.POSITIVE), ) self.assertEqual( - ProtoInt.match(None, "0x7A3d2").node, - ProtoInt(None, 0x7A3D2, ProtoIntSign.POSITIVE), + ProtoInt.match("0x7A3d2").node, + ProtoInt(0x7A3D2, ProtoIntSign.POSITIVE), ) with self.assertRaises(ValueError): - ProtoInt.match(None, "0x72G42") + ProtoInt.match("0x72G42") if __name__ == "__main__": diff --git a/test/proto_map_test.py b/test/proto_map_test.py index b67c424..59e7ba1 100644 --- a/test/proto_map_test.py +++ b/test/proto_map_test.py @@ -16,84 +16,72 @@ class MapTest(unittest.TestCase): maxDiff = None def test_simple_map(self): - parsed_map_simple = ProtoMap.match( - None, "map my_map = 10;" - ) + parsed_map_simple = ProtoMap.match("map my_map = 10;") self.assertEqual( parsed_map_simple.node, ProtoMap( - None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "my_map"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + ProtoIdentifier("my_map"), + ProtoInt(10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier("NestedMessage"), [], ), ) def test_map_without_spaces(self): - map_without_spaces = ProtoMap.match( - None, "map my_map = 10;" - ) + map_without_spaces = ProtoMap.match("map my_map = 10;") self.assertEqual( map_without_spaces.node, ProtoMap( - None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "my_map"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + ProtoIdentifier("my_map"), + ProtoInt(10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier("NestedMessage"), [], ), ) def test_map_with_options(self): parsed_map_simple = ProtoMap.match( - None, "map my_map = 10 [ java_package = 'com.example.foo', baz.bat = 48 ];", ) self.assertEqual(parsed_map_simple.node.key_type, ProtoMapKeyTypesEnum.SFIXED64) self.assertEqual( parsed_map_simple.node.value_type, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE ) - self.assertEqual(parsed_map_simple.node.name, ProtoIdentifier(None, "my_map")) + self.assertEqual(parsed_map_simple.node.name, ProtoIdentifier("my_map")) self.assertEqual( - parsed_map_simple.node.number, ProtoInt(None, 10, ProtoIntSign.POSITIVE) + parsed_map_simple.node.number, ProtoInt(10, ProtoIntSign.POSITIVE) ) self.assertEqual( parsed_map_simple.node.enum_or_message_type_name, - ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + ProtoEnumOrMessageIdentifier("NestedMessage"), ) self.assertEqual( parsed_map_simple.node.options, [ ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "com.example.foo")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), ), ProtoMessageFieldOption( - None, - ProtoFullIdentifier(None, "baz.bat"), - ProtoConstant(None, ProtoInt(None, 48, ProtoIntSign.POSITIVE)), + ProtoFullIdentifier("baz.bat"), + ProtoConstant(ProtoInt(48, ProtoIntSign.POSITIVE)), ), ], ) def test_map_message_value(self): - parsed_map_simple = ProtoMap.match( - None, "map string_map = 11;" - ) + parsed_map_simple = ProtoMap.match("map string_map = 11;") self.assertEqual( parsed_map_simple.node, ProtoMap( - None, ProtoMapKeyTypesEnum.STRING, ProtoMapValueTypesEnum.STRING, - ProtoIdentifier(None, "string_map"), - ProtoInt(None, 11, ProtoIntSign.POSITIVE), + ProtoIdentifier("string_map"), + ProtoInt(11, ProtoIntSign.POSITIVE), None, [], ), diff --git a/test/proto_message_field_test.py b/test/proto_message_field_test.py index 26c82e6..fa6a882 100644 --- a/test/proto_message_field_test.py +++ b/test/proto_message_field_test.py @@ -19,14 +19,13 @@ class MessageFieldTest(unittest.TestCase): maxDiff = None def test_field_optional_default_false(self): - string_field = ProtoMessageField.match(None, "string single_field = 1;") + string_field = ProtoMessageField.match("string single_field = 1;") self.assertEqual( string_field.node, ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "single_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("single_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), False, False, ), @@ -34,15 +33,14 @@ def test_field_optional_default_false(self): def test_field_optional_set(self): string_field = ProtoMessageField.match( - None, "optional string single_field = 1;".strip() + "optional string single_field = 1;".strip() ) self.assertEqual( string_field.node, ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "single_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("single_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), False, True, ), @@ -51,116 +49,104 @@ def test_field_optional_set(self): def test_field_cannot_have_repeated_and_optional(self): with self.assertRaises(ValueError): ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "single_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("single_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), True, True, ) def test_message_field_starts_with_underscore(self): - parsed_undescored_field = ProtoMessageField.match( - None, "string _test_field = 1;" - ) + parsed_undescored_field = ProtoMessageField.match("string _test_field = 1;") self.assertEqual( parsed_undescored_field.node, ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "_test_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("_test_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ) parsed_double_undescored_field = ProtoMessageField.match( - None, "bool __test_field = 1;" + "bool __test_field = 1;" ) self.assertEqual( parsed_double_undescored_field.node, ProtoMessageField( - None, ProtoMessageFieldTypesEnum.BOOL, - ProtoIdentifier(None, "__test_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("__test_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ) def test_field_repeated(self): parsed_message_with_repeated_field_simple = ProtoMessageField.match( - None, "repeated bool repeated_field = 3;" + "repeated bool repeated_field = 3;" ) self.assertEqual( parsed_message_with_repeated_field_simple.node, ProtoMessageField( - None, ProtoMessageFieldTypesEnum.BOOL, - ProtoIdentifier(None, "repeated_field"), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoIdentifier("repeated_field"), + ProtoInt(3, ProtoIntSign.POSITIVE), True, ), ) def test_field_enum_or_message(self): parsed_message_with_repeated_field_simple = ProtoMessageField.match( - None, "foo.SomeEnumOrMessage enum_or_message_field = 1;" + "foo.SomeEnumOrMessage enum_or_message_field = 1;" ) self.assertEqual( parsed_message_with_repeated_field_simple.node, ProtoMessageField( - None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "enum_or_message_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("enum_or_message_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier(None, "foo.SomeEnumOrMessage"), + ProtoFullIdentifier("foo.SomeEnumOrMessage"), ), ) def test_field_starts_with_period(self): parsed_field_with_type_starting_with_period = ProtoMessageField.match( - None, ".google.proto.FooType enum_or_message_field = 1;" + ".google.proto.FooType enum_or_message_field = 1;" ) self.assertEqual( parsed_field_with_type_starting_with_period.node, ProtoMessageField( - None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "enum_or_message_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("enum_or_message_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), False, False, - ProtoEnumOrMessageIdentifier(None, ".google.proto.FooType"), + ProtoEnumOrMessageIdentifier(".google.proto.FooType"), ), ) def test_diff_same_field_returns_empty(self): pmf1 = ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "my_message_field"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoIdentifier("my_message_field"), + ProtoInt(10, ProtoIntSign.POSITIVE), ) pmf2 = ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "my_message_field"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoIdentifier("my_message_field"), + ProtoInt(10, ProtoIntSign.POSITIVE), ) self.assertEqual(ProtoMessageField.diff(None, pmf1, pmf2), []) def test_diff_different_field_name_same_number_returns_field_diff(self): pmf1 = ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(10, ProtoIntSign.POSITIVE), ) pmf2 = ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "bar"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar"), + ProtoInt(10, ProtoIntSign.POSITIVE), ) self.assertEqual( [ @@ -175,10 +161,9 @@ def test_diff_different_field_name_same_number_returns_field_diff(self): def test_diff_field_removed(self): pmf1 = ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(10, ProtoIntSign.POSITIVE), ) pmf2 = None self.assertEqual( @@ -196,22 +181,19 @@ def test_diff_sets_empty_returns_empty(self): def test_diff_sets_no_change(self): set1 = [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "bar"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "baz"), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoIdentifier("baz"), + ProtoInt(3, ProtoIntSign.POSITIVE), ), ] self.assertEqual([], ProtoMessageField.diff_sets(None, set1, set1)) @@ -220,22 +202,19 @@ def test_diff_sets_all_removed(self): set1 = [] set2 = [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "bar"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "baz"), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoIdentifier("baz"), + ProtoInt(3, ProtoIntSign.POSITIVE), ), ] diff = ProtoMessageField.diff_sets(None, set1, set2) @@ -250,22 +229,19 @@ def test_diff_sets_all_removed(self): def test_diff_sets_all_added(self): set1 = [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "bar"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "baz"), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoIdentifier("baz"), + ProtoInt(3, ProtoIntSign.POSITIVE), ), ] set2 = [] @@ -282,42 +258,36 @@ def test_diff_sets_all_added(self): def test_diff_sets_mutually_exclusive(self): set1 = [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "bar"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "baz"), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoIdentifier("baz"), + ProtoInt(3, ProtoIntSign.POSITIVE), ), ] set2 = [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "foo2"), - ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo2"), + ProtoInt(4, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "bar2"), - ProtoInt(None, 5, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar2"), + ProtoInt(5, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "baz2"), - ProtoInt(None, 6, ProtoIntSign.POSITIVE), + ProtoIdentifier("baz2"), + ProtoInt(6, ProtoIntSign.POSITIVE), ), ] @@ -340,42 +310,36 @@ def test_diff_sets_mutually_exclusive(self): def test_diff_sets_overlap(self): set1 = [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "bar"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "baz"), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoIdentifier("baz"), + ProtoInt(3, ProtoIntSign.POSITIVE), ), ] set2 = [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "foo2"), - ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo2"), + ProtoInt(4, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "bar"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.FLOAT, - ProtoIdentifier(None, "baz2"), - ProtoInt(None, 6, ProtoIntSign.POSITIVE), + ProtoIdentifier("baz2"), + ProtoInt(6, ProtoIntSign.POSITIVE), ), ] diff --git a/test/proto_message_test.py b/test/proto_message_test.py index 9e0f684..fa4a5ae 100644 --- a/test/proto_message_test.py +++ b/test/proto_message_test.py @@ -36,7 +36,6 @@ class MessageTest(unittest.TestCase): def test_message_all_features(self): parsed_message_multiple_fields = ProtoMessage.match( - None, dedent( """ message FooMessage { @@ -68,152 +67,119 @@ def test_message_all_features(self): parsed_message_multiple_fields.node.nodes, [ ProtoOption( - None, - ProtoIdentifier(None, "(foo.bar).baz"), - ProtoConstant(None, ProtoStringLiteral(None, "bat")), + ProtoIdentifier("(foo.bar).baz"), + ProtoConstant(ProtoStringLiteral("bat")), ), ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_UNDEFINED"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_UNDEFINED"), + ProtoInt(0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_VALONE"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_VALONE"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_VALTWO"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_VALTWO"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ], ), - ProtoMessage(None, ProtoIdentifier(None, "NestedMessage"), []), - ProtoReserved(None, fields=[ProtoIdentifier(None, "a")]), + ProtoMessage(ProtoIdentifier("NestedMessage"), []), + ProtoReserved(fields=[ProtoIdentifier("a")]), ProtoReserved( - None, ranges=[ ProtoRange( - None, - ProtoInt(None, 1, ProtoIntSign.POSITIVE), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoInt(3, ProtoIntSign.POSITIVE), ) ], ), - ProtoSingleLineComment(None, " single-line comment"), + ProtoSingleLineComment(" single-line comment"), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "some_field"), - ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ProtoIdentifier("some_field"), + ProtoInt(4, ProtoIntSign.POSITIVE), True, False, None, [ ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "(bar.baz).bat"), - ProtoConstant(None, ProtoStringLiteral(None, "bat")), + ProtoIdentifier("(bar.baz).bat"), + ProtoConstant(ProtoStringLiteral("bat")), ), ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "baz.bat"), - ProtoConstant( - None, ProtoInt(None, 100, ProtoIntSign.NEGATIVE) - ), + ProtoIdentifier("baz.bat"), + ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), ), ], ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.BOOL, - ProtoIdentifier(None, "some_bool_field"), - ProtoInt(None, 5, ProtoIntSign.POSITIVE), + ProtoIdentifier("some_bool_field"), + ProtoInt(5, ProtoIntSign.POSITIVE), ), ProtoOneOf( - None, - ProtoIdentifier(None, "one_of_field"), + ProtoIdentifier("one_of_field"), [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "name"), - ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), ), ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant( - None, ProtoStringLiteral(None, "com.example.foo") - ), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "sub_message"), - ProtoInt(None, 9, ProtoIntSign.POSITIVE), + ProtoIdentifier("sub_message"), + ProtoInt(9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier(None, "SubMessage"), + ProtoFullIdentifier("SubMessage"), [ ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "(bar.baz).bat"), - ProtoConstant( - None, ProtoStringLiteral(None, "bat") - ), + ProtoIdentifier("(bar.baz).bat"), + ProtoConstant(ProtoStringLiteral("bat")), ), ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "baz.bat"), - ProtoConstant( - None, ProtoInt(None, 100, ProtoIntSign.NEGATIVE) - ), + ProtoIdentifier("baz.bat"), + ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), ), ], ), ], ), ProtoMap( - None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "my_map"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + ProtoIdentifier("my_map"), + ProtoInt(10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier("NestedMessage"), [], ), ProtoMap( - None, # map string_map = 11 [ java_package = "com.example.foo", baz.bat = 48 ]; ProtoMapKeyTypesEnum.STRING, ProtoMapValueTypesEnum.STRING, - ProtoIdentifier(None, "string_map"), - ProtoInt(None, 11, ProtoIntSign.POSITIVE), + ProtoIdentifier("string_map"), + ProtoInt(11, ProtoIntSign.POSITIVE), None, [ ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant( - None, ProtoStringLiteral(None, "com.example.foo") - ), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), ), ProtoMessageFieldOption( - None, - ProtoFullIdentifier(None, "baz.bat"), - ProtoConstant( - None, ProtoInt(None, 48, ProtoIntSign.POSITIVE) - ), + ProtoFullIdentifier("baz.bat"), + ProtoConstant(ProtoInt(48, ProtoIntSign.POSITIVE)), ), ], ), - ProtoExtensions(None, [ProtoRange(None, 8, ProtoRangeEnum.MAX)]), + ProtoExtensions([ProtoRange(8, ProtoRangeEnum.MAX)]), ], ) self.assertEqual( @@ -248,14 +214,11 @@ def test_message_all_features(self): ) def test_empty_message(self): - parsed_empty_message = ProtoMessage.match(None, """message FooMessage {}""") + parsed_empty_message = ProtoMessage.match("""message FooMessage {}""") self.assertIsNotNone(parsed_empty_message) - self.assertEqual( - parsed_empty_message.node.name, ProtoIdentifier(None, "FooMessage") - ) + self.assertEqual(parsed_empty_message.node.name, ProtoIdentifier("FooMessage")) parsed_spaced_message = ProtoMessage.match( - None, dedent( """ message FooMessage { @@ -265,13 +228,10 @@ def test_empty_message(self): ), ) self.assertIsNotNone(parsed_spaced_message) - self.assertEqual( - parsed_spaced_message.node.name, ProtoIdentifier(None, "FooMessage") - ) + self.assertEqual(parsed_spaced_message.node.name, ProtoIdentifier("FooMessage")) def test_message_empty_statements(self): empty_statement_message = ProtoMessage.match( - None, dedent( """ message FooMessage { @@ -283,12 +243,11 @@ def test_message_empty_statements(self): ) self.assertIsNotNone(empty_statement_message) self.assertEqual( - empty_statement_message.node.name, ProtoIdentifier(None, "FooMessage") + empty_statement_message.node.name, ProtoIdentifier("FooMessage") ) def test_message_optionals(self): parsed_message_with_optionals = ProtoMessage.match( - None, dedent( """ message FooMessage { @@ -302,24 +261,21 @@ def test_message_optionals(self): parsed_message_with_optionals.node.options, [ ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foobar")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foobar")), ), ProtoOption( - None, - ProtoIdentifier(None, "(foo.bar).baz"), - ProtoConstant(None, ProtoBool(None, False)), + ProtoIdentifier("(foo.bar).baz"), + ProtoConstant(ProtoBool(False)), ), ], ) self.assertEqual( - parsed_message_with_optionals.node.name, ProtoIdentifier(None, "FooMessage") + parsed_message_with_optionals.node.name, ProtoIdentifier("FooMessage") ) def test_message_nested_enum(self): parsed_message_with_enum = ProtoMessage.match( - None, dedent( """ message FooMessage { @@ -335,27 +291,22 @@ def test_message_nested_enum(self): self.assertEqual( parsed_message_with_enum.node, ProtoMessage( - None, - ProtoIdentifier(None, "FooMessage"), + ProtoIdentifier("FooMessage"), [ ProtoEnum( - None, - ProtoIdentifier(None, "MyEnum"), + ProtoIdentifier("MyEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_UNDEFINED"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_UNDEFINED"), + ProtoInt(0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_NEGATIVE"), - ProtoInt(None, 1, ProtoIntSign.NEGATIVE), + ProtoIdentifier("ME_NEGATIVE"), + ProtoInt(1, ProtoIntSign.NEGATIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "ME_VALONE"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("ME_VALONE"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ], ) @@ -365,7 +316,6 @@ def test_message_nested_enum(self): def test_message_nested_message(self): parsed_message_with_enum = ProtoMessage.match( - None, dedent( """ message FooMessage { @@ -377,17 +327,15 @@ def test_message_nested_message(self): self.assertEqual( parsed_message_with_enum.node, ProtoMessage( - None, - ProtoIdentifier(None, "FooMessage"), + ProtoIdentifier("FooMessage"), [ - ProtoMessage(None, ProtoIdentifier(None, "NestedMessage"), []), + ProtoMessage(ProtoIdentifier("NestedMessage"), []), ], ), ) def test_message_reserved_single_field(self): parsed_message_with_reserved_single_field = ProtoMessage.match( - None, dedent( """ message FooMessage { @@ -400,30 +348,25 @@ def test_message_reserved_single_field(self): self.assertEqual( parsed_message_with_reserved_single_field.node, ProtoMessage( - None, - ProtoIdentifier(None, "FooMessage"), + ProtoIdentifier("FooMessage"), [ ProtoReserved( - None, ranges=[ - ProtoRange(None, ProtoInt(None, 38, ProtoIntSign.POSITIVE)), + ProtoRange(ProtoInt(38, ProtoIntSign.POSITIVE)), ProtoRange( - None, - ProtoInt(None, 48, ProtoIntSign.POSITIVE), - ProtoInt(None, 100, ProtoIntSign.POSITIVE), + ProtoInt(48, ProtoIntSign.POSITIVE), + ProtoInt(100, ProtoIntSign.POSITIVE), ), ProtoRange( - None, - ProtoInt(None, 72, ProtoIntSign.POSITIVE), + ProtoInt(72, ProtoIntSign.POSITIVE), ProtoRangeEnum.MAX, ), ], ), ProtoReserved( - None, fields=[ - ProtoIdentifier(None, "foo"), - ProtoIdentifier(None, "barBaz"), + ProtoIdentifier("foo"), + ProtoIdentifier("barBaz"), ], ), ], @@ -432,7 +375,6 @@ def test_message_reserved_single_field(self): def test_message_simple_field(self): parsed_message_with_single_field_simple = ProtoMessage.match( - None, dedent( """ message FooMessage { @@ -444,35 +386,29 @@ def test_message_simple_field(self): self.assertEqual( parsed_message_with_single_field_simple.node, ProtoMessage( - None, - ProtoIdentifier(None, "FooMessage"), + ProtoIdentifier("FooMessage"), [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "single_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("single_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), ) ], ), ) def test_oneof_empty(self): - parsed_oneof_empty = ProtoOneOf.match( - None, dedent("oneof one_of_field {}".strip()) - ) + parsed_oneof_empty = ProtoOneOf.match(dedent("oneof one_of_field {}".strip())) self.assertEqual( parsed_oneof_empty.node, ProtoOneOf( - None, - ProtoIdentifier(None, "one_of_field"), + ProtoIdentifier("one_of_field"), [], ), ) def test_oneof_empty_statements(self): parsed_oneof_empty = ProtoOneOf.match( - None, dedent( """oneof one_of_field { ; @@ -483,15 +419,13 @@ def test_oneof_empty_statements(self): self.assertEqual( parsed_oneof_empty.node, ProtoOneOf( - None, - ProtoIdentifier(None, "one_of_field"), + ProtoIdentifier("one_of_field"), [], ), ) def test_oneof_basic_fields(self): parsed_oneof_basic_fields = ProtoOneOf.match( - None, dedent( """oneof one_of_field { string name = 4; @@ -502,23 +436,20 @@ def test_oneof_basic_fields(self): self.assertEqual( parsed_oneof_basic_fields.node, ProtoOneOf( - None, - ProtoIdentifier(None, "one_of_field"), + ProtoIdentifier("one_of_field"), [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "name"), - ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "sub_message"), - ProtoInt(None, 9, ProtoIntSign.POSITIVE), + ProtoIdentifier("sub_message"), + ProtoInt(9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier(None, "SubMessage"), + ProtoFullIdentifier("SubMessage"), [], ), ], @@ -527,7 +458,6 @@ def test_oneof_basic_fields(self): def test_oneof_options(self): parsed_oneof_options = ProtoOneOf.match( - None, dedent( """oneof one_of_field { option java_package = "com.example.foo"; @@ -537,15 +467,11 @@ def test_oneof_options(self): self.assertEqual( parsed_oneof_options.node, ProtoOneOf( - None, - ProtoIdentifier(None, "one_of_field"), + ProtoIdentifier("one_of_field"), [ ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant( - None, ProtoStringLiteral(None, "com.example.foo") - ), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), ), ], ), @@ -553,7 +479,6 @@ def test_oneof_options(self): def test_oneof_field_option(self): parsed_oneof_field_option = ProtoOneOf.match( - None, dedent( """oneof one_of_field { string name = 4 [ (bar.baz).bat = "bat", baz.bat = -100 ]; @@ -563,29 +488,23 @@ def test_oneof_field_option(self): self.assertEqual( parsed_oneof_field_option.node, ProtoOneOf( - None, - ProtoIdentifier(None, "one_of_field"), + ProtoIdentifier("one_of_field"), [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "name"), - ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), False, False, None, [ ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "(bar.baz).bat"), - ProtoConstant(None, ProtoStringLiteral(None, "bat")), + ProtoIdentifier("(bar.baz).bat"), + ProtoConstant(ProtoStringLiteral("bat")), ), ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "baz.bat"), - ProtoConstant( - None, ProtoInt(None, 100, ProtoIntSign.NEGATIVE) - ), + ProtoIdentifier("baz.bat"), + ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), ), ], ) @@ -595,7 +514,6 @@ def test_oneof_field_option(self): def test_oneof_with_comment(self): parsed_oneof_with_comment = ProtoOneOf.match( - None, dedent( """oneof one_of_field { string name = 4; @@ -607,24 +525,21 @@ def test_oneof_with_comment(self): self.assertEqual( parsed_oneof_with_comment.node, ProtoOneOf( - None, - ProtoIdentifier(None, "one_of_field"), + ProtoIdentifier("one_of_field"), [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "name"), - ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), ), - ProtoSingleLineComment(None, " single-line comment!"), + ProtoSingleLineComment(" single-line comment!"), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "sub_message"), - ProtoInt(None, 9, ProtoIntSign.POSITIVE), + ProtoIdentifier("sub_message"), + ProtoInt(9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier(None, "SubMessage"), + ProtoFullIdentifier("SubMessage"), [], ), ], @@ -633,7 +548,6 @@ def test_oneof_with_comment(self): def test_oneof_normalize_removes_comment(self): normalized_oneof = ProtoOneOf.match( - None, dedent( """oneof one_of_field { string name = 4; @@ -646,103 +560,89 @@ def test_oneof_normalize_removes_comment(self): normalized_oneof.nodes, [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "name"), - ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "sub_message"), - ProtoInt(None, 9, ProtoIntSign.POSITIVE), + ProtoIdentifier("sub_message"), + ProtoInt(9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier(None, "SubMessage"), + ProtoFullIdentifier("SubMessage"), [], ), ], ) def test_simple_map(self): - parsed_map_simple = ProtoMap.match( - None, "map my_map = 10;" - ) + parsed_map_simple = ProtoMap.match("map my_map = 10;") self.assertEqual( parsed_map_simple.node, ProtoMap( - None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "my_map"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + ProtoIdentifier("my_map"), + ProtoInt(10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier("NestedMessage"), [], ), ) def test_map_without_spaces(self): - map_without_spaces = ProtoMap.match( - None, "map my_map = 10;" - ) + map_without_spaces = ProtoMap.match("map my_map = 10;") self.assertEqual( map_without_spaces.node, ProtoMap( - None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "my_map"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + ProtoIdentifier("my_map"), + ProtoInt(10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier("NestedMessage"), [], ), ) def test_map_with_options(self): parsed_map_simple = ProtoMap.match( - None, "map my_map = 10 [ java_package = 'com.example.foo', baz.bat = 48 ];", ) self.assertEqual(parsed_map_simple.node.key_type, ProtoMapKeyTypesEnum.SFIXED64) self.assertEqual( parsed_map_simple.node.value_type, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE ) - self.assertEqual(parsed_map_simple.node.name, ProtoIdentifier(None, "my_map")) + self.assertEqual(parsed_map_simple.node.name, ProtoIdentifier("my_map")) self.assertEqual( - parsed_map_simple.node.number, ProtoInt(None, 10, ProtoIntSign.POSITIVE) + parsed_map_simple.node.number, ProtoInt(10, ProtoIntSign.POSITIVE) ) self.assertEqual( parsed_map_simple.node.enum_or_message_type_name, - ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + ProtoEnumOrMessageIdentifier("NestedMessage"), ) self.assertEqual( parsed_map_simple.node.options, [ ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "com.example.foo")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), ), ProtoMessageFieldOption( - None, - ProtoFullIdentifier(None, "baz.bat"), - ProtoConstant(None, ProtoInt(None, 48, ProtoIntSign.POSITIVE)), + ProtoFullIdentifier("baz.bat"), + ProtoConstant(ProtoInt(48, ProtoIntSign.POSITIVE)), ), ], ) def test_map_message_value(self): - parsed_map_simple = ProtoMap.match( - None, "map string_map = 11;" - ) + parsed_map_simple = ProtoMap.match("map string_map = 11;") self.assertEqual( parsed_map_simple.node, ProtoMap( - None, ProtoMapKeyTypesEnum.STRING, ProtoMapValueTypesEnum.STRING, - ProtoIdentifier(None, "string_map"), - ProtoInt(None, 11, ProtoIntSign.POSITIVE), + ProtoIdentifier("string_map"), + ProtoInt(11, ProtoIntSign.POSITIVE), None, [], ), @@ -750,7 +650,6 @@ def test_map_message_value(self): def test_message_parses_comments(self): parsed_comments = ProtoMessage.match( - None, dedent( """ message MyMessage { @@ -771,34 +670,29 @@ def test_message_parses_comments(self): parsed_comments.node.nodes, [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), - ProtoSingleLineComment(None, " single-line comment!"), + ProtoSingleLineComment(" single-line comment!"), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.BOOL, - ProtoIdentifier(None, "bar"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ProtoMultiLineComment( - None, "\n multiple\n line\n comment!\n ", ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "baz"), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoIdentifier("baz"), + ProtoInt(3, ProtoIntSign.POSITIVE), ), ], ) def test_message_extends(self): parsed_extends = ProtoMessage.match( - None, dedent( """ message MyMessage { @@ -814,20 +708,17 @@ def test_message_extends(self): parsed_extends.node.nodes, [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoExtend( - None, - ProtoEnumOrMessageIdentifier(None, "SomeOtherMessage"), + ProtoEnumOrMessageIdentifier("SomeOtherMessage"), [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(2, ProtoIntSign.POSITIVE), ) ], ), @@ -836,7 +727,6 @@ def test_message_extends(self): def test_message_normalizes_away_comments(self): parsed_comments = ProtoMessage.match( - None, dedent( """ message MyMessage { @@ -857,73 +747,62 @@ def test_message_normalizes_away_comments(self): parsed_comments.nodes, [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "foo"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("foo"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.BOOL, - ProtoIdentifier(None, "bar"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("bar"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "baz"), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoIdentifier("baz"), + ProtoInt(3, ProtoIntSign.POSITIVE), ), ], ) def test_diff_same_message_returns_empty(self): pm1 = ProtoMessage( - None, - ProtoIdentifier(None, "MyMessage"), + ProtoIdentifier("MyMessage"), [], ) pm2 = ProtoMessage( - None, - ProtoIdentifier(None, "MyMessage"), + ProtoIdentifier("MyMessage"), [], ) self.assertEqual(ProtoMessage.diff(pm1, pm2), []) def test_diff_different_message_name_returns_empty(self): pm1 = ProtoMessage( - None, - ProtoIdentifier(None, "MyMessage"), + ProtoIdentifier("MyMessage"), [], ) pm2 = ProtoMessage( - None, - ProtoIdentifier(None, "OtherMessage"), + ProtoIdentifier("OtherMessage"), [], ) self.assertEqual(ProtoMessage.diff(pm1, pm2), []) def test_diff_enum_added(self): pm1 = None - pm2 = ProtoMessage(None, ProtoIdentifier(None, "MyMessage"), []) + pm2 = ProtoMessage(ProtoIdentifier("MyMessage"), []) self.assertEqual( ProtoMessage.diff(pm1, pm2), [ - ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "MyMessage"), []) - ), + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("MyMessage"), [])), ], ) def test_diff_message_removed(self): - pm1 = ProtoMessage(None, ProtoIdentifier(None, "MyMessage"), []) + pm1 = ProtoMessage(ProtoIdentifier("MyMessage"), []) pm2 = None self.assertEqual( ProtoMessage.diff(pm1, pm2), [ - ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "MyMessage"), []) - ), + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("MyMessage"), [])), ], ) @@ -934,36 +813,30 @@ def test_diff_sets_empty_returns_empty(self): def test_diff_sets_no_change_returns_empty(self): set1 = [ - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), ] self.assertEqual(ProtoMessage.diff_sets(set1, set1), []) def test_diff_sets_all_removed(self): set1 = [ - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), ] set2 = [] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( - ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) - ), + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff, ) self.assertIn( - ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []) - ), + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BarMessage"), [])), diff, ) self.assertIn( - ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) - ), + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff, ) self.assertEqual(3, len(diff)) @@ -971,78 +844,60 @@ def test_diff_sets_all_removed(self): def test_diff_sets_all_added(self): set1 = [] set2 = [ - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), ] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( - ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) - ), + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff, ) self.assertIn( - ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []) - ), + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BarMessage"), [])), diff, ) self.assertIn( - ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) - ), + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff, ) self.assertEqual(3, len(diff)) def test_diff_sets_mutually_exclusive(self): set1 = [ - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), ] set2 = [ - ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []), - ProtoMessage(None, ProtoIdentifier(None, "BarMessage2"), []), - ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []), + ProtoMessage(ProtoIdentifier("FooMessage2"), []), + ProtoMessage(ProtoIdentifier("BarMessage2"), []), + ProtoMessage(ProtoIdentifier("BazMessage2"), []), ] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( - ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []) - ), + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage2"), [])), diff, ) self.assertIn( - ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "BarMessage2"), []) - ), + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BarMessage2"), [])), diff, ) self.assertIn( - ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []) - ), + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage2"), [])), diff, ) self.assertIn( - ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) - ), + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff, ) self.assertIn( - ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []) - ), + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BarMessage"), [])), diff, ) self.assertIn( - ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) - ), + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff, ) self.assertEqual(6, len(diff)) @@ -1050,38 +905,30 @@ def test_diff_sets_mutually_exclusive(self): def test_diff_sets_overlap(self): set1 = [ - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []), + ProtoMessage(ProtoIdentifier("FooMessage"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage"), []), ] set2 = [ - ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []), - ProtoMessage(None, ProtoIdentifier(None, "BarMessage"), []), - ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []), + ProtoMessage(ProtoIdentifier("FooMessage2"), []), + ProtoMessage(ProtoIdentifier("BarMessage"), []), + ProtoMessage(ProtoIdentifier("BazMessage2"), []), ] diff = ProtoMessage.diff_sets(set1, set2) self.assertIn( - ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage2"), []) - ), + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage2"), [])), diff, ) self.assertIn( - ProtoMessageAdded( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage2"), []) - ), + ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage2"), [])), diff, ) self.assertIn( - ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "FooMessage"), []) - ), + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage"), [])), diff, ) self.assertIn( - ProtoMessageRemoved( - ProtoMessage(None, ProtoIdentifier(None, "BazMessage"), []) - ), + ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage"), [])), diff, ) self.assertEqual(4, len(diff)) diff --git a/test/proto_option_test.py b/test/proto_option_test.py index b4f52fc..b6a90a2 100644 --- a/test/proto_option_test.py +++ b/test/proto_option_test.py @@ -19,245 +19,231 @@ class OptionTest(unittest.TestCase): maxDiff = None def test_string_option(self): - string_option = ProtoOption.match(None, "option foo = 'test value';") - self.assertEqual(string_option.node.name, ProtoIdentifier(None, "foo")) + string_option = ProtoOption.match("option foo = 'test value';") + self.assertEqual(string_option.node.name, ProtoIdentifier("foo")) self.assertEqual( - string_option.node.value.value, ProtoStringLiteral(None, "test value") + string_option.node.value.value, ProtoStringLiteral("test value") ) self.assertEqual(string_option.remaining_source, "") - string_option = ProtoOption.match(None, 'option foo = "test value";') - self.assertEqual(string_option.node.name, ProtoIdentifier(None, "foo")) + string_option = ProtoOption.match('option foo = "test value";') + self.assertEqual(string_option.node.name, ProtoIdentifier("foo")) self.assertEqual( - string_option.node.value.value, ProtoStringLiteral(None, "test value") + string_option.node.value.value, ProtoStringLiteral("test value") ) self.assertEqual(string_option.remaining_source, "") def test_packaged_name(self): - packaged_option = ProtoOption.match(None, "option foo.bar.baz = 'test value';") + packaged_option = ProtoOption.match("option foo.bar.baz = 'test value';") + self.assertEqual(packaged_option.node.name, ProtoFullIdentifier("foo.bar.baz")) self.assertEqual( - packaged_option.node.name, ProtoFullIdentifier(None, "foo.bar.baz") - ) - self.assertEqual( - packaged_option.node.value.value, ProtoStringLiteral(None, "test value") + packaged_option.node.value.value, ProtoStringLiteral("test value") ) def test_parenthesized_name(self): - parenthesized_option = ProtoOption.match(None, "option (foo) = 'test value';") - self.assertEqual(parenthesized_option.node.name, ProtoIdentifier(None, "(foo)")) + parenthesized_option = ProtoOption.match("option (foo) = 'test value';") + self.assertEqual(parenthesized_option.node.name, ProtoIdentifier("(foo)")) self.assertEqual( parenthesized_option.node.value.value, - ProtoStringLiteral(None, "test value"), + ProtoStringLiteral("test value"), ) fully_qualified_name_option = ProtoOption.match( - None, "option (foo).bar.baz = 'test value';" + "option (foo).bar.baz = 'test value';" ) self.assertEqual( fully_qualified_name_option.node.name, - ProtoFullIdentifier(None, "(foo).bar.baz"), + ProtoFullIdentifier("(foo).bar.baz"), ) self.assertEqual( fully_qualified_name_option.node.value.value, - ProtoStringLiteral(None, "test value"), + ProtoStringLiteral("test value"), ) def test_string_option_missing_semicolon(self): with self.assertRaises(ValueError): - ProtoOption.match(None, "option foo = 'test value'") + ProtoOption.match("option foo = 'test value'") with self.assertRaises(ValueError): - ProtoOption.match(None, 'option foo = "test value"') + ProtoOption.match('option foo = "test value"') def test_string_option_missing_quote(self): with self.assertRaises(ValueError): - ProtoOption.match(None, "option foo = test value;") + ProtoOption.match("option foo = test value;") with self.assertRaises(ValueError): - ProtoOption.match(None, "option foo = 'test value;") + ProtoOption.match("option foo = 'test value;") with self.assertRaises(ValueError): - ProtoOption.match(None, 'option foo = "test value;') + ProtoOption.match('option foo = "test value;') with self.assertRaises(ValueError): - ProtoOption.match(None, "option foo = test value';") + ProtoOption.match("option foo = test value';") with self.assertRaises(ValueError): - ProtoOption.match(None, 'option foo = test value";') + ProtoOption.match('option foo = test value";') with self.assertRaises(ValueError): - ProtoOption.match(None, "option foo = 'test value\";") + ProtoOption.match("option foo = 'test value\";") with self.assertRaises(ValueError): - ProtoOption.match(None, "option foo = \"test value';") + ProtoOption.match("option foo = \"test value';") def test_identifier_option(self): - identifier_option = ProtoOption.match(None, "option foo = test_identifier;") - self.assertEqual(identifier_option.node.name, ProtoIdentifier(None, "foo")) + identifier_option = ProtoOption.match("option foo = test_identifier;") + self.assertEqual(identifier_option.node.name, ProtoIdentifier("foo")) self.assertEqual( identifier_option.node.value, - ProtoConstant(None, ProtoIdentifier(None, "test_identifier")), + ProtoConstant(ProtoIdentifier("test_identifier")), ) self.assertEqual(identifier_option.remaining_source, "") - identifier_option = ProtoOption.match(None, "option bar = foo.bar.baz;") - self.assertEqual(identifier_option.node.name, ProtoIdentifier(None, "bar")) + identifier_option = ProtoOption.match("option bar = foo.bar.baz;") + self.assertEqual(identifier_option.node.name, ProtoIdentifier("bar")) self.assertEqual( identifier_option.node.value, - ProtoConstant(None, ProtoFullIdentifier(None, "foo.bar.baz")), + ProtoConstant(ProtoFullIdentifier("foo.bar.baz")), ) self.assertEqual(identifier_option.remaining_source, "") def test_int_option(self): - int_option = ProtoOption.match(None, "option foo = 0;") - self.assertEqual(int_option.node.name, ProtoIdentifier(None, "foo")) + int_option = ProtoOption.match("option foo = 0;") + self.assertEqual(int_option.node.name, ProtoIdentifier("foo")) self.assertEqual( int_option.node.value, - ProtoConstant(None, ProtoInt(None, 0, ProtoIntSign.POSITIVE)), + ProtoConstant(ProtoInt(0, ProtoIntSign.POSITIVE)), ) self.assertEqual(int_option.remaining_source, "") - int_option = ProtoOption.match(None, "option foo = 12345;") - self.assertEqual(int_option.node.name, ProtoIdentifier(None, "foo")) + int_option = ProtoOption.match("option foo = 12345;") + self.assertEqual(int_option.node.name, ProtoIdentifier("foo")) self.assertEqual( int_option.node.value, - ProtoConstant(None, ProtoInt(None, 12345, ProtoIntSign.POSITIVE)), + ProtoConstant(ProtoInt(12345, ProtoIntSign.POSITIVE)), ) self.assertEqual(int_option.remaining_source, "") - int_option = ProtoOption.match(None, "option foo = +42;") - self.assertEqual(int_option.node.name, ProtoIdentifier(None, "foo")) + int_option = ProtoOption.match("option foo = +42;") + self.assertEqual(int_option.node.name, ProtoIdentifier("foo")) self.assertEqual( int_option.node.value, - ProtoConstant(None, ProtoInt(None, 42, ProtoIntSign.POSITIVE)), + ProtoConstant(ProtoInt(42, ProtoIntSign.POSITIVE)), ) self.assertEqual(int_option.remaining_source, "") - int_option = ProtoOption.match(None, "option foo = -12;") - self.assertEqual(int_option.node.name, ProtoIdentifier(None, "foo")) + int_option = ProtoOption.match("option foo = -12;") + self.assertEqual(int_option.node.name, ProtoIdentifier("foo")) self.assertEqual( int_option.node.value, - ProtoConstant(None, ProtoInt(None, 12, ProtoIntSign.NEGATIVE)), + ProtoConstant(ProtoInt(12, ProtoIntSign.NEGATIVE)), ) self.assertEqual(int_option.remaining_source, "") def test_float_option(self): - float_option = ProtoOption.match(None, "option foo = inf;") + float_option = ProtoOption.match("option foo = inf;") self.assertEqual( float_option.node.value, - ProtoConstant( - None, ProtoFloat(None, float("inf"), ProtoFloatSign.POSITIVE) - ), + ProtoConstant(ProtoFloat(float("inf"), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match(None, "option foo = nan;") + float_option = ProtoOption.match("option foo = nan;") self.assertEqual( float_option.node.value, - ProtoConstant( - None, ProtoFloat(None, float("nan"), ProtoFloatSign.POSITIVE) - ), + ProtoConstant(ProtoFloat(float("nan"), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match(None, "option foo = 12.1;") + float_option = ProtoOption.match("option foo = 12.1;") self.assertEqual( float_option.node.value, - ProtoConstant(None, ProtoFloat(None, float(12.1), ProtoFloatSign.POSITIVE)), + ProtoConstant(ProtoFloat(float(12.1), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match(None, "option foo = .1;") + float_option = ProtoOption.match("option foo = .1;") self.assertEqual( float_option.node.value, - ProtoConstant(None, ProtoFloat(None, float(0.1), ProtoFloatSign.POSITIVE)), + ProtoConstant(ProtoFloat(float(0.1), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match(None, "option foo = .1e3;") + float_option = ProtoOption.match("option foo = .1e3;") self.assertEqual( float_option.node.value, - ProtoConstant(None, ProtoFloat(None, float(100), ProtoFloatSign.POSITIVE)), + ProtoConstant(ProtoFloat(float(100), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match(None, "option foo = +12.1;") + float_option = ProtoOption.match("option foo = +12.1;") self.assertEqual( float_option.node.value, - ProtoConstant(None, ProtoFloat(None, float(12.1), ProtoFloatSign.POSITIVE)), + ProtoConstant(ProtoFloat(float(12.1), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match(None, "option foo = +.1;") + float_option = ProtoOption.match("option foo = +.1;") self.assertEqual( float_option.node.value, - ProtoConstant(None, ProtoFloat(None, float(0.1), ProtoFloatSign.POSITIVE)), + ProtoConstant(ProtoFloat(float(0.1), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match(None, "option foo = +.1e2;") + float_option = ProtoOption.match("option foo = +.1e2;") self.assertEqual( float_option.node.value, - ProtoConstant(None, ProtoFloat(None, float(10), ProtoFloatSign.POSITIVE)), + ProtoConstant(ProtoFloat(float(10), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match(None, "option foo = +.1e-2;") + float_option = ProtoOption.match("option foo = +.1e-2;") self.assertEqual( float_option.node.value, - ProtoConstant( - None, ProtoFloat(None, float(0.001), ProtoFloatSign.POSITIVE) - ), + ProtoConstant(ProtoFloat(float(0.001), ProtoFloatSign.POSITIVE)), ) - float_option = ProtoOption.match(None, "option foo = -.1e0;") + float_option = ProtoOption.match("option foo = -.1e0;") self.assertEqual( float_option.node.value, - ProtoConstant(None, ProtoFloat(None, float(0.1), ProtoFloatSign.NEGATIVE)), + ProtoConstant(ProtoFloat(float(0.1), ProtoFloatSign.NEGATIVE)), ) - float_option = ProtoOption.match(None, "option foo = -12E+1;") + float_option = ProtoOption.match("option foo = -12E+1;") self.assertEqual( float_option.node.value, - ProtoConstant(None, ProtoFloat(None, float(120), ProtoFloatSign.NEGATIVE)), + ProtoConstant(ProtoFloat(float(120), ProtoFloatSign.NEGATIVE)), ) def test_diff_same_option_returns_empty(self): po1 = ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) po2 = ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) self.assertEqual(ProtoOption.diff(po1, po2), []) def test_diff_different_option_name_returns_empty(self): po1 = ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) po2 = ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) self.assertEqual(ProtoOption.diff(po1, po2), []) def test_diff_different_option_value_returns_option_diff(self): po1 = ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) po2 = ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "other value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("other value")), ) self.assertEqual( ProtoOption.diff(po1, po2), [ ProtoOptionValueChanged( - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), - ProtoConstant(None, ProtoStringLiteral(None, "other value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), + ProtoConstant(ProtoStringLiteral("other value")), ) ], ) @@ -265,18 +251,16 @@ def test_diff_different_option_value_returns_option_diff(self): def test_diff_option_added(self): po1 = None po2 = ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) self.assertEqual( ProtoOption.diff(po1, po2), [ ProtoOptionAdded( ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) ), ], @@ -284,9 +268,8 @@ def test_diff_option_added(self): def test_diff_option_removed(self): po1 = ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) po2 = None self.assertEqual( @@ -294,9 +277,8 @@ def test_diff_option_removed(self): [ ProtoOptionRemoved( ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) ), ], @@ -310,19 +292,16 @@ def test_diff_sets_empty_returns_empty(self): def test_diff_sets_no_change(self): set1 = [ ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ), ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ), ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ), ] self.assertEqual(ProtoOption.diff_sets(set1, set1), []) @@ -330,19 +309,16 @@ def test_diff_sets_no_change(self): def test_diff_sets_all_removed(self): set1 = [ ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ), ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ), ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ), ] set2 = [] @@ -351,9 +327,8 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) ), diff, @@ -361,9 +336,8 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ) ), diff, @@ -371,9 +345,8 @@ def test_diff_sets_all_removed(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -384,19 +357,16 @@ def test_diff_sets_all_added(self): set1 = [] set2 = [ ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ), ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ), ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ), ] diff = ProtoOption.diff_sets(set1, set2) @@ -404,9 +374,8 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoOptionAdded( ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) ), diff, @@ -414,9 +383,8 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoOptionAdded( ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ) ), diff, @@ -424,9 +392,8 @@ def test_diff_sets_all_added(self): self.assertIn( ProtoOptionAdded( ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -436,36 +403,30 @@ def test_diff_sets_all_added(self): def test_diff_sets_mutually_exclusive(self): set1 = [ ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ), ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ), ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ), ] set2 = [ ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option.but.not.prior"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option.but.not.prior"), + ProtoConstant(ProtoStringLiteral("some value")), ), ProtoOption( - None, - ProtoIdentifier(None, "ruby_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("ruby_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ), ProtoOption( - None, - ProtoIdentifier(None, "other.option.but.stil.not.prior"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option.but.stil.not.prior"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ), ] @@ -474,9 +435,8 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionAdded( ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option.but.not.prior"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option.but.not.prior"), + ProtoConstant(ProtoStringLiteral("some value")), ) ), diff, @@ -484,9 +444,8 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionAdded( ProtoOption( - None, - ProtoIdentifier(None, "other.option.but.stil.not.prior"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option.but.stil.not.prior"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -495,9 +454,8 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionAdded( ProtoOption( - None, - ProtoIdentifier(None, "ruby_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("ruby_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ) ), diff, @@ -506,9 +464,8 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -517,9 +474,8 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) ), diff, @@ -528,9 +484,8 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ) ), diff, @@ -541,36 +496,30 @@ def test_diff_sets_mutually_exclusive(self): def test_diff_sets_overlap(self): set1 = [ ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ), ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ), ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ), ] set2 = [ ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option.but.not.prior"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option.but.not.prior"), + ProtoConstant(ProtoStringLiteral("some value")), ), ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.bat")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.bat")), ), ProtoOption( - None, - ProtoIdentifier(None, "other.option.but.stil.not.prior"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option.but.stil.not.prior"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ), ] @@ -579,9 +528,8 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option"), + ProtoConstant(ProtoStringLiteral("some value")), ) ), diff, @@ -590,9 +538,8 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoOptionRemoved( ProtoOption( - None, - ProtoIdentifier(None, "other.option"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ) ), diff, @@ -600,9 +547,8 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoOptionAdded( ProtoOption( - None, - ProtoIdentifier(None, "some.custom.option.but.not.prior"), - ProtoConstant(None, ProtoStringLiteral(None, "some value")), + ProtoIdentifier("some.custom.option.but.not.prior"), + ProtoConstant(ProtoStringLiteral("some value")), ) ), diff, @@ -610,18 +556,17 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoOptionAdded( ProtoOption( - None, - ProtoIdentifier(None, "other.option.but.stil.not.prior"), - ProtoConstant(None, ProtoInt(None, 100, ProtoIntSign.POSITIVE)), + ProtoIdentifier("other.option.but.stil.not.prior"), + ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ) ), diff, ) self.assertIn( ProtoOptionValueChanged( - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.baz")), - ProtoConstant(None, ProtoStringLiteral(None, "foo.bar.bat")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("foo.bar.baz")), + ProtoConstant(ProtoStringLiteral("foo.bar.bat")), ), diff, ) diff --git a/test/proto_package_test.py b/test/proto_package_test.py index 611dd37..bf6bd7d 100644 --- a/test/proto_package_test.py +++ b/test/proto_package_test.py @@ -11,92 +11,90 @@ class PackageTest(unittest.TestCase): def test_correct_package(self): - self.assertEqual(ProtoPackage.match(None, "package foo;").node.package, "foo") + self.assertEqual(ProtoPackage.match("package foo;").node.package, "foo") + self.assertEqual(ProtoPackage.match("package foo.bar;").node.package, "foo.bar") self.assertEqual( - ProtoPackage.match(None, "package foo.bar;").node.package, "foo.bar" - ) - self.assertEqual( - ProtoPackage.match(None, "package foo.bar.baz;").node.package, "foo.bar.baz" + ProtoPackage.match("package foo.bar.baz;").node.package, "foo.bar.baz" ) def test_package_serialize(self): self.assertEqual( - ProtoPackage.match(None, "package foo;").node.serialize(), "package foo;" + ProtoPackage.match("package foo;").node.serialize(), "package foo;" ) self.assertEqual( - ProtoPackage.match(None, "package foo.bar;").node.serialize(), + ProtoPackage.match("package foo.bar;").node.serialize(), "package foo.bar;", ) self.assertEqual( - ProtoPackage.match(None, "package foo.bar.baz;").node.serialize(), + ProtoPackage.match("package foo.bar.baz;").node.serialize(), "package foo.bar.baz;", ) def test_package_malformed(self): with self.assertRaises(ValueError): - ProtoPackage.match(None, "package") + ProtoPackage.match("package") with self.assertRaises(ValueError): - ProtoPackage.match(None, "package;") + ProtoPackage.match("package;") with self.assertRaises(ValueError): - ProtoPackage.match(None, "package ") + ProtoPackage.match("package ") with self.assertRaises(ValueError): - ProtoPackage.match(None, "package ;") + ProtoPackage.match("package ;") with self.assertRaises(ValueError): - ProtoPackage.match(None, "packagefoo") + ProtoPackage.match("packagefoo") with self.assertRaises(ValueError): - ProtoPackage.match(None, "package foo.") + ProtoPackage.match("package foo.") with self.assertRaises(ValueError): - ProtoPackage.match(None, "packagefoo.") + ProtoPackage.match("packagefoo.") with self.assertRaises(ValueError): - ProtoPackage.match(None, "package foo.;") + ProtoPackage.match("package foo.;") with self.assertRaises(ValueError): - ProtoPackage.match(None, "package foo.bar") + ProtoPackage.match("package foo.bar") with self.assertRaises(ValueError): - ProtoPackage.match(None, "packagefoo.bar;") + ProtoPackage.match("packagefoo.bar;") def test_diff_same_package_returns_empty(self): - pp1 = ProtoPackage(None, "my.awesome.package") - pp2 = ProtoPackage(None, "my.awesome.package") + pp1 = ProtoPackage("my.awesome.package") + pp2 = ProtoPackage("my.awesome.package") self.assertEqual(ProtoPackage.diff(pp1, pp2), []) def test_diff_different_package_returns_package_diff(self): - pp1 = ProtoPackage(None, "my.awesome.package") - pp2 = ProtoPackage(None, "my.other.awesome.package") + pp1 = ProtoPackage("my.awesome.package") + pp2 = ProtoPackage("my.other.awesome.package") self.assertEqual( ProtoPackage.diff(pp1, pp2), [ ProtoPackageChanged( - ProtoPackage(None, "my.awesome.package"), - ProtoPackage(None, "my.other.awesome.package"), + ProtoPackage("my.awesome.package"), + ProtoPackage("my.other.awesome.package"), ) ], ) def test_diff_package_added(self): pp1 = None - pp2 = ProtoPackage(None, "my.new.package") + pp2 = ProtoPackage("my.new.package") self.assertEqual( [ - ProtoPackageAdded(ProtoPackage(None, "my.new.package")), + ProtoPackageAdded(ProtoPackage("my.new.package")), ], ProtoPackage.diff(pp1, pp2), ) def test_diff_package_removed(self): - pp1 = ProtoPackage(None, "my.old.package") + pp1 = ProtoPackage("my.old.package") pp2 = None self.assertEqual( [ - ProtoPackageRemoved(ProtoPackage(None, "my.old.package")), + ProtoPackageRemoved(ProtoPackage("my.old.package")), ], ProtoPackage.diff(pp1, pp2), ) diff --git a/test/proto_range_test.py b/test/proto_range_test.py index 24f90a5..ce78433 100644 --- a/test/proto_range_test.py +++ b/test/proto_range_test.py @@ -5,42 +5,38 @@ class RangeTest(unittest.TestCase): def test_range_single_int(self): - self.assertEqual(ProtoRange.match(None, "42").node.serialize(), "42") - self.assertEqual(ProtoRange.match(None, "-1").node.serialize(), "-1") + self.assertEqual(ProtoRange.match("42").node.serialize(), "42") + self.assertEqual(ProtoRange.match("-1").node.serialize(), "-1") def test_range_invalid_non_ints(self): - self.assertIsNone(ProtoRange.match(None, "42.5")) - self.assertIsNone(ProtoRange.match(None, "a")) - self.assertIsNone(ProtoRange.match(None, "-")) + self.assertIsNone(ProtoRange.match("42.5")) + self.assertIsNone(ProtoRange.match("a")) + self.assertIsNone(ProtoRange.match("-")) def test_range_int_range(self): - self.assertEqual(ProtoRange.match(None, "1 to 1").node.serialize(), "1 to 1") - self.assertEqual(ProtoRange.match(None, "1 to 7").node.serialize(), "1 to 7") - self.assertEqual( - ProtoRange.match(None, "-100 to -5").node.serialize(), "-100 to -5" - ) + self.assertEqual(ProtoRange.match("1 to 1").node.serialize(), "1 to 1") + self.assertEqual(ProtoRange.match("1 to 7").node.serialize(), "1 to 7") + self.assertEqual(ProtoRange.match("-100 to -5").node.serialize(), "-100 to -5") def test_range_invalid_range(self): with self.assertRaises(ValueError): - ProtoRange.match(None, "8 to 2") + ProtoRange.match("8 to 2") with self.assertRaises(ValueError): - ProtoRange.match(None, "3 to 0") + ProtoRange.match("3 to 0") with self.assertRaises(ValueError): - ProtoRange.match(None, "1 to -1") + ProtoRange.match("1 to -1") def test_range_invalid_range_non_int(self): with self.assertRaises(ValueError): - ProtoRange.match(None, "1 to c") + ProtoRange.match("1 to c") with self.assertRaises(ValueError): - ProtoRange.match(None, "1 to -bc3") + ProtoRange.match("1 to -bc3") def test_range_max(self): - self.assertEqual( - ProtoRange.match(None, "7 to max").node.serialize(), "7 to max" - ) + self.assertEqual(ProtoRange.match("7 to max").node.serialize(), "7 to max") if __name__ == "__main__": diff --git a/test/proto_reserved_test.py b/test/proto_reserved_test.py index f7d1c8b..e83aca8 100644 --- a/test/proto_reserved_test.py +++ b/test/proto_reserved_test.py @@ -7,47 +7,47 @@ class ReservedTest(unittest.TestCase): def test_reserved_single_int(self): self.assertEqual( - ProtoReserved.match(None, "reserved 21;").node.serialize(), "reserved 21;" + ProtoReserved.match("reserved 21;").node.serialize(), "reserved 21;" ) self.assertEqual( - ProtoReserved.match(None, "reserved -1;").node.serialize(), "reserved -1;" + ProtoReserved.match("reserved -1;").node.serialize(), "reserved -1;" ) def test_reserved_multiple_ints(self): self.assertEqual( - ProtoReserved.match(None, "reserved 1, 5, 2, 42;").node.serialize(), + ProtoReserved.match("reserved 1, 5, 2, 42;").node.serialize(), "reserved 1, 5, 2, 42;", ) def test_reserved_range_max(self): self.assertEqual( - ProtoReserved.match(None, "reserved 8 to max;").node.serialize(), + ProtoReserved.match("reserved 8 to max;").node.serialize(), "reserved 8 to max;", ) def test_reserved_single_string_field(self): self.assertEqual( - ProtoReserved.match(None, "reserved 'foo';").node.serialize(), + ProtoReserved.match("reserved 'foo';").node.serialize(), "reserved 'foo';", ) self.assertEqual( - ProtoReserved.match(None, 'reserved "foo";').node.serialize(), + ProtoReserved.match('reserved "foo";').node.serialize(), 'reserved "foo";', ) def test_reserved_multiple_string_fields(self): self.assertEqual( - ProtoReserved.match(None, "reserved 'foo', 'bar';").node.serialize(), + ProtoReserved.match("reserved 'foo', 'bar';").node.serialize(), "reserved 'foo', 'bar';", ) self.assertEqual( - ProtoReserved.match(None, 'reserved "foo", "bar", "baz";').node.serialize(), + ProtoReserved.match('reserved "foo", "bar", "baz";').node.serialize(), 'reserved "foo", "bar", "baz";', ) def test_reserved_cannot_have_ints_and_strings(self): with self.assertRaises(ValueError): - ProtoReserved.match(None, "reserved 1, 'foo';") + ProtoReserved.match("reserved 1, 'foo';") if __name__ == "__main__": diff --git a/test/proto_service_test.py b/test/proto_service_test.py index b99a242..0b5a4fb 100644 --- a/test/proto_service_test.py +++ b/test/proto_service_test.py @@ -20,7 +20,6 @@ class ServiceTest(unittest.TestCase): def test_service_all_features(self): test_service_all_features = ProtoService.match( - None, dedent( """ service FooService { @@ -41,52 +40,42 @@ def test_service_all_features(self): self.assertEqual( test_service_all_features.node, ProtoService( - None, - ProtoIdentifier(None, "FooService"), + ProtoIdentifier("FooService"), [ ProtoOption( - None, - ProtoIdentifier(None, "(foo.bar).baz"), - ProtoConstant(None, ProtoStringLiteral(None, "bat")), + ProtoIdentifier("(foo.bar).baz"), + ProtoConstant(ProtoStringLiteral("bat")), ), - ProtoSingleLineComment(None, " single-line comment!"), + ProtoSingleLineComment(" single-line comment!"), ProtoServiceRPC( - None, - ProtoIdentifier(None, "OneRPC"), - ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), + ProtoIdentifier("OneRPC"), + ProtoEnumOrMessageIdentifier("OneRPCRequest"), + ProtoEnumOrMessageIdentifier("OneRPCResponse"), ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "TwoRPC"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), + ProtoIdentifier("TwoRPC"), + ProtoEnumOrMessageIdentifier("TwoRPCRequest"), + ProtoEnumOrMessageIdentifier("TwoRPCResponse"), False, True, ), ProtoMultiLineComment( - None, "\n multiple\n line\n comment\n ", ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "ThreeRPC"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), + ProtoIdentifier("ThreeRPC"), + ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), False, False, [ ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant( - None, ProtoStringLiteral(None, "com.example.foo") - ), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), ), ProtoOption( - None, - ProtoFullIdentifier(None, "(foo.bar).baz"), - ProtoConstant(None, ProtoBool(None, False)), + ProtoFullIdentifier("(foo.bar).baz"), + ProtoConstant(ProtoBool(False)), ), ], ), @@ -114,14 +103,11 @@ def test_service_all_features(self): ) def test_service_empty(self): - parsed_empty_service = ProtoService.match(None, """service FooService {}""") + parsed_empty_service = ProtoService.match("""service FooService {}""") self.assertIsNotNone(parsed_empty_service) - self.assertEqual( - parsed_empty_service.node.name, ProtoIdentifier(None, "FooService") - ) + self.assertEqual(parsed_empty_service.node.name, ProtoIdentifier("FooService")) parsed_spaced_service = ProtoService.match( - None, dedent( """ service FooService { @@ -133,12 +119,11 @@ def test_service_empty(self): self.assertIsNotNone(parsed_spaced_service) self.assertEqual( parsed_spaced_service.node, - ProtoService(None, ProtoIdentifier(None, "FooService"), []), + ProtoService(ProtoIdentifier("FooService"), []), ) def test_service_empty_statements(self): empty_statement_service = ProtoService.match( - None, dedent( """ service FooService { @@ -151,12 +136,11 @@ def test_service_empty_statements(self): self.assertIsNotNone(empty_statement_service) self.assertEqual( empty_statement_service.node, - ProtoService(None, ProtoIdentifier(None, "FooService"), []), + ProtoService(ProtoIdentifier("FooService"), []), ) def test_service_option(self): service_with_options = ProtoService.match( - None, dedent( """ service FooService { @@ -169,16 +153,14 @@ def test_service_option(self): service_with_options.node.nodes, [ ProtoOption( - None, - ProtoIdentifier(None, "(foo.bar).baz"), - ProtoConstant(None, ProtoStringLiteral(None, "bat")), + ProtoIdentifier("(foo.bar).baz"), + ProtoConstant(ProtoStringLiteral("bat")), ) ], ) def test_service_rpc_basic(self): service_with_options = ProtoService.match( - None, dedent( """ service FooService { @@ -193,29 +175,25 @@ def test_service_rpc_basic(self): service_with_options.node.nodes, [ ProtoServiceRPC( - None, - ProtoIdentifier(None, "OneRPC"), - ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), + ProtoIdentifier("OneRPC"), + ProtoEnumOrMessageIdentifier("OneRPCRequest"), + ProtoEnumOrMessageIdentifier("OneRPCResponse"), ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "TwoRPC"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), + ProtoIdentifier("TwoRPC"), + ProtoEnumOrMessageIdentifier("TwoRPCRequest"), + ProtoEnumOrMessageIdentifier("TwoRPCResponse"), ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "ThreeRPC"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), + ProtoIdentifier("ThreeRPC"), + ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), ), ], ) def test_service_rpc_stream(self): service_with_options = ProtoService.match( - None, dedent( """ service FooService { @@ -229,18 +207,16 @@ def test_service_rpc_stream(self): service_with_options.node.nodes, [ ProtoServiceRPC( - None, - ProtoIdentifier(None, "OneRPC"), - ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), + ProtoIdentifier("OneRPC"), + ProtoEnumOrMessageIdentifier("OneRPCRequest"), + ProtoEnumOrMessageIdentifier("OneRPCResponse"), True, False, ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "TwoRPC"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), + ProtoIdentifier("TwoRPC"), + ProtoEnumOrMessageIdentifier("TwoRPCRequest"), + ProtoEnumOrMessageIdentifier("TwoRPCResponse"), False, True, ), @@ -249,7 +225,6 @@ def test_service_rpc_stream(self): def test_service_rpc_options(self): service_with_options = ProtoService.match( - None, dedent( """ service FooService { @@ -263,30 +238,24 @@ def test_service_rpc_options(self): service_with_options.node.nodes, [ ProtoServiceRPC( - None, - ProtoIdentifier(None, "OneRPC"), - ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), + ProtoIdentifier("OneRPC"), + ProtoEnumOrMessageIdentifier("OneRPCRequest"), + ProtoEnumOrMessageIdentifier("OneRPCResponse"), ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "TwoRPC"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), + ProtoIdentifier("TwoRPC"), + ProtoEnumOrMessageIdentifier("TwoRPCRequest"), + ProtoEnumOrMessageIdentifier("TwoRPCResponse"), False, False, [ ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant( - None, ProtoStringLiteral(None, "com.example.foo") - ), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), ), ProtoOption( - None, - ProtoFullIdentifier(None, "(foo.bar).baz"), - ProtoConstant(None, ProtoBool(None, False)), + ProtoFullIdentifier("(foo.bar).baz"), + ProtoConstant(ProtoBool(False)), ), ], ), @@ -295,7 +264,6 @@ def test_service_rpc_options(self): def test_service_parses_comments(self): service_with_comments = ProtoService.match( - None, dedent( """ service FooService { @@ -316,34 +284,29 @@ def test_service_parses_comments(self): service_with_comments.node.nodes, [ ProtoServiceRPC( - None, - ProtoIdentifier(None, "OneRPC"), - ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), + ProtoIdentifier("OneRPC"), + ProtoEnumOrMessageIdentifier("OneRPCRequest"), + ProtoEnumOrMessageIdentifier("OneRPCResponse"), ), - ProtoSingleLineComment(None, " single-line comment!"), + ProtoSingleLineComment(" single-line comment!"), ProtoServiceRPC( - None, - ProtoIdentifier(None, "TwoRPC"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), + ProtoIdentifier("TwoRPC"), + ProtoEnumOrMessageIdentifier("TwoRPCRequest"), + ProtoEnumOrMessageIdentifier("TwoRPCResponse"), ), ProtoMultiLineComment( - None, "\n multiple\n line\n comment\n ", ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "ThreeRPC"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), + ProtoIdentifier("ThreeRPC"), + ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), ), ], ) def test_service_normalize_removes_comments(self): normalized_service = ProtoService.match( - None, dedent( """ service FooService { @@ -364,22 +327,19 @@ def test_service_normalize_removes_comments(self): normalized_service.nodes, [ ProtoServiceRPC( - None, - ProtoIdentifier(None, "OneRPC"), - ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), + ProtoIdentifier("OneRPC"), + ProtoEnumOrMessageIdentifier("OneRPCRequest"), + ProtoEnumOrMessageIdentifier("OneRPCResponse"), ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "ThreeRPC"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), + ProtoIdentifier("ThreeRPC"), + ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "TwoRPC"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), + ProtoIdentifier("TwoRPC"), + ProtoEnumOrMessageIdentifier("TwoRPCRequest"), + ProtoEnumOrMessageIdentifier("TwoRPCResponse"), ), ], ) diff --git a/test/proto_string_literal_test.py b/test/proto_string_literal_test.py index b3bb303..73ad4dc 100644 --- a/test/proto_string_literal_test.py +++ b/test/proto_string_literal_test.py @@ -5,33 +5,33 @@ class StringLiteralTest(unittest.TestCase): def test_correct_syntax(self): - parsed_single_quote = ProtoStringLiteral.match(None, """'foo'""") + parsed_single_quote = ProtoStringLiteral.match("""'foo'""") self.assertEqual(parsed_single_quote.node.value, "foo") self.assertEqual(parsed_single_quote.remaining_source, "") self.assertEqual(parsed_single_quote.node.serialize(), "'foo'") - parsed_double_quote = ProtoStringLiteral.match(None, """\"foo\"""") + parsed_double_quote = ProtoStringLiteral.match("""\"foo\"""") self.assertEqual(parsed_double_quote.node.value, "foo") self.assertEqual(parsed_double_quote.remaining_source, "") self.assertEqual(parsed_double_quote.node.serialize(), '"foo"') def test_remaining_source(self): - parsed_single_quote = ProtoStringLiteral.match(None, """'foo'\nbar baz""") + parsed_single_quote = ProtoStringLiteral.match("""'foo'\nbar baz""") self.assertEqual(parsed_single_quote.remaining_source, "bar baz") - parsed_double_quote = ProtoStringLiteral.match(None, """\"foo\"\"foobar\"""") + parsed_double_quote = ProtoStringLiteral.match("""\"foo\"\"foobar\"""") self.assertEqual(parsed_double_quote.remaining_source, '"foobar"') def test_missing_quote(self): - self.assertIsNone(ProtoStringLiteral.match(None, """'foo""")) - self.assertIsNone(ProtoStringLiteral.match(None, """foo'""")) - self.assertIsNone(ProtoStringLiteral.match(None, """\"foo""")) - self.assertIsNone(ProtoStringLiteral.match(None, """foo\"""")) - self.assertIsNone(ProtoStringLiteral.match(None, """'foo\"""")) - self.assertIsNone(ProtoStringLiteral.match(None, """\"foo'""")) + self.assertIsNone(ProtoStringLiteral.match("""'foo""")) + self.assertIsNone(ProtoStringLiteral.match("""foo'""")) + self.assertIsNone(ProtoStringLiteral.match("""\"foo""")) + self.assertIsNone(ProtoStringLiteral.match("""foo\"""")) + self.assertIsNone(ProtoStringLiteral.match("""'foo\"""")) + self.assertIsNone(ProtoStringLiteral.match("""\"foo'""")) def test_escaped_quote(self): - self.assertIsNone(ProtoStringLiteral.match(None, """'foo\\'""")) - self.assertIsNone(ProtoStringLiteral.match(None, """\"foo\\\"""")) - parsed_escaped_quote = ProtoStringLiteral.match(None, """\"foo\\\"barbaz\"""") + self.assertIsNone(ProtoStringLiteral.match("""'foo\\'""")) + self.assertIsNone(ProtoStringLiteral.match("""\"foo\\\"""")) + parsed_escaped_quote = ProtoStringLiteral.match("""\"foo\\\"barbaz\"""") self.assertEqual(parsed_escaped_quote.node.value, 'foo\\"barbaz') self.assertEqual(parsed_escaped_quote.remaining_source, "") self.assertEqual(parsed_escaped_quote.node.serialize(), '"foo\\"barbaz"') diff --git a/test/proto_syntax_test.py b/test/proto_syntax_test.py index d0e4a3f..6abfda1 100644 --- a/test/proto_syntax_test.py +++ b/test/proto_syntax_test.py @@ -7,88 +7,88 @@ class SyntaxTest(unittest.TestCase): def test_correct_syntax(self): self.assertEqual( - ProtoSyntax.match(None, "syntax = 'proto3';").node.syntax.value, "proto3" + ProtoSyntax.match("syntax = 'proto3';").node.syntax.value, "proto3" ) self.assertEqual( - ProtoSyntax.match(None, 'syntax = "proto3";').node.syntax.value, "proto3" + ProtoSyntax.match('syntax = "proto3";').node.syntax.value, "proto3" ) self.assertEqual( - ProtoSyntax.match(None, "syntax = 'proto2';").node.syntax.value, "proto2" + ProtoSyntax.match("syntax = 'proto2';").node.syntax.value, "proto2" ) self.assertEqual( - ProtoSyntax.match(None, 'syntax = "proto2";').node.syntax.value, "proto2" + ProtoSyntax.match('syntax = "proto2";').node.syntax.value, "proto2" ) def test_serialize(self): self.assertEqual( - ProtoSyntax.match(None, "syntax = 'proto3';").node.serialize(), + ProtoSyntax.match("syntax = 'proto3';").node.serialize(), "syntax = 'proto3';", ) self.assertEqual( - ProtoSyntax.match(None, 'syntax = "proto3";').node.serialize(), + ProtoSyntax.match('syntax = "proto3";').node.serialize(), 'syntax = "proto3";', ) self.assertEqual( - ProtoSyntax.match(None, "syntax = 'proto2';").node.serialize(), + ProtoSyntax.match("syntax = 'proto2';").node.serialize(), "syntax = 'proto2';", ) self.assertEqual( - ProtoSyntax.match(None, 'syntax = "proto2";').node.serialize(), + ProtoSyntax.match('syntax = "proto2";').node.serialize(), 'syntax = "proto2";', ) def test_syntax_not_present(self): - self.assertIsNone(ProtoSyntax.match(None, "")) - self.assertIsNone(ProtoSyntax.match(None, 'import "foo.proto";')) + self.assertIsNone(ProtoSyntax.match("")) + self.assertIsNone(ProtoSyntax.match('import "foo.proto";')) def test_syntax_malformed(self): with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = 'proto3'") + ProtoSyntax.match("syntax = 'proto3'") with self.assertRaises(ValueError): - ProtoSyntax.match(None, 'syntax = "proto3"') + ProtoSyntax.match('syntax = "proto3"') with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = 'proto2'") + ProtoSyntax.match("syntax = 'proto2'") with self.assertRaises(ValueError): - ProtoSyntax.match(None, 'syntax = "proto2"') + ProtoSyntax.match('syntax = "proto2"') with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = proto3") + ProtoSyntax.match("syntax = proto3") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = proto3;") + ProtoSyntax.match("syntax = proto3;") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = 'proto3") + ProtoSyntax.match("syntax = 'proto3") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = 'proto3;") + ProtoSyntax.match("syntax = 'proto3;") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = proto3'") + ProtoSyntax.match("syntax = proto3'") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = proto3';") + ProtoSyntax.match("syntax = proto3';") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = 'proton';") + ProtoSyntax.match("syntax = 'proton';") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = 'proton'") + ProtoSyntax.match("syntax = 'proton'") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = 'proton") + ProtoSyntax.match("syntax = 'proton") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = proton';") + ProtoSyntax.match("syntax = proton';") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = proton'") + ProtoSyntax.match("syntax = proton'") with self.assertRaises(ValueError): - ProtoSyntax.match(None, "syntax = proton") + ProtoSyntax.match("syntax = proton") def test_diff_empty_same_syntax_returns_empty(self): - pf1 = ProtoSyntax(None, ProtoStringLiteral(None, "proto3")) - pf2 = ProtoSyntax(None, ProtoStringLiteral(None, "proto3")) + pf1 = ProtoSyntax(ProtoStringLiteral("proto3")) + pf2 = ProtoSyntax(ProtoStringLiteral("proto3")) self.assertEqual(ProtoSyntax.diff(pf1, pf2), []) def test_diff_empty_different_syntax_returns_syntax_diff(self): - pf1 = ProtoSyntax(None, ProtoStringLiteral(None, "proto3")) - pf2 = ProtoSyntax(None, ProtoStringLiteral(None, "proto2")) + pf1 = ProtoSyntax(ProtoStringLiteral("proto3")) + pf2 = ProtoSyntax(ProtoStringLiteral("proto2")) self.assertEqual( ProtoSyntax.diff(pf1, pf2), [ ProtoSyntaxChanged( - ProtoSyntax(None, ProtoStringLiteral(None, "proto3")), - ProtoSyntax(None, ProtoStringLiteral(None, "proto2")), + ProtoSyntax(ProtoStringLiteral("proto3")), + ProtoSyntax(ProtoStringLiteral("proto2")), ) ], ) diff --git a/test/util/parser_test.py b/test/util/parser_test.py index 08c9470..a610651 100644 --- a/test/util/parser_test.py +++ b/test/util/parser_test.py @@ -100,54 +100,45 @@ def test_parser(self): self.assertEqual( proto_file.imports, [ - ProtoImport(None, ProtoStringLiteral(None, "foo.proto"), public=True), - ProtoImport(None, ProtoStringLiteral(None, "bar/baz.proto"), weak=True), - ProtoImport(None, ProtoStringLiteral(None, "bat.proto")), + ProtoImport(ProtoStringLiteral("foo.proto"), public=True), + ProtoImport(ProtoStringLiteral("bar/baz.proto"), weak=True), + ProtoImport(ProtoStringLiteral("bat.proto")), ], ) self.assertEqual( proto_file.options, [ ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant(None, ProtoStringLiteral(None, "my.test.package")), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("my.test.package")), ), ProtoOption( - None, - ProtoIdentifier(None, "(fully.qualified).option"), - ProtoConstant( - None, ProtoFloat(None, 3.14159265, ProtoFloatSign.POSITIVE) - ), + ProtoIdentifier("(fully.qualified).option"), + ProtoConstant(ProtoFloat(3.14159265, ProtoFloatSign.POSITIVE)), ), ], ) self.assertIn( ProtoEnum( - None, - ProtoIdentifier(None, "MyAwesomeEnum"), + ProtoIdentifier("MyAwesomeEnum"), [ ProtoOption( - None, - ProtoIdentifier(None, "allow_alias"), - ProtoConstant(None, ProtoBool(None, True)), + ProtoIdentifier("allow_alias"), + ProtoConstant(ProtoBool(True)), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "MAE_UNSPECIFIED"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("MAE_UNSPECIFIED"), + ProtoInt(0, ProtoIntSign.POSITIVE), [], ), ProtoEnumValue( - None, - ProtoIdentifier(None, "MAE_STARTED"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("MAE_STARTED"), + ProtoInt(1, ProtoIntSign.POSITIVE), [], ), ProtoEnumValue( - None, - ProtoIdentifier(None, "MAE_RUNNING"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("MAE_RUNNING"), + ProtoInt(2, ProtoIntSign.POSITIVE), [], ), ], @@ -156,113 +147,89 @@ def test_parser(self): ) self.assertIn( ProtoMessage( - None, - ProtoIdentifier(None, "MyAwesomeMessage"), + ProtoIdentifier("MyAwesomeMessage"), [ ProtoOption( - None, - ProtoFullIdentifier(None, "(bar).baz"), - ProtoConstant( - None, ProtoFloat(None, 1.2, ProtoFloatSign.POSITIVE) - ), + ProtoFullIdentifier("(bar).baz"), + ProtoConstant(ProtoFloat(1.2, ProtoFloatSign.POSITIVE)), ), ProtoEnum( - None, - ProtoIdentifier(None, "MyNestedEnum"), + ProtoIdentifier("MyNestedEnum"), [ ProtoEnumValue( - None, - ProtoIdentifier(None, "MNE_UNDEFINED"), - ProtoInt(None, 0, ProtoIntSign.POSITIVE), + ProtoIdentifier("MNE_UNDEFINED"), + ProtoInt(0, ProtoIntSign.POSITIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "MNE_NEGATIVE"), - ProtoInt(None, 1, ProtoIntSign.NEGATIVE), + ProtoIdentifier("MNE_NEGATIVE"), + ProtoInt(1, ProtoIntSign.NEGATIVE), ), ProtoEnumValue( - None, - ProtoIdentifier(None, "MNE_POSITIVE"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("MNE_POSITIVE"), + ProtoInt(2, ProtoIntSign.POSITIVE), ), ], ), - ProtoMessage(None, ProtoIdentifier(None, "MyNestedMessage"), []), + ProtoMessage(ProtoIdentifier("MyNestedMessage"), []), ProtoReserved( - None, ranges=[ ProtoRange( - None, - ProtoInt(None, 1, ProtoIntSign.POSITIVE), - ProtoInt(None, 3, ProtoIntSign.POSITIVE), + ProtoInt(1, ProtoIntSign.POSITIVE), + ProtoInt(3, ProtoIntSign.POSITIVE), ) ], ), - ProtoReserved(None, fields=[ProtoIdentifier(None, "yay")]), - ProtoSingleLineComment(None, " testing nested comment"), + ProtoReserved(fields=[ProtoIdentifier("yay")]), + ProtoSingleLineComment(" testing nested comment"), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "field_one"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("field_one"), + ProtoInt(1, ProtoIntSign.POSITIVE), True, ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "field_two"), - ProtoInt(None, 2, ProtoIntSign.POSITIVE), + ProtoIdentifier("field_two"), + ProtoInt(2, ProtoIntSign.POSITIVE), False, False, - ProtoIdentifier(None, "MyNestedMessage"), + ProtoIdentifier("MyNestedMessage"), [ ProtoMessageFieldOption( - None, - ProtoFullIdentifier(None, "bar.baz"), - ProtoConstant(None, ProtoBool(None, True)), + ProtoFullIdentifier("bar.baz"), + ProtoConstant(ProtoBool(True)), ) ], ), - ProtoExtensions(None, [ProtoRange(None, 8, ProtoRangeEnum.MAX)]), + ProtoExtensions([ProtoRange(8, ProtoRangeEnum.MAX)]), ProtoOneOf( - None, - ProtoIdentifier(None, "foo"), + ProtoIdentifier("foo"), [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "name"), - ProtoInt(None, 4, ProtoIntSign.POSITIVE), + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), ), ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant( - None, ProtoStringLiteral(None, "com.example.foo") - ), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), ), ProtoMessageField( - None, ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "sub_message"), - ProtoInt(None, 9, ProtoIntSign.POSITIVE), + ProtoIdentifier("sub_message"), + ProtoInt(9, ProtoIntSign.POSITIVE), False, False, - ProtoFullIdentifier(None, "SubMessage"), + ProtoFullIdentifier("SubMessage"), [ ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "(bar.baz).bat"), - ProtoConstant( - None, ProtoStringLiteral(None, "bat") - ), + ProtoIdentifier("(bar.baz).bat"), + ProtoConstant(ProtoStringLiteral("bat")), ), ProtoMessageFieldOption( - None, - ProtoIdentifier(None, "baz.bat"), + ProtoIdentifier("baz.bat"), ProtoConstant( - None, - ProtoInt(None, 100, ProtoIntSign.NEGATIVE), + ProtoInt(100, ProtoIntSign.NEGATIVE), ), ), ], @@ -270,12 +237,11 @@ def test_parser(self): ], ), ProtoMap( - None, ProtoMapKeyTypesEnum.SFIXED64, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier(None, "my_map"), - ProtoInt(None, 10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier(None, "NestedMessage"), + ProtoIdentifier("my_map"), + ProtoInt(10, ProtoIntSign.POSITIVE), + ProtoEnumOrMessageIdentifier("NestedMessage"), [], ), ], @@ -285,47 +251,38 @@ def test_parser(self): self.assertIn( ProtoService( - None, - ProtoIdentifier(None, "MyGreatService"), + ProtoIdentifier("MyGreatService"), [ ProtoOption( - None, - ProtoIdentifier(None, "(foo.bar).baz"), - ProtoConstant(None, ProtoStringLiteral(None, "bat")), + ProtoIdentifier("(foo.bar).baz"), + ProtoConstant(ProtoStringLiteral("bat")), ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "OneRPC"), - ProtoEnumOrMessageIdentifier(None, "OneRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "OneRPCResponse"), + ProtoIdentifier("OneRPC"), + ProtoEnumOrMessageIdentifier("OneRPCRequest"), + ProtoEnumOrMessageIdentifier("OneRPCResponse"), ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "TwoRPC"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "TwoRPCResponse"), + ProtoIdentifier("TwoRPC"), + ProtoEnumOrMessageIdentifier("TwoRPCRequest"), + ProtoEnumOrMessageIdentifier("TwoRPCResponse"), False, True, ), ProtoServiceRPC( - None, - ProtoIdentifier(None, "ThreeRPC"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCRequest"), - ProtoEnumOrMessageIdentifier(None, "ThreeRPCResponse"), + ProtoIdentifier("ThreeRPC"), + ProtoEnumOrMessageIdentifier("ThreeRPCRequest"), + ProtoEnumOrMessageIdentifier("ThreeRPCResponse"), False, False, [ ProtoOption( - None, - ProtoIdentifier(None, "java_package"), - ProtoConstant( - None, ProtoStringLiteral(None, "com.example.foo") - ), + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), ), ProtoOption( - None, - ProtoFullIdentifier(None, "(foo.bar).baz"), - ProtoConstant(None, ProtoBool(None, False)), + ProtoFullIdentifier("(foo.bar).baz"), + ProtoConstant(ProtoBool(False)), ), ], ), @@ -336,16 +293,14 @@ def test_parser(self): self.assertIn( ProtoExtend( - None, - ProtoIdentifier(None, "SomeExtendableMessage"), + ProtoIdentifier("SomeExtendableMessage"), [ ProtoMessageField( - None, ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier(None, "some_extendable_field"), - ProtoInt(None, 1, ProtoIntSign.POSITIVE), + ProtoIdentifier("some_extendable_field"), + ProtoInt(1, ProtoIntSign.POSITIVE), ), - ProtoSingleLineComment(None, " yay"), + ProtoSingleLineComment(" yay"), ], ), proto_file.nodes, From 91898489414e2d0bc1e64cca0ee0f7c5e62e12ea Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Mon, 20 Feb 2023 22:44:23 -0500 Subject: [PATCH 19/35] Break out oneof tests into separate file (#76) --- test/BUILD.bazel | 15 +++ test/proto_message_test.py | 259 +------------------------------------ test/proto_oneof_test.py | 202 +++++++++++++++++++++++++++++ 3 files changed, 219 insertions(+), 257 deletions(-) create mode 100644 test/proto_oneof_test.py diff --git a/test/BUILD.bazel b/test/BUILD.bazel index 47cd15a..836c370 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -145,6 +145,21 @@ py_test( ], ) +py_test( + name = "proto_oneof_test", + srcs = ["proto_oneof_test.py"], + deps = [ + "//src:proto_comment", + "//src:proto_constant", + "//src:proto_identifier", + "//src:proto_int", + "//src:proto_message_field", + "//src:proto_oneof", + "//src:proto_option", + "//src:proto_string_literal", + ], +) + py_test( name = "proto_message_test", srcs = ["proto_message_test.py"], diff --git a/test/proto_message_test.py b/test/proto_message_test.py index fa4a5ae..1eae4f6 100644 --- a/test/proto_message_test.py +++ b/test/proto_message_test.py @@ -14,17 +14,13 @@ ) from src.proto_int import ProtoInt, ProtoIntSign from src.proto_map import ProtoMap, ProtoMapKeyTypesEnum, ProtoMapValueTypesEnum -from src.proto_message import ( - ProtoMessage, - ProtoMessageAdded, - ProtoMessageRemoved, - ProtoOneOf, -) +from src.proto_message import ProtoMessage, ProtoMessageAdded, ProtoMessageRemoved from src.proto_message_field import ( ProtoMessageField, ProtoMessageFieldOption, ProtoMessageFieldTypesEnum, ) +from src.proto_oneof import ProtoOneOf from src.proto_option import ProtoOption from src.proto_range import ProtoRange, ProtoRangeEnum from src.proto_reserved import ProtoReserved @@ -397,257 +393,6 @@ def test_message_simple_field(self): ), ) - def test_oneof_empty(self): - parsed_oneof_empty = ProtoOneOf.match(dedent("oneof one_of_field {}".strip())) - self.assertEqual( - parsed_oneof_empty.node, - ProtoOneOf( - ProtoIdentifier("one_of_field"), - [], - ), - ) - - def test_oneof_empty_statements(self): - parsed_oneof_empty = ProtoOneOf.match( - dedent( - """oneof one_of_field { - ; - ; - }""".strip() - ), - ) - self.assertEqual( - parsed_oneof_empty.node, - ProtoOneOf( - ProtoIdentifier("one_of_field"), - [], - ), - ) - - def test_oneof_basic_fields(self): - parsed_oneof_basic_fields = ProtoOneOf.match( - dedent( - """oneof one_of_field { - string name = 4; - SubMessage sub_message = 9; - }""".strip() - ), - ) - self.assertEqual( - parsed_oneof_basic_fields.node, - ProtoOneOf( - ProtoIdentifier("one_of_field"), - [ - ProtoMessageField( - ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), - ), - ProtoMessageField( - ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("sub_message"), - ProtoInt(9, ProtoIntSign.POSITIVE), - False, - False, - ProtoFullIdentifier("SubMessage"), - [], - ), - ], - ), - ) - - def test_oneof_options(self): - parsed_oneof_options = ProtoOneOf.match( - dedent( - """oneof one_of_field { - option java_package = "com.example.foo"; - }""".strip() - ), - ) - self.assertEqual( - parsed_oneof_options.node, - ProtoOneOf( - ProtoIdentifier("one_of_field"), - [ - ProtoOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), - ), - ], - ), - ) - - def test_oneof_field_option(self): - parsed_oneof_field_option = ProtoOneOf.match( - dedent( - """oneof one_of_field { - string name = 4 [ (bar.baz).bat = "bat", baz.bat = -100 ]; - }""".strip() - ), - ) - self.assertEqual( - parsed_oneof_field_option.node, - ProtoOneOf( - ProtoIdentifier("one_of_field"), - [ - ProtoMessageField( - ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), - False, - False, - None, - [ - ProtoMessageFieldOption( - ProtoIdentifier("(bar.baz).bat"), - ProtoConstant(ProtoStringLiteral("bat")), - ), - ProtoMessageFieldOption( - ProtoIdentifier("baz.bat"), - ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), - ), - ], - ) - ], - ), - ) - - def test_oneof_with_comment(self): - parsed_oneof_with_comment = ProtoOneOf.match( - dedent( - """oneof one_of_field { - string name = 4; - // single-line comment! - SubMessage sub_message = 9; - }""".strip() - ), - ) - self.assertEqual( - parsed_oneof_with_comment.node, - ProtoOneOf( - ProtoIdentifier("one_of_field"), - [ - ProtoMessageField( - ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), - ), - ProtoSingleLineComment(" single-line comment!"), - ProtoMessageField( - ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("sub_message"), - ProtoInt(9, ProtoIntSign.POSITIVE), - False, - False, - ProtoFullIdentifier("SubMessage"), - [], - ), - ], - ), - ) - - def test_oneof_normalize_removes_comment(self): - normalized_oneof = ProtoOneOf.match( - dedent( - """oneof one_of_field { - string name = 4; - // single-line comment! - SubMessage sub_message = 9; - }""".strip() - ), - ).node.normalize() - self.assertEqual( - normalized_oneof.nodes, - [ - ProtoMessageField( - ProtoMessageFieldTypesEnum.STRING, - ProtoIdentifier("name"), - ProtoInt(4, ProtoIntSign.POSITIVE), - ), - ProtoMessageField( - ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("sub_message"), - ProtoInt(9, ProtoIntSign.POSITIVE), - False, - False, - ProtoFullIdentifier("SubMessage"), - [], - ), - ], - ) - - def test_simple_map(self): - parsed_map_simple = ProtoMap.match("map my_map = 10;") - self.assertEqual( - parsed_map_simple.node, - ProtoMap( - ProtoMapKeyTypesEnum.SFIXED64, - ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("my_map"), - ProtoInt(10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier("NestedMessage"), - [], - ), - ) - - def test_map_without_spaces(self): - map_without_spaces = ProtoMap.match("map my_map = 10;") - self.assertEqual( - map_without_spaces.node, - ProtoMap( - ProtoMapKeyTypesEnum.SFIXED64, - ProtoMapValueTypesEnum.ENUM_OR_MESSAGE, - ProtoIdentifier("my_map"), - ProtoInt(10, ProtoIntSign.POSITIVE), - ProtoEnumOrMessageIdentifier("NestedMessage"), - [], - ), - ) - - def test_map_with_options(self): - parsed_map_simple = ProtoMap.match( - "map my_map = 10 [ java_package = 'com.example.foo', baz.bat = 48 ];", - ) - self.assertEqual(parsed_map_simple.node.key_type, ProtoMapKeyTypesEnum.SFIXED64) - self.assertEqual( - parsed_map_simple.node.value_type, ProtoMapValueTypesEnum.ENUM_OR_MESSAGE - ) - self.assertEqual(parsed_map_simple.node.name, ProtoIdentifier("my_map")) - self.assertEqual( - parsed_map_simple.node.number, ProtoInt(10, ProtoIntSign.POSITIVE) - ) - self.assertEqual( - parsed_map_simple.node.enum_or_message_type_name, - ProtoEnumOrMessageIdentifier("NestedMessage"), - ) - self.assertEqual( - parsed_map_simple.node.options, - [ - ProtoMessageFieldOption( - ProtoIdentifier("java_package"), - ProtoConstant(ProtoStringLiteral("com.example.foo")), - ), - ProtoMessageFieldOption( - ProtoFullIdentifier("baz.bat"), - ProtoConstant(ProtoInt(48, ProtoIntSign.POSITIVE)), - ), - ], - ) - - def test_map_message_value(self): - parsed_map_simple = ProtoMap.match("map string_map = 11;") - self.assertEqual( - parsed_map_simple.node, - ProtoMap( - ProtoMapKeyTypesEnum.STRING, - ProtoMapValueTypesEnum.STRING, - ProtoIdentifier("string_map"), - ProtoInt(11, ProtoIntSign.POSITIVE), - None, - [], - ), - ) - def test_message_parses_comments(self): parsed_comments = ProtoMessage.match( dedent( diff --git a/test/proto_oneof_test.py b/test/proto_oneof_test.py new file mode 100644 index 0000000..0f0eec3 --- /dev/null +++ b/test/proto_oneof_test.py @@ -0,0 +1,202 @@ +import unittest +from textwrap import dedent + +from src.proto_comment import ProtoSingleLineComment +from src.proto_constant import ProtoConstant +from src.proto_identifier import ProtoFullIdentifier, ProtoIdentifier +from src.proto_int import ProtoInt, ProtoIntSign +from src.proto_message_field import ( + ProtoMessageField, + ProtoMessageFieldOption, + ProtoMessageFieldTypesEnum, +) +from src.proto_oneof import ProtoOneOf +from src.proto_option import ProtoOption +from src.proto_string_literal import ProtoStringLiteral + + +class OneOfTest(unittest.TestCase): + maxDiff = None + + def test_oneof_empty(self): + parsed_oneof_empty = ProtoOneOf.match(dedent("oneof one_of_field {}".strip())) + self.assertEqual( + parsed_oneof_empty.node, + ProtoOneOf( + ProtoIdentifier("one_of_field"), + [], + ), + ) + + def test_oneof_empty_statements(self): + parsed_oneof_empty = ProtoOneOf.match( + dedent( + """oneof one_of_field { + ; + ; + }""".strip() + ), + ) + self.assertEqual( + parsed_oneof_empty.node, + ProtoOneOf( + ProtoIdentifier("one_of_field"), + [], + ), + ) + + def test_oneof_basic_fields(self): + parsed_oneof_basic_fields = ProtoOneOf.match( + dedent( + """oneof one_of_field { + string name = 4; + SubMessage sub_message = 9; + }""".strip() + ), + ) + self.assertEqual( + parsed_oneof_basic_fields.node, + ProtoOneOf( + ProtoIdentifier("one_of_field"), + [ + ProtoMessageField( + ProtoMessageFieldTypesEnum.STRING, + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, + ProtoIdentifier("sub_message"), + ProtoInt(9, ProtoIntSign.POSITIVE), + False, + False, + ProtoFullIdentifier("SubMessage"), + [], + ), + ], + ), + ) + + def test_oneof_options(self): + parsed_oneof_options = ProtoOneOf.match( + dedent( + """oneof one_of_field { + option java_package = "com.example.foo"; + }""".strip() + ), + ) + self.assertEqual( + parsed_oneof_options.node, + ProtoOneOf( + ProtoIdentifier("one_of_field"), + [ + ProtoOption( + ProtoIdentifier("java_package"), + ProtoConstant(ProtoStringLiteral("com.example.foo")), + ), + ], + ), + ) + + def test_oneof_field_option(self): + parsed_oneof_field_option = ProtoOneOf.match( + dedent( + """oneof one_of_field { + string name = 4 [ (bar.baz).bat = "bat", baz.bat = -100 ]; + }""".strip() + ), + ) + self.assertEqual( + parsed_oneof_field_option.node, + ProtoOneOf( + ProtoIdentifier("one_of_field"), + [ + ProtoMessageField( + ProtoMessageFieldTypesEnum.STRING, + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), + False, + False, + None, + [ + ProtoMessageFieldOption( + ProtoIdentifier("(bar.baz).bat"), + ProtoConstant(ProtoStringLiteral("bat")), + ), + ProtoMessageFieldOption( + ProtoIdentifier("baz.bat"), + ProtoConstant(ProtoInt(100, ProtoIntSign.NEGATIVE)), + ), + ], + ) + ], + ), + ) + + def test_oneof_with_comment(self): + parsed_oneof_with_comment = ProtoOneOf.match( + dedent( + """oneof one_of_field { + string name = 4; + // single-line comment! + SubMessage sub_message = 9; + }""".strip() + ), + ) + self.assertEqual( + parsed_oneof_with_comment.node, + ProtoOneOf( + ProtoIdentifier("one_of_field"), + [ + ProtoMessageField( + ProtoMessageFieldTypesEnum.STRING, + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), + ), + ProtoSingleLineComment(" single-line comment!"), + ProtoMessageField( + ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, + ProtoIdentifier("sub_message"), + ProtoInt(9, ProtoIntSign.POSITIVE), + False, + False, + ProtoFullIdentifier("SubMessage"), + [], + ), + ], + ), + ) + + def test_oneof_normalize_removes_comment(self): + normalized_oneof = ProtoOneOf.match( + dedent( + """oneof one_of_field { + string name = 4; + // single-line comment! + SubMessage sub_message = 9; + }""".strip() + ), + ).node.normalize() + self.assertEqual( + normalized_oneof.nodes, + [ + ProtoMessageField( + ProtoMessageFieldTypesEnum.STRING, + ProtoIdentifier("name"), + ProtoInt(4, ProtoIntSign.POSITIVE), + ), + ProtoMessageField( + ProtoMessageFieldTypesEnum.ENUM_OR_MESSAGE, + ProtoIdentifier("sub_message"), + ProtoInt(9, ProtoIntSign.POSITIVE), + False, + False, + ProtoFullIdentifier("SubMessage"), + [], + ), + ], + ) + + +if __name__ == "__main__": + unittest.main() From 0f8d56d9b9ec1be302f320ac7cca5738c28316d8 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Mon, 20 Feb 2023 22:46:40 -0500 Subject: [PATCH 20/35] Specify a direct dep that we're missing (#77) --- test/BUILD.bazel | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/BUILD.bazel b/test/BUILD.bazel index 836c370..69fd827 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -174,6 +174,8 @@ py_test( "//src:proto_int", "//src:proto_map", "//src:proto_message", + "//src:proto_message_field", + "//src:proto_oneof", "//src:proto_option", "//src:proto_reserved", "//src:proto_string_literal", From b30ad8873b2fa741763d6bb752fc6a42ac86ebfd Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Wed, 8 Mar 2023 11:11:59 -0400 Subject: [PATCH 21/35] Make ProtoFile a ProtoNode subclass (#78) --- src/BUILD.bazel | 3 ++ src/proto_file.py | 100 +++++++++++++++++++++++++++++++++++++++++-- src/util/BUILD.bazel | 9 ---- src/util/parser.py | 90 ++++---------------------------------- 4 files changed, 108 insertions(+), 94 deletions(-) diff --git a/src/BUILD.bazel b/src/BUILD.bazel index 13dfe8f..c11c756 100644 --- a/src/BUILD.bazel +++ b/src/BUILD.bazel @@ -248,12 +248,15 @@ py_library( srcs = ["proto_file.py"], visibility = ["//visibility:public"], deps = [ + ":proto_comment", ":proto_enum", + ":proto_extend", ":proto_import", ":proto_message", ":proto_node", ":proto_option", ":proto_package", + ":proto_service", ":proto_syntax", ], ) diff --git a/src/proto_file.py b/src/proto_file.py index adcd7f8..a5bdd46 100644 --- a/src/proto_file.py +++ b/src/proto_file.py @@ -1,16 +1,29 @@ from typing import Optional, Sequence +from src.proto_comment import ( + ProtoComment, + ProtoMultiLineComment, + ProtoSingleLineComment, +) from src.proto_enum import ProtoEnum +from src.proto_extend import ProtoExtend from src.proto_import import ProtoImport from src.proto_message import ProtoMessage -from src.proto_node import ProtoNode, ProtoNodeDiff +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff from src.proto_option import ProtoOption from src.proto_package import ProtoPackage +from src.proto_service import ProtoService from src.proto_syntax import ProtoSyntax -class ProtoFile: - def __init__(self, syntax: ProtoSyntax, nodes: list[ProtoNode]): +class ParsedProtoFileNode(ParsedProtoNode): + node: "ProtoFile" + remaining_source: str + + +class ProtoFile(ProtoNode): + def __init__(self, syntax: ProtoSyntax, nodes: list[ProtoNode], *args, **kwargs): + super().__init__(*args, **kwargs) self.syntax = syntax self.nodes = nodes @@ -40,6 +53,87 @@ def enums(self) -> list[ProtoEnum]: def messages(self) -> list[ProtoMessage]: return [node for node in self.nodes if isinstance(node, ProtoMessage)] + @staticmethod + def parse_partial_content(partial_proto_content: str) -> ParsedProtoNode: + node_types: list[type[ProtoNode]] = [ + ProtoImport, + ProtoMessage, + ProtoPackage, + ProtoOption, + ProtoEnum, + ProtoExtend, + ProtoService, + ProtoSingleLineComment, + ProtoMultiLineComment, + ] + for node_type in node_types: + try: + match_result = node_type.match(partial_proto_content) + except (ValueError, IndexError, TypeError): + raise ValueError( + f"Could not parse proto content:\n{partial_proto_content}" + ) + if match_result is not None: + return match_result + raise ValueError(f"Could not parse proto content:\n{partial_proto_content}") + + @staticmethod + def parse_syntax_and_preceding_comments( + proto_content: str, + ) -> tuple[ProtoSyntax, Sequence[ProtoComment], str]: + # First, parse any preceding comments. + parsed_tree = [] + while True: + for node_type in [ProtoSingleLineComment, ProtoMultiLineComment]: + try: + match_result = node_type.match(proto_content) + except (ValueError, IndexError, TypeError): + raise ValueError(f"Could not parse proto content:\n{proto_content}") + if match_result is not None: + parsed_tree.append(match_result.node) + proto_content = match_result.remaining_source.strip() + break + if match_result is None: + break + + # Next, parse syntax. + try: + syntax_match = ProtoSyntax.match(proto_content.strip()) + except (ValueError, IndexError, TypeError): + raise ValueError(f"Proto doesn't have parseable syntax:\n{proto_content}") + if syntax_match is None: + raise ValueError(f"Proto doesn't have parseable syntax:\n{proto_content}") + syntax = syntax_match.node + proto_content = syntax_match.remaining_source.strip() + + return syntax, parsed_tree, proto_content + + @classmethod + def match( + cls, proto_content: str, parent: Optional["ProtoNode"] = None + ) -> Optional[ParsedProtoFileNode]: + syntax, parsed_tree, proto_content = cls.parse_syntax_and_preceding_comments( + proto_content + ) + new_tree: list[ProtoNode] = list(parsed_tree) + while proto_content: + # Remove empty statements. + if proto_content.startswith(";"): + proto_content = proto_content[1:].strip() + continue + match_result = cls.parse_partial_content(proto_content) + new_tree.append(match_result.node) + proto_content = match_result.remaining_source.strip() + + return ParsedProtoFileNode(cls(syntax, new_tree), proto_content) + + def normalize(self) -> Optional["ProtoNode"]: + normalized_nodes = [n.normalize() for n in self.nodes] + return ProtoFile( + syntax=self.syntax.normalize(), + nodes=[n for n in normalized_nodes if n is not None], + ) + def serialize(self) -> str: serialized_parts = [self.syntax.serialize()] previous_type: type[ProtoNode] = self.syntax.__class__ diff --git a/src/util/BUILD.bazel b/src/util/BUILD.bazel index 827decd..03f3423 100644 --- a/src/util/BUILD.bazel +++ b/src/util/BUILD.bazel @@ -5,16 +5,7 @@ py_library( srcs = ["parser.py"], visibility = ["//visibility:public"], deps = [ - "//src:proto_enum", - "//src:proto_extend", "//src:proto_file", - "//src:proto_import", - "//src:proto_message", - "//src:proto_node", - "//src:proto_option", - "//src:proto_package", - "//src:proto_service", - "//src:proto_syntax", ], ) diff --git a/src/util/parser.py b/src/util/parser.py index 75b9de9..dd00352 100644 --- a/src/util/parser.py +++ b/src/util/parser.py @@ -1,21 +1,6 @@ import sys -from typing import Sequence -from src.proto_comment import ( - ProtoComment, - ProtoMultiLineComment, - ProtoSingleLineComment, -) -from src.proto_enum import ProtoEnum -from src.proto_extend import ProtoExtend from src.proto_file import ProtoFile -from src.proto_import import ProtoImport -from src.proto_message import ProtoMessage -from src.proto_node import ParsedProtoNode, ProtoNode -from src.proto_option import ProtoOption -from src.proto_package import ProtoPackage -from src.proto_service import ProtoService -from src.proto_syntax import ProtoSyntax class ParseError(ValueError): @@ -24,76 +9,17 @@ class ParseError(ValueError): class Parser: @staticmethod - def parse_partial_content(partial_proto_content: str) -> ParsedProtoNode: - node_types: list[type[ProtoNode]] = [ - ProtoImport, - ProtoMessage, - ProtoPackage, - ProtoOption, - ProtoEnum, - ProtoExtend, - ProtoService, - ProtoSingleLineComment, - ProtoMultiLineComment, - ] - for node_type in node_types: - try: - match_result = node_type.match(partial_proto_content) - except (ValueError, IndexError, TypeError): - raise ParseError( - f"Could not parse proto content:\n{partial_proto_content}" - ) - if match_result is not None: - return match_result - raise ParseError(f"Could not parse proto content:\n{partial_proto_content}") - - @staticmethod - def parse_syntax_and_preceding_comments( - proto_content: str, - ) -> tuple[ProtoSyntax, Sequence[ProtoComment], str]: - # First, parse any preceding comments. - parsed_tree = [] - while True: - for node_type in [ProtoSingleLineComment, ProtoMultiLineComment]: - try: - match_result = node_type.match(proto_content) - except (ValueError, IndexError, TypeError): - raise ParseError(f"Could not parse proto content:\n{proto_content}") - if match_result is not None: - parsed_tree.append(match_result.node) - proto_content = match_result.remaining_source.strip() - break - if match_result is None: - break - - # Next, parse syntax. + def loads(proto_content: str) -> ProtoFile: try: - syntax_match = ProtoSyntax.match(proto_content.strip()) - except (ValueError, IndexError, TypeError): - raise ParseError(f"Proto doesn't have parseable syntax:\n{proto_content}") - if syntax_match is None: + parsed_file = ProtoFile.match(proto_content, None) + except ValueError as e: + raise ParseError( + f"Proto doesn't have parseable syntax:\n{proto_content}\n{e}" + ) + if parsed_file is None: raise ParseError(f"Proto doesn't have parseable syntax:\n{proto_content}") - syntax = syntax_match.node - proto_content = syntax_match.remaining_source.strip() - - return syntax, parsed_tree, proto_content - - @staticmethod - def loads(proto_content: str) -> ProtoFile: - syntax, parsed_tree, proto_content = Parser.parse_syntax_and_preceding_comments( - proto_content - ) - new_tree: list[ProtoNode] = list(parsed_tree) - while proto_content: - # Remove empty statements. - if proto_content.startswith(";"): - proto_content = proto_content[1:].strip() - continue - match_result = Parser.parse_partial_content(proto_content) - new_tree.append(match_result.node) - proto_content = match_result.remaining_source.strip() - return ProtoFile(syntax, new_tree) + return parsed_file.node if __name__ == "__main__": From 0b12d272cc2147d9d62164d17723cc32abf25b1c Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Thu, 9 Mar 2023 10:14:41 -0400 Subject: [PATCH 22/35] Support oneof diffs in messages (#79) --- TODO.md | 1 + src/proto_enum.py | 41 ++++-- src/proto_file.py | 4 +- src/proto_message.py | 53 ++++++-- src/proto_message_field.py | 2 +- src/proto_oneof.py | 83 +++++++++++- src/proto_option.py | 56 +++++--- test/proto_enum_test.py | 47 +++++-- test/proto_message_test.py | 96 +++++++++----- test/proto_oneof_test.py | 259 ++++++++++++++++++++++++++++++++++++- test/proto_option_test.py | 82 +++++++----- 11 files changed, 603 insertions(+), 121 deletions(-) diff --git a/TODO.md b/TODO.md index 0ade4bf..2ac2e2c 100644 --- a/TODO.md +++ b/TODO.md @@ -84,6 +84,7 @@ - [ ] RPC changes - [ ] Additions/removals - [ ] Option changes + - [ ] Comment diffs - [ ] Backwards-compatibility check - [ ] __eq__ should enforce parent equality - [ ] Scoping of diffs under containing objects diff --git a/src/proto_enum.py b/src/proto_enum.py index b427221..a37bd07 100644 --- a/src/proto_enum.py +++ b/src/proto_enum.py @@ -182,7 +182,9 @@ def diff( f"Don't know how to handle diff between enums whose names aren't identical: {before}, {after}" ) - diffs.extend(ProtoEnumValueOption.diff_sets(before.options, after.options)) + diffs.extend( + ProtoEnumValueOption.diff_sets(before, before.options, after.options) + ) return diffs @staticmethod @@ -323,11 +325,13 @@ def serialize(self) -> str: return "\n".join(serialize_parts) @staticmethod - def diff(before: "ProtoEnum", after: "ProtoEnum") -> list["ProtoNodeDiff"]: + def diff( + parent: ProtoNode, before: "ProtoEnum", after: "ProtoEnum" + ) -> list["ProtoNodeDiff"]: if before is None and after is not None: - return [ProtoEnumAdded(after)] + return [ProtoEnumAdded(parent, after)] elif before is not None and after is None: - return [ProtoEnumRemoved(before)] + return [ProtoEnumRemoved(parent, before)] elif before is None and after is None: return [] elif before.name != after.name: @@ -336,42 +340,51 @@ def diff(before: "ProtoEnum", after: "ProtoEnum") -> list["ProtoNodeDiff"]: return [] diffs: list[ProtoNodeDiff] = [] # TODO: scope these diffs under ProtoEnum - diffs.extend(ProtoOption.diff_sets(before.options, after.options)) + diffs.extend(ProtoOption.diff_sets(parent, before.options, after.options)) diffs.extend(ProtoEnumValue.diff_sets(before, before.values, after.values)) return diffs @staticmethod def diff_sets( - before: list["ProtoEnum"], after: list["ProtoEnum"] + parent: ProtoNode, before: list["ProtoEnum"], after: list["ProtoEnum"] ) -> list["ProtoNodeDiff"]: diffs: list[ProtoNodeDiff] = [] before_names = set(o.name.identifier for o in before) after_names = set(o.name.identifier for o in after) for name in before_names - after_names: diffs.append( - ProtoEnumRemoved(next(i for i in before if i.name.identifier == name)) + ProtoEnumRemoved( + parent, next(i for i in before if i.name.identifier == name) + ) ) for name in after_names - before_names: diffs.append( - ProtoEnumAdded(next(i for i in after if i.name.identifier == name)) + ProtoEnumAdded( + parent, next(i for i in after if i.name.identifier == name) + ) ) for name in before_names & after_names: before_enum = next(i for i in before if i.name.identifier == name) after_enum = next(i for i in after if i.name.identifier == name) - diffs.extend(ProtoEnum.diff(before_enum, after_enum)) + diffs.extend(ProtoEnum.diff(parent, before_enum, after_enum)) return diffs class ProtoEnumDiff(ProtoNodeDiff): - def __init__(self, enum: ProtoEnum): + def __init__(self, parent: ProtoNode, enum: ProtoEnum): + self.parent = parent self.enum = enum def __eq__(self, other: object) -> bool: - return isinstance(other, ProtoEnumDiff) and self.enum == other.enum + return ( + isinstance(other, ProtoEnumDiff) + and self.parent == other.parent + and self.enum == other.enum + ) def __str__(self) -> str: - return f"<{self.__class__.__name__} enum={self.enum}>" + return f"<{self.__class__.__name__} enum={self.enum} parent={self.parent}>" class ProtoEnumAdded(ProtoEnumDiff): @@ -382,9 +395,9 @@ class ProtoEnumRemoved(ProtoEnumDiff): pass -class ProtoEnumValueDiff(ProtoEnumDiff): +class ProtoEnumValueDiff(ProtoNodeDiff): def __init__(self, enum: "ProtoEnum", enum_value: "ProtoEnumValue"): - super().__init__(enum) + self.enum = enum self.enum_value = enum_value def __eq__(self, other: object) -> bool: diff --git a/src/proto_file.py b/src/proto_file.py index a5bdd46..0b72760 100644 --- a/src/proto_file.py +++ b/src/proto_file.py @@ -151,7 +151,7 @@ def diff(self, other: "ProtoFile") -> Sequence[ProtoNodeDiff]: diffs.extend(ProtoSyntax.diff(self.syntax, other.syntax)) diffs.extend(ProtoImport.diff_sets(self.imports, other.imports)) diffs.extend(ProtoPackage.diff(self.package, other.package)) - diffs.extend(ProtoEnum.diff_sets(self.enums, other.enums)) - diffs.extend(ProtoMessage.diff_sets(self.messages, other.messages)) + diffs.extend(ProtoEnum.diff_sets(self, self.enums, other.enums)) + diffs.extend(ProtoMessage.diff_sets(self, self.messages, other.messages)) return [d for d in diffs if d is not None] diff --git a/src/proto_message.py b/src/proto_message.py index 5cc85be..8776aaf 100644 --- a/src/proto_message.py +++ b/src/proto_message.py @@ -165,6 +165,10 @@ def maps(self) -> list[ProtoMap]: def message_fields(self) -> list[ProtoMessageField]: return [node for node in self.nodes if isinstance(node, ProtoMessageField)] + @property + def oneofs(self) -> list[ProtoOneOf]: + return [node for node in self.nodes if isinstance(node, ProtoOneOf)] + def serialize(self) -> str: serialize_parts = ( [f"message {self.name.serialize()} {{"] @@ -175,12 +179,14 @@ def serialize(self) -> str: @staticmethod def diff( - before: "ProtoMessage", after: "ProtoMessage" + parent: ProtoNode, + before: "ProtoMessage", + after: "ProtoMessage", ) -> Sequence["ProtoNodeDiff"]: if before is None and after is not None: - return [ProtoMessageAdded(after)] + return [ProtoMessageAdded(parent, after)] elif before is not None and after is None: - return [ProtoMessageRemoved(before)] + return [ProtoMessageRemoved(parent, before)] elif before is None and after is None: return [] elif before.name != after.name: @@ -188,8 +194,15 @@ def diff( elif before == after: return [] diffs: list[ProtoNodeDiff] = [] - diffs.extend(ProtoOption.diff_sets(before.options, after.options)) - # diffs.extend(ProtoOneOf.diff_sets(before, before.oneofs, after.oneofs)) + + # TODO: + # ProtoEnum, + # ProtoExtend, + # ProtoExtensions, + # ProtoMessage, + # ProtoReserved, + diffs.extend(ProtoOption.diff_sets(before, before.options, after.options)) + diffs.extend(ProtoOneOf.diff_sets(before, before.oneofs, after.oneofs)) diffs.extend(ProtoMap.diff_sets(before, before.maps, after.maps)) diffs.extend( ProtoMessageField.diff_sets( @@ -200,7 +213,9 @@ def diff( @staticmethod def diff_sets( - before: list["ProtoMessage"], after: list["ProtoMessage"] + parent: ProtoNode, + before: list["ProtoMessage"], + after: list["ProtoMessage"], ) -> Sequence["ProtoNodeDiff"]: diffs: list[ProtoNodeDiff] = [] before_names = set(o.name.identifier for o in before) @@ -208,30 +223,40 @@ def diff_sets( for name in before_names - after_names: diffs.append( ProtoMessageRemoved( - next(i for i in before if i.name.identifier == name) + parent, + next(i for i in before if i.name.identifier == name), ) ) for name in after_names - before_names: diffs.append( - ProtoMessageAdded(next(i for i in after if i.name.identifier == name)) + ProtoMessageAdded( + parent, next(i for i in after if i.name.identifier == name) + ) ) for name in before_names & after_names: - before_enum = next(i for i in before if i.name.identifier == name) - after_enum = next(i for i in after if i.name.identifier == name) - diffs.extend(ProtoMessage.diff(before_enum, after_enum)) + before_message = next(i for i in before if i.name.identifier == name) + after_message = next(i for i in after if i.name.identifier == name) + diffs.extend(ProtoMessage.diff(parent, before_message, after_message)) return diffs class ProtoMessageDiff(ProtoNodeDiff): - def __init__(self, message: ProtoMessage): + def __init__(self, parent: ProtoNode, message: ProtoMessage): + self.parent = parent self.message = message def __eq__(self, other: object) -> bool: - return isinstance(other, ProtoMessageDiff) and self.message == other.message + return ( + isinstance(other, ProtoMessageDiff) + and self.message == other.message + and self.parent == other.parent + ) def __str__(self) -> str: - return f"<{self.__class__.__name__} message={self.message}>" + return ( + f"<{self.__class__.__name__} message={self.message} parent={self.parent}>" + ) class ProtoMessageAdded(ProtoMessageDiff): diff --git a/src/proto_message_field.py b/src/proto_message_field.py index 2c3c749..1046646 100644 --- a/src/proto_message_field.py +++ b/src/proto_message_field.py @@ -264,7 +264,7 @@ def diff( f"Don't know how to handle diff between message fields whose names are identical: {before}, {after}" ) diffs.extend( - ProtoMessageFieldOption.diff_sets(before.options, after.options) + ProtoMessageFieldOption.diff_sets(before, before.options, after.options) ) return diffs diff --git a/src/proto_oneof.py b/src/proto_oneof.py index 5e225ab..b71c264 100644 --- a/src/proto_oneof.py +++ b/src/proto_oneof.py @@ -10,7 +10,7 @@ from src.proto_identifier import ProtoIdentifier from src.proto_map import ProtoMap from src.proto_message_field import ParsedProtoMessageFieldNode, ProtoMessageField -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff from src.proto_option import ParsedProtoOptionNode, ProtoOption ProtoOneOfNodeTypes = ( @@ -151,6 +151,10 @@ def match( def options(self) -> list[ProtoOption]: return [node for node in self.nodes if isinstance(node, ProtoOption)] + @property + def message_fields(self) -> list[ProtoMessageField]: + return [node for node in self.nodes if isinstance(node, ProtoMessageField)] + def serialize(self) -> str: serialize_parts = ( [f"oneof {self.name.serialize()} {{"] @@ -158,3 +162,80 @@ def serialize(self) -> str: + ["}"] ) return "\n".join(serialize_parts) + + @staticmethod + def diff( + parent: ProtoNode, before: "ProtoOneOf", after: "ProtoOneOf" + ) -> Sequence["ProtoNodeDiff"]: + if before is None and after is not None: + return [ProtoOneOfAdded(parent, after)] + elif before is not None and after is None: + return [ProtoOneOfRemoved(parent, before)] + elif before is None and after is None: + return [] + elif before.name != after.name: + return [] + elif before == after: + return [] + diffs: list[ProtoNodeDiff] = [] + diffs.extend(ProtoOption.diff_sets(before, before.options, after.options)) + diffs.extend( + ProtoMessageField.diff_sets( + before, before.message_fields, after.message_fields + ) + ) + return diffs + + @staticmethod + def diff_sets( + parent: ProtoNode, + before: list["ProtoOneOf"], + after: list["ProtoOneOf"], + ) -> Sequence["ProtoNodeDiff"]: + diffs: list[ProtoNodeDiff] = [] + before_names = set(o.name.identifier for o in before) + after_names = set(o.name.identifier for o in after) + for name in before_names - after_names: + diffs.append( + ProtoOneOfRemoved( + parent, next(i for i in before if i.name.identifier == name) + ) + ) + for name in after_names - before_names: + diffs.append( + ProtoOneOfAdded( + parent, next(i for i in after if i.name.identifier == name) + ) + ) + for name in before_names & after_names: + before_oneof = next(i for i in before if i.name.identifier == name) + after_oneof = next(i for i in after if i.name.identifier == name) + diffs.extend(ProtoOneOf.diff(parent, before_oneof, after_oneof)) + + return diffs + + +class ProtoOneOfDiff(ProtoNodeDiff): + def __init__(self, parent: ProtoNode, oneof: ProtoOneOf): + self.parent = parent + self.oneof = oneof + + def __eq__(self, other: object) -> bool: + return ( + isinstance(other, ProtoOneOfDiff) + and self.oneof == other.oneof + and self.parent == other.parent + ) + + def __str__(self) -> str: + return f"<{self.__class__.__name__} oneof={self.oneof} parent={self.parent}>" + + +class ProtoOneOfAdded(ProtoOneOfDiff): + def __eq__(self, other: object) -> bool: + return super().__eq__(other) and isinstance(other, ProtoOneOfAdded) + + +class ProtoOneOfRemoved(ProtoOneOfDiff): + def __eq__(self, other: object) -> bool: + return super().__eq__(other) and isinstance(other, ProtoOneOfRemoved) diff --git a/src/proto_option.py b/src/proto_option.py index 2d07312..6ba48d2 100644 --- a/src/proto_option.py +++ b/src/proto_option.py @@ -124,39 +124,47 @@ def serialize(self) -> str: @staticmethod def diff( - before: "ProtoOption", after: "ProtoOption" + parent: ProtoNode, + before: "ProtoOption", + after: "ProtoOption", ) -> Sequence["ProtoOptionDiff"]: if before is None and after is not None: - return [ProtoOptionAdded(after)] + return [ProtoOptionAdded(parent, after)] elif before is not None and after is None: - return [ProtoOptionRemoved(before)] + return [ProtoOptionRemoved(parent, before)] elif before is None and after is None: return [] elif before.name != after.name: return [] elif before == after: return [] - return [ProtoOptionValueChanged(before.name, before.value, after.value)] + return [ProtoOptionValueChanged(parent, before.name, before.value, after.value)] @staticmethod def diff_sets( - before: Sequence["ProtoOption"], after: Sequence["ProtoOption"] + parent: ProtoNode, + before: Sequence["ProtoOption"], + after: Sequence["ProtoOption"], ) -> list["ProtoOptionDiff"]: diffs: list[ProtoOptionDiff] = [] before_names = set(o.name.identifier for o in before) after_names = set(o.name.identifier for o in after) for name in before_names - after_names: diffs.append( - ProtoOptionRemoved(next(i for i in before if i.name.identifier == name)) + ProtoOptionRemoved( + parent, next(i for i in before if i.name.identifier == name) + ) ) for name in after_names - before_names: diffs.append( - ProtoOptionAdded(next(i for i in after if i.name.identifier == name)) + ProtoOptionAdded( + parent, next(i for i in after if i.name.identifier == name) + ) ) for name in before_names & after_names: before_option = next(i for i in before if i.name.identifier == name) after_option = next(i for i in after if i.name.identifier == name) - diffs.extend(ProtoOption.diff(before_option, after_option)) + diffs.extend(ProtoOption.diff(parent, before_option, after_option)) return diffs @@ -167,11 +175,16 @@ class ProtoOptionDiff(ProtoNodeDiff): class ProtoOptionValueChanged(ProtoOptionDiff): def __init__( - self, name: ProtoIdentifier, before: ProtoConstant, after: ProtoConstant + self, + parent: ProtoNode, + name: ProtoIdentifier, + before: ProtoConstant, + after: ProtoConstant, ): self.name = name self.before = before self.after = after + self.parent = parent def __eq__(self, other: object) -> bool: return ( @@ -179,29 +192,40 @@ def __eq__(self, other: object) -> bool: and self.name == other.name and self.before == other.before and self.after == other.after + and self.parent == other.parent ) def __str__(self) -> str: - return f"" + return f"" class ProtoOptionAdded(ProtoOptionDiff): - def __init__(self, before: ProtoOption): + def __init__(self, parent: ProtoNode, before: ProtoOption): + self.parent = parent self.before = before def __eq__(self, other: object) -> bool: - return isinstance(other, ProtoOptionAdded) and self.before == other.before + return ( + isinstance(other, ProtoOptionAdded) + and self.before == other.before + and self.parent == other.parent + ) def __str__(self) -> str: - return f"" + return f"" class ProtoOptionRemoved(ProtoOptionDiff): - def __init__(self, after: ProtoOption): + def __init__(self, parent: ProtoNode, after: ProtoOption): + self.parent = parent self.after = after def __eq__(self, other: object) -> bool: - return isinstance(other, ProtoOptionRemoved) and self.after == other.after + return ( + isinstance(other, ProtoOptionRemoved) + and self.after == other.after + and self.parent == other.parent + ) def __str__(self) -> str: - return f"" + return f"" diff --git a/test/proto_enum_test.py b/test/proto_enum_test.py index 237aabc..3463a6b 100644 --- a/test/proto_enum_test.py +++ b/test/proto_enum_test.py @@ -24,6 +24,7 @@ class EnumTest(unittest.TestCase): maxDiff = None + DEFAULT_PARENT = ProtoEnum(ProtoIdentifier("DefaultParent"), []) def test_enum_all_features(self): parsed_enum_multiple_values = ProtoEnum.match( @@ -333,7 +334,7 @@ def test_diff_same_enum_returns_empty(self): ProtoIdentifier("MyEnum"), [], ) - self.assertEqual(ProtoEnum.diff(pe1, pe2), []) + self.assertEqual(ProtoEnum.diff(self.DEFAULT_PARENT, pe1, pe2), []) def test_diff_different_enum_name_returns_empty(self): pe1 = ProtoEnum( @@ -344,7 +345,7 @@ def test_diff_different_enum_name_returns_empty(self): ProtoIdentifier("OtherEnum"), [], ) - self.assertEqual(ProtoEnum.diff(pe1, pe2), []) + self.assertEqual(ProtoEnum.diff(self.DEFAULT_PARENT, pe1, pe2), []) def test_diff_different_enum_value_name_returns_enum_diff(self): pe1 = ProtoEnum( @@ -373,7 +374,7 @@ def test_diff_different_enum_value_name_returns_enum_diff(self): ProtoIdentifier("ME_KNOWN"), ) ], - ProtoEnum.diff(pe1, pe2), + ProtoEnum.diff(self.DEFAULT_PARENT, pe1, pe2), ) def test_diff_different_enum_value_value_returns_enum_diff(self): @@ -396,7 +397,7 @@ def test_diff_different_enum_value_value_returns_enum_diff(self): ], ) - diff = ProtoEnum.diff(pe1, pe2) + diff = ProtoEnum.diff(self.DEFAULT_PARENT, pe1, pe2) self.assertIn( ProtoEnumValueRemoved( @@ -426,9 +427,10 @@ def test_diff_enum_added(self): ], ) self.assertEqual( - ProtoEnum.diff(pe1, pe2), + ProtoEnum.diff(self.DEFAULT_PARENT, pe1, pe2), [ ProtoEnumAdded( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("MyEnum"), [ @@ -437,7 +439,7 @@ def test_diff_enum_added(self): ProtoInt(0, ProtoIntSign.POSITIVE), ) ], - ) + ), ), ], ) @@ -454,9 +456,10 @@ def test_diff_enum_removed(self): ) pe2 = None self.assertEqual( - ProtoEnum.diff(pe1, pe2), + ProtoEnum.diff(self.DEFAULT_PARENT, pe1, pe2), [ ProtoEnumRemoved( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("MyEnum"), [ @@ -465,7 +468,7 @@ def test_diff_enum_removed(self): ProtoInt(0, ProtoIntSign.POSITIVE), ) ], - ) + ), ), ], ) @@ -473,7 +476,7 @@ def test_diff_enum_removed(self): def test_diff_sets_empty_returns_empty(self): set1 = [] set2 = [] - self.assertEqual(ProtoEnum.diff_sets(set1, set2), []) + self.assertEqual(ProtoEnum.diff_sets(self.DEFAULT_PARENT, set1, set2), []) def test_diff_sets_no_change(self): set1 = [ @@ -505,7 +508,7 @@ def test_diff_sets_no_change(self): ], ), ] - self.assertEqual(ProtoEnum.diff_sets(set1, set1), []) + self.assertEqual(ProtoEnum.diff_sets(self.DEFAULT_PARENT, set1, set1), []) def test_diff_sets_all_removed(self): set1 = [] @@ -538,10 +541,11 @@ def test_diff_sets_all_removed(self): ], ), ] - diff = ProtoEnum.diff_sets(set1, set2) + diff = ProtoEnum.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( ProtoEnumRemoved( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("FooEnum"), [ @@ -556,6 +560,7 @@ def test_diff_sets_all_removed(self): ) self.assertIn( ProtoEnumRemoved( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("BarEnum"), [ @@ -570,6 +575,7 @@ def test_diff_sets_all_removed(self): ) self.assertIn( ProtoEnumRemoved( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("TagEnum"), [ @@ -615,10 +621,11 @@ def test_diff_sets_all_added(self): ), ] set2 = [] - diff = ProtoEnum.diff_sets(set1, set2) + diff = ProtoEnum.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( ProtoEnumAdded( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("FooEnum"), [ @@ -633,6 +640,7 @@ def test_diff_sets_all_added(self): ) self.assertIn( ProtoEnumAdded( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("BarEnum"), [ @@ -647,6 +655,7 @@ def test_diff_sets_all_added(self): ) self.assertIn( ProtoEnumAdded( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("TagEnum"), [ @@ -721,10 +730,11 @@ def test_diff_sets_mutually_exclusive(self): ), ] - diff = ProtoEnum.diff_sets(set1, set2) + diff = ProtoEnum.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( ProtoEnumAdded( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("FooEnum"), [ @@ -739,6 +749,7 @@ def test_diff_sets_mutually_exclusive(self): ) self.assertIn( ProtoEnumAdded( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("BarEnum"), [ @@ -754,6 +765,7 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumAdded( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("TagEnum"), [ @@ -769,6 +781,7 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumRemoved( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("FooEnum2"), [ @@ -784,6 +797,7 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumRemoved( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("BarEnum2"), [ @@ -799,6 +813,7 @@ def test_diff_sets_mutually_exclusive(self): self.assertIn( ProtoEnumRemoved( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("TagEnum2"), [ @@ -874,10 +889,11 @@ def test_diff_sets_overlap(self): ), ] - diff = ProtoEnum.diff_sets(set1, set2) + diff = ProtoEnum.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( ProtoEnumRemoved( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("FooEnum"), [ @@ -893,6 +909,7 @@ def test_diff_sets_overlap(self): self.assertIn( ProtoEnumRemoved( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("TagEnum"), [ @@ -907,6 +924,7 @@ def test_diff_sets_overlap(self): ) self.assertIn( ProtoEnumAdded( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("FooEnum2"), [ @@ -921,6 +939,7 @@ def test_diff_sets_overlap(self): ) self.assertIn( ProtoEnumAdded( + self.DEFAULT_PARENT, ProtoEnum( ProtoIdentifier("TagEnum2"), [ diff --git a/test/proto_message_test.py b/test/proto_message_test.py index 1eae4f6..963adfc 100644 --- a/test/proto_message_test.py +++ b/test/proto_message_test.py @@ -30,6 +30,8 @@ class MessageTest(unittest.TestCase): maxDiff = None + DEFAULT_PARENT = ProtoMessage(ProtoIdentifier("DefaultParent"), []) + def test_message_all_features(self): parsed_message_multiple_fields = ProtoMessage.match( dedent( @@ -518,7 +520,7 @@ def test_diff_same_message_returns_empty(self): ProtoIdentifier("MyMessage"), [], ) - self.assertEqual(ProtoMessage.diff(pm1, pm2), []) + self.assertEqual(ProtoMessage.diff(self.DEFAULT_PARENT, pm1, pm2), []) def test_diff_different_message_name_returns_empty(self): pm1 = ProtoMessage( @@ -529,15 +531,17 @@ def test_diff_different_message_name_returns_empty(self): ProtoIdentifier("OtherMessage"), [], ) - self.assertEqual(ProtoMessage.diff(pm1, pm2), []) + self.assertEqual(ProtoMessage.diff(self.DEFAULT_PARENT, pm1, pm2), []) - def test_diff_enum_added(self): + def test_diff_message_added(self): pm1 = None pm2 = ProtoMessage(ProtoIdentifier("MyMessage"), []) self.assertEqual( - ProtoMessage.diff(pm1, pm2), + ProtoMessage.diff(self.DEFAULT_PARENT, pm1, pm2), [ - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("MyMessage"), [])), + ProtoMessageAdded( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("MyMessage"), []) + ), ], ) @@ -545,16 +549,18 @@ def test_diff_message_removed(self): pm1 = ProtoMessage(ProtoIdentifier("MyMessage"), []) pm2 = None self.assertEqual( - ProtoMessage.diff(pm1, pm2), + ProtoMessage.diff(self.DEFAULT_PARENT, pm1, pm2), [ - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("MyMessage"), [])), + ProtoMessageRemoved( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("MyMessage"), []) + ), ], ) def test_diff_sets_empty_returns_empty(self): set1 = [] set2 = [] - self.assertEqual(ProtoMessage.diff_sets(set1, set2), []) + self.assertEqual(ProtoMessage.diff_sets(self.DEFAULT_PARENT, set1, set2), []) def test_diff_sets_no_change_returns_empty(self): set1 = [ @@ -562,7 +568,7 @@ def test_diff_sets_no_change_returns_empty(self): ProtoMessage(ProtoIdentifier("BarMessage"), []), ProtoMessage(ProtoIdentifier("BazMessage"), []), ] - self.assertEqual(ProtoMessage.diff_sets(set1, set1), []) + self.assertEqual(ProtoMessage.diff_sets(self.DEFAULT_PARENT, set1, set1), []) def test_diff_sets_all_removed(self): set1 = [ @@ -571,17 +577,23 @@ def test_diff_sets_all_removed(self): ProtoMessage(ProtoIdentifier("BazMessage"), []), ] set2 = [] - diff = ProtoMessage.diff_sets(set1, set2) + diff = ProtoMessage.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage"), [])), + ProtoMessageRemoved( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("FooMessage"), []) + ), diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BarMessage"), [])), + ProtoMessageRemoved( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BarMessage"), []) + ), diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage"), [])), + ProtoMessageRemoved( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BazMessage"), []) + ), diff, ) self.assertEqual(3, len(diff)) @@ -594,17 +606,23 @@ def test_diff_sets_all_added(self): ProtoMessage(ProtoIdentifier("BazMessage"), []), ] - diff = ProtoMessage.diff_sets(set1, set2) + diff = ProtoMessage.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage"), [])), + ProtoMessageAdded( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("FooMessage"), []) + ), diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BarMessage"), [])), + ProtoMessageAdded( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BarMessage"), []) + ), diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage"), [])), + ProtoMessageAdded( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BazMessage"), []) + ), diff, ) self.assertEqual(3, len(diff)) @@ -620,29 +638,41 @@ def test_diff_sets_mutually_exclusive(self): ProtoMessage(ProtoIdentifier("BarMessage2"), []), ProtoMessage(ProtoIdentifier("BazMessage2"), []), ] - diff = ProtoMessage.diff_sets(set1, set2) + diff = ProtoMessage.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage2"), [])), + ProtoMessageAdded( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("FooMessage2"), []) + ), diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BarMessage2"), [])), + ProtoMessageAdded( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BarMessage2"), []) + ), diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage2"), [])), + ProtoMessageAdded( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BazMessage2"), []) + ), diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage"), [])), + ProtoMessageRemoved( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("FooMessage"), []) + ), diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BarMessage"), [])), + ProtoMessageRemoved( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BarMessage"), []) + ), diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage"), [])), + ProtoMessageRemoved( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BazMessage"), []) + ), diff, ) self.assertEqual(6, len(diff)) @@ -659,21 +689,29 @@ def test_diff_sets_overlap(self): ProtoMessage(ProtoIdentifier("BarMessage"), []), ProtoMessage(ProtoIdentifier("BazMessage2"), []), ] - diff = ProtoMessage.diff_sets(set1, set2) + diff = ProtoMessage.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("FooMessage2"), [])), + ProtoMessageAdded( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("FooMessage2"), []) + ), diff, ) self.assertIn( - ProtoMessageAdded(ProtoMessage(ProtoIdentifier("BazMessage2"), [])), + ProtoMessageAdded( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BazMessage2"), []) + ), diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("FooMessage"), [])), + ProtoMessageRemoved( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("FooMessage"), []) + ), diff, ) self.assertIn( - ProtoMessageRemoved(ProtoMessage(ProtoIdentifier("BazMessage"), [])), + ProtoMessageRemoved( + self.DEFAULT_PARENT, ProtoMessage(ProtoIdentifier("BazMessage"), []) + ), diff, ) self.assertEqual(4, len(diff)) diff --git a/test/proto_oneof_test.py b/test/proto_oneof_test.py index 0f0eec3..fbcb350 100644 --- a/test/proto_oneof_test.py +++ b/test/proto_oneof_test.py @@ -7,10 +7,13 @@ from src.proto_int import ProtoInt, ProtoIntSign from src.proto_message_field import ( ProtoMessageField, + ProtoMessageFieldAdded, + ProtoMessageFieldNameChanged, ProtoMessageFieldOption, + ProtoMessageFieldRemoved, ProtoMessageFieldTypesEnum, ) -from src.proto_oneof import ProtoOneOf +from src.proto_oneof import ProtoOneOf, ProtoOneOfAdded, ProtoOneOfRemoved from src.proto_option import ProtoOption from src.proto_string_literal import ProtoStringLiteral @@ -18,6 +21,11 @@ class OneOfTest(unittest.TestCase): maxDiff = None + DEFAULT_PARENT = ProtoOneOf( + ProtoIdentifier("default_parent"), + [], + ) + def test_oneof_empty(self): parsed_oneof_empty = ProtoOneOf.match(dedent("oneof one_of_field {}".strip())) self.assertEqual( @@ -197,6 +205,255 @@ def test_oneof_normalize_removes_comment(self): ], ) + def test_diff_same_oneof_returns_empty(self): + po1 = ProtoOneOf( + ProtoIdentifier("my_one_of"), + [], + ) + po2 = ProtoOneOf( + ProtoIdentifier("my_one_of"), + [], + ) + self.assertEqual(ProtoOneOf.diff(self.DEFAULT_PARENT, po1, po2), []) + + def test_diff_different_oneof_name_returns_empty(self): + po1 = ProtoOneOf( + ProtoIdentifier("my_one_of"), + [], + ) + po2 = ProtoOneOf( + ProtoIdentifier("other_one_of"), + [], + ) + self.assertEqual(ProtoOneOf.diff(self.DEFAULT_PARENT, po1, po2), []) + + def test_diff_oneof_added(self): + po1 = None + po2 = ProtoOneOf(ProtoIdentifier("my_one_of"), []) + self.assertEqual( + ProtoOneOf.diff(self.DEFAULT_PARENT, po1, po2), + [ + ProtoOneOfAdded( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("my_one_of"), []) + ), + ], + ) + + def test_diff_oneof_removed(self): + po1 = ProtoOneOf(ProtoIdentifier("my_one_of"), []) + po2 = None + self.assertEqual( + [ + ProtoOneOfRemoved( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("my_one_of"), []) + ), + ], + ProtoOneOf.diff(self.DEFAULT_PARENT, po1, po2), + ) + + def test_diff_member_added(self): + po1 = ProtoOneOf(ProtoIdentifier("my_one_of"), []) + mf = ProtoMessageField( + ProtoMessageFieldTypesEnum.BOOL, + ProtoIdentifier("new_member"), + ProtoInt(1, ProtoIntSign.POSITIVE), + ) + po2 = ProtoOneOf(ProtoIdentifier("my_one_of"), [mf]) + self.assertEqual( + [ProtoMessageFieldAdded(po1, mf)], + ProtoOneOf.diff(self.DEFAULT_PARENT, po1, po2), + ) + + def test_diff_member_removed(self): + mf = ProtoMessageField( + ProtoMessageFieldTypesEnum.BOOL, + ProtoIdentifier("new_member"), + ProtoInt(1, ProtoIntSign.POSITIVE), + ) + po1 = ProtoOneOf(ProtoIdentifier("my_one_of"), [mf]) + po2 = ProtoOneOf(ProtoIdentifier("my_one_of"), []) + self.assertEqual( + [ProtoMessageFieldRemoved(po1, mf)], + ProtoOneOf.diff(self.DEFAULT_PARENT, po1, po2), + ) + + def test_diff_member_changed(self): + mf1 = ProtoMessageField( + ProtoMessageFieldTypesEnum.BOOL, + ProtoIdentifier("new_member"), + ProtoInt(1, ProtoIntSign.POSITIVE), + ) + po1 = ProtoOneOf(ProtoIdentifier("my_one_of"), [mf1]) + mf2 = ProtoMessageField( + ProtoMessageFieldTypesEnum.BOOL, + ProtoIdentifier("new_member_changed"), + ProtoInt(1, ProtoIntSign.POSITIVE), + ) + po2 = ProtoOneOf(ProtoIdentifier("my_one_of"), [mf2]) + self.assertEqual( + [ProtoMessageFieldNameChanged(po1, mf1, mf2.name)], + ProtoOneOf.diff(self.DEFAULT_PARENT, po1, po2), + ) + + def test_diff_sets_empty_returns_empty(self): + set1 = [] + set2 = [] + self.assertEqual(ProtoOneOf.diff_sets(self.DEFAULT_PARENT, set1, set2), []) + + def test_diff_sets_no_change_returns_empty(self): + set1 = [ + ProtoOneOf(ProtoIdentifier("foo_one_of"), []), + ProtoOneOf(ProtoIdentifier("bar_one_of"), []), + ProtoOneOf(ProtoIdentifier("baz_one_of"), []), + ] + self.assertEqual(ProtoOneOf.diff_sets(self.DEFAULT_PARENT, set1, set1), []) + + def test_diff_sets_all_removed(self): + set1 = [ + ProtoOneOf(ProtoIdentifier("foo_one_of"), []), + ProtoOneOf(ProtoIdentifier("bar_one_of"), []), + ProtoOneOf(ProtoIdentifier("baz_one_of"), []), + ] + set2 = [] + diff = ProtoOneOf.diff_sets(self.DEFAULT_PARENT, set1, set2) + self.assertIn( + ProtoOneOfRemoved( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("foo_one_of"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfRemoved( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("bar_one_of"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfRemoved( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("baz_one_of"), []) + ), + diff, + ) + self.assertEqual(3, len(diff)) + + def test_diff_sets_all_added(self): + set1 = [] + set2 = [ + ProtoOneOf(ProtoIdentifier("foo_one_of"), []), + ProtoOneOf(ProtoIdentifier("bar_one_of"), []), + ProtoOneOf(ProtoIdentifier("baz_one_of"), []), + ] + + diff = ProtoOneOf.diff_sets(self.DEFAULT_PARENT, set1, set2) + self.assertIn( + ProtoOneOfAdded( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("foo_one_of"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfAdded( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("bar_one_of"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfAdded( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("baz_one_of"), []) + ), + diff, + ) + self.assertEqual(3, len(diff)) + + def test_diff_sets_mutually_exclusive(self): + set1 = [ + ProtoOneOf(ProtoIdentifier("foo_one_of"), []), + ProtoOneOf(ProtoIdentifier("bar_one_of"), []), + ProtoOneOf(ProtoIdentifier("baz_one_of"), []), + ] + set2 = [ + ProtoOneOf(ProtoIdentifier("foo_one_of2"), []), + ProtoOneOf(ProtoIdentifier("bar_one_of2"), []), + ProtoOneOf(ProtoIdentifier("baz_one_of2"), []), + ] + diff = ProtoOneOf.diff_sets(self.DEFAULT_PARENT, set1, set2) + self.assertIn( + ProtoOneOfAdded( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("foo_one_of2"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfAdded( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("bar_one_of2"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfAdded( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("baz_one_of2"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfRemoved( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("foo_one_of"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfRemoved( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("bar_one_of"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfRemoved( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("baz_one_of"), []) + ), + diff, + ) + self.assertEqual(6, len(diff)) + + def test_diff_sets_overlap(self): + + set1 = [ + ProtoOneOf(ProtoIdentifier("foo_one_of"), []), + ProtoOneOf(ProtoIdentifier("bar_one_of"), []), + ProtoOneOf(ProtoIdentifier("baz_one_of"), []), + ] + set2 = [ + ProtoOneOf(ProtoIdentifier("foo_one_of2"), []), + ProtoOneOf(ProtoIdentifier("bar_one_of"), []), + ProtoOneOf(ProtoIdentifier("baz_one_of2"), []), + ] + diff = ProtoOneOf.diff_sets(self.DEFAULT_PARENT, set1, set2) + self.assertIn( + ProtoOneOfAdded( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("foo_one_of2"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfAdded( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("baz_one_of2"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfRemoved( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("foo_one_of"), []) + ), + diff, + ) + self.assertIn( + ProtoOneOfRemoved( + self.DEFAULT_PARENT, ProtoOneOf(ProtoIdentifier("baz_one_of"), []) + ), + diff, + ) + self.assertEqual(4, len(diff)) + if __name__ == "__main__": unittest.main() diff --git a/test/proto_option_test.py b/test/proto_option_test.py index b6a90a2..f7a6a00 100644 --- a/test/proto_option_test.py +++ b/test/proto_option_test.py @@ -17,6 +17,10 @@ class OptionTest(unittest.TestCase): maxDiff = None + DEFAULT_PARENT = ProtoOption( + ProtoIdentifier("default.parent"), + ProtoConstant(ProtoInt(1, ProtoIntSign.POSITIVE)), + ) def test_string_option(self): string_option = ProtoOption.match("option foo = 'test value';") @@ -215,7 +219,7 @@ def test_diff_same_option_returns_empty(self): ProtoIdentifier("some.custom.option"), ProtoConstant(ProtoStringLiteral("some value")), ) - self.assertEqual(ProtoOption.diff(po1, po2), []) + self.assertEqual(ProtoOption.diff(self.DEFAULT_PARENT, po1, po2), []) def test_diff_different_option_name_returns_empty(self): po1 = ProtoOption( @@ -226,7 +230,7 @@ def test_diff_different_option_name_returns_empty(self): ProtoIdentifier("other.option"), ProtoConstant(ProtoStringLiteral("some value")), ) - self.assertEqual(ProtoOption.diff(po1, po2), []) + self.assertEqual(ProtoOption.diff(self.DEFAULT_PARENT, po1, po2), []) def test_diff_different_option_value_returns_option_diff(self): po1 = ProtoOption( @@ -238,9 +242,10 @@ def test_diff_different_option_value_returns_option_diff(self): ProtoConstant(ProtoStringLiteral("other value")), ) self.assertEqual( - ProtoOption.diff(po1, po2), + ProtoOption.diff(self.DEFAULT_PARENT, po1, po2), [ ProtoOptionValueChanged( + self.DEFAULT_PARENT, ProtoIdentifier("some.custom.option"), ProtoConstant(ProtoStringLiteral("some value")), ProtoConstant(ProtoStringLiteral("other value")), @@ -255,13 +260,14 @@ def test_diff_option_added(self): ProtoConstant(ProtoStringLiteral("some value")), ) self.assertEqual( - ProtoOption.diff(po1, po2), + ProtoOption.diff(self.DEFAULT_PARENT, po1, po2), [ ProtoOptionAdded( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("some.custom.option"), ProtoConstant(ProtoStringLiteral("some value")), - ) + ), ), ], ) @@ -273,13 +279,14 @@ def test_diff_option_removed(self): ) po2 = None self.assertEqual( - ProtoOption.diff(po1, po2), + ProtoOption.diff(self.DEFAULT_PARENT, po1, po2), [ ProtoOptionRemoved( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("some.custom.option"), ProtoConstant(ProtoStringLiteral("some value")), - ) + ), ), ], ) @@ -287,7 +294,7 @@ def test_diff_option_removed(self): def test_diff_sets_empty_returns_empty(self): set1 = [] set2 = [] - self.assertEqual(ProtoOption.diff_sets(set1, set2), []) + self.assertEqual(ProtoOption.diff_sets(self.DEFAULT_PARENT, set1, set2), []) def test_diff_sets_no_change(self): set1 = [ @@ -304,7 +311,7 @@ def test_diff_sets_no_change(self): ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ), ] - self.assertEqual(ProtoOption.diff_sets(set1, set1), []) + self.assertEqual(ProtoOption.diff_sets(self.DEFAULT_PARENT, set1, set1), []) def test_diff_sets_all_removed(self): set1 = [ @@ -322,32 +329,35 @@ def test_diff_sets_all_removed(self): ), ] set2 = [] - diff = ProtoOption.diff_sets(set1, set2) + diff = ProtoOption.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( ProtoOptionRemoved( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("some.custom.option"), ProtoConstant(ProtoStringLiteral("some value")), - ) + ), ), diff, ) self.assertIn( ProtoOptionRemoved( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("java_package"), ProtoConstant(ProtoStringLiteral("foo.bar.baz")), - ) + ), ), diff, ) self.assertIn( ProtoOptionRemoved( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("other.option"), ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), - ) + ), ), diff, ) @@ -369,32 +379,35 @@ def test_diff_sets_all_added(self): ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), ), ] - diff = ProtoOption.diff_sets(set1, set2) + diff = ProtoOption.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( ProtoOptionAdded( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("some.custom.option"), ProtoConstant(ProtoStringLiteral("some value")), - ) + ), ), diff, ) self.assertIn( ProtoOptionAdded( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("java_package"), ProtoConstant(ProtoStringLiteral("foo.bar.baz")), - ) + ), ), diff, ) self.assertIn( ProtoOptionAdded( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("other.option"), ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), - ) + ), ), diff, ) @@ -430,63 +443,69 @@ def test_diff_sets_mutually_exclusive(self): ), ] - diff = ProtoOption.diff_sets(set1, set2) + diff = ProtoOption.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( ProtoOptionAdded( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("some.custom.option.but.not.prior"), ProtoConstant(ProtoStringLiteral("some value")), - ) + ), ), diff, ) self.assertIn( ProtoOptionAdded( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("other.option.but.stil.not.prior"), ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), - ) + ), ), diff, ) self.assertIn( ProtoOptionAdded( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("ruby_package"), ProtoConstant(ProtoStringLiteral("foo.bar.baz")), - ) + ), ), diff, ) self.assertIn( ProtoOptionRemoved( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("other.option"), ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), - ) + ), ), diff, ) self.assertIn( ProtoOptionRemoved( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("some.custom.option"), ProtoConstant(ProtoStringLiteral("some value")), - ) + ), ), diff, ) self.assertIn( ProtoOptionRemoved( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("java_package"), ProtoConstant(ProtoStringLiteral("foo.bar.baz")), - ) + ), ), diff, ) @@ -523,47 +542,52 @@ def test_diff_sets_overlap(self): ), ] - diff = ProtoOption.diff_sets(set1, set2) + diff = ProtoOption.diff_sets(self.DEFAULT_PARENT, set1, set2) self.assertIn( ProtoOptionRemoved( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("some.custom.option"), ProtoConstant(ProtoStringLiteral("some value")), - ) + ), ), diff, ) self.assertIn( ProtoOptionRemoved( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("other.option"), ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), - ) + ), ), diff, ) self.assertIn( ProtoOptionAdded( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("some.custom.option.but.not.prior"), ProtoConstant(ProtoStringLiteral("some value")), - ) + ), ), diff, ) self.assertIn( ProtoOptionAdded( + self.DEFAULT_PARENT, ProtoOption( ProtoIdentifier("other.option.but.stil.not.prior"), ProtoConstant(ProtoInt(100, ProtoIntSign.POSITIVE)), - ) + ), ), diff, ) self.assertIn( ProtoOptionValueChanged( + self.DEFAULT_PARENT, ProtoIdentifier("java_package"), ProtoConstant(ProtoStringLiteral("foo.bar.baz")), ProtoConstant(ProtoStringLiteral("foo.bar.bat")), From f2049fdcfe9890125a7db2d52048385b30111472 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sat, 11 Mar 2023 01:47:11 -0400 Subject: [PATCH 23/35] Make generic proto container class (#80) --- src/proto_enum.py | 74 +++++++++++-------------------- src/proto_extend.py | 68 +++++++++++------------------ src/proto_message.py | 91 +++++++++++++++----------------------- src/proto_node.py | 102 ++++++++++++++++++++++++++++++++++++++++++- src/proto_oneof.py | 99 +++++++++++++++++------------------------ src/proto_service.py | 84 +++++++++++++++-------------------- 6 files changed, 264 insertions(+), 254 deletions(-) diff --git a/src/proto_enum.py b/src/proto_enum.py index a37bd07..986769a 100644 --- a/src/proto_enum.py +++ b/src/proto_enum.py @@ -5,10 +5,10 @@ ProtoMultiLineComment, ProtoSingleLineComment, ) -from src.proto_identifier import ProtoIdentifier +from src.proto_identifier import ParsedProtoIdentifierNode, ProtoIdentifier from src.proto_int import ProtoInt, ProtoIntSign -from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff -from src.proto_option import ParsedProtoOptionNode, ProtoOption, ProtoOptionDiff +from src.proto_node import ParsedProtoNode, ProtoContainerNode, ProtoNode, ProtoNodeDiff +from src.proto_option import ParsedProtoOptionNode, ProtoOption from src.proto_reserved import ProtoReserved @@ -212,20 +212,17 @@ def diff_sets( return diffs -class ProtoEnum(ProtoNode): - def __init__(self, name: ProtoIdentifier, nodes: list[ProtoNode], *args, **kwargs): +class ProtoEnum(ProtoContainerNode): + def __init__(self, name: ProtoIdentifier, *args, **kwargs): super().__init__(*args, **kwargs) self.name = name self.name.parent = self - self.nodes = nodes - for option in self.options: - option.parent = self def __eq__(self, other: object) -> bool: return ( isinstance(other, ProtoEnum) + and super().__eq__(other) and self.name == other.name - and self.nodes == other.nodes ) def __str__(self) -> str: @@ -244,34 +241,22 @@ def normalize(self) -> "ProtoEnum": parent=self.parent, ) - @staticmethod - def parse_partial_content(partial_enum_content: str) -> ParsedProtoNode: - supported_types: list[type[ProtoNode]] = [ + @classmethod + def container_types(cls) -> list[type[ProtoNode]]: + return [ ProtoSingleLineComment, ProtoMultiLineComment, ProtoOption, ProtoReserved, ProtoEnumValue, ] - for node_type in supported_types: - try: - match_result = node_type.match( - proto_source=partial_enum_content, parent=None - ) - except (ValueError, IndexError, TypeError): - raise ValueError( - f"Could not parse partial enum content:\n{partial_enum_content}" - ) - if match_result is not None: - return match_result - raise ValueError( - f"Could not parse partial enum content:\n{partial_enum_content}" - ) @classmethod - def match( - cls, proto_source: str, parent: Optional[ProtoNode] = None - ) -> Optional["ParsedProtoNode"]: + def match_header( + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, + ) -> Optional["ParsedProtoIdentifierNode"]: if not proto_source.startswith("enum "): return None @@ -288,25 +273,18 @@ def match( f"Proto has invalid syntax, expecting opening curly brace: {proto_source}" ) - proto_source = proto_source[1:].strip() - parsed_tree = [] - while proto_source: - # Remove empty statements. - if proto_source.startswith(";"): - proto_source = proto_source[1:].strip() - continue - - if proto_source.startswith("}"): - proto_source = proto_source[1:].strip() - break - - match_result = ProtoEnum.parse_partial_content(proto_source) - parsed_tree.append(match_result.node) - proto_source = match_result.remaining_source.strip() - - return ParsedProtoNode( - ProtoEnum(name=enum_name, nodes=parsed_tree, parent=parent), proto_source - ) + return ParsedProtoIdentifierNode(enum_name, proto_source[1:].strip()) + + @classmethod + def construct( + cls, + header_match: ParsedProtoNode, + contained_nodes: list[ProtoNode], + footer_match: str, + parent: Optional[ProtoNode] = None, + ) -> ProtoNode: + assert isinstance(header_match, ParsedProtoIdentifierNode) + return ProtoEnum(name=header_match.node, nodes=contained_nodes, parent=parent) @property def options(self) -> list[ProtoOption]: diff --git a/src/proto_extend.py b/src/proto_extend.py index ece3e23..007a942 100644 --- a/src/proto_extend.py +++ b/src/proto_extend.py @@ -5,28 +5,27 @@ ProtoMultiLineComment, ProtoSingleLineComment, ) -from src.proto_identifier import ProtoEnumOrMessageIdentifier +from src.proto_identifier import ( + ParsedProtoEnumOrMessageIdentifierNode, + ProtoEnumOrMessageIdentifier, +) from src.proto_message_field import ProtoMessageField -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_node import ParsedProtoNode, ProtoContainerNode, ProtoNode -class ProtoExtend(ProtoNode): +class ProtoExtend(ProtoContainerNode): def __init__( self, name: ProtoEnumOrMessageIdentifier, - nodes: list[ProtoNode], *args, **kwargs, ): super().__init__(*args, **kwargs) self.name = name self.name.parent = self - self.nodes = nodes - for node in self.nodes: - node.parent = self def __eq__(self, other) -> bool: - return self.name == other.name and self.nodes == other.nodes + return super().__eq__(other) and self.name == other.name def __str__(self) -> str: return f"" @@ -44,28 +43,20 @@ def normalize(self) -> "ProtoExtend": parent=self.parent, ) - @staticmethod - def parse_partial_content(partial_content: str) -> ParsedProtoNode: - supported_types: list[type[ProtoNode]] = [ + @classmethod + def container_types(cls) -> list[type[ProtoNode]]: + return [ ProtoSingleLineComment, ProtoMultiLineComment, ProtoMessageField, ] - for node_type in supported_types: - try: - match_result = node_type.match(partial_content) - except (ValueError, IndexError, TypeError): - raise ValueError( - f"Could not parse partial extend content:\n{partial_content}" - ) - if match_result is not None: - return match_result - raise ValueError(f"Could not parse partial extend content:\n{partial_content}") @classmethod - def match( - cls, proto_source: str, parent: Optional[ProtoNode] = None - ) -> Optional["ParsedProtoNode"]: + def match_header( + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, + ) -> Optional["ParsedProtoEnumOrMessageIdentifierNode"]: if not proto_source.startswith("extend "): return None @@ -82,25 +73,18 @@ def match( f"Proto extend has invalid syntax, expecting opening curly brace: {proto_source}" ) - proto_source = proto_source[1:].strip() - parsed_tree = [] - while proto_source: - # Remove empty statements. - if proto_source.startswith(";"): - proto_source = proto_source[1:].strip() - continue - - if proto_source.startswith("}"): - proto_source = proto_source[1:].strip() - break + return ParsedProtoEnumOrMessageIdentifierNode(name, proto_source[1:].strip()) - match_result = ProtoExtend.parse_partial_content(proto_source) - parsed_tree.append(match_result.node) - proto_source = match_result.remaining_source.strip() - - return ParsedProtoNode( - ProtoExtend(name=name, nodes=parsed_tree, parent=parent), proto_source - ) + @classmethod + def construct( + cls, + header_match: ParsedProtoNode, + contained_nodes: list[ProtoNode], + footer_match: str, + parent: Optional[ProtoNode] = None, + ) -> ProtoNode: + assert isinstance(header_match, ParsedProtoEnumOrMessageIdentifierNode) + return ProtoExtend(name=header_match.node, nodes=contained_nodes, parent=parent) def serialize(self) -> str: serialize_parts = ( diff --git a/src/proto_message.py b/src/proto_message.py index 8776aaf..6e261c0 100644 --- a/src/proto_message.py +++ b/src/proto_message.py @@ -8,32 +8,28 @@ from src.proto_enum import ProtoEnum from src.proto_extend import ProtoExtend from src.proto_extensions import ProtoExtensions -from src.proto_identifier import ProtoIdentifier +from src.proto_identifier import ParsedProtoIdentifierNode, ProtoIdentifier from src.proto_map import ProtoMap from src.proto_message_field import ProtoMessageField -from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff +from src.proto_node import ParsedProtoNode, ProtoContainerNode, ProtoNode, ProtoNodeDiff from src.proto_oneof import ProtoOneOf from src.proto_option import ProtoOption from src.proto_reserved import ProtoReserved -class ProtoMessage(ProtoNode): +class ProtoMessage(ProtoContainerNode): def __init__( self, name: ProtoIdentifier, - nodes: Sequence[ProtoNode], *args, **kwargs, ): super().__init__(*args, **kwargs) self.name = name self.name.parent = self - self.nodes = nodes - for node in self.nodes: - node.parent = self def __eq__(self, other) -> bool: - return self.name == other.name and self.nodes == other.nodes + return super().__eq__(other) and self.name == other.name def __str__(self) -> str: return f"" @@ -85,38 +81,12 @@ def normalize(self) -> "ProtoMessage": parent=self.parent, ) - @staticmethod - def parse_partial_content(partial_message_content: str) -> ParsedProtoNode: - supported_types: list[type[ProtoNode]] = [ - ProtoSingleLineComment, - ProtoMultiLineComment, - ProtoEnum, - ProtoExtend, - ProtoExtensions, - ProtoOption, - ProtoMessage, - ProtoReserved, - ProtoMessageField, - ProtoOneOf, - ProtoMap, - ] - for node_type in supported_types: - try: - match_result = node_type.match(partial_message_content) - except (ValueError, IndexError, TypeError): - raise ValueError( - f"Could not parse partial message content:\n{partial_message_content}" - ) - if match_result is not None: - return match_result - raise ValueError( - f"Could not parse partial message content:\n{partial_message_content}" - ) - @classmethod - def match( - cls, proto_source: str, parent: Optional[ProtoNode] = None - ) -> Optional["ParsedProtoNode"]: + def match_header( + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, + ) -> Optional["ParsedProtoIdentifierNode"]: if not proto_source.startswith("message "): return None @@ -133,24 +103,35 @@ def match( f"Proto message has invalid syntax, expecting opening curly brace: {proto_source}" ) - proto_source = proto_source[1:].strip() - parsed_tree = [] - while proto_source: - # Remove empty statements. - if proto_source.startswith(";"): - proto_source = proto_source[1:].strip() - continue + return ParsedProtoIdentifierNode(enum_name, proto_source[1:].strip()) - if proto_source.startswith("}"): - proto_source = proto_source[1:].strip() - break - - match_result = ProtoMessage.parse_partial_content(proto_source) - parsed_tree.append(match_result.node) - proto_source = match_result.remaining_source.strip() + @classmethod + def container_types(cls) -> list[type[ProtoNode]]: + return [ + ProtoSingleLineComment, + ProtoMultiLineComment, + ProtoEnum, + ProtoExtend, + ProtoExtensions, + ProtoOption, + ProtoMessage, + ProtoReserved, + ProtoMessageField, + ProtoOneOf, + ProtoMap, + ] - return ParsedProtoNode( - ProtoMessage(name=enum_name, nodes=parsed_tree, parent=parent), proto_source + @classmethod + def construct( + cls, + header_match: ParsedProtoNode, + contained_nodes: list[ProtoNode], + footer_match: str, + parent: Optional[ProtoNode] = None, + ) -> ProtoNode: + assert isinstance(header_match, ParsedProtoIdentifierNode) + return ProtoMessage( + name=header_match.node, nodes=contained_nodes, parent=parent ) @property diff --git a/src/proto_node.py b/src/proto_node.py index 5647cb6..f69c3f4 100644 --- a/src/proto_node.py +++ b/src/proto_node.py @@ -1,5 +1,5 @@ import abc -from typing import NamedTuple, Optional +from typing import NamedTuple, Optional, Sequence class ProtoNode(abc.ABC): @@ -24,6 +24,106 @@ def normalize(self) -> Optional["ProtoNode"]: raise NotImplementedError +class ProtoContainerNode(ProtoNode): + def __init__( + self, + nodes: Sequence[ProtoNode], + *args, + **kwargs, + ): + super().__init__(*args, **kwargs) + self.nodes = nodes + for node in self.nodes: + node.parent = self + + def __eq__(self, other) -> bool: + return self.nodes == other.nodes + + @classmethod + @abc.abstractmethod + def match_header( + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, + ) -> Optional["ParsedProtoNode"]: + raise NotImplementedError + + @classmethod + def match_footer( + cls, + proto_source: str, + parent: Optional[ProtoNode] = None, + ) -> Optional[str]: + if proto_source.startswith("}"): + return proto_source[1:].strip() + + return None + + @classmethod + @abc.abstractmethod + def container_types(cls) -> list[type[ProtoNode]]: + raise NotImplementedError + + @classmethod + @abc.abstractmethod + def construct( + cls, + header_match: "ParsedProtoNode", + contained_nodes: list[ProtoNode], + footer_match: str, + parent: Optional[ProtoNode] = None, + ) -> ProtoNode: + raise NotImplementedError + + @classmethod + def parse_partial_content(cls, partial_content: str) -> "ParsedProtoNode": + for node_type in cls.container_types(): + try: + match_result = node_type.match(partial_content) + except (ValueError, IndexError, TypeError): + raise ValueError(f"Could not parse partial content:\n{partial_content}") + if match_result is not None: + return match_result + raise ValueError(f"Could not parse partial content:\n{partial_content}") + + @classmethod + def match( + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, + ) -> Optional["ParsedProtoNode"]: + header_match = cls.match_header(proto_source, parent=parent) + if header_match is None: + return None + + proto_source = header_match.remaining_source.strip() + nodes = [] + while proto_source: + # Remove empty statements. + if proto_source.startswith(";"): + proto_source = proto_source[1:].strip() + continue + + footer_match = cls.match_footer(proto_source, parent) + if footer_match is not None: + proto_source = footer_match.strip() + break + + match_result = cls.parse_partial_content(proto_source) + nodes.append(match_result.node) + proto_source = match_result.remaining_source.strip() + + if footer_match is None: + raise ValueError( + f"Footer was not found when matching container node {cls} for remaining proto source {proto_source}" + ) + + return ParsedProtoNode( + cls.construct(header_match, nodes, footer_match, parent=parent), + proto_source.strip(), + ) + + class ParsedProtoNode(NamedTuple): node: ProtoNode remaining_source: str diff --git a/src/proto_oneof.py b/src/proto_oneof.py index b71c264..50493d3 100644 --- a/src/proto_oneof.py +++ b/src/proto_oneof.py @@ -7,10 +7,10 @@ ProtoMultiLineComment, ProtoSingleLineComment, ) -from src.proto_identifier import ProtoIdentifier +from src.proto_identifier import ParsedProtoIdentifierNode, ProtoIdentifier from src.proto_map import ProtoMap from src.proto_message_field import ParsedProtoMessageFieldNode, ProtoMessageField -from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff +from src.proto_node import ParsedProtoNode, ProtoContainerNode, ProtoNode, ProtoNodeDiff from src.proto_option import ParsedProtoOptionNode, ProtoOption ProtoOneOfNodeTypes = ( @@ -29,23 +29,19 @@ class ParsedProtoOneOfNode(ParsedProtoNode): remaining_source: str -class ProtoOneOf(ProtoNode): +class ProtoOneOf(ProtoContainerNode): def __init__( self, name: ProtoIdentifier, - nodes: Sequence[ProtoOneOfNodeTypes], *args, **kwargs, ): super().__init__(*args, **kwargs) self.name = name self.name.parent = self - self.nodes = nodes - for node in self.nodes: - node.parent = self def __eq__(self, other) -> bool: - return self.name == other.name and self.nodes == other.nodes + return super().__eq__(other) and self.name == other.name def __str__(self) -> str: return f"<{self.__class__.__name__} name={self.name}, nodes={self.nodes}>" @@ -58,56 +54,39 @@ def normalize(self) -> "ProtoOneOf": lambda n: not isinstance(n, ProtoComment), self.nodes ) options = [] - fields = [] + fields: list[ProtoMessageField | ProtoMap] = [] + oneofs: list[ProtoOneOf] = [] for node in non_comment_nodes: if isinstance(node, ProtoOption): options.append(node.normalize()) - elif ( - isinstance(node, ProtoMessageField) - or isinstance(node, ProtoOneOf) - or isinstance(node, ProtoMap) - ): + elif isinstance(node, ProtoMessageField) or isinstance(node, ProtoMap): fields.append(node.normalize()) + elif isinstance(node, ProtoOneOf): + oneofs.append(node.normalize()) else: raise ValueError( f"Can't sort message {self} node for normalizing: {node}" ) - sorted_nodes_for_normalizing = sorted( - options, key=lambda o: str(o.normalize()) - ) + sorted(fields, key=lambda f: int(f.number)) + sorted_options = sorted(options, key=lambda o: str(o.normalize())) + sorted_fields = sorted(fields, key=lambda f: int(f.number)) + sorted_oneofs = sorted( + oneofs, + key=lambda x: min(int(f.number) for f in x.message_fields), + ) return ProtoOneOf( name=self.name, - nodes=sorted_nodes_for_normalizing, + nodes=(sorted_options + sorted_fields + sorted_oneofs), parent=self.parent, ) - @staticmethod - def parse_partial_content(partial_oneof_content: str) -> ProtoParsedOneOfNodeTypes: - supported_types: list[type[ProtoOneOfNodeTypes]] = [ - ProtoMessageField, - ProtoOption, - ProtoSingleLineComment, - ProtoMultiLineComment, - ] - for node_type in supported_types: - try: - match_result = node_type.match(partial_oneof_content) - except (ValueError, IndexError, TypeError): - raise ValueError( - f"Could not parse partial oneof content:\n{partial_oneof_content}" - ) - if match_result is not None: - return match_result - raise ValueError( - f"Could not parse partial oneof content:\n{partial_oneof_content}" - ) - @classmethod - def match( - cls, proto_source: str, parent: Optional[ProtoNode] = None - ) -> Optional["ParsedProtoOneOfNode"]: + def match_header( + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, + ) -> Optional["ParsedProtoIdentifierNode"]: if not proto_source.startswith("oneof "): return None @@ -127,25 +106,27 @@ def match( f"Proto has invalid syntax, expecting opening curly brace: {proto_source}" ) - proto_source = proto_source[1:].strip() - parsed_tree = [] - while proto_source: - # Remove empty statements. - if proto_source.startswith(";"): - proto_source = proto_source[1:].strip() - continue - - if proto_source.startswith("}"): - proto_source = proto_source[1:].strip() - break + return ParsedProtoIdentifierNode(oneof_name, proto_source[1:].strip()) - match_result = ProtoOneOf.parse_partial_content(proto_source) - parsed_tree.append(match_result.node) - proto_source = match_result.remaining_source.strip() + @classmethod + def container_types(cls) -> list[type[ProtoNode]]: + return [ + ProtoMessageField, + ProtoOption, + ProtoSingleLineComment, + ProtoMultiLineComment, + ] - return ParsedProtoOneOfNode( - ProtoOneOf(name=oneof_name, nodes=parsed_tree, parent=parent), proto_source - ) + @classmethod + def construct( + cls, + header_match: ParsedProtoNode, + contained_nodes: list[ProtoNode], + footer_match: str, + parent: Optional[ProtoNode] = None, + ) -> ProtoNode: + assert isinstance(header_match, ParsedProtoIdentifierNode) + return ProtoOneOf(name=header_match.node, nodes=contained_nodes, parent=parent) @property def options(self) -> list[ProtoOption]: diff --git a/src/proto_service.py b/src/proto_service.py index d408849..26f7d17 100644 --- a/src/proto_service.py +++ b/src/proto_service.py @@ -5,8 +5,12 @@ ProtoMultiLineComment, ProtoSingleLineComment, ) -from src.proto_identifier import ProtoEnumOrMessageIdentifier, ProtoIdentifier -from src.proto_node import ParsedProtoNode, ProtoNode +from src.proto_identifier import ( + ParsedProtoIdentifierNode, + ProtoEnumOrMessageIdentifier, + ProtoIdentifier, +) +from src.proto_node import ParsedProtoNode, ProtoContainerNode, ProtoNode from src.proto_option import ProtoOption @@ -218,17 +222,14 @@ def serialize(self) -> str: return " ".join(serialized_parts) + ";" -class ProtoService(ProtoNode): - def __init__(self, name: ProtoIdentifier, nodes: list[ProtoNode], *args, **kwargs): +class ProtoService(ProtoContainerNode): + def __init__(self, name: ProtoIdentifier, *args, **kwargs): super().__init__(*args, **kwargs) self.name = name self.name.parent = self - self.nodes = nodes - for node in self.nodes: - node.parent = self def __eq__(self, other) -> bool: - return self.name == other.name and self.nodes == other.nodes + return super().__eq__(other) and self.name == other.name def __str__(self) -> str: return f"" @@ -246,31 +247,12 @@ def normalize(self) -> "ProtoService": parent=self.parent, ) - @staticmethod - def parse_partial_content(partial_service_content: str) -> ParsedProtoNode: - supported_types: list[type[ProtoNode]] = [ - ProtoOption, - ProtoServiceRPC, - ProtoSingleLineComment, - ProtoMultiLineComment, - ] - for node_type in supported_types: - try: - match_result = node_type.match(partial_service_content) - except (ValueError, IndexError, TypeError): - raise ValueError( - f"Could not parse partial service content:\n{partial_service_content}" - ) - if match_result is not None: - return match_result - raise ValueError( - f"Could not parse partial service content:\n{partial_service_content}" - ) - @classmethod - def match( - cls, proto_source: str, parent: Optional[ProtoNode] = None - ) -> Optional["ParsedProtoNode"]: + def match_header( + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, + ) -> Optional["ParsedProtoIdentifierNode"]: if not proto_source.startswith("service "): return None @@ -279,7 +261,7 @@ def match( if match is None: raise ValueError(f"Proto has invalid service name: {proto_source}") - enum_name = match.node + service_name = match.node proto_source = match.remaining_source.strip() if not proto_source.startswith("{"): @@ -287,24 +269,28 @@ def match( f"Proto service has invalid syntax, expecting opening curly brace: {proto_source}" ) - proto_source = proto_source[1:].strip() - parsed_tree = [] - while proto_source: - # Remove empty statements. - if proto_source.startswith(";"): - proto_source = proto_source[1:].strip() - continue - - if proto_source.startswith("}"): - proto_source = proto_source[1:].strip() - break + return ParsedProtoIdentifierNode(service_name, proto_source[1:].strip()) - match_result = ProtoService.parse_partial_content(proto_source) - parsed_tree.append(match_result.node) - proto_source = match_result.remaining_source.strip() + @classmethod + def container_types(cls) -> list[type[ProtoNode]]: + return [ + ProtoOption, + ProtoServiceRPC, + ProtoSingleLineComment, + ProtoMultiLineComment, + ] - return ParsedProtoNode( - ProtoService(name=enum_name, nodes=parsed_tree, parent=parent), proto_source + @classmethod + def construct( + cls, + header_match: ParsedProtoNode, + contained_nodes: list[ProtoNode], + footer_match: str, + parent: Optional[ProtoNode] = None, + ) -> ProtoNode: + assert isinstance(header_match, ParsedProtoIdentifierNode) + return ProtoService( + name=header_match.node, nodes=contained_nodes, parent=parent ) @property From 8aa68dcf7015e52a8c0edeb9bd8ccf6870f46c8b Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Sat, 11 Mar 2023 02:56:10 -0400 Subject: [PATCH 24/35] Make ProtoFile a container type (#81) --- src/proto_file.py | 111 ++++++++++++++++++++++++++++++--------------- src/proto_node.py | 9 ++-- src/util/parser.py | 5 +- 3 files changed, 82 insertions(+), 43 deletions(-) diff --git a/src/proto_file.py b/src/proto_file.py index 0b72760..94d793a 100644 --- a/src/proto_file.py +++ b/src/proto_file.py @@ -9,7 +9,7 @@ from src.proto_extend import ProtoExtend from src.proto_import import ProtoImport from src.proto_message import ProtoMessage -from src.proto_node import ParsedProtoNode, ProtoNode, ProtoNodeDiff +from src.proto_node import ParsedProtoNode, ProtoContainerNode, ProtoNode, ProtoNodeDiff from src.proto_option import ProtoOption from src.proto_package import ProtoPackage from src.proto_service import ProtoService @@ -21,13 +21,40 @@ class ParsedProtoFileNode(ParsedProtoNode): remaining_source: str -class ProtoFile(ProtoNode): - def __init__(self, syntax: ProtoSyntax, nodes: list[ProtoNode], *args, **kwargs): +class ProtoFileHeaderNode(ProtoNode): + def __init__( + self, header_nodes: list[ProtoNode], syntax: ProtoSyntax, *args, **kwargs + ): super().__init__(*args, **kwargs) + self.header_nodes = header_nodes self.syntax = syntax - self.nodes = nodes - if len([node for node in nodes if isinstance(node, ProtoPackage)]) > 1: + @classmethod + def match( + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, + ) -> Optional["ParsedProtoNode"]: + pass + + def serialize(self) -> str: + raise NotImplementedError + + def normalize(self) -> Optional["ProtoNode"]: + raise NotImplementedError + + +class ParsedProtoFileHeaderNode(ParsedProtoNode): + node: "ProtoFileHeaderNode" + remaining_source: str + + +class ProtoFile(ProtoContainerNode): + def __init__(self, syntax: ProtoSyntax, *args, **kwargs): + super().__init__(*args, **kwargs) + self.syntax = syntax + + if len([node for node in self.nodes if isinstance(node, ProtoPackage)]) > 1: raise ValueError(f"Proto can't have more than one package statement") @property @@ -53,9 +80,34 @@ def enums(self) -> list[ProtoEnum]: def messages(self) -> list[ProtoMessage]: return [node for node in self.nodes if isinstance(node, ProtoMessage)] - @staticmethod - def parse_partial_content(partial_proto_content: str) -> ParsedProtoNode: - node_types: list[type[ProtoNode]] = [ + @classmethod + def match_header( + cls, + proto_source: str, + parent: Optional["ProtoNode"] = None, + ) -> Optional["ParsedProtoNode"]: + syntax, parsed_tree, remaining_source = cls.parse_syntax_and_preceding_comments( + proto_source.strip() + ) + return ParsedProtoFileHeaderNode( + ProtoFileHeaderNode(list(parsed_tree), syntax, parent=parent), + remaining_source.strip(), + ) + + @classmethod + def match_footer( + cls, + proto_source: str, + parent: Optional[ProtoNode] = None, + ) -> Optional[str]: + trimmed_source = proto_source.strip() + if trimmed_source == "": + return "" + return None + + @classmethod + def container_types(cls) -> list[type[ProtoNode]]: + return [ ProtoImport, ProtoMessage, ProtoPackage, @@ -66,16 +118,20 @@ def parse_partial_content(partial_proto_content: str) -> ParsedProtoNode: ProtoSingleLineComment, ProtoMultiLineComment, ] - for node_type in node_types: - try: - match_result = node_type.match(partial_proto_content) - except (ValueError, IndexError, TypeError): - raise ValueError( - f"Could not parse proto content:\n{partial_proto_content}" - ) - if match_result is not None: - return match_result - raise ValueError(f"Could not parse proto content:\n{partial_proto_content}") + + @classmethod + def construct( + cls, + header_match: "ParsedProtoNode", + contained_nodes: list[ProtoNode], + footer_match: str, + parent: Optional[ProtoNode] = None, + ) -> ProtoNode: + assert isinstance(header_match, ParsedProtoFileHeaderNode) + return cls( + header_match.node.syntax, + header_match.node.header_nodes + contained_nodes, + ) @staticmethod def parse_syntax_and_preceding_comments( @@ -108,25 +164,6 @@ def parse_syntax_and_preceding_comments( return syntax, parsed_tree, proto_content - @classmethod - def match( - cls, proto_content: str, parent: Optional["ProtoNode"] = None - ) -> Optional[ParsedProtoFileNode]: - syntax, parsed_tree, proto_content = cls.parse_syntax_and_preceding_comments( - proto_content - ) - new_tree: list[ProtoNode] = list(parsed_tree) - while proto_content: - # Remove empty statements. - if proto_content.startswith(";"): - proto_content = proto_content[1:].strip() - continue - match_result = cls.parse_partial_content(proto_content) - new_tree.append(match_result.node) - proto_content = match_result.remaining_source.strip() - - return ParsedProtoFileNode(cls(syntax, new_tree), proto_content) - def normalize(self) -> Optional["ProtoNode"]: normalized_nodes = [n.normalize() for n in self.nodes] return ProtoFile( diff --git a/src/proto_node.py b/src/proto_node.py index f69c3f4..05f145c 100644 --- a/src/proto_node.py +++ b/src/proto_node.py @@ -98,6 +98,7 @@ def match( proto_source = header_match.remaining_source.strip() nodes = [] + footer_match: Optional[str] = None while proto_source: # Remove empty statements. if proto_source.startswith(";"): @@ -114,9 +115,11 @@ def match( proto_source = match_result.remaining_source.strip() if footer_match is None: - raise ValueError( - f"Footer was not found when matching container node {cls} for remaining proto source {proto_source}" - ) + footer_match = cls.match_footer(proto_source, parent) + if footer_match is None: + raise ValueError( + f"Footer was not found when matching container node {cls} for remaining proto source {proto_source}" + ) return ParsedProtoNode( cls.construct(header_match, nodes, footer_match, parent=parent), diff --git a/src/util/parser.py b/src/util/parser.py index dd00352..1bd067f 100644 --- a/src/util/parser.py +++ b/src/util/parser.py @@ -13,12 +13,11 @@ def loads(proto_content: str) -> ProtoFile: try: parsed_file = ProtoFile.match(proto_content, None) except ValueError as e: - raise ParseError( - f"Proto doesn't have parseable syntax:\n{proto_content}\n{e}" - ) + raise ParseError(f"Proto doesn't have parseable syntax:\n{e}") if parsed_file is None: raise ParseError(f"Proto doesn't have parseable syntax:\n{proto_content}") + assert isinstance(parsed_file.node, ProtoFile) return parsed_file.node From f0b88d1586c6ae04aebc385636c7cbe953d29bb2 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Tue, 13 Feb 2024 22:09:45 -0500 Subject: [PATCH 25/35] Add pre-commit badge to README (#82) --- .pre-commit-config.yaml | 9 +++++---- README.md | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d256485..32d14aa 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,14 +15,15 @@ repos: hooks: - id: black - repo: https://github.com/pycqa/isort - rev: 5.10.1 + rev: 5.13.2 hooks: - id: isort name: isort (python) - - repo: https://github.com/FelixSeptem/pre-commit-golang.git - rev: "12f5442f51377b10b26651ad745206bbe1500ad6" + - repo: https://github.com/keith/pre-commit-buildifier + rev: 6.4.0 hooks: - - id: bazel-buildifier + - id: buildifier + - id: buildifier-lint - repo: https://github.com/pre-commit/mirrors-mypy rev: v0.991 hooks: diff --git a/README.md b/README.md index 5e98825..1060e46 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # py_proto +[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/shaldengeki/py_proto/main.svg)](https://results.pre-commit.ci/latest/github/shaldengeki/py_proto/main) + This is a Python-based protobuf parser. It is intended to serve as a reference implementation and is _not_ production-ready. ![Build status](https://github.com/shaldengeki/py_proto/actions/workflows/main.yml/badge.svg) From b548c0d3a3f82ed94471d2045f5b39961f37cbd3 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Tue, 13 Feb 2024 22:16:28 -0500 Subject: [PATCH 26/35] Move badge just a little (#83) --- .pre-commit-config.yaml | 5 +++++ README.md | 4 +--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 32d14aa..a22ac4c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,10 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks +ci: + skip: + - buildifier + - buildifier-lint + repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 diff --git a/README.md b/README.md index 1060e46..7e33b13 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ # py_proto -[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/shaldengeki/py_proto/main.svg)](https://results.pre-commit.ci/latest/github/shaldengeki/py_proto/main) - This is a Python-based protobuf parser. It is intended to serve as a reference implementation and is _not_ production-ready. -![Build status](https://github.com/shaldengeki/py_proto/actions/workflows/main.yml/badge.svg) +[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/shaldengeki/py_proto/main.svg)](https://results.pre-commit.ci/latest/github/shaldengeki/py_proto/main) ![Build status](https://github.com/shaldengeki/py_proto/actions/workflows/main.yml/badge.svg) ## Usage From 3ad8d98e3b4743680f0697ec59741014d6c0f4b7 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Tue, 13 Feb 2024 22:18:47 -0500 Subject: [PATCH 27/35] Add dependabot support (#84) --- .github/dependabot.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..4c0fa9f --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "pip" + directory: "/src" + schedule: + interval: "weekly" From 86eea726b451292a18906696ae65f2667b3630fa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 22:19:55 -0500 Subject: [PATCH 28/35] Bump actions/checkout from 2 to 4 (#85) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 4.
Release notes

Sourced from actions/checkout's releases.

v4.0.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3...v4.0.0

v3.6.0

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3.5.3...v3.6.0

v3.5.3

What's Changed

New Contributors

Full Changelog: https://github.com/actions/checkout/compare/v3...v3.5.3

v3.5.2

What's Changed

Full Changelog: https://github.com/actions/checkout/compare/v3.5.1...v3.5.2

v3.5.1

What's Changed

New Contributors

... (truncated)

Changelog

Sourced from actions/checkout's changelog.

Changelog

v4.1.0

v4.0.0

v3.6.0

v3.5.3

v3.5.2

v3.5.1

v3.5.0

v3.4.0

v3.3.0

v3.2.0

v3.1.0

v3.0.2

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/checkout&package-manager=github_actions&previous-version=2&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e880a90..742c31d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: bazel test //... env: # Bazelisk will download bazel to here From 3d069d646c4a5a464afc5441560803dfa72059e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 22:20:04 -0500 Subject: [PATCH 29/35] Bump black from 22.10.0 to 24.2.0 in /src (#86) Bumps [black](https://github.com/psf/black) from 22.10.0 to 24.2.0.
Release notes

Sourced from black's releases.

24.2.0

Stable style

  • Fixed a bug where comments where mistakenly removed along with redundant parentheses (#4218)

Preview style

  • Move the hug_parens_with_braces_and_square_brackets feature to the unstable style due to an outstanding crash and proposed formatting tweaks (#4198)
  • Fixed a bug where base expressions caused inconsistent formatting of ** in tenary expression (#4154)
  • Checking for newline before adding one on docstring that is almost at the line limit (#4185)
  • Remove redundant parentheses in case statement if guards (#4214).

Configuration

  • Fix issue where Black would ignore input files in the presence of symlinks (#4222)
  • Black now ignores pyproject.toml that is missing a tool.black section when discovering project root and configuration. Since Black continues to use version control as an indicator of project root, this is expected to primarily change behavior for users in a monorepo setup (desirably). If you wish to preserve previous behavior, simply add an empty [tool.black] to the previously discovered pyproject.toml (#4204)

Output

  • Black will swallow any SyntaxWarnings or DeprecationWarnings produced by the ast module when performing equivalence checks (#4189)

Integrations

  • Add a JSONSchema and provide a validate-pyproject entry-point (#4181)

24.1.1

Bugfix release to fix a bug that made Black unusable on certain file systems with strict limits on path length.

Preview style

  • Consistently add trailing comma on typed parameters (#4164)

Configuration

  • Shorten the length of the name of the cache file to fix crashes on file systems that do not support long paths (#4176)

... (truncated)

Changelog

Sourced from black's changelog.

24.2.0

Stable style

  • Fixed a bug where comments where mistakenly removed along with redundant parentheses (#4218)

Preview style

  • Move the hug_parens_with_braces_and_square_brackets feature to the unstable style due to an outstanding crash and proposed formatting tweaks (#4198)
  • Fixed a bug where base expressions caused inconsistent formatting of ** in tenary expression (#4154)
  • Checking for newline before adding one on docstring that is almost at the line limit (#4185)
  • Remove redundant parentheses in case statement if guards (#4214).

Configuration

  • Fix issue where Black would ignore input files in the presence of symlinks (#4222)
  • Black now ignores pyproject.toml that is missing a tool.black section when discovering project root and configuration. Since Black continues to use version control as an indicator of project root, this is expected to primarily change behavior for users in a monorepo setup (desirably). If you wish to preserve previous behavior, simply add an empty [tool.black] to the previously discovered pyproject.toml (#4204)

Output

  • Black will swallow any SyntaxWarnings or DeprecationWarnings produced by the ast module when performing equivalence checks (#4189)

Integrations

  • Add a JSONSchema and provide a validate-pyproject entry-point (#4181)

24.1.1

Bugfix release to fix a bug that made Black unusable on certain file systems with strict limits on path length.

Preview style

  • Consistently add trailing comma on typed parameters (#4164)

Configuration

  • Shorten the length of the name of the cache file to fix crashes on file systems that do not support long paths (#4176)

... (truncated)

Commits
  • 6fdf8a4 Prepare release 24.2.0 (#4226)
  • 8af4394 fix: Don't remove comments along with parens (#4218)
  • 35e9776 Bump pre-commit/action from 3.0.0 to 3.0.1 (#4225)
  • 23dfc5b Fix ignoring input files for symlink reasons (#4222)
  • a201003 Simplify check for symlinks that resolve outside root (#4221)
  • dab37a6 Remove redundant parentheses in case statement if guards (#4214)
  • 32230e6 fix: bug where the doublestar operation had inconsistent formatting. (#4154)
  • 7edb50f fix: additional newline added to docstring when the previous line length is l...
  • 3e80de3 Bump furo from 2023.9.10 to 2024.1.29 in /docs (#4211)
  • a08b480 Bump pypa/cibuildwheel from 2.16.4 to 2.16.5 (#4212)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=black&package-manager=pip&previous-version=22.10.0&new-version=24.2.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requirements.txt b/src/requirements.txt index 531c159..c808582 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -8,7 +8,7 @@ astroid==2.12.13 # via # -r src/requirements.txt # pylint -black==22.10.0 +black==24.2.0 # via -r src/requirements.txt cfgv==3.3.1 # via From 18251a1d7e62c032f1893d7858d6ae2f68f9cb99 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 22:20:16 -0500 Subject: [PATCH 30/35] Bump astroid from 2.12.13 to 3.0.3 in /src (#87) Bumps [astroid](https://github.com/pylint-dev/astroid) from 2.12.13 to 3.0.3.
Changelog

Sourced from astroid's changelog.

What's New in astroid 3.0.3?

Release date: 2024-02-04

What's New in astroid 3.0.2?

Release date: 2023-12-12

  • Avoid duplicate inference results for some uses of typing.X constructs like Tuple[Optional[int], ...]. This was causing pylint to occasionally omit messages like deprecated-typing-alias.

    Closes pylint-dev/pylint#9220

What's New in astroid 3.0.1?

Release date: 2023-10-15

What's New in astroid 3.0.0?

Release date: 2023-09-26

  • Add support for Python 3.12, including PEP 695 type parameter syntax.

    Closes #2201

  • Remove support for Python 3.7.

    Refs #2137

  • Use the global inference cache when inferring, even without an explicit InferenceContext. This is a significant performance improvement given how often methods default to None for the context argument. (Linting astroid itself now takes ~5% less time on Python 3.12; other projects requiring more complex inference calculations will see greater speedups.)

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=astroid&package-manager=pip&previous-version=2.12.13&new-version=3.0.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requirements.txt b/src/requirements.txt index c808582..a6ada45 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -4,7 +4,7 @@ # # pip-compile src/requirements.txt # -astroid==2.12.13 +astroid==3.0.3 # via # -r src/requirements.txt # pylint From 9776505fbd3df081d032fd5493ac6dd62ecc04bf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 22:20:53 -0500 Subject: [PATCH 31/35] Bump nodeenv from 1.7.0 to 1.8.0 in /src (#88) Bumps [nodeenv](https://github.com/ekalinin/nodeenv) from 1.7.0 to 1.8.0.
Release notes

Sourced from nodeenv's releases.

1.8.0: fix fish; add riscv64; multiple attempt to download node

Changes:

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=nodeenv&package-manager=pip&previous-version=1.7.0&new-version=1.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requirements.txt b/src/requirements.txt index a6ada45..f0a7241 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -50,7 +50,7 @@ mypy-extensions==0.4.3 # via # -r src/requirements.txt # black -nodeenv==1.7.0 +nodeenv==1.8.0 # via # -r src/requirements.txt # pre-commit From 3fee9bb24b7e734cd8a0b69a8557e368e673b03c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 22:22:11 -0500 Subject: [PATCH 32/35] Bump pathspec from 0.10.2 to 0.12.1 in /src (#89) Bumps [pathspec](https://github.com/cpburnz/python-pathspec) from 0.10.2 to 0.12.1.
Release notes

Sourced from pathspec's releases.

v0.12.1

Release v0.12.1. See CHANGES.rst.

v0.12.0

Release v0.12.0. See CHANGES.rst.

v0.11.2

Release v0.11.2. See CHANGES.rst.

v0.11.1

Release v0.11.1. See CHANGES.rst.

v0.11.0

Release v0.11.0. See CHANGES.rst.

v0.10.3

Release v0.10.3. See CHANGES.rst.

Changelog

Sourced from pathspec's changelog.

0.12.1 (2023-12-10)

Bug fixes:

  • Issue [#84](https://github.com/cpburnz/python-pathspec/issues/84)_: PathSpec.match_file() returns None since 0.12.0.

.. _Issue [#84](https://github.com/cpburnz/python-pathspec/issues/84): cpburnz/python-pathspec#84

0.12.0 (2023-12-09)

Major changes:

  • Dropped support of EOL Python 3.7. See Pull [#82](https://github.com/cpburnz/python-pathspec/issues/82)_.

API changes:

  • Signature of protected method pathspec.pathspec.PathSpec._match_file() (with a leading underscore) has been changed from def _match_file(patterns: Iterable[Pattern], file: str) -> bool to def _match_file(patterns: Iterable[Tuple[int, Pattern]], file: str) -> Tuple[Optional[bool], Optional[int]].

New features:

  • Added pathspec.pathspec.PathSpec.check_*() methods. These methods behave similarly to .match_*() but return additional information in the pathspec.util.CheckResult objects (e.g., CheckResult.index indicates the index of the last pattern that matched the file).
  • Added pathspec.pattern.RegexPattern.pattern attribute which stores the original, uncompiled pattern.

Bug fixes:

  • Issue [#81](https://github.com/cpburnz/python-pathspec/issues/81)_: GitIgnoreSpec behaviors differ from git.
  • Pull [#83](https://github.com/cpburnz/python-pathspec/issues/83)_: Fix ReadTheDocs builds.

Improvements:

  • Mark Python 3.12 as supported. See Pull [#82](https://github.com/cpburnz/python-pathspec/issues/82)_.
  • Improve test debugging.
  • Improve type hint on on_error parameter on pathspec.pathspec.PathSpec.match_tree_entries().
  • Improve type hint on on_error parameter on pathspec.util.iter_tree_entries().

.. _Issue [#81](https://github.com/cpburnz/python-pathspec/issues/81): cpburnz/python-pathspec#81 .. _Pull [#82](https://github.com/cpburnz/python-pathspec/issues/82): cpburnz/python-pathspec#82 .. _Pull [#83](https://github.com/cpburnz/python-pathspec/issues/83): cpburnz/python-pathspec#83

0.11.2 (2023-07-28)

New features:

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pathspec&package-manager=pip&previous-version=0.10.2&new-version=0.12.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requirements.txt b/src/requirements.txt index f0a7241..f1c3836 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -54,7 +54,7 @@ nodeenv==1.8.0 # via # -r src/requirements.txt # pre-commit -pathspec==0.10.2 +pathspec==0.12.1 # via # -r src/requirements.txt # black From eb10750d25b26d7af56d7bf2ee842b9dc94d576c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 22:23:12 -0500 Subject: [PATCH 33/35] Bump distlib from 0.3.6 to 0.3.8 in /src (#90) Bumps [distlib](https://github.com/pypa/distlib) from 0.3.6 to 0.3.8.
Changelog

Sourced from distlib's changelog.

0.3.8


Released: 2023-12-12
  • markers

    • Fix #209: use legacy version implementation for Python versions.
  • tests

    • Fix #204: use symlinks in venv creation during test.

    • Fix #208: handle deprecation removals in Python 3.13.

0.3.7

Released: 2023-07-17

  • database

    • Handle newlines when parsing metadata.
  • markers

    • Use version comparison logic for python_full_version. Thanks to Albert Peschar for the patch.

    • Simplify code with a set comprehension. Thanks to Christian Clauss for the patch.

  • scripts

    • Fix shebang computation for source builds of Python. Thanks to Eli Schwartz for the patch.
  • util

    • Extract tarfiles more safely by incorporating tarfile filters. Thanks to Petr Viktorin for the patch.

    • Check for 'has_cert' attribute before using it. Thanks to Lumir Balhar for the patch.

    • Fix #203: Handle parsing of export entries to allow script names such as "," or ",foo". Thanks to Flavio Amurrio for the report.

  • versions

... (truncated)

Commits
  • ab5f8e7 Changes for 0.3.8.
  • 86bb212 Update change log.
  • 488599f Updates based on flake8 checks.
  • 0e261af Use legacy version implementation for Python itself.
  • 8242f39 Update copyright years.
  • e27569b Fix #208: Handle deprecation removals in Python 3.13.
  • 65a014b Update requirements and CI matrix.
  • 124108a Skip test for non-final Python versions.
  • ff48e09 Fix #206: include tox.ini in sdist.
  • eeaa18d Fix #204: Use symlinks in venv creation during test.
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=distlib&package-manager=pip&previous-version=0.3.6&new-version=0.3.8)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/requirements.txt b/src/requirements.txt index f1c3836..ac0152e 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -22,7 +22,7 @@ dill==0.3.6 # via # -r src/requirements.txt # pylint -distlib==0.3.6 +distlib==0.3.8 # via # -r src/requirements.txt # virtualenv From 168931bc207647b887112741a4910ffa47d8b3b4 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Tue, 13 Feb 2024 22:26:28 -0500 Subject: [PATCH 34/35] Update to bazel 7 (#91) --- .bazelversion | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bazelversion b/.bazelversion index 09b254e..a8907c0 100644 --- a/.bazelversion +++ b/.bazelversion @@ -1 +1 @@ -6.0.0 +7.0.2 From f8ed13f53f169db0cf4179fc6ea37a9bae0d5ee8 Mon Sep 17 00:00:00 2001 From: Charles OuGuo Date: Tue, 13 Feb 2024 22:37:47 -0500 Subject: [PATCH 35/35] Use bzlmod (#92) --- MODULE.bazel | 15 + MODULE.bazel.lock | 2312 +++++++++++++++++++++++++++++++++++++++++++++ WORKSPACE | 36 - 3 files changed, 2327 insertions(+), 36 deletions(-) create mode 100644 MODULE.bazel create mode 100644 MODULE.bazel.lock diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000..83fd0ca --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,15 @@ +bazel_dep(name = "rules_python", version = "0.31.0") + +python = use_extension("@rules_python//python/extensions:python.bzl", "python") +python.toolchain( + python_version = "3.10", +) + +pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip") +pip.parse( + python_version = "3.10", + requirements_lock = "//src:requirements.txt", +) +use_repo(pip, "py_proto_deps") + +bazel_dep(name = "bazel_skylib", version = "1.5.0") diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock new file mode 100644 index 0000000..aeeacbe --- /dev/null +++ b/MODULE.bazel.lock @@ -0,0 +1,2312 @@ +{ + "lockFileVersion": 3, + "moduleFileHash": "60ddefc0e85720d83b75b5ac5f314791a9cd92eee654d7ca947f3c9e3d587d0b", + "flags": { + "cmdRegistries": [ + "https://bcr.bazel.build/" + ], + "cmdModuleOverrides": {}, + "allowedYankedVersions": [], + "envVarAllowedYankedVersions": "", + "ignoreDevDependency": false, + "directDependenciesMode": "WARNING", + "compatibilityMode": "ERROR" + }, + "localOverrideHashes": { + "bazel_tools": "922ea6752dc9105de5af957f7a99a6933c0a6a712d23df6aad16a9c399f7e787" + }, + "moduleDepGraph": { + "": { + "name": "", + "version": "", + "key": "", + "repoName": "", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_python//python/extensions:python.bzl", + "extensionName": "python", + "usingModule": "", + "location": { + "file": "@@//:MODULE.bazel", + "line": 2, + "column": 23 + }, + "imports": {}, + "devImports": [], + "tags": [ + { + "tagName": "toolchain", + "attributeValues": { + "python_version": "3.10" + }, + "devDependency": false, + "location": { + "file": "@@//:MODULE.bazel", + "line": 3, + "column": 17 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@rules_python//python/extensions:pip.bzl", + "extensionName": "pip", + "usingModule": "", + "location": { + "file": "@@//:MODULE.bazel", + "line": 7, + "column": 20 + }, + "imports": { + "py_proto_deps": "py_proto_deps" + }, + "devImports": [], + "tags": [ + { + "tagName": "parse", + "attributeValues": { + "python_version": "3.10", + "requirements_lock": "//src:requirements.txt" + }, + "devDependency": false, + "location": { + "file": "@@//:MODULE.bazel", + "line": 8, + "column": 10 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "rules_python": "rules_python@0.31.0", + "bazel_skylib": "bazel_skylib@1.5.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + } + }, + "rules_python@0.31.0": { + "name": "rules_python", + "version": "0.31.0", + "key": "rules_python@0.31.0", + "repoName": "rules_python", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@pythons_hub//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_python//python/private/bzlmod:internal_deps.bzl", + "extensionName": "internal_deps", + "usingModule": "rules_python@0.31.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel", + "line": 15, + "column": 30 + }, + "imports": { + "rules_python_internal": "rules_python_internal", + "pypi__build": "pypi__build", + "pypi__click": "pypi__click", + "pypi__colorama": "pypi__colorama", + "pypi__importlib_metadata": "pypi__importlib_metadata", + "pypi__installer": "pypi__installer", + "pypi__more_itertools": "pypi__more_itertools", + "pypi__packaging": "pypi__packaging", + "pypi__pep517": "pypi__pep517", + "pypi__pip": "pypi__pip", + "pypi__pip_tools": "pypi__pip_tools", + "pypi__pyproject_hooks": "pypi__pyproject_hooks", + "pypi__setuptools": "pypi__setuptools", + "pypi__tomli": "pypi__tomli", + "pypi__wheel": "pypi__wheel", + "pypi__zipp": "pypi__zipp" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": {}, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel", + "line": 16, + "column": 22 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@rules_python//python/extensions:python.bzl", + "extensionName": "python", + "usingModule": "rules_python@0.31.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel", + "line": 41, + "column": 23 + }, + "imports": { + "pythons_hub": "pythons_hub" + }, + "devImports": [], + "tags": [ + { + "tagName": "toolchain", + "attributeValues": { + "is_default": true, + "python_version": "3.11" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel", + "line": 47, + "column": 17 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_features": "bazel_features@1.1.1", + "bazel_skylib": "bazel_skylib@1.5.0", + "platforms": "platforms@0.0.7", + "rules_proto": "rules_proto@5.3.0-21.7", + "com_google_protobuf": "protobuf@21.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0", + "urls": [ + "https://github.com/bazelbuild/rules_python/releases/download/0.31.0/rules_python-0.31.0.tar.gz" + ], + "integrity": "sha256-xovcT77CXeW1STuIGc/Id8TqKZwNyxXCRMWgAgjN4xE=", + "strip_prefix": "rules_python-0.31.0", + "remote_patches": { + "https://bcr.bazel.build/modules/rules_python/0.31.0/patches/module_dot_bazel_version.patch": "sha256-j2KF6j66J2fRAGtc56Zj7Hp1dTGqOWPAR3+IODr0oLQ=" + }, + "remote_patch_strip": 1 + } + } + }, + "bazel_skylib@1.5.0": { + "name": "bazel_skylib", + "version": "1.5.0", + "key": "bazel_skylib@1.5.0", + "repoName": "bazel_skylib", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "//toolchains/unittest:cmd_toolchain", + "//toolchains/unittest:bash_toolchain" + ], + "extensionUsages": [], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "bazel_skylib~1.5.0", + "urls": [ + "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz" + ], + "integrity": "sha256-zVWgYudjuTSZIfD124w5MyiNyLpPdt2UFqrGis7jy5Q=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "bazel_tools@_": { + "name": "bazel_tools", + "version": "", + "key": "bazel_tools@_", + "repoName": "bazel_tools", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_cc_toolchains//:all", + "@local_config_sh//:local_sh_toolchain" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", + "extensionName": "cc_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 17, + "column": 29 + }, + "imports": { + "local_config_cc": "local_config_cc", + "local_config_cc_toolchains": "local_config_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/osx:xcode_configure.bzl", + "extensionName": "xcode_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 21, + "column": 32 + }, + "imports": { + "local_config_xcode": "local_config_xcode" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@rules_java//java:extensions.bzl", + "extensionName": "toolchains", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 24, + "column": 32 + }, + "imports": { + "local_jdk": "local_jdk", + "remote_java_tools": "remote_java_tools", + "remote_java_tools_linux": "remote_java_tools_linux", + "remote_java_tools_windows": "remote_java_tools_windows", + "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", + "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/sh:sh_configure.bzl", + "extensionName": "sh_configure_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 35, + "column": 39 + }, + "imports": { + "local_config_sh": "local_config_sh" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/test:extensions.bzl", + "extensionName": "remote_coverage_tools_extension", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 39, + "column": 48 + }, + "imports": { + "remote_coverage_tools": "remote_coverage_tools" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": "@bazel_tools//tools/android:android_extensions.bzl", + "extensionName": "remote_android_tools_extensions", + "usingModule": "bazel_tools@_", + "location": { + "file": "@@bazel_tools//:MODULE.bazel", + "line": 42, + "column": 42 + }, + "imports": { + "android_gmaven_r8": "android_gmaven_r8", + "android_tools": "android_tools" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "rules_cc": "rules_cc@0.0.9", + "rules_java": "rules_java@7.1.0", + "rules_license": "rules_license@0.0.7", + "rules_proto": "rules_proto@5.3.0-21.7", + "rules_python": "rules_python@0.31.0", + "platforms": "platforms@0.0.7", + "com_google_protobuf": "protobuf@21.7", + "zlib": "zlib@1.3", + "build_bazel_apple_support": "apple_support@1.5.0", + "local_config_platform": "local_config_platform@_" + } + }, + "local_config_platform@_": { + "name": "local_config_platform", + "version": "", + "key": "local_config_platform@_", + "repoName": "local_config_platform", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_" + } + }, + "bazel_features@1.1.1": { + "name": "bazel_features", + "version": "1.1.1", + "key": "bazel_features@1.1.1", + "repoName": "bazel_features", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_features//private:extensions.bzl", + "extensionName": "version_extension", + "usingModule": "bazel_features@1.1.1", + "location": { + "file": "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel", + "line": 6, + "column": 24 + }, + "imports": { + "bazel_features_globals": "bazel_features_globals", + "bazel_features_version": "bazel_features_version" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "bazel_features~1.1.1", + "urls": [ + "https://github.com/bazel-contrib/bazel_features/releases/download/v1.1.1/bazel_features-v1.1.1.tar.gz" + ], + "integrity": "sha256-YsJuQn5cvHUQJERpJ2IuOYqdzfMsZDJSOIFXCdEcEag=", + "strip_prefix": "bazel_features-1.1.1", + "remote_patches": { + "https://bcr.bazel.build/modules/bazel_features/1.1.1/patches/module_dot_bazel_version.patch": "sha256-+56MAEsc7bYN/Pzhn252ZQUxiRzZg9bynXj1qpsmCYs=" + }, + "remote_patch_strip": 1 + } + } + }, + "platforms@0.0.7": { + "name": "platforms", + "version": "0.0.7", + "key": "platforms@0.0.7", + "repoName": "platforms", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "rules_license": "rules_license@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "platforms", + "urls": [ + "https://github.com/bazelbuild/platforms/releases/download/0.0.7/platforms-0.0.7.tar.gz" + ], + "integrity": "sha256-OlYcmee9vpFzqmU/1Xn+hJ8djWc5V4CrR3Cx84FDHVE=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_proto@5.3.0-21.7": { + "name": "rules_proto", + "version": "5.3.0-21.7", + "key": "rules_proto@5.3.0-21.7", + "repoName": "rules_proto", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "com_google_protobuf": "protobuf@21.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_proto~5.3.0-21.7", + "urls": [ + "https://github.com/bazelbuild/rules_proto/archive/refs/tags/5.3.0-21.7.tar.gz" + ], + "integrity": "sha256-3D+yBqLLNEG0heseQjFlsjEjWh6psDG0Qzz3vB+kYN0=", + "strip_prefix": "rules_proto-5.3.0-21.7", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "protobuf@21.7": { + "name": "protobuf", + "version": "21.7", + "key": "protobuf@21.7", + "repoName": "protobuf", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_jvm_external//:extensions.bzl", + "extensionName": "maven", + "usingModule": "protobuf@21.7", + "location": { + "file": "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel", + "line": 22, + "column": 22 + }, + "imports": { + "maven": "maven" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": { + "name": "maven", + "artifacts": [ + "com.google.code.findbugs:jsr305:3.0.2", + "com.google.code.gson:gson:2.8.9", + "com.google.errorprone:error_prone_annotations:2.3.2", + "com.google.j2objc:j2objc-annotations:1.3", + "com.google.guava:guava:31.1-jre", + "com.google.guava:guava-testlib:31.1-jre", + "com.google.truth:truth:1.1.2", + "junit:junit:4.13.2", + "org.mockito:mockito-core:4.3.1" + ] + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel", + "line": 24, + "column": 14 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "rules_python": "rules_python@0.31.0", + "rules_cc": "rules_cc@0.0.9", + "rules_proto": "rules_proto@5.3.0-21.7", + "rules_java": "rules_java@7.1.0", + "rules_pkg": "rules_pkg@0.7.0", + "com_google_abseil": "abseil-cpp@20211102.0", + "zlib": "zlib@1.3", + "upb": "upb@0.0.0-20220923-a547704", + "rules_jvm_external": "rules_jvm_external@4.4.2", + "com_google_googletest": "googletest@1.11.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "protobuf~21.7", + "urls": [ + "https://github.com/protocolbuffers/protobuf/releases/download/v21.7/protobuf-all-21.7.zip" + ], + "integrity": "sha256-VJOiH17T/FAuZv7GuUScBqVRztYwAvpIkDxA36jeeko=", + "strip_prefix": "protobuf-21.7", + "remote_patches": { + "https://bcr.bazel.build/modules/protobuf/21.7/patches/add_module_dot_bazel.patch": "sha256-q3V2+eq0v2XF0z8z+V+QF4cynD6JvHI1y3kI/+rzl5s=", + "https://bcr.bazel.build/modules/protobuf/21.7/patches/add_module_dot_bazel_for_examples.patch": "sha256-O7YP6s3lo/1opUiO0jqXYORNHdZ/2q3hjz1QGy8QdIU=", + "https://bcr.bazel.build/modules/protobuf/21.7/patches/relative_repo_names.patch": "sha256-RK9RjW8T5UJNG7flIrnFiNE9vKwWB+8uWWtJqXYT0w4=", + "https://bcr.bazel.build/modules/protobuf/21.7/patches/add_missing_files.patch": "sha256-Hyne4DG2u5bXcWHNxNMirA2QFAe/2Cl8oMm1XJdkQIY=" + }, + "remote_patch_strip": 1 + } + } + }, + "rules_cc@0.0.9": { + "name": "rules_cc", + "version": "0.0.9", + "key": "rules_cc@0.0.9", + "repoName": "rules_cc", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_cc_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@bazel_tools//tools/cpp:cc_configure.bzl", + "extensionName": "cc_configure_extension", + "usingModule": "rules_cc@0.0.9", + "location": { + "file": "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel", + "line": 9, + "column": 29 + }, + "imports": { + "local_config_cc_toolchains": "local_config_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_cc~0.0.9", + "urls": [ + "https://github.com/bazelbuild/rules_cc/releases/download/0.0.9/rules_cc-0.0.9.tar.gz" + ], + "integrity": "sha256-IDeHW5pEVtzkp50RKorohbvEqtlo5lh9ym5k86CQDN8=", + "strip_prefix": "rules_cc-0.0.9", + "remote_patches": { + "https://bcr.bazel.build/modules/rules_cc/0.0.9/patches/module_dot_bazel_version.patch": "sha256-mM+qzOI0SgAdaJBlWOSMwMPKpaA9b7R37Hj/tp5bb4g=" + }, + "remote_patch_strip": 0 + } + } + }, + "rules_java@7.1.0": { + "name": "rules_java", + "version": "7.1.0", + "key": "rules_java@7.1.0", + "repoName": "rules_java", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "//toolchains:all", + "@local_jdk//:runtime_toolchain_definition", + "@local_jdk//:bootstrap_runtime_toolchain_definition", + "@remotejdk11_linux_toolchain_config_repo//:all", + "@remotejdk11_linux_aarch64_toolchain_config_repo//:all", + "@remotejdk11_linux_ppc64le_toolchain_config_repo//:all", + "@remotejdk11_linux_s390x_toolchain_config_repo//:all", + "@remotejdk11_macos_toolchain_config_repo//:all", + "@remotejdk11_macos_aarch64_toolchain_config_repo//:all", + "@remotejdk11_win_toolchain_config_repo//:all", + "@remotejdk11_win_arm64_toolchain_config_repo//:all", + "@remotejdk17_linux_toolchain_config_repo//:all", + "@remotejdk17_linux_aarch64_toolchain_config_repo//:all", + "@remotejdk17_linux_ppc64le_toolchain_config_repo//:all", + "@remotejdk17_linux_s390x_toolchain_config_repo//:all", + "@remotejdk17_macos_toolchain_config_repo//:all", + "@remotejdk17_macos_aarch64_toolchain_config_repo//:all", + "@remotejdk17_win_toolchain_config_repo//:all", + "@remotejdk17_win_arm64_toolchain_config_repo//:all", + "@remotejdk21_linux_toolchain_config_repo//:all", + "@remotejdk21_linux_aarch64_toolchain_config_repo//:all", + "@remotejdk21_macos_toolchain_config_repo//:all", + "@remotejdk21_macos_aarch64_toolchain_config_repo//:all", + "@remotejdk21_win_toolchain_config_repo//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_java//java:extensions.bzl", + "extensionName": "toolchains", + "usingModule": "rules_java@7.1.0", + "location": { + "file": "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel", + "line": 19, + "column": 27 + }, + "imports": { + "remote_java_tools": "remote_java_tools", + "remote_java_tools_linux": "remote_java_tools_linux", + "remote_java_tools_windows": "remote_java_tools_windows", + "remote_java_tools_darwin_x86_64": "remote_java_tools_darwin_x86_64", + "remote_java_tools_darwin_arm64": "remote_java_tools_darwin_arm64", + "local_jdk": "local_jdk", + "remotejdk11_linux_toolchain_config_repo": "remotejdk11_linux_toolchain_config_repo", + "remotejdk11_linux_aarch64_toolchain_config_repo": "remotejdk11_linux_aarch64_toolchain_config_repo", + "remotejdk11_linux_ppc64le_toolchain_config_repo": "remotejdk11_linux_ppc64le_toolchain_config_repo", + "remotejdk11_linux_s390x_toolchain_config_repo": "remotejdk11_linux_s390x_toolchain_config_repo", + "remotejdk11_macos_toolchain_config_repo": "remotejdk11_macos_toolchain_config_repo", + "remotejdk11_macos_aarch64_toolchain_config_repo": "remotejdk11_macos_aarch64_toolchain_config_repo", + "remotejdk11_win_toolchain_config_repo": "remotejdk11_win_toolchain_config_repo", + "remotejdk11_win_arm64_toolchain_config_repo": "remotejdk11_win_arm64_toolchain_config_repo", + "remotejdk17_linux_toolchain_config_repo": "remotejdk17_linux_toolchain_config_repo", + "remotejdk17_linux_aarch64_toolchain_config_repo": "remotejdk17_linux_aarch64_toolchain_config_repo", + "remotejdk17_linux_ppc64le_toolchain_config_repo": "remotejdk17_linux_ppc64le_toolchain_config_repo", + "remotejdk17_linux_s390x_toolchain_config_repo": "remotejdk17_linux_s390x_toolchain_config_repo", + "remotejdk17_macos_toolchain_config_repo": "remotejdk17_macos_toolchain_config_repo", + "remotejdk17_macos_aarch64_toolchain_config_repo": "remotejdk17_macos_aarch64_toolchain_config_repo", + "remotejdk17_win_toolchain_config_repo": "remotejdk17_win_toolchain_config_repo", + "remotejdk17_win_arm64_toolchain_config_repo": "remotejdk17_win_arm64_toolchain_config_repo", + "remotejdk21_linux_toolchain_config_repo": "remotejdk21_linux_toolchain_config_repo", + "remotejdk21_linux_aarch64_toolchain_config_repo": "remotejdk21_linux_aarch64_toolchain_config_repo", + "remotejdk21_macos_toolchain_config_repo": "remotejdk21_macos_toolchain_config_repo", + "remotejdk21_macos_aarch64_toolchain_config_repo": "remotejdk21_macos_aarch64_toolchain_config_repo", + "remotejdk21_win_toolchain_config_repo": "remotejdk21_win_toolchain_config_repo" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "platforms": "platforms@0.0.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_skylib": "bazel_skylib@1.5.0", + "rules_proto": "rules_proto@5.3.0-21.7", + "rules_license": "rules_license@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0", + "urls": [ + "https://github.com/bazelbuild/rules_java/releases/download/7.1.0/rules_java-7.1.0.tar.gz" + ], + "integrity": "sha256-o3pOX2OrgnFuXdau75iO2EYcegC46TYnImKJn1h81OE=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_license@0.0.7": { + "name": "rules_license", + "version": "0.0.7", + "key": "rules_license@0.0.7", + "repoName": "rules_license", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_license~0.0.7", + "urls": [ + "https://github.com/bazelbuild/rules_license/releases/download/0.0.7/rules_license-0.0.7.tar.gz" + ], + "integrity": "sha256-RTHezLkTY5ww5cdRKgVNXYdWmNrrddjPkPKEN1/nw2A=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "zlib@1.3": { + "name": "zlib", + "version": "1.3", + "key": "zlib@1.3", + "repoName": "zlib", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "platforms": "platforms@0.0.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "zlib~1.3", + "urls": [ + "https://github.com/madler/zlib/releases/download/v1.3/zlib-1.3.tar.gz" + ], + "integrity": "sha256-/wukwpIBPbwnUws6geH5qBPNOd4Byl4Pi/NVcC76WT4=", + "strip_prefix": "zlib-1.3", + "remote_patches": { + "https://bcr.bazel.build/modules/zlib/1.3/patches/add_build_file.patch": "sha256-Ei+FYaaOo7A3jTKunMEodTI0Uw5NXQyZEcboMC8JskY=", + "https://bcr.bazel.build/modules/zlib/1.3/patches/module_dot_bazel.patch": "sha256-fPWLM+2xaF/kuy+kZc1YTfW6hNjrkG400Ho7gckuyJk=" + }, + "remote_patch_strip": 0 + } + } + }, + "apple_support@1.5.0": { + "name": "apple_support", + "version": "1.5.0", + "key": "apple_support@1.5.0", + "repoName": "build_bazel_apple_support", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [ + "@local_config_apple_cc_toolchains//:all" + ], + "extensionUsages": [ + { + "extensionBzlFile": "@build_bazel_apple_support//crosstool:setup.bzl", + "extensionName": "apple_cc_configure_extension", + "usingModule": "apple_support@1.5.0", + "location": { + "file": "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel", + "line": 17, + "column": 35 + }, + "imports": { + "local_config_apple_cc": "local_config_apple_cc", + "local_config_apple_cc_toolchains": "local_config_apple_cc_toolchains" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "apple_support~1.5.0", + "urls": [ + "https://github.com/bazelbuild/apple_support/releases/download/1.5.0/apple_support.1.5.0.tar.gz" + ], + "integrity": "sha256-miM41vja0yRPgj8txghKA+TQ+7J8qJLclw5okNW0gYQ=", + "strip_prefix": "", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "rules_pkg@0.7.0": { + "name": "rules_pkg", + "version": "0.7.0", + "key": "rules_pkg@0.7.0", + "repoName": "rules_pkg", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "rules_python": "rules_python@0.31.0", + "bazel_skylib": "bazel_skylib@1.5.0", + "rules_license": "rules_license@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_pkg~0.7.0", + "urls": [ + "https://github.com/bazelbuild/rules_pkg/releases/download/0.7.0/rules_pkg-0.7.0.tar.gz" + ], + "integrity": "sha256-iimOgydi7aGDBZfWT+fbWBeKqEzVkm121bdE1lWJQcI=", + "strip_prefix": "", + "remote_patches": { + "https://bcr.bazel.build/modules/rules_pkg/0.7.0/patches/module_dot_bazel.patch": "sha256-4OaEPZwYF6iC71ZTDg6MJ7LLqX7ZA0/kK4mT+4xKqiE=" + }, + "remote_patch_strip": 0 + } + } + }, + "abseil-cpp@20211102.0": { + "name": "abseil-cpp", + "version": "20211102.0", + "key": "abseil-cpp@20211102.0", + "repoName": "abseil-cpp", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "rules_cc": "rules_cc@0.0.9", + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "abseil-cpp~20211102.0", + "urls": [ + "https://github.com/abseil/abseil-cpp/archive/refs/tags/20211102.0.tar.gz" + ], + "integrity": "sha256-3PcbnLqNwMqZQMSzFqDHlr6Pq0KwcLtrfKtitI8OZsQ=", + "strip_prefix": "abseil-cpp-20211102.0", + "remote_patches": { + "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/patches/module_dot_bazel.patch": "sha256-4izqopgGCey4jVZzl/w3M2GVPNohjh2B5TmbThZNvPY=" + }, + "remote_patch_strip": 0 + } + } + }, + "upb@0.0.0-20220923-a547704": { + "name": "upb", + "version": "0.0.0-20220923-a547704", + "key": "upb@0.0.0-20220923-a547704", + "repoName": "upb", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "rules_proto": "rules_proto@5.3.0-21.7", + "com_google_protobuf": "protobuf@21.7", + "com_google_absl": "abseil-cpp@20211102.0", + "platforms": "platforms@0.0.7", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "upb~0.0.0-20220923-a547704", + "urls": [ + "https://github.com/protocolbuffers/upb/archive/a5477045acaa34586420942098f5fecd3570f577.tar.gz" + ], + "integrity": "sha256-z39x6v+QskwaKLSWRan/A6mmwecTQpHOcJActj5zZLU=", + "strip_prefix": "upb-a5477045acaa34586420942098f5fecd3570f577", + "remote_patches": { + "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/patches/module_dot_bazel.patch": "sha256-wH4mNS6ZYy+8uC0HoAft/c7SDsq2Kxf+J8dUakXhaB0=" + }, + "remote_patch_strip": 0 + } + } + }, + "rules_jvm_external@4.4.2": { + "name": "rules_jvm_external", + "version": "4.4.2", + "key": "rules_jvm_external@4.4.2", + "repoName": "rules_jvm_external", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [ + { + "extensionBzlFile": "@rules_jvm_external//:non-module-deps.bzl", + "extensionName": "non_module_deps", + "usingModule": "rules_jvm_external@4.4.2", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel", + "line": 9, + "column": 32 + }, + "imports": { + "io_bazel_rules_kotlin": "io_bazel_rules_kotlin" + }, + "devImports": [], + "tags": [], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + }, + { + "extensionBzlFile": ":extensions.bzl", + "extensionName": "maven", + "usingModule": "rules_jvm_external@4.4.2", + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel", + "line": 16, + "column": 22 + }, + "imports": { + "rules_jvm_external_deps": "rules_jvm_external_deps" + }, + "devImports": [], + "tags": [ + { + "tagName": "install", + "attributeValues": { + "name": "rules_jvm_external_deps", + "artifacts": [ + "com.google.cloud:google-cloud-core:1.93.10", + "com.google.cloud:google-cloud-storage:1.113.4", + "com.google.code.gson:gson:2.9.0", + "org.apache.maven:maven-artifact:3.8.6", + "software.amazon.awssdk:s3:2.17.183" + ], + "lock_file": "@rules_jvm_external//:rules_jvm_external_deps_install.json" + }, + "devDependency": false, + "location": { + "file": "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel", + "line": 18, + "column": 14 + } + } + ], + "hasDevUseExtension": false, + "hasNonDevUseExtension": true + } + ], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "io_bazel_stardoc": "stardoc@0.5.1", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_jvm_external~4.4.2", + "urls": [ + "https://github.com/bazelbuild/rules_jvm_external/archive/refs/tags/4.4.2.zip" + ], + "integrity": "sha256-c1YC9QgT6y6pPKP15DsZWb2AshO4NqB6YqKddXZwt3s=", + "strip_prefix": "rules_jvm_external-4.4.2", + "remote_patches": {}, + "remote_patch_strip": 0 + } + } + }, + "googletest@1.11.0": { + "name": "googletest", + "version": "1.11.0", + "key": "googletest@1.11.0", + "repoName": "googletest", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "com_google_absl": "abseil-cpp@20211102.0", + "platforms": "platforms@0.0.7", + "rules_cc": "rules_cc@0.0.9", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "googletest~1.11.0", + "urls": [ + "https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz" + ], + "integrity": "sha256-tIcL8SH/d5W6INILzdhie44Ijy0dqymaAxwQNO3ck9U=", + "strip_prefix": "googletest-release-1.11.0", + "remote_patches": { + "https://bcr.bazel.build/modules/googletest/1.11.0/patches/module_dot_bazel.patch": "sha256-HuahEdI/n8KCI071sN3CEziX+7qP/Ec77IWayYunLP0=" + }, + "remote_patch_strip": 0 + } + } + }, + "stardoc@0.5.1": { + "name": "stardoc", + "version": "0.5.1", + "key": "stardoc@0.5.1", + "repoName": "stardoc", + "executionPlatformsToRegister": [], + "toolchainsToRegister": [], + "extensionUsages": [], + "deps": { + "bazel_skylib": "bazel_skylib@1.5.0", + "rules_java": "rules_java@7.1.0", + "bazel_tools": "bazel_tools@_", + "local_config_platform": "local_config_platform@_" + }, + "repoSpec": { + "bzlFile": "@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "stardoc~0.5.1", + "urls": [ + "https://github.com/bazelbuild/stardoc/releases/download/0.5.1/stardoc-0.5.1.tar.gz" + ], + "integrity": "sha256-qoFNrgrEALurLoiB+ZFcb0fElmS/CHxAmhX5BDjSwj4=", + "strip_prefix": "", + "remote_patches": { + "https://bcr.bazel.build/modules/stardoc/0.5.1/patches/module_dot_bazel.patch": "sha256-UAULCuTpJE7SG0YrR9XLjMfxMRmbP+za3uW9ONZ5rjI=" + }, + "remote_patch_strip": 0 + } + } + } + }, + "moduleExtensions": { + "@@apple_support~1.5.0//crosstool:setup.bzl%apple_cc_configure_extension": { + "general": { + "bzlTransitiveDigest": "pMLFCYaRPkgXPQ8vtuNkMfiHfPmRBy6QJfnid4sWfv0=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_apple_cc": { + "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf", + "attributes": { + "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc" + } + }, + "local_config_apple_cc_toolchains": { + "bzlFile": "@@apple_support~1.5.0//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf_toolchains", + "attributes": { + "name": "apple_support~1.5.0~apple_cc_configure_extension~local_config_apple_cc_toolchains" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "apple_support~1.5.0", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@bazel_tools//tools/cpp:cc_configure.bzl%cc_configure_extension": { + "general": { + "bzlTransitiveDigest": "mcsWHq3xORJexV5/4eCvNOLxFOQKV6eli3fkr+tEaqE=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_cc": { + "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", + "ruleClassName": "cc_autoconf", + "attributes": { + "name": "bazel_tools~cc_configure_extension~local_config_cc" + } + }, + "local_config_cc_toolchains": { + "bzlFile": "@@bazel_tools//tools/cpp:cc_configure.bzl", + "ruleClassName": "cc_autoconf_toolchains", + "attributes": { + "name": "bazel_tools~cc_configure_extension~local_config_cc_toolchains" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "bazel_tools", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@bazel_tools//tools/osx:xcode_configure.bzl%xcode_configure_extension": { + "general": { + "bzlTransitiveDigest": "Qh2bWTU6QW6wkrd87qrU4YeY+SG37Nvw3A0PR4Y0L2Y=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_xcode": { + "bzlFile": "@@bazel_tools//tools/osx:xcode_configure.bzl", + "ruleClassName": "xcode_autoconf", + "attributes": { + "name": "bazel_tools~xcode_configure_extension~local_config_xcode", + "xcode_locator": "@bazel_tools//tools/osx:xcode_locator.m", + "remote_xcode": "" + } + } + }, + "recordedRepoMappingEntries": [] + } + }, + "@@bazel_tools//tools/sh:sh_configure.bzl%sh_configure_extension": { + "general": { + "bzlTransitiveDigest": "hp4NgmNjEg5+xgvzfh6L83bt9/aiiWETuNpwNuF1MSU=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "local_config_sh": { + "bzlFile": "@@bazel_tools//tools/sh:sh_configure.bzl", + "ruleClassName": "sh_config", + "attributes": { + "name": "bazel_tools~sh_configure_extension~local_config_sh" + } + } + }, + "recordedRepoMappingEntries": [] + } + }, + "@@rules_java~7.1.0//java:extensions.bzl%toolchains": { + "general": { + "bzlTransitiveDigest": "D02GmifxnV/IhYgspsJMDZ/aE8HxAjXgek5gi6FSto4=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "remotejdk21_linux_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux//:jdk\",\n)\n" + } + }, + "remotejdk17_linux_s390x_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_s390x//:jdk\",\n)\n" + } + }, + "remotejdk17_macos_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos//:jdk\",\n)\n" + } + }, + "remotejdk21_macos_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk17_linux_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk21_macos_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "2a7a99a3ea263dbd8d32a67d1e6e363ba8b25c645c826f5e167a02bbafaff1fa", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_aarch64.tar.gz" + ] + } + }, + "remotejdk17_linux_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux//:jdk\",\n)\n" + } + }, + "remotejdk17_macos_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "314b04568ec0ae9b36ba03c9cbd42adc9e1265f74678923b19297d66eb84dcca", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_aarch64.tar.gz" + ] + } + }, + "remote_java_tools_windows": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools_windows", + "sha256": "c5c70c214a350f12cbf52da8270fa43ba629b795f3dd328028a38f8f0d39c2a1", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_windows-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_windows-v13.1.zip" + ] + } + }, + "remotejdk11_win": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_win", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "43408193ce2fa0862819495b5ae8541085b95660153f2adcf91a52d3a1710e83", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-win_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-win_x64.zip" + ] + } + }, + "remotejdk11_win_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_win_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "54174439f2b3fddd11f1048c397fe7bb45d4c9d66d452d6889b013d04d21c4de", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_aarch64.tar.gz" + ] + } + }, + "remotejdk17_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "b9482f2304a1a68a614dfacddcf29569a72f0fac32e6c74f83dc1b9a157b8340", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_x64.tar.gz" + ] + } + }, + "remotejdk11_linux_s390x_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:s390x\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_s390x//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux//:jdk\",\n)\n" + } + }, + "remotejdk11_macos": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_macos", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "bcaab11cfe586fae7583c6d9d311c64384354fb2638eb9a012eca4c3f1a1d9fd", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_x64.tar.gz" + ] + } + }, + "remotejdk11_win_arm64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "b8a28e6e767d90acf793ea6f5bed0bb595ba0ba5ebdf8b99f395266161e53ec2", + "strip_prefix": "jdk-11.0.13+8", + "urls": [ + "https://mirror.bazel.build/aka.ms/download-jdk/microsoft-jdk-11.0.13.8.1-windows-aarch64.zip" + ] + } + }, + "remotejdk17_macos": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_macos", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "640453e8afe8ffe0fb4dceb4535fb50db9c283c64665eebb0ba68b19e65f4b1f", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-macosx_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-macosx_x64.tar.gz" + ] + } + }, + "remotejdk21_macos": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_macos", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "9639b87db586d0c89f7a9892ae47f421e442c64b97baebdff31788fbe23265bd", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-macosx_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-macosx_x64.tar.gz" + ] + } + }, + "remotejdk21_macos_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_macos_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_macos//:jdk\",\n)\n" + } + }, + "remotejdk17_macos_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_macos_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_macos_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk17_win": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_win", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "192f2afca57701de6ec496234f7e45d971bf623ff66b8ee4a5c81582054e5637", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_x64.zip" + ] + } + }, + "remotejdk11_macos_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_ppc64le_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_ppc64le//:jdk\",\n)\n" + } + }, + "remotejdk21_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_linux", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "0c0eadfbdc47a7ca64aeab51b9c061f71b6e4d25d2d87674512e9b6387e9e3a6", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_x64.tar.gz" + ] + } + }, + "remote_java_tools_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools_linux", + "sha256": "d134da9b04c9023fb6e56a5d4bffccee73f7bc9572ddc4e747778dacccd7a5a7", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_linux-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_linux-v13.1.zip" + ] + } + }, + "remotejdk21_win": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_win", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "e9959d500a0d9a7694ac243baf657761479da132f0f94720cbffd092150bd802", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-win_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-win_x64.zip" + ] + } + }, + "remotejdk21_linux_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 21,\n)\n", + "sha256": "1fb64b8036c5d463d8ab59af06bf5b6b006811e6012e3b0eb6bccf57f1c55835", + "strip_prefix": "zulu21.28.85-ca-jdk21.0.0-linux_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu21.28.85-ca-jdk21.0.0-linux_aarch64.tar.gz" + ] + } + }, + "remotejdk11_linux_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_linux_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_s390x": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_s390x", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "a58fc0361966af0a5d5a31a2d8a208e3c9bb0f54f345596fd80b99ea9a39788b", + "strip_prefix": "jdk-11.0.15+10", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.15_10.tar.gz" + ] + } + }, + "remotejdk17_linux_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "6531cef61e416d5a7b691555c8cf2bdff689201b8a001ff45ab6740062b44313", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-linux_aarch64.tar.gz" + ] + } + }, + "remotejdk17_win_arm64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win_arm64//:jdk\",\n)\n" + } + }, + "remotejdk11_linux": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "a34b404f87a08a61148b38e1416d837189e1df7a040d949e743633daf4695a3c", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-linux_x64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-linux_x64.tar.gz" + ] + } + }, + "remotejdk11_macos_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:macos\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_macos//:jdk\",\n)\n" + } + }, + "remotejdk17_linux_ppc64le_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:ppc\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_linux_ppc64le//:jdk\",\n)\n" + } + }, + "remotejdk17_win_arm64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_win_arm64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "6802c99eae0d788e21f52d03cab2e2b3bf42bc334ca03cbf19f71eb70ee19f85", + "strip_prefix": "zulu17.44.53-ca-jdk17.0.8.1-win_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip", + "https://cdn.azul.com/zulu/bin/zulu17.44.53-ca-jdk17.0.8.1-win_aarch64.zip" + ] + } + }, + "remote_java_tools_darwin_arm64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_arm64", + "sha256": "dab5bb87ec43e980faea6e1cec14bafb217b8e2f5346f53aa784fd715929a930", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_arm64-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_arm64-v13.1.zip" + ] + } + }, + "remotejdk17_linux_ppc64le": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_ppc64le", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "00a4c07603d0218cd678461b5b3b7e25b3253102da4022d31fc35907f21a2efd", + "strip_prefix": "jdk-17.0.8.1+1", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.8.1_1.tar.gz" + ] + } + }, + "remotejdk21_linux_aarch64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_linux_aarch64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:linux\", \"@platforms//cpu:aarch64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_linux_aarch64//:jdk\",\n)\n" + } + }, + "remotejdk11_win_arm64_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_win_arm64_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_11\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"11\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:arm64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk11_win_arm64//:jdk\",\n)\n" + } + }, + "local_jdk": { + "bzlFile": "@@rules_java~7.1.0//toolchains:local_java_repository.bzl", + "ruleClassName": "_local_java_repository_rule", + "attributes": { + "name": "rules_java~7.1.0~toolchains~local_jdk", + "java_home": "", + "version": "", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = {RUNTIME_VERSION},\n)\n" + } + }, + "remote_java_tools_darwin_x86_64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools_darwin_x86_64", + "sha256": "0db40d8505a2b65ef0ed46e4256757807db8162f7acff16225be57c1d5726dbc", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools_darwin_x86_64-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools_darwin_x86_64-v13.1.zip" + ] + } + }, + "remote_java_tools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remote_java_tools", + "sha256": "286bdbbd66e616fc4ed3f90101418729a73baa7e8c23a98ffbef558f74c0ad14", + "urls": [ + "https://mirror.bazel.build/bazel_java_tools/releases/java/v13.1/java_tools-v13.1.zip", + "https://github.com/bazelbuild/java_tools/releases/download/java_v13.1/java_tools-v13.1.zip" + ] + } + }, + "remotejdk17_linux_s390x": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_linux_s390x", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 17,\n)\n", + "sha256": "ffacba69c6843d7ca70d572489d6cc7ab7ae52c60f0852cedf4cf0d248b6fc37", + "strip_prefix": "jdk-17.0.8.1+1", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz", + "https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.8.1%2B1/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.8.1_1.tar.gz" + ] + } + }, + "remotejdk17_win_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk17_win_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_17\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"17\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk17_win//:jdk\",\n)\n" + } + }, + "remotejdk11_linux_ppc64le": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_linux_ppc64le", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "a8fba686f6eb8ae1d1a9566821dbd5a85a1108b96ad857fdbac5c1e4649fc56f", + "strip_prefix": "jdk-11.0.15+10", + "urls": [ + "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz", + "https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.15+10/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.15_10.tar.gz" + ] + } + }, + "remotejdk11_macos_aarch64": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk11_macos_aarch64", + "build_file_content": "load(\"@rules_java//java:defs.bzl\", \"java_runtime\")\n\npackage(default_visibility = [\"//visibility:public\"])\n\nexports_files([\"WORKSPACE\", \"BUILD.bazel\"])\n\nfilegroup(\n name = \"jre\",\n srcs = glob(\n [\n \"jre/bin/**\",\n \"jre/lib/**\",\n ],\n allow_empty = True,\n # In some configurations, Java browser plugin is considered harmful and\n # common antivirus software blocks access to npjp2.dll interfering with Bazel,\n # so do not include it in JRE on Windows.\n exclude = [\"jre/bin/plugin2/**\"],\n ),\n)\n\nfilegroup(\n name = \"jdk-bin\",\n srcs = glob(\n [\"bin/**\"],\n # The JDK on Windows sometimes contains a directory called\n # \"%systemroot%\", which is not a valid label.\n exclude = [\"**/*%*/**\"],\n ),\n)\n\n# This folder holds security policies.\nfilegroup(\n name = \"jdk-conf\",\n srcs = glob(\n [\"conf/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-include\",\n srcs = glob(\n [\"include/**\"],\n allow_empty = True,\n ),\n)\n\nfilegroup(\n name = \"jdk-lib\",\n srcs = glob(\n [\"lib/**\", \"release\"],\n allow_empty = True,\n exclude = [\n \"lib/missioncontrol/**\",\n \"lib/visualvm/**\",\n ],\n ),\n)\n\njava_runtime(\n name = \"jdk\",\n srcs = [\n \":jdk-bin\",\n \":jdk-conf\",\n \":jdk-include\",\n \":jdk-lib\",\n \":jre\",\n ],\n # Provide the 'java` binary explicitly so that the correct path is used by\n # Bazel even when the host platform differs from the execution platform.\n # Exactly one of the two globs will be empty depending on the host platform.\n # When --incompatible_disallow_empty_glob is enabled, each individual empty\n # glob will fail without allow_empty = True, even if the overall result is\n # non-empty.\n java = glob([\"bin/java.exe\", \"bin/java\"], allow_empty = True)[0],\n version = 11,\n)\n", + "sha256": "7632bc29f8a4b7d492b93f3bc75a7b61630894db85d136456035ab2a24d38885", + "strip_prefix": "zulu11.66.15-ca-jdk11.0.20-macosx_aarch64", + "urls": [ + "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz", + "https://cdn.azul.com/zulu/bin/zulu11.66.15-ca-jdk11.0.20-macosx_aarch64.tar.gz" + ] + } + }, + "remotejdk21_win_toolchain_config_repo": { + "bzlFile": "@@rules_java~7.1.0//toolchains:remote_java_repository.bzl", + "ruleClassName": "_toolchain_config", + "attributes": { + "name": "rules_java~7.1.0~toolchains~remotejdk21_win_toolchain_config_repo", + "build_file": "\nconfig_setting(\n name = \"prefix_version_setting\",\n values = {\"java_runtime_version\": \"remotejdk_21\"},\n visibility = [\"//visibility:private\"],\n)\nconfig_setting(\n name = \"version_setting\",\n values = {\"java_runtime_version\": \"21\"},\n visibility = [\"//visibility:private\"],\n)\nalias(\n name = \"version_or_prefix_version_setting\",\n actual = select({\n \":version_setting\": \":version_setting\",\n \"//conditions:default\": \":prefix_version_setting\",\n }),\n visibility = [\"//visibility:private\"],\n)\ntoolchain(\n name = \"toolchain\",\n target_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\ntoolchain(\n name = \"bootstrap_runtime_toolchain\",\n # These constraints are not required for correctness, but prevent fetches of remote JDK for\n # different architectures. As every Java compilation toolchain depends on a bootstrap runtime in\n # the same configuration, this constraint will not result in toolchain resolution failures.\n exec_compatible_with = [\"@platforms//os:windows\", \"@platforms//cpu:x86_64\"],\n target_settings = [\":version_or_prefix_version_setting\"],\n toolchain_type = \"@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type\",\n toolchain = \"@remotejdk21_win//:jdk\",\n)\n" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_java~7.1.0", + "bazel_tools", + "bazel_tools" + ], + [ + "rules_java~7.1.0", + "remote_java_tools", + "rules_java~7.1.0~toolchains~remote_java_tools" + ] + ] + } + }, + "@@rules_python~0.31.0//python/extensions:python.bzl%python": { + "general": { + "bzlTransitiveDigest": "nfcQ92K2B0JOoUwqlGTKoGF7+XoHjDW/y8t8LMG8TE4=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "python_3_11_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_11_s390x-unknown-linux-gnu", + "sha256": "49520e3ff494708020f306e30b0964f079170be83e956be4504f850557378a22", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_host": { + "bzlFile": "@@rules_python~0.31.0//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_11_host", + "python_version": "3.11.7", + "user_repository_name": "python_3_11", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_10_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_10_aarch64-apple-darwin", + "sha256": "fd027b1dedf1ea034cdaa272e91771bdf75ddef4c8653b05d224a0645aa2ca3c", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_10_x86_64-apple-darwin", + "sha256": "be0b19b6af1f7d8c667e5abef5505ad06cf72e5a11bb5844970c395a7e5b1275", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_11_aarch64-unknown-linux-gnu", + "sha256": "b102eaf865eb715aa98a8a2ef19037b6cc3ae7dfd4a632802650f29de635aa13", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_11_aarch64-apple-darwin", + "sha256": "b042c966920cf8465385ca3522986b12d745151a72c060991088977ca36d3883", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_10_ppc64le-unknown-linux-gnu", + "sha256": "f3f9c43eec1a0c3f72845d0b705da17a336d3906b7df212d2640b8f47e8ff375", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_10_x86_64-pc-windows-msvc", + "sha256": "b8d930ce0d04bda83037ad3653d7450f8907c88e24bb8255a29b8dab8930d6f1", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "pythons_hub": { + "bzlFile": "@@rules_python~0.31.0//python/private/bzlmod:pythons_hub.bzl", + "ruleClassName": "hub_repo", + "attributes": { + "name": "rules_python~0.31.0~python~pythons_hub", + "default_python_version": "3.10", + "toolchain_prefixes": [ + "_0000_python_3_11_", + "_0001_python_3_10_" + ], + "toolchain_python_versions": [ + "3.11", + "3.10" + ], + "toolchain_set_python_version_constraints": [ + "True", + "False" + ], + "toolchain_user_repository_names": [ + "python_3_11", + "python_3_10" + ] + } + }, + "python_3_11_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_11_x86_64-pc-windows-msvc", + "sha256": "67077e6fa918e4f4fd60ba169820b00be7c390c497bf9bc9cab2c255ea8e6f3e", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_10_aarch64-unknown-linux-gnu", + "sha256": "8675915ff454ed2f1597e27794bc7df44f5933c26b94aa06af510fe91b58bb97", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11": { + "bzlFile": "@@rules_python~0.31.0//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_11", + "python_version": "3.11.7", + "user_repository_name": "python_3_11", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_10_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_10_s390x-unknown-linux-gnu", + "sha256": "859f6cfe9aedb6e8858892fdc124037e83ab05f28d42a7acd314c6a16d6bd66c", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10": { + "bzlFile": "@@rules_python~0.31.0//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_10", + "python_version": "3.10.13", + "user_repository_name": "python_3_10", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_11_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_11_ppc64le-unknown-linux-gnu", + "sha256": "b44e1b74afe75c7b19143413632c4386708ae229117f8f950c2094e9681d34c7", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_11_x86_64-apple-darwin", + "sha256": "a0e615eef1fafdc742da0008425a9030b7ea68a4ae4e73ac557ef27b112836d4", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_versions": { + "bzlFile": "@@rules_python~0.31.0//python/private:toolchains_repo.bzl", + "ruleClassName": "multi_toolchain_aliases", + "attributes": { + "name": "rules_python~0.31.0~python~python_versions", + "python_versions": { + "3.10": "python_3_10", + "3.11": "python_3_11" + } + } + }, + "python_3_10_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_10_x86_64-unknown-linux-gnu", + "sha256": "5d0429c67c992da19ba3eb58b3acd0b35ec5e915b8cae9a4aa8ca565c423847a", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_host": { + "bzlFile": "@@rules_python~0.31.0//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_10_host", + "python_version": "3.10.13", + "user_repository_name": "python_3_10", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_11_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~0.31.0//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "name": "rules_python~0.31.0~python~python_3_11_x86_64-unknown-linux-gnu", + "sha256": "4a51ce60007a6facf64e5495f4cf322e311ba9f39a8cd3f3e4c026eae488e140", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_python~0.31.0", + "bazel_skylib", + "bazel_skylib~1.5.0" + ], + [ + "rules_python~0.31.0", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_python~0.31.0//python/private/bzlmod:internal_deps.bzl%internal_deps": { + "general": { + "bzlTransitiveDigest": "YM6cXp9AuQVARYWBY5VPn25r/wLyW6Lq09HCAiVNngE=", + "accumulatedFileDigests": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "pypi__wheel": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__wheel", + "url": "https://files.pythonhosted.org/packages/b8/8b/31273bf66016be6ad22bb7345c37ff350276cfd46e389a0c2ac5da9d9073/wheel-0.41.2-py3-none-any.whl", + "sha256": "75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__click": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__click", + "url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", + "sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__importlib_metadata": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__importlib_metadata", + "url": "https://files.pythonhosted.org/packages/cc/37/db7ba97e676af155f5fcb1a35466f446eadc9104e25b83366e8088c9c926/importlib_metadata-6.8.0-py3-none-any.whl", + "sha256": "3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pyproject_hooks": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__pyproject_hooks", + "url": "https://files.pythonhosted.org/packages/d5/ea/9ae603de7fbb3df820b23a70f6aff92bf8c7770043254ad8d2dc9d6bcba4/pyproject_hooks-1.0.0-py3-none-any.whl", + "sha256": "283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pep517": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__pep517", + "url": "https://files.pythonhosted.org/packages/ee/2f/ef63e64e9429111e73d3d6cbee80591672d16f2725e648ebc52096f3d323/pep517-0.13.0-py3-none-any.whl", + "sha256": "4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__packaging": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__packaging", + "url": "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl", + "sha256": "994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pip_tools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__pip_tools", + "url": "https://files.pythonhosted.org/packages/e8/df/47e6267c6b5cdae867adbdd84b437393e6202ce4322de0a5e0b92960e1d6/pip_tools-7.3.0-py3-none-any.whl", + "sha256": "8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__setuptools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__setuptools", + "url": "https://files.pythonhosted.org/packages/4f/ab/0bcfebdfc3bfa8554b2b2c97a555569c4c1ebc74ea288741ea8326c51906/setuptools-68.1.2-py3-none-any.whl", + "sha256": "3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__zipp": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__zipp", + "url": "https://files.pythonhosted.org/packages/8c/08/d3006317aefe25ea79d3b76c9650afabaf6d63d1c8443b236e7405447503/zipp-3.16.2-py3-none-any.whl", + "sha256": "679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__colorama": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__colorama", + "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", + "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__build": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__build", + "url": "https://files.pythonhosted.org/packages/58/91/17b00d5fac63d3dca605f1b8269ba3c65e98059e1fd99d00283e42a454f0/build-0.10.0-py3-none-any.whl", + "sha256": "af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "rules_python_internal": { + "bzlFile": "@@rules_python~0.31.0//python/private:internal_config_repo.bzl", + "ruleClassName": "internal_config_repo", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~rules_python_internal" + } + }, + "pypi__pip": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__pip", + "url": "https://files.pythonhosted.org/packages/50/c2/e06851e8cc28dcad7c155f4753da8833ac06a5c704c109313b8d5a62968a/pip-23.2.1-py3-none-any.whl", + "sha256": "7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__installer": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__installer", + "url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl", + "sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__more_itertools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__more_itertools", + "url": "https://files.pythonhosted.org/packages/5a/cb/6dce742ea14e47d6f565589e859ad225f2a5de576d7696e0623b784e226b/more_itertools-10.1.0-py3-none-any.whl", + "sha256": "64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__tomli": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "name": "rules_python~0.31.0~internal_deps~pypi__tomli", + "url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", + "sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_python~0.31.0", + "bazel_tools", + "bazel_tools" + ] + ] + } + } + } +} diff --git a/WORKSPACE b/WORKSPACE index c1ff813..0976905 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -4,42 +4,6 @@ workspace( load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -http_archive( - name = "rules_python", - sha256 = "a868059c8c6dd6ad45a205cca04084c652cfe1852e6df2d5aca036f6e5438380", - strip_prefix = "rules_python-0.14.0", - url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.14.0.tar.gz", -) - -load("@rules_python//python:repositories.bzl", "python_register_toolchains") - -python_register_toolchains( - name = "python3_10", - # Available versions are listed in @rules_python//python:versions.bzl. - # We recommend using the same version your team is already standardized on. - python_version = "3.10.6", -) - -load("@python3_10//:defs.bzl", "interpreter") -load("@rules_python//python:pip.bzl", "pip_parse") - -pip_parse( - name = "py_proto_deps", - python_interpreter_target = interpreter, - requirements_lock = "//src:requirements.txt", -) - -http_archive( - name = "bazel_skylib", - sha256 = "97e70364e9249702246c0e9444bccdc4b847bed1eb03c5a3ece4f83dfe6abc44", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz", - "https://github.com/bazelbuild/bazel-skylib/releases/download/1.0.2/bazel-skylib-1.0.2.tar.gz", - ], -) - -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - http_archive( name = "com_google_protobuf", build_file_content = """