linkml 1.9.4rc2__py3-none-any.whl → 1.9.5rc2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. linkml/cli/main.py +5 -1
  2. linkml/converter/__init__.py +0 -0
  3. linkml/generators/__init__.py +2 -0
  4. linkml/generators/common/build.py +5 -20
  5. linkml/generators/common/template.py +289 -3
  6. linkml/generators/docgen.py +55 -10
  7. linkml/generators/erdiagramgen.py +9 -5
  8. linkml/generators/graphqlgen.py +32 -6
  9. linkml/generators/jsonldcontextgen.py +78 -12
  10. linkml/generators/jsonschemagen.py +29 -12
  11. linkml/generators/mermaidclassdiagramgen.py +21 -3
  12. linkml/generators/owlgen.py +13 -2
  13. linkml/generators/panderagen/dataframe_class.py +13 -0
  14. linkml/generators/panderagen/dataframe_field.py +50 -0
  15. linkml/generators/panderagen/linkml_pandera_validator.py +186 -0
  16. linkml/generators/panderagen/panderagen.py +22 -5
  17. linkml/generators/panderagen/panderagen_class_based/class.jinja2 +70 -13
  18. linkml/generators/panderagen/panderagen_class_based/custom_checks.jinja2 +27 -0
  19. linkml/generators/panderagen/panderagen_class_based/enums.jinja2 +3 -3
  20. linkml/generators/panderagen/panderagen_class_based/pandera.jinja2 +12 -2
  21. linkml/generators/panderagen/panderagen_class_based/slots.jinja2 +19 -17
  22. linkml/generators/panderagen/slot_generator_mixin.py +143 -16
  23. linkml/generators/panderagen/transforms/__init__.py +19 -0
  24. linkml/generators/panderagen/transforms/collection_dict_model_transform.py +62 -0
  25. linkml/generators/panderagen/transforms/list_dict_model_transform.py +66 -0
  26. linkml/generators/panderagen/transforms/model_transform.py +8 -0
  27. linkml/generators/panderagen/transforms/nested_struct_model_transform.py +27 -0
  28. linkml/generators/panderagen/transforms/simple_dict_model_transform.py +86 -0
  29. linkml/generators/plantumlgen.py +17 -11
  30. linkml/generators/pydanticgen/pydanticgen.py +53 -2
  31. linkml/generators/pydanticgen/template.py +45 -233
  32. linkml/generators/pydanticgen/templates/attribute.py.jinja +1 -0
  33. linkml/generators/pydanticgen/templates/base_model.py.jinja +16 -2
  34. linkml/generators/pydanticgen/templates/imports.py.jinja +1 -1
  35. linkml/generators/rdfgen.py +11 -2
  36. linkml/generators/rustgen/__init__.py +3 -0
  37. linkml/generators/rustgen/build.py +97 -0
  38. linkml/generators/rustgen/cli.py +83 -0
  39. linkml/generators/rustgen/rustgen.py +1186 -0
  40. linkml/generators/rustgen/template.py +910 -0
  41. linkml/generators/rustgen/templates/Cargo.toml.jinja +42 -0
  42. linkml/generators/rustgen/templates/anything.rs.jinja +149 -0
  43. linkml/generators/rustgen/templates/as_key_value.rs.jinja +86 -0
  44. linkml/generators/rustgen/templates/class_module.rs.jinja +8 -0
  45. linkml/generators/rustgen/templates/enum.rs.jinja +70 -0
  46. linkml/generators/rustgen/templates/file.rs.jinja +75 -0
  47. linkml/generators/rustgen/templates/import.rs.jinja +4 -0
  48. linkml/generators/rustgen/templates/imports.rs.jinja +8 -0
  49. linkml/generators/rustgen/templates/lib_shim.rs.jinja +52 -0
  50. linkml/generators/rustgen/templates/poly.rs.jinja +9 -0
  51. linkml/generators/rustgen/templates/poly_containers.rs.jinja +439 -0
  52. linkml/generators/rustgen/templates/poly_trait.rs.jinja +15 -0
  53. linkml/generators/rustgen/templates/poly_trait_impl.rs.jinja +5 -0
  54. linkml/generators/rustgen/templates/poly_trait_impl_orsubtype.rs.jinja +5 -0
  55. linkml/generators/rustgen/templates/poly_trait_property.rs.jinja +8 -0
  56. linkml/generators/rustgen/templates/poly_trait_property_impl.rs.jinja +134 -0
  57. linkml/generators/rustgen/templates/poly_trait_property_match.rs.jinja +10 -0
  58. linkml/generators/rustgen/templates/property.rs.jinja +28 -0
  59. linkml/generators/rustgen/templates/pyproject.toml.jinja +10 -0
  60. linkml/generators/rustgen/templates/serde_utils.rs.jinja +490 -0
  61. linkml/generators/rustgen/templates/slot_range_as_union.rs.jinja +64 -0
  62. linkml/generators/rustgen/templates/struct.rs.jinja +81 -0
  63. linkml/generators/rustgen/templates/struct_or_subtype_enum.rs.jinja +111 -0
  64. linkml/generators/rustgen/templates/stub_gen.rs.jinja +71 -0
  65. linkml/generators/rustgen/templates/stub_utils.rs.jinja +76 -0
  66. linkml/generators/rustgen/templates/typealias.rs.jinja +13 -0
  67. linkml/generators/sqltablegen.py +18 -16
  68. linkml/generators/yarrrmlgen.py +173 -0
  69. linkml/linter/config/datamodel/config.py +160 -293
  70. linkml/linter/config/datamodel/config.yaml +34 -26
  71. linkml/linter/config/default.yaml +4 -0
  72. linkml/linter/config/recommended.yaml +4 -0
  73. linkml/linter/linter.py +1 -2
  74. linkml/linter/rules.py +37 -0
  75. linkml/utils/schema_builder.py +2 -0
  76. linkml/utils/schemaloader.py +55 -3
  77. {linkml-1.9.4rc2.dist-info → linkml-1.9.5rc2.dist-info}/METADATA +1 -1
  78. {linkml-1.9.4rc2.dist-info → linkml-1.9.5rc2.dist-info}/RECORD +82 -40
  79. {linkml-1.9.4rc2.dist-info → linkml-1.9.5rc2.dist-info}/entry_points.txt +2 -1
  80. linkml/generators/panderagen/panderagen_class_based/mixins.jinja2 +0 -26
  81. /linkml/{utils/converter.py → converter/cli.py} +0 -0
  82. {linkml-1.9.4rc2.dist-info → linkml-1.9.5rc2.dist-info}/WHEEL +0 -0
  83. {linkml-1.9.4rc2.dist-info → linkml-1.9.5rc2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,490 @@
1
+ #[cfg(feature = "serde")]
2
+ use serde::{
3
+ de::{DeserializeOwned, IntoDeserializer},
4
+ Deserialize,
5
+ Deserializer,
6
+ Serialize,
7
+ Serializer,
8
+ };
9
+ #[cfg(feature = "serde")]
10
+ use serde::de::Error;
11
+ #[cfg(feature = "serde")]
12
+ use serde_value::{to_value, Value, ValueDeserializer};
13
+ #[cfg(feature = "serde")]
14
+ use std::collections::{BTreeMap, HashMap};
15
+ #[cfg(all(feature = "serde", feature = "pyo3"))]
16
+ use pyo3::prelude::*;
17
+ #[cfg(all(feature = "serde", feature = "pyo3"))]
18
+ use pyo3::types::{PyAny, PyDict, PyList, PyTuple};
19
+
20
+ #[cfg(feature = "serde")]
21
+ pub trait InlinedPair: Sized {
22
+ type Key: std::hash::Hash + Eq + serde::de::DeserializeOwned + Clone + Ord;
23
+ type Value: serde::de::DeserializeOwned;
24
+ type Error: std::fmt::Display;
25
+
26
+ fn from_pair_mapping(k: Self::Key, v: Value) -> Result<Self,Self::Error>;
27
+ fn from_pair_simple(k: Self::Key, v: Value) -> Result<Self,Self::Error>;
28
+ fn extract_key(&self) -> &Self::Key;
29
+
30
+ fn simple_value(&self) -> Option<&Self::Value> {
31
+ None
32
+ }
33
+
34
+ fn compact_value(&self) -> Option<Value> {
35
+ None
36
+ }
37
+ }
38
+
39
+ #[cfg(feature = "serde")]
40
+ impl<T> InlinedPair for Box<T>
41
+ where
42
+ T: InlinedPair + ?Sized, // allow unsized boxes too
43
+ {
44
+ type Key = T::Key;
45
+ type Value = T::Value;
46
+ type Error = T::Error;
47
+
48
+ #[inline]
49
+ fn from_pair_mapping(k: Self::Key, v: Value) -> Result<Self, Self::Error> {
50
+ T::from_pair_mapping(k, v).map(|x| Box::new(x))
51
+ }
52
+
53
+ #[inline]
54
+ fn from_pair_simple(k: Self::Key, v: Value) -> Result<Self, Self::Error> {
55
+ T::from_pair_simple(k, v).map(|x| Box::new(x))
56
+ }
57
+
58
+ #[inline]
59
+ fn extract_key(&self) -> &Self::Key {
60
+ T::extract_key(self)
61
+ }
62
+
63
+ fn simple_value(&self) -> Option<&Self::Value> {
64
+ self.as_ref().simple_value()
65
+ }
66
+
67
+ fn compact_value(&self) -> Option<Value> {
68
+ self.as_ref().compact_value()
69
+ }
70
+
71
+ }
72
+
73
+ #[cfg(feature = "serde")]
74
+ #[allow(dead_code)]
75
+ pub fn deserialize_inlined_dict_list<'de, D, T>(de: D) -> Result<Vec<T>, D::Error>
76
+ where
77
+ D: Deserializer<'de>,
78
+ T: InlinedPair,
79
+ {
80
+ let raw: BTreeMap<T::Key, Value> = BTreeMap::deserialize(de)?;
81
+ raw.into_iter().map(|(k, v)| {
82
+ let obj = T::from_pair_mapping(k.clone(), v).map_err(D::Error::custom)?;
83
+ Ok(obj)
84
+ }).collect()
85
+
86
+ }
87
+
88
+ #[cfg(feature = "serde")]
89
+ pub fn deserialize_inlined_dict_map<'de, D, T>(
90
+ de: D,
91
+ ) -> Result<HashMap<T::Key, T>, D::Error>
92
+ where
93
+ D: Deserializer<'de>,
94
+ T: InlinedPair + Deserialize<'de>,
95
+ {
96
+
97
+ // Parse into a generic AST once
98
+ let ast: Value = Value::deserialize(de)?;
99
+
100
+ match ast {
101
+ // ---------- { key : value } form ----------
102
+ Value::Map(m) => {
103
+ let mut out = HashMap::with_capacity(m.len());
104
+ for (k_ast, v_ast) in m {
105
+ // 1) convert key and value separately
106
+ let key: T::Key = Deserialize::deserialize(
107
+ ValueDeserializer::<D::Error>::new(k_ast)
108
+ ).map_err(D::Error::custom)?;
109
+
110
+
111
+ // ----------------- decide by the *value* shape
112
+ let obj = match v_ast {
113
+ // (1) full object (mapping) -> deserialize directly
114
+ Value::Map(_) => {
115
+ let m: Value = Deserialize::deserialize(
116
+ ValueDeserializer::<D::Error>::new(v_ast)
117
+ ).map_err(D::Error::custom)?;
118
+ T::from_pair_mapping(key.clone(), m).map_err(D::Error::custom)?
119
+ }
120
+ other => {
121
+ T::from_pair_simple(key.clone(), other).map_err(D::Error::custom)?
122
+ }
123
+ };
124
+
125
+
126
+ out.insert(key, obj);
127
+ }
128
+ Ok(out)
129
+ }
130
+
131
+ // ---------- [ value, ... ] form -------------
132
+ Value::Seq(seq) => {
133
+ let mut out = HashMap::with_capacity(seq.len());
134
+ for v_ast in seq {
135
+ let val: T = Deserialize::deserialize(
136
+ ValueDeserializer::<D::Error>::new(v_ast)
137
+ ).map_err(D::Error::custom)?;
138
+
139
+ let key = val.extract_key().clone();
140
+ if out.insert(key, val).is_some() {
141
+ return Err(D::Error::custom("duplicate key"));
142
+ }
143
+ }
144
+ Ok(out)
145
+ }
146
+
147
+ _ => Err(D::Error::custom("expected mapping or sequence")),
148
+ }
149
+ }
150
+
151
+ #[cfg(feature = "serde")]
152
+ pub fn deserialize_inlined_dict_map_optional<'de, D, T>(
153
+ de: D,
154
+ ) -> Result<Option<HashMap<T::Key, T>>, D::Error>
155
+ where
156
+ D: Deserializer<'de>,
157
+ T: InlinedPair + Deserialize<'de>,
158
+ {
159
+ let ast: Value = Value::deserialize(de)?;
160
+ match ast {
161
+ Value::Unit => Ok(None),
162
+ Value::Map(_) | Value::Seq(_) => {
163
+ let map = deserialize_inlined_dict_map(ValueDeserializer::<D::Error>::new(ast))?;
164
+ Ok(Some(map))
165
+ }
166
+ _ => Err(D::Error::custom("expected mapping, sequence, or unit")),
167
+ }
168
+ }
169
+
170
+
171
+ #[cfg(feature = "serde")]
172
+ #[allow(dead_code)]
173
+ pub fn deserialize_inlined_dict_list_optional<'de, D, T>(
174
+ de: D,
175
+ ) -> Result<Option<Vec<T>>, D::Error>
176
+ where
177
+ D: Deserializer<'de>,
178
+ T: InlinedPair + Deserialize<'de>,
179
+ {
180
+ let ast: Value = Value::deserialize(de)?;
181
+ match ast {
182
+ Value::Unit => Ok(None),
183
+ Value::Map(_) => {
184
+ let list = deserialize_inlined_dict_list(ValueDeserializer::<D::Error>::new(ast))?;
185
+ Ok(Some(list))
186
+ }
187
+ Value::Seq(seq) => {
188
+ let mut out = Vec::with_capacity(seq.len());
189
+ for v_ast in seq {
190
+ let val: T = Deserialize::deserialize(ValueDeserializer::<D::Error>::new(v_ast))
191
+ .map_err(D::Error::custom)?;
192
+ out.push(val);
193
+ }
194
+ Ok(Some(out))
195
+ }
196
+ _ => Err(D::Error::custom("expected mapping, sequence, or unit")),
197
+ }
198
+ }
199
+
200
+ pub fn deserialize_primitive_list_or_single_value<'de, D, T>(
201
+ deserializer: D
202
+ ) -> Result<Vec<T>, D::Error>
203
+ where
204
+ D: Deserializer<'de>,
205
+ T: Deserialize<'de>,
206
+ {
207
+ let ast: Value = Value::deserialize(deserializer)?;
208
+ match ast {
209
+ Value::Seq(seq) => {
210
+ seq.into_iter()
211
+ .map(|v| T::deserialize(ValueDeserializer::<D::Error>::new(v)))
212
+ .collect()
213
+ }
214
+ Value::Unit => Ok(vec![]),
215
+ other => {
216
+ let single_value: T = Deserialize::deserialize(
217
+ ValueDeserializer::<D::Error>::new(other)
218
+ ).map_err(D::Error::custom)?;
219
+ Ok(vec![single_value])
220
+ }
221
+ }
222
+ }
223
+
224
+
225
+ pub fn deserialize_primitive_list_or_single_value_optional<'de, D, T>(
226
+ deserializer: D
227
+ ) -> Result<Option<Vec<T>>, D::Error>
228
+ where
229
+ D: Deserializer<'de>,
230
+ T: Deserialize<'de>,
231
+ {
232
+ let ast: Value = Value::deserialize(deserializer)?;
233
+ match ast {
234
+ Value::Unit => Ok(None),
235
+ _ => {
236
+ let d = deserialize_primitive_list_or_single_value(ValueDeserializer::<D::Error>::new(ast))?;
237
+ Ok(Some(d))
238
+ }
239
+ }
240
+ }
241
+
242
+ #[cfg(all(feature = "serde", feature = "pyo3"))]
243
+ fn py_any_to_value(bound: &Bound<'_, PyAny>) -> PyResult<Value> {
244
+ if bound.is_none() {
245
+ return Ok(Value::Unit);
246
+ }
247
+
248
+ if let Ok(b) = bound.extract::<bool>() {
249
+ return Ok(Value::Bool(b));
250
+ }
251
+
252
+ if let Ok(i) = bound.extract::<i64>() {
253
+ return Ok(Value::I64(i));
254
+ }
255
+
256
+ if let Ok(f) = bound.extract::<f64>() {
257
+ return Ok(Value::F64(f));
258
+ }
259
+
260
+ if let Ok(s) = bound.extract::<String>() {
261
+ return Ok(Value::String(s));
262
+ }
263
+
264
+ if let Ok(dict_obj) = bound.getattr("__dict__") {
265
+ if let Ok(dict) = dict_obj.downcast::<PyDict>() {
266
+ let mut map: BTreeMap<Value, Value> = BTreeMap::new();
267
+ for (k, v) in dict.iter() {
268
+ let key_str: String = k.extract()?;
269
+ let val = py_any_to_value(&v)?;
270
+ map.insert(Value::String(key_str), val);
271
+ }
272
+ return Ok(Value::Map(map));
273
+ }
274
+ }
275
+
276
+ if let Ok(dict) = bound.downcast::<PyDict>() {
277
+ let mut map: BTreeMap<Value, Value> = BTreeMap::new();
278
+ for (k, v) in dict.iter() {
279
+ let key_str: String = k.extract()?;
280
+ let val = py_any_to_value(&v)?;
281
+ map.insert(Value::String(key_str), val);
282
+ }
283
+ return Ok(Value::Map(map));
284
+ }
285
+
286
+ if let Ok(list) = bound.downcast::<PyList>() {
287
+ let mut items = Vec::with_capacity(list.len());
288
+ for item in list.iter() {
289
+ items.push(py_any_to_value(&item)?);
290
+ }
291
+ return Ok(Value::Seq(items));
292
+ }
293
+
294
+ if let Ok(tuple) = bound.downcast::<PyTuple>() {
295
+ let mut items = Vec::with_capacity(tuple.len());
296
+ for item in tuple.iter() {
297
+ items.push(py_any_to_value(&item)?);
298
+ }
299
+ return Ok(Value::Seq(items));
300
+ }
301
+
302
+ Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
303
+ "unsupported value type for conversion",
304
+ ))
305
+ }
306
+
307
+ #[cfg(feature = "serde")]
308
+ #[allow(dead_code)]
309
+ pub fn serialize_inlined_dict_map<S, T>(
310
+ value: &HashMap<T::Key, T>,
311
+ serializer: S,
312
+ ) -> Result<S::Ok, S::Error>
313
+ where
314
+ S: Serializer,
315
+ T: InlinedPair + Serialize,
316
+ T::Key: Serialize + Clone + Ord,
317
+ T::Value: Serialize,
318
+ {
319
+ let mut ordered: BTreeMap<T::Key, &T> = BTreeMap::new();
320
+ for (k, v) in value.iter() {
321
+ ordered.insert(k.clone(), v);
322
+ }
323
+
324
+ let mut as_values: BTreeMap<T::Key, Value> = BTreeMap::new();
325
+ for (k, v) in ordered.iter() {
326
+ if let Some(simple) = v.simple_value() {
327
+ let val = to_value(simple)
328
+ .map_err(|e| <S::Error as serde::ser::Error>::custom(e))?;
329
+ as_values.insert((*k).clone(), val);
330
+ continue;
331
+ }
332
+ if let Some(compact) = v.compact_value() {
333
+ as_values.insert((*k).clone(), compact);
334
+ continue;
335
+ }
336
+ let val = to_value(*v)
337
+ .map_err(|e| <S::Error as serde::ser::Error>::custom(e))?;
338
+ as_values.insert((*k).clone(), val);
339
+ }
340
+ as_values.serialize(serializer)
341
+ }
342
+
343
+ #[cfg(feature = "serde")]
344
+ #[allow(dead_code)]
345
+ pub fn serialize_inlined_dict_map_optional<S, T>(
346
+ value: &Option<HashMap<T::Key, T>>,
347
+ serializer: S,
348
+ ) -> Result<S::Ok, S::Error>
349
+ where
350
+ S: Serializer,
351
+ T: InlinedPair + Serialize,
352
+ T::Key: Serialize + Clone + Ord,
353
+ T::Value: Serialize,
354
+ {
355
+ match value {
356
+ Some(map) => serialize_inlined_dict_map(map, serializer),
357
+ None => serializer.serialize_none(),
358
+ }
359
+ }
360
+
361
+ #[cfg(feature = "serde")]
362
+ #[allow(dead_code)]
363
+ pub fn serialize_inlined_dict_list<S, T>(
364
+ value: &Vec<T>,
365
+ serializer: S,
366
+ ) -> Result<S::Ok, S::Error>
367
+ where
368
+ S: Serializer,
369
+ T: InlinedPair + Serialize,
370
+ T::Key: Serialize + Clone + Ord,
371
+ T::Value: Serialize,
372
+ {
373
+ let mut ordered: BTreeMap<T::Key, &T> = BTreeMap::new();
374
+ for item in value.iter() {
375
+ ordered.insert(item.extract_key().clone(), item);
376
+ }
377
+
378
+ let mut as_values: BTreeMap<T::Key, Value> = BTreeMap::new();
379
+ for (k, v) in ordered.iter() {
380
+ if let Some(simple) = v.simple_value() {
381
+ let val = to_value(simple)
382
+ .map_err(|e| <S::Error as serde::ser::Error>::custom(e))?;
383
+ as_values.insert((*k).clone(), val);
384
+ continue;
385
+ }
386
+ if let Some(compact) = v.compact_value() {
387
+ as_values.insert((*k).clone(), compact);
388
+ continue;
389
+ }
390
+ let val = to_value(*v)
391
+ .map_err(|e| <S::Error as serde::ser::Error>::custom(e))?;
392
+ as_values.insert((*k).clone(), val);
393
+ }
394
+ as_values.serialize(serializer)
395
+ }
396
+
397
+ #[cfg(feature = "serde")]
398
+ #[allow(dead_code)]
399
+ pub fn serialize_inlined_dict_list_optional<S, T>(
400
+ value: &Option<Vec<T>>,
401
+ serializer: S,
402
+ ) -> Result<S::Ok, S::Error>
403
+ where
404
+ S: Serializer,
405
+ T: InlinedPair + Serialize,
406
+ T::Key: Serialize + Clone + Ord,
407
+ T::Value: Serialize,
408
+ {
409
+ match value {
410
+ Some(items) => serialize_inlined_dict_list(items, serializer),
411
+ None => serializer.serialize_none(),
412
+ }
413
+ }
414
+
415
+ #[cfg(feature = "serde")]
416
+ #[allow(dead_code)]
417
+ pub fn serialize_primitive_list_or_single_value<S, T>(
418
+ value: &Vec<T>,
419
+ serializer: S,
420
+ ) -> Result<S::Ok, S::Error>
421
+ where
422
+ S: Serializer,
423
+ T: Serialize,
424
+ {
425
+ match value.as_slice() {
426
+ [single] => single.serialize(serializer),
427
+ _ => value.serialize(serializer),
428
+ }
429
+ }
430
+
431
+ #[cfg(feature = "serde")]
432
+ #[allow(dead_code)]
433
+ pub fn serialize_primitive_list_or_single_value_optional<S, T>(
434
+ value: &Option<Vec<T>>,
435
+ serializer: S,
436
+ ) -> Result<S::Ok, S::Error>
437
+ where
438
+ S: Serializer,
439
+ T: Serialize,
440
+ {
441
+ match value {
442
+ Some(v) => serialize_primitive_list_or_single_value(v, serializer),
443
+ None => serializer.serialize_none(),
444
+ }
445
+ }
446
+
447
+ #[cfg(all(feature = "serde", feature = "pyo3"))]
448
+ pub fn deserialize_py_any<'py, T>(bound: &Bound<'py, PyAny>) -> PyResult<T>
449
+ where
450
+ T: DeserializeOwned,
451
+ {
452
+ let value = py_any_to_value(bound)?;
453
+ let de = value.into_deserializer();
454
+ match serde_path_to_error::deserialize(de) {
455
+ Ok(ok) => Ok(ok),
456
+ Err(err) => Err(PyErr::new::<pyo3::exceptions::PyValueError, _>(
457
+ format!("at `{}`: {}", err.path(), err.inner()),
458
+ )),
459
+ }
460
+ }
461
+
462
+ #[cfg(feature = "pyo3")]
463
+ pub struct PyValue<T>(pub T);
464
+
465
+ #[cfg(feature = "pyo3")]
466
+ impl<T> PyValue<T> {
467
+ pub fn into_inner(self) -> T {
468
+ self.0
469
+ }
470
+ }
471
+
472
+ #[cfg(all(feature = "pyo3", feature = "stubgen"))]
473
+ impl<T> ::pyo3_stub_gen::PyStubType for PyValue<T>
474
+ where
475
+ T: ::pyo3_stub_gen::PyStubType,
476
+ {
477
+ fn type_output() -> ::pyo3_stub_gen::TypeInfo {
478
+ T::type_output()
479
+ }
480
+ }
481
+
482
+ #[cfg(all(feature = "pyo3", feature = "serde"))]
483
+ impl<'py, T> FromPyObject<'py> for PyValue<T>
484
+ where
485
+ T: DeserializeOwned,
486
+ {
487
+ fn extract_bound(ob: &Bound<'py, PyAny>) -> PyResult<Self> {
488
+ deserialize_py_any(ob).map(PyValue)
489
+ }
490
+ }
@@ -0,0 +1,64 @@
1
+ #[derive(Debug, Clone, PartialEq)]
2
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
3
+ pub enum {{ slot_name }}_range {
4
+ {% for r in ranges %}
5
+ {{ r }}({{ r }}){% if not loop.last %},
6
+ {% endif %}
7
+ {% endfor %}
8
+ }
9
+
10
+ #[cfg(feature = "pyo3")]
11
+ impl<'py> FromPyObject<'py> for {{ slot_name }}_range {
12
+ fn extract_bound(ob: &pyo3::Bound<'py, pyo3::types::PyAny>) -> pyo3::PyResult<Self> {
13
+ {% for t in ranges %}
14
+ if let Ok(val) = ob.extract::<{{ t }}>() {
15
+ return Ok({{ slot_name }}_range::{{ t }}(val));
16
+ }
17
+ {%- endfor -%}
18
+ Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
19
+ "invalid {{ slot_name }}",
20
+ ))
21
+ }
22
+ }
23
+
24
+ #[cfg(feature = "pyo3")]
25
+ impl<'py> IntoPyObject<'py> for {{ slot_name }}_range {
26
+ type Target = PyAny;
27
+ type Output = Bound<'py, Self::Target>;
28
+ type Error = PyErr;
29
+
30
+ fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
31
+ match self {
32
+ {% for t in ranges %}
33
+ {{ slot_name }}_range::{{ t }}(val) => Ok(val.into_pyobject(py).map(move |b| <pyo3::Bound<'_, _> as Clone>::clone(&b).into_any())?),
34
+ {% endfor %}
35
+ }
36
+ }
37
+ }
38
+
39
+
40
+ #[cfg(feature = "pyo3")]
41
+ impl<'py> IntoPyObject<'py> for Box<{{ slot_name }}_range>
42
+ {
43
+ type Target = PyAny;
44
+ type Output = Bound<'py, Self::Target>;
45
+ type Error = PyErr;
46
+ fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
47
+ (*self).into_pyobject(py).map(move |x| x.into_any())
48
+ }
49
+ }
50
+
51
+ #[cfg(feature = "pyo3")]
52
+ impl<'py> FromPyObject<'py> for Box<{{ slot_name }}_range> {
53
+ fn extract_bound(ob: &pyo3::Bound<'py, pyo3::types::PyAny>) -> pyo3::PyResult<Self> {
54
+ if let Ok(val) = ob.extract::<{{ slot_name }}_range>() {
55
+ return Ok(Box::new(val));
56
+ }
57
+ Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
58
+ "invalid {{ slot_name }}",
59
+ ))
60
+ }
61
+ }
62
+
63
+ #[cfg(feature = "stubgen")]
64
+ ::pyo3_stub_gen::impl_stub_type!({{ slot_name }}_range = {{ ranges | join(' | ') }});
@@ -0,0 +1,81 @@
1
+ {% if special_case_enabled and name == 'Anything' %}
2
+ {% include 'anything.rs.jinja' %}
3
+ {% elif special_case_enabled and name == 'AnyValue' %}
4
+ pub type AnyValue = Anything;
5
+ {% else %}
6
+ {% if class_module %}
7
+ {{ class_module }}
8
+ {% endif %}
9
+ #[derive(Debug, Clone, PartialEq)]
10
+ #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11
+ {% if stubgen %}
12
+ #[cfg_attr(feature = "stubgen", gen_stub_pyclass)]
13
+ {% endif %}
14
+ #[cfg_attr(feature = "pyo3", pyclass(subclass, get_all, set_all))]
15
+ {% if generate_merge %}
16
+ #[derive(Merge)]
17
+ {% endif %}
18
+ pub struct {{ name }} {
19
+ {% for property in properties %}
20
+ {% filter indent(width=4, first=True, blank=False) %}
21
+ {{ property }}
22
+ {%- if not loop.last -%},{{ '\n' }}{% else %}{{ '\n' }}{%- endif -%}
23
+ {% endfilter %}
24
+ {% endfor %}
25
+ }
26
+ {% if properties | length > 0 %}
27
+ #[cfg(feature = "pyo3")]
28
+ {% if stubgen %}
29
+ #[cfg_attr(feature = "stubgen", gen_stub_pymethods)]
30
+ {% endif %}
31
+ #[pymethods]
32
+ impl {{ name }} {
33
+ #[new]
34
+ #[pyo3(signature = ({{ constructor_signature }}))]
35
+ pub fn new({% for (n, t) in property_names_and_types %}{{ n }}: {{ t }}{% if not loop.last %}, {% endif %}{% endfor %}) -> Self {
36
+ {% for name, expr in constructor_conversions %}
37
+ let {{ name }} = {{ expr }};
38
+ {% endfor %}
39
+ {{ name }}{{ "{" }}{% for (p, _) in property_names_and_types %}{{ p }}{% if not loop.last %}, {% endif %}{% endfor %}{{ "}" }}
40
+ }
41
+ }
42
+
43
+ #[cfg(feature = "pyo3")]
44
+ impl<'py> IntoPyObject<'py> for Box<{{ name }}>
45
+ {
46
+ type Target = PyAny;
47
+ type Output = Bound<'py, Self::Target>;
48
+ type Error = PyErr;
49
+ fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
50
+ (*self).into_pyobject(py).map(move |x| x.into_any())
51
+ }
52
+ }
53
+
54
+ #[cfg(feature = "pyo3")]
55
+ impl<'py> FromPyObject<'py> for Box<{{ name }}> {
56
+ fn extract_bound(ob: &pyo3::Bound<'py, pyo3::types::PyAny>) -> pyo3::PyResult<Self> {
57
+ if let Ok(val) = ob.extract::<{{ name }}>() {
58
+ return Ok(Box::new(val));
59
+ }
60
+ Err(PyErr::new::<pyo3::exceptions::PyTypeError, _>(
61
+ "invalid {{ name}}",
62
+ ))
63
+ }
64
+ }
65
+
66
+ {% if generate_merge %}
67
+ impl {{ name }} {
68
+ pub fn merge_with(&mut self, other: &{{ name }}) {
69
+ self.merge(other.clone())
70
+ }
71
+ }
72
+ {% endif %}
73
+
74
+ {% endif %}
75
+ {% if as_key_value %}
76
+ {{ as_key_value }}
77
+ {% endif %}
78
+ {% if struct_or_subtype_enum %}
79
+ {{ struct_or_subtype_enum }}
80
+ {% endif %}
81
+ {% endif %}