oarepo-runtime 1.5.28__py3-none-any.whl → 1.5.30__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.
@@ -27,13 +27,15 @@ class LocalizedUIJSONSerializer(MarshmallowSerializer):
27
27
  self.object_schema_cls = object_schema_cls
28
28
  self.list_schema_cls = list_schema_cls
29
29
 
30
- def dump_obj(self, obj):
30
+ def dump_obj(self, obj, *args, **kwargs):
31
31
  """Dump the object using object schema class."""
32
- return self.object_schema_cls(
33
- context={**self.schema_context, "locale": get_locale()}
34
- ).dump(obj)
32
+ ctx = {**self.schema_context, "locale": get_locale()}
33
+ if "extra_context" in kwargs:
34
+ ctx |= kwargs["extra_context"]
35
35
 
36
- def dump_list(self, obj_list):
36
+ return self.object_schema_cls(context=ctx).dump(obj)
37
+
38
+ def dump_list(self, obj_list, *args, **kwargs):
37
39
  """Dump the list of objects."""
38
40
  ctx = {
39
41
  "object_schema_cls": self.object_schema_cls,
@@ -41,6 +43,9 @@ class LocalizedUIJSONSerializer(MarshmallowSerializer):
41
43
  ctx.update(self.schema_context)
42
44
  ctx["locale"] = get_locale()
43
45
 
46
+ if "extra_context" in kwargs:
47
+ ctx |= kwargs["extra_context"]
48
+
44
49
  if self.list_schema_cls is None:
45
50
  return self.object_schema_cls(context=self.schema_context).dump(
46
51
  obj_list, many=True
@@ -0,0 +1,192 @@
1
+ import typing
2
+
3
+ from marshmallow import Schema, ValidationError
4
+
5
+
6
+ class OneOfSchema(Schema):
7
+ """
8
+ This is a special kind of schema that actually multiplexes other schemas
9
+ based on object type. When serializing values, it uses get_obj_type() method
10
+ to get object type name. Then it uses `type_schemas` name-to-Schema mapping
11
+ to get schema for that particular object type, serializes object using that
12
+ schema and adds an extra "type" field with name of object type.
13
+ Deserialization is reverse.
14
+
15
+ Example:
16
+
17
+ class Foo(object):
18
+ def __init__(self, foo):
19
+ self.foo = foo
20
+
21
+ class Bar(object):
22
+ def __init__(self, bar):
23
+ self.bar = bar
24
+
25
+ class FooSchema(marshmallow.Schema):
26
+ foo = marshmallow.fields.String(required=True)
27
+
28
+ @marshmallow.post_load
29
+ def make_foo(self, data, **kwargs):
30
+ return Foo(**data)
31
+
32
+ class BarSchema(marshmallow.Schema):
33
+ bar = marshmallow.fields.Integer(required=True)
34
+
35
+ @marshmallow.post_load
36
+ def make_bar(self, data, **kwargs):
37
+ return Bar(**data)
38
+
39
+ class MyUberSchema(marshmallow.OneOfSchema):
40
+ type_schemas = {
41
+ 'foo': FooSchema,
42
+ 'bar': BarSchema,
43
+ }
44
+
45
+ def get_obj_type(self, obj):
46
+ if isinstance(obj, Foo):
47
+ return 'foo'
48
+ elif isinstance(obj, Bar):
49
+ return 'bar'
50
+ else:
51
+ raise Exception('Unknown object type: %s' % repr(obj))
52
+
53
+ MyUberSchema().dump([Foo(foo='hello'), Bar(bar=123)], many=True)
54
+ # => [{'type': 'foo', 'foo': 'hello'}, {'type': 'bar', 'bar': 123}]
55
+
56
+ You can control type field name added to serialized object representation by
57
+ setting `type_field` class property.
58
+ """
59
+
60
+ type_field = "type"
61
+ type_field_remove = True
62
+ type_schemas: typing.Mapping[str, typing.Union[typing.Type[Schema], Schema]] = {}
63
+
64
+ def get_obj_type(self, obj):
65
+ """Returns name of the schema during dump() calls, given the object
66
+ being dumped."""
67
+ return obj.__class__.__name__
68
+
69
+ def get_data_type(self, data):
70
+ """Returns name of the schema during load() calls, given the data being
71
+ loaded. Defaults to looking up `type_field` in the data."""
72
+ data_type = data.get(self.type_field)
73
+ if self.type_field in data and self.type_field_remove:
74
+ data.pop(self.type_field)
75
+ return data_type
76
+
77
+ def dump(self, obj, *, many=None, **kwargs):
78
+ errors = {}
79
+ result_data = []
80
+ result_errors = {}
81
+ many = self.many if many is None else bool(many)
82
+ if not many:
83
+ result = result_data = self._dump(obj, **kwargs)
84
+ else:
85
+ for idx, o in enumerate(obj):
86
+ try:
87
+ result = self._dump(o, **kwargs)
88
+ result_data.append(result)
89
+ except ValidationError as error:
90
+ result_errors[idx] = error.normalized_messages()
91
+ result_data.append(error.valid_data)
92
+
93
+ result = result_data
94
+ errors = result_errors
95
+
96
+ if not errors:
97
+ return result
98
+ else:
99
+ exc = ValidationError(errors, data=obj, valid_data=result)
100
+ raise exc
101
+
102
+ def _dump(self, obj, *, update_fields=True, **kwargs):
103
+ obj_type = self.get_obj_type(obj)
104
+ if obj_type is None:
105
+ return (
106
+ None,
107
+ {"_schema": "Unknown object class: %s" % obj.__class__.__name__},
108
+ )
109
+
110
+ type_schema = self.type_schemas.get(obj_type)
111
+ if not type_schema:
112
+ return None, {"_schema": "Unsupported object type: %s" % obj_type}
113
+
114
+ schema = type_schema if isinstance(type_schema, Schema) else type_schema()
115
+
116
+ schema.context.update(getattr(self, "context", {}))
117
+
118
+ result = schema.dump(obj, many=False, **kwargs)
119
+ if result is not None:
120
+ result[self.type_field] = obj_type
121
+ return result
122
+
123
+ def load(self, data, *, many=None, partial=None, unknown=None, **kwargs):
124
+ errors = {}
125
+ result_data = []
126
+ result_errors = {}
127
+ many = self.many if many is None else bool(many)
128
+ if partial is None:
129
+ partial = self.partial
130
+ if not many:
131
+ try:
132
+ result_data = self._load(
133
+ data, partial=partial, unknown=unknown, **kwargs
134
+ )
135
+ except ValidationError as error:
136
+ result_errors = error.normalized_messages()
137
+ result_data = error.valid_data
138
+ else:
139
+ for idx, item in enumerate(data):
140
+ try:
141
+ result = self._load(item, partial=partial, **kwargs)
142
+ result_data.append(result)
143
+ except ValidationError as error:
144
+ result_errors[idx] = error.normalized_messages()
145
+ result_data.append(error.valid_data)
146
+
147
+ result = result_data
148
+ errors = result_errors
149
+
150
+ if not errors:
151
+ return result
152
+ else:
153
+ exc = ValidationError(errors, data=data, valid_data=result)
154
+ raise exc
155
+
156
+ def _load(self, data, *, partial=None, unknown=None, **kwargs):
157
+ if not isinstance(data, dict):
158
+ raise ValidationError({"_schema": "Invalid data type: %s" % data})
159
+
160
+ data = dict(data)
161
+ unknown = unknown or self.unknown
162
+ data_type = self.get_data_type(data)
163
+
164
+ if data_type is None:
165
+ raise ValidationError(
166
+ {self.type_field: ["Missing data for required field."]}
167
+ )
168
+
169
+ try:
170
+ type_schema = self.type_schemas.get(data_type)
171
+ except TypeError as error:
172
+ # data_type could be unhashable
173
+ raise ValidationError(
174
+ {self.type_field: ["Invalid value: %s" % data_type]}
175
+ ) from error
176
+ if not type_schema:
177
+ raise ValidationError(
178
+ {self.type_field: ["Unsupported value: %s" % data_type]}
179
+ )
180
+
181
+ schema = type_schema if isinstance(type_schema, Schema) else type_schema()
182
+
183
+ schema.context.update(getattr(self, "context", {}))
184
+
185
+ return schema.load(data, many=False, partial=partial, unknown=unknown, **kwargs)
186
+
187
+ def validate(self, data, *, many=None, partial=None):
188
+ try:
189
+ self.load(data, many=many, partial=partial)
190
+ except ValidationError as ve:
191
+ return ve.messages
192
+ return {}
@@ -1,8 +1,8 @@
1
1
  from functools import cached_property
2
2
 
3
3
  import marshmallow as ma
4
- from marshmallow_oneofschema import OneOfSchema
5
-
4
+ #from marshmallow_oneofschema import OneOfSchema
5
+ from oarepo_runtime.services.schema.oneofschema import OneOfSchema
6
6
 
7
7
  class PolymorphicSchema(OneOfSchema):
8
8
  type_field_remove = False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: oarepo-runtime
3
- Version: 1.5.28
3
+ Version: 1.5.30
4
4
  Summary: A set of runtime extensions of Invenio repository
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE
@@ -66,7 +66,7 @@ oarepo_runtime/records/systemfields/selectors.py,sha256=VlbV3FKP2h3PLU7H4-YsI4qr
66
66
  oarepo_runtime/records/systemfields/synthetic.py,sha256=zRsQdekcgsrD9R2UuI2kgVLjyQMIT8j3HAYav_e-xfM,4238
67
67
  oarepo_runtime/resources/__init__.py,sha256=v8BGrOTu_FjKzd0eozV7Q4GoGxyfybsL2cI-tbP5Pys,185
68
68
  oarepo_runtime/resources/file_resource.py,sha256=Ta3bFce7l0xwqkkOMOEu9mxbB8BbKj5HUHRHmidhnl8,414
69
- oarepo_runtime/resources/localized_ui_json_serializer.py,sha256=4Kle34k-_uu3Y9JJ2vAXcQ9DqYRxXgy-_iZhiFuukmE,1684
69
+ oarepo_runtime/resources/localized_ui_json_serializer.py,sha256=3V9cJaG_e1PMXKVX_wKfBp1LmbeForwHyBNYdyha4uQ,1878
70
70
  oarepo_runtime/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
71
  oarepo_runtime/services/components.py,sha256=9wt9CmoCFA8Utbb8eNA-Mvzo5LCApHT9zHpWIWZNyXY,1506
72
72
  oarepo_runtime/services/generators.py,sha256=V582uA813AIXnFhzqUwakmDgBOI1SQe3XZeJtUXNbwM,872
@@ -100,7 +100,8 @@ oarepo_runtime/services/schema/i18n.py,sha256=myyg0tU8up0BmMt9IESKD91w5KC0V9v8Qa
100
100
  oarepo_runtime/services/schema/i18n_ui.py,sha256=18tA6uA067TP_wcit47hTel2M4hz88wYtwBgaeZDrew,1880
101
101
  oarepo_runtime/services/schema/i18n_validation.py,sha256=fyMTi2Rw-KiHv7c7HN61zGxRVa9sAjAEEkAL5wUyKNo,236
102
102
  oarepo_runtime/services/schema/marshmallow.py,sha256=LmcSxvbZ9jIhkNHCqqxt1SA2UNijoDmIzqli1MkoTrE,1153
103
- oarepo_runtime/services/schema/polymorphic.py,sha256=CkvXVUiXbrsLWFgoNnjjpUviQyzRMCmpsD3GWfV0WZA,494
103
+ oarepo_runtime/services/schema/oneofschema.py,sha256=X_pXzrkYcLGGAtGN1qltrz45OzD_atrJHkHkp3L01xg,6660
104
+ oarepo_runtime/services/schema/polymorphic.py,sha256=f9yC7MGVynAFGM0fXIq0NbqGJxI65Xpi8GaM2ZM4c6Q,561
104
105
  oarepo_runtime/services/schema/ui.py,sha256=caRca4vuUVoLew3gkhbPQYGaLXB8C67E5jxz45-9zkE,3663
105
106
  oarepo_runtime/services/schema/validation.py,sha256=fahqKGDdIYWux5ZeoljrEe8VD2fDZR9VpfvYmTYAmpw,1050
106
107
  oarepo_runtime/translations/default_translations.py,sha256=060GBlA1ghWxfeumo6NqxCCZDb-6OezOuF6pr-_GEOQ,104
@@ -114,9 +115,9 @@ oarepo_runtime/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hS
114
115
  oarepo_runtime/utils/functools.py,sha256=gKS9YZtlIYcDvdNA9cmYO00yjiXBYV1jg8VpcRUyQyg,1324
115
116
  oarepo_runtime/utils/path.py,sha256=V1NVyk3m12_YLbj7QHYvUpE1wScO78bYsX1LOLeXDkI,3108
116
117
  tests/pkg_data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
117
- oarepo_runtime-1.5.28.dist-info/LICENSE,sha256=h2uWz0OaB3EN-J1ImdGJZzc7yvfQjvHVYdUhQ-H7ypY,1064
118
- oarepo_runtime-1.5.28.dist-info/METADATA,sha256=ck-L-b49r3ffcCAjvGjsUxW173E2ay8T_-sx7q1LYkY,4680
119
- oarepo_runtime-1.5.28.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
120
- oarepo_runtime-1.5.28.dist-info/entry_points.txt,sha256=QrlXAKuPDVBinaSh_v3yO9_Nb9ZNmJCJ0VFcCW-z0Jg,327
121
- oarepo_runtime-1.5.28.dist-info/top_level.txt,sha256=bHhlkT1_RQC4IkfTQCqA3iN4KCB6cSFQlsXpQMSP-bE,21
122
- oarepo_runtime-1.5.28.dist-info/RECORD,,
118
+ oarepo_runtime-1.5.30.dist-info/LICENSE,sha256=h2uWz0OaB3EN-J1ImdGJZzc7yvfQjvHVYdUhQ-H7ypY,1064
119
+ oarepo_runtime-1.5.30.dist-info/METADATA,sha256=-RxYSie_VM-QdwV_3we-zToS-EeWEmGaYgG4HYVaOvw,4680
120
+ oarepo_runtime-1.5.30.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
121
+ oarepo_runtime-1.5.30.dist-info/entry_points.txt,sha256=QrlXAKuPDVBinaSh_v3yO9_Nb9ZNmJCJ0VFcCW-z0Jg,327
122
+ oarepo_runtime-1.5.30.dist-info/top_level.txt,sha256=bHhlkT1_RQC4IkfTQCqA3iN4KCB6cSFQlsXpQMSP-bE,21
123
+ oarepo_runtime-1.5.30.dist-info/RECORD,,