structurize 2.16.6__tar.gz → 2.18.0__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.
Files changed (74) hide show
  1. {structurize-2.16.6/structurize.egg-info → structurize-2.18.0}/PKG-INFO +1 -1
  2. {structurize-2.16.6 → structurize-2.18.0}/avrotize/__init__.py +1 -0
  3. {structurize-2.16.6 → structurize-2.18.0}/avrotize/_version.py +3 -3
  4. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotocsharp.py +74 -10
  5. structurize-2.18.0/avrotize/avrotojava.py +2102 -0
  6. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotopython.py +4 -2
  7. {structurize-2.16.6 → structurize-2.18.0}/avrotize/commands.json +671 -53
  8. {structurize-2.16.6 → structurize-2.18.0}/avrotize/common.py +6 -1
  9. {structurize-2.16.6 → structurize-2.18.0}/avrotize/jsonstoavro.py +518 -49
  10. structurize-2.18.0/avrotize/structuretocpp.py +697 -0
  11. structurize-2.18.0/avrotize/structuretocsv.py +365 -0
  12. structurize-2.18.0/avrotize/structuretodatapackage.py +659 -0
  13. structurize-2.18.0/avrotize/structuretodb.py +1125 -0
  14. structurize-2.18.0/avrotize/structuretogo.py +720 -0
  15. structurize-2.18.0/avrotize/structuretographql.py +502 -0
  16. structurize-2.18.0/avrotize/structuretoiceberg.py +355 -0
  17. structurize-2.18.0/avrotize/structuretokusto.py +639 -0
  18. structurize-2.18.0/avrotize/structuretomd.py +322 -0
  19. structurize-2.18.0/avrotize/structuretoproto.py +764 -0
  20. structurize-2.18.0/avrotize/structuretorust.py +714 -0
  21. structurize-2.18.0/avrotize/structuretoxsd.py +679 -0
  22. {structurize-2.16.6 → structurize-2.18.0/structurize.egg-info}/PKG-INFO +1 -1
  23. {structurize-2.16.6 → structurize-2.18.0}/structurize.egg-info/SOURCES.txt +41 -0
  24. structurize-2.16.6/avrotize/avrotojava.py +0 -1023
  25. {structurize-2.16.6 → structurize-2.18.0}/.gitignore +0 -0
  26. {structurize-2.16.6 → structurize-2.18.0}/LICENSE +0 -0
  27. {structurize-2.16.6 → structurize-2.18.0}/MANIFEST.in +0 -0
  28. {structurize-2.16.6 → structurize-2.18.0}/README.md +0 -0
  29. {structurize-2.16.6 → structurize-2.18.0}/avrotize/__main__.py +0 -0
  30. {structurize-2.16.6 → structurize-2.18.0}/avrotize/asn1toavro.py +0 -0
  31. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotize.py +0 -0
  32. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotocpp.py +0 -0
  33. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotocsv.py +0 -0
  34. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotodatapackage.py +0 -0
  35. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotodb.py +0 -0
  36. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotogo.py +0 -0
  37. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotographql.py +0 -0
  38. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotoiceberg.py +0 -0
  39. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotojs.py +0 -0
  40. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotojsons.py +0 -0
  41. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotojstruct.py +0 -0
  42. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotokusto.py +0 -0
  43. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotomd.py +0 -0
  44. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotools.py +0 -0
  45. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotoparquet.py +0 -0
  46. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotoproto.py +0 -0
  47. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotorust.py +0 -0
  48. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotots.py +0 -0
  49. {structurize-2.16.6 → structurize-2.18.0}/avrotize/avrotoxsd.py +0 -0
  50. {structurize-2.16.6 → structurize-2.18.0}/avrotize/constants.py +0 -0
  51. {structurize-2.16.6 → structurize-2.18.0}/avrotize/csvtoavro.py +0 -0
  52. {structurize-2.16.6 → structurize-2.18.0}/avrotize/datapackagetoavro.py +0 -0
  53. {structurize-2.16.6 → structurize-2.18.0}/avrotize/dependency_resolver.py +0 -0
  54. {structurize-2.16.6 → structurize-2.18.0}/avrotize/jsonstostructure.py +0 -0
  55. {structurize-2.16.6 → structurize-2.18.0}/avrotize/jstructtoavro.py +0 -0
  56. {structurize-2.16.6 → structurize-2.18.0}/avrotize/kstructtoavro.py +0 -0
  57. {structurize-2.16.6 → structurize-2.18.0}/avrotize/kustotoavro.py +0 -0
  58. {structurize-2.16.6 → structurize-2.18.0}/avrotize/parquettoavro.py +0 -0
  59. {structurize-2.16.6 → structurize-2.18.0}/avrotize/proto2parser.py +0 -0
  60. {structurize-2.16.6 → structurize-2.18.0}/avrotize/proto3parser.py +0 -0
  61. {structurize-2.16.6 → structurize-2.18.0}/avrotize/prototoavro.py +0 -0
  62. {structurize-2.16.6 → structurize-2.18.0}/avrotize/structuretocsharp.py +0 -0
  63. {structurize-2.16.6 → structurize-2.18.0}/avrotize/structuretojsons.py +0 -0
  64. {structurize-2.16.6 → structurize-2.18.0}/avrotize/structuretopython.py +0 -0
  65. {structurize-2.16.6 → structurize-2.18.0}/avrotize/structuretots.py +0 -0
  66. {structurize-2.16.6 → structurize-2.18.0}/avrotize/xsdtoavro.py +0 -0
  67. {structurize-2.16.6 → structurize-2.18.0}/build.ps1 +0 -0
  68. {structurize-2.16.6 → structurize-2.18.0}/build.sh +0 -0
  69. {structurize-2.16.6 → structurize-2.18.0}/pyproject.toml +0 -0
  70. {structurize-2.16.6 → structurize-2.18.0}/setup.cfg +0 -0
  71. {structurize-2.16.6 → structurize-2.18.0}/structurize.egg-info/dependency_links.txt +0 -0
  72. {structurize-2.16.6 → structurize-2.18.0}/structurize.egg-info/entry_points.txt +0 -0
  73. {structurize-2.16.6 → structurize-2.18.0}/structurize.egg-info/requires.txt +0 -0
  74. {structurize-2.16.6 → structurize-2.18.0}/structurize.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: structurize
3
- Version: 2.16.6
3
+ Version: 2.18.0
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
@@ -48,6 +48,7 @@ _mappings = {
48
48
  "convert_avro_to_javascript": (f"{mod}.avrotojs", "convert_avro_to_javascript"),
49
49
  "convert_avro_schema_to_javascript": (f"{mod}.avrotojs", "convert_avro_schema_to_javascript"),
50
50
  "convert_avro_to_markdown": (f"{mod}.avrotomd", "convert_avro_to_markdown"),
51
+ "convert_structure_to_markdown": (f"{mod}.structuretomd", "convert_structure_to_markdown"),
51
52
  "convert_avro_to_cpp": (f"{mod}.avrotocpp", "convert_avro_to_cpp"),
52
53
  "convert_avro_schema_to_cpp": (f"{mod}.avrotocpp", "convert_avro_schema_to_cpp"),
53
54
  "convert_avro_to_go": (f"{mod}.avrotogo", "convert_avro_to_go"),
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '2.16.6'
32
- __version_tuple__ = version_tuple = (2, 16, 6)
31
+ __version__ = version = '2.18.0'
32
+ __version_tuple__ = version_tuple = (2, 18, 0)
33
33
 
34
- __commit_id__ = commit_id = 'ge83b5f25d'
34
+ __commit_id__ = commit_id = 'gdae473138'
@@ -567,7 +567,7 @@ class AvroToCSharp:
567
567
  class_definition += \
568
568
  f"{INDENT}public sealed class {union_class_name}"
569
569
  if self.system_text_json_annotation:
570
- class_definition += f": System.Text.Json.Serialization.JsonConverter<{union_class_name}>"
570
+ class_definition += f": System.Text.Json.Serialization.JsonConverter<global::{namespace}.{class_name}.{union_class_name}>"
571
571
  class_definition += f"\n{INDENT}{{\n" + \
572
572
  f"{INDENT*2}/// <summary>\n{INDENT*2}/// Default constructor\n{INDENT*2}/// </summary>\n" + \
573
573
  f"{INDENT*2}public {union_class_name}() {{ }}\n"
@@ -602,7 +602,7 @@ class AvroToCSharp:
602
602
  if self.system_text_json_annotation:
603
603
  class_definition += \
604
604
  f"\n{INDENT*2}/// <summary>\n{INDENT*2}/// Reads the JSON representation of the object.\n{INDENT*2}/// </summary>\n" + \
605
- f"{INDENT*2}public override {union_class_name}? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n{INDENT*2}{{\n{INDENT*3}var element = JsonElement.ParseValue(ref reader);\n" + \
605
+ f"{INDENT*2}public override {union_class_name}? Read(ref Utf8JsonReader reader, System.Type typeToConvert, JsonSerializerOptions options)\n{INDENT*2}{{\n{INDENT*3}var element = JsonElement.ParseValue(ref reader);\n" + \
606
606
  class_definition_read + \
607
607
  f"{INDENT*3}throw new NotSupportedException(\"No record type matched the JSON data\");\n{INDENT*2}}}\n" + \
608
608
  f"\n{INDENT*2}/// <summary>\n{INDENT*2}/// Writes the JSON representation of the object.\n{INDENT*2}/// </summary>\n" + \
@@ -612,6 +612,51 @@ class AvroToCSharp:
612
612
  f"\n{INDENT*2}/// <summary>\n{INDENT*2}/// Checks if the JSON element matches the schema\n{INDENT*2}/// </summary>\n" + \
613
613
  f"{INDENT*2}public static bool IsJsonMatch(System.Text.Json.JsonElement element)\n{INDENT*2}{{" + \
614
614
  f"\n{INDENT*3}return "+f"\n{INDENT*3} || ".join(list_is_json_match)+f";\n{INDENT*2}}}\n"
615
+
616
+ # Generate Equals and GetHashCode for the union class
617
+ # Build list of property names for comparison
618
+ union_property_names = []
619
+ for union_type in union_types:
620
+ if union_type.startswith("Dictionary<"):
621
+ match = re.findall(r"Dictionary<(.+)\s*,\s*(.+)>", union_type)
622
+ union_property_names.append("Map" + pascal(match[0][1].rsplit('.', 1)[-1]))
623
+ elif union_type.startswith("List<"):
624
+ match = re.findall(r"List<(.+)>", union_type)
625
+ union_property_names.append("Array" + pascal(match[0].rsplit('.', 1)[-1]))
626
+ elif union_type == "byte[]":
627
+ union_property_names.append("bytes")
628
+ else:
629
+ prop_name = union_type.rsplit('.', 1)[-1]
630
+ if self.is_csharp_reserved_word(prop_name):
631
+ prop_name = f"@{prop_name}"
632
+ union_property_names.append(prop_name)
633
+
634
+ equals_conditions = " && ".join([f"Equals({name}, other.{name})" for name in union_property_names])
635
+
636
+ # HashCode.Combine only accepts up to 8 arguments, so we need to chain calls for larger unions
637
+ def generate_hashcode_expression(props: list) -> str:
638
+ if len(props) <= 8:
639
+ return f"HashCode.Combine({', '.join(props)})"
640
+ else:
641
+ # Chain HashCode.Combine calls: Combine(Combine(first 7...), next 7...)
642
+ first_batch = props[:7]
643
+ remaining = props[7:]
644
+ inner = generate_hashcode_expression(remaining)
645
+ return f"HashCode.Combine({', '.join(first_batch)}, {inner})"
646
+
647
+ hashcode_expression = generate_hashcode_expression(union_property_names)
648
+
649
+ class_definition += \
650
+ f"\n{INDENT*2}/// <summary>\n{INDENT*2}/// Determines whether the specified object is equal to the current object.\n{INDENT*2}/// </summary>\n" + \
651
+ f"{INDENT*2}public override bool Equals(object? obj)\n{INDENT*2}{{\n" + \
652
+ f"{INDENT*3}if (obj is not {union_class_name} other) return false;\n" + \
653
+ f"{INDENT*3}return {equals_conditions};\n" + \
654
+ f"{INDENT*2}}}\n" + \
655
+ f"\n{INDENT*2}/// <summary>\n{INDENT*2}/// Serves as the default hash function.\n{INDENT*2}/// </summary>\n" + \
656
+ f"{INDENT*2}public override int GetHashCode()\n{INDENT*2}{{\n" + \
657
+ f"{INDENT*3}return {hashcode_expression};\n" + \
658
+ f"{INDENT*2}}}\n"
659
+
615
660
  class_definition += f"{INDENT}}}\n}}"
616
661
 
617
662
  if write_file:
@@ -628,26 +673,34 @@ class AvroToCSharp:
628
673
  if found:
629
674
  return found
630
675
  elif isinstance(avro_schema, dict):
631
- if avro_schema['type'] == kind and avro_schema['name'] == type_name and avro_schema.get('namespace', parent_namespace) == type_namespace:
676
+ if avro_schema.get('type') == kind and avro_schema.get('name') == type_name and avro_schema.get('namespace', parent_namespace) == type_namespace:
632
677
  return avro_schema
633
678
  parent_namespace = avro_schema.get('namespace', parent_namespace)
634
679
  if 'fields' in avro_schema and isinstance(avro_schema['fields'], list):
635
680
  for field in avro_schema['fields']:
636
- if isinstance(field,dict) and 'type' in field and isinstance(field['type'], dict):
637
- return self.find_type(kind, field['type'], type_name, type_namespace, parent_namespace)
681
+ if isinstance(field, dict) and 'type' in field:
682
+ # Recursively search within field types (including union arrays)
683
+ found = self.find_type(kind, field['type'], type_name, type_namespace, parent_namespace)
684
+ if found:
685
+ return found
638
686
  return None
639
687
 
640
688
  def is_enum_type(self, avro_type: Union[str, Dict, List]) -> bool:
641
- """ Checks if a type is an enum """
689
+ """ Checks if a type is an enum (including nullable enums) """
642
690
  if isinstance(avro_type, str):
643
691
  schema = self.schema_doc
644
692
  name = avro_type.split('.')[-1]
645
693
  namespace = ".".join(avro_type.split('.')[:-1])
646
694
  return self.find_type('enum', schema, name, namespace) is not None
647
695
  elif isinstance(avro_type, list):
696
+ # Check for nullable enum: ["null", <enum-type>] or [<enum-type>, "null"]
697
+ non_null_types = [t for t in avro_type if t != 'null']
698
+ if len(non_null_types) == 1:
699
+ return self.is_enum_type(non_null_types[0])
648
700
  return False
649
701
  elif isinstance(avro_type, dict):
650
- return avro_type['type'] == 'enum'
702
+ return avro_type.get('type') == 'enum'
703
+ return False
651
704
 
652
705
  def generate_property(self, field: Dict, class_name: str, parent_namespace: str) -> str:
653
706
  """ Generates a property """
@@ -686,7 +739,15 @@ class AvroToCSharp:
686
739
  initialization = ""
687
740
  if field_default is not None:
688
741
  # Has explicit default value
689
- initialization = " = " + (f"\"{field_default}\"" if isinstance(field_default, str) else str(field_default)) + ";"
742
+ if is_enum_type:
743
+ # For enum types, use qualified enum value (e.g., Type.Circle)
744
+ # Get the base enum type name (strip nullable ? suffix if present)
745
+ enum_type = field_type.rstrip('?')
746
+ initialization = f" = {enum_type}.{field_default};"
747
+ elif isinstance(field_default, str):
748
+ initialization = f" = \"{field_default}\";"
749
+ else:
750
+ initialization = f" = {field_default};"
690
751
  elif field_type == "string":
691
752
  # Non-nullable string without default should be initialized to empty string
692
753
  initialization = " = string.Empty;"
@@ -786,12 +847,13 @@ class AvroToCSharp:
786
847
  """ Retrieves fields for a given class name """
787
848
 
788
849
  class Field:
789
- def __init__(self, fn: str, ft:str, tv:Any, ct: bool, pm: bool):
850
+ def __init__(self, fn: str, ft:str, tv:Any, ct: bool, pm: bool, ie: bool):
790
851
  self.field_name = fn
791
852
  self.field_type = ft
792
853
  self.test_value = tv
793
854
  self.is_const = ct
794
855
  self.is_primitive = pm
856
+ self.is_enum = ie
795
857
 
796
858
  fields: List[Field] = []
797
859
  if avro_schema and 'fields' in avro_schema:
@@ -805,11 +867,13 @@ class AvroToCSharp:
805
867
  field_name = f"@{field_name}"
806
868
  field_type = self.convert_avro_type_to_csharp(class_name, field_name, field['type'], str(avro_schema.get('namespace', '')))
807
869
  is_class = field_type in self.generated_types and self.generated_types[field_type] == "class"
870
+ is_enum = self.is_enum_type(field['type'])
808
871
  f = Field(field_name,
809
872
  field_type,
810
873
  (self.get_test_value(field_type) if not "const" in field else '\"'+str(field["const"])+'\"'),
811
874
  "const" in field and field["const"] is not None,
812
- not is_class)
875
+ not is_class,
876
+ is_enum)
813
877
  fields.append(f)
814
878
  return cast(List[Any], fields)
815
879