valuesets 0.3.1__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.

Potentially problematic release.


This version of valuesets might be problematic. Click here for more details.

Files changed (248) hide show
  1. valuesets/__init__.py +7 -0
  2. valuesets/_version.py +8 -0
  3. valuesets/datamodel/valuesets.py +13796 -0
  4. valuesets/datamodel/valuesets_dataclass.py +24503 -0
  5. valuesets/datamodel/valuesets_pydantic.py +13796 -0
  6. valuesets/enums/__init__.py +590 -0
  7. valuesets/enums/academic/__init__.py +1 -0
  8. valuesets/enums/academic/research.py +559 -0
  9. valuesets/enums/analytical_chemistry/__init__.py +1 -0
  10. valuesets/enums/analytical_chemistry/mass_spectrometry.py +198 -0
  11. valuesets/enums/bio/__init__.py +1 -0
  12. valuesets/enums/bio/biological_colors.py +238 -0
  13. valuesets/enums/bio/cell_cycle.py +180 -0
  14. valuesets/enums/bio/currency_chemicals.py +52 -0
  15. valuesets/enums/bio/developmental_stages.py +103 -0
  16. valuesets/enums/bio/genome_features.py +182 -0
  17. valuesets/enums/bio/genomics.py +91 -0
  18. valuesets/enums/bio/go_aspect.py +32 -0
  19. valuesets/enums/bio/go_causality.py +58 -0
  20. valuesets/enums/bio/go_evidence.py +129 -0
  21. valuesets/enums/bio/human_developmental_stages.py +62 -0
  22. valuesets/enums/bio/insdc_geographic_locations.py +591 -0
  23. valuesets/enums/bio/insdc_missing_values.py +49 -0
  24. valuesets/enums/bio/lipid_categories.py +67 -0
  25. valuesets/enums/bio/mouse_developmental_stages.py +62 -0
  26. valuesets/enums/bio/plant_biology.py +86 -0
  27. valuesets/enums/bio/plant_developmental_stages.py +54 -0
  28. valuesets/enums/bio/plant_sex.py +81 -0
  29. valuesets/enums/bio/protein_evidence.py +61 -0
  30. valuesets/enums/bio/proteomics_standards.py +123 -0
  31. valuesets/enums/bio/psi_mi.py +306 -0
  32. valuesets/enums/bio/relationship_to_oxygen.py +37 -0
  33. valuesets/enums/bio/sequence_alphabets.py +449 -0
  34. valuesets/enums/bio/sequence_chemistry.py +357 -0
  35. valuesets/enums/bio/sequencing_platforms.py +302 -0
  36. valuesets/enums/bio/structural_biology.py +320 -0
  37. valuesets/enums/bio/taxonomy.py +238 -0
  38. valuesets/enums/bio/trophic_levels.py +85 -0
  39. valuesets/enums/bio/uniprot_species.py +344 -0
  40. valuesets/enums/bio/viral_genome_types.py +47 -0
  41. valuesets/enums/bioprocessing/__init__.py +1 -0
  42. valuesets/enums/bioprocessing/scale_up.py +249 -0
  43. valuesets/enums/business/__init__.py +1 -0
  44. valuesets/enums/business/human_resources.py +275 -0
  45. valuesets/enums/business/industry_classifications.py +181 -0
  46. valuesets/enums/business/management_operations.py +228 -0
  47. valuesets/enums/business/organizational_structures.py +236 -0
  48. valuesets/enums/business/quality_management.py +181 -0
  49. valuesets/enums/business/supply_chain.py +232 -0
  50. valuesets/enums/chemistry/__init__.py +1 -0
  51. valuesets/enums/chemistry/chemical_entities.py +315 -0
  52. valuesets/enums/chemistry/reaction_directionality.py +65 -0
  53. valuesets/enums/chemistry/reactions.py +256 -0
  54. valuesets/enums/clinical/__init__.py +1 -0
  55. valuesets/enums/clinical/nih_demographics.py +177 -0
  56. valuesets/enums/clinical/phenopackets.py +254 -0
  57. valuesets/enums/common_value_sets.py +8791 -0
  58. valuesets/enums/computing/__init__.py +1 -0
  59. valuesets/enums/computing/file_formats.py +294 -0
  60. valuesets/enums/computing/maturity_levels.py +196 -0
  61. valuesets/enums/computing/mime_types.py +227 -0
  62. valuesets/enums/confidence_levels.py +168 -0
  63. valuesets/enums/contributor.py +30 -0
  64. valuesets/enums/core.py +42 -0
  65. valuesets/enums/data/__init__.py +1 -0
  66. valuesets/enums/data/data_absent_reason.py +53 -0
  67. valuesets/enums/data_science/__init__.py +1 -0
  68. valuesets/enums/data_science/binary_classification.py +87 -0
  69. valuesets/enums/data_science/emotion_classification.py +66 -0
  70. valuesets/enums/data_science/priority_severity.py +73 -0
  71. valuesets/enums/data_science/quality_control.py +46 -0
  72. valuesets/enums/data_science/sentiment_analysis.py +50 -0
  73. valuesets/enums/data_science/text_classification.py +97 -0
  74. valuesets/enums/demographics.py +206 -0
  75. valuesets/enums/ecological_interactions.py +151 -0
  76. valuesets/enums/energy/__init__.py +1 -0
  77. valuesets/enums/energy/energy.py +343 -0
  78. valuesets/enums/energy/fossil_fuels.py +29 -0
  79. valuesets/enums/energy/nuclear/__init__.py +1 -0
  80. valuesets/enums/energy/nuclear/nuclear_facilities.py +195 -0
  81. valuesets/enums/energy/nuclear/nuclear_fuel_cycle.py +96 -0
  82. valuesets/enums/energy/nuclear/nuclear_fuels.py +175 -0
  83. valuesets/enums/energy/nuclear/nuclear_operations.py +191 -0
  84. valuesets/enums/energy/nuclear/nuclear_regulatory.py +188 -0
  85. valuesets/enums/energy/nuclear/nuclear_safety.py +164 -0
  86. valuesets/enums/energy/nuclear/nuclear_waste.py +158 -0
  87. valuesets/enums/energy/nuclear/reactor_types.py +163 -0
  88. valuesets/enums/environmental_health/__init__.py +1 -0
  89. valuesets/enums/environmental_health/exposures.py +265 -0
  90. valuesets/enums/geography/__init__.py +1 -0
  91. valuesets/enums/geography/geographic_codes.py +741 -0
  92. valuesets/enums/health/__init__.py +12 -0
  93. valuesets/enums/health/vaccination.py +98 -0
  94. valuesets/enums/health.py +36 -0
  95. valuesets/enums/health_base.py +36 -0
  96. valuesets/enums/healthcare.py +45 -0
  97. valuesets/enums/industry/__init__.py +1 -0
  98. valuesets/enums/industry/extractive_industry.py +94 -0
  99. valuesets/enums/industry/mining.py +388 -0
  100. valuesets/enums/industry/safety_colors.py +201 -0
  101. valuesets/enums/investigation.py +27 -0
  102. valuesets/enums/materials_science/__init__.py +1 -0
  103. valuesets/enums/materials_science/characterization_methods.py +112 -0
  104. valuesets/enums/materials_science/crystal_structures.py +76 -0
  105. valuesets/enums/materials_science/material_properties.py +119 -0
  106. valuesets/enums/materials_science/material_types.py +104 -0
  107. valuesets/enums/materials_science/pigments_dyes.py +198 -0
  108. valuesets/enums/materials_science/synthesis_methods.py +109 -0
  109. valuesets/enums/medical/__init__.py +1 -0
  110. valuesets/enums/medical/clinical.py +277 -0
  111. valuesets/enums/medical/neuroimaging.py +119 -0
  112. valuesets/enums/mining_processing.py +302 -0
  113. valuesets/enums/physics/__init__.py +1 -0
  114. valuesets/enums/physics/states_of_matter.py +46 -0
  115. valuesets/enums/social/__init__.py +1 -0
  116. valuesets/enums/social/person_status.py +29 -0
  117. valuesets/enums/spatial/__init__.py +1 -0
  118. valuesets/enums/spatial/spatial_qualifiers.py +246 -0
  119. valuesets/enums/statistics/__init__.py +5 -0
  120. valuesets/enums/statistics/prediction_outcomes.py +31 -0
  121. valuesets/enums/statistics.py +31 -0
  122. valuesets/enums/time/__init__.py +1 -0
  123. valuesets/enums/time/temporal.py +254 -0
  124. valuesets/enums/units/__init__.py +1 -0
  125. valuesets/enums/units/measurements.py +310 -0
  126. valuesets/enums/visual/__init__.py +1 -0
  127. valuesets/enums/visual/colors.py +376 -0
  128. valuesets/generators/__init__.py +19 -0
  129. valuesets/generators/auto_slot_injector.py +280 -0
  130. valuesets/generators/enhanced_pydantic_generator.py +100 -0
  131. valuesets/generators/enum_slot_generator.py +201 -0
  132. valuesets/generators/modular_rich_generator.py +353 -0
  133. valuesets/generators/prefix_standardizer.py +198 -0
  134. valuesets/generators/rich_enum.py +127 -0
  135. valuesets/generators/rich_pydantic_generator.py +310 -0
  136. valuesets/generators/smart_slot_syncer.py +428 -0
  137. valuesets/generators/sssom_generator.py +394 -0
  138. valuesets/merged/merged_hierarchy.yaml +21649 -0
  139. valuesets/schema/README.md +3 -0
  140. valuesets/schema/academic/research.yaml +911 -0
  141. valuesets/schema/analytical_chemistry/mass_spectrometry.yaml +206 -0
  142. valuesets/schema/bio/bio_entities.yaml +364 -0
  143. valuesets/schema/bio/biological_colors.yaml +434 -0
  144. valuesets/schema/bio/cell_cycle.yaml +309 -0
  145. valuesets/schema/bio/currency_chemicals.yaml +70 -0
  146. valuesets/schema/bio/developmental_stages.yaml +226 -0
  147. valuesets/schema/bio/genome_features.yaml +342 -0
  148. valuesets/schema/bio/genomics.yaml +101 -0
  149. valuesets/schema/bio/go_aspect.yaml +39 -0
  150. valuesets/schema/bio/go_causality.yaml +119 -0
  151. valuesets/schema/bio/go_evidence.yaml +215 -0
  152. valuesets/schema/bio/insdc_geographic_locations.yaml +911 -0
  153. valuesets/schema/bio/insdc_missing_values.yaml +85 -0
  154. valuesets/schema/bio/lipid_categories.yaml +72 -0
  155. valuesets/schema/bio/plant_biology.yaml +125 -0
  156. valuesets/schema/bio/plant_developmental_stages.yaml +77 -0
  157. valuesets/schema/bio/plant_sex.yaml +108 -0
  158. valuesets/schema/bio/protein_evidence.yaml +63 -0
  159. valuesets/schema/bio/proteomics_standards.yaml +116 -0
  160. valuesets/schema/bio/psi_mi.yaml +400 -0
  161. valuesets/schema/bio/relationship_to_oxygen.yaml +46 -0
  162. valuesets/schema/bio/sequence_alphabets.yaml +1168 -0
  163. valuesets/schema/bio/sequence_chemistry.yaml +477 -0
  164. valuesets/schema/bio/sequencing_platforms.yaml +515 -0
  165. valuesets/schema/bio/structural_biology.yaml +428 -0
  166. valuesets/schema/bio/taxonomy.yaml +453 -0
  167. valuesets/schema/bio/trophic_levels.yaml +118 -0
  168. valuesets/schema/bio/uniprot_species.yaml +1209 -0
  169. valuesets/schema/bio/viral_genome_types.yaml +99 -0
  170. valuesets/schema/bioprocessing/scale_up.yaml +458 -0
  171. valuesets/schema/business/human_resources.yaml +752 -0
  172. valuesets/schema/business/industry_classifications.yaml +448 -0
  173. valuesets/schema/business/management_operations.yaml +602 -0
  174. valuesets/schema/business/organizational_structures.yaml +645 -0
  175. valuesets/schema/business/quality_management.yaml +502 -0
  176. valuesets/schema/business/supply_chain.yaml +688 -0
  177. valuesets/schema/chemistry/chemical_entities.yaml +639 -0
  178. valuesets/schema/chemistry/reaction_directionality.yaml +60 -0
  179. valuesets/schema/chemistry/reactions.yaml +442 -0
  180. valuesets/schema/clinical/nih_demographics.yaml +285 -0
  181. valuesets/schema/clinical/phenopackets.yaml +429 -0
  182. valuesets/schema/computing/file_formats.yaml +631 -0
  183. valuesets/schema/computing/maturity_levels.yaml +229 -0
  184. valuesets/schema/computing/mime_types.yaml +266 -0
  185. valuesets/schema/confidence_levels.yaml +206 -0
  186. valuesets/schema/contributor.yaml +30 -0
  187. valuesets/schema/core.yaml +55 -0
  188. valuesets/schema/data/data_absent_reason.yaml +82 -0
  189. valuesets/schema/data_science/binary_classification.yaml +125 -0
  190. valuesets/schema/data_science/emotion_classification.yaml +109 -0
  191. valuesets/schema/data_science/priority_severity.yaml +122 -0
  192. valuesets/schema/data_science/quality_control.yaml +68 -0
  193. valuesets/schema/data_science/sentiment_analysis.yaml +81 -0
  194. valuesets/schema/data_science/text_classification.yaml +135 -0
  195. valuesets/schema/demographics.yaml +238 -0
  196. valuesets/schema/ecological_interactions.yaml +298 -0
  197. valuesets/schema/energy/energy.yaml +595 -0
  198. valuesets/schema/energy/fossil_fuels.yaml +28 -0
  199. valuesets/schema/energy/nuclear/nuclear_facilities.yaml +463 -0
  200. valuesets/schema/energy/nuclear/nuclear_fuel_cycle.yaml +82 -0
  201. valuesets/schema/energy/nuclear/nuclear_fuels.yaml +421 -0
  202. valuesets/schema/energy/nuclear/nuclear_operations.yaml +480 -0
  203. valuesets/schema/energy/nuclear/nuclear_regulatory.yaml +200 -0
  204. valuesets/schema/energy/nuclear/nuclear_safety.yaml +352 -0
  205. valuesets/schema/energy/nuclear/nuclear_waste.yaml +332 -0
  206. valuesets/schema/energy/nuclear/reactor_types.yaml +394 -0
  207. valuesets/schema/environmental_health/exposures.yaml +355 -0
  208. valuesets/schema/generated_slots.yaml +1828 -0
  209. valuesets/schema/geography/geographic_codes.yaml +1018 -0
  210. valuesets/schema/health/vaccination.yaml +102 -0
  211. valuesets/schema/health.yaml +38 -0
  212. valuesets/schema/healthcare.yaml +53 -0
  213. valuesets/schema/industry/extractive_industry.yaml +89 -0
  214. valuesets/schema/industry/mining.yaml +888 -0
  215. valuesets/schema/industry/safety_colors.yaml +375 -0
  216. valuesets/schema/investigation.yaml +64 -0
  217. valuesets/schema/materials_science/characterization_methods.yaml +193 -0
  218. valuesets/schema/materials_science/crystal_structures.yaml +138 -0
  219. valuesets/schema/materials_science/material_properties.yaml +135 -0
  220. valuesets/schema/materials_science/material_types.yaml +151 -0
  221. valuesets/schema/materials_science/pigments_dyes.yaml +465 -0
  222. valuesets/schema/materials_science/synthesis_methods.yaml +186 -0
  223. valuesets/schema/medical/clinical.yaml +610 -0
  224. valuesets/schema/medical/neuroimaging.yaml +325 -0
  225. valuesets/schema/mining_processing.yaml +295 -0
  226. valuesets/schema/physics/states_of_matter.yaml +46 -0
  227. valuesets/schema/slot_mixins.yaml +143 -0
  228. valuesets/schema/social/person_status.yaml +28 -0
  229. valuesets/schema/spatial/spatial_qualifiers.yaml +466 -0
  230. valuesets/schema/statistics/prediction_outcomes.yaml +26 -0
  231. valuesets/schema/statistics.yaml +34 -0
  232. valuesets/schema/time/temporal.yaml +435 -0
  233. valuesets/schema/types.yaml +15 -0
  234. valuesets/schema/units/measurements.yaml +675 -0
  235. valuesets/schema/valuesets.yaml +100 -0
  236. valuesets/schema/visual/colors.yaml +778 -0
  237. valuesets/utils/__init__.py +6 -0
  238. valuesets/utils/comparison.py +102 -0
  239. valuesets/utils/expand_dynamic_enums.py +414 -0
  240. valuesets/utils/mapping_utils.py +236 -0
  241. valuesets/validators/__init__.py +11 -0
  242. valuesets/validators/enum_evaluator.py +669 -0
  243. valuesets/validators/oak_config.yaml +70 -0
  244. valuesets/validators/validate_with_ols.py +241 -0
  245. valuesets-0.3.1.dist-info/METADATA +395 -0
  246. valuesets-0.3.1.dist-info/RECORD +248 -0
  247. valuesets-0.3.1.dist-info/WHEEL +4 -0
  248. valuesets-0.3.1.dist-info/licenses/LICENSE +201 -0
@@ -0,0 +1,310 @@
1
+ """
2
+ Rich Pydantic Generator for LinkML Schemas
3
+
4
+ This generator creates Pydantic-compatible Python code from LinkML schemas,
5
+ with enhanced enum support that includes metadata (descriptions, meanings, annotations).
6
+ """
7
+
8
+ import re
9
+ from dataclasses import dataclass
10
+ from typing import Dict, Any, List, Optional, TextIO
11
+ from pathlib import Path
12
+
13
+ from linkml_runtime.utils.schemaview import SchemaView
14
+ from linkml_runtime.linkml_model.meta import (
15
+ SchemaDefinition, EnumDefinition, PermissibleValue, ClassDefinition
16
+ )
17
+ from linkml.generators.pydanticgen import PydanticGenerator
18
+
19
+
20
+ class RichPydanticGenerator(PydanticGenerator):
21
+ """
22
+ Enhanced Pydantic generator that creates enums with metadata support.
23
+
24
+ This generator extends the base PydanticGenerator to create enums that:
25
+ 1. Are fully compatible with standard Python enums
26
+ 2. Include all metadata from LinkML schemas (descriptions, meanings, annotations)
27
+ 3. Provide convenient methods to access metadata
28
+ """
29
+
30
+ generatorname = "rich-pydantic"
31
+ generatorversion = "0.1.0"
32
+
33
+ def __init__(self, schema: str, **kwargs):
34
+ super().__init__(schema, **kwargs)
35
+ self.schema_view = SchemaView(schema)
36
+
37
+ def serialize(self, **kwargs) -> str:
38
+ """Generate the complete Python module."""
39
+ output = []
40
+
41
+ # Header and imports
42
+ output.extend(self._generate_header())
43
+ output.extend(self._generate_imports())
44
+
45
+ # Base classes and utilities
46
+ output.extend(self._generate_base_classes())
47
+
48
+ # Generate all enums with rich metadata
49
+ output.extend(self._generate_rich_enums())
50
+
51
+ # Generate classes (reuse base generator logic)
52
+ output.extend(self._generate_classes())
53
+
54
+ return "\n".join(output)
55
+
56
+ def _generate_header(self) -> List[str]:
57
+ """Generate file header."""
58
+ return [
59
+ '"""',
60
+ 'Generated Pydantic models with rich enum support.',
61
+ '',
62
+ 'This module was automatically generated from a LinkML schema.',
63
+ 'It includes enums with full metadata support (descriptions, meanings, annotations).',
64
+ '"""',
65
+ '',
66
+ 'from __future__ import annotations',
67
+ ''
68
+ ]
69
+
70
+ def _generate_imports(self) -> List[str]:
71
+ """Generate import statements."""
72
+ return [
73
+ 'import re',
74
+ 'import sys',
75
+ 'from datetime import date, datetime, time',
76
+ 'from decimal import Decimal',
77
+ 'from enum import Enum',
78
+ 'from typing import Any, ClassVar, List, Literal, Dict, Optional, Union',
79
+ '',
80
+ 'from pydantic import BaseModel, ConfigDict, Field, RootModel, field_validator',
81
+ '',
82
+ '# Import our rich enum support',
83
+ 'from valuesets.generators.rich_enum import RichEnum',
84
+ '',
85
+ ]
86
+
87
+ def _generate_base_classes(self) -> List[str]:
88
+ """Generate base configuration classes."""
89
+ return [
90
+ 'metamodel_version = "None"',
91
+ 'version = "None"',
92
+ '',
93
+ '',
94
+ 'class ConfiguredBaseModel(BaseModel):',
95
+ ' model_config = ConfigDict(',
96
+ ' validate_assignment=True,',
97
+ ' validate_default=True,',
98
+ ' extra="forbid",',
99
+ ' arbitrary_types_allowed=True,',
100
+ ' use_enum_values=True,',
101
+ ' strict=False,',
102
+ ' )',
103
+ ' pass',
104
+ '',
105
+ '',
106
+ 'class LinkMLMeta(RootModel):',
107
+ ' root: Dict[str, Any] = {}',
108
+ ' model_config = ConfigDict(frozen=True)',
109
+ '',
110
+ ' def __getattr__(self, key: str):',
111
+ ' return getattr(self.root, key)',
112
+ '',
113
+ ' def __getitem__(self, key: str):',
114
+ ' return self.root[key]',
115
+ '',
116
+ ' def __setitem__(self, key: str, value):',
117
+ ' self.root[key] = value',
118
+ '',
119
+ ' def __contains__(self, key: str) -> bool:',
120
+ ' return key in self.root',
121
+ '',
122
+ '',
123
+ f'linkml_meta = LinkMLMeta({self._generate_linkml_meta()})',
124
+ '',
125
+ ]
126
+
127
+ def _generate_linkml_meta(self) -> str:
128
+ """Generate the linkml_meta dictionary."""
129
+ schema = self.schema_view.schema
130
+ meta_dict = {
131
+ 'default_prefix': schema.default_prefix,
132
+ 'description': schema.description,
133
+ 'id': schema.id,
134
+ 'name': schema.name,
135
+ 'title': schema.title,
136
+ }
137
+ return repr(meta_dict)
138
+
139
+ def _generate_rich_enums(self) -> List[str]:
140
+ """Generate all enums with metadata support."""
141
+ output = []
142
+
143
+ for enum_name in self.schema_view.all_enums():
144
+ enum_def = self.schema_view.get_enum(enum_name)
145
+ if enum_def and enum_def.permissible_values:
146
+ output.extend(self._generate_single_rich_enum(enum_name, enum_def))
147
+ output.append('') # Add spacing between enums
148
+
149
+ return output
150
+
151
+ def _generate_single_rich_enum(self, enum_name: str, enum_def: EnumDefinition) -> List[str]:
152
+ """Generate a single rich enum."""
153
+ output = []
154
+
155
+ # Class definition
156
+ class_name = self._get_class_name(enum_name)
157
+ output.append(f'class {class_name}(RichEnum):')
158
+
159
+ # Class docstring
160
+ if enum_def.description:
161
+ output.append(' """')
162
+ output.append(f' {enum_def.description}')
163
+ output.append(' """')
164
+
165
+ # Enum members
166
+ output.append(' # Enum members')
167
+ for pv_name, pv in enum_def.permissible_values.items():
168
+ member_name = self._get_enum_member_name(pv_name)
169
+ member_value = pv.text if pv.text is not None else pv_name
170
+ output.append(f' {member_name} = "{member_value}"')
171
+
172
+ output.append('')
173
+
174
+ # Set metadata after class creation to avoid it becoming an enum member
175
+ output.append(f'# Set metadata after class creation to avoid it becoming an enum member')
176
+ output.append(f'{class_name}._metadata = {{')
177
+
178
+ for pv_name, pv in enum_def.permissible_values.items():
179
+ member_name = self._get_enum_member_name(pv_name)
180
+ metadata = self._build_metadata_dict(pv)
181
+
182
+ if metadata: # Only add if there's actual metadata
183
+ output.append(f' "{member_name}": {repr(metadata)},')
184
+
185
+ output.append('}')
186
+
187
+ return output
188
+
189
+ def _build_metadata_dict(self, pv: PermissibleValue) -> Dict[str, Any]:
190
+ """Build metadata dictionary for a permissible value."""
191
+ metadata = {}
192
+
193
+ if pv.description:
194
+ metadata['description'] = pv.description
195
+
196
+ if pv.meaning:
197
+ metadata['meaning'] = pv.meaning
198
+
199
+ if pv.annotations:
200
+ # Convert annotation objects to simple dictionaries
201
+ annotations_dict = {}
202
+ for key, annotation in pv.annotations.items():
203
+ if hasattr(annotation, 'value'):
204
+ annotations_dict[key] = annotation.value
205
+ else:
206
+ annotations_dict[key] = str(annotation)
207
+ metadata['annotations'] = annotations_dict
208
+
209
+ # Add other fields if they exist
210
+ if hasattr(pv, 'aliases') and pv.aliases:
211
+ metadata['aliases'] = list(pv.aliases)
212
+
213
+ if hasattr(pv, 'deprecated') and pv.deprecated:
214
+ metadata['deprecated'] = pv.deprecated
215
+
216
+ return metadata
217
+
218
+ def _generate_classes(self) -> List[str]:
219
+ """Generate Pydantic model classes."""
220
+ # For now, we'll use a simplified approach
221
+ # In a full implementation, we'd generate full Pydantic models
222
+ output = []
223
+
224
+ for class_name in self.schema_view.all_classes():
225
+ class_def = self.schema_view.get_class(class_name)
226
+ if class_def:
227
+ output.extend(self._generate_single_class(class_name, class_def))
228
+ output.append('')
229
+
230
+ return output
231
+
232
+ def _generate_single_class(self, class_name: str, class_def: ClassDefinition) -> List[str]:
233
+ """Generate a single Pydantic model class."""
234
+ output = []
235
+
236
+ # For now, just create empty classes with docstrings
237
+ pydantic_class_name = self._get_class_name(class_name)
238
+ output.append(f'class {pydantic_class_name}(ConfiguredBaseModel):')
239
+
240
+ if class_def.description:
241
+ output.append(' """')
242
+ output.append(f' {class_def.description}')
243
+ output.append(' """')
244
+
245
+ output.append(' pass # TODO: Implement class slots')
246
+
247
+ return output
248
+
249
+ def _get_class_name(self, name: str) -> str:
250
+ """Convert a LinkML name to a Python class name with proper CamelCase."""
251
+ # Handle already CamelCase names
252
+ if not any(c in name for c in ['_', '-', ' ']):
253
+ # If it's already in some form of CamelCase, preserve it
254
+ # Just ensure first letter is capitalized
255
+ return name[0].upper() + name[1:] if name else ''
256
+
257
+ # Convert snake_case, kebab-case, or space-separated to CamelCase
258
+ words = re.split(r'[_\s-]+', name)
259
+
260
+ # Properly capitalize each word, preserving existing caps when appropriate
261
+ result = []
262
+ for word in words:
263
+ if word:
264
+ if word.isupper():
265
+ # If the word is all caps (like "ISO"), keep it that way
266
+ result.append(word)
267
+ elif word[0].isupper() and len(word) > 1:
268
+ # If already starts with capital, preserve the casing
269
+ result.append(word)
270
+ else:
271
+ # Otherwise, capitalize first letter
272
+ result.append(word[0].upper() + word[1:].lower())
273
+
274
+ return ''.join(result)
275
+
276
+ def _get_enum_member_name(self, name: str) -> str:
277
+ """Convert a permissible value name to a Python enum member name."""
278
+ # Convert to valid Python identifier in UPPER_CASE
279
+ # Replace invalid characters with underscores
280
+ member_name = re.sub(r'[^a-zA-Z0-9_]', '_', name).upper()
281
+
282
+ # Ensure it doesn't start with a digit
283
+ if member_name and member_name[0].isdigit():
284
+ member_name = f'_{member_name}'
285
+
286
+ return member_name
287
+
288
+
289
+ def cli():
290
+ """Command line interface for the rich pydantic generator."""
291
+ import argparse
292
+
293
+ parser = argparse.ArgumentParser(description='Generate rich Pydantic models from LinkML schema')
294
+ parser.add_argument('schema', help='LinkML schema file')
295
+ parser.add_argument('-o', '--output', help='Output file (default: stdout)')
296
+
297
+ args = parser.parse_args()
298
+
299
+ generator = RichPydanticGenerator(args.schema)
300
+ output = generator.serialize()
301
+
302
+ if args.output:
303
+ with open(args.output, 'w') as f:
304
+ f.write(output)
305
+ else:
306
+ print(output)
307
+
308
+
309
+ if __name__ == '__main__':
310
+ cli()