structurize 2.16.2__py3-none-any.whl → 2.16.6__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.
Files changed (54) hide show
  1. avrotize/__init__.py +63 -63
  2. avrotize/__main__.py +5 -5
  3. avrotize/_version.py +34 -34
  4. avrotize/asn1toavro.py +160 -160
  5. avrotize/avrotize.py +152 -152
  6. avrotize/avrotocpp.py +483 -483
  7. avrotize/avrotocsharp.py +992 -992
  8. avrotize/avrotocsv.py +121 -121
  9. avrotize/avrotodatapackage.py +173 -173
  10. avrotize/avrotodb.py +1383 -1383
  11. avrotize/avrotogo.py +476 -476
  12. avrotize/avrotographql.py +197 -197
  13. avrotize/avrotoiceberg.py +210 -210
  14. avrotize/avrotojava.py +1023 -1023
  15. avrotize/avrotojs.py +250 -250
  16. avrotize/avrotojsons.py +481 -481
  17. avrotize/avrotojstruct.py +345 -345
  18. avrotize/avrotokusto.py +363 -363
  19. avrotize/avrotomd.py +137 -137
  20. avrotize/avrotools.py +168 -168
  21. avrotize/avrotoparquet.py +208 -208
  22. avrotize/avrotoproto.py +358 -358
  23. avrotize/avrotopython.py +622 -622
  24. avrotize/avrotorust.py +435 -435
  25. avrotize/avrotots.py +598 -598
  26. avrotize/avrotoxsd.py +344 -344
  27. avrotize/commands.json +2493 -2433
  28. avrotize/common.py +828 -828
  29. avrotize/constants.py +4 -4
  30. avrotize/csvtoavro.py +131 -131
  31. avrotize/datapackagetoavro.py +76 -76
  32. avrotize/dependency_resolver.py +348 -348
  33. avrotize/jsonstoavro.py +1698 -1698
  34. avrotize/jsonstostructure.py +2642 -2642
  35. avrotize/jstructtoavro.py +878 -878
  36. avrotize/kstructtoavro.py +93 -93
  37. avrotize/kustotoavro.py +455 -455
  38. avrotize/parquettoavro.py +157 -157
  39. avrotize/proto2parser.py +497 -497
  40. avrotize/proto3parser.py +402 -402
  41. avrotize/prototoavro.py +382 -382
  42. avrotize/structuretocsharp.py +2005 -2005
  43. avrotize/structuretojsons.py +498 -498
  44. avrotize/structuretopython.py +772 -772
  45. avrotize/structuretots.py +653 -0
  46. avrotize/xsdtoavro.py +413 -413
  47. structurize-2.16.6.dist-info/METADATA +107 -0
  48. structurize-2.16.6.dist-info/RECORD +52 -0
  49. {structurize-2.16.2.dist-info → structurize-2.16.6.dist-info}/licenses/LICENSE +200 -200
  50. structurize-2.16.2.dist-info/METADATA +0 -805
  51. structurize-2.16.2.dist-info/RECORD +0 -51
  52. {structurize-2.16.2.dist-info → structurize-2.16.6.dist-info}/WHEEL +0 -0
  53. {structurize-2.16.2.dist-info → structurize-2.16.6.dist-info}/entry_points.txt +0 -0
  54. {structurize-2.16.2.dist-info → structurize-2.16.6.dist-info}/top_level.txt +0 -0
avrotize/__init__.py CHANGED
@@ -1,63 +1,63 @@
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_avro_to_cpp": (f"{mod}.avrotocpp", "convert_avro_to_cpp"),
52
- "convert_avro_schema_to_cpp": (f"{mod}.avrotocpp", "convert_avro_schema_to_cpp"),
53
- "convert_avro_to_go": (f"{mod}.avrotogo", "convert_avro_to_go"),
54
- "convert_avro_schema_to_go": (f"{mod}.avrotogo", "convert_avro_schema_to_go"),
55
- "convert_avro_to_rust": (f"{mod}.avrotorust", "convert_avro_to_rust"),
56
- "convert_avro_schema_to_rust": (f"{mod}.avrotorust", "convert_avro_schema_to_rust"),
57
- "convert_avro_to_datapackage": (f"{mod}.avrotodatapackage", "convert_avro_to_datapackage"),
58
- }
59
-
60
- _lazy_loader = LazyLoader(_mappings)
61
-
62
- def __getattr__(name):
63
- return getattr(_lazy_loader, name)
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_avro_to_cpp": (f"{mod}.avrotocpp", "convert_avro_to_cpp"),
52
+ "convert_avro_schema_to_cpp": (f"{mod}.avrotocpp", "convert_avro_schema_to_cpp"),
53
+ "convert_avro_to_go": (f"{mod}.avrotogo", "convert_avro_to_go"),
54
+ "convert_avro_schema_to_go": (f"{mod}.avrotogo", "convert_avro_schema_to_go"),
55
+ "convert_avro_to_rust": (f"{mod}.avrotorust", "convert_avro_to_rust"),
56
+ "convert_avro_schema_to_rust": (f"{mod}.avrotorust", "convert_avro_schema_to_rust"),
57
+ "convert_avro_to_datapackage": (f"{mod}.avrotodatapackage", "convert_avro_to_datapackage"),
58
+ }
59
+
60
+ _lazy_loader = LazyLoader(_mappings)
61
+
62
+ def __getattr__(name):
63
+ return getattr(_lazy_loader, name)
avrotize/__main__.py CHANGED
@@ -1,6 +1,6 @@
1
- # __main__.py
2
-
3
- from . import avrotize
4
-
5
- if __name__ == '__main__':
1
+ # __main__.py
2
+
3
+ from . import avrotize
4
+
5
+ if __name__ == '__main__':
6
6
  avrotize.main()
avrotize/_version.py CHANGED
@@ -1,34 +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.16.2.dev4+g5d7720e36.d20251121'
32
- __version_tuple__ = version_tuple = (2, 16, 2, 'dev4', 'g5d7720e36.d20251121')
33
-
34
- __commit_id__ = commit_id = 'g5d7720e36'
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.16.6'
32
+ __version_tuple__ = version_tuple = (2, 16, 6)
33
+
34
+ __commit_id__ = commit_id = 'ge83b5f25d'
avrotize/asn1toavro.py CHANGED
@@ -1,160 +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)
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)