|
10 | 10 |
|
11 | 11 | class LINK_REL:
|
12 | 12 | UDP = "openeo-process"
|
| 13 | + SERVICE = "service" |
13 | 14 |
|
14 | 15 |
|
15 | 16 | def _load_json_resource(src: Union[dict, str, Path]) -> dict:
|
@@ -61,13 +62,36 @@ def from_link_object(cls, data: dict) -> UdpLink:
|
61 | 62 | title=data.get("title"),
|
62 | 63 | )
|
63 | 64 |
|
| 65 | +@dataclasses.dataclass(frozen=True) |
| 66 | +class ServiceLink: |
| 67 | + href: str |
| 68 | + title: Optional[str] = None |
| 69 | + |
| 70 | + @classmethod |
| 71 | + def from_link_object(cls, data: dict) -> ServiceLink: |
| 72 | + """Parse a link object (dict/mapping) into a UdpLink object.""" |
| 73 | + if "rel" not in data: |
| 74 | + raise InvalidMetadataError("Missing 'rel' attribute in link object") |
| 75 | + if data["rel"] != LINK_REL.SERVICE: |
| 76 | + raise InvalidMetadataError(f"Expected link with rel='{LINK_REL.SERVICE}' but got {data['rel']!r}") |
| 77 | + if "href" not in data: |
| 78 | + raise InvalidMetadataError("Missing 'href' attribute in link object") |
| 79 | + return cls( |
| 80 | + href=data["href"], |
| 81 | + title=data.get("title"), |
| 82 | + ) |
| 83 | + |
| 84 | + def __str__(self): |
| 85 | + return self.title or self.href |
| 86 | + |
64 | 87 |
|
65 | 88 | @dataclasses.dataclass(frozen=True)
|
66 | 89 | class Algorithm:
|
67 | 90 | id: str
|
68 | 91 | title: Optional[str] = None
|
69 | 92 | description: Optional[str] = None
|
70 | 93 | udp_link: Optional[UdpLink] = None
|
| 94 | + service_links: List[ServiceLink] = None |
71 | 95 | license: Optional[str] = None
|
72 | 96 | organization: Optional[str] = None
|
73 | 97 | # TODO more fields
|
@@ -95,19 +119,25 @@ def from_ogc_api_record(cls, src: Union[dict, str, Path]) -> Algorithm:
|
95 | 119 | udp_links = [UdpLink.from_link_object(link) for link in links if link.get("rel") == LINK_REL.UDP]
|
96 | 120 | if len(udp_links) > 1:
|
97 | 121 | raise InvalidMetadataError("Multiple UDP links found")
|
98 |
| - # TODO: is having a UDP link a requirement? |
| 122 | + # TODO: is having a UDP link a requirement? => No, it can also be an application package |
99 | 123 | udp_link = udp_links[0] if udp_links else None
|
100 | 124 |
|
| 125 | + service_links = [ServiceLink.from_link_object(link) for link in links if link.get("rel") == LINK_REL.SERVICE] |
| 126 | + if len(udp_links) == 0: |
| 127 | + raise InvalidMetadataError("No service links found, the algorithm requires at least one valid service that is known to execute it.") |
| 128 | + |
| 129 | + |
| 130 | + |
101 | 131 | pis = [ c for c in properties.get("contacts",[]) if "principal investigator" in c.get("roles",[]) ]
|
102 | 132 | pi_org = pis[0].get("organization", None) if pis else None
|
103 | 133 |
|
104 | 134 | service_license = data.get("license",None)
|
105 |
| - |
106 | 135 | return cls(
|
107 | 136 | id=data["id"],
|
108 | 137 | title=properties.get("title"),
|
109 | 138 | description=properties.get("description"),
|
110 | 139 | udp_link=udp_link,
|
| 140 | + service_links=service_links, |
111 | 141 | license=service_license,
|
112 | 142 | organization = pi_org
|
113 | 143 | )
|
|
0 commit comments