python-re3data-v2 0.1.0__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.
re3data/_serializer.py ADDED
@@ -0,0 +1,82 @@
1
+ """Serialize parsed re3data resources into dict, JSON and CSV representations.
2
+
3
+ Dict conventions (matching the contract established by the original
4
+ python-re3data library):
5
+
6
+ - Keys are the XML element/attribute names (camelCase).
7
+ - Elements with text and attributes become ``{"value": ..., "language": ...}``.
8
+ - Dates are rendered as ISO-8601 strings (``2023-12-06``).
9
+ - Absent optional scalars are ``None``; absent repeats are empty lists.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import csv
15
+ import io
16
+ import json
17
+ from dataclasses import asdict, is_dataclass
18
+ from datetime import date
19
+ from typing import TYPE_CHECKING, Any
20
+
21
+ from re3data._resources import RepositorySummary
22
+
23
+ if TYPE_CHECKING:
24
+ from re3data._resources import Repository
25
+
26
+
27
+ def _normalize(node: Any) -> Any:
28
+ """Recursively convert non-JSON-native leaves into JSON-native ones."""
29
+ if isinstance(node, date):
30
+ return node.isoformat()
31
+ if is_dataclass(node):
32
+ return {key: _normalize(value) for key, value in asdict(node).items()}
33
+ if isinstance(node, dict):
34
+ return {key: _normalize(value) for key, value in node.items()}
35
+ if isinstance(node, (list, tuple)):
36
+ return [_normalize(item) for item in node]
37
+ return node
38
+
39
+
40
+ def _to_dict(parsed: Repository | list[RepositorySummary]) -> dict[str, Any] | list[dict[str, Any]]:
41
+ """Serialize a parsed resource into a dictionary."""
42
+ return _normalize(parsed)
43
+
44
+
45
+ def _to_json(parsed: Repository | list[RepositorySummary]) -> str:
46
+ """Serialize a parsed resource into a JSON string."""
47
+ return json.dumps(_normalize(parsed), indent=2, ensure_ascii=False)
48
+
49
+
50
+ def _repository_summary_row(summary: RepositorySummary) -> dict[str, Any]:
51
+ return {
52
+ "id": summary.id,
53
+ "doi": summary.doi,
54
+ "name": summary.name,
55
+ "href": summary.href,
56
+ }
57
+
58
+
59
+ def _to_csv(parsed: Repository | list[RepositorySummary]) -> str:
60
+ """Serialize repository summaries into a CSV string.
61
+
62
+ Only list responses produce tabular output; a single repository detail is
63
+ rendered as one summary row.
64
+ """
65
+ summaries: list[RepositorySummary]
66
+ if isinstance(parsed, list):
67
+ summaries = parsed
68
+ else:
69
+ summaries = [
70
+ RepositorySummary(
71
+ id=parsed.id,
72
+ doi=parsed.identifiers.doi if parsed.identifiers else None,
73
+ name=parsed.repositoryName.value if parsed.repositoryName else None,
74
+ link=None,
75
+ )
76
+ ]
77
+ buffer = io.StringIO()
78
+ writer = csv.DictWriter(buffer, fieldnames=["id", "doi", "name", "href"], lineterminator="\n")
79
+ writer.writeheader()
80
+ for summary in summaries:
81
+ writer.writerow(_repository_summary_row(summary))
82
+ return buffer.getvalue().rstrip("\n")