iodd-parser 0.1.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 (156) hide show
  1. iodd_parser-0.1.0/PKG-INFO +258 -0
  2. iodd_parser-0.1.0/README.md +245 -0
  3. iodd_parser-0.1.0/pyproject.toml +63 -0
  4. iodd_parser-0.1.0/src/iodd_parser/__init__.py +56 -0
  5. iodd_parser-0.1.0/src/iodd_parser/generated/__init__.py +1 -0
  6. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/__init__.py +349 -0
  7. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/abstract_value_t.py +19 -0
  8. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/abstract_variable_t.py +65 -0
  9. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/access_rights_t.py +11 -0
  10. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/array_t.py +36 -0
  11. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/boolean_t.py +21 -0
  12. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/boolean_value_t.py +17 -0
  13. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/button_t.py +34 -0
  14. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/cable_connection_t.py +12 -0
  15. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/character_encoding_t.py +10 -0
  16. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/collection_t.py +10 -0
  17. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/comm_network_profile_t.py +10 -0
  18. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/complex_datatype_t.py +18 -0
  19. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/condition_t.py +30 -0
  20. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/connection_t.py +110 -0
  21. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/data_item_t.py +29 -0
  22. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/datatype_collection_t.py +21 -0
  23. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/datatype_ref_t.py +17 -0
  24. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/datatype_t.py +16 -0
  25. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/device_function_t.py +92 -0
  26. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/device_identity_t.py +123 -0
  27. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/device_variant_collection_t.py +21 -0
  28. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/device_variant_t.py +64 -0
  29. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/document_info_t.py +34 -0
  30. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/error_type128_t.py +18 -0
  31. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/error_type129_t.py +18 -0
  32. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/error_type_collection_t.py +29 -0
  33. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/error_type_t.py +40 -0
  34. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/event_collection_t.py +29 -0
  35. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/event_desc_t.py +41 -0
  36. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/event_desc_t_type.py +11 -0
  37. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/external_text_collection_t.py +29 -0
  38. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/external_text_document.py +20 -0
  39. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/external_text_document_t.py +48 -0
  40. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/features_t.py +45 -0
  41. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/float32_t.py +29 -0
  42. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/float32_value_range_t.py +25 -0
  43. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/float32_value_t.py +17 -0
  44. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/integer_t.py +38 -0
  45. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/integer_value_range_t.py +25 -0
  46. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/integer_value_t.py +17 -0
  47. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/ioddstandard_definitions.py +16 -0
  48. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/ioddstandard_definitions_t.py +96 -0
  49. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/ioddstandard_error_type_collection_t.py +24 -0
  50. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/ioddstandard_event_collection_t.py +24 -0
  51. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/ioddstandard_unit_definitions.py +16 -0
  52. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/ioddstandard_unit_definitions_t.py +58 -0
  53. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/ioddstandard_variable_collection_t.py +26 -0
  54. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/ioddstandard_variable_t.py +20 -0
  55. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iodevice.py +75 -0
  56. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_comm_network_profile_t.py +56 -0
  57. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_comm_network_profile_t_compatible_with.py +9 -0
  58. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_physical_layer_t.py +54 -0
  59. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_physical_layer_t_bitrate.py +11 -0
  60. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_test_config7_t.py +30 -0
  61. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_test_config_t.py +26 -0
  62. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_test_event_t.py +26 -0
  63. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_test_t.py +47 -0
  64. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_transport_layers_t.py +24 -0
  65. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_wireless_comm_network_profile_t.py +44 -0
  66. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_wireless_physical_layer_t.py +70 -0
  67. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_wireless_physical_layer_t_default_slot_type.py +10 -0
  68. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/iolink_wireless_transport_layers_t.py +24 -0
  69. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/lang_value.py +9 -0
  70. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/language_t.py +35 -0
  71. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/m12_4_connection_t.py +104 -0
  72. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/m12_5_connection_t.py +120 -0
  73. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/m5_connection_t.py +101 -0
  74. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/m8_connection_t.py +101 -0
  75. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/menu_collection_t.py +21 -0
  76. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/menu_set_t.py +43 -0
  77. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/menu_t.py +53 -0
  78. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/number_t.py +12 -0
  79. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/object_t.py +16 -0
  80. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/octet_string_t.py +20 -0
  81. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/other_connection_t.py +20 -0
  82. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/primary_language_t.py +12 -0
  83. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_collection_t.py +21 -0
  84. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_in_union_t.py +12 -0
  85. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_info_t.py +37 -0
  86. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_item_t.py +29 -0
  87. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_out_union_t.py +12 -0
  88. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_record_item_info_t.py +18 -0
  89. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_ref_collection_t.py +20 -0
  90. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_ref_t.py +38 -0
  91. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_t.py +37 -0
  92. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/process_data_union_t.py +16 -0
  93. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/product_ref_t.py +16 -0
  94. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/profile_body_t.py +28 -0
  95. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/profile_header_t.py +106 -0
  96. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/profile_header_t_profile_class_id.py +9 -0
  97. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/profile_header_t_profile_identification.py +9 -0
  98. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/profile_header_t_profile_name.py +9 -0
  99. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/profile_header_t_profile_revision.py +9 -0
  100. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/profile_header_t_profile_source.py +9 -0
  101. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/record_item_info_t.py +37 -0
  102. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/record_item_t.py +68 -0
  103. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/record_t.py +30 -0
  104. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/simple_datatype_t.py +12 -0
  105. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/single_value_t.py +12 -0
  106. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/stamp_t.py +39 -0
  107. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/std_data_item_ref_t.py +72 -0
  108. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/std_error_type_ref_t.py +23 -0
  109. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/std_event_ref_t.py +15 -0
  110. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/std_record_item_ref_t.py +18 -0
  111. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/std_single_value_ref_t.py +15 -0
  112. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/std_variable_ref_t.py +42 -0
  113. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/string_t.py +27 -0
  114. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/supported_access_locks_t.py +36 -0
  115. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/text_definition_t.py +22 -0
  116. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/text_ref_t.py +17 -0
  117. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/time_span_t.py +12 -0
  118. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/time_t.py +12 -0
  119. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/uidata_item_ref_t.py +39 -0
  120. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/uimenu_ref_simple_t.py +20 -0
  121. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/uimenu_ref_t.py +23 -0
  122. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/uinteger_t.py +43 -0
  123. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/uinteger_value_range_t.py +28 -0
  124. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/uinteger_value_t.py +20 -0
  125. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/uirecord_item_ref_t.py +21 -0
  126. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/uivariable_ref_t.py +13 -0
  127. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/unit_collection_t.py +43 -0
  128. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/user_interface_t.py +55 -0
  129. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/value_range_t.py +12 -0
  130. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/variable_collection_t.py +49 -0
  131. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/variable_t.py +17 -0
  132. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire1_t.py +35 -0
  133. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire2_function_1.py +10 -0
  134. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire2_function_2.py +11 -0
  135. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire3_t.py +35 -0
  136. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire4_t.py +34 -0
  137. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire5_function.py +10 -0
  138. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire_any_t.py +34 -0
  139. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire_color_t.py +26 -0
  140. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire_function_t.py +15 -0
  141. iodd_parser-0.1.0/src/iodd_parser/generated/v1_1/wire_t.py +33 -0
  142. iodd_parser-0.1.0/src/iodd_parser/parser.py +267 -0
  143. iodd_parser-0.1.0/src/iodd_parser/py.typed +0 -0
  144. iodd_parser-0.1.0/src/iodd_parser/resolvers.py +804 -0
  145. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1-de.xml +230 -0
  146. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1-es.xml +230 -0
  147. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1-fr.xml +230 -0
  148. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1-it.xml +230 -0
  149. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1-ja.xml +230 -0
  150. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1-ko.xml +230 -0
  151. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1-pt.xml +230 -0
  152. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1-ru.xml +230 -0
  153. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1-zh.xml +230 -0
  154. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardDefinitions1.1.xml +866 -0
  155. iodd_parser-0.1.0/src/iodd_parser/standard_definitions/v1_1/IODD-StandardUnitDefinitions1.1.xml +1401 -0
  156. iodd_parser-0.1.0/src/iodd_parser/types.py +831 -0
@@ -0,0 +1,258 @@
1
+ Metadata-Version: 2.3
2
+ Name: iodd-parser
3
+ Version: 0.1.0
4
+ Summary: A simple Python package for parsing IO-Link Device Description (IODD) v1.1 files
5
+ Author: Štěpán Venclík
6
+ Author-email: Štěpán Venclík <stepan.venclik@gmail.com>
7
+ Requires-Dist: xsdata[cli,lxml,soap]>=26.1
8
+ Requires-Python: >=3.13
9
+ Project-URL: Documentation, https://oberth-effect.github.io/iodd-parser/
10
+ Project-URL: Homepage, https://github.com/oberth-effect/iodd-parser
11
+ Project-URL: Issues, https://github.com/oberth-effect/iodd-parser/issues
12
+ Description-Content-Type: text/markdown
13
+
14
+ # IODD Parser
15
+
16
+ A simple Python package for parsing [IO-Link Device Description (IODD)](https://ioddfinder.io-link.com/) v1.1 files.
17
+
18
+ Built on top of [`xsdata`](https://github.com/tefra/xsdata)-generated parsers from the official
19
+ [IO-Link Specification](https://io-link.com/downloads) XSD schema files (snippets schema excluded), this package provides
20
+ a convenient API that resolves references (texts, datatypes, variables, errors, units)
21
+ into unified data structures.
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install iodd-parser
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ### Basic Usage
32
+
33
+ ```python
34
+ from iodd_parser import IODDParser
35
+
36
+ parser = IODDParser()
37
+
38
+ # Parse and resolve in one step
39
+ result = parser.parse_and_resolve("path/to/device-IODD1.1.zip")
40
+
41
+ print(result.device_name)
42
+ print(result.device_manufacturer)
43
+
44
+ # Access resolved variables by ID
45
+ for var_id, var in result.variables.items():
46
+ print(f"{var_id}: {var.name} (index={var.index})")
47
+
48
+ # Access resolved process data
49
+ for pd_id, pd in result.process_data.items():
50
+ if pd.process_data_in:
51
+ print(f"Input: {pd.process_data_in.name} ({pd.process_data_in.bit_length} bits)")
52
+
53
+ # Access resolved errors
54
+ for (code, additional_code), error in result.errors.items():
55
+ print(f"Error {code}/{additional_code}: {error.name}")
56
+
57
+ # Access resolved units
58
+ for unit_code, unit in result.units.items():
59
+ print(f"Unit {unit_code}: {unit.name} ({unit.abbreviation})")
60
+ ```
61
+
62
+ ### Two-Step Parse and Resolve
63
+
64
+ For more control, you can separate the parse and resolve steps:
65
+
66
+ ```python
67
+ from iodd_parser import IODDParser
68
+
69
+ parser = IODDParser()
70
+
71
+ # Step 1: Parse the IODD file (discovers all available languages)
72
+ parsed = parser.parse("path/to/device-IODD1.1.zip")
73
+
74
+ # Check available languages
75
+ print(f"Available languages: {parsed.available_languages}")
76
+
77
+ # Step 2: Resolve with a specific language
78
+ result = parsed.resolve(lang="de")
79
+ ```
80
+
81
+ ### Language Support
82
+
83
+ The parser supports multiple languages for text resolution. Language-specific standard
84
+ definition files are auto-discovered and pre-loaded at parser initialisation, and device-specific
85
+ language files are discovered automatically from the IODD ZIP archive during parsing.
86
+
87
+ ```python
88
+ from iodd_parser import IODDParser
89
+
90
+ parser = IODDParser()
91
+
92
+ # Parse the IODD file (all language files are discovered)
93
+ parsed = parser.parse("path/to/device-IODD1.1.zip")
94
+
95
+ # Check what languages are available
96
+ print(f"Available: {parsed.available_languages}") # e.g., {'de', 'fr', 'es', ...}
97
+
98
+ # Resolve with German texts
99
+ result = parsed.resolve(lang="de")
100
+
101
+ # Variable names are now in German
102
+ print(result.variables["V_VendorName"].name) # "Herstellername"
103
+
104
+ # Or use the convenience method
105
+ result = parser.parse_and_resolve("path/to/device-IODD1.1.zip", lang="de")
106
+ ```
107
+
108
+ ### Custom Standard Definitions Folder
109
+
110
+ You can load standard definitions from a custom folder instead of the bundled files:
111
+
112
+ ```python
113
+ from iodd_parser import IODDParser
114
+
115
+ parser = IODDParser(standard_definitions_folder="/path/to/definitions")
116
+ ```
117
+
118
+ ### Loading Images
119
+
120
+ ```python
121
+ from iodd_parser import IODDParser
122
+
123
+ parser = IODDParser(load_images=True)
124
+ result = parser.parse("path/to/device-IODD1.1.zip")
125
+
126
+ for image in result.images:
127
+ print(f"Image: {image.filename} ({len(image.data)} bytes)")
128
+ ```
129
+
130
+ ## Result Structure
131
+
132
+ ### ParsedIODD
133
+
134
+ The `parse()` method returns a `ParsedIODD` object containing the raw parsed data:
135
+
136
+ ```python
137
+ @dataclass
138
+ class ParsedIODD:
139
+ # Raw parsed objects (as per IODD schema)
140
+ iodd_definitions: IoddstandardDefinitions
141
+ iodd_units: IoddstandardUnitDefinitions
142
+ iodd_device: Iodevice
143
+
144
+ # Language texts from standard definitions and device
145
+ standard_lang_texts: dict[str, dict[str, str]] # lang -> text_id -> text
146
+ device_lang_texts: dict[str, dict[str, str]] # lang -> text_id -> text
147
+
148
+ # Extracted images (if load_images=True)
149
+ images: list[IoddImage]
150
+
151
+ # Properties and methods
152
+ available_languages: set[str] # All discovered language codes
153
+ def resolve(self, lang: str | None = None) -> ResolvedIODD: ...
154
+ ```
155
+
156
+ ### ResolvedIODD
157
+
158
+ The `resolve()` method (or `parse_and_resolve()`) returns a `ResolvedIODD` object:
159
+
160
+ ```python
161
+ @dataclass
162
+ class ResolvedIODD:
163
+ # Raw parsed objects (as per IODD schema)
164
+ iodd_definitions: IoddstandardDefinitions
165
+ iodd_units: IoddstandardUnitDefinitions
166
+ iodd_device: Iodevice
167
+
168
+ # Resolved device information
169
+ device_name: str
170
+ device_manufacturer: str
171
+
172
+ # Resolved collections (with all references resolved)
173
+ variables: dict[str, ResolvedVariable] # Keyed by variable ID
174
+ process_data: dict[str, ResolvedProcessData] # Keyed by process data ID
175
+ texts: dict[str, str] # Keyed by text ID
176
+ datatypes: dict[str, DatatypeT] # Keyed by datatype ID (raw types)
177
+ errors: dict[tuple[int, int], ResolvedError] # Keyed by (code, additional_code)
178
+ units: dict[int, ResolvedUnit] # Keyed by unit code
179
+ user_interface: ResolvedUserInterface # Menus and role assignments
180
+
181
+ # Extracted images (if load_images=True)
182
+ images: list[IoddImage]
183
+ ```
184
+
185
+ ### Resolved Types
186
+
187
+ #### Variables and Data
188
+
189
+ - **`ResolvedVariable`**: Variables from StdVariableRef, DirectParameterOverlay, or vendor-specific Variable elements
190
+ - **`ResolvedError`**: Error types (code=128 for standard, code=129 for vendor-specific)
191
+ - **`ResolvedUnit`**: Unit definitions with code, abbreviation, and name
192
+ - **`ResolvedProcessData`**: Process data configuration with optional condition for switching
193
+ - **`ResolvedProcessDataItem`**: Individual process data input/output description
194
+
195
+ #### Resolved Datatypes
196
+
197
+ Variables and process data items have a `datatype` field containing one of the following resolved types (instead of raw generated types):
198
+
199
+ - **`ResolvedUIntegerT`**: Unsigned integer with `bit_length`, `single_values`, and `value_ranges`
200
+ - **`ResolvedIntegerT`**: Signed integer with `bit_length`, `single_values`, and `value_ranges`
201
+ - **`ResolvedFloat32T`**: 32-bit float with `single_values` and `value_ranges`
202
+ - **`ResolvedBooleanT`**: Boolean with `single_values` (for true/false labels)
203
+ - **`ResolvedStringT`**: String with `fixed_length` and `encoding`
204
+ - **`ResolvedOctetStringT`**: Byte array with `fixed_length`
205
+ - **`ResolvedTimeT`**: Absolute timestamp
206
+ - **`ResolvedTimeSpanT`**: Duration/time span
207
+ - **`ResolvedRecordT`**: Record/struct with `bit_length`, `subindex_access_supported`, and `items`
208
+ - **`ResolvedArrayT`**: Array with `count`, `subindex_access_supported`, and `element_datatype`
209
+
210
+ Single values and value ranges have their text references resolved:
211
+
212
+ ```python
213
+ from iodd_parser import IODDParser
214
+
215
+ parser = IODDParser()
216
+ result = parser.parse("path/to/device-IODD1.1.zip")
217
+
218
+ var = result.variables["V_DeviceStatus"]
219
+ if hasattr(var.datatype, "single_values"):
220
+ for sv in var.datatype.single_values:
221
+ print(f" {sv.value}: {sv.name}")
222
+ # Output:
223
+ # 0: Device is OK
224
+ # 1: Maintenance required
225
+ # 2: Out of specification
226
+ ```
227
+
228
+ #### User Interface
229
+
230
+ The user interface defines how the device is presented in IO-Link Tools:
231
+
232
+ - **`ResolvedUserInterface`**: Contains menus and three role-based menu sets
233
+ - **`ResolvedMenuSet`**: Top-level menu references for a user role (Identification, Parameter, Observation, Diagnosis)
234
+ - **`ResolvedMenu`**: A menu containing variable refs, record item refs, and sub-menu refs
235
+ - **`ResolvedVariableRef`**: Reference to a variable with display options (gradient, offset, unit, format)
236
+ - **`ResolvedRecordItemRef`**: Reference to a record item with subindex
237
+ - **`ResolvedMenuRef`**: Reference to a sub-menu with optional condition
238
+ - **`ResolvedCondition`**: Condition for conditional menu display
239
+
240
+ ```python
241
+ # Access user interface menus
242
+ ui = result.user_interface
243
+
244
+ # Get the specialist role menu set
245
+ specialist = ui.specialist_role_menu_set
246
+ print(f"Identification menu: {specialist.identification_menu_id}")
247
+
248
+ # Access menu details
249
+ menu = ui.menus[specialist.identification_menu_id]
250
+ for var_ref in menu.variable_refs:
251
+ print(f" Variable: {var_ref.variable_id}")
252
+ ```
253
+
254
+ ## Licence
255
+
256
+ Everything except `src/iodd_parser/generated/` and `src/iodd_parser/standard_definitions/` is licensed under the MIT licence.
257
+
258
+ The files in `generated/` and `standard_definitions/` are derived from the IO-Link specification and are subject to the IO-Link Community licensing terms.
@@ -0,0 +1,245 @@
1
+ # IODD Parser
2
+
3
+ A simple Python package for parsing [IO-Link Device Description (IODD)](https://ioddfinder.io-link.com/) v1.1 files.
4
+
5
+ Built on top of [`xsdata`](https://github.com/tefra/xsdata)-generated parsers from the official
6
+ [IO-Link Specification](https://io-link.com/downloads) XSD schema files (snippets schema excluded), this package provides
7
+ a convenient API that resolves references (texts, datatypes, variables, errors, units)
8
+ into unified data structures.
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ pip install iodd-parser
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ### Basic Usage
19
+
20
+ ```python
21
+ from iodd_parser import IODDParser
22
+
23
+ parser = IODDParser()
24
+
25
+ # Parse and resolve in one step
26
+ result = parser.parse_and_resolve("path/to/device-IODD1.1.zip")
27
+
28
+ print(result.device_name)
29
+ print(result.device_manufacturer)
30
+
31
+ # Access resolved variables by ID
32
+ for var_id, var in result.variables.items():
33
+ print(f"{var_id}: {var.name} (index={var.index})")
34
+
35
+ # Access resolved process data
36
+ for pd_id, pd in result.process_data.items():
37
+ if pd.process_data_in:
38
+ print(f"Input: {pd.process_data_in.name} ({pd.process_data_in.bit_length} bits)")
39
+
40
+ # Access resolved errors
41
+ for (code, additional_code), error in result.errors.items():
42
+ print(f"Error {code}/{additional_code}: {error.name}")
43
+
44
+ # Access resolved units
45
+ for unit_code, unit in result.units.items():
46
+ print(f"Unit {unit_code}: {unit.name} ({unit.abbreviation})")
47
+ ```
48
+
49
+ ### Two-Step Parse and Resolve
50
+
51
+ For more control, you can separate the parse and resolve steps:
52
+
53
+ ```python
54
+ from iodd_parser import IODDParser
55
+
56
+ parser = IODDParser()
57
+
58
+ # Step 1: Parse the IODD file (discovers all available languages)
59
+ parsed = parser.parse("path/to/device-IODD1.1.zip")
60
+
61
+ # Check available languages
62
+ print(f"Available languages: {parsed.available_languages}")
63
+
64
+ # Step 2: Resolve with a specific language
65
+ result = parsed.resolve(lang="de")
66
+ ```
67
+
68
+ ### Language Support
69
+
70
+ The parser supports multiple languages for text resolution. Language-specific standard
71
+ definition files are auto-discovered and pre-loaded at parser initialisation, and device-specific
72
+ language files are discovered automatically from the IODD ZIP archive during parsing.
73
+
74
+ ```python
75
+ from iodd_parser import IODDParser
76
+
77
+ parser = IODDParser()
78
+
79
+ # Parse the IODD file (all language files are discovered)
80
+ parsed = parser.parse("path/to/device-IODD1.1.zip")
81
+
82
+ # Check what languages are available
83
+ print(f"Available: {parsed.available_languages}") # e.g., {'de', 'fr', 'es', ...}
84
+
85
+ # Resolve with German texts
86
+ result = parsed.resolve(lang="de")
87
+
88
+ # Variable names are now in German
89
+ print(result.variables["V_VendorName"].name) # "Herstellername"
90
+
91
+ # Or use the convenience method
92
+ result = parser.parse_and_resolve("path/to/device-IODD1.1.zip", lang="de")
93
+ ```
94
+
95
+ ### Custom Standard Definitions Folder
96
+
97
+ You can load standard definitions from a custom folder instead of the bundled files:
98
+
99
+ ```python
100
+ from iodd_parser import IODDParser
101
+
102
+ parser = IODDParser(standard_definitions_folder="/path/to/definitions")
103
+ ```
104
+
105
+ ### Loading Images
106
+
107
+ ```python
108
+ from iodd_parser import IODDParser
109
+
110
+ parser = IODDParser(load_images=True)
111
+ result = parser.parse("path/to/device-IODD1.1.zip")
112
+
113
+ for image in result.images:
114
+ print(f"Image: {image.filename} ({len(image.data)} bytes)")
115
+ ```
116
+
117
+ ## Result Structure
118
+
119
+ ### ParsedIODD
120
+
121
+ The `parse()` method returns a `ParsedIODD` object containing the raw parsed data:
122
+
123
+ ```python
124
+ @dataclass
125
+ class ParsedIODD:
126
+ # Raw parsed objects (as per IODD schema)
127
+ iodd_definitions: IoddstandardDefinitions
128
+ iodd_units: IoddstandardUnitDefinitions
129
+ iodd_device: Iodevice
130
+
131
+ # Language texts from standard definitions and device
132
+ standard_lang_texts: dict[str, dict[str, str]] # lang -> text_id -> text
133
+ device_lang_texts: dict[str, dict[str, str]] # lang -> text_id -> text
134
+
135
+ # Extracted images (if load_images=True)
136
+ images: list[IoddImage]
137
+
138
+ # Properties and methods
139
+ available_languages: set[str] # All discovered language codes
140
+ def resolve(self, lang: str | None = None) -> ResolvedIODD: ...
141
+ ```
142
+
143
+ ### ResolvedIODD
144
+
145
+ The `resolve()` method (or `parse_and_resolve()`) returns a `ResolvedIODD` object:
146
+
147
+ ```python
148
+ @dataclass
149
+ class ResolvedIODD:
150
+ # Raw parsed objects (as per IODD schema)
151
+ iodd_definitions: IoddstandardDefinitions
152
+ iodd_units: IoddstandardUnitDefinitions
153
+ iodd_device: Iodevice
154
+
155
+ # Resolved device information
156
+ device_name: str
157
+ device_manufacturer: str
158
+
159
+ # Resolved collections (with all references resolved)
160
+ variables: dict[str, ResolvedVariable] # Keyed by variable ID
161
+ process_data: dict[str, ResolvedProcessData] # Keyed by process data ID
162
+ texts: dict[str, str] # Keyed by text ID
163
+ datatypes: dict[str, DatatypeT] # Keyed by datatype ID (raw types)
164
+ errors: dict[tuple[int, int], ResolvedError] # Keyed by (code, additional_code)
165
+ units: dict[int, ResolvedUnit] # Keyed by unit code
166
+ user_interface: ResolvedUserInterface # Menus and role assignments
167
+
168
+ # Extracted images (if load_images=True)
169
+ images: list[IoddImage]
170
+ ```
171
+
172
+ ### Resolved Types
173
+
174
+ #### Variables and Data
175
+
176
+ - **`ResolvedVariable`**: Variables from StdVariableRef, DirectParameterOverlay, or vendor-specific Variable elements
177
+ - **`ResolvedError`**: Error types (code=128 for standard, code=129 for vendor-specific)
178
+ - **`ResolvedUnit`**: Unit definitions with code, abbreviation, and name
179
+ - **`ResolvedProcessData`**: Process data configuration with optional condition for switching
180
+ - **`ResolvedProcessDataItem`**: Individual process data input/output description
181
+
182
+ #### Resolved Datatypes
183
+
184
+ Variables and process data items have a `datatype` field containing one of the following resolved types (instead of raw generated types):
185
+
186
+ - **`ResolvedUIntegerT`**: Unsigned integer with `bit_length`, `single_values`, and `value_ranges`
187
+ - **`ResolvedIntegerT`**: Signed integer with `bit_length`, `single_values`, and `value_ranges`
188
+ - **`ResolvedFloat32T`**: 32-bit float with `single_values` and `value_ranges`
189
+ - **`ResolvedBooleanT`**: Boolean with `single_values` (for true/false labels)
190
+ - **`ResolvedStringT`**: String with `fixed_length` and `encoding`
191
+ - **`ResolvedOctetStringT`**: Byte array with `fixed_length`
192
+ - **`ResolvedTimeT`**: Absolute timestamp
193
+ - **`ResolvedTimeSpanT`**: Duration/time span
194
+ - **`ResolvedRecordT`**: Record/struct with `bit_length`, `subindex_access_supported`, and `items`
195
+ - **`ResolvedArrayT`**: Array with `count`, `subindex_access_supported`, and `element_datatype`
196
+
197
+ Single values and value ranges have their text references resolved:
198
+
199
+ ```python
200
+ from iodd_parser import IODDParser
201
+
202
+ parser = IODDParser()
203
+ result = parser.parse("path/to/device-IODD1.1.zip")
204
+
205
+ var = result.variables["V_DeviceStatus"]
206
+ if hasattr(var.datatype, "single_values"):
207
+ for sv in var.datatype.single_values:
208
+ print(f" {sv.value}: {sv.name}")
209
+ # Output:
210
+ # 0: Device is OK
211
+ # 1: Maintenance required
212
+ # 2: Out of specification
213
+ ```
214
+
215
+ #### User Interface
216
+
217
+ The user interface defines how the device is presented in IO-Link Tools:
218
+
219
+ - **`ResolvedUserInterface`**: Contains menus and three role-based menu sets
220
+ - **`ResolvedMenuSet`**: Top-level menu references for a user role (Identification, Parameter, Observation, Diagnosis)
221
+ - **`ResolvedMenu`**: A menu containing variable refs, record item refs, and sub-menu refs
222
+ - **`ResolvedVariableRef`**: Reference to a variable with display options (gradient, offset, unit, format)
223
+ - **`ResolvedRecordItemRef`**: Reference to a record item with subindex
224
+ - **`ResolvedMenuRef`**: Reference to a sub-menu with optional condition
225
+ - **`ResolvedCondition`**: Condition for conditional menu display
226
+
227
+ ```python
228
+ # Access user interface menus
229
+ ui = result.user_interface
230
+
231
+ # Get the specialist role menu set
232
+ specialist = ui.specialist_role_menu_set
233
+ print(f"Identification menu: {specialist.identification_menu_id}")
234
+
235
+ # Access menu details
236
+ menu = ui.menus[specialist.identification_menu_id]
237
+ for var_ref in menu.variable_refs:
238
+ print(f" Variable: {var_ref.variable_id}")
239
+ ```
240
+
241
+ ## Licence
242
+
243
+ Everything except `src/iodd_parser/generated/` and `src/iodd_parser/standard_definitions/` is licensed under the MIT licence.
244
+
245
+ The files in `generated/` and `standard_definitions/` are derived from the IO-Link specification and are subject to the IO-Link Community licensing terms.
@@ -0,0 +1,63 @@
1
+ [project]
2
+ name = "iodd-parser"
3
+ version = "0.1.0"
4
+ description = "A simple Python package for parsing IO-Link Device Description (IODD) v1.1 files"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Štěpán Venclík", email = "stepan.venclik@gmail.com" }
8
+ ]
9
+ requires-python = ">=3.13"
10
+ dependencies = [
11
+ "xsdata[cli,lxml,soap]>=26.1",
12
+ ]
13
+
14
+ [build-system]
15
+ requires = ["uv_build>=0.8.3,<0.9.0"]
16
+ build-backend = "uv_build"
17
+
18
+ [tool.ruff]
19
+ line-length = 120
20
+ exclude = ["src/iodd_parser/generated"]
21
+
22
+ [tool.ruff.lint]
23
+ select = [
24
+ # pycodestyle
25
+ "E",
26
+ # Pyflakes
27
+ "F",
28
+ # pyupgrade
29
+ "UP",
30
+ # flake8-bugbear
31
+ "B",
32
+ # flake8-simplify
33
+ "SIM",
34
+ # flake8-comperhensions
35
+ "C4",
36
+ # flake8-builitins
37
+ "A",
38
+ # isort
39
+ "I",
40
+ # flake8-fixme
41
+ "FIX",
42
+ # flake8-return
43
+ "RET",
44
+ # ruff specific rules
45
+ "RUF"
46
+ ]
47
+
48
+ [dependency-groups]
49
+ dev = [
50
+ "ruff>=0.14.14",
51
+ "ty>=0.0.14",
52
+ ]
53
+ docs = [
54
+ "mkdocs>=1.6.1",
55
+ "mkdocs-include-markdown-plugin>=7.2.1",
56
+ "mkdocs-material>=9.7.1",
57
+ "mkdocstrings[python]>=1.0.2",
58
+ ]
59
+
60
+ [project.urls]
61
+ Homepage = "https://github.com/oberth-effect/iodd-parser"
62
+ Issues = "https://github.com/oberth-effect/iodd-parser/issues"
63
+ Documentation = "https://oberth-effect.github.io/iodd-parser/"
@@ -0,0 +1,56 @@
1
+ """
2
+ IODD Parser package.
3
+
4
+ This package provides tools for parsing IO-Link Device Description (IODD)
5
+ files and resolving all references to produce unified data structures.
6
+ """
7
+
8
+ from iodd_parser.parser import IODDParser
9
+ from iodd_parser.types import (
10
+ IoddImage,
11
+ ParsedIODD,
12
+ ResolvedButton,
13
+ ResolvedCondition,
14
+ ResolvedError,
15
+ ResolvedIODD,
16
+ ResolvedMenu,
17
+ ResolvedMenuRef,
18
+ ResolvedMenuSet,
19
+ ResolvedProcessData,
20
+ ResolvedProcessDataInfo,
21
+ ResolvedProcessDataItem,
22
+ ResolvedProcessDataRecordItemInfo,
23
+ ResolvedProcessDataRef,
24
+ ResolvedRecordItemRef,
25
+ ResolvedUnit,
26
+ ResolvedUserInterface,
27
+ ResolvedVariable,
28
+ ResolvedVariableRef,
29
+ TopLevelMenuType,
30
+ UserRole,
31
+ )
32
+
33
+ __all__ = [
34
+ "IODDParser",
35
+ "IoddImage",
36
+ "ParsedIODD",
37
+ "ResolvedButton",
38
+ "ResolvedCondition",
39
+ "ResolvedError",
40
+ "ResolvedIODD",
41
+ "ResolvedMenu",
42
+ "ResolvedMenuRef",
43
+ "ResolvedMenuSet",
44
+ "ResolvedProcessData",
45
+ "ResolvedProcessDataInfo",
46
+ "ResolvedProcessDataItem",
47
+ "ResolvedProcessDataRecordItemInfo",
48
+ "ResolvedProcessDataRef",
49
+ "ResolvedRecordItemRef",
50
+ "ResolvedUnit",
51
+ "ResolvedUserInterface",
52
+ "ResolvedVariable",
53
+ "ResolvedVariableRef",
54
+ "TopLevelMenuType",
55
+ "UserRole",
56
+ ]
@@ -0,0 +1 @@
1
+ # nothing here