Files
Tommaso Fontana 0ad8e8c849 Pypeline: add pypeline.daemon
Add implementation of the generic pype daemon.
It's implementation is split into `daemon.py` where we implement an
http framework agnostic interface, and `app.py` that uses it to serve
them using starlette.
2025-11-11 17:15:28 +01:00

98 lines
2.8 KiB
Python

#
# This file is distributed under the MIT License. See LICENSE.md for details.
#
from typing import Any, Optional
from revng.pypeline.model import ReadOnlyModel
from revng.pypeline.object import Kind, ObjectID, ObjectSet
from revng.pypeline.pipeline import Pipeline
from revng.pypeline.storage.storage_provider import StorageProvider
from revng.pypeline.utils.registry import get_singleton
class DaemonException(Exception):
"""
An exception that a route can raise to do an early-exit with
some data and a status code.
"""
def __init__(self, status_code: int, data: Any):
self.code = status_code
self.data = data
Epoch = int
def compute_objects(
model: ReadOnlyModel,
kind: Kind,
objects: Optional[list[str]],
) -> ObjectSet:
"""
If objects is not None, deserialize all objects, otherwise return all the objects producible of
the given Kind.
"""
# If the user did not provide any objects for this container,
# we will use all objects of the given kind from the model.
if objects is None or len(objects) == 0:
return model.all_objects(kind)
# Otherwise we have to parse the objects provided by the user.
# Parse the objects into ObjectSet
objset = set()
for obj in objects:
if not isinstance(obj, str):
raise DaemonException(
400,
{
"msg": f'Object "{obj}" must be a string, got "{type(obj)}"',
},
)
# Deserialize the object ID
obj_type = get_singleton(ObjectID) # type: ignore [type-abstract]
try:
obj_id = obj_type.deserialize(obj)
except ValueError as e:
raise DaemonException(
400,
{
"msg": f'Invalid object ID "{obj}": {e}',
},
)
objset.add(obj_id)
return ObjectSet(kind, objset)
def compute_artifact(
storage_provider: StorageProvider,
pipeline: Pipeline,
model: ReadOnlyModel,
artifact_name: str,
artifact_data: dict,
) -> dict[str, Any]:
"""
Compute the requested artifact and return it in a HTTP compatible format.
"""
artifact_type = pipeline.artifacts[artifact_name]
artifact = pipeline.artifacts[artifact_name]
container = pipeline.get_artifact(
model=model,
artifact=artifact,
requests=compute_objects(
model=model,
kind=artifact_type.container.container_type.kind,
objects=artifact_data.get("objects"),
),
pipeline_configuration=artifact_data.get("configuration", {}),
storage_provider=storage_provider,
)
return {
"cacheable": artifact.is_cacheable(),
"objects": container.to_dict(),
}