From e6ef8b7482c91b1d92d4db2d4280110175b95587 Mon Sep 17 00:00:00 2001 From: David Kegley Date: Tue, 1 Aug 2023 14:41:02 -0400 Subject: [PATCH 01/10] Add --no-env-restore-py and --no-env-restore-r flags for all manfest-writing functions --- rsconnect/actions.py | 88 +++++++++++++++++++++++-- rsconnect/bundle.py | 151 ++++++++++++++++++++++++++++++++++++------- rsconnect/main.py | 124 +++++++++++++++++++++-------------- 3 files changed, 284 insertions(+), 79 deletions(-) diff --git a/rsconnect/actions.py b/rsconnect/actions.py index ac6a941e..81359f05 100644 --- a/rsconnect/actions.py +++ b/rsconnect/actions.py @@ -527,6 +527,8 @@ def write_quarto_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Quarto project. @@ -538,6 +540,8 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) @@ -549,6 +553,8 @@ def write_quarto_manifest_json( extra_files, excludes, image, + no_env_restore_py, + no_env_restore_r, ) base_dir = file_or_directory @@ -624,6 +630,8 @@ def deploy_jupyter_notebook( hide_all_input: bool, hide_tagged_input: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> None: """ A function to deploy a Jupyter notebook to Connect. Depending on the files involved @@ -651,6 +659,8 @@ def deploy_jupyter_notebook( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -699,6 +709,8 @@ def deploy_jupyter_notebook( hide_all_input, hide_tagged_input, image=image, + no_env_restore_py=no_env_restore_py, + no_env_restore_r=no_env_restore_r, ) else: ce.make_bundle( @@ -709,6 +721,8 @@ def deploy_jupyter_notebook( hide_all_input, hide_tagged_input, image=image, + no_env_restore_py=no_env_restore_py, + no_env_restore_r=no_env_restore_r, ) ce.deploy_bundle().save_deployed_info().emit_task_log() @@ -747,6 +761,8 @@ def deploy_app( extra_files: typing.List[str] = None, env_vars: typing.Dict[str, str] = None, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, account: str = None, token: str = None, secret: str = None, @@ -798,6 +814,8 @@ def deploy_app( extra_files, excludes, image=image, + no_env_restore_py=no_env_restore_py, + no_env_restore_r=no_env_restore_r, ) .deploy_bundle() .save_deployed_info() @@ -819,6 +837,8 @@ def deploy_python_api( force_generate: bool, log_callback: typing.Callable, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python WSGi API module to Connect. Depending on the files involved @@ -843,6 +863,8 @@ def deploy_python_api( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -863,6 +885,8 @@ def deploy_python_fastapi( force_generate: bool, log_callback: typing.Callable, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python ASGI API module to Posit Connect. Depending on the files involved @@ -887,6 +911,8 @@ def deploy_python_fastapi( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -949,6 +975,8 @@ def deploy_dash_app( force_generate: bool, log_callback: typing.Callable, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Dash app module to Connect. Depending on the files involved @@ -973,6 +1001,8 @@ def deploy_dash_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -993,6 +1023,8 @@ def deploy_streamlit_app( force_generate: bool, log_callback: typing.Callable, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Streamlit app module to Connect. Depending on the files involved @@ -1017,6 +1049,8 @@ def deploy_streamlit_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1037,6 +1071,8 @@ def deploy_bokeh_app( force_generate: bool, log_callback: typing.Callable, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Bokeh app module to Connect. Depending on the files involved @@ -1061,6 +1097,8 @@ def deploy_bokeh_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1144,6 +1182,8 @@ def create_notebook_deployment_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1161,6 +1201,8 @@ def create_notebook_deployment_bundle( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the bundle. """ @@ -1177,6 +1219,8 @@ def create_notebook_deployment_bundle( hide_all_input, hide_tagged_input, image=image, + no_env_restore_py=no_env_restore_py, + no_env_restore_r=no_env_restore_r, ) except subprocess.CalledProcessError as exc: # Jupyter rendering failures are often due to @@ -1190,6 +1234,8 @@ def create_notebook_deployment_bundle( hide_all_input, hide_tagged_input, image=image, + no_env_restore_py=no_env_restore_py, + no_env_restore_r=no_env_restore_r, ) @@ -1202,6 +1248,8 @@ def create_api_deployment_bundle( environment: Environment, extra_files_need_validating: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1217,6 +1265,8 @@ def create_api_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the bundle. """ entry_point = validate_entry_point(entry_point, directory) @@ -1227,7 +1277,8 @@ def create_api_deployment_bundle( if app_mode is None: app_mode = AppModes.PYTHON_API - return make_api_bundle(directory, entry_point, app_mode, environment, extra_files, excludes, image) + return make_api_bundle(directory, entry_point, app_mode, environment, extra_files, excludes, + image, no_env_restore_py, no_env_restore_r) def create_quarto_deployment_bundle( @@ -1238,6 +1289,8 @@ def create_quarto_deployment_bundle( inspect: typing.Dict[str, typing.Any], environment: Environment, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1253,12 +1306,15 @@ def create_quarto_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the bundle. """ if app_mode is None: app_mode = AppModes.STATIC_QUARTO - return make_quarto_source_bundle(file_or_directory, inspect, app_mode, environment, extra_files, excludes, image) + return make_quarto_source_bundle(file_or_directory, inspect, app_mode, environment, extra_files, excludes, + image, no_env_restore_py, no_env_restore_r) def deploy_bundle( @@ -1336,6 +1392,8 @@ def create_notebook_manifest_and_environment_file( hide_all_input: bool, hide_tagged_input: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given notebook entry point file. @@ -1355,12 +1413,15 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) if ( not write_notebook_manifest_json( - entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, image + entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, + image, no_env_restore_py, no_env_restore_r, ) or force ): @@ -1375,6 +1436,8 @@ def write_notebook_manifest_json( hide_all_input: bool, hide_tagged_input: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1392,6 +1455,8 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ @@ -1407,7 +1472,8 @@ def write_notebook_manifest_json( if app_mode == AppModes.UNKNOWN: raise RSConnectException('Could not determine the app mode from "%s"; please specify one.' % extension) - manifest_data = make_source_manifest(app_mode, environment, file_name, None, image) + manifest_data = make_source_manifest(app_mode, environment, file_name, None, + image, no_env_restore_py, no_env_restore_r) manifest_add_file(manifest_data, file_name, directory) manifest_add_buffer(manifest_data, environment.filename, environment.contents) @@ -1428,6 +1494,8 @@ def create_api_manifest_and_environment_file( excludes: typing.List[str], force: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Python API entry point. If @@ -1444,11 +1512,14 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) if ( - not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, image) + not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, + image, no_env_restore_py, no_env_restore_r) or force ): write_environment_file(environment, directory) @@ -1462,6 +1533,8 @@ def write_api_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1476,12 +1549,15 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) extra_files = validate_extra_files(directory, extra_files) - manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, image) + manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, + image, no_env_restore_py, no_env_restore_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) diff --git a/rsconnect/bundle.py b/rsconnect/bundle.py index 8081ec01..7b45a32a 100644 --- a/rsconnect/bundle.py +++ b/rsconnect/bundle.py @@ -66,6 +66,8 @@ def __init__( entrypoint: str = None, quarto_inspection: dict = None, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, primary_html: str = None, metadata: dict = None, files: dict = None, @@ -118,10 +120,17 @@ def __init__( }, } - if image: - self.data["environment"] = { - "image": image, - } + + if image or no_env_restore_py or no_env_restore_r: + self.data["environment"] = {} + if image: + self.data["environment"]["image"] = image + if no_env_restore_py or no_env_restore_r: + self.data["environment"]["environment_management"] = {} + if no_env_restore_py: + self.data["environment"]["environment_management"]["python"] = False + if no_env_restore_r: + self.data["environment"]["environment_management"]["r"] = False self.data["files"] = {} if files: @@ -298,6 +307,8 @@ def make_source_manifest( entrypoint: str, quarto_inspection: typing.Dict[str, typing.Any], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Dict[str, typing.Any]: manifest = { "version": 1, @@ -339,10 +350,17 @@ def make_source_manifest( }, } - if image: - manifest["environment"] = { - "image": image, - } + + if image or no_env_restore_py or no_env_restore_r: + manifest["environment"] = {} + if image: + manifest["environment"]["image"] = image + if no_env_restore_py or no_env_restore_r: + manifest["environment"]["environment_management"] = {} + if no_env_restore_py: + manifest["environment"]["environment_management"]["python"] = False + if no_env_restore_r: + manifest["environment"]["environment_management"]["r"] = False manifest["files"] = {} @@ -435,6 +453,8 @@ def write_manifest( hide_all_input: bool = False, hide_tagged_input: bool = False, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Tuple[list, list]: """Create a manifest for source publishing the specified notebook. @@ -444,7 +464,8 @@ def write_manifest( Returns the list of filenames written. """ manifest_filename = "manifest.json" - manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, image) + manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, + image, no_env_restore_py, no_env_restore_r) if hide_all_input: if "jupyter" not in manifest: manifest["jupyter"] = {} @@ -513,6 +534,8 @@ def make_notebook_source_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.IO[bytes]: """Create a bundle containing the specified notebook and python environment. @@ -523,7 +546,8 @@ def make_notebook_source_bundle( base_dir = dirname(file) nb_name = basename(file) - manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, image) + manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, + image, no_env_restore_py, no_env_restore_r) if hide_all_input: if "jupyter" not in manifest: manifest["jupyter"] = {} @@ -566,6 +590,8 @@ def make_quarto_source_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.IO[bytes]: """ Create a bundle containing the specified Quarto content and (optional) @@ -574,7 +600,8 @@ def make_quarto_source_bundle( Returns a file-like object containing the bundle tarball. """ manifest, relevant_files = make_quarto_manifest( - file_or_directory, inspect, app_mode, environment, extra_files, excludes, image + file_or_directory, inspect, app_mode, environment, extra_files, excludes, + image, no_env_restore_py, no_env_restore_r, ) bundle_file = tempfile.TemporaryFile(prefix="rsc_bundle") @@ -599,6 +626,8 @@ def make_quarto_source_bundle( def make_html_manifest( filename: str, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Dict[str, typing.Any]: # noinspection SpellCheckingInspection manifest = { @@ -608,10 +637,17 @@ def make_html_manifest( "primary_html": filename, }, } - if image: - manifest["environment"] = { - "image": image, - } + + if image or no_env_restore_py or no_env_restore_r: + manifest["environment"] = {} + if image: + manifest["environment"]["image"] = image + if no_env_restore_py or no_env_restore_r: + manifest["environment"]["environment_management"] = {} + if no_env_restore_py: + manifest["environment"]["environment_management"]["python"] = False + if no_env_restore_r: + manifest["environment"]["environment_management"]["r"] = False return manifest @@ -621,6 +657,8 @@ def make_notebook_html_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, check_output: typing.Callable = subprocess.check_output, ) -> typing.IO[bytes]: # noinspection SpellCheckingInspection @@ -656,7 +694,7 @@ def make_notebook_html_bundle( bundle_add_buffer(bundle, filename, output) # manifest - manifest = make_html_manifest(filename, image) + manifest = make_html_manifest(filename, image, no_env_restore_py, no_env_restore_r) bundle_add_buffer(bundle, "manifest.json", json.dumps(manifest, indent=2)) # rewind file pointer @@ -802,6 +840,8 @@ def make_api_manifest( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Tuple[typing.Dict[str, typing.Any], typing.List[str]]: """ Makes a manifest for an API. @@ -813,6 +853,8 @@ def make_api_manifest( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the manifest and a list of the files involved. """ if is_environment_dir(directory): @@ -829,7 +871,8 @@ def make_api_manifest( excludes.extend(list_environment_dirs(directory)) relevant_files = create_file_list(directory, extra_files, excludes) - manifest = make_source_manifest(app_mode, environment, entry_point, None, image) + manifest = make_source_manifest(app_mode, environment, entry_point, None, + image, no_env_restore_py, no_env_restore_r) manifest_add_buffer(manifest, environment.filename, environment.contents) @@ -845,6 +888,8 @@ def create_html_manifest( extra_files: typing.List[str] = None, excludes: typing.List[str] = None, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, **kwargs ) -> Manifest: """ @@ -860,6 +905,8 @@ def create_html_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the manifest data structure. """ if not path: @@ -887,7 +934,8 @@ def create_html_manifest( excludes.extend(["manifest.json"]) excludes.extend(list_environment_dirs(deploy_dir)) - manifest = Manifest(app_mode=AppModes.STATIC, entrypoint=entrypoint, primary_html=entrypoint, image=image) + manifest = Manifest(app_mode=AppModes.STATIC, entrypoint=entrypoint, primary_html=entrypoint, + image=image, no_env_restore_py=no_env_restore_py, no_env_restore_r=no_env_restore_r) manifest.deploy_dir = deploy_dir file_list = create_file_list(path, extra_files, excludes, use_abspath=True) @@ -903,6 +951,8 @@ def make_html_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.IO[bytes]: """ Create an html bundle, given a path and/or entrypoint. @@ -914,6 +964,8 @@ def make_html_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: a file-like object containing the bundle tarball. """ @@ -1065,6 +1117,8 @@ def make_voila_bundle( force_generate: bool, environment: Environment, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, multi_notebook: bool = False, ) -> typing.IO[bytes]: """ @@ -1080,6 +1134,8 @@ def make_voila_bundle( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: a file-like object containing the bundle tarball. """ @@ -1112,6 +1168,8 @@ def make_api_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.IO[bytes]: """ Create an API bundle, given a directory path and a manifest. @@ -1123,10 +1181,13 @@ def make_api_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: a file-like object containing the bundle tarball. """ manifest, relevant_files = make_api_manifest( - directory, entry_point, app_mode, environment, extra_files, excludes, image + directory, entry_point, app_mode, environment, extra_files, excludes, + image, no_env_restore_py, no_env_restore_r, ) bundle_file = tempfile.TemporaryFile(prefix="rsc_bundle") @@ -1180,6 +1241,8 @@ def make_quarto_manifest( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> typing.Tuple[typing.Dict[str, typing.Any], typing.List[str]]: """ Makes a manifest for a Quarto project. @@ -1191,6 +1254,8 @@ def make_quarto_manifest( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the manifest and a list of the files involved. """ if environment: @@ -1231,6 +1296,8 @@ def make_quarto_manifest( None, quarto_inspection, image, + no_env_restore_py, + no_env_restore_r, ) if environment: @@ -1520,6 +1587,8 @@ def create_notebook_manifest_and_environment_file( hide_all_input: bool, hide_tagged_input: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given notebook entry point file. @@ -1539,11 +1608,14 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: """ if ( not write_notebook_manifest_json( - entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, image + entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, + image, no_env_restore_py, no_env_restore_r, ) or force ): @@ -1558,6 +1630,8 @@ def write_notebook_manifest_json( hide_all_input: bool, hide_tagged_input: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1575,6 +1649,8 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ @@ -1589,7 +1665,8 @@ def write_notebook_manifest_json( if app_mode == AppModes.UNKNOWN: raise RSConnectException('Could not determine the app mode from "%s"; please specify one.' % extension) - manifest_data = make_source_manifest(app_mode, environment, file_name, None, image) + manifest_data = make_source_manifest(app_mode, environment, file_name, None, + image, no_env_restore_py, no_env_restore_r) if hide_all_input or hide_tagged_input: if "jupyter" not in manifest_data: manifest_data["jupyter"] = dict() @@ -1627,6 +1704,8 @@ def create_voila_manifest( excludes: typing.List[str] = None, force_generate: bool = True, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, multi_notebook: bool = False, **kwargs ) -> Manifest: @@ -1643,6 +1722,8 @@ def create_voila_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: the manifest data structure. """ if not path: @@ -1680,7 +1761,8 @@ def create_voila_manifest( if isfile(voila_json_path): extra_files.append(voila_json_path) - manifest = Manifest(app_mode=AppModes.JUPYTER_VOILA, environment=environment, entrypoint=entrypoint, image=image) + manifest = Manifest(app_mode=AppModes.JUPYTER_VOILA, environment=environment, entrypoint=entrypoint, + image=image, no_env_restore_py=no_env_restore_py, no_env_restore_r=no_env_restore_r) manifest.deploy_dir = deploy_dir if entrypoint and isfile(entrypoint): validate_file_is_notebook(entrypoint) @@ -1703,6 +1785,8 @@ def write_voila_manifest_json( excludes: typing.List[str] = None, force_generate: bool = True, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, multi_notebook: bool = False, ) -> bool: """ @@ -1718,6 +1802,8 @@ def write_voila_manifest_json( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: whether the manifest was written. """ manifest = create_voila_manifest(**locals()) @@ -1739,6 +1825,8 @@ def create_api_manifest_and_environment_file( excludes: typing.List[str], force: bool, image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Python API entry point. If @@ -1755,10 +1843,13 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: """ if ( - not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, image) + not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, + image, no_env_restore_py, no_env_restore_r) or force ): write_environment_file(environment, directory) @@ -1772,6 +1863,8 @@ def write_api_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1786,11 +1879,14 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ extra_files = validate_extra_files(directory, extra_files) - manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, image) + manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, + image, no_env_restore_py, no_env_restore_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) @@ -1847,6 +1943,8 @@ def write_quarto_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Quarto project. @@ -1858,10 +1956,13 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. """ extra_files = validate_extra_files(directory, extra_files) - manifest, _ = make_quarto_manifest(directory, inspect, app_mode, environment, extra_files, excludes, image) + manifest, _ = make_quarto_manifest(directory, inspect, app_mode, environment, extra_files, excludes, + image, no_env_restore_py, no_env_restore_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) diff --git a/rsconnect/main.py b/rsconnect/main.py index 11d2545f..8f5ba3ba 100644 --- a/rsconnect/main.py +++ b/rsconnect/main.py @@ -244,6 +244,34 @@ def wrapper(*args, **kwargs): return wrapper +def runtime_environment_args(func): + @click.option( + "--image", + "-I", + help="Target image to be used during content build and execution. This option is only applicable if the Connect " + "server is configured to use off-host execution.", + ) + @click.option( + "--no-env-restore-py", + is_flag=True, + help="Disable Python environment restore. When this flag is provided, Connect will not " + "perform any Python package installation. It is the user's responsibility to ensure required " + "packages are installed in the runtime environment.", + ) + @click.option( + "--no-env-restore-r", + is_flag=True, + help="Disable R environment restore. When this flag is provided, Connect will not " + "perform any R package installation. It is the user's responsibility to ensure required " + "packages are installed in the runtime environment.", + ) + @functools.wraps(func) + def wrapper(*args, **kwargs): + return func(*args, **kwargs) + + return wrapper + + @click.group(no_args_is_help=True) @click.option("--future", "-u", is_flag=True, hidden=True, help="Enables future functionality.") def cli(future): @@ -750,6 +778,7 @@ def _warn_on_ignored_requirements(directory, requirements_file_name): ) @server_args @content_args +@runtime_environment_args @click.option( "--static", "-S", @@ -786,12 +815,6 @@ def _warn_on_ignored_requirements(directory, requirements_file_name): @click.option( "--hide-tagged-input", is_flag=True, default=False, help="Hide input code cells with the 'hide_input' tag" ) -@click.option( - "--image", - "-I", - help="Target image to be used during content execution (only applicable if the Posit Connect " - "server is configured to use off-host execution)", -) @click.argument("file", type=click.Path(exists=True, dir_okay=False, file_okay=True)) @click.argument( "extra_files", @@ -819,6 +842,8 @@ def deploy_notebook( hide_tagged_input: bool, env_vars: typing.Dict[str, str], image: str, + no_env_restore_py: bool, + no_env_restore_r: bool, ): kwargs = locals() set_verbosity(verbose) @@ -845,6 +870,8 @@ def deploy_notebook( hide_all_input, hide_tagged_input, image=image, + no_env_restore_py=no_env_restore_py, + no_env_restore_r=no_env_restore_r, ) else: ce.make_bundle( @@ -855,6 +882,8 @@ def deploy_notebook( hide_all_input, hide_tagged_input, image=image, + no_env_restore_py=no_env_restore_py, + no_env_restore_r=no_env_restore_r, ) ce.deploy_bundle().save_deployed_info().emit_task_log() @@ -868,6 +897,7 @@ def deploy_notebook( ) @server_args @content_args +@runtime_environment_args @click.option( "--entrypoint", "-e", @@ -904,12 +934,6 @@ def deploy_notebook( is_flag=True, help='Force generating "requirements.txt", even if it already exists.', ) -@click.option( - "--image", - "-I", - help="Target image to be used during content execution (only applicable if the RStudio Connect " - "server is configured to use off-host execution)", -) @click.argument("path", type=click.Path(exists=True, dir_okay=True, file_okay=True)) @click.argument( "extra_files", @@ -925,6 +949,8 @@ def deploy_voila( extra_files=None, exclude=None, image: str = "", + no_env_restore_py: bool = False, + no_env_restore_r: bool = False, title: str = None, env_vars: typing.Dict[str, str] = None, verbose: bool = False, @@ -956,6 +982,8 @@ def deploy_voila( force_generate, environment, image=image, + no_env_restore_py=no_env_restore_py, + no_env_restore_r=no_env_restore_r, multi_notebook=multi_notebook, ).deploy_bundle().save_deployed_info().emit_task_log() @@ -1030,6 +1058,7 @@ def deploy_manifest( ) @server_args @content_args +@runtime_environment_args @click.option( "--exclude", "-x", @@ -1061,12 +1090,6 @@ def deploy_manifest( is_flag=True, help='Force generating "requirements.txt", even if it already exists.', ) -@click.option( - "--image", - "-I", - help="Target image to be used during content execution (only applicable if the Posit Connect " - "server is configured to use off-host execution)", -) @click.argument("file_or_directory", type=click.Path(exists=True, dir_okay=True, file_okay=True)) @click.argument( "extra_files", @@ -1092,6 +1115,8 @@ def deploy_quarto( extra_files, env_vars: typing.Dict[str, str], image: str, + no_env_restore_py: bool, + no_env_restore_r: bool, ): kwargs = locals() set_verbosity(verbose) @@ -1137,6 +1162,8 @@ def deploy_quarto( inspect, environment, image=image, + no_env_restore_py=no_env_restore_py, + no_env_restore_r=no_env_restore_r, ) .deploy_bundle() .save_deployed_info() @@ -1237,6 +1264,7 @@ def generate_deploy_python(app_mode, alias, min_version): @server_args @content_args @cloud_shinyapps_args + @runtime_environment_args @click.option( "--entrypoint", "-e", @@ -1276,12 +1304,6 @@ def generate_deploy_python(app_mode, alias, min_version): is_flag=True, help='Force generating "requirements.txt", even if it already exists.', ) - @click.option( - "--image", - "-I", - help="Target image to be used during content execution (only applicable if the Posit Connect " - "server is configured to use off-host execution)", - ) @click.argument("directory", type=click.Path(exists=True, dir_okay=True, file_okay=False)) @click.argument( "extra_files", @@ -1310,6 +1332,8 @@ def deploy_app( visibility: typing.Optional[str], env_vars: typing.Dict[str, str], image: str, + no_env_restore_py: bool, + no_env_restore_r: bool, account: str = None, token: str = None, secret: str = None, @@ -1337,6 +1361,8 @@ def deploy_app( extra_files, exclude, image=image, + no_env_restore_py, + no_env_restore_r, ) .deploy_bundle() .save_deployed_info() @@ -1422,18 +1448,13 @@ def write_manifest(): @click.option("--hide-all-input", is_flag=True, default=None, help="Hide all input cells when rendering output") @click.option("--hide-tagged-input", is_flag=True, default=None, help="Hide input code cells with the 'hide_input' tag") @click.option("--verbose", "-v", "verbose", is_flag=True, help="Print detailed messages") -@click.option( - "--image", - "-I", - help="Target image to be used during content execution (only applicable if the Posit Connect " - "server is configured to use off-host execution)", -) @click.argument("file", type=click.Path(exists=True, dir_okay=False, file_okay=True)) @click.argument( "extra_files", nargs=-1, type=click.Path(exists=True, dir_okay=False, file_okay=True), ) +@runtime_environment_args def write_manifest_notebook( overwrite, python, @@ -1443,6 +1464,8 @@ def write_manifest_notebook( file, extra_files, image, + no_env_restore_py, + no_env_restore_r, hide_all_input=None, hide_tagged_input=None, ): @@ -1470,6 +1493,8 @@ def write_manifest_notebook( hide_all_input, hide_tagged_input, image, + no_env_restore_py, + no_env_restore_r, ) if environment_file_exists and not force_generate: @@ -1506,12 +1531,6 @@ def write_manifest_notebook( help='Force generating "requirements.txt", even if it already exists.', ) @click.option("--verbose", "-v", "verbose", is_flag=True, help="Print detailed messages") -@click.option( - "--image", - "-I", - help="Target image to be used during content execution (only applicable if the RStudio Connect " - "server is configured to use off-host execution)", -) @click.argument("path", type=click.Path(exists=True, dir_okay=True, file_okay=True)) @click.argument( "extra_files", @@ -1535,6 +1554,7 @@ def write_manifest_notebook( is_flag=True, help=("Set the manifest for multi-notebook mode."), ) +@runtime_environment_args def write_manifest_voila( path: str, entrypoint: str, @@ -1545,6 +1565,8 @@ def write_manifest_voila( extra_files, exclude, image, + no_env_restore_py, + no_env_restore_r, multi_notebook, ): set_verbosity(verbose) @@ -1581,6 +1603,8 @@ def write_manifest_voila( exclude, force_generate, image, + no_env_restore_py, + no_env_restore_r, multi_notebook, ) @@ -1629,18 +1653,13 @@ def write_manifest_voila( help='Force generating "requirements.txt", even if it already exists.', ) @click.option("--verbose", "-v", "verbose", is_flag=True, help="Print detailed messages") -@click.option( - "--image", - "-I", - help="Target image to be used during content execution (only applicable if the Posit Connect " - "server is configured to use off-host execution)", -) @click.argument("file_or_directory", type=click.Path(exists=True, dir_okay=True, file_okay=True)) @click.argument( "extra_files", nargs=-1, type=click.Path(exists=True, dir_okay=False, file_okay=True), ) +@runtime_environment_args def write_manifest_quarto( overwrite, exclude, @@ -1651,6 +1670,8 @@ def write_manifest_quarto( file_or_directory, extra_files, image, + no_env_restore_py, + no_env_restore_r, ): set_verbosity(verbose) @@ -1695,6 +1716,8 @@ def write_manifest_quarto( extra_files, exclude, image, + no_env_restore_py, + no_env_restore_r, ) @@ -1748,18 +1771,13 @@ def generate_write_manifest_python(app_mode, alias): help='Force generating "requirements.txt", even if it already exists.', ) @click.option("--verbose", "-v", "verbose", is_flag=True, help="Print detailed messages") - @click.option( - "--image", - "-I", - help="Target image to be used during content execution (only applicable if the Posit Connect " - "server is configured to use off-host execution)", - ) @click.argument("directory", type=click.Path(exists=True, dir_okay=True, file_okay=False)) @click.argument( "extra_files", nargs=-1, type=click.Path(exists=True, dir_okay=False, file_okay=True), ) + @runtime_environment_args def manifest_writer( overwrite, entrypoint, @@ -1771,6 +1789,8 @@ def manifest_writer( directory, extra_files, image, + no_env_restore_py, + no_env_restore_r, ): _write_framework_manifest( overwrite, @@ -1784,6 +1804,8 @@ def manifest_writer( extra_files, app_mode, image, + no_env_restore_py, + no_env_restore_r, ) return manifest_writer @@ -1810,6 +1832,8 @@ def _write_framework_manifest( extra_files, app_mode, image, + no_env_restore_py, + no_env_restore_r, ): """ A common function for writing manifests for APIs as well as Dash, Streamlit, and Bokeh apps. @@ -1827,6 +1851,8 @@ def _write_framework_manifest( :param extra_files: any extra files that should be included. :param app_mode: the app mode to use. :param image: an optional docker image for off-host execution. + :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. + :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. """ set_verbosity(verbose) @@ -1851,6 +1877,8 @@ def _write_framework_manifest( extra_files, exclude, image, + no_env_restore_py, + no_env_restore_r, ) if environment_file_exists and not force_generate: From 4158829459bbfae7546db2d9274e69daf82cb8b2 Mon Sep 17 00:00:00 2001 From: David Kegley Date: Tue, 1 Aug 2023 16:36:27 -0400 Subject: [PATCH 02/10] Rename --no-env-restore flags to --no-env-management --- rsconnect/actions.py | 180 ++++++++++++++++++++---------------- rsconnect/bundle.py | 212 ++++++++++++++++++++++++------------------- rsconnect/main.py | 90 +++++++++--------- 3 files changed, 269 insertions(+), 213 deletions(-) diff --git a/rsconnect/actions.py b/rsconnect/actions.py index 81359f05..5f3bf0cf 100644 --- a/rsconnect/actions.py +++ b/rsconnect/actions.py @@ -527,8 +527,8 @@ def write_quarto_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Quarto project. @@ -540,8 +540,10 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) @@ -553,8 +555,8 @@ def write_quarto_manifest_json( extra_files, excludes, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, ) base_dir = file_or_directory @@ -630,8 +632,8 @@ def deploy_jupyter_notebook( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> None: """ A function to deploy a Jupyter notebook to Connect. Depending on the files involved @@ -659,8 +661,10 @@ def deploy_jupyter_notebook( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -709,8 +713,8 @@ def deploy_jupyter_notebook( hide_all_input, hide_tagged_input, image=image, - no_env_restore_py=no_env_restore_py, - no_env_restore_r=no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, ) else: ce.make_bundle( @@ -721,8 +725,8 @@ def deploy_jupyter_notebook( hide_all_input, hide_tagged_input, image=image, - no_env_restore_py=no_env_restore_py, - no_env_restore_r=no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, ) ce.deploy_bundle().save_deployed_info().emit_task_log() @@ -761,8 +765,8 @@ def deploy_app( extra_files: typing.List[str] = None, env_vars: typing.Dict[str, str] = None, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, account: str = None, token: str = None, secret: str = None, @@ -814,8 +818,8 @@ def deploy_app( extra_files, excludes, image=image, - no_env_restore_py=no_env_restore_py, - no_env_restore_r=no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, ) .deploy_bundle() .save_deployed_info() @@ -837,8 +841,8 @@ def deploy_python_api( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python WSGi API module to Connect. Depending on the files involved @@ -863,8 +867,10 @@ def deploy_python_api( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -885,8 +891,8 @@ def deploy_python_fastapi( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python ASGI API module to Posit Connect. Depending on the files involved @@ -911,8 +917,10 @@ def deploy_python_fastapi( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -975,8 +983,8 @@ def deploy_dash_app( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Dash app module to Connect. Depending on the files involved @@ -1001,8 +1009,10 @@ def deploy_dash_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1023,8 +1033,8 @@ def deploy_streamlit_app( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Streamlit app module to Connect. Depending on the files involved @@ -1049,8 +1059,10 @@ def deploy_streamlit_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1071,8 +1083,8 @@ def deploy_bokeh_app( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Bokeh app module to Connect. Depending on the files involved @@ -1097,8 +1109,10 @@ def deploy_bokeh_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1182,8 +1196,8 @@ def create_notebook_deployment_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1201,8 +1215,10 @@ def create_notebook_deployment_bundle( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the bundle. """ @@ -1219,8 +1235,8 @@ def create_notebook_deployment_bundle( hide_all_input, hide_tagged_input, image=image, - no_env_restore_py=no_env_restore_py, - no_env_restore_r=no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, ) except subprocess.CalledProcessError as exc: # Jupyter rendering failures are often due to @@ -1234,8 +1250,8 @@ def create_notebook_deployment_bundle( hide_all_input, hide_tagged_input, image=image, - no_env_restore_py=no_env_restore_py, - no_env_restore_r=no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, ) @@ -1248,8 +1264,8 @@ def create_api_deployment_bundle( environment: Environment, extra_files_need_validating: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1265,8 +1281,10 @@ def create_api_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the bundle. """ entry_point = validate_entry_point(entry_point, directory) @@ -1278,7 +1296,7 @@ def create_api_deployment_bundle( app_mode = AppModes.PYTHON_API return make_api_bundle(directory, entry_point, app_mode, environment, extra_files, excludes, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) def create_quarto_deployment_bundle( @@ -1289,8 +1307,8 @@ def create_quarto_deployment_bundle( inspect: typing.Dict[str, typing.Any], environment: Environment, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1306,15 +1324,17 @@ def create_quarto_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the bundle. """ if app_mode is None: app_mode = AppModes.STATIC_QUARTO return make_quarto_source_bundle(file_or_directory, inspect, app_mode, environment, extra_files, excludes, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) def deploy_bundle( @@ -1392,8 +1412,8 @@ def create_notebook_manifest_and_environment_file( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given notebook entry point file. @@ -1413,15 +1433,17 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) if ( not write_notebook_manifest_json( entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, - image, no_env_restore_py, no_env_restore_r, + image, no_env_management_py, no_env_management_r, ) or force ): @@ -1436,8 +1458,8 @@ def write_notebook_manifest_json( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1455,8 +1477,10 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ @@ -1473,7 +1497,7 @@ def write_notebook_manifest_json( raise RSConnectException('Could not determine the app mode from "%s"; please specify one.' % extension) manifest_data = make_source_manifest(app_mode, environment, file_name, None, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) manifest_add_file(manifest_data, file_name, directory) manifest_add_buffer(manifest_data, environment.filename, environment.contents) @@ -1494,8 +1518,8 @@ def create_api_manifest_and_environment_file( excludes: typing.List[str], force: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Python API entry point. If @@ -1512,14 +1536,16 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) if ( not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) or force ): write_environment_file(environment, directory) @@ -1533,8 +1559,8 @@ def write_api_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1549,15 +1575,17 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) extra_files = validate_extra_files(directory, extra_files) manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) diff --git a/rsconnect/bundle.py b/rsconnect/bundle.py index 7b45a32a..25d53a3f 100644 --- a/rsconnect/bundle.py +++ b/rsconnect/bundle.py @@ -66,8 +66,8 @@ def __init__( entrypoint: str = None, quarto_inspection: dict = None, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, primary_html: str = None, metadata: dict = None, files: dict = None, @@ -121,15 +121,15 @@ def __init__( } - if image or no_env_restore_py or no_env_restore_r: + if image or no_env_management_py or no_env_management_r: self.data["environment"] = {} if image: self.data["environment"]["image"] = image - if no_env_restore_py or no_env_restore_r: + if no_env_management_py or no_env_management_r: self.data["environment"]["environment_management"] = {} - if no_env_restore_py: + if no_env_management_py: self.data["environment"]["environment_management"]["python"] = False - if no_env_restore_r: + if no_env_management_r: self.data["environment"]["environment_management"]["r"] = False self.data["files"] = {} @@ -307,8 +307,8 @@ def make_source_manifest( entrypoint: str, quarto_inspection: typing.Dict[str, typing.Any], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Dict[str, typing.Any]: manifest = { "version": 1, @@ -351,15 +351,15 @@ def make_source_manifest( } - if image or no_env_restore_py or no_env_restore_r: + if image or no_env_management_py or no_env_management_r: manifest["environment"] = {} if image: manifest["environment"]["image"] = image - if no_env_restore_py or no_env_restore_r: + if no_env_management_py or no_env_management_r: manifest["environment"]["environment_management"] = {} - if no_env_restore_py: + if no_env_management_py: manifest["environment"]["environment_management"]["python"] = False - if no_env_restore_r: + if no_env_management_r: manifest["environment"]["environment_management"]["r"] = False manifest["files"] = {} @@ -453,8 +453,8 @@ def write_manifest( hide_all_input: bool = False, hide_tagged_input: bool = False, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Tuple[list, list]: """Create a manifest for source publishing the specified notebook. @@ -465,7 +465,7 @@ def write_manifest( """ manifest_filename = "manifest.json" manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) if hide_all_input: if "jupyter" not in manifest: manifest["jupyter"] = {} @@ -534,8 +534,8 @@ def make_notebook_source_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.IO[bytes]: """Create a bundle containing the specified notebook and python environment. @@ -547,7 +547,7 @@ def make_notebook_source_bundle( nb_name = basename(file) manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) if hide_all_input: if "jupyter" not in manifest: manifest["jupyter"] = {} @@ -590,8 +590,8 @@ def make_quarto_source_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create a bundle containing the specified Quarto content and (optional) @@ -601,7 +601,7 @@ def make_quarto_source_bundle( """ manifest, relevant_files = make_quarto_manifest( file_or_directory, inspect, app_mode, environment, extra_files, excludes, - image, no_env_restore_py, no_env_restore_r, + image, no_env_management_py, no_env_management_r, ) bundle_file = tempfile.TemporaryFile(prefix="rsc_bundle") @@ -626,8 +626,8 @@ def make_quarto_source_bundle( def make_html_manifest( filename: str, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Dict[str, typing.Any]: # noinspection SpellCheckingInspection manifest = { @@ -638,15 +638,15 @@ def make_html_manifest( }, } - if image or no_env_restore_py or no_env_restore_r: + if image or no_env_management_py or no_env_management_r: manifest["environment"] = {} if image: manifest["environment"]["image"] = image - if no_env_restore_py or no_env_restore_r: + if no_env_management_py or no_env_management_r: manifest["environment"]["environment_management"] = {} - if no_env_restore_py: + if no_env_management_py: manifest["environment"]["environment_management"]["python"] = False - if no_env_restore_r: + if no_env_management_r: manifest["environment"]["environment_management"]["r"] = False return manifest @@ -657,8 +657,8 @@ def make_notebook_html_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, check_output: typing.Callable = subprocess.check_output, ) -> typing.IO[bytes]: # noinspection SpellCheckingInspection @@ -694,7 +694,7 @@ def make_notebook_html_bundle( bundle_add_buffer(bundle, filename, output) # manifest - manifest = make_html_manifest(filename, image, no_env_restore_py, no_env_restore_r) + manifest = make_html_manifest(filename, image, no_env_management_py, no_env_management_r) bundle_add_buffer(bundle, "manifest.json", json.dumps(manifest, indent=2)) # rewind file pointer @@ -840,8 +840,8 @@ def make_api_manifest( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Tuple[typing.Dict[str, typing.Any], typing.List[str]]: """ Makes a manifest for an API. @@ -853,8 +853,10 @@ def make_api_manifest( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the manifest and a list of the files involved. """ if is_environment_dir(directory): @@ -872,7 +874,7 @@ def make_api_manifest( relevant_files = create_file_list(directory, extra_files, excludes) manifest = make_source_manifest(app_mode, environment, entry_point, None, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) manifest_add_buffer(manifest, environment.filename, environment.contents) @@ -888,8 +890,8 @@ def create_html_manifest( extra_files: typing.List[str] = None, excludes: typing.List[str] = None, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, **kwargs ) -> Manifest: """ @@ -905,8 +907,10 @@ def create_html_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the manifest data structure. """ if not path: @@ -935,7 +939,7 @@ def create_html_manifest( excludes.extend(list_environment_dirs(deploy_dir)) manifest = Manifest(app_mode=AppModes.STATIC, entrypoint=entrypoint, primary_html=entrypoint, - image=image, no_env_restore_py=no_env_restore_py, no_env_restore_r=no_env_restore_r) + image=image, no_env_management_py=no_env_management_py, no_env_management_r=no_env_management_r) manifest.deploy_dir = deploy_dir file_list = create_file_list(path, extra_files, excludes, use_abspath=True) @@ -951,8 +955,8 @@ def make_html_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an html bundle, given a path and/or entrypoint. @@ -964,8 +968,10 @@ def make_html_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: a file-like object containing the bundle tarball. """ @@ -1117,8 +1123,8 @@ def make_voila_bundle( force_generate: bool, environment: Environment, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, multi_notebook: bool = False, ) -> typing.IO[bytes]: """ @@ -1134,8 +1140,10 @@ def make_voila_bundle( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: a file-like object containing the bundle tarball. """ @@ -1168,8 +1176,8 @@ def make_api_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an API bundle, given a directory path and a manifest. @@ -1181,13 +1189,15 @@ def make_api_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: a file-like object containing the bundle tarball. """ manifest, relevant_files = make_api_manifest( directory, entry_point, app_mode, environment, extra_files, excludes, - image, no_env_restore_py, no_env_restore_r, + image, no_env_management_py, no_env_management_r, ) bundle_file = tempfile.TemporaryFile(prefix="rsc_bundle") @@ -1241,8 +1251,8 @@ def make_quarto_manifest( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> typing.Tuple[typing.Dict[str, typing.Any], typing.List[str]]: """ Makes a manifest for a Quarto project. @@ -1254,8 +1264,10 @@ def make_quarto_manifest( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the manifest and a list of the files involved. """ if environment: @@ -1296,8 +1308,8 @@ def make_quarto_manifest( None, quarto_inspection, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, ) if environment: @@ -1587,8 +1599,8 @@ def create_notebook_manifest_and_environment_file( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given notebook entry point file. @@ -1608,14 +1620,16 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: """ if ( not write_notebook_manifest_json( entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, - image, no_env_restore_py, no_env_restore_r, + image, no_env_management_py, no_env_management_r, ) or force ): @@ -1630,8 +1644,8 @@ def write_notebook_manifest_json( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1649,8 +1663,10 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ @@ -1666,7 +1682,7 @@ def write_notebook_manifest_json( raise RSConnectException('Could not determine the app mode from "%s"; please specify one.' % extension) manifest_data = make_source_manifest(app_mode, environment, file_name, None, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) if hide_all_input or hide_tagged_input: if "jupyter" not in manifest_data: manifest_data["jupyter"] = dict() @@ -1704,8 +1720,8 @@ def create_voila_manifest( excludes: typing.List[str] = None, force_generate: bool = True, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, multi_notebook: bool = False, **kwargs ) -> Manifest: @@ -1722,8 +1738,10 @@ def create_voila_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: the manifest data structure. """ if not path: @@ -1762,7 +1780,7 @@ def create_voila_manifest( extra_files.append(voila_json_path) manifest = Manifest(app_mode=AppModes.JUPYTER_VOILA, environment=environment, entrypoint=entrypoint, - image=image, no_env_restore_py=no_env_restore_py, no_env_restore_r=no_env_restore_r) + image=image, no_env_management_py=no_env_management_py, no_env_management_r=no_env_management_r) manifest.deploy_dir = deploy_dir if entrypoint and isfile(entrypoint): validate_file_is_notebook(entrypoint) @@ -1785,8 +1803,8 @@ def write_voila_manifest_json( excludes: typing.List[str] = None, force_generate: bool = True, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, multi_notebook: bool = False, ) -> bool: """ @@ -1802,8 +1820,10 @@ def write_voila_manifest_json( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: whether the manifest was written. """ manifest = create_voila_manifest(**locals()) @@ -1825,8 +1845,8 @@ def create_api_manifest_and_environment_file( excludes: typing.List[str], force: bool, image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Python API entry point. If @@ -1843,13 +1863,15 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: """ if ( not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) or force ): write_environment_file(environment, directory) @@ -1863,8 +1885,8 @@ def write_api_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1879,14 +1901,16 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ extra_files = validate_extra_files(directory, extra_files) manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) @@ -1943,8 +1967,8 @@ def write_quarto_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Quarto project. @@ -1956,13 +1980,15 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. Default = False. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. """ extra_files = validate_extra_files(directory, extra_files) manifest, _ = make_quarto_manifest(directory, inspect, app_mode, environment, extra_files, excludes, - image, no_env_restore_py, no_env_restore_r) + image, no_env_management_py, no_env_management_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) diff --git a/rsconnect/main.py b/rsconnect/main.py index 8f5ba3ba..ae6b8ffe 100644 --- a/rsconnect/main.py +++ b/rsconnect/main.py @@ -252,16 +252,16 @@ def runtime_environment_args(func): "server is configured to use off-host execution.", ) @click.option( - "--no-env-restore-py", + "--no-env-management-py", is_flag=True, - help="Disable Python environment restore. When this flag is provided, Connect will not " + help="Disable Python environment management. When this flag is provided, Connect will not " "perform any Python package installation. It is the user's responsibility to ensure required " "packages are installed in the runtime environment.", ) @click.option( - "--no-env-restore-r", + "--no-env-management-r", is_flag=True, - help="Disable R environment restore. When this flag is provided, Connect will not " + help="Disable R environment management. When this flag is provided, Connect will not " "perform any R package installation. It is the user's responsibility to ensure required " "packages are installed in the runtime environment.", ) @@ -842,8 +842,8 @@ def deploy_notebook( hide_tagged_input: bool, env_vars: typing.Dict[str, str], image: str, - no_env_restore_py: bool, - no_env_restore_r: bool, + no_env_management_py: bool, + no_env_management_r: bool, ): kwargs = locals() set_verbosity(verbose) @@ -870,8 +870,8 @@ def deploy_notebook( hide_all_input, hide_tagged_input, image=image, - no_env_restore_py=no_env_restore_py, - no_env_restore_r=no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, ) else: ce.make_bundle( @@ -882,8 +882,8 @@ def deploy_notebook( hide_all_input, hide_tagged_input, image=image, - no_env_restore_py=no_env_restore_py, - no_env_restore_r=no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, ) ce.deploy_bundle().save_deployed_info().emit_task_log() @@ -949,8 +949,8 @@ def deploy_voila( extra_files=None, exclude=None, image: str = "", - no_env_restore_py: bool = False, - no_env_restore_r: bool = False, + no_env_management_py: bool = False, + no_env_management_r: bool = False, title: str = None, env_vars: typing.Dict[str, str] = None, verbose: bool = False, @@ -982,8 +982,8 @@ def deploy_voila( force_generate, environment, image=image, - no_env_restore_py=no_env_restore_py, - no_env_restore_r=no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, multi_notebook=multi_notebook, ).deploy_bundle().save_deployed_info().emit_task_log() @@ -1115,8 +1115,8 @@ def deploy_quarto( extra_files, env_vars: typing.Dict[str, str], image: str, - no_env_restore_py: bool, - no_env_restore_r: bool, + no_env_management_py: bool, + no_env_management_r: bool, ): kwargs = locals() set_verbosity(verbose) @@ -1162,8 +1162,8 @@ def deploy_quarto( inspect, environment, image=image, - no_env_restore_py=no_env_restore_py, - no_env_restore_r=no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, ) .deploy_bundle() .save_deployed_info() @@ -1332,8 +1332,8 @@ def deploy_app( visibility: typing.Optional[str], env_vars: typing.Dict[str, str], image: str, - no_env_restore_py: bool, - no_env_restore_r: bool, + no_env_management_py: bool, + no_env_management_r: bool, account: str = None, token: str = None, secret: str = None, @@ -1361,8 +1361,8 @@ def deploy_app( extra_files, exclude, image=image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py=no_env_management_py, + no_env_management_r=no_env_management_r, ) .deploy_bundle() .save_deployed_info() @@ -1464,8 +1464,8 @@ def write_manifest_notebook( file, extra_files, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, hide_all_input=None, hide_tagged_input=None, ): @@ -1493,8 +1493,8 @@ def write_manifest_notebook( hide_all_input, hide_tagged_input, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, ) if environment_file_exists and not force_generate: @@ -1565,8 +1565,8 @@ def write_manifest_voila( extra_files, exclude, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, multi_notebook, ): set_verbosity(verbose) @@ -1603,8 +1603,8 @@ def write_manifest_voila( exclude, force_generate, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, multi_notebook, ) @@ -1670,8 +1670,8 @@ def write_manifest_quarto( file_or_directory, extra_files, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, ): set_verbosity(verbose) @@ -1716,8 +1716,8 @@ def write_manifest_quarto( extra_files, exclude, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, ) @@ -1789,8 +1789,8 @@ def manifest_writer( directory, extra_files, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, ): _write_framework_manifest( overwrite, @@ -1804,8 +1804,8 @@ def manifest_writer( extra_files, app_mode, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, ) return manifest_writer @@ -1832,8 +1832,8 @@ def _write_framework_manifest( extra_files, app_mode, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, ): """ A common function for writing manifests for APIs as well as Dash, Streamlit, and Bokeh apps. @@ -1851,8 +1851,10 @@ def _write_framework_manifest( :param extra_files: any extra files that should be included. :param app_mode: the app mode to use. :param image: an optional docker image for off-host execution. - :param no_env_restore_py: whether the user is responsible for Python package installation in the runtime environment. - :param no_env_restore_r: whether the user is responsible for R package installation in the runtime environment. + :param no_env_management_py: True indicates that the user is responsible for Python package installation + in the runtime environment. Default = False. + :param no_env_management_r: True indicates that the user is responsible for R package installation + in the runtime environment. Default = False. """ set_verbosity(verbose) @@ -1877,8 +1879,8 @@ def _write_framework_manifest( extra_files, exclude, image, - no_env_restore_py, - no_env_restore_r, + no_env_management_py, + no_env_management_r, ) if environment_file_exists and not force_generate: From 4136ab3933a1a53a2f268b716fb05ca223046ac0 Mon Sep 17 00:00:00 2001 From: David Kegley Date: Tue, 1 Aug 2023 16:36:34 -0400 Subject: [PATCH 03/10] Update changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad8dba11..7db70690 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +- Add `--no-env-management-py` and `--no-env-management-r` flags for all content types that support environment restores (non static). + This flag indicates to Connect that the user is responsible for Python/R package installation and Connect should not install + packages during the build. The Python/R packages must still be available in the runtime environment in order to run the content. + This is especially useful if off-host execution is enabled when the execution environment (specified by `--image`) already contains the required + packages. Requires Posit Connect `>=2023.07.0`. + ## [1.19.1] - 2023-08-01 ### Added From e41fa7bdcef7592aac1bf5a7da604cc592d8f1e6 Mon Sep 17 00:00:00 2001 From: David Kegley Date: Wed, 2 Aug 2023 11:15:22 -0400 Subject: [PATCH 04/10] Add runtime_environment args unit tests for manifest-writers --- tests/test_bundle.py | 218 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 211 insertions(+), 7 deletions(-) diff --git a/tests/test_bundle.py b/tests/test_bundle.py index d0de581b..81300bf0 100644 --- a/tests/test_bundle.py +++ b/tests/test_bundle.py @@ -74,7 +74,8 @@ def test_make_notebook_source_bundle1(self): # the kernel environment and not the notebook server environment. environment = detect_environment(directory) with make_notebook_source_bundle( - nb_path, environment, None, hide_all_input=False, hide_tagged_input=False, image=None + nb_path, environment, None, hide_all_input=False, hide_tagged_input=False, + image=None, no_env_management_py=False, no_env_management_r=False, ) as bundle, tarfile.open(mode="r:gz", fileobj=bundle) as tar: names = sorted(tar.getnames()) self.assertEqual( @@ -145,6 +146,8 @@ def test_make_notebook_source_bundle2(self): hide_all_input=False, hide_tagged_input=False, image="rstudio/connect:bionic", + no_env_management_py=True, + no_env_management_r=True, ) as bundle, tarfile.open(mode="r:gz", fileobj=bundle) as tar: names = sorted(tar.getnames()) self.assertEqual( @@ -196,7 +199,13 @@ def test_make_notebook_source_bundle2(self): "package_file": "requirements.txt", }, }, - "environment": {"image": "rstudio/connect:bionic"}, + "environment": { + "image": "rstudio/connect:bionic", + "environment_management": { + "python": False, + "r": False, + } + }, "files": { "dummy.ipynb": { "checksum": ipynb_hash, @@ -554,7 +563,7 @@ def test_make_source_manifest(self): # quarto_inspection=None, # type: typing.Optional[typing.Dict[str, typing.Any]] # No optional parameters - manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, None) + manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None) self.assertEqual( manifest, {"version": 1, "metadata": {"appmode": "python-api"}, "files": {}}, @@ -567,7 +576,59 @@ def test_make_source_manifest(self): { "version": 1, "metadata": {"appmode": "python-api"}, - "environment": {"image": "rstudio/connect:bionic"}, + "environment": { + "image": "rstudio/connect:bionic", + }, + "files": {}, + }, + ) + + # include no_env_management_py parameter + manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, None, True, False) + self.assertEqual( + manifest, + { + "version": 1, + "metadata": {"appmode": "python-api"}, + "environment": { + "environment_management": { + "python": False + } + }, + "files": {}, + }, + ) + + # include no_env_management_r parameter + manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, None, False, True) + self.assertEqual( + manifest, + { + "version": 1, + "metadata": {"appmode": "python-api"}, + "environment": { + "environment_management": { + "r": False + } + }, + "files": {}, + }, + ) + + # include all runtime environment parameters + manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, "rstudio/connect:bionic", True, True) + self.assertEqual( + manifest, + { + "version": 1, + "metadata": {"appmode": "python-api"}, + "environment": { + "image": "rstudio/connect:bionic", + "environment_management": { + "r": False, + "python": False + } + }, "files": {}, }, ) @@ -893,7 +954,7 @@ def test_make_html_manifest(self): # image=None, # type: str # No optional parameters - manifest = make_html_manifest("abc.html", None) + manifest = make_html_manifest("abc.html") # print(manifest) self.assertEqual( manifest, @@ -907,7 +968,8 @@ def test_make_html_manifest(self): ) # include image parameter - manifest = make_html_manifest("abc.html", image="rstudio/connect:bionic") + manifest = make_html_manifest("abc.html", + image="rstudio/connect:bionic") # print(manifest) self.assertEqual( manifest, @@ -917,7 +979,73 @@ def test_make_html_manifest(self): "appmode": "static", "primary_html": "abc.html", }, - "environment": {"image": "rstudio/connect:bionic"}, + "environment": { + "image": "rstudio/connect:bionic", + }, + }, + ) + + # include no_env_management_py parameter + manifest = make_html_manifest("abc.html", + no_env_management_py=True) + # print(manifest) + self.assertEqual( + manifest, + { + "version": 1, + "metadata": { + "appmode": "static", + "primary_html": "abc.html", + }, + "environment": { + "environment_management": { + "python": False, + } + }, + }, + ) + + # include no_env_management_r parameter + manifest = make_html_manifest("abc.html", + no_env_management_r=True) + # print(manifest) + self.assertEqual( + manifest, + { + "version": 1, + "metadata": { + "appmode": "static", + "primary_html": "abc.html", + }, + "environment": { + "environment_management": { + "r": False, + } + }, + }, + ) + + # include all runtime environment parameters + manifest = make_html_manifest("abc.html", + image="rstudio/connect:bionic", + no_env_management_py=True, + no_env_management_r=True) + # print(manifest) + self.assertEqual( + manifest, + { + "version": 1, + "metadata": { + "appmode": "static", + "primary_html": "abc.html", + }, + "environment": { + "image": "rstudio/connect:bionic", + "environment_management": { + "python": False, + "r": False, + } + }, }, ) @@ -1880,6 +2008,82 @@ def test_create_html_manifest(): ) assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) + # check all runtime_environment vars + single_file_index_file_ans = { + "version": 1, + "metadata": {"appmode": "static", "primary_html": "index.html", "entrypoint": "index.html"}, + "files": {"index.html": {"checksum": index_hash}}, + "environment": { + "image": "rstudio/connect:bionic", + "environment_management": { + "python": False, + "r": False, + } + }, + } + manifest = create_html_manifest( + single_file_index_file, + None, + image="rstudio/connect:bionic", + no_env_management_py=True, + no_env_management_r=True, + ) + assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) + + # check image param + single_file_index_file_ans = { + "version": 1, + "metadata": {"appmode": "static", "primary_html": "index.html", "entrypoint": "index.html"}, + "files": {"index.html": {"checksum": index_hash}}, + "environment": { + "image": "rstudio/connect:bionic", + }, + } + manifest = create_html_manifest( + single_file_index_file, + None, + image="rstudio/connect:bionic", + no_env_management_py=None, + no_env_management_r=None, + ) + assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) + + # check no_env_management_py param + single_file_index_file_ans = { + "version": 1, + "metadata": {"appmode": "static", "primary_html": "index.html", "entrypoint": "index.html"}, + "files": {"index.html": {"checksum": index_hash}}, + "environment": { + "environment_management": { + "python": False, + } + }, + } + manifest = create_html_manifest( + single_file_index_file, + None, + no_env_management_py=True, + ) + assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) + + # check no_env_management_r param + single_file_index_file_ans = { + "version": 1, + "metadata": {"appmode": "static", "primary_html": "index.html", "entrypoint": "index.html"}, + "files": {"index.html": {"checksum": index_hash}}, + "environment": { + "environment_management": { + "r": False, + } + }, + } + manifest = create_html_manifest( + single_file_index_file, + None, + no_env_management_r=True, + ) + assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) + single_file_index_dir_ans = { "version": 1, "metadata": {"appmode": "static", "primary_html": "index.html", "entrypoint": "index.html"}, From 2f31062a43190c745129b3e12ebe5cf65127afa8 Mon Sep 17 00:00:00 2001 From: David Kegley Date: Fri, 4 Aug 2023 11:06:40 -0400 Subject: [PATCH 05/10] Rename no-env-management flags to disable-env-management --- CHANGELOG.md | 2 +- rsconnect/actions.py | 152 +++++++++++++++++------------------ rsconnect/bundle.py | 186 +++++++++++++++++++++---------------------- rsconnect/main.py | 84 +++++++++---------- tests/test_bundle.py | 38 ++++----- 5 files changed, 231 insertions(+), 231 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7db70690..1bbed6ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add `--no-env-management-py` and `--no-env-management-r` flags for all content types that support environment restores (non static). +- Add `--disable-env-management-py` and `--disable-env-management-r` flags for all content types that support environment restores (non static). This flag indicates to Connect that the user is responsible for Python/R package installation and Connect should not install packages during the build. The Python/R packages must still be available in the runtime environment in order to run the content. This is especially useful if off-host execution is enabled when the execution environment (specified by `--image`) already contains the required diff --git a/rsconnect/actions.py b/rsconnect/actions.py index 5f3bf0cf..214e3de7 100644 --- a/rsconnect/actions.py +++ b/rsconnect/actions.py @@ -527,8 +527,8 @@ def write_quarto_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Quarto project. @@ -540,9 +540,9 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) @@ -555,8 +555,8 @@ def write_quarto_manifest_json( extra_files, excludes, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, ) base_dir = file_or_directory @@ -632,8 +632,8 @@ def deploy_jupyter_notebook( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> None: """ A function to deploy a Jupyter notebook to Connect. Depending on the files involved @@ -661,9 +661,9 @@ def deploy_jupyter_notebook( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. @@ -713,8 +713,8 @@ def deploy_jupyter_notebook( hide_all_input, hide_tagged_input, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, ) else: ce.make_bundle( @@ -725,8 +725,8 @@ def deploy_jupyter_notebook( hide_all_input, hide_tagged_input, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, ) ce.deploy_bundle().save_deployed_info().emit_task_log() @@ -765,8 +765,8 @@ def deploy_app( extra_files: typing.List[str] = None, env_vars: typing.Dict[str, str] = None, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, account: str = None, token: str = None, secret: str = None, @@ -818,8 +818,8 @@ def deploy_app( extra_files, excludes, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, ) .deploy_bundle() .save_deployed_info() @@ -841,8 +841,8 @@ def deploy_python_api( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python WSGi API module to Connect. Depending on the files involved @@ -867,9 +867,9 @@ def deploy_python_api( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. @@ -891,8 +891,8 @@ def deploy_python_fastapi( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python ASGI API module to Posit Connect. Depending on the files involved @@ -917,9 +917,9 @@ def deploy_python_fastapi( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. @@ -983,8 +983,8 @@ def deploy_dash_app( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Dash app module to Connect. Depending on the files involved @@ -1009,9 +1009,9 @@ def deploy_dash_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. @@ -1033,8 +1033,8 @@ def deploy_streamlit_app( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Streamlit app module to Connect. Depending on the files involved @@ -1059,9 +1059,9 @@ def deploy_streamlit_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. @@ -1083,8 +1083,8 @@ def deploy_bokeh_app( force_generate: bool, log_callback: typing.Callable, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Bokeh app module to Connect. Depending on the files involved @@ -1109,9 +1109,9 @@ def deploy_bokeh_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. @@ -1196,8 +1196,8 @@ def create_notebook_deployment_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1215,9 +1215,9 @@ def create_notebook_deployment_bundle( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the bundle. @@ -1235,8 +1235,8 @@ def create_notebook_deployment_bundle( hide_all_input, hide_tagged_input, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, ) except subprocess.CalledProcessError as exc: # Jupyter rendering failures are often due to @@ -1250,8 +1250,8 @@ def create_notebook_deployment_bundle( hide_all_input, hide_tagged_input, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, ) @@ -1264,8 +1264,8 @@ def create_api_deployment_bundle( environment: Environment, extra_files_need_validating: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1281,9 +1281,9 @@ def create_api_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the bundle. """ @@ -1296,7 +1296,7 @@ def create_api_deployment_bundle( app_mode = AppModes.PYTHON_API return make_api_bundle(directory, entry_point, app_mode, environment, extra_files, excludes, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) def create_quarto_deployment_bundle( @@ -1307,8 +1307,8 @@ def create_quarto_deployment_bundle( inspect: typing.Dict[str, typing.Any], environment: Environment, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1324,9 +1324,9 @@ def create_quarto_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the bundle. """ @@ -1334,7 +1334,7 @@ def create_quarto_deployment_bundle( app_mode = AppModes.STATIC_QUARTO return make_quarto_source_bundle(file_or_directory, inspect, app_mode, environment, extra_files, excludes, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) def deploy_bundle( @@ -1412,8 +1412,8 @@ def create_notebook_manifest_and_environment_file( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given notebook entry point file. @@ -1433,9 +1433,9 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: """ @@ -1443,7 +1443,7 @@ def create_notebook_manifest_and_environment_file( if ( not write_notebook_manifest_json( entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, - image, no_env_management_py, no_env_management_r, + image, disable_env_management_py, disable_env_management_r, ) or force ): @@ -1458,8 +1458,8 @@ def write_notebook_manifest_json( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1477,9 +1477,9 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. @@ -1497,7 +1497,7 @@ def write_notebook_manifest_json( raise RSConnectException('Could not determine the app mode from "%s"; please specify one.' % extension) manifest_data = make_source_manifest(app_mode, environment, file_name, None, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) manifest_add_file(manifest_data, file_name, directory) manifest_add_buffer(manifest_data, environment.filename, environment.contents) @@ -1518,8 +1518,8 @@ def create_api_manifest_and_environment_file( excludes: typing.List[str], force: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Python API entry point. If @@ -1536,16 +1536,16 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) if ( not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) or force ): write_environment_file(environment, directory) @@ -1559,8 +1559,8 @@ def write_api_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1575,9 +1575,9 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. @@ -1585,7 +1585,7 @@ def write_api_manifest_json( warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) extra_files = validate_extra_files(directory, extra_files) manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) diff --git a/rsconnect/bundle.py b/rsconnect/bundle.py index 25d53a3f..c99c5b91 100644 --- a/rsconnect/bundle.py +++ b/rsconnect/bundle.py @@ -66,8 +66,8 @@ def __init__( entrypoint: str = None, quarto_inspection: dict = None, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, primary_html: str = None, metadata: dict = None, files: dict = None, @@ -121,15 +121,15 @@ def __init__( } - if image or no_env_management_py or no_env_management_r: + if image or disable_env_management_py or disable_env_management_r: self.data["environment"] = {} if image: self.data["environment"]["image"] = image - if no_env_management_py or no_env_management_r: + if disable_env_management_py or disable_env_management_r: self.data["environment"]["environment_management"] = {} - if no_env_management_py: + if disable_env_management_py: self.data["environment"]["environment_management"]["python"] = False - if no_env_management_r: + if disable_env_management_r: self.data["environment"]["environment_management"]["r"] = False self.data["files"] = {} @@ -307,8 +307,8 @@ def make_source_manifest( entrypoint: str, quarto_inspection: typing.Dict[str, typing.Any], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Dict[str, typing.Any]: manifest = { "version": 1, @@ -351,15 +351,15 @@ def make_source_manifest( } - if image or no_env_management_py or no_env_management_r: + if image or disable_env_management_py or disable_env_management_r: manifest["environment"] = {} if image: manifest["environment"]["image"] = image - if no_env_management_py or no_env_management_r: + if disable_env_management_py or disable_env_management_r: manifest["environment"]["environment_management"] = {} - if no_env_management_py: + if disable_env_management_py: manifest["environment"]["environment_management"]["python"] = False - if no_env_management_r: + if disable_env_management_r: manifest["environment"]["environment_management"]["r"] = False manifest["files"] = {} @@ -453,8 +453,8 @@ def write_manifest( hide_all_input: bool = False, hide_tagged_input: bool = False, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Tuple[list, list]: """Create a manifest for source publishing the specified notebook. @@ -465,7 +465,7 @@ def write_manifest( """ manifest_filename = "manifest.json" manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) if hide_all_input: if "jupyter" not in manifest: manifest["jupyter"] = {} @@ -534,8 +534,8 @@ def make_notebook_source_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.IO[bytes]: """Create a bundle containing the specified notebook and python environment. @@ -547,7 +547,7 @@ def make_notebook_source_bundle( nb_name = basename(file) manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) if hide_all_input: if "jupyter" not in manifest: manifest["jupyter"] = {} @@ -590,8 +590,8 @@ def make_quarto_source_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create a bundle containing the specified Quarto content and (optional) @@ -601,7 +601,7 @@ def make_quarto_source_bundle( """ manifest, relevant_files = make_quarto_manifest( file_or_directory, inspect, app_mode, environment, extra_files, excludes, - image, no_env_management_py, no_env_management_r, + image, disable_env_management_py, disable_env_management_r, ) bundle_file = tempfile.TemporaryFile(prefix="rsc_bundle") @@ -626,8 +626,8 @@ def make_quarto_source_bundle( def make_html_manifest( filename: str, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Dict[str, typing.Any]: # noinspection SpellCheckingInspection manifest = { @@ -638,15 +638,15 @@ def make_html_manifest( }, } - if image or no_env_management_py or no_env_management_r: + if image or disable_env_management_py or disable_env_management_r: manifest["environment"] = {} if image: manifest["environment"]["image"] = image - if no_env_management_py or no_env_management_r: + if disable_env_management_py or disable_env_management_r: manifest["environment"]["environment_management"] = {} - if no_env_management_py: + if disable_env_management_py: manifest["environment"]["environment_management"]["python"] = False - if no_env_management_r: + if disable_env_management_r: manifest["environment"]["environment_management"]["r"] = False return manifest @@ -657,8 +657,8 @@ def make_notebook_html_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, check_output: typing.Callable = subprocess.check_output, ) -> typing.IO[bytes]: # noinspection SpellCheckingInspection @@ -694,7 +694,7 @@ def make_notebook_html_bundle( bundle_add_buffer(bundle, filename, output) # manifest - manifest = make_html_manifest(filename, image, no_env_management_py, no_env_management_r) + manifest = make_html_manifest(filename, image, disable_env_management_py, disable_env_management_r) bundle_add_buffer(bundle, "manifest.json", json.dumps(manifest, indent=2)) # rewind file pointer @@ -840,8 +840,8 @@ def make_api_manifest( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Tuple[typing.Dict[str, typing.Any], typing.List[str]]: """ Makes a manifest for an API. @@ -853,9 +853,9 @@ def make_api_manifest( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the manifest and a list of the files involved. """ @@ -874,7 +874,7 @@ def make_api_manifest( relevant_files = create_file_list(directory, extra_files, excludes) manifest = make_source_manifest(app_mode, environment, entry_point, None, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) manifest_add_buffer(manifest, environment.filename, environment.contents) @@ -890,8 +890,8 @@ def create_html_manifest( extra_files: typing.List[str] = None, excludes: typing.List[str] = None, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, **kwargs ) -> Manifest: """ @@ -907,9 +907,9 @@ def create_html_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the manifest data structure. """ @@ -939,7 +939,7 @@ def create_html_manifest( excludes.extend(list_environment_dirs(deploy_dir)) manifest = Manifest(app_mode=AppModes.STATIC, entrypoint=entrypoint, primary_html=entrypoint, - image=image, no_env_management_py=no_env_management_py, no_env_management_r=no_env_management_r) + image=image, disable_env_management_py=disable_env_management_py, disable_env_management_r=disable_env_management_r) manifest.deploy_dir = deploy_dir file_list = create_file_list(path, extra_files, excludes, use_abspath=True) @@ -955,8 +955,8 @@ def make_html_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an html bundle, given a path and/or entrypoint. @@ -968,9 +968,9 @@ def make_html_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: a file-like object containing the bundle tarball. """ @@ -1123,8 +1123,8 @@ def make_voila_bundle( force_generate: bool, environment: Environment, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, multi_notebook: bool = False, ) -> typing.IO[bytes]: """ @@ -1140,9 +1140,9 @@ def make_voila_bundle( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: a file-like object containing the bundle tarball. """ @@ -1176,8 +1176,8 @@ def make_api_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.IO[bytes]: """ Create an API bundle, given a directory path and a manifest. @@ -1189,15 +1189,15 @@ def make_api_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: a file-like object containing the bundle tarball. """ manifest, relevant_files = make_api_manifest( directory, entry_point, app_mode, environment, extra_files, excludes, - image, no_env_management_py, no_env_management_r, + image, disable_env_management_py, disable_env_management_r, ) bundle_file = tempfile.TemporaryFile(prefix="rsc_bundle") @@ -1251,8 +1251,8 @@ def make_quarto_manifest( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> typing.Tuple[typing.Dict[str, typing.Any], typing.List[str]]: """ Makes a manifest for a Quarto project. @@ -1264,9 +1264,9 @@ def make_quarto_manifest( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the manifest and a list of the files involved. """ @@ -1308,8 +1308,8 @@ def make_quarto_manifest( None, quarto_inspection, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, ) if environment: @@ -1599,8 +1599,8 @@ def create_notebook_manifest_and_environment_file( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given notebook entry point file. @@ -1620,16 +1620,16 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: """ if ( not write_notebook_manifest_json( entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, - image, no_env_management_py, no_env_management_r, + image, disable_env_management_py, disable_env_management_r, ) or force ): @@ -1644,8 +1644,8 @@ def write_notebook_manifest_json( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1663,9 +1663,9 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. @@ -1682,7 +1682,7 @@ def write_notebook_manifest_json( raise RSConnectException('Could not determine the app mode from "%s"; please specify one.' % extension) manifest_data = make_source_manifest(app_mode, environment, file_name, None, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) if hide_all_input or hide_tagged_input: if "jupyter" not in manifest_data: manifest_data["jupyter"] = dict() @@ -1720,8 +1720,8 @@ def create_voila_manifest( excludes: typing.List[str] = None, force_generate: bool = True, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, multi_notebook: bool = False, **kwargs ) -> Manifest: @@ -1738,9 +1738,9 @@ def create_voila_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: the manifest data structure. """ @@ -1780,7 +1780,7 @@ def create_voila_manifest( extra_files.append(voila_json_path) manifest = Manifest(app_mode=AppModes.JUPYTER_VOILA, environment=environment, entrypoint=entrypoint, - image=image, no_env_management_py=no_env_management_py, no_env_management_r=no_env_management_r) + image=image, disable_env_management_py=disable_env_management_py, disable_env_management_r=disable_env_management_r) manifest.deploy_dir = deploy_dir if entrypoint and isfile(entrypoint): validate_file_is_notebook(entrypoint) @@ -1803,8 +1803,8 @@ def write_voila_manifest_json( excludes: typing.List[str] = None, force_generate: bool = True, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, multi_notebook: bool = False, ) -> bool: """ @@ -1820,9 +1820,9 @@ def write_voila_manifest_json( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: whether the manifest was written. """ @@ -1845,8 +1845,8 @@ def create_api_manifest_and_environment_file( excludes: typing.List[str], force: bool, image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Python API entry point. If @@ -1863,15 +1863,15 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: """ if ( not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) or force ): write_environment_file(environment, directory) @@ -1885,8 +1885,8 @@ def write_api_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1901,16 +1901,16 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ extra_files = validate_extra_files(directory, extra_files) manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) @@ -1967,8 +1967,8 @@ def write_quarto_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, ) -> None: """ Creates and writes a manifest.json file for the given Quarto project. @@ -1980,15 +1980,15 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. """ extra_files = validate_extra_files(directory, extra_files) manifest, _ = make_quarto_manifest(directory, inspect, app_mode, environment, extra_files, excludes, - image, no_env_management_py, no_env_management_r) + image, disable_env_management_py, disable_env_management_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) diff --git a/rsconnect/main.py b/rsconnect/main.py index ae6b8ffe..61afb8dc 100644 --- a/rsconnect/main.py +++ b/rsconnect/main.py @@ -252,14 +252,14 @@ def runtime_environment_args(func): "server is configured to use off-host execution.", ) @click.option( - "--no-env-management-py", + "--disable-env-management-py", is_flag=True, help="Disable Python environment management. When this flag is provided, Connect will not " "perform any Python package installation. It is the user's responsibility to ensure required " "packages are installed in the runtime environment.", ) @click.option( - "--no-env-management-r", + "--disable-env-management-r", is_flag=True, help="Disable R environment management. When this flag is provided, Connect will not " "perform any R package installation. It is the user's responsibility to ensure required " @@ -842,8 +842,8 @@ def deploy_notebook( hide_tagged_input: bool, env_vars: typing.Dict[str, str], image: str, - no_env_management_py: bool, - no_env_management_r: bool, + disable_env_management_py: bool, + disable_env_management_r: bool, ): kwargs = locals() set_verbosity(verbose) @@ -870,8 +870,8 @@ def deploy_notebook( hide_all_input, hide_tagged_input, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, ) else: ce.make_bundle( @@ -882,8 +882,8 @@ def deploy_notebook( hide_all_input, hide_tagged_input, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, ) ce.deploy_bundle().save_deployed_info().emit_task_log() @@ -949,8 +949,8 @@ def deploy_voila( extra_files=None, exclude=None, image: str = "", - no_env_management_py: bool = False, - no_env_management_r: bool = False, + disable_env_management_py: bool = False, + disable_env_management_r: bool = False, title: str = None, env_vars: typing.Dict[str, str] = None, verbose: bool = False, @@ -982,8 +982,8 @@ def deploy_voila( force_generate, environment, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, multi_notebook=multi_notebook, ).deploy_bundle().save_deployed_info().emit_task_log() @@ -1115,8 +1115,8 @@ def deploy_quarto( extra_files, env_vars: typing.Dict[str, str], image: str, - no_env_management_py: bool, - no_env_management_r: bool, + disable_env_management_py: bool, + disable_env_management_r: bool, ): kwargs = locals() set_verbosity(verbose) @@ -1162,8 +1162,8 @@ def deploy_quarto( inspect, environment, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, ) .deploy_bundle() .save_deployed_info() @@ -1332,8 +1332,8 @@ def deploy_app( visibility: typing.Optional[str], env_vars: typing.Dict[str, str], image: str, - no_env_management_py: bool, - no_env_management_r: bool, + disable_env_management_py: bool, + disable_env_management_r: bool, account: str = None, token: str = None, secret: str = None, @@ -1361,8 +1361,8 @@ def deploy_app( extra_files, exclude, image=image, - no_env_management_py=no_env_management_py, - no_env_management_r=no_env_management_r, + disable_env_management_py=disable_env_management_py, + disable_env_management_r=disable_env_management_r, ) .deploy_bundle() .save_deployed_info() @@ -1464,8 +1464,8 @@ def write_manifest_notebook( file, extra_files, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, hide_all_input=None, hide_tagged_input=None, ): @@ -1493,8 +1493,8 @@ def write_manifest_notebook( hide_all_input, hide_tagged_input, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, ) if environment_file_exists and not force_generate: @@ -1565,8 +1565,8 @@ def write_manifest_voila( extra_files, exclude, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, multi_notebook, ): set_verbosity(verbose) @@ -1603,8 +1603,8 @@ def write_manifest_voila( exclude, force_generate, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, multi_notebook, ) @@ -1670,8 +1670,8 @@ def write_manifest_quarto( file_or_directory, extra_files, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, ): set_verbosity(verbose) @@ -1716,8 +1716,8 @@ def write_manifest_quarto( extra_files, exclude, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, ) @@ -1789,8 +1789,8 @@ def manifest_writer( directory, extra_files, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, ): _write_framework_manifest( overwrite, @@ -1804,8 +1804,8 @@ def manifest_writer( extra_files, app_mode, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, ) return manifest_writer @@ -1832,8 +1832,8 @@ def _write_framework_manifest( extra_files, app_mode, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, ): """ A common function for writing manifests for APIs as well as Dash, Streamlit, and Bokeh apps. @@ -1851,9 +1851,9 @@ def _write_framework_manifest( :param extra_files: any extra files that should be included. :param app_mode: the app mode to use. :param image: an optional docker image for off-host execution. - :param no_env_management_py: True indicates that the user is responsible for Python package installation + :param disable_env_management_py: True indicates that the user is responsible for Python package installation in the runtime environment. Default = False. - :param no_env_management_r: True indicates that the user is responsible for R package installation + :param disable_env_management_r: True indicates that the user is responsible for R package installation in the runtime environment. Default = False. """ set_verbosity(verbose) @@ -1879,8 +1879,8 @@ def _write_framework_manifest( extra_files, exclude, image, - no_env_management_py, - no_env_management_r, + disable_env_management_py, + disable_env_management_r, ) if environment_file_exists and not force_generate: diff --git a/tests/test_bundle.py b/tests/test_bundle.py index 81300bf0..e5b32e16 100644 --- a/tests/test_bundle.py +++ b/tests/test_bundle.py @@ -75,7 +75,7 @@ def test_make_notebook_source_bundle1(self): environment = detect_environment(directory) with make_notebook_source_bundle( nb_path, environment, None, hide_all_input=False, hide_tagged_input=False, - image=None, no_env_management_py=False, no_env_management_r=False, + image=None, disable_env_management_py=False, disable_env_management_r=False, ) as bundle, tarfile.open(mode="r:gz", fileobj=bundle) as tar: names = sorted(tar.getnames()) self.assertEqual( @@ -146,8 +146,8 @@ def test_make_notebook_source_bundle2(self): hide_all_input=False, hide_tagged_input=False, image="rstudio/connect:bionic", - no_env_management_py=True, - no_env_management_r=True, + disable_env_management_py=True, + disable_env_management_r=True, ) as bundle, tarfile.open(mode="r:gz", fileobj=bundle) as tar: names = sorted(tar.getnames()) self.assertEqual( @@ -583,7 +583,7 @@ def test_make_source_manifest(self): }, ) - # include no_env_management_py parameter + # include disable_env_management_py parameter manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, None, True, False) self.assertEqual( manifest, @@ -599,7 +599,7 @@ def test_make_source_manifest(self): }, ) - # include no_env_management_r parameter + # include disable_env_management_r parameter manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, None, False, True) self.assertEqual( manifest, @@ -985,9 +985,9 @@ def test_make_html_manifest(self): }, ) - # include no_env_management_py parameter + # include disable_env_management_py parameter manifest = make_html_manifest("abc.html", - no_env_management_py=True) + disable_env_management_py=True) # print(manifest) self.assertEqual( manifest, @@ -1005,9 +1005,9 @@ def test_make_html_manifest(self): }, ) - # include no_env_management_r parameter + # include disable_env_management_r parameter manifest = make_html_manifest("abc.html", - no_env_management_r=True) + disable_env_management_r=True) # print(manifest) self.assertEqual( manifest, @@ -1028,8 +1028,8 @@ def test_make_html_manifest(self): # include all runtime environment parameters manifest = make_html_manifest("abc.html", image="rstudio/connect:bionic", - no_env_management_py=True, - no_env_management_r=True) + disable_env_management_py=True, + disable_env_management_r=True) # print(manifest) self.assertEqual( manifest, @@ -2025,8 +2025,8 @@ def test_create_html_manifest(): single_file_index_file, None, image="rstudio/connect:bionic", - no_env_management_py=True, - no_env_management_r=True, + disable_env_management_py=True, + disable_env_management_r=True, ) assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) @@ -2043,12 +2043,12 @@ def test_create_html_manifest(): single_file_index_file, None, image="rstudio/connect:bionic", - no_env_management_py=None, - no_env_management_r=None, + disable_env_management_py=None, + disable_env_management_r=None, ) assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) - # check no_env_management_py param + # check disable_env_management_py param single_file_index_file_ans = { "version": 1, "metadata": {"appmode": "static", "primary_html": "index.html", "entrypoint": "index.html"}, @@ -2062,11 +2062,11 @@ def test_create_html_manifest(): manifest = create_html_manifest( single_file_index_file, None, - no_env_management_py=True, + disable_env_management_py=True, ) assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) - # check no_env_management_r param + # check disable_env_management_r param single_file_index_file_ans = { "version": 1, "metadata": {"appmode": "static", "primary_html": "index.html", "entrypoint": "index.html"}, @@ -2080,7 +2080,7 @@ def test_create_html_manifest(): manifest = create_html_manifest( single_file_index_file, None, - no_env_management_r=True, + disable_env_management_r=True, ) assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) From 00dacdea9503b3ffc8512308d1f0541bd38e0da8 Mon Sep 17 00:00:00 2001 From: David Kegley Date: Fri, 4 Aug 2023 14:38:44 -0400 Subject: [PATCH 06/10] Add shorthand disable_env_management flag, make api params non-negative and nullable --- CHANGELOG.md | 10 +- rsconnect/actions.py | 208 +++++++++++++++++------------------ rsconnect/bundle.py | 251 +++++++++++++++++++++---------------------- rsconnect/main.py | 128 +++++++++++++--------- tests/test_bundle.py | 50 +++++---- 5 files changed, 341 insertions(+), 306 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1bbed6ac..a0cb8990 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Add `--disable-env-management-py` and `--disable-env-management-r` flags for all content types that support environment restores (non static). - This flag indicates to Connect that the user is responsible for Python/R package installation and Connect should not install - packages during the build. The Python/R packages must still be available in the runtime environment in order to run the content. - This is especially useful if off-host execution is enabled when the execution environment (specified by `--image`) already contains the required - packages. Requires Posit Connect `>=2023.07.0`. +- Add `--disable-env-management`, `--disable-env-management-py` and `--disable-env-management-r` flags for all content types + that support environment restores. These flags indicate to Connect that the user is responsible for Python/R package + installation, and Connect should not install packages during the build. The Python/R packages must still be available in the runtime + environment in order to run the content. This is especially useful if off-host execution is enabled when the execution environment + (specified by `--image`) already contains the required packages. Requires Posit Connect `>=2023.07.0`. ## [1.19.1] - 2023-08-01 diff --git a/rsconnect/actions.py b/rsconnect/actions.py index 214e3de7..39c7cfd8 100644 --- a/rsconnect/actions.py +++ b/rsconnect/actions.py @@ -527,8 +527,8 @@ def write_quarto_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> None: """ Creates and writes a manifest.json file for the given Quarto project. @@ -540,10 +540,10 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) @@ -555,8 +555,8 @@ def write_quarto_manifest_json( extra_files, excludes, image, - disable_env_management_py, - disable_env_management_r, + env_management_py, + env_management_r, ) base_dir = file_or_directory @@ -632,8 +632,8 @@ def deploy_jupyter_notebook( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> None: """ A function to deploy a Jupyter notebook to Connect. Depending on the files involved @@ -661,10 +661,10 @@ def deploy_jupyter_notebook( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -713,8 +713,8 @@ def deploy_jupyter_notebook( hide_all_input, hide_tagged_input, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, ) else: ce.make_bundle( @@ -725,8 +725,8 @@ def deploy_jupyter_notebook( hide_all_input, hide_tagged_input, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, ) ce.deploy_bundle().save_deployed_info().emit_task_log() @@ -765,8 +765,8 @@ def deploy_app( extra_files: typing.List[str] = None, env_vars: typing.Dict[str, str] = None, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, account: str = None, token: str = None, secret: str = None, @@ -818,8 +818,8 @@ def deploy_app( extra_files, excludes, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, ) .deploy_bundle() .save_deployed_info() @@ -841,8 +841,8 @@ def deploy_python_api( force_generate: bool, log_callback: typing.Callable, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python WSGi API module to Connect. Depending on the files involved @@ -867,10 +867,10 @@ def deploy_python_api( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -891,8 +891,8 @@ def deploy_python_fastapi( force_generate: bool, log_callback: typing.Callable, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python ASGI API module to Posit Connect. Depending on the files involved @@ -917,10 +917,10 @@ def deploy_python_fastapi( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -983,8 +983,8 @@ def deploy_dash_app( force_generate: bool, log_callback: typing.Callable, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Dash app module to Connect. Depending on the files involved @@ -1009,10 +1009,10 @@ def deploy_dash_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1033,8 +1033,8 @@ def deploy_streamlit_app( force_generate: bool, log_callback: typing.Callable, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Streamlit app module to Connect. Depending on the files involved @@ -1059,10 +1059,10 @@ def deploy_streamlit_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1083,8 +1083,8 @@ def deploy_bokeh_app( force_generate: bool, log_callback: typing.Callable, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Tuple[str, typing.Union[list, None]]: """ A function to deploy a Python Bokeh app module to Connect. Depending on the files involved @@ -1109,10 +1109,10 @@ def deploy_bokeh_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1196,8 +1196,8 @@ def create_notebook_deployment_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1215,10 +1215,10 @@ def create_notebook_deployment_bundle( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the bundle. """ @@ -1235,8 +1235,8 @@ def create_notebook_deployment_bundle( hide_all_input, hide_tagged_input, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, ) except subprocess.CalledProcessError as exc: # Jupyter rendering failures are often due to @@ -1250,8 +1250,8 @@ def create_notebook_deployment_bundle( hide_all_input, hide_tagged_input, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, ) @@ -1264,8 +1264,8 @@ def create_api_deployment_bundle( environment: Environment, extra_files_need_validating: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1281,10 +1281,10 @@ def create_api_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the bundle. """ entry_point = validate_entry_point(entry_point, directory) @@ -1296,7 +1296,7 @@ def create_api_deployment_bundle( app_mode = AppModes.PYTHON_API return make_api_bundle(directory, entry_point, app_mode, environment, extra_files, excludes, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) def create_quarto_deployment_bundle( @@ -1307,8 +1307,8 @@ def create_quarto_deployment_bundle( inspect: typing.Dict[str, typing.Any], environment: Environment, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.IO[bytes]: """ Create an in-memory bundle, ready to deploy. @@ -1324,17 +1324,17 @@ def create_quarto_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the bundle. """ if app_mode is None: app_mode = AppModes.STATIC_QUARTO return make_quarto_source_bundle(file_or_directory, inspect, app_mode, environment, extra_files, excludes, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) def deploy_bundle( @@ -1412,8 +1412,8 @@ def create_notebook_manifest_and_environment_file( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> None: """ Creates and writes a manifest.json file for the given notebook entry point file. @@ -1433,17 +1433,17 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) if ( not write_notebook_manifest_json( entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, - image, disable_env_management_py, disable_env_management_r, + image, env_management_py, env_management_r, ) or force ): @@ -1458,8 +1458,8 @@ def write_notebook_manifest_json( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1477,10 +1477,10 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ @@ -1497,7 +1497,7 @@ def write_notebook_manifest_json( raise RSConnectException('Could not determine the app mode from "%s"; please specify one.' % extension) manifest_data = make_source_manifest(app_mode, environment, file_name, None, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) manifest_add_file(manifest_data, file_name, directory) manifest_add_buffer(manifest_data, environment.filename, environment.contents) @@ -1518,8 +1518,8 @@ def create_api_manifest_and_environment_file( excludes: typing.List[str], force: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> None: """ Creates and writes a manifest.json file for the given Python API entry point. If @@ -1536,16 +1536,16 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) if ( not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) or force ): write_environment_file(environment, directory) @@ -1559,8 +1559,8 @@ def write_api_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1575,17 +1575,17 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) extra_files = validate_extra_files(directory, extra_files) manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) diff --git a/rsconnect/bundle.py b/rsconnect/bundle.py index c99c5b91..6d1cfb85 100644 --- a/rsconnect/bundle.py +++ b/rsconnect/bundle.py @@ -66,8 +66,8 @@ def __init__( entrypoint: str = None, quarto_inspection: dict = None, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, primary_html: str = None, metadata: dict = None, files: dict = None, @@ -121,16 +121,16 @@ def __init__( } - if image or disable_env_management_py or disable_env_management_r: + if image or env_management_py is not None or env_management_r is not None: self.data["environment"] = {} if image: self.data["environment"]["image"] = image - if disable_env_management_py or disable_env_management_r: + if env_management_py is not None or env_management_r is not None: self.data["environment"]["environment_management"] = {} - if disable_env_management_py: - self.data["environment"]["environment_management"]["python"] = False - if disable_env_management_r: - self.data["environment"]["environment_management"]["r"] = False + if env_management_py is not None: + self.data["environment"]["environment_management"]["python"] = env_management_py + if env_management_r is not None: + self.data["environment"]["environment_management"]["r"] = env_management_r self.data["files"] = {} if files: @@ -307,8 +307,8 @@ def make_source_manifest( entrypoint: str, quarto_inspection: typing.Dict[str, typing.Any], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Dict[str, typing.Any]: manifest = { "version": 1, @@ -350,17 +350,16 @@ def make_source_manifest( }, } - - if image or disable_env_management_py or disable_env_management_r: + if image or env_management_py is not None or env_management_r is not None: manifest["environment"] = {} if image: manifest["environment"]["image"] = image - if disable_env_management_py or disable_env_management_r: + if env_management_py is not None or env_management_r is not None: manifest["environment"]["environment_management"] = {} - if disable_env_management_py: - manifest["environment"]["environment_management"]["python"] = False - if disable_env_management_r: - manifest["environment"]["environment_management"]["r"] = False + if env_management_py is not None: + manifest["environment"]["environment_management"]["python"] = env_management_py + if env_management_r is not None: + manifest["environment"]["environment_management"]["r"] = env_management_r manifest["files"] = {} @@ -453,8 +452,8 @@ def write_manifest( hide_all_input: bool = False, hide_tagged_input: bool = False, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Tuple[list, list]: """Create a manifest for source publishing the specified notebook. @@ -465,7 +464,7 @@ def write_manifest( """ manifest_filename = "manifest.json" manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) if hide_all_input: if "jupyter" not in manifest: manifest["jupyter"] = {} @@ -534,8 +533,8 @@ def make_notebook_source_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.IO[bytes]: """Create a bundle containing the specified notebook and python environment. @@ -547,7 +546,7 @@ def make_notebook_source_bundle( nb_name = basename(file) manifest = make_source_manifest(AppModes.JUPYTER_NOTEBOOK, environment, nb_name, None, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) if hide_all_input: if "jupyter" not in manifest: manifest["jupyter"] = {} @@ -590,8 +589,8 @@ def make_quarto_source_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.IO[bytes]: """ Create a bundle containing the specified Quarto content and (optional) @@ -601,7 +600,7 @@ def make_quarto_source_bundle( """ manifest, relevant_files = make_quarto_manifest( file_or_directory, inspect, app_mode, environment, extra_files, excludes, - image, disable_env_management_py, disable_env_management_r, + image, env_management_py, env_management_r, ) bundle_file = tempfile.TemporaryFile(prefix="rsc_bundle") @@ -626,8 +625,8 @@ def make_quarto_source_bundle( def make_html_manifest( filename: str, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Dict[str, typing.Any]: # noinspection SpellCheckingInspection manifest = { @@ -638,16 +637,16 @@ def make_html_manifest( }, } - if image or disable_env_management_py or disable_env_management_r: + if image or env_management_py is not None or env_management_r is not None: manifest["environment"] = {} if image: manifest["environment"]["image"] = image - if disable_env_management_py or disable_env_management_r: + if env_management_py is not None or env_management_r is not None: manifest["environment"]["environment_management"] = {} - if disable_env_management_py: - manifest["environment"]["environment_management"]["python"] = False - if disable_env_management_r: - manifest["environment"]["environment_management"]["r"] = False + if env_management_py is not None: + manifest["environment"]["environment_management"]["python"] = env_management_py + if env_management_r is not None: + manifest["environment"]["environment_management"]["r"] = env_management_r return manifest @@ -657,8 +656,8 @@ def make_notebook_html_bundle( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, check_output: typing.Callable = subprocess.check_output, ) -> typing.IO[bytes]: # noinspection SpellCheckingInspection @@ -694,7 +693,7 @@ def make_notebook_html_bundle( bundle_add_buffer(bundle, filename, output) # manifest - manifest = make_html_manifest(filename, image, disable_env_management_py, disable_env_management_r) + manifest = make_html_manifest(filename, image, env_management_py, env_management_r) bundle_add_buffer(bundle, "manifest.json", json.dumps(manifest, indent=2)) # rewind file pointer @@ -840,8 +839,8 @@ def make_api_manifest( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Tuple[typing.Dict[str, typing.Any], typing.List[str]]: """ Makes a manifest for an API. @@ -853,10 +852,10 @@ def make_api_manifest( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the manifest and a list of the files involved. """ if is_environment_dir(directory): @@ -874,7 +873,7 @@ def make_api_manifest( relevant_files = create_file_list(directory, extra_files, excludes) manifest = make_source_manifest(app_mode, environment, entry_point, None, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) manifest_add_buffer(manifest, environment.filename, environment.contents) @@ -890,8 +889,8 @@ def create_html_manifest( extra_files: typing.List[str] = None, excludes: typing.List[str] = None, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, **kwargs ) -> Manifest: """ @@ -907,10 +906,10 @@ def create_html_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the manifest data structure. """ if not path: @@ -939,7 +938,7 @@ def create_html_manifest( excludes.extend(list_environment_dirs(deploy_dir)) manifest = Manifest(app_mode=AppModes.STATIC, entrypoint=entrypoint, primary_html=entrypoint, - image=image, disable_env_management_py=disable_env_management_py, disable_env_management_r=disable_env_management_r) + image=image, env_management_py=env_management_py, env_management_r=env_management_r) manifest.deploy_dir = deploy_dir file_list = create_file_list(path, extra_files, excludes, use_abspath=True) @@ -955,8 +954,8 @@ def make_html_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.IO[bytes]: """ Create an html bundle, given a path and/or entrypoint. @@ -968,10 +967,10 @@ def make_html_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: a file-like object containing the bundle tarball. """ @@ -1123,8 +1122,8 @@ def make_voila_bundle( force_generate: bool, environment: Environment, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, multi_notebook: bool = False, ) -> typing.IO[bytes]: """ @@ -1140,10 +1139,10 @@ def make_voila_bundle( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: a file-like object containing the bundle tarball. """ @@ -1176,8 +1175,8 @@ def make_api_bundle( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.IO[bytes]: """ Create an API bundle, given a directory path and a manifest. @@ -1189,15 +1188,15 @@ def make_api_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: a file-like object containing the bundle tarball. """ manifest, relevant_files = make_api_manifest( directory, entry_point, app_mode, environment, extra_files, excludes, - image, disable_env_management_py, disable_env_management_r, + image, env_management_py, env_management_r, ) bundle_file = tempfile.TemporaryFile(prefix="rsc_bundle") @@ -1251,8 +1250,8 @@ def make_quarto_manifest( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> typing.Tuple[typing.Dict[str, typing.Any], typing.List[str]]: """ Makes a manifest for a Quarto project. @@ -1264,10 +1263,10 @@ def make_quarto_manifest( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the manifest and a list of the files involved. """ if environment: @@ -1308,8 +1307,8 @@ def make_quarto_manifest( None, quarto_inspection, image, - disable_env_management_py, - disable_env_management_r, + env_management_py, + env_management_r, ) if environment: @@ -1599,8 +1598,8 @@ def create_notebook_manifest_and_environment_file( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> None: """ Creates and writes a manifest.json file for the given notebook entry point file. @@ -1620,16 +1619,16 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: """ if ( not write_notebook_manifest_json( entry_point_file, environment, app_mode, extra_files, hide_all_input, hide_tagged_input, - image, disable_env_management_py, disable_env_management_r, + image, env_management_py, env_management_r, ) or force ): @@ -1644,8 +1643,8 @@ def write_notebook_manifest_json( hide_all_input: bool, hide_tagged_input: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1663,10 +1662,10 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ @@ -1682,7 +1681,7 @@ def write_notebook_manifest_json( raise RSConnectException('Could not determine the app mode from "%s"; please specify one.' % extension) manifest_data = make_source_manifest(app_mode, environment, file_name, None, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) if hide_all_input or hide_tagged_input: if "jupyter" not in manifest_data: manifest_data["jupyter"] = dict() @@ -1720,8 +1719,8 @@ def create_voila_manifest( excludes: typing.List[str] = None, force_generate: bool = True, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, multi_notebook: bool = False, **kwargs ) -> Manifest: @@ -1738,10 +1737,10 @@ def create_voila_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: the manifest data structure. """ if not path: @@ -1780,7 +1779,7 @@ def create_voila_manifest( extra_files.append(voila_json_path) manifest = Manifest(app_mode=AppModes.JUPYTER_VOILA, environment=environment, entrypoint=entrypoint, - image=image, disable_env_management_py=disable_env_management_py, disable_env_management_r=disable_env_management_r) + image=image, env_management_py=env_management_py, env_management_r=env_management_r) manifest.deploy_dir = deploy_dir if entrypoint and isfile(entrypoint): validate_file_is_notebook(entrypoint) @@ -1803,8 +1802,8 @@ def write_voila_manifest_json( excludes: typing.List[str] = None, force_generate: bool = True, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, multi_notebook: bool = False, ) -> bool: """ @@ -1820,10 +1819,10 @@ def write_voila_manifest_json( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: whether the manifest was written. """ manifest = create_voila_manifest(**locals()) @@ -1845,8 +1844,8 @@ def create_api_manifest_and_environment_file( excludes: typing.List[str], force: bool, image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> None: """ Creates and writes a manifest.json file for the given Python API entry point. If @@ -1863,15 +1862,15 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: """ if ( not write_api_manifest_json(directory, entry_point, environment, app_mode, extra_files, excludes, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) or force ): write_environment_file(environment, directory) @@ -1885,8 +1884,8 @@ def write_api_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> bool: """ Creates and writes a manifest.json file for the given entry point file. If @@ -1901,16 +1900,16 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ extra_files = validate_extra_files(directory, extra_files) manifest, _ = make_api_manifest(directory, entry_point, app_mode, environment, extra_files, excludes, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) @@ -1967,8 +1966,8 @@ def write_quarto_manifest_json( extra_files: typing.List[str], excludes: typing.List[str], image: str = None, - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + env_management_py: bool = None, + env_management_r: bool = None, ) -> None: """ Creates and writes a manifest.json file for the given Quarto project. @@ -1980,15 +1979,15 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. """ extra_files = validate_extra_files(directory, extra_files) manifest, _ = make_quarto_manifest(directory, inspect, app_mode, environment, extra_files, excludes, - image, disable_env_management_py, disable_env_management_r) + image, env_management_py, env_management_r) manifest_path = join(directory, "manifest.json") write_manifest_json(manifest_path, manifest) diff --git a/rsconnect/main.py b/rsconnect/main.py index 61afb8dc..3a746396 100644 --- a/rsconnect/main.py +++ b/rsconnect/main.py @@ -244,6 +244,19 @@ def wrapper(*args, **kwargs): return wrapper +# inverts bool args if they are provided, otherwise returns None +def env_management_callback(ctx, param, value): + # eval the shorthand flag if it was provided + disable_env_management = ctx.params.get('disable_env_management') + if disable_env_management is not None: + value = disable_env_management + + # invert env_management value if it was provided + if value is not None: + return not value + return value + + def runtime_environment_args(func): @click.option( "--image", @@ -251,19 +264,30 @@ def runtime_environment_args(func): help="Target image to be used during content build and execution. This option is only applicable if the Connect " "server is configured to use off-host execution.", ) + @click.option( + "--disable-env-management", + is_flag=True, + is_eager=True, + default=None, + help="Shorthand to disable environment management for both Python and R.", + ) @click.option( "--disable-env-management-py", + "env_management_py", is_flag=True, - help="Disable Python environment management. When this flag is provided, Connect will not " - "perform any Python package installation. It is the user's responsibility to ensure required " - "packages are installed in the runtime environment.", + default=None, + help="Disable Python environment management. Connect will not perform any Python package installation. " + "It is the user's responsibility to ensure required packages are installed in the runtime environment.", + callback=env_management_callback, ) @click.option( "--disable-env-management-r", + "env_management_r", is_flag=True, - help="Disable R environment management. When this flag is provided, Connect will not " - "perform any R package installation. It is the user's responsibility to ensure required " - "packages are installed in the runtime environment.", + default=None, + help="Disable R environment management. Connect will not perform any R package installation. " + "It is the user's responsibility to ensure required packages are installed in the runtime environment.", + callback=env_management_callback, ) @functools.wraps(func) def wrapper(*args, **kwargs): @@ -842,8 +866,9 @@ def deploy_notebook( hide_tagged_input: bool, env_vars: typing.Dict[str, str], image: str, - disable_env_management_py: bool, - disable_env_management_r: bool, + disable_env_management: bool, + env_management_py: bool, + env_management_r: bool, ): kwargs = locals() set_verbosity(verbose) @@ -870,8 +895,8 @@ def deploy_notebook( hide_all_input, hide_tagged_input, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, ) else: ce.make_bundle( @@ -882,8 +907,8 @@ def deploy_notebook( hide_all_input, hide_tagged_input, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, ) ce.deploy_bundle().save_deployed_info().emit_task_log() @@ -949,8 +974,9 @@ def deploy_voila( extra_files=None, exclude=None, image: str = "", - disable_env_management_py: bool = False, - disable_env_management_r: bool = False, + disable_env_management: bool = None, + env_management_py: bool = None, + env_management_r: bool = None, title: str = None, env_vars: typing.Dict[str, str] = None, verbose: bool = False, @@ -982,8 +1008,8 @@ def deploy_voila( force_generate, environment, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, multi_notebook=multi_notebook, ).deploy_bundle().save_deployed_info().emit_task_log() @@ -1115,8 +1141,9 @@ def deploy_quarto( extra_files, env_vars: typing.Dict[str, str], image: str, - disable_env_management_py: bool, - disable_env_management_r: bool, + disable_env_management: bool, + env_management_py: bool, + env_management_r: bool, ): kwargs = locals() set_verbosity(verbose) @@ -1162,8 +1189,8 @@ def deploy_quarto( inspect, environment, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, ) .deploy_bundle() .save_deployed_info() @@ -1332,8 +1359,9 @@ def deploy_app( visibility: typing.Optional[str], env_vars: typing.Dict[str, str], image: str, - disable_env_management_py: bool, - disable_env_management_r: bool, + disable_env_management: bool, + env_management_py: bool, + env_management_r: bool, account: str = None, token: str = None, secret: str = None, @@ -1361,8 +1389,8 @@ def deploy_app( extra_files, exclude, image=image, - disable_env_management_py=disable_env_management_py, - disable_env_management_r=disable_env_management_r, + env_management_py=env_management_py, + env_management_r=env_management_r, ) .deploy_bundle() .save_deployed_info() @@ -1464,8 +1492,9 @@ def write_manifest_notebook( file, extra_files, image, - disable_env_management_py, - disable_env_management_r, + disable_env_management, + env_management_py, + env_management_r, hide_all_input=None, hide_tagged_input=None, ): @@ -1493,8 +1522,8 @@ def write_manifest_notebook( hide_all_input, hide_tagged_input, image, - disable_env_management_py, - disable_env_management_r, + env_management_py, + env_management_r, ) if environment_file_exists and not force_generate: @@ -1565,8 +1594,9 @@ def write_manifest_voila( extra_files, exclude, image, - disable_env_management_py, - disable_env_management_r, + disable_env_management, + env_management_py, + env_management_r, multi_notebook, ): set_verbosity(verbose) @@ -1603,8 +1633,8 @@ def write_manifest_voila( exclude, force_generate, image, - disable_env_management_py, - disable_env_management_r, + env_management_py, + env_management_r, multi_notebook, ) @@ -1670,8 +1700,9 @@ def write_manifest_quarto( file_or_directory, extra_files, image, - disable_env_management_py, - disable_env_management_r, + disable_env_management, + env_management_py, + env_management_r, ): set_verbosity(verbose) @@ -1716,8 +1747,8 @@ def write_manifest_quarto( extra_files, exclude, image, - disable_env_management_py, - disable_env_management_r, + env_management_py, + env_management_r, ) @@ -1789,8 +1820,9 @@ def manifest_writer( directory, extra_files, image, - disable_env_management_py, - disable_env_management_r, + disable_env_management, + env_management_py, + env_management_r, ): _write_framework_manifest( overwrite, @@ -1804,8 +1836,8 @@ def manifest_writer( extra_files, app_mode, image, - disable_env_management_py, - disable_env_management_r, + env_management_py, + env_management_r, ) return manifest_writer @@ -1832,8 +1864,8 @@ def _write_framework_manifest( extra_files, app_mode, image, - disable_env_management_py, - disable_env_management_r, + env_management_py, + env_management_r, ): """ A common function for writing manifests for APIs as well as Dash, Streamlit, and Bokeh apps. @@ -1851,10 +1883,10 @@ def _write_framework_manifest( :param extra_files: any extra files that should be included. :param app_mode: the app mode to use. :param image: an optional docker image for off-host execution. - :param disable_env_management_py: True indicates that the user is responsible for Python package installation - in the runtime environment. Default = False. - :param disable_env_management_r: True indicates that the user is responsible for R package installation - in the runtime environment. Default = False. + :param env_management_py: False indicates that the user is responsible for Python package installation + in the runtime environment. Default = None. + :param env_management_r: False indicates that the user is responsible for R package installation + in the runtime environment. Default = None. """ set_verbosity(verbose) @@ -1879,8 +1911,8 @@ def _write_framework_manifest( extra_files, exclude, image, - disable_env_management_py, - disable_env_management_r, + env_management_py, + env_management_r, ) if environment_file_exists and not force_generate: diff --git a/tests/test_bundle.py b/tests/test_bundle.py index e5b32e16..d87ff20a 100644 --- a/tests/test_bundle.py +++ b/tests/test_bundle.py @@ -75,7 +75,7 @@ def test_make_notebook_source_bundle1(self): environment = detect_environment(directory) with make_notebook_source_bundle( nb_path, environment, None, hide_all_input=False, hide_tagged_input=False, - image=None, disable_env_management_py=False, disable_env_management_r=False, + image=None, env_management_py=None, env_management_r=None, ) as bundle, tarfile.open(mode="r:gz", fileobj=bundle) as tar: names = sorted(tar.getnames()) self.assertEqual( @@ -146,8 +146,8 @@ def test_make_notebook_source_bundle2(self): hide_all_input=False, hide_tagged_input=False, image="rstudio/connect:bionic", - disable_env_management_py=True, - disable_env_management_r=True, + env_management_py=False, + env_management_r=False, ) as bundle, tarfile.open(mode="r:gz", fileobj=bundle) as tar: names = sorted(tar.getnames()) self.assertEqual( @@ -570,7 +570,8 @@ def test_make_source_manifest(self): ) # include image parameter - manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, "rstudio/connect:bionic") + manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, + image="rstudio/connect:bionic") self.assertEqual( manifest, { @@ -583,8 +584,9 @@ def test_make_source_manifest(self): }, ) - # include disable_env_management_py parameter - manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, None, True, False) + # include env_management_py parameter + manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, + env_management_py=False) self.assertEqual( manifest, { @@ -599,8 +601,9 @@ def test_make_source_manifest(self): }, ) - # include disable_env_management_r parameter - manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, None, False, True) + # include env_management_r parameter + manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, + env_management_r=False) self.assertEqual( manifest, { @@ -616,7 +619,8 @@ def test_make_source_manifest(self): ) # include all runtime environment parameters - manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, "rstudio/connect:bionic", True, True) + manifest = make_source_manifest(AppModes.PYTHON_API, None, None, None, + image="rstudio/connect:bionic", env_management_py=False, env_management_r=False) self.assertEqual( manifest, { @@ -985,9 +989,9 @@ def test_make_html_manifest(self): }, ) - # include disable_env_management_py parameter + # include env_management_py parameter manifest = make_html_manifest("abc.html", - disable_env_management_py=True) + env_management_py=False) # print(manifest) self.assertEqual( manifest, @@ -1005,9 +1009,9 @@ def test_make_html_manifest(self): }, ) - # include disable_env_management_r parameter + # include env_management_r parameter manifest = make_html_manifest("abc.html", - disable_env_management_r=True) + env_management_r=False) # print(manifest) self.assertEqual( manifest, @@ -1028,8 +1032,8 @@ def test_make_html_manifest(self): # include all runtime environment parameters manifest = make_html_manifest("abc.html", image="rstudio/connect:bionic", - disable_env_management_py=True, - disable_env_management_r=True) + env_management_py=False, + env_management_r=False) # print(manifest) self.assertEqual( manifest, @@ -2025,8 +2029,8 @@ def test_create_html_manifest(): single_file_index_file, None, image="rstudio/connect:bionic", - disable_env_management_py=True, - disable_env_management_r=True, + env_management_py=False, + env_management_r=False, ) assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) @@ -2043,12 +2047,12 @@ def test_create_html_manifest(): single_file_index_file, None, image="rstudio/connect:bionic", - disable_env_management_py=None, - disable_env_management_r=None, + env_management_py=None, + env_management_r=None, ) assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) - # check disable_env_management_py param + # check env_management_py param single_file_index_file_ans = { "version": 1, "metadata": {"appmode": "static", "primary_html": "index.html", "entrypoint": "index.html"}, @@ -2062,11 +2066,11 @@ def test_create_html_manifest(): manifest = create_html_manifest( single_file_index_file, None, - disable_env_management_py=True, + env_management_py=False, ) assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) - # check disable_env_management_r param + # check env_management_r param single_file_index_file_ans = { "version": 1, "metadata": {"appmode": "static", "primary_html": "index.html", "entrypoint": "index.html"}, @@ -2080,7 +2084,7 @@ def test_create_html_manifest(): manifest = create_html_manifest( single_file_index_file, None, - disable_env_management_r=True, + env_management_r=False, ) assert single_file_index_file_ans == json.loads(manifest.flattened_copy.json) From 4a43eae61bebb8477cce87b67b467ced973ad4c5 Mon Sep 17 00:00:00 2001 From: David Kegley Date: Fri, 4 Aug 2023 16:03:56 -0400 Subject: [PATCH 07/10] Fix black linting errors --- rsconnect/bundle.py | 2 +- rsconnect/main.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rsconnect/bundle.py b/rsconnect/bundle.py index 6d1cfb85..905921d3 100644 --- a/rsconnect/bundle.py +++ b/rsconnect/bundle.py @@ -635,7 +635,7 @@ def make_html_manifest( "appmode": "static", "primary_html": filename, }, - } + } # type: typing.Dict[str, typing.Any] if image or env_management_py is not None or env_management_r is not None: manifest["environment"] = {} diff --git a/rsconnect/main.py b/rsconnect/main.py index 3a746396..c6c83cf6 100644 --- a/rsconnect/main.py +++ b/rsconnect/main.py @@ -261,8 +261,8 @@ def runtime_environment_args(func): @click.option( "--image", "-I", - help="Target image to be used during content build and execution. This option is only applicable if the Connect " - "server is configured to use off-host execution.", + help="Target image to be used during content build and execution. " + "This option is only applicable if the Connect server is configured to use off-host execution.", ) @click.option( "--disable-env-management", From 04ab9983de28336ec0c36c536c787257070c3afa Mon Sep 17 00:00:00 2001 From: David Kegley Date: Mon, 7 Aug 2023 12:06:12 -0400 Subject: [PATCH 08/10] Update help text and docstrings for env_managment args --- rsconnect/actions.py | 112 +++++++++++++++++++++---------------------- rsconnect/bundle.py | 104 ++++++++++++++++++++-------------------- rsconnect/main.py | 31 +++++++----- 3 files changed, 127 insertions(+), 120 deletions(-) diff --git a/rsconnect/actions.py b/rsconnect/actions.py index 39c7cfd8..4af40e60 100644 --- a/rsconnect/actions.py +++ b/rsconnect/actions.py @@ -540,10 +540,10 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) @@ -661,10 +661,10 @@ def deploy_jupyter_notebook( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -867,10 +867,10 @@ def deploy_python_api( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -917,10 +917,10 @@ def deploy_python_fastapi( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1009,10 +1009,10 @@ def deploy_dash_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1059,10 +1059,10 @@ def deploy_streamlit_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1109,10 +1109,10 @@ def deploy_bokeh_app( If a log callback is provided, then None will be returned for the log lines part of the return tuple. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the ultimate URL where the deployed app may be accessed and the sequence of log lines. The log lines value will be None if a log callback was provided. """ @@ -1215,10 +1215,10 @@ def create_notebook_deployment_bundle( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the bundle. """ @@ -1281,10 +1281,10 @@ def create_api_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the bundle. """ entry_point = validate_entry_point(entry_point, directory) @@ -1324,10 +1324,10 @@ def create_quarto_deployment_bundle( with the specified directory. If you provide False here, make sure the names are properly qualified first. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the bundle. """ if app_mode is None: @@ -1433,10 +1433,10 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) @@ -1477,10 +1477,10 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ @@ -1536,10 +1536,10 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: """ warn("This method has been moved and will be deprecated.", DeprecationWarning, stacklevel=2) @@ -1575,10 +1575,10 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ diff --git a/rsconnect/bundle.py b/rsconnect/bundle.py index 905921d3..d48693c6 100644 --- a/rsconnect/bundle.py +++ b/rsconnect/bundle.py @@ -852,10 +852,10 @@ def make_api_manifest( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the manifest and a list of the files involved. """ if is_environment_dir(directory): @@ -906,10 +906,10 @@ def create_html_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the manifest data structure. """ if not path: @@ -967,10 +967,10 @@ def make_html_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: a file-like object containing the bundle tarball. """ @@ -1139,10 +1139,10 @@ def make_voila_bundle( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: a file-like object containing the bundle tarball. """ @@ -1188,10 +1188,10 @@ def make_api_bundle( :param extra_files: a sequence of any extra files to include in the bundle. :param excludes: a sequence of glob patterns that will exclude matched files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: a file-like object containing the bundle tarball. """ manifest, relevant_files = make_api_manifest( @@ -1263,10 +1263,10 @@ def make_quarto_manifest( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the manifest and a list of the files involved. """ if environment: @@ -1619,10 +1619,10 @@ def create_notebook_manifest_and_environment_file( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: an optional docker image for off-host execution. Previous default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: """ if ( @@ -1662,10 +1662,10 @@ def write_notebook_manifest_json( :param hide_tagged_input: If True, will hide input code cells with the 'hide_input' tag when rendering output. Previous default = False. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ @@ -1737,10 +1737,10 @@ def create_voila_manifest( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: the manifest data structure. """ if not path: @@ -1819,10 +1819,10 @@ def write_voila_manifest_json( :param excludes: a sequence of glob patterns that will exclude matched files. :param force_generate: bool indicating whether to force generate manifest and related environment files. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: whether the manifest was written. """ manifest = create_voila_manifest(**locals()) @@ -1862,10 +1862,10 @@ def create_api_manifest_and_environment_file( :param force: if True, forces the environment file to be written. even if it already exists. Previous default = True. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: """ if ( @@ -1900,10 +1900,10 @@ def write_api_manifest_json( :param extra_files: any extra files that should be included in the manifest. Previous default = None. :param excludes: a sequence of glob patterns that will exclude matched files. Previous default = None. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. :return: whether or not the environment file (requirements.txt, environment.yml, etc.) that goes along with the manifest exists. """ @@ -1979,10 +1979,10 @@ def write_quarto_manifest_json( :param extra_files: Any extra files to include in the manifest. :param excludes: A sequence of glob patterns to exclude when enumerating files to bundle. :param image: the optional docker image to be specified for off-host execution. Default = None. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. """ extra_files = validate_extra_files(directory, extra_files) diff --git a/rsconnect/main.py b/rsconnect/main.py index c6c83cf6..0ab05a40 100644 --- a/rsconnect/main.py +++ b/rsconnect/main.py @@ -243,15 +243,20 @@ def wrapper(*args, **kwargs): return wrapper - -# inverts bool args if they are provided, otherwise returns None -def env_management_callback(ctx, param, value): +# This callback handles the "shorthand" --disable-env-management option. +# If the shorthand flag is provided, then it takes precendence over the R and Python flags. +# This callback also inverts the --disable-env-management-r and +# --disable-env-management-py boolean flags if they are provided, +# otherwise returns None. This is so that we can pass the +# non-negative (env_management_r, env_management_py) args to our API functions, +# which is more consistent when writing these values to the manifest. +def env_management_callback(ctx, param, value) -> typing.Optional[bool]: # eval the shorthand flag if it was provided disable_env_management = ctx.params.get('disable_env_management') if disable_env_management is not None: value = disable_env_management - # invert env_management value if it was provided + # invert value if it is defined. if value is not None: return not value return value @@ -276,8 +281,9 @@ def runtime_environment_args(func): "env_management_py", is_flag=True, default=None, - help="Disable Python environment management. Connect will not perform any Python package installation. " - "It is the user's responsibility to ensure required packages are installed in the runtime environment.", + help="Disable Python environment management for this bundle. " + "Connect will not create an environment or install packages. An administrator must install the " + " required packages in the correct Python environment on the Connect server.", callback=env_management_callback, ) @click.option( @@ -285,8 +291,9 @@ def runtime_environment_args(func): "env_management_r", is_flag=True, default=None, - help="Disable R environment management. Connect will not perform any R package installation. " - "It is the user's responsibility to ensure required packages are installed in the runtime environment.", + help="Disable R environment management for this bundle. " + "Connect will not create an environment or install packages. An administrator must install the " + " required packages in the correct R environment on the Connect server.", callback=env_management_callback, ) @functools.wraps(func) @@ -1883,10 +1890,10 @@ def _write_framework_manifest( :param extra_files: any extra files that should be included. :param app_mode: the app mode to use. :param image: an optional docker image for off-host execution. - :param env_management_py: False indicates that the user is responsible for Python package installation - in the runtime environment. Default = None. - :param env_management_r: False indicates that the user is responsible for R package installation - in the runtime environment. Default = None. + :param env_management_py: False prevents Connect from managing the Python environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. + :param env_management_r: False prevents Connect from managing the R environment for this bundle. + The server administrator is responsible for installing packages in the runtime environment. Default = None. """ set_verbosity(verbose) From 7e3b4c68139e26efdf9cc7ff201e17d9212cc183 Mon Sep 17 00:00:00 2001 From: David Kegley Date: Mon, 7 Aug 2023 14:24:59 -0400 Subject: [PATCH 09/10] Add unit test for env_management_callback func --- tests/test_main.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/test_main.py b/tests/test_main.py index d7a0b0be..9d159bd4 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -7,6 +7,7 @@ import httpretty import pytest +import click from click.testing import CliRunner from rsconnect.json_web_token import SECRET_KEY_ENV @@ -22,7 +23,7 @@ require_connect, has_jwt_structure, ) -from rsconnect.main import cli +from rsconnect.main import cli, env_management_callback from rsconnect import VERSION @@ -746,6 +747,22 @@ def test_add_shinyapps_missing_options(self): os.environ["CONNECT_SERVER"] = original_server_value + def test_env_management_callback(self): + ctx = click.Context(cli) + + # env_management is always False when --disable-env-management is True + ctx.params = {'disable_env_management': True} + assert env_management_callback(ctx, None, None) is False + assert env_management_callback(ctx, None, True) is False + assert env_management_callback(ctx, None, False) is False + + # (env_management == not value) when --disable-env-management is None + ctx.params = {'disable_env_management': None} + assert env_management_callback(ctx, None, None) is None + assert env_management_callback(ctx, None, True) is False + assert env_management_callback(ctx, None, False) is True + + class TestBootstrap(TestCase): def setUp(self): self.mock_server = "http://localhost:8080" From 568e217ec7a76d68aaec69bf2555d4f6f7854b8c Mon Sep 17 00:00:00 2001 From: David Kegley Date: Fri, 18 Aug 2023 15:46:44 -0400 Subject: [PATCH 10/10] Fix spacing in help text --- rsconnect/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rsconnect/main.py b/rsconnect/main.py index 0ab05a40..c9b6e23c 100644 --- a/rsconnect/main.py +++ b/rsconnect/main.py @@ -283,7 +283,7 @@ def runtime_environment_args(func): default=None, help="Disable Python environment management for this bundle. " "Connect will not create an environment or install packages. An administrator must install the " - " required packages in the correct Python environment on the Connect server.", + "required packages in the correct Python environment on the Connect server.", callback=env_management_callback, ) @click.option( @@ -293,7 +293,7 @@ def runtime_environment_args(func): default=None, help="Disable R environment management for this bundle. " "Connect will not create an environment or install packages. An administrator must install the " - " required packages in the correct R environment on the Connect server.", + "required packages in the correct R environment on the Connect server.", callback=env_management_callback, ) @functools.wraps(func)