structurize 3.5.4__tar.gz → 3.5.6__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 (90) hide show
  1. {structurize-3.5.4/structurize.egg-info → structurize-3.5.6}/PKG-INFO +1 -1
  2. {structurize-3.5.4 → structurize-3.5.6}/avrotize/_version.py +3 -3
  3. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretopython.py +116 -6
  4. {structurize-3.5.4 → structurize-3.5.6/structurize.egg-info}/PKG-INFO +1 -1
  5. {structurize-3.5.4 → structurize-3.5.6}/.gitignore +0 -0
  6. {structurize-3.5.4 → structurize-3.5.6}/LICENSE +0 -0
  7. {structurize-3.5.4 → structurize-3.5.6}/MANIFEST.in +0 -0
  8. {structurize-3.5.4 → structurize-3.5.6}/README.md +0 -0
  9. {structurize-3.5.4 → structurize-3.5.6}/avrotize/__init__.py +0 -0
  10. {structurize-3.5.4 → structurize-3.5.6}/avrotize/__main__.py +0 -0
  11. {structurize-3.5.4 → structurize-3.5.6}/avrotize/asn1toavro.py +0 -0
  12. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotize.py +0 -0
  13. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotocpp.py +0 -0
  14. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotocsharp.py +0 -0
  15. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotocsv.py +0 -0
  16. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotodatapackage.py +0 -0
  17. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotodb.py +0 -0
  18. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotogo.py +0 -0
  19. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotographql.py +0 -0
  20. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotoiceberg.py +0 -0
  21. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotojava.py +0 -0
  22. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotojs.py +0 -0
  23. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotojsons.py +0 -0
  24. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotojstruct.py +0 -0
  25. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotokusto.py +0 -0
  26. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotomd.py +0 -0
  27. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotools.py +0 -0
  28. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotoparquet.py +0 -0
  29. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotoproto.py +0 -0
  30. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotopython.py +0 -0
  31. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotorust.py +0 -0
  32. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotots.py +0 -0
  33. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrotoxsd.py +0 -0
  34. {structurize-3.5.4 → structurize-3.5.6}/avrotize/avrovalidator.py +0 -0
  35. {structurize-3.5.4 → structurize-3.5.6}/avrotize/cddltostructure.py +0 -0
  36. {structurize-3.5.4 → structurize-3.5.6}/avrotize/choice_inference.py +0 -0
  37. {structurize-3.5.4 → structurize-3.5.6}/avrotize/commands.json +0 -0
  38. {structurize-3.5.4 → structurize-3.5.6}/avrotize/common.py +0 -0
  39. {structurize-3.5.4 → structurize-3.5.6}/avrotize/constants.py +0 -0
  40. {structurize-3.5.4 → structurize-3.5.6}/avrotize/csvtoavro.py +0 -0
  41. {structurize-3.5.4 → structurize-3.5.6}/avrotize/datapackagetoavro.py +0 -0
  42. {structurize-3.5.4 → structurize-3.5.6}/avrotize/dependencies/cpp/vcpkg/vcpkg.json +0 -0
  43. {structurize-3.5.4 → structurize-3.5.6}/avrotize/dependencies/typescript/node22/package.json +0 -0
  44. {structurize-3.5.4 → structurize-3.5.6}/avrotize/dependency_resolver.py +0 -0
  45. {structurize-3.5.4 → structurize-3.5.6}/avrotize/dependency_version.py +0 -0
  46. {structurize-3.5.4 → structurize-3.5.6}/avrotize/jsonstoavro.py +0 -0
  47. {structurize-3.5.4 → structurize-3.5.6}/avrotize/jsonstostructure.py +0 -0
  48. {structurize-3.5.4 → structurize-3.5.6}/avrotize/jsontoschema.py +0 -0
  49. {structurize-3.5.4 → structurize-3.5.6}/avrotize/jstructtoavro.py +0 -0
  50. {structurize-3.5.4 → structurize-3.5.6}/avrotize/kstructtoavro.py +0 -0
  51. {structurize-3.5.4 → structurize-3.5.6}/avrotize/kustotoavro.py +0 -0
  52. {structurize-3.5.4 → structurize-3.5.6}/avrotize/kustotojstruct.py +0 -0
  53. {structurize-3.5.4 → structurize-3.5.6}/avrotize/mcp_server.py +0 -0
  54. {structurize-3.5.4 → structurize-3.5.6}/avrotize/openapitostructure.py +0 -0
  55. {structurize-3.5.4 → structurize-3.5.6}/avrotize/parquettoavro.py +0 -0
  56. {structurize-3.5.4 → structurize-3.5.6}/avrotize/proto2parser.py +0 -0
  57. {structurize-3.5.4 → structurize-3.5.6}/avrotize/proto3parser.py +0 -0
  58. {structurize-3.5.4 → structurize-3.5.6}/avrotize/prototoavro.py +0 -0
  59. {structurize-3.5.4 → structurize-3.5.6}/avrotize/schema_inference.py +0 -0
  60. {structurize-3.5.4 → structurize-3.5.6}/avrotize/sqltoavro.py +0 -0
  61. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretocddl.py +0 -0
  62. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretocpp.py +0 -0
  63. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretocsharp.py +0 -0
  64. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretocsv.py +0 -0
  65. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretodatapackage.py +0 -0
  66. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretodb.py +0 -0
  67. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretogo.py +0 -0
  68. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretographql.py +0 -0
  69. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretoiceberg.py +0 -0
  70. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretojava.py +0 -0
  71. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretojs.py +0 -0
  72. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretojsons.py +0 -0
  73. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretokusto.py +0 -0
  74. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretomd.py +0 -0
  75. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretoproto.py +0 -0
  76. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretorust.py +0 -0
  77. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretots.py +0 -0
  78. {structurize-3.5.4 → structurize-3.5.6}/avrotize/structuretoxsd.py +0 -0
  79. {structurize-3.5.4 → structurize-3.5.6}/avrotize/validate.py +0 -0
  80. {structurize-3.5.4 → structurize-3.5.6}/avrotize/xmltoschema.py +0 -0
  81. {structurize-3.5.4 → structurize-3.5.6}/avrotize/xsdtoavro.py +0 -0
  82. {structurize-3.5.4 → structurize-3.5.6}/build.ps1 +0 -0
  83. {structurize-3.5.4 → structurize-3.5.6}/build.sh +0 -0
  84. {structurize-3.5.4 → structurize-3.5.6}/pyproject.toml +0 -0
  85. {structurize-3.5.4 → structurize-3.5.6}/setup.cfg +0 -0
  86. {structurize-3.5.4 → structurize-3.5.6}/structurize.egg-info/SOURCES.txt +0 -0
  87. {structurize-3.5.4 → structurize-3.5.6}/structurize.egg-info/dependency_links.txt +0 -0
  88. {structurize-3.5.4 → structurize-3.5.6}/structurize.egg-info/entry_points.txt +0 -0
  89. {structurize-3.5.4 → structurize-3.5.6}/structurize.egg-info/requires.txt +0 -0
  90. {structurize-3.5.4 → structurize-3.5.6}/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.5.4
3
+ Version: 3.5.6
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
@@ -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.5.4'
22
- __version_tuple__ = version_tuple = (3, 5, 4)
21
+ __version__ = version = '3.5.6'
22
+ __version_tuple__ = version_tuple = (3, 5, 6)
23
23
 
24
- __commit_id__ = commit_id = 'g783dbb9df'
24
+ __commit_id__ = commit_id = 'g8153c67a3'
@@ -489,6 +489,36 @@ class StructureToPython:
489
489
  field_docstring = f"{field_name} ({field_type})"
490
490
  return field_docstring
491
491
 
492
+ def _python_enum_member_name(self, value) -> str:
493
+ """Derives a valid Python identifier for an enum member from a JSON
494
+ Structure enum value.
495
+
496
+ Numeric values (including negative integers) are prefixed with
497
+ ``VALUE_`` (with negatives spelled ``VALUE_NEG_n``) so the generated
498
+ class body is valid Python. String values that aren't already valid
499
+ identifiers — e.g. they start with a digit or contain hyphens/spaces —
500
+ are coerced via ``pascal`` and prefixed with ``VALUE_`` if they still
501
+ don't start with a letter or underscore. Reserved words get a
502
+ trailing underscore.
503
+ """
504
+ if isinstance(value, bool):
505
+ return "TRUE_" if value else "FALSE_"
506
+ if isinstance(value, (int, float)):
507
+ if isinstance(value, float):
508
+ token = str(value).replace('.', '_').replace('-', 'NEG_')
509
+ elif value < 0:
510
+ token = f"NEG_{abs(value)}"
511
+ else:
512
+ token = str(value)
513
+ return f"VALUE_{token}"
514
+ text = str(value)
515
+ candidate = re.sub(r'[^0-9A-Za-z_]', '_', text)
516
+ if not candidate or not (candidate[0].isalpha() or candidate[0] == '_'):
517
+ candidate = f"VALUE_{candidate}" if candidate else "VALUE_"
518
+ if is_python_reserved_word(candidate):
519
+ candidate = candidate + "_"
520
+ return candidate
521
+
492
522
  def generate_enum(self, structure_schema: Dict, field_name: str, parent_namespace: str,
493
523
  write_file: bool) -> str:
494
524
  """ Generates a Python enum from JSON Structure enum """
@@ -502,8 +532,24 @@ class StructureToPython:
502
532
  if python_qualified_name in self.generated_types:
503
533
  return python_qualified_name
504
534
 
505
- symbols = [symbol if not is_python_reserved_word(symbol) else symbol + "_"
506
- for symbol in structure_schema.get('enum', [])]
535
+ raw_values = structure_schema.get('enum', [])
536
+ is_numeric = bool(raw_values) and all(
537
+ isinstance(v, (int, float)) and not isinstance(v, bool) for v in raw_values
538
+ )
539
+
540
+ # Build (member_name, repr) pairs. ``repr`` is rendered verbatim into the
541
+ # class body, so for numeric enums we emit the bare numeric literal and
542
+ # for string enums a quoted Python string literal.
543
+ members: List[Tuple[str, str]] = []
544
+ symbols: List[str] = []
545
+ for value in raw_values:
546
+ member_name = self._python_enum_member_name(value)
547
+ if is_numeric:
548
+ value_repr = repr(value)
549
+ else:
550
+ value_repr = repr(str(value))
551
+ members.append((member_name, value_repr))
552
+ symbols.append(member_name)
507
553
 
508
554
  doc = structure_schema.get('description', structure_schema.get('doc', f'A {class_name} enum.'))
509
555
 
@@ -511,12 +557,15 @@ class StructureToPython:
511
557
  "structuretopython/enum_core.jinja",
512
558
  class_name=class_name,
513
559
  docstring=doc,
560
+ members=members,
561
+ is_numeric=is_numeric,
562
+ # ``symbols`` kept for backward compatibility with any external use
514
563
  symbols=symbols,
515
564
  )
516
565
 
517
566
  if write_file:
518
567
  self.write_to_file(package_name, class_name, enum_definition)
519
- self.generate_test_enum(package_name, class_name, symbols)
568
+ self.generate_test_enum(package_name, class_name, members, is_numeric)
520
569
 
521
570
  self.generated_types[python_qualified_name] = 'enum'
522
571
  self.generated_enum_symbols[python_qualified_name] = symbols
@@ -717,7 +766,8 @@ class StructureToPython:
717
766
  with open(test_file_path, 'w', encoding='utf-8') as file:
718
767
  file.write(test_class_definition)
719
768
 
720
- def generate_test_enum(self, package_name: str, class_name: str, symbols: List[str]) -> None:
769
+ def generate_test_enum(self, package_name: str, class_name: str,
770
+ members: List[Tuple[str, str]], is_numeric: bool) -> None:
721
771
  """Generates a unit test class for a Python enum"""
722
772
  test_class_name = f"Test_{class_name}"
723
773
  # Use a simpler file naming scheme based on class name only
@@ -727,7 +777,8 @@ class StructureToPython:
727
777
  package_name=package_name,
728
778
  class_name=class_name,
729
779
  test_class_name=test_class_name,
730
- symbols=symbols
780
+ members=members,
781
+ is_numeric=is_numeric,
731
782
  )
732
783
  base_dir = os.path.join(self.output_dir, "tests")
733
784
  test_file_path = os.path.join(base_dir, f"{test_file_name}.py")
@@ -812,6 +863,32 @@ class StructureToPython:
812
863
  with open(os.path.join(self.output_dir, 'pyproject.toml'), 'w', encoding='utf-8') as file:
813
864
  file.write(pyproject_content)
814
865
 
866
+ def process_definitions(self, definitions: Dict, namespace_path: str) -> None:
867
+ """ Recursively walks the definitions tree and generates a Python type for each leaf.
868
+
869
+ Leaves are sub-schemas that carry an ``enum`` keyword or a ``type`` of
870
+ ``object``/``choice``/``map``. Other dict entries are treated as nested
871
+ namespace segments (matching the path-as-namespace convention used in
872
+ ``$root`` JSON pointers like ``#/definitions/de/wsv/pegelonline/Station``).
873
+ """
874
+ for name, definition in definitions.items():
875
+ if not isinstance(definition, dict):
876
+ continue
877
+ if 'enum' in definition:
878
+ self.generate_enum(definition, name, namespace_path, write_file=True)
879
+ elif definition.get('type') == 'object':
880
+ self.generate_class(definition, namespace_path, write_file=True, explicit_name=name)
881
+ elif definition.get('type') == 'choice':
882
+ self.generate_choice(definition, namespace_path, write_file=True, explicit_name=name)
883
+ elif definition.get('type') == 'map':
884
+ # generate_map_alias doesn't accept explicit_name; stamp the name on a copy.
885
+ map_schema = dict(definition)
886
+ map_schema.setdefault('name', name)
887
+ self.generate_map_alias(map_schema, namespace_path, write_file=True)
888
+ else:
889
+ new_namespace = f"{namespace_path}.{name}" if namespace_path else name
890
+ self.process_definitions(definition, new_namespace)
891
+
815
892
  def convert_schemas(self, structure_schemas: List, output_dir: str):
816
893
  """ Converts JSON Structure schemas to Python dataclasses"""
817
894
  self.output_dir = output_dir
@@ -827,15 +904,48 @@ class StructureToPython:
827
904
  if 'definitions' in structure_schema:
828
905
  self.definitions = structure_schema['definitions']
829
906
 
907
+ handled = False
830
908
  if 'enum' in structure_schema:
831
- self.generate_enum(structure_schema, structure_schema.get('name', 'Enum'),
909
+ self.generate_enum(structure_schema, structure_schema.get('name', 'Enum'),
832
910
  structure_schema.get('namespace', ''), write_file=True)
911
+ handled = True
833
912
  elif structure_schema.get('type') == 'object':
834
913
  self.generate_class(structure_schema, structure_schema.get('namespace', ''), write_file=True)
914
+ handled = True
835
915
  elif structure_schema.get('type') == 'choice':
836
916
  self.generate_choice(structure_schema, structure_schema.get('namespace', ''), write_file=True)
917
+ handled = True
837
918
  elif structure_schema.get('type') == 'map':
838
919
  self.generate_map_alias(structure_schema, structure_schema.get('namespace', ''), write_file=True)
920
+ handled = True
921
+ elif '$root' in structure_schema:
922
+ # $root + definitions wrapper: resolve the pointer, derive the namespace
923
+ # from the pointer path (segments between 'definitions' and the type name),
924
+ # and emit the targeted class explicitly. Sibling types in `definitions`
925
+ # are picked up below by process_definitions.
926
+ root_ref = structure_schema['$root']
927
+ root_schema = self.resolve_ref(root_ref, structure_schema)
928
+ if root_schema:
929
+ ref_path = root_ref.split('/')
930
+ type_name = ref_path[-1]
931
+ ref_namespace = '.'.join(ref_path[2:-1]) if len(ref_path) > 3 else ''
932
+ self.generate_class_or_choice(root_schema, ref_namespace, write_file=True, explicit_name=type_name)
933
+ handled = True
934
+
935
+ # Recursively walk the definitions tree so every named type is emitted,
936
+ # regardless of whether the top-level schema also dispatched something.
937
+ if 'definitions' in structure_schema:
938
+ self.process_definitions(structure_schema['definitions'], '')
939
+ handled = True
940
+
941
+ if not handled:
942
+ schema_id = structure_schema.get('$id', '<no $id>')
943
+ schema_name = structure_schema.get('name', '<no name>')
944
+ print(
945
+ f"Warning: structure schema (id={schema_id}, name={schema_name}) did not "
946
+ "match any recognized top-level shape (enum, type=object/choice/map, "
947
+ "$root, or definitions); no Python output generated for it."
948
+ )
839
949
 
840
950
  self.write_init_files()
841
951
  self.write_pyproject_toml()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: structurize
3
- Version: 3.5.4
3
+ Version: 3.5.6
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes