structurize 3.6.1__tar.gz → 3.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {structurize-3.6.1/structurize.egg-info → structurize-3.7.1}/PKG-INFO +1 -1
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/__init__.py +30 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/_version.py +3 -3
- structurize-3.7.1/avrotize/avrotocapnproto.py +207 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotocsharp.py +230 -68
- structurize-3.7.1/avrotize/avrotocue.py +145 -0
- structurize-3.7.1/avrotize/avrotoflatbuffers.py +179 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotojstruct.py +20 -0
- structurize-3.7.1/avrotize/avrotojtd.py +228 -0
- structurize-3.7.1/avrotize/avrotoraml.py +144 -0
- structurize-3.7.1/avrotize/avrotosmithy.py +311 -0
- structurize-3.7.1/avrotize/avrotosurreal.py +138 -0
- structurize-3.7.1/avrotize/avrotothrift.py +140 -0
- structurize-3.7.1/avrotize/capnprototoavro.py +407 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/commands.json +1288 -3
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/common.py +18 -0
- structurize-3.7.1/avrotize/cuetoavro.py +450 -0
- structurize-3.7.1/avrotize/cuetostructure.py +67 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/dependency_resolver.py +60 -1
- structurize-3.7.1/avrotize/flatbufferstoavro.py +433 -0
- structurize-3.7.1/avrotize/flatbufferstojstruct.py +76 -0
- structurize-3.7.1/avrotize/jstructtoflatbuffers.py +23 -0
- structurize-3.7.1/avrotize/jstructtoraml.py +20 -0
- structurize-3.7.1/avrotize/jstructtosmithy.py +24 -0
- structurize-3.7.1/avrotize/jtdtoavro.py +233 -0
- structurize-3.7.1/avrotize/jtdtostructure.py +24 -0
- structurize-3.7.1/avrotize/ramltoavro.py +251 -0
- structurize-3.7.1/avrotize/ramltojstruct.py +20 -0
- structurize-3.7.1/avrotize/smithytoavro.py +542 -0
- structurize-3.7.1/avrotize/smithytojstruct.py +24 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretocsharp.py +167 -37
- structurize-3.7.1/avrotize/structuretocue.py +26 -0
- structurize-3.7.1/avrotize/structuretojtd.py +24 -0
- structurize-3.7.1/avrotize/structuretoparquet.py +296 -0
- structurize-3.7.1/avrotize/surrealtoavro.py +318 -0
- structurize-3.7.1/avrotize/thriftstructure.py +48 -0
- structurize-3.7.1/avrotize/thrifttoavro.py +412 -0
- {structurize-3.6.1 → structurize-3.7.1/structurize.egg-info}/PKG-INFO +1 -1
- {structurize-3.6.1 → structurize-3.7.1}/structurize.egg-info/SOURCES.txt +56 -0
- {structurize-3.6.1 → structurize-3.7.1}/.gitignore +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/LICENSE +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/MANIFEST.in +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/README.md +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/__main__.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/asn1toavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotize.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotocpp.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotocsv.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotodatapackage.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotodb.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotogo.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotographql.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotoiceberg.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotojava.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotojs.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotojsons.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotokusto.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotomd.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotools.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotoparquet.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotoproto.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotopython.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotorust.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotots.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrototsml.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrotoxsd.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/avrovalidator.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/cddltostructure.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/choice_inference.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/constants.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/csvtoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/datapackagetoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/dependencies/cpp/vcpkg/vcpkg.json +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/dependencies/typescript/node22/package.json +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/dependency_version.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/jsonstoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/jsonstostructure.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/jsontoschema.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/jstructtoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/kstructtoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/kustotoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/kustotojstruct.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/mcp_server.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/openapitostructure.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/parquettoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/proto2parser.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/proto3parser.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/prototoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/schema_inference.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/sqltoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretocddl.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretocpp.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretocsv.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretodatapackage.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretodb.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretogo.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretographql.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretoiceberg.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretojava.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretojs.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretojsons.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretokusto.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretomd.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretoproto.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretopython.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretorust.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretots.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretotsml.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/structuretoxsd.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/tmslvalidate.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/validate.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/xmltoschema.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/avrotize/xsdtoavro.py +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/build.ps1 +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/build.sh +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/pyproject.toml +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/setup.cfg +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/structurize.egg-info/dependency_links.txt +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/structurize.egg-info/entry_points.txt +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/structurize.egg-info/requires.txt +0 -0
- {structurize-3.6.1 → structurize-3.7.1}/structurize.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: structurize
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.7.1
|
|
4
4
|
Summary: Tools to convert from and to JSON Structure from various other schema languages.
|
|
5
5
|
Author-email: Clemens Vasters <clemensv@microsoft.com>
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -25,6 +25,28 @@ class LazyLoader:
|
|
|
25
25
|
# Define the functions and their corresponding module paths
|
|
26
26
|
_mappings = {
|
|
27
27
|
"convert_proto_to_avro": (f"{mod}.prototoavro", "convert_proto_to_avro"),
|
|
28
|
+
"convert_jtd_to_avro": (f"{mod}.jtdtoavro", "convert_jtd_to_avro"),
|
|
29
|
+
"convert_avro_to_jtd": (f"{mod}.avrotojtd", "convert_avro_to_jtd"),
|
|
30
|
+
"convert_jtd_to_structure": (f"{mod}.jtdtostructure", "convert_jtd_to_structure"),
|
|
31
|
+
"convert_structure_to_jtd": (f"{mod}.structuretojtd", "convert_structure_to_jtd"),
|
|
32
|
+
"convert_surrealql_to_avro": (f"{mod}.surrealtoavro", "convert_surrealql_to_avro"),
|
|
33
|
+
"convert_avro_to_surrealql": (f"{mod}.avrotosurreal", "convert_avro_to_surrealql"),
|
|
34
|
+
"convert_flatbuffers_to_avro": (f"{mod}.flatbufferstoavro", "convert_flatbuffers_to_avro"),
|
|
35
|
+
"convert_avro_to_flatbuffers": (f"{mod}.avrotoflatbuffers", "convert_avro_to_flatbuffers"),
|
|
36
|
+
"convert_flatbuffers_to_json_structure": (f"{mod}.flatbufferstojstruct", "convert_flatbuffers_to_json_structure"),
|
|
37
|
+
"convert_json_structure_to_flatbuffers": (f"{mod}.jstructtoflatbuffers", "convert_json_structure_to_flatbuffers"),
|
|
38
|
+
"convert_thrift_to_avro": (f"{mod}.thrifttoavro", "convert_thrift_to_avro"),
|
|
39
|
+
"convert_avro_to_thrift": (f"{mod}.avrotothrift", "convert_avro_to_thrift"),
|
|
40
|
+
"convert_thrift_to_structure": (f"{mod}.thriftstructure", "convert_thrift_to_structure"),
|
|
41
|
+
"convert_structure_to_thrift": (f"{mod}.thriftstructure", "convert_structure_to_thrift"),
|
|
42
|
+
"convert_smithy_to_avro": (f"{mod}.smithytoavro", "convert_smithy_to_avro"),
|
|
43
|
+
"convert_avro_to_smithy": (f"{mod}.avrotosmithy", "convert_avro_to_smithy"),
|
|
44
|
+
"convert_smithy_to_json_structure": (f"{mod}.smithytojstruct", "convert_smithy_to_json_structure"),
|
|
45
|
+
"convert_json_structure_to_smithy": (f"{mod}.jstructtosmithy", "convert_json_structure_to_smithy"),
|
|
46
|
+
"convert_raml_to_avro": (f"{mod}.ramltoavro", "convert_raml_to_avro"),
|
|
47
|
+
"convert_avro_to_raml": (f"{mod}.avrotoraml", "convert_avro_to_raml"),
|
|
48
|
+
"convert_raml_to_json_structure": (f"{mod}.ramltojstruct", "convert_raml_to_json_structure"),
|
|
49
|
+
"convert_json_structure_to_raml": (f"{mod}.jstructtoraml", "convert_json_structure_to_raml"),
|
|
28
50
|
"convert_jsons_to_avro": (f"{mod}.jsonstoavro", "convert_jsons_to_avro"),
|
|
29
51
|
"convert_kafka_struct_to_avro_schema": (f"{mod}.kstructtoavro", "convert_kafka_struct_to_avro_schema"),
|
|
30
52
|
"convert_kusto_to_avro": (f"{mod}.kustotoavro", "convert_kusto_to_avro"),
|
|
@@ -35,6 +57,14 @@ _mappings = {
|
|
|
35
57
|
"convert_avro_to_kusto_db": (f"{mod}.avrotokusto", "convert_avro_to_kusto_db"),
|
|
36
58
|
"convert_avro_to_parquet": (f"{mod}.avrotoparquet", "convert_avro_to_parquet"),
|
|
37
59
|
"convert_avro_to_proto": (f"{mod}.avrotoproto", "convert_avro_to_proto"),
|
|
60
|
+
"convert_cue_to_avro": (f"{mod}.cuetoavro", "convert_cue_to_avro"),
|
|
61
|
+
"convert_avro_to_cue": (f"{mod}.avrotocue", "convert_avro_to_cue"),
|
|
62
|
+
"convert_cue_to_json_structure": (f"{mod}.cuetostructure", "convert_cue_to_json_structure"),
|
|
63
|
+
"convert_json_structure_to_cue": (f"{mod}.structuretocue", "convert_json_structure_to_cue"),
|
|
64
|
+
"convert_capnproto_to_avro": (f"{mod}.capnprototoavro", "convert_capnproto_to_avro"),
|
|
65
|
+
"convert_avro_to_capnproto": (f"{mod}.avrotocapnproto", "convert_avro_to_capnproto"),
|
|
66
|
+
"convert_capnproto_to_json_structure": (f"{mod}.capnprototoavro", "convert_capnproto_to_json_structure"),
|
|
67
|
+
"convert_json_structure_to_capnproto": (f"{mod}.avrotocapnproto", "convert_json_structure_to_capnproto"),
|
|
38
68
|
"convert_avro_to_sql": (f"{mod}.avrotodb", "convert_avro_to_sql"),
|
|
39
69
|
"convert_avro_to_xsd": (f"{mod}.avrotoxsd", "convert_avro_to_xsd"),
|
|
40
70
|
"convert_avro_to_java": (f"{mod}.avrotojava", "convert_avro_to_java"),
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '3.
|
|
22
|
-
__version_tuple__ = version_tuple = (3,
|
|
21
|
+
__version__ = version = '3.7.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (3, 7, 1)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g2f9460efb'
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Convert Avrotize/Avro schemas to Cap'n Proto .capnp schemas."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import os
|
|
7
|
+
import re
|
|
8
|
+
import tempfile
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from avrotize.common import unique_name
|
|
12
|
+
|
|
13
|
+
INDENT = " "
|
|
14
|
+
FILE_ID = "0xd12f8a7e9b0c4a6f"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _safe_ident(name: str) -> str:
|
|
18
|
+
safe = re.sub(r"[^A-Za-z0-9_]", "_", name)
|
|
19
|
+
if not safe or safe[0].isdigit():
|
|
20
|
+
safe = f"_{safe}"
|
|
21
|
+
return safe
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _type_name(schema: dict[str, Any]) -> str:
|
|
25
|
+
namespace = schema.get("namespace")
|
|
26
|
+
name = schema["name"]
|
|
27
|
+
return f"{namespace}.{name}" if namespace else name
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class AvroToCapnpConverter:
|
|
31
|
+
primitive_map = {
|
|
32
|
+
"null": "Void",
|
|
33
|
+
"boolean": "Bool",
|
|
34
|
+
"int": "Int32",
|
|
35
|
+
"long": "Int64",
|
|
36
|
+
"float": "Float32",
|
|
37
|
+
"double": "Float64",
|
|
38
|
+
"bytes": "Data",
|
|
39
|
+
"string": "Text",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
def __init__(self, namespace: str | None = None) -> None:
|
|
43
|
+
self.namespace = namespace
|
|
44
|
+
self.named: dict[str, dict[str, Any]] = {}
|
|
45
|
+
self.emitted: set[str] = set()
|
|
46
|
+
self.type_names: dict[int, str] = {}
|
|
47
|
+
self.top_level_type_names: set[str] = set()
|
|
48
|
+
|
|
49
|
+
def convert(self, avro_schema: Any) -> str:
|
|
50
|
+
schemas = avro_schema if isinstance(avro_schema, list) else [avro_schema]
|
|
51
|
+
for schema in schemas:
|
|
52
|
+
if isinstance(schema, dict) and schema.get("type") in {"record", "enum"}:
|
|
53
|
+
self.named[schema["name"]] = schema
|
|
54
|
+
self.named[_type_name(schema)] = schema
|
|
55
|
+
self._assign_type_name(schema, self.top_level_type_names)
|
|
56
|
+
lines = [f"@{FILE_ID};", ""]
|
|
57
|
+
if self.namespace:
|
|
58
|
+
lines.append(f"# namespace: {self.namespace}")
|
|
59
|
+
lines.append("# Generated by avrotize. File id is stable for deterministic output; replace if needed.")
|
|
60
|
+
lines.append("")
|
|
61
|
+
for schema in schemas:
|
|
62
|
+
if isinstance(schema, dict) and schema.get("type") in {"enum", "record"}:
|
|
63
|
+
name = _type_name(schema)
|
|
64
|
+
if name not in self.emitted:
|
|
65
|
+
lines.extend(self._render_named(schema, 0, self.top_level_type_names))
|
|
66
|
+
lines.append("")
|
|
67
|
+
return "\n".join(lines).rstrip() + "\n"
|
|
68
|
+
|
|
69
|
+
def _assign_type_name(self, schema: dict[str, Any], used: set[str] | None = None) -> str:
|
|
70
|
+
key = id(schema)
|
|
71
|
+
if key not in self.type_names:
|
|
72
|
+
self.type_names[key] = unique_name(_safe_ident(schema["name"]), used if used is not None else self.top_level_type_names)
|
|
73
|
+
return self.type_names[key]
|
|
74
|
+
|
|
75
|
+
def _render_named(self, schema: dict[str, Any], level: int, used_type_names: set[str] | None = None) -> list[str]:
|
|
76
|
+
if schema.get("type") == "enum":
|
|
77
|
+
return self._render_enum(schema, level, used_type_names)
|
|
78
|
+
if schema.get("type") == "record":
|
|
79
|
+
return self._render_struct(schema, level, used_type_names)
|
|
80
|
+
return []
|
|
81
|
+
|
|
82
|
+
def _render_enum(self, schema: dict[str, Any], level: int, used_type_names: set[str] | None = None) -> list[str]:
|
|
83
|
+
self.emitted.add(_type_name(schema))
|
|
84
|
+
lines = [f"{INDENT * level}enum {self._assign_type_name(schema, used_type_names)} {{"]
|
|
85
|
+
used_symbols: set[str] = set()
|
|
86
|
+
for index, symbol in enumerate(schema.get("symbols", [])):
|
|
87
|
+
lines.append(f"{INDENT * (level + 1)}{unique_name(_safe_ident(symbol), used_symbols)} @{index};")
|
|
88
|
+
lines.append(f"{INDENT * level}}}")
|
|
89
|
+
return lines
|
|
90
|
+
|
|
91
|
+
def _render_struct(self, schema: dict[str, Any], level: int, used_type_names: set[str] | None = None) -> list[str]:
|
|
92
|
+
self.emitted.add(_type_name(schema))
|
|
93
|
+
lines = [f"{INDENT * level}struct {self._assign_type_name(schema, used_type_names)} {{"]
|
|
94
|
+
fields = schema.get("fields", [])
|
|
95
|
+
grouped: dict[str, list[tuple[int, dict[str, Any], Any, str]]] = {}
|
|
96
|
+
normal: list[tuple[int, dict[str, Any], Any, str]] = []
|
|
97
|
+
used_fields: set[str] = set()
|
|
98
|
+
for index, field in enumerate(fields):
|
|
99
|
+
avro_type = field.get("type")
|
|
100
|
+
union_name = field.get("capnpUnion")
|
|
101
|
+
safe_field_name = unique_name(_safe_ident(field.get("name", f"field{index}")), used_fields)
|
|
102
|
+
item = (index, field, avro_type, safe_field_name)
|
|
103
|
+
if union_name:
|
|
104
|
+
grouped.setdefault(str(union_name), []).append(item)
|
|
105
|
+
else:
|
|
106
|
+
normal.append(item)
|
|
107
|
+
nested_type_names: set[str] = set()
|
|
108
|
+
for index, field, avro_type, safe_field_name in normal:
|
|
109
|
+
lines.extend(self._render_field(field, avro_type, index, level + 1, safe_field_name, nested_type_names))
|
|
110
|
+
for _, items in grouped.items():
|
|
111
|
+
lines.append(f"{INDENT * (level + 1)}union {{")
|
|
112
|
+
for index, field, avro_type, safe_field_name in items:
|
|
113
|
+
lines.extend(self._render_field(field, avro_type, index, level + 2, safe_field_name, nested_type_names))
|
|
114
|
+
lines.append(f"{INDENT * (level + 1)}}}")
|
|
115
|
+
lines.append(f"{INDENT * level}}}")
|
|
116
|
+
return lines
|
|
117
|
+
|
|
118
|
+
def _render_field(
|
|
119
|
+
self,
|
|
120
|
+
field: dict[str, Any],
|
|
121
|
+
avro_type: Any,
|
|
122
|
+
index: int,
|
|
123
|
+
level: int,
|
|
124
|
+
safe_field_name: str,
|
|
125
|
+
used_type_names: set[str],
|
|
126
|
+
) -> list[str]:
|
|
127
|
+
capnp_type, nested = self._capnp_type(avro_type, safe_field_name, used_type_names)
|
|
128
|
+
ordinal = index
|
|
129
|
+
lines: list[str] = []
|
|
130
|
+
lines.extend(self._render_inline_nested(nested, level, used_type_names))
|
|
131
|
+
lines.append(f"{INDENT * level}{safe_field_name} @{ordinal} :{capnp_type};")
|
|
132
|
+
return lines
|
|
133
|
+
|
|
134
|
+
def _render_inline_nested(self, nested: list[dict[str, Any]], level: int, used_type_names: set[str]) -> list[str]:
|
|
135
|
+
lines: list[str] = []
|
|
136
|
+
for schema in nested:
|
|
137
|
+
lines.extend(self._render_named(schema, level, used_type_names))
|
|
138
|
+
return lines
|
|
139
|
+
|
|
140
|
+
def _non_null_union(self, avro_type: list[Any]) -> list[Any]:
|
|
141
|
+
return [item for item in avro_type if item != "null" and not (isinstance(item, dict) and item.get("type") == "null")]
|
|
142
|
+
|
|
143
|
+
def _capnp_type(self, avro_type: Any, field_name: str, used_type_names: set[str] | None = None) -> tuple[str, list[dict[str, Any]]]:
|
|
144
|
+
used_type_names = used_type_names if used_type_names is not None else self.top_level_type_names
|
|
145
|
+
if isinstance(avro_type, list):
|
|
146
|
+
non_null = self._non_null_union(avro_type)
|
|
147
|
+
if len(non_null) == 1:
|
|
148
|
+
return self._capnp_type(non_null[0], field_name, used_type_names)
|
|
149
|
+
union_schema = {
|
|
150
|
+
"type": "record",
|
|
151
|
+
"name": f"{field_name[:1].upper()}{field_name[1:]}Choice",
|
|
152
|
+
"fields": [{"name": f"choice{i}", "type": t, "capnpUnion": "union"} for i, t in enumerate(non_null)],
|
|
153
|
+
}
|
|
154
|
+
return self._assign_type_name(union_schema, used_type_names), [union_schema]
|
|
155
|
+
if isinstance(avro_type, dict):
|
|
156
|
+
avro_kind = avro_type.get("type")
|
|
157
|
+
if isinstance(avro_kind, list):
|
|
158
|
+
return self._capnp_type(avro_kind, field_name, used_type_names)
|
|
159
|
+
if avro_kind == "array":
|
|
160
|
+
item_type, nested = self._capnp_type(avro_type.get("items", "string"), f"{field_name}Item", used_type_names)
|
|
161
|
+
return f"List({item_type})", nested
|
|
162
|
+
if avro_kind == "map":
|
|
163
|
+
entry = {
|
|
164
|
+
"type": "record",
|
|
165
|
+
"name": f"{field_name[:1].upper()}{field_name[1:]}Entry",
|
|
166
|
+
"fields": [
|
|
167
|
+
{"name": "key", "type": "string"},
|
|
168
|
+
{"name": "value", "type": avro_type.get("values", "string")},
|
|
169
|
+
],
|
|
170
|
+
}
|
|
171
|
+
return f"List({self._assign_type_name(entry, used_type_names)})", [entry]
|
|
172
|
+
if avro_kind == "record":
|
|
173
|
+
return self._assign_type_name(avro_type, used_type_names), [avro_type]
|
|
174
|
+
if avro_kind == "enum":
|
|
175
|
+
return self._assign_type_name(avro_type, used_type_names), [avro_type]
|
|
176
|
+
if avro_kind == "fixed":
|
|
177
|
+
return "Data", []
|
|
178
|
+
return self._capnp_type(avro_kind, field_name, used_type_names)
|
|
179
|
+
if isinstance(avro_type, str):
|
|
180
|
+
named = self.named.get(avro_type)
|
|
181
|
+
if named:
|
|
182
|
+
return self._assign_type_name(named), []
|
|
183
|
+
return self.primitive_map.get(avro_type, _safe_ident(avro_type.split(".")[-1])), []
|
|
184
|
+
return "Text", []
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def convert_avro_to_capnproto(avro_schema_path: str, capnp_file_path: str, namespace: str | None = None) -> None:
|
|
188
|
+
"""Convert an Avrotize/Avro schema file to a Cap'n Proto .capnp schema file."""
|
|
189
|
+
with open(avro_schema_path, "r", encoding="utf-8") as avro_file:
|
|
190
|
+
avro_schema = json.load(avro_file)
|
|
191
|
+
converter = AvroToCapnpConverter(namespace=namespace)
|
|
192
|
+
capnp_schema = converter.convert(avro_schema)
|
|
193
|
+
os.makedirs(os.path.dirname(os.path.abspath(capnp_file_path)) or ".", exist_ok=True)
|
|
194
|
+
with open(capnp_file_path, "w", encoding="utf-8") as capnp_file:
|
|
195
|
+
capnp_file.write(capnp_schema)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def convert_json_structure_to_capnproto(structure_file: str, capnp_file_path: str, namespace: str | None = None) -> None:
|
|
199
|
+
"""Convert JSON Structure to Cap'n Proto by bridging through Avrotize/Avro."""
|
|
200
|
+
from avrotize.jstructtoavro import convert_json_structure_to_avro
|
|
201
|
+
|
|
202
|
+
temp_parent = os.path.dirname(os.path.abspath(capnp_file_path)) or os.getcwd()
|
|
203
|
+
os.makedirs(temp_parent, exist_ok=True)
|
|
204
|
+
with tempfile.TemporaryDirectory(prefix="avrotize-capnp-", dir=temp_parent) as temp_dir:
|
|
205
|
+
avro_file = os.path.join(temp_dir, "schema.avsc")
|
|
206
|
+
convert_json_structure_to_avro(structure_file, avro_file)
|
|
207
|
+
convert_avro_to_capnproto(avro_file, capnp_file_path, namespace=namespace)
|