Skip to content
This repository was archived by the owner on Aug 20, 2025. It is now read-only.

Commit f959091

Browse files
committed
add service links
1 parent d9189f5 commit f959091

File tree

1 file changed

+32
-2
lines changed

1 file changed

+32
-2
lines changed

src/esa_apex_toolbox/algorithms.py

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
class LINK_REL:
1212
UDP = "openeo-process"
13+
SERVICE = "service"
1314

1415

1516
def _load_json_resource(src: Union[dict, str, Path]) -> dict:
@@ -61,13 +62,36 @@ def from_link_object(cls, data: dict) -> UdpLink:
6162
title=data.get("title"),
6263
)
6364

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+
6487

6588
@dataclasses.dataclass(frozen=True)
6689
class Algorithm:
6790
id: str
6891
title: Optional[str] = None
6992
description: Optional[str] = None
7093
udp_link: Optional[UdpLink] = None
94+
service_links: List[ServiceLink] = None
7195
license: Optional[str] = None
7296
organization: Optional[str] = None
7397
# TODO more fields
@@ -95,19 +119,25 @@ def from_ogc_api_record(cls, src: Union[dict, str, Path]) -> Algorithm:
95119
udp_links = [UdpLink.from_link_object(link) for link in links if link.get("rel") == LINK_REL.UDP]
96120
if len(udp_links) > 1:
97121
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
99123
udp_link = udp_links[0] if udp_links else None
100124

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+
101131
pis = [ c for c in properties.get("contacts",[]) if "principal investigator" in c.get("roles",[]) ]
102132
pi_org = pis[0].get("organization", None) if pis else None
103133

104134
service_license = data.get("license",None)
105-
106135
return cls(
107136
id=data["id"],
108137
title=properties.get("title"),
109138
description=properties.get("description"),
110139
udp_link=udp_link,
140+
service_links=service_links,
111141
license=service_license,
112142
organization = pi_org
113143
)

0 commit comments

Comments
 (0)