def dagnode_from_json(input_json: Any) -> Union[DAGNode, RayServeHandle, Any]: """ Decode a DAGNode from given input json dictionary. JSON serialization is only used and enforced in ray serve from ray core API authored DAGNode(s). Covers both RayServeHandle and DAGNode types. Assumptions: - User object's JSON dict does not have keys that collide with our reserved DAGNODE_TYPE_KEY - RayServeHandle and Deployment can be re-constructed without losing states needed for their functionality or correctness. - DAGNode type can be re-constructed with new stable_uuid upon each deserialization without effective correctness of execution. - Only exception is ClassNode used as parent of ClassMethodNode that we perserve the same parent node. - .options() does not contain any DAGNode type """ node_type_to_cls = { # Ray DAG Inputs InputNode.__name__: InputNode, InputAttributeNode.__name__: InputAttributeNode, # Deployment graph execution nodes DeploymentExecutorNode.__name__: DeploymentExecutorNode, DeploymentMethodExecutorNode.__name__: DeploymentMethodExecutorNode, DeploymentFunctionExecutorNode.__name__: DeploymentFunctionExecutorNode, } # Deserialize RayServeHandle type if SERVE_HANDLE_JSON_KEY in input_json: return serve_handle_from_json_dict(input_json) # Base case for plain objects elif DAGNODE_TYPE_KEY not in input_json: return input_json elif input_json[DAGNODE_TYPE_KEY] == RayServeDAGHandle.__name__: return RayServeDAGHandle(input_json["dag_node_json"]) elif input_json[DAGNODE_TYPE_KEY] == "DeploymentSchema": return DeploymentSchema.parse_obj(input_json["schema"]) elif input_json[DAGNODE_TYPE_KEY] == RayServeLazySyncHandle.__name__: return RayServeLazySyncHandle( input_json["deployment_name"], HandleOptions(input_json["handle_options_method_name"]), ) # Deserialize DAGNode type elif input_json[DAGNODE_TYPE_KEY] in node_type_to_cls: return node_type_to_cls[input_json[DAGNODE_TYPE_KEY]].from_json( input_json) else: # Class and Function nodes require original module as body. module_name, attr_name = parse_import_path(input_json["import_path"]) module = getattr(import_module(module_name), attr_name) if input_json[DAGNODE_TYPE_KEY] == FunctionNode.__name__: return FunctionNode.from_json(input_json, module) elif input_json[DAGNODE_TYPE_KEY] == ClassNode.__name__: return ClassNode.from_json(input_json, module)
async def test_basic(self, serve_instance, sync): handle = get_handle(sync) assert await call(handle, "hi") == "hi" serialized = json.dumps(serve_handle_to_json_dict(handle)) # Check we can go through multiple rounds of serde. serialized = json.dumps(json.loads(serialized)) # Load the handle back from the dict. handle = serve_handle_from_json_dict(json.loads(serialized)) assert await call(handle, "hi") == "hi"
def test_invalid(self, serve_instance): with pytest.raises(ValueError): serve_handle_from_json_dict({"blah": 123})