import math import graphene from graphql import ( DirectiveLocation, GraphQLArgument, GraphQLDirective, GraphQLNonNull, GraphQLString, ) import mlflow from mlflow.server.graphql.autogenerated_graphql_schema import ( MlflowExperiment, MlflowMetric, MlflowModelVersion, MlflowRun, MlflowSearchRunsInput, MlflowSearchRunsResponse, MutationType, QueryType, ) from mlflow.utils.proto_json_utils import parse_dict # Component identifier, to keep compatible with Databricks in-house implementations. ComponentDirective = GraphQLDirective( name="component", locations=[ DirectiveLocation.QUERY, DirectiveLocation.MUTATION, ], args={"name": GraphQLArgument(GraphQLNonNull(GraphQLString))}, ) class Test(graphene.ObjectType): output = graphene.String(description="Echoes the input string") class TestMutation(graphene.ObjectType): output = graphene.String(description="Echoes the input string") class MlflowRunExtension(MlflowRun): experiment = graphene.Field(MlflowExperiment) model_versions = graphene.List(graphene.NonNull(MlflowModelVersion)) def resolve_experiment(self, info): experiment_id = self.info.experiment_id input_dict = {"experiment_id": experiment_id} request_message = mlflow.protos.service_pb2.GetExperiment() parse_dict(input_dict, request_message) return mlflow.server.handlers.get_experiment_impl(request_message).experiment def resolve_model_versions(self, info): run_id = self.info.run_id input_dict = {"filter": f"run_id='{run_id}'"} request_message = mlflow.protos.model_registry_pb2.SearchModelVersions() parse_dict(input_dict, request_message) return mlflow.server.handlers.search_model_versions_impl(request_message).model_versions class MlflowMetricExtension(MlflowMetric): value = graphene.Float() # metric values that are NaN will cause an error in graphQL validation as # the type is Float. as a workaround, we return None if the value is NaN. def resolve_value(self, info): return None if math.isnan(self.value) else self.value class Query(QueryType): test = graphene.Field(Test, input_string=graphene.String(), description="Simple echoing field") mlflow_search_runs = graphene.Field(MlflowSearchRunsResponse, input=MlflowSearchRunsInput()) def resolve_test(self, info, input_string): return {"output": input_string} def resolve_mlflow_search_runs(self, info, input): input_dict = vars(input) request_message = mlflow.protos.service_pb2.SearchRuns() parse_dict(input_dict, request_message) return mlflow.server.handlers.search_runs_impl(request_message) class Mutation(MutationType): testMutation = graphene.Field( TestMutation, input_string=graphene.String(), description="Simple echoing field" ) def resolve_test_mutation(self, info, input_string): return {"output": input_string} schema = graphene.Schema(query=Query, mutation=Mutation, directives=[ComponentDirective])