structurize 2.19.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- avrotize/__init__.py +64 -0
- avrotize/__main__.py +6 -0
- avrotize/_version.py +34 -0
- avrotize/asn1toavro.py +160 -0
- avrotize/avrotize.py +152 -0
- avrotize/avrotocpp.py +483 -0
- avrotize/avrotocsharp.py +1075 -0
- avrotize/avrotocsv.py +121 -0
- avrotize/avrotodatapackage.py +173 -0
- avrotize/avrotodb.py +1383 -0
- avrotize/avrotogo.py +476 -0
- avrotize/avrotographql.py +197 -0
- avrotize/avrotoiceberg.py +210 -0
- avrotize/avrotojava.py +2156 -0
- avrotize/avrotojs.py +250 -0
- avrotize/avrotojsons.py +481 -0
- avrotize/avrotojstruct.py +345 -0
- avrotize/avrotokusto.py +364 -0
- avrotize/avrotomd.py +137 -0
- avrotize/avrotools.py +168 -0
- avrotize/avrotoparquet.py +208 -0
- avrotize/avrotoproto.py +359 -0
- avrotize/avrotopython.py +624 -0
- avrotize/avrotorust.py +435 -0
- avrotize/avrotots.py +598 -0
- avrotize/avrotoxsd.py +344 -0
- avrotize/cddltostructure.py +1841 -0
- avrotize/commands.json +3337 -0
- avrotize/common.py +834 -0
- avrotize/constants.py +72 -0
- avrotize/csvtoavro.py +132 -0
- avrotize/datapackagetoavro.py +76 -0
- avrotize/dependencies/cpp/vcpkg/vcpkg.json +19 -0
- avrotize/dependencies/typescript/node22/package.json +16 -0
- avrotize/dependency_resolver.py +348 -0
- avrotize/dependency_version.py +432 -0
- avrotize/jsonstoavro.py +2167 -0
- avrotize/jsonstostructure.py +2642 -0
- avrotize/jstructtoavro.py +878 -0
- avrotize/kstructtoavro.py +93 -0
- avrotize/kustotoavro.py +455 -0
- avrotize/parquettoavro.py +157 -0
- avrotize/proto2parser.py +498 -0
- avrotize/proto3parser.py +403 -0
- avrotize/prototoavro.py +382 -0
- avrotize/structuretocddl.py +597 -0
- avrotize/structuretocpp.py +697 -0
- avrotize/structuretocsharp.py +2295 -0
- avrotize/structuretocsv.py +365 -0
- avrotize/structuretodatapackage.py +659 -0
- avrotize/structuretodb.py +1125 -0
- avrotize/structuretogo.py +720 -0
- avrotize/structuretographql.py +502 -0
- avrotize/structuretoiceberg.py +355 -0
- avrotize/structuretojava.py +853 -0
- avrotize/structuretojsons.py +498 -0
- avrotize/structuretokusto.py +639 -0
- avrotize/structuretomd.py +322 -0
- avrotize/structuretoproto.py +764 -0
- avrotize/structuretopython.py +772 -0
- avrotize/structuretorust.py +714 -0
- avrotize/structuretots.py +653 -0
- avrotize/structuretoxsd.py +679 -0
- avrotize/xsdtoavro.py +413 -0
- structurize-2.19.0.dist-info/METADATA +107 -0
- structurize-2.19.0.dist-info/RECORD +70 -0
- structurize-2.19.0.dist-info/WHEEL +5 -0
- structurize-2.19.0.dist-info/entry_points.txt +2 -0
- structurize-2.19.0.dist-info/licenses/LICENSE +201 -0
- structurize-2.19.0.dist-info/top_level.txt +1 -0
avrotize/__init__.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
|
|
3
|
+
mod = "avrotize"
|
|
4
|
+
class LazyLoader:
|
|
5
|
+
"""
|
|
6
|
+
Lazy loader for the avrotize functions to speed up startup time.
|
|
7
|
+
"""
|
|
8
|
+
def __init__(self, mappings):
|
|
9
|
+
self._modules = {}
|
|
10
|
+
self._mappings = mappings
|
|
11
|
+
|
|
12
|
+
def _load_module(self, module_name):
|
|
13
|
+
if module_name not in self._modules:
|
|
14
|
+
self._modules[module_name] = importlib.import_module(module_name)
|
|
15
|
+
return self._modules[module_name]
|
|
16
|
+
|
|
17
|
+
def __getattr__(self, item):
|
|
18
|
+
if item in self._mappings:
|
|
19
|
+
module_name, func_name = self._mappings[item]
|
|
20
|
+
module = self._load_module(module_name)
|
|
21
|
+
return getattr(module, func_name)
|
|
22
|
+
else:
|
|
23
|
+
return self._load_module(f"{mod}.{item}")
|
|
24
|
+
|
|
25
|
+
# Define the functions and their corresponding module paths
|
|
26
|
+
_mappings = {
|
|
27
|
+
"convert_proto_to_avro": (f"{mod}.prototoavro", "convert_proto_to_avro"),
|
|
28
|
+
"convert_jsons_to_avro": (f"{mod}.jsonstoavro", "convert_jsons_to_avro"),
|
|
29
|
+
"convert_kafka_struct_to_avro_schema": (f"{mod}.kstructtoavro", "convert_kafka_struct_to_avro_schema"),
|
|
30
|
+
"convert_kusto_to_avro": (f"{mod}.kustotoavro", "convert_kusto_to_avro"),
|
|
31
|
+
"convert_asn1_to_avro": (f"{mod}.asn1toavro", "convert_asn1_to_avro"),
|
|
32
|
+
"convert_xsd_to_avro": (f"{mod}.xsdtoavro", "convert_xsd_to_avro"),
|
|
33
|
+
"convert_avro_to_json_schema": (f"{mod}.avrotojsons", "convert_avro_to_json_schema"),
|
|
34
|
+
"convert_avro_to_kusto_file": (f"{mod}.avrotokusto", "convert_avro_to_kusto_file"),
|
|
35
|
+
"convert_avro_to_kusto_db": (f"{mod}.avrotokusto", "convert_avro_to_kusto_db"),
|
|
36
|
+
"convert_avro_to_parquet": (f"{mod}.avrotoparquet", "convert_avro_to_parquet"),
|
|
37
|
+
"convert_avro_to_proto": (f"{mod}.avrotoproto", "convert_avro_to_proto"),
|
|
38
|
+
"convert_avro_to_sql": (f"{mod}.avrotodb", "convert_avro_to_sql"),
|
|
39
|
+
"convert_avro_to_xsd": (f"{mod}.avrotoxsd", "convert_avro_to_xsd"),
|
|
40
|
+
"convert_avro_to_java": (f"{mod}.avrotojava", "convert_avro_to_java"),
|
|
41
|
+
"convert_avro_schema_to_java": (f"{mod}.avrotojava", "convert_avro_schema_to_java"),
|
|
42
|
+
"convert_avro_to_csharp": (f"{mod}.avrotocsharp", "convert_avro_to_csharp"),
|
|
43
|
+
"convert_avro_schema_to_csharp": (f"{mod}.avrotocsharp", "convert_avro_schema_to_csharp"),
|
|
44
|
+
"convert_avro_to_python": (f"{mod}.avrotopython", "convert_avro_to_python"),
|
|
45
|
+
"convert_avro_schema_to_python": (f"{mod}.avrotopython", "convert_avro_schema_to_python"),
|
|
46
|
+
"convert_avro_to_typescript": (f"{mod}.avrotots", "convert_avro_to_typescript"),
|
|
47
|
+
"convert_avro_schema_to_typescript": (f"{mod}.avrotots", "convert_avro_schema_to_typescript"),
|
|
48
|
+
"convert_avro_to_javascript": (f"{mod}.avrotojs", "convert_avro_to_javascript"),
|
|
49
|
+
"convert_avro_schema_to_javascript": (f"{mod}.avrotojs", "convert_avro_schema_to_javascript"),
|
|
50
|
+
"convert_avro_to_markdown": (f"{mod}.avrotomd", "convert_avro_to_markdown"),
|
|
51
|
+
"convert_structure_to_markdown": (f"{mod}.structuretomd", "convert_structure_to_markdown"),
|
|
52
|
+
"convert_avro_to_cpp": (f"{mod}.avrotocpp", "convert_avro_to_cpp"),
|
|
53
|
+
"convert_avro_schema_to_cpp": (f"{mod}.avrotocpp", "convert_avro_schema_to_cpp"),
|
|
54
|
+
"convert_avro_to_go": (f"{mod}.avrotogo", "convert_avro_to_go"),
|
|
55
|
+
"convert_avro_schema_to_go": (f"{mod}.avrotogo", "convert_avro_schema_to_go"),
|
|
56
|
+
"convert_avro_to_rust": (f"{mod}.avrotorust", "convert_avro_to_rust"),
|
|
57
|
+
"convert_avro_schema_to_rust": (f"{mod}.avrotorust", "convert_avro_schema_to_rust"),
|
|
58
|
+
"convert_avro_to_datapackage": (f"{mod}.avrotodatapackage", "convert_avro_to_datapackage"),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_lazy_loader = LazyLoader(_mappings)
|
|
62
|
+
|
|
63
|
+
def __getattr__(name):
|
|
64
|
+
return getattr(_lazy_loader, name)
|
avrotize/__main__.py
ADDED
avrotize/_version.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"__version__",
|
|
6
|
+
"__version_tuple__",
|
|
7
|
+
"version",
|
|
8
|
+
"version_tuple",
|
|
9
|
+
"__commit_id__",
|
|
10
|
+
"commit_id",
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
TYPE_CHECKING = False
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from typing import Tuple
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
19
|
+
COMMIT_ID = Union[str, None]
|
|
20
|
+
else:
|
|
21
|
+
VERSION_TUPLE = object
|
|
22
|
+
COMMIT_ID = object
|
|
23
|
+
|
|
24
|
+
version: str
|
|
25
|
+
__version__: str
|
|
26
|
+
__version_tuple__: VERSION_TUPLE
|
|
27
|
+
version_tuple: VERSION_TUPLE
|
|
28
|
+
commit_id: COMMIT_ID
|
|
29
|
+
__commit_id__: COMMIT_ID
|
|
30
|
+
|
|
31
|
+
__version__ = version = '2.19.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (2, 19, 0)
|
|
33
|
+
|
|
34
|
+
__commit_id__ = commit_id = 'geec8f9840'
|
avrotize/asn1toavro.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import List
|
|
3
|
+
import asn1tools
|
|
4
|
+
from asn1tools.codecs.ber import Sequence, SequenceOf, Integer, Boolean, Enumerated, OctetString, IA5String, UTF8String, Date, Real, Choice, Null, SetOf, Recursive, ExplicitTag
|
|
5
|
+
from asn1tools.codecs.ber import BitString, VisibleString, BMPString, GeneralString, GraphicString, NumericString, PrintableString, TeletexString, UniversalString, ObjectIdentifier, Set
|
|
6
|
+
|
|
7
|
+
from avrotize.common import avro_name
|
|
8
|
+
from avrotize.dependency_resolver import sort_messages_by_dependencies
|
|
9
|
+
|
|
10
|
+
def asn1_type_to_avro_type(asn1_type: dict, avro_schema: list, namespace: str, parent_type_name: str | None, parent_member_name: str | None, dependencies: list)-> str | dict | None:
|
|
11
|
+
"""Convert an ASN.1 type to an Avro type."""
|
|
12
|
+
avro_type: str | dict | list | None = None
|
|
13
|
+
deps: List[str] = []
|
|
14
|
+
|
|
15
|
+
if isinstance(asn1_type,Integer):
|
|
16
|
+
avro_type = 'int'
|
|
17
|
+
elif isinstance(asn1_type, Boolean):
|
|
18
|
+
avro_type = 'boolean'
|
|
19
|
+
elif isinstance(asn1_type, Enumerated):
|
|
20
|
+
symbols = [avro_name(member) for member in asn1_type.data_to_value.keys()]
|
|
21
|
+
avro_type = {
|
|
22
|
+
'type': 'enum',
|
|
23
|
+
'name': avro_name(parent_member_name if parent_member_name else asn1_type.name),
|
|
24
|
+
'namespace': namespace,
|
|
25
|
+
'symbols': symbols
|
|
26
|
+
}
|
|
27
|
+
elif isinstance(asn1_type, Sequence) or isinstance(asn1_type, Choice) or isinstance(asn1_type, Set):
|
|
28
|
+
if avro_schema and next((s for s in avro_schema if s.get('name') == asn1_type.type_name), []):
|
|
29
|
+
return namespace + '.' + asn1_type.type_name
|
|
30
|
+
else:
|
|
31
|
+
record_name = asn1_type.type_name if asn1_type.type_name else asn1_type.name
|
|
32
|
+
if record_name == 'CHOICE' or record_name == 'SEQUENCE' or record_name == 'SET':
|
|
33
|
+
if parent_member_name and parent_type_name:
|
|
34
|
+
record_name = parent_type_name + parent_member_name
|
|
35
|
+
elif parent_type_name:
|
|
36
|
+
record_name = parent_type_name
|
|
37
|
+
else:
|
|
38
|
+
raise ValueError(f"Can't name record without a type name and member name")
|
|
39
|
+
|
|
40
|
+
fields = []
|
|
41
|
+
for member in asn1_type.members if isinstance(asn1_type, Choice) else asn1_type.root_members:
|
|
42
|
+
field_type = asn1_type_to_avro_type(member, avro_schema, namespace, record_name, member.name, deps)
|
|
43
|
+
if isinstance(field_type, dict) and (field_type.get('type') == 'record' or field_type.get('type') == 'enum'):
|
|
44
|
+
existing_type = next((t for t in avro_schema if (isinstance(t,dict) and t.get('name') == field_type['name'] and t.get('namespace') == field_type.get('namespace')) ), None)
|
|
45
|
+
if not existing_type:
|
|
46
|
+
field_type['dependencies'] = [dep for dep in deps if dep != field_type['namespace']+'.'+field_type['name']]
|
|
47
|
+
avro_schema.append(field_type)
|
|
48
|
+
field_type = namespace + '.' + field_type.get('name','')
|
|
49
|
+
dependencies.append(field_type)
|
|
50
|
+
if isinstance(asn1_type, Choice):
|
|
51
|
+
field_type = [field_type, 'null']
|
|
52
|
+
fields.append({
|
|
53
|
+
'name': avro_name(member.name),
|
|
54
|
+
'type': field_type
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
avro_type = {
|
|
58
|
+
'type': 'record',
|
|
59
|
+
'name': avro_name(record_name),
|
|
60
|
+
'namespace': namespace,
|
|
61
|
+
'fields': fields
|
|
62
|
+
}
|
|
63
|
+
elif isinstance(asn1_type, BitString):
|
|
64
|
+
avro_type = {
|
|
65
|
+
'type': 'bytes',
|
|
66
|
+
'logicalType': 'bitstring'
|
|
67
|
+
}
|
|
68
|
+
elif isinstance(asn1_type, ObjectIdentifier):
|
|
69
|
+
avro_type = 'string'
|
|
70
|
+
elif isinstance(asn1_type, SequenceOf):
|
|
71
|
+
record_name = asn1_type.name if asn1_type.name else parent_member_name
|
|
72
|
+
if record_name == 'SEQUENCE OF':
|
|
73
|
+
record_name = parent_member_name if parent_member_name else ''
|
|
74
|
+
if parent_type_name:
|
|
75
|
+
record_name = parent_type_name + record_name
|
|
76
|
+
item_type = asn1_type_to_avro_type(asn1_type.element_type, avro_schema, namespace, record_name, 'Item', deps)
|
|
77
|
+
if isinstance(item_type, dict) and not item_type.get('name'):
|
|
78
|
+
item_type['name'] = asn1_type.name + 'Item'
|
|
79
|
+
avro_type = {
|
|
80
|
+
'type': 'array',
|
|
81
|
+
'namespace': namespace,
|
|
82
|
+
'name': avro_name(record_name),
|
|
83
|
+
'items': item_type
|
|
84
|
+
}
|
|
85
|
+
elif isinstance(asn1_type, SetOf):
|
|
86
|
+
record_name = asn1_type.name if asn1_type.name else parent_member_name
|
|
87
|
+
if record_name == 'SET OF':
|
|
88
|
+
record_name = parent_member_name if parent_member_name else ''
|
|
89
|
+
if parent_type_name:
|
|
90
|
+
record_name = parent_type_name + record_name
|
|
91
|
+
item_type = asn1_type_to_avro_type(asn1_type.element_type, avro_schema, namespace, record_name, 'Item', deps)
|
|
92
|
+
if isinstance(item_type, dict) and not item_type.get('name'):
|
|
93
|
+
item_type['name'] = asn1_type.name + 'Item'
|
|
94
|
+
avro_type = {
|
|
95
|
+
'type': 'array',
|
|
96
|
+
'namespace': namespace,
|
|
97
|
+
'name': avro_name(record_name),
|
|
98
|
+
'items': item_type
|
|
99
|
+
}
|
|
100
|
+
elif isinstance(asn1_type, OctetString):
|
|
101
|
+
avro_type = 'bytes'
|
|
102
|
+
elif isinstance(asn1_type, IA5String) or isinstance(asn1_type, UTF8String) or isinstance(asn1_type, VisibleString) or isinstance(asn1_type, BMPString) or isinstance(asn1_type, GeneralString) or isinstance(asn1_type, GraphicString) or isinstance(asn1_type, NumericString) or isinstance(asn1_type, PrintableString) or isinstance(asn1_type, TeletexString) or isinstance(asn1_type, UniversalString):
|
|
103
|
+
avro_type = 'string'
|
|
104
|
+
elif isinstance(asn1_type, Date):
|
|
105
|
+
avro_type = {'type': 'int', 'logicalType': 'date'}
|
|
106
|
+
elif isinstance(asn1_type, Real):
|
|
107
|
+
avro_type = 'double'
|
|
108
|
+
elif isinstance(asn1_type, Null):
|
|
109
|
+
avro_type = 'null'
|
|
110
|
+
elif isinstance(asn1_type, Recursive):
|
|
111
|
+
avro_type = asn1_type.type_name
|
|
112
|
+
elif isinstance(asn1_type, ExplicitTag):
|
|
113
|
+
avro_type = asn1_type_to_avro_type(asn1_type.inner, avro_schema, namespace, parent_type_name, parent_member_name, dependencies)
|
|
114
|
+
if isinstance(avro_type, dict):
|
|
115
|
+
avro_type['name'] = asn1_type.name if asn1_type.name else asn1_type.type_name
|
|
116
|
+
else:
|
|
117
|
+
raise ValueError(f"Don't know how to translate ASN.1 type '{type(asn1_type)}' to Avro")
|
|
118
|
+
|
|
119
|
+
if len(avro_schema) > 0 and isinstance(avro_type, dict) and 'name' in avro_type:
|
|
120
|
+
existing_type = next((t for t in avro_schema if (isinstance(t,dict) and t.get('name') == avro_type['name'] and t.get('namespace') == avro_type.get('namespace')) ), None)
|
|
121
|
+
if existing_type:
|
|
122
|
+
qualified_name = namespace + '.' + existing_type.get('name','')
|
|
123
|
+
dependencies.append(qualified_name)
|
|
124
|
+
return qualified_name
|
|
125
|
+
|
|
126
|
+
return avro_type
|
|
127
|
+
|
|
128
|
+
def convert_asn1_to_avro_schema(asn1_spec_list: List[str]):
|
|
129
|
+
"""Convert ASN.1 specification to Avro schema."""
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
spec = asn1tools.compile_files(asn1_spec_list)
|
|
133
|
+
except asn1tools.ParseError as e:
|
|
134
|
+
print(f"Error parsing ASN.1 files: {e.args[0]}")
|
|
135
|
+
for file in asn1_spec_list:
|
|
136
|
+
print(f" {file}")
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
avro_schema: List[dict] = []
|
|
140
|
+
for module_name, module in spec.modules.items():
|
|
141
|
+
for type_name, asn1_type in module.items():
|
|
142
|
+
dependencies: List [str] = []
|
|
143
|
+
avro_type = asn1_type_to_avro_type(asn1_type.type, avro_schema, avro_name(module_name), type_name, None, dependencies)
|
|
144
|
+
if avro_type and not isinstance(avro_type, str):
|
|
145
|
+
avro_type['dependencies'] = [dep for dep in dependencies if dep != avro_type['namespace'] + '.' + avro_type['name']]
|
|
146
|
+
avro_schema.append(avro_type)
|
|
147
|
+
|
|
148
|
+
avro_schema = sort_messages_by_dependencies(avro_schema)
|
|
149
|
+
|
|
150
|
+
if len(avro_schema) == 1:
|
|
151
|
+
return avro_schema[0]
|
|
152
|
+
return avro_schema
|
|
153
|
+
|
|
154
|
+
def convert_asn1_to_avro(asn1_spec_list: List[str], avro_file_path: str):
|
|
155
|
+
"""Convert ASN.1 specification to Avro schema and save it to a file."""
|
|
156
|
+
avro_schema = convert_asn1_to_avro_schema(asn1_spec_list)
|
|
157
|
+
if avro_schema is None:
|
|
158
|
+
return
|
|
159
|
+
with open(avro_file_path, 'w') as file:
|
|
160
|
+
json.dump(avro_schema, file, indent=4)
|
avrotize/avrotize.py
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""
|
|
2
|
+
|
|
3
|
+
Command line utility to convert a variety of schema formats to Avrotize schema and vice versa.
|
|
4
|
+
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import tempfile
|
|
10
|
+
import sys
|
|
11
|
+
import os
|
|
12
|
+
import json
|
|
13
|
+
try:
|
|
14
|
+
from avrotize import _version
|
|
15
|
+
VERSION = _version.version
|
|
16
|
+
except ImportError:
|
|
17
|
+
VERSION = "dev"
|
|
18
|
+
|
|
19
|
+
def load_commands():
|
|
20
|
+
"""Load the commands from the commands.json file."""
|
|
21
|
+
commands_path = os.path.join(os.path.dirname(__file__), 'commands.json')
|
|
22
|
+
with open(commands_path, 'r', encoding='utf-8') as f:
|
|
23
|
+
return json.load(f)
|
|
24
|
+
|
|
25
|
+
def create_subparsers(subparsers, commands):
|
|
26
|
+
"""Create subparsers for the commands."""
|
|
27
|
+
for command in commands:
|
|
28
|
+
cmd_parser = subparsers.add_parser(command['command'], help=command['description'])
|
|
29
|
+
for arg in command['args']:
|
|
30
|
+
kwargs = {
|
|
31
|
+
'type': eval(arg['type']),
|
|
32
|
+
'help': arg['help'],
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if 'nargs' in arg:
|
|
36
|
+
kwargs['nargs'] = arg['nargs']
|
|
37
|
+
if 'choices' in arg:
|
|
38
|
+
kwargs['choices'] = arg['choices']
|
|
39
|
+
if 'default' in arg:
|
|
40
|
+
kwargs['default'] = arg['default']
|
|
41
|
+
if arg['type'] == 'bool':
|
|
42
|
+
kwargs['action'] = 'store_true'
|
|
43
|
+
del kwargs['type']
|
|
44
|
+
argname = arg['name']
|
|
45
|
+
if '_' in argname:
|
|
46
|
+
argname2 = argname.replace('_', '-')
|
|
47
|
+
carg = cmd_parser.add_argument(argname, argname2, **kwargs)
|
|
48
|
+
else:
|
|
49
|
+
carg = cmd_parser.add_argument(arg['name'], **kwargs)
|
|
50
|
+
else:
|
|
51
|
+
if '_' in arg['name']:
|
|
52
|
+
argname2 = arg['name'].replace('_', '-')
|
|
53
|
+
carg = cmd_parser.add_argument(arg['name'], argname2, **kwargs)
|
|
54
|
+
else:
|
|
55
|
+
carg = cmd_parser.add_argument(arg['name'], **kwargs)
|
|
56
|
+
carg.required = arg.get('required', True)
|
|
57
|
+
|
|
58
|
+
def dynamic_import(module, func):
|
|
59
|
+
"""Dynamically import a module and function."""
|
|
60
|
+
mod = __import__(module, fromlist=[func])
|
|
61
|
+
return getattr(mod, func)
|
|
62
|
+
|
|
63
|
+
def main():
|
|
64
|
+
"""Main function for the command line utility."""
|
|
65
|
+
commands = load_commands()
|
|
66
|
+
parser = argparse.ArgumentParser(description='Convert a variety of schema formats to Avrotize schema and vice versa.')
|
|
67
|
+
parser.add_argument('--version', action='store_true', help='Print the version of Avrotize.')
|
|
68
|
+
|
|
69
|
+
subparsers = parser.add_subparsers(dest='command')
|
|
70
|
+
create_subparsers(subparsers, commands)
|
|
71
|
+
|
|
72
|
+
args = parser.parse_args()
|
|
73
|
+
|
|
74
|
+
if 'version' in args and args.version:
|
|
75
|
+
print(f'Avrotize {VERSION}')
|
|
76
|
+
return
|
|
77
|
+
|
|
78
|
+
if args.command is None:
|
|
79
|
+
parser.print_help()
|
|
80
|
+
return
|
|
81
|
+
|
|
82
|
+
try:
|
|
83
|
+
command = next((cmd for cmd in commands if cmd['command'] == args.command), None)
|
|
84
|
+
if not command:
|
|
85
|
+
print(f"Error: Command {args.command} not found.")
|
|
86
|
+
exit(1)
|
|
87
|
+
|
|
88
|
+
input_file_path = args.input or getattr(args, 'avsc', None) or getattr(args, 'proto', None) or getattr(args, 'jsons', None) or getattr(args, 'xsd', None) or getattr(args, 'kusto_uri', None) or getattr(args, 'parquet', None) or getattr(args, 'asn', None) or getattr(args, 'kstruct', None)
|
|
89
|
+
temp_input = None
|
|
90
|
+
skip_input_file_handling = command.get('skip_input_file_handling', False)
|
|
91
|
+
if not skip_input_file_handling:
|
|
92
|
+
if input_file_path is None:
|
|
93
|
+
temp_input = tempfile.NamedTemporaryFile(delete=False, mode='w', encoding='utf-8')
|
|
94
|
+
input_file_path = temp_input.name
|
|
95
|
+
# read to EOF
|
|
96
|
+
s = sys.stdin.read()
|
|
97
|
+
while s:
|
|
98
|
+
temp_input.write(s)
|
|
99
|
+
s = sys.stdin.read()
|
|
100
|
+
temp_input.flush()
|
|
101
|
+
temp_input.close()
|
|
102
|
+
|
|
103
|
+
suppress_print = False
|
|
104
|
+
temp_output = None
|
|
105
|
+
output_file_path = ''
|
|
106
|
+
if 'out' in args:
|
|
107
|
+
output_file_path = args.out
|
|
108
|
+
if output_file_path is None:
|
|
109
|
+
suppress_print = True
|
|
110
|
+
temp_output = tempfile.NamedTemporaryFile(delete=False)
|
|
111
|
+
output_file_path = temp_output.name
|
|
112
|
+
|
|
113
|
+
def printmsg(s):
|
|
114
|
+
if not suppress_print:
|
|
115
|
+
print(s)
|
|
116
|
+
|
|
117
|
+
module_name, func_name = command['function']['name'].rsplit('.', 1)
|
|
118
|
+
func = dynamic_import(module_name, func_name)
|
|
119
|
+
func_args = {}
|
|
120
|
+
for arg in command['function']['args']:
|
|
121
|
+
if command['function']['args'][arg] == 'input_file_path':
|
|
122
|
+
func_args[arg] = input_file_path
|
|
123
|
+
elif output_file_path and command['function']['args'][arg] == 'output_file_path':
|
|
124
|
+
func_args[arg] = output_file_path
|
|
125
|
+
else:
|
|
126
|
+
val = command['function']['args'][arg]
|
|
127
|
+
if val.startswith('args.'):
|
|
128
|
+
if hasattr(args, val[5:]):
|
|
129
|
+
func_args[arg] = getattr(args, val[5:])
|
|
130
|
+
else:
|
|
131
|
+
func_args[arg] = val
|
|
132
|
+
if output_file_path:
|
|
133
|
+
printmsg(f'Executing {command["description"]} with input {input_file_path} and output {output_file_path}')
|
|
134
|
+
func(**func_args)
|
|
135
|
+
|
|
136
|
+
if temp_output:
|
|
137
|
+
with open(output_file_path, 'r', encoding='utf-8') as f:
|
|
138
|
+
sys.stdout.write(f.read())
|
|
139
|
+
temp_output.close()
|
|
140
|
+
|
|
141
|
+
except Exception as e:
|
|
142
|
+
print("Error: ", str(e))
|
|
143
|
+
exit(1)
|
|
144
|
+
finally:
|
|
145
|
+
if temp_input:
|
|
146
|
+
try:
|
|
147
|
+
os.remove(temp_input.name)
|
|
148
|
+
except OSError as e:
|
|
149
|
+
print(f"Error: Could not delete temporary input file {temp_input.name}. {e}")
|
|
150
|
+
|
|
151
|
+
if __name__ == "__main__":
|
|
152
|
+
main()
|