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.
- linkml/cli/main.py +5 -1
- linkml/converter/__init__.py +0 -0
- linkml/generators/__init__.py +2 -0
- linkml/generators/common/build.py +5 -20
- linkml/generators/common/template.py +289 -3
- linkml/generators/docgen.py +55 -10
- linkml/generators/erdiagramgen.py +9 -5
- linkml/generators/graphqlgen.py +32 -6
- linkml/generators/jsonldcontextgen.py +78 -12
- linkml/generators/jsonschemagen.py +29 -12
- linkml/generators/mermaidclassdiagramgen.py +21 -3
- linkml/generators/owlgen.py +13 -2
- linkml/generators/panderagen/dataframe_class.py +13 -0
- linkml/generators/panderagen/dataframe_field.py +50 -0
- linkml/generators/panderagen/linkml_pandera_validator.py +186 -0
- linkml/generators/panderagen/panderagen.py +22 -5
- linkml/generators/panderagen/panderagen_class_based/class.jinja2 +70 -13
- linkml/generators/panderagen/panderagen_class_based/custom_checks.jinja2 +27 -0
- linkml/generators/panderagen/panderagen_class_based/enums.jinja2 +3 -3
- linkml/generators/panderagen/panderagen_class_based/pandera.jinja2 +12 -2
- linkml/generators/panderagen/panderagen_class_based/slots.jinja2 +19 -17
- linkml/generators/panderagen/slot_generator_mixin.py +143 -16
- linkml/generators/panderagen/transforms/__init__.py +19 -0
- linkml/generators/panderagen/transforms/collection_dict_model_transform.py +62 -0
- linkml/generators/panderagen/transforms/list_dict_model_transform.py +66 -0
- linkml/generators/panderagen/transforms/model_transform.py +8 -0
- linkml/generators/panderagen/transforms/nested_struct_model_transform.py +27 -0
- linkml/generators/panderagen/transforms/simple_dict_model_transform.py +86 -0
- linkml/generators/plantumlgen.py +17 -11
- linkml/generators/pydanticgen/pydanticgen.py +53 -2
- linkml/generators/pydanticgen/template.py +45 -233
- linkml/generators/pydanticgen/templates/attribute.py.jinja +1 -0
- linkml/generators/pydanticgen/templates/base_model.py.jinja +16 -2
- linkml/generators/pydanticgen/templates/imports.py.jinja +1 -1
- linkml/generators/rdfgen.py +11 -2
- linkml/generators/rustgen/__init__.py +3 -0
- linkml/generators/rustgen/build.py +97 -0
- linkml/generators/rustgen/cli.py +83 -0
- linkml/generators/rustgen/rustgen.py +1186 -0
- linkml/generators/rustgen/template.py +910 -0
- linkml/generators/rustgen/templates/Cargo.toml.jinja +42 -0
- linkml/generators/rustgen/templates/anything.rs.jinja +149 -0
- linkml/generators/rustgen/templates/as_key_value.rs.jinja +86 -0
- linkml/generators/rustgen/templates/class_module.rs.jinja +8 -0
- linkml/generators/rustgen/templates/enum.rs.jinja +70 -0
- linkml/generators/rustgen/templates/file.rs.jinja +75 -0
- linkml/generators/rustgen/templates/import.rs.jinja +4 -0
- linkml/generators/rustgen/templates/imports.rs.jinja +8 -0
- linkml/generators/rustgen/templates/lib_shim.rs.jinja +52 -0
- linkml/generators/rustgen/templates/poly.rs.jinja +9 -0
- linkml/generators/rustgen/templates/poly_containers.rs.jinja +439 -0
- linkml/generators/rustgen/templates/poly_trait.rs.jinja +15 -0
- linkml/generators/rustgen/templates/poly_trait_impl.rs.jinja +5 -0
- linkml/generators/rustgen/templates/poly_trait_impl_orsubtype.rs.jinja +5 -0
- linkml/generators/rustgen/templates/poly_trait_property.rs.jinja +8 -0
- linkml/generators/rustgen/templates/poly_trait_property_impl.rs.jinja +134 -0
- linkml/generators/rustgen/templates/poly_trait_property_match.rs.jinja +10 -0
- linkml/generators/rustgen/templates/property.rs.jinja +28 -0
- linkml/generators/rustgen/templates/pyproject.toml.jinja +10 -0
- linkml/generators/rustgen/templates/serde_utils.rs.jinja +490 -0
- linkml/generators/rustgen/templates/slot_range_as_union.rs.jinja +64 -0
- linkml/generators/rustgen/templates/struct.rs.jinja +81 -0
- linkml/generators/rustgen/templates/struct_or_subtype_enum.rs.jinja +111 -0
- linkml/generators/rustgen/templates/stub_gen.rs.jinja +71 -0
- linkml/generators/rustgen/templates/stub_utils.rs.jinja +76 -0
- linkml/generators/rustgen/templates/typealias.rs.jinja +13 -0
- linkml/generators/sqltablegen.py +18 -16
- linkml/generators/yarrrmlgen.py +173 -0
- linkml/linter/config/datamodel/config.py +160 -293
- linkml/linter/config/datamodel/config.yaml +34 -26
- linkml/linter/config/default.yaml +4 -0
- linkml/linter/config/recommended.yaml +4 -0
- linkml/linter/linter.py +1 -2
- linkml/linter/rules.py +37 -0
- linkml/utils/schema_builder.py +2 -0
- linkml/utils/schemaloader.py +55 -3
- {linkml-1.9.4rc2.dist-info → linkml-1.9.5rc2.dist-info}/METADATA +1 -1
- {linkml-1.9.4rc2.dist-info → linkml-1.9.5rc2.dist-info}/RECORD +82 -40
- {linkml-1.9.4rc2.dist-info → linkml-1.9.5rc2.dist-info}/entry_points.txt +2 -1
- linkml/generators/panderagen/panderagen_class_based/mixins.jinja2 +0 -26
- /linkml/{utils/converter.py → converter/cli.py} +0 -0
- {linkml-1.9.4rc2.dist-info → linkml-1.9.5rc2.dist-info}/WHEEL +0 -0
- {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 %}
|