def test_deploy_from_yaml(self, serve_instance): config_file_name = os.path.join( os.path.dirname(__file__), "test_config_files", "two_deployments.yaml" ) # Check if yaml string and yaml file both produce the same Application with open(config_file_name, "r") as f: app1 = Application.from_yaml(f) with open(config_file_name, "r") as f: yaml_str = f.read() app2 = Application.from_yaml(yaml_str) compare_specified_options(app1.to_dict(), app2.to_dict()) # Check that deployment works app1.deploy() assert ( requests.get("http://localhost:8000/shallow").text == "Hello shallow world!" ) assert requests.get("http://localhost:8000/one").text == "2" # Check if yaml string output is same as the Application recreated_app = Application.from_yaml(app1.to_yaml()) compare_specified_options(recreated_app.to_dict(), app1.to_dict()) # Check if yaml file output is same as the Application with tempfile.TemporaryFile(mode="w+") as tmp: app1.to_yaml(tmp) tmp.seek(0) compare_specified_options( Application.from_yaml(tmp).to_dict(), app1.to_dict() )
def test_get_set_item(serve_instance): config_file_name = os.path.join( os.path.dirname(__file__), "test_config_files", "two_deployments.yaml" ) with open(config_file_name, "r") as f: app = Application.from_yaml(f) app["shallow"].deploy() app["one"].deploy() assert requests.get("http://localhost:8000/shallow").text == "Hello shallow world!" assert requests.get("http://localhost:8000/one").text == "2"
def test_convert_to_import_path(self, serve_instance): f = decorated_func.options(name="f") C = DecoratedClass.options(name="C") app = Application([f, C]) reconstructed_app = Application.from_yaml(app.to_yaml()) serve.run(reconstructed_app) assert requests.get( "http://localhost:8000/f").text == "got decorated func" assert requests.get( "http://localhost:8000/C").text == "got decorated class"
def run( config_or_import_path: str, runtime_env: str, runtime_env_json: str, working_dir: str, app_dir: str, address: str, host: str, port: int, blocking: bool, ): sys.path.insert(0, app_dir) final_runtime_env = parse_runtime_env_args( runtime_env=runtime_env, runtime_env_json=runtime_env_json, working_dir=working_dir, ) app_or_node = None if pathlib.Path(config_or_import_path).is_file(): config_path = config_or_import_path cli_logger.print(f"Deploying from config file: '{config_path}'.") with open(config_path, "r") as config_file: app_or_node = Application.from_yaml(config_file) else: import_path = config_or_import_path cli_logger.print(f"Deploying from import path: '{import_path}'.") app_or_node = import_attr(import_path) # Setting the runtime_env here will set defaults for the deployments. ray.init(address=address, namespace="serve", runtime_env=final_runtime_env) try: serve.run(app_or_node, host=host, port=port) cli_logger.success("Deployed successfully.") if blocking: while True: # Block, letting Ray print logs to the terminal. time.sleep(10) except KeyboardInterrupt: cli_logger.info("Got KeyboardInterrupt, shutting down...") serve.shutdown() sys.exit()
def test_immutable_deployment_list(serve_instance): config_file_name = os.path.join(os.path.dirname(__file__), "test_config_files", "two_deployments.yaml") with open(config_file_name, "r") as f: app = Application.from_yaml(f) assert len(app.deployments.values()) == 2 for name in app.deployments.keys(): with pytest.raises(RuntimeError): app.deployments[name] = app.deployments[name].options( name="sneaky") for deployment in app.deployments.values(): deployment.deploy() assert requests.get( "http://localhost:8000/shallow").text == "Hello shallow world!" assert requests.get("http://localhost:8000/one").text == "2"
def run( config_or_import_path: str, args_and_kwargs: Tuple[str], runtime_env: str, runtime_env_json: str, working_dir: str, address: str, ): # Check if path provided is for config or import is_config = pathlib.Path(config_or_import_path).is_file() args, kwargs = _process_args_and_kwargs(args_and_kwargs) # Calculate deployments' runtime env updates requested via args runtime_env_updates = parse_runtime_env_args( runtime_env=runtime_env, runtime_env_json=runtime_env_json, working_dir=working_dir, ) # Create ray.init()'s runtime_env if "working_dir" in runtime_env_updates: ray_runtime_env = { "working_dir": runtime_env_updates.pop("working_dir") } else: ray_runtime_env = {} if is_config: config_path = config_or_import_path # Delay serve.start() to catch invalid inputs without waiting if len(args) + len(kwargs) > 0: raise ValueError( "ARGS_AND_KWARGS cannot be defined for a " "config file deployment. Please specify the " "init_args and init_kwargs inside the config file.") cli_logger.print("Deploying application in config file at " f"{config_path}.") with open(config_path, "r") as config_file: app = Application.from_yaml(config_file) else: import_path = config_or_import_path if "." not in import_path: raise ValueError( "Import paths must be of the form " '"module.submodule_1...submodule_n.MyClassOrFunction".') cli_logger.print( f'Deploying function or class imported from "{import_path}".') deployment_name = import_path[import_path.rfind(".") + 1:] deployment = serve.deployment(name=deployment_name)(import_path) app = Application( [deployment.options(init_args=args, init_kwargs=kwargs)]) ray.init(address=address, namespace="serve", runtime_env=ray_runtime_env) for deployment in app: _configure_runtime_env(deployment, runtime_env_updates) app.run(logger=cli_logger)