Skip to content

Commit 5a517f1

Browse files
authored
Allow passing user when creating AiiDA data (#61)
Support creating an AiiDA node in a different thread.
1 parent b41717f commit 5a517f1

File tree

4 files changed

+20
-15
lines changed

4 files changed

+20
-15
lines changed

src/aiida_pythonjob/data/jsonable_data.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,19 +64,20 @@ def _extract_dict(self, obj: typing.Any) -> dict:
6464
f"Object `{obj}` does not have any of the following dictionary-conversion methods: {self._DICT_METHODS}"
6565
)
6666

67-
def _make_jsonable(self, data: typing.Any) -> typing.Any:
67+
@classmethod
68+
def _make_jsonable(cls, data: typing.Any) -> typing.Any:
6869
"""
6970
Recursively walk `data`. Convert anything that is not JSON-serializable
7071
into JSON-friendly structures (e.g. convert NumPy arrays to lists).
7172
"""
7273
if isinstance(data, dict):
73-
return {k: self._make_jsonable(v) for k, v in data.items()}
74+
return {k: cls._make_jsonable(v) for k, v in data.items()}
7475

7576
elif isinstance(data, list):
76-
return [self._make_jsonable(v) for v in data]
77+
return [cls._make_jsonable(v) for v in data]
7778

7879
elif isinstance(data, tuple):
79-
return tuple(self._make_jsonable(v) for v in data)
80+
return tuple(cls._make_jsonable(v) for v in data)
8081

8182
elif isinstance(data, np.ndarray):
8283
return data.tolist()

src/aiida_pythonjob/data/serializer.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ def general_serializer(
103103
data: Any,
104104
serializers: dict | None = None,
105105
store: bool = True,
106+
user: orm.User | None = None,
106107
) -> orm.Node:
107108
"""
108109
Attempt to serialize the data to an AiiDA data node based on the preference from `config`:
@@ -123,7 +124,7 @@ def general_serializer(
123124
if ep_key in serializers:
124125
try:
125126
serializer = import_from_path(serializers[ep_key])
126-
new_node = serializer(data)
127+
new_node = serializer(data, user=user)
127128
if store:
128129
new_node.store()
129130
return new_node
@@ -132,7 +133,7 @@ def general_serializer(
132133
raise ValueError(f"Error in serializing {ep_key}: {error_traceback}")
133134

134135
try:
135-
node = JsonableData(data)
136+
node = JsonableData(data, user=user)
136137
if store:
137138
node.store()
138139
return node

src/aiida_pythonjob/parsers/utils.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def parse_outputs(
3535
exit_codes,
3636
logger,
3737
serializers: Optional[Dict[str, str]] = None,
38+
user: Optional[orm.User] = None,
3839
) -> Tuple[Optional[Dict[str, Any]], Optional[ExitCode]]:
3940
"""Validate & convert *results* according to *output_spec*.
4041
@@ -58,7 +59,7 @@ def parse_outputs(
5859
for i, name in enumerate(names):
5960
child_spec = fields[name]
6061
val = results[i]
61-
outs[name] = serialize_ports(val, child_spec, serializers=serializers)
62+
outs[name] = serialize_ports(val, child_spec, serializers=serializers, user=user)
6263
return outs, None
6364

6465
# dict
@@ -83,19 +84,19 @@ def parse_outputs(
8384
((only_name, only_spec),) = fields.items()
8485
# if user used the same key as port name, use that value;
8586
if only_name in results:
86-
outs[only_name] = serialize_ports(results.pop(only_name), only_spec, serializers=serializers)
87+
outs[only_name] = serialize_ports(results.pop(only_name), only_spec, serializers=serializers, user=user)
8788
if results:
8889
logger.warning(f"Found extra results that are not included in the output: {list(results.keys())}")
8990
else:
9091
# else treat the entire dict as the value for that single port.
91-
outs[only_name] = serialize_ports(results, only_spec, serializers=serializers)
92+
outs[only_name] = serialize_ports(results, only_spec, serializers=serializers, user=user)
9293
return outs, None
9394

9495
# fixed fields
9596
for name, child_spec in fields.items():
9697
if name in remaining:
9798
value = remaining.pop(name)
98-
outs[name] = serialize_ports(value, child_spec, serializers=serializers)
99+
outs[name] = serialize_ports(value, child_spec, serializers=serializers, user=user)
99100
else:
100101
# If the field is explicitly required -> invalid output
101102
required = getattr(child_spec.meta, "required", None)
@@ -109,6 +110,7 @@ def parse_outputs(
109110
remaining,
110111
spec or SocketSpec(identifier="node_graph.any"),
111112
serializers=serializers,
113+
user=user,
112114
)
113115
)
114116
return outs, None
@@ -120,7 +122,7 @@ def parse_outputs(
120122
# single fixed output + non-dict/tuple scalar
121123
if len(fields) == 1 and not is_dyn:
122124
((only_name, only_spec),) = fields.items()
123-
return {only_name: serialize_ports(results, only_spec, serializers=serializers)}, None
125+
return {only_name: serialize_ports(results, only_spec, serializers=serializers, user=user)}, None
124126

125127
# empty output spec + None result
126128
if len(fields) == 0 and results is None:

src/aiida_pythonjob/utils.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@ def serialize_ports(
283283
python_data: Any,
284284
port_schema: SocketSpec | Dict[str, Any],
285285
serializers: Optional[Dict[str, str]] = None,
286+
user: Optional[User] = None,
286287
) -> Any:
287288
"""Serialize raw Python data to AiiDA Data following a SocketSpec schema.
288289
@@ -309,21 +310,21 @@ def serialize_ports(
309310
elif child_spec.is_namespace():
310311
out[key] = serialize_ports(value, child_spec, serializers=serializers)
311312
else:
312-
out[key] = general_serializer(value, serializers=serializers, store=False)
313+
out[key] = general_serializer(value, serializers=serializers, store=False, user=user)
313314
elif spec.meta.dynamic:
314315
if spec.item is None:
315316
if isinstance(value, dict):
316317
item = SocketSpec(identifier="node_graph.namespace", meta=SocketMeta(dynamic=True))
317318
out[key] = serialize_ports(value, item, serializers=serializers)
318319
else:
319-
out[key] = general_serializer(value, serializers=serializers, store=False)
320+
out[key] = general_serializer(value, serializers=serializers, store=False, user=user)
320321
elif spec.item.is_namespace():
321322
out[key] = serialize_ports(value, spec.item, serializers=serializers)
322323
else:
323-
out[key] = general_serializer(value, serializers=serializers, store=False)
324+
out[key] = general_serializer(value, serializers=serializers, store=False, user=user)
324325
else:
325326
raise ValueError(f"Unexpected key '{key}' for namespace '{name}' (not dynamic).")
326327
return out
327328

328329
# Leaf
329-
return general_serializer(python_data, serializers=serializers, store=False)
330+
return general_serializer(python_data, serializers=serializers, store=False, user=user)

0 commit comments

Comments
 (0)