Skip to content

Commit 1113e69

Browse files
committed
WIP: Enrich UserDefinedProcesses API
for Open-EO/openeo-aggregator#125 and related to #377
1 parent ca79053 commit 1113e69

File tree

2 files changed

+58
-31
lines changed

2 files changed

+58
-31
lines changed

openeo_driver/backend.py

+52
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,47 @@ def from_dict(cls, d: dict) -> 'UserDefinedProcessMetadata':
634634
def prepare_for_json(self) -> dict:
635635
return self._asdict() # pylint: disable=no-member
636636

637+
def to_api_dict(self, full=True, user: User = None) -> dict:
638+
"""API-version-aware conversion of UDP metadata to jsonable dict"""
639+
d = self.prepare_for_json()
640+
if not full:
641+
# API recommends to limit response size by omitting larger/optional fields
642+
d = {k: v for k, v in d.items() if k in ["id", "summary", "description", "parameters", "returns"]}
643+
elif self.public and user:
644+
namespace = "u:" + user.user_id
645+
d["links"] = (d.get("links") or []) + [
646+
{
647+
"rel": "canonical",
648+
# TODO: use signed url?
649+
"href": flask.url_for(
650+
".processes_details", namespace=namespace, process_id=self.id, _external=True
651+
),
652+
"title": f"Public URL for user-defined process {self.id!r}",
653+
}
654+
]
655+
elif "public" in d and not d["public"]:
656+
# Don't include non-standard "public" field when false to stay closer to standard API
657+
del d["public"]
658+
659+
return dict_no_none(**d)
660+
661+
662+
class UserDefinedProcessesListing:
663+
def __init__(self, udps: List[UserDefinedProcessMetadata]):
664+
self._udps = udps
665+
666+
def to_response_dict(self, build_url: Callable[[dict], str], api_version: ComparableVersion = None) -> dict:
667+
"""
668+
Produce `GET /process_graphs` response data, to be JSONified.
669+
670+
:param build_url: function to generate a paginated" URL from given pagination related parameters,
671+
e.g. `lambda params: flask.url_for(".list_jobs", **params, _external=True)`
672+
"""
673+
return {
674+
"processes": [udp.to_api_dict(full=False) for udp in self._udps],
675+
"links": [],
676+
}
677+
637678

638679
class UserDefinedProcesses(MicroService):
639680
"""
@@ -653,8 +694,19 @@ def get_for_user(self, user_id: str) -> List[UserDefinedProcessMetadata]:
653694
List user's UDPs
654695
https://openeo.org/documentation/1.0/developers/api/reference.html#operation/list-custom-processes
655696
"""
697+
# TODO remove this deprecated API when unused
656698
raise NotImplementedError
657699

700+
def list_for_user(
701+
self,
702+
user_id: str,
703+
# TODO: encapsulate limit and request_parameters in a pagination object?
704+
limit: Optional[int] = None,
705+
request_parameters: Optional[dict] = None,
706+
) -> UserDefinedProcessesListing:
707+
udps = self.get_for_user(user_id=user_id)
708+
...
709+
658710
def save(self, user_id: str, process_id: str, spec: dict) -> None:
659711
"""
660712
Store new UDP

openeo_driver/views.py

+6-31
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,7 @@ def processes_from_namespace(namespace):
761761
if namespace.startswith("u:") and backend_implementation.user_defined_processes:
762762
user_id = namespace.partition("u:")[-1]
763763
user_udps = [p for p in backend_implementation.user_defined_processes.get_for_user(user_id) if p.public]
764-
processes = [_jsonable_udp_metadata(udp, full=full, user=User(user_id=user_id)) for udp in user_udps]
764+
processes = [udp.to_api_dict(full=full, user=User(user_id=user_id)) for udp in user_udps]
765765
elif ":" not in namespace:
766766
process_registry = backend_implementation.processing.get_process_registry(
767767
api_version=requested_api_version()
@@ -796,7 +796,7 @@ def processes_details(namespace, process_id):
796796
udp = backend_implementation.user_defined_processes.get(user_id=user_id, process_id=process_id)
797797
if not udp:
798798
raise ProcessUnsupportedException(process=process_id, namespace=namespace)
799-
process = _jsonable_udp_metadata(udp, full=True, user=User(user_id=user_id))
799+
process = udp.to_api_dict(full=True, user=User(user_id=user_id))
800800
elif ":" not in namespace:
801801
process_registry = backend_implementation.processing.get_process_registry(
802802
api_version=requested_api_version()
@@ -1754,21 +1754,17 @@ def udp_get(process_graph_id: str, user: User):
17541754
_check_valid_process_graph_id(process_id=process_graph_id)
17551755
udp = backend_implementation.user_defined_processes.get(user_id=user.user_id, process_id=process_graph_id)
17561756
if udp:
1757-
return _jsonable_udp_metadata(udp, full=True , user=user)
1757+
return udp.to_api_dict(full=True, user=user)
17581758

17591759
raise ProcessGraphNotFoundException(process_graph_id)
17601760

17611761
@api_endpoint
17621762
@blueprint.route('/process_graphs', methods=['GET'])
17631763
@auth_handler.requires_bearer_auth
17641764
def udp_list_for_user(user: User):
1765-
user_udps = backend_implementation.user_defined_processes.get_for_user(user.user_id)
1766-
return {
1767-
'processes': [_jsonable_udp_metadata(udp, full=False) for udp in user_udps],
1768-
# TODO: pagination links?
1769-
# TODO: allow backend_implementation to define links?
1770-
"links": [],
1771-
}
1765+
# TODO #377 pagination support
1766+
udps = backend_implementation.user_defined_processes.list_for_user(user_id=user.user_id)
1767+
return jsonify(udps.to_response_dict())
17721768

17731769
@api_endpoint
17741770
@blueprint.route('/process_graphs/<process_graph_id>', methods=['DELETE'])
@@ -1779,27 +1775,6 @@ def udp_delete(process_graph_id: str, user: User):
17791775
return response_204_no_content()
17801776

17811777

1782-
def _jsonable_udp_metadata(metadata: UserDefinedProcessMetadata, full=True, user: User = None) -> dict:
1783-
"""API-version-aware conversion of UDP metadata to jsonable dict"""
1784-
d = metadata.prepare_for_json()
1785-
if not full:
1786-
# API recommends to limit response size by omitting larger/optional fields
1787-
d = {k: v for k, v in d.items() if k in ["id", "summary", "description", "parameters", "returns"]}
1788-
elif metadata.public and user:
1789-
namespace = "u:" + user.user_id
1790-
d["links"] = (d.get("links") or []) + [
1791-
{
1792-
"rel": "canonical",
1793-
# TODO: use signed url?
1794-
"href": url_for(".processes_details", namespace=namespace, process_id=metadata.id, _external=True),
1795-
"title": f"Public URL for user-defined process {metadata.id!r}"
1796-
}
1797-
]
1798-
elif "public" in d and not d["public"]:
1799-
# Don't include non-standard "public" field when false to stay closer to standard API
1800-
del d["public"]
1801-
1802-
return dict_no_none(**d)
18031778

18041779

18051780
def _normalize_collection_metadata(metadata: dict, api_version: ComparableVersion, full=False) -> dict:

0 commit comments

Comments
 (0)