diff --git a/doc/changes/unreleased.md b/doc/changes/unreleased.md index 7d9e5f6..8419d6b 100644 --- a/doc/changes/unreleased.md +++ b/doc/changes/unreleased.md @@ -1,6 +1,11 @@ # Unreleased +## Summary ## Dependency Updates -* #130: Poetry relock \ No newline at end of file +* #130: Poetry relock + +## Features + +* #132: Simplified using `LanguageContainerDeployer` in TE and similar projects diff --git a/exasol/python_extension_common/cli/std_options.py b/exasol/python_extension_common/cli/std_options.py index 15421ca..f078844 100644 --- a/exasol/python_extension_common/cli/std_options.py +++ b/exasol/python_extension_common/cli/std_options.py @@ -32,7 +32,7 @@ class ParameterFormatters: the update if the value of the parameter dressed with the callback is None. """ - def __init__(self): + def __init__(self) -> None: self._formatters: dict[str, str] = {} def __call__(self, ctx: click.Context, param: click.Parameter, value: Any | None) -> Any | None: diff --git a/exasol/python_extension_common/deployment/language_container_deployer.py b/exasol/python_extension_common/deployment/language_container_deployer.py index 2f36045..1734e06 100644 --- a/exasol/python_extension_common/deployment/language_container_deployer.py +++ b/exasol/python_extension_common/deployment/language_container_deployer.py @@ -140,6 +140,20 @@ def __init__( def pyexasol_connection(self) -> pyexasol.ExaConnection: return self._pyexasol_conn + def download_url(self, version: str | None) -> str: + """ + Sub classes can override this method to infer the download url + from the version in `download_and_run()`. + """ + return "" + + def default_bucket_file_path(self, version: str | None) -> str: + """ + Sub classes can override this method to specify a default value + for `bucket_file_path` in `run()`. + """ + return "" + def download_and_run( self, url: str, @@ -148,21 +162,40 @@ def download_and_run( allow_override: bool = False, wait_for_completion: bool = True, print_activation_statements: bool = True, + version: str = "", ) -> None: """ - Downloads the language container from the provided url to a temporary file and then deploys it. - See docstring on the `run` method for details on what is involved in the deployment. + Downloads the language container from the provided url to a + temporary file and then deploys it. See docstring on the `run` method + for details on what is involved in the deployment. - url - Address where the container will be downloaded from. - bucket_file_path - Path within the designated bucket where the container should be uploaded. - alter_system - If True will try to activate the container at the System level. - allow_override - If True the activation of a language container with the same alias will be - overriden, otherwise a RuntimeException will be thrown. - wait_for_completion - If True will wait until the language container becomes operational. - print_activation_statements - If True and alter_system is False, - it will print the ALTER SESSION command to stdout. + Arguments: + + url: Address where the container will be downloaded from. If url is + empty, then method download_url(version) is called to retrieve a + default URL, that can depend on the version. + + bucket_file_path: Path within the designated bucket where the + container should be uploaded. + + alter_system: If True will try to activate the container at the System + level. + + allow_override: If True the activation of a language container with + the same alias will be overriden, otherwise a RuntimeException + will be thrown. + + wait_for_completion: If True will wait until the language container + becomes operational. + + print_activation_statements: If True and alter_system is False, it + will print the ALTER SESSION command to stdout. + + version: Optional argument to infer the download URL by calling method + self.download_url(version). """ + url = url or self.download_url(version) with tempfile.NamedTemporaryFile() as tmp_file: response = requests.get(url, stream=True, timeout=300) response.raise_for_status() @@ -175,6 +208,7 @@ def download_and_run( allow_override, wait_for_completion, print_activation_statements, + version, ) def _upload_path(self, bucket_file_path: str | None) -> bfs.path.PathLike: @@ -188,30 +222,54 @@ def run( allow_override: bool = False, wait_for_completion: bool = True, print_activation_statements: bool = True, + version: str = "", ) -> None: """ - Deploys the language container. This includes two steps, both of which are optional: - - Uploading the container into the database. This step can be skipped if the container - has already been uploaded. - - Activating the container. In case the container does not get activated at the System - level, two alternative activation SQL commands (one for the System and one for the Session - levels) will be printed on the console. + Deploys the language container. - container_file - Path of the container tar.gz file in a local file system. - If not provided the container is assumed to be uploaded already. - bucket_file_path - Path within the designated bucket where the container should be uploaded. - If not specified the name of the container file will be used instead. - alter_system - If True will try to activate the container at the System level. - allow_override - If True the activation of a language container with the same alias will be - overriden, otherwise a RuntimeException will be thrown. - wait_for_completion - If True will wait until the language container becomes operational. - For this to work either of the two conditions should be met. - The pyexasol connection should have an open schema, or - The calling user should have a permission to create schema. - print_activation_statements - If True and alter_system is False, - it will print the ALTER SESSION command to stdout. + This includes two steps, both of which are optional: + + * Uploading the container into the database. This step can be skipped + if the container has already been uploaded. + + * Activating the container. In case the container does not get + activated at the System level, two alternative activation SQL + commands (one for the System and one for the Session levels) will be + printed on the console. + + Arguments: + + container_file: Path of the container tar.gz file in a local file + system. If not provided the container is assumed to be uploaded + already. + + bucket_file_path: Path within the designated bucket where the + container should be uploaded. If not specified then method + default_bucket_file_path(version) is called to get a default + value. If still empty, then the name of the container file will be + used instead. + + alter_system: If True will try to activate the container at the System + level. + + allow_override: If True the activation of a language container with + the same alias will be overriden, otherwise a RuntimeException + will be thrown. + + wait_for_completion: If True will wait until the language container + becomes operational. For this to work either of the two conditions + should be met. The pyexasol connection should have an open schema, + or The calling user should have a permission to create schema. + + print_activation_statements: If True and alter_system is False, it + will print the ALTER SESSION command to stdout. + + version: Optional argument to infer the bucket_file_path by calling + method self.default_bucket_file_path(version). """ + bucket_file_path = bucket_file_path or self.default_bucket_file_path(version) + if not bucket_file_path: if not container_file: raise ValueError("Either a container file or a bucket file path must be specified.") @@ -237,10 +295,10 @@ def run( f""" In SQL, you can activate the SLC by using the following statements: - + To activate the SLC only for the current session: {self.generate_activation_command(bucket_file_path, LanguageActivationLevel.Session, True)} - + To activate the SLC on the system: {self.generate_activation_command(bucket_file_path, LanguageActivationLevel.System, True)} """