From d18cd8064fa253f4aba52a64a4c65fe3384bab20 Mon Sep 17 00:00:00 2001 From: Pontus Lurcock Date: Wed, 19 Mar 2025 10:57:14 +0100 Subject: [PATCH 1/9] Update copyright years --- LICENSE | 2 +- xcengine/cli.py | 2 +- xcengine/core.py | 2 +- xcengine/util.py | 2 +- xcengine/wrapper.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LICENSE b/LICENSE index eb79e6a..394c8aa 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2024 Brockmann Consult GmbH +Copyright (c) 2024-2025 Brockmann Consult GmbH Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/xcengine/cli.py b/xcengine/cli.py index 02060db..4f537b3 100644 --- a/xcengine/cli.py +++ b/xcengine/cli.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright (c) 2024 by Brockmann Consult GmbH +# Copyright (c) 2024-2025 by Brockmann Consult GmbH # Permissions are hereby granted under the terms of the MIT License: # https://opensource.org/licenses/MIT. diff --git a/xcengine/core.py b/xcengine/core.py index 182e86c..ff6fa1c 100755 --- a/xcengine/core.py +++ b/xcengine/core.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 by Brockmann Consult GmbH +# Copyright (c) 2024-2025 by Brockmann Consult GmbH # Permissions are hereby granted under the terms of the MIT License: # https://opensource.org/licenses/MIT. diff --git a/xcengine/util.py b/xcengine/util.py index f1f7a78..c909e95 100644 --- a/xcengine/util.py +++ b/xcengine/util.py @@ -1,4 +1,4 @@ -# Copyright (c) 2024 by Brockmann Consult GmbH +# Copyright (c) 2024-2025 by Brockmann Consult GmbH # Permissions are hereby granted under the terms of the MIT License: # https://opensource.org/licenses/MIT. from collections import namedtuple diff --git a/xcengine/wrapper.py b/xcengine/wrapper.py index 45c94d7..acd7a8b 100644 --- a/xcengine/wrapper.py +++ b/xcengine/wrapper.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 -# Copyright (c) 2024 by Brockmann Consult GmbH +# Copyright (c) 2024-2025 by Brockmann Consult GmbH # Permissions are hereby granted under the terms of the MIT License: # https://opensource.org/licenses/MIT. From e2d5529e8fc0eb0d86bfae14928842aaf8c4b769 Mon Sep 17 00:00:00 2001 From: Pontus Lurcock Date: Wed, 19 Mar 2025 14:19:07 +0100 Subject: [PATCH 2/9] Remove run options from "image build" subcommand These options complicate the UI and are redundant; effectively they duplicate the functionality of the "image run" subcommand. See Issue #3. --- xcengine/cli.py | 18 ++++-------------- xcengine/core.py | 17 +++-------------- 2 files changed, 7 insertions(+), 28 deletions(-) diff --git a/xcengine/cli.py b/xcengine/cli.py index 4f537b3..81a0b5a 100644 --- a/xcengine/cli.py +++ b/xcengine/cli.py @@ -113,9 +113,6 @@ def image_cli(): @image_cli.command( help="Build, and optionally run, a compute engine as a Docker image" ) -@batch_option -@server_option -@from_saved_option @click.option( "-b", "--build-dir", @@ -123,7 +120,6 @@ def image_cli(): help="Build directory to use for preparing the Docker image. If not " "specified, an automatically created temporary directory will be used.", ) -@keep_option @click.option( "-e", "--environment", @@ -150,10 +146,6 @@ def image_cli(): ) @notebook_argument def build( - batch: bool, - server: bool, - from_saved: bool, - keep: bool, build_dir: pathlib.Path, notebook: pathlib.Path, output: pathlib.Path, @@ -162,23 +154,21 @@ def build( eoap: pathlib.Path, ) -> None: init_args = dict( - notebook=notebook, output_dir=output, environment=environment, tag=tag - ) - build_args = dict( - run_batch=batch, run_server=server, from_saved=from_saved, keep=keep + notebook=notebook, environment=environment, tag=tag ) if build_dir: image_builder = ImageBuilder(build_dir=build_dir, **init_args) os.makedirs(build_dir, exist_ok=True) - image_builder.build(**build_args) + image = image_builder.build() else: with tempfile.TemporaryDirectory() as temp_dir: image_builder = ImageBuilder( build_dir=pathlib.Path(temp_dir), **init_args ) - image_builder.build(**build_args) + image = image_builder.build() if eoap: eoap.write_text(yaml.dump(image_builder.create_cwl())) + print(f"Built image with tags {image.tags}") @image_cli.command(help="Run a compute engine image as a Docker container") diff --git a/xcengine/core.py b/xcengine/core.py index ff6fa1c..096be4d 100755 --- a/xcengine/core.py +++ b/xcengine/core.py @@ -153,13 +153,11 @@ class ImageBuilder: def __init__( self, notebook: pathlib.Path, - output_dir: pathlib.Path, environment: pathlib.Path, build_dir: pathlib.Path, tag: str | None, ): self.notebook = notebook - self.output_dir = output_dir self.environment = environment self.build_dir = build_dir if tag is None: @@ -171,13 +169,7 @@ def __init__( self.tag = tag self.script_creator = ScriptCreator(self.notebook) - def build( - self, - run_batch: bool, - run_server: bool, - from_saved: bool, - keep: bool, - ) -> None: + def build(self) -> Image: self.script_creator.convert_notebook_to_script(self.build_dir) if self.environment: with open(self.environment, "r") as fh: @@ -192,10 +184,7 @@ def build( self.add_packages_to_environment(env_def, ["xcube", "pystac"]) with open(self.build_dir / "environment.yml", "w") as fh: fh.write(yaml.safe_dump(env_def)) - image: Image = self.build_image() - if run_batch or run_server: - runner = ContainerRunner(image, self.output_dir) - runner.run(run_batch, run_server, from_saved, keep) + return self._build_image() @staticmethod def export_conda_env() -> dict: @@ -253,7 +242,7 @@ def ensure_present(pkg: str): ensure_present(package) return conda_env - def build_image(self) -> docker.models.images.Image: + def _build_image(self) -> docker.models.images.Image: client = docker.from_env() dockerfile = textwrap.dedent( """ From 980954b285fbeb56036bbffba7432534c898fb37 Mon Sep 17 00:00:00 2001 From: Pontus Lurcock Date: Wed, 19 Mar 2025 18:00:47 +0100 Subject: [PATCH 3/9] Add host port option to run subcommand The "--server" option now takes an optional "port" argument. --- xcengine/cli.py | 31 ++++++++++++++++++------------- xcengine/core.py | 15 +++++++++------ 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/xcengine/cli.py b/xcengine/cli.py index 81a0b5a..c989a2f 100644 --- a/xcengine/cli.py +++ b/xcengine/cli.py @@ -30,13 +30,6 @@ def cli(verbose): "-b", "--batch", is_flag=True, help="Run as batch script after creating" ) -server_option = click.option( - "-s", - "--server", - is_flag=True, - help="Run as xcube server script after creating", -) - output_option = click.option( "-o", "--output", @@ -69,7 +62,12 @@ def cli(verbose): @cli.command(help="Create a compute engine script on the host system") @batch_option -@server_option +@click.option( + "-s", + "--server", + is_flag=True, + help="Run the script as an xcube server after creating it.", +) @from_saved_option @click.option( "-c", @@ -127,7 +125,6 @@ def image_cli(): help="Conda environment file to use in Docker image. " "If not specified, try to reproduce the current environment.", ) -@output_option @click.option( "-t", "--tag", @@ -148,7 +145,6 @@ def image_cli(): def build( build_dir: pathlib.Path, notebook: pathlib.Path, - output: pathlib.Path, environment: pathlib.Path, tag: str, eoap: pathlib.Path, @@ -173,14 +169,23 @@ def build( @image_cli.command(help="Run a compute engine image as a Docker container") @batch_option -@server_option +@click.option( + "-s", + "--server", + is_flag=False, + flag_value=-1, + type=int, + default="8080", + help="Run as xcube server after creating, mapping to specified " + "host port (default: 8080).", +) @from_saved_option @output_option @keep_option @click.argument("image", type=str) def run( batch: bool, - server: bool, + server: int, from_saved: bool, keep: bool, image: str, @@ -188,7 +193,7 @@ def run( ) -> None: runner = ContainerRunner(image=image, output_dir=output) runner.run( - run_batch=batch, run_server=server, from_saved=from_saved, keep=keep + run_batch=batch, server_port=server, from_saved=from_saved, keep=keep ) diff --git a/xcengine/core.py b/xcengine/core.py index 096be4d..f6020d5 100755 --- a/xcengine/core.py +++ b/xcengine/core.py @@ -306,23 +306,26 @@ def client(self): return self._client def run( - self, run_batch: bool, run_server: bool, from_saved: bool, keep: bool + self, run_batch: bool, server_port: int, from_saved: bool, keep: bool ): LOGGER.info(f"Running container from image {self.image.short_id}") LOGGER.info(f"Image tags: {' '.join(self.image.tags)}") command = ( ["python", "execute.py"] + (["--batch"] if run_batch else []) - + (["--server"] if run_server else []) + + (["--server"] if server_port > -1 else []) + (["--from-saved"] if from_saved else []) ) - container: Container = self.client.containers.run( + run_args = dict( image=self.image, command=command, - ports={"8080": 8080}, remove=False, - detach=True, + detach=True ) + if server_port > -1: + run_args["ports"] = {"8080": server_port} + print(run_args) + container: Container = self.client.containers.run(**run_args) LOGGER.info(f"Waiting for container {container.short_id} to complete.") while container.status in {"created", "running"}: LOGGER.debug( @@ -338,7 +341,7 @@ def run( ) self.extract_output_from_container(container) LOGGER.info(f"Results copied.") - if not run_server and not keep: + if server_port == -1 and not keep: LOGGER.info(f"Removing container {container.short_id}...") container.remove(force=True) LOGGER.info(f"Container {container.short_id} removed.") From d5ec7985ed8933b22a8af97d993cdc3736790625 Mon Sep 17 00:00:00 2001 From: Pontus Lurcock Date: Wed, 19 Mar 2025 18:03:08 +0100 Subject: [PATCH 4/9] Pint Python to <3.13 in example environment micromamba xcube install is currently broken: all current xcube packages are (directly or transitively) Python 3.13 incompatible, but older ones aren't marked as such, so without a pin micromamba installs Python 3.13 and incompatible xcube 1.7.1. --- examples/environment.yml | 2 +- examples/staging.ipynb | 100 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 examples/staging.ipynb diff --git a/examples/environment.yml b/examples/environment.yml index 51ff45d..6a9e275 100644 --- a/examples/environment.yml +++ b/examples/environment.yml @@ -2,6 +2,6 @@ name: xce-example-1 channels: - conda-forge dependencies: - - python >=3.10 + - python >=3.10,<3.13 - xcube >=1.7.1 - matplotlib-base diff --git a/examples/staging.ipynb b/examples/staging.ipynb new file mode 100644 index 0000000..57f0206 --- /dev/null +++ b/examples/staging.ipynb @@ -0,0 +1,100 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a7055ada-b79a-467f-bbc8-48b744367324", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "source": [ + "Parameters cell" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "fbb2fa57-fb9c-4b67-86c4-6fc02cfe9e12", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [ + "parameters" + ] + }, + "outputs": [], + "source": [ + "import xcube.core.new\n", + "\n", + "periods = 10\n", + "cube1 = xcube.core.new.new_cube(\n", + " variables={\"v\": lambda x, y, t: (x + y + t) % 10},\n", + " time_periods=periods\n", + ")\n", + "cube2 = xcube.core.new.new_cube(\n", + " variables={\"v\": lambda x, y, t: (x - y + t) % 10},\n", + " time_periods=periods\n", + ")\n", + "\n", + "del xcube" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "df9686d6-395b-4bfd-bd10-c7e03df5cf38", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [ + "cube1.attrs[\"title\"] = \"Cube 1\"\n", + "cube2.attrs[\"title\"] = \"Cube 2\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fb0b2d6-364a-4875-aa80-37e9f4e76abf", + "metadata": { + "editable": true, + "slideshow": { + "slide_type": "" + }, + "tags": [] + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From b95855c3410baba55695a38d51d235d2c80e6dba Mon Sep 17 00:00:00 2001 From: Pontus Lurcock Date: Wed, 19 Mar 2025 18:53:42 +0100 Subject: [PATCH 5/9] Add explicit --port option to run subcommand Click has trouble parsing optional parameters to options reliably, so --server is now a flag again and --port is a new option that always takes exactly one parameter. --- xcengine/cli.py | 41 ++++++++++++++++++++++++++--------------- xcengine/core.py | 20 ++++++++++---------- xcengine/wrapper.py | 5 ++++- 3 files changed, 40 insertions(+), 26 deletions(-) diff --git a/xcengine/cli.py b/xcengine/cli.py index c989a2f..bfc7f4c 100644 --- a/xcengine/cli.py +++ b/xcengine/cli.py @@ -12,6 +12,7 @@ import click import yaml +from click.core import ParameterSource from .core import ScriptCreator, ImageBuilder, ContainerRunner @@ -59,15 +60,17 @@ def cli(verbose): ), ) - -@cli.command(help="Create a compute engine script on the host system") -@batch_option -@click.option( +server_option = click.option( "-s", "--server", is_flag=True, help="Run the script as an xcube server after creating it.", ) + + +@cli.command(help="Create a compute engine script on the host system") +@batch_option +@server_option @from_saved_option @click.option( "-c", @@ -149,9 +152,7 @@ def build( tag: str, eoap: pathlib.Path, ) -> None: - init_args = dict( - notebook=notebook, environment=environment, tag=tag - ) + init_args = dict(notebook=notebook, environment=environment, tag=tag) if build_dir: image_builder = ImageBuilder(build_dir=build_dir, **init_args) os.makedirs(build_dir, exist_ok=True) @@ -169,31 +170,41 @@ def build( @image_cli.command(help="Run a compute engine image as a Docker container") @batch_option +@server_option @click.option( - "-s", - "--server", + "-p", + "--port", is_flag=False, - flag_value=-1, type=int, - default="8080", - help="Run as xcube server after creating, mapping to specified " - "host port (default: 8080).", + default=8080, + help="Host port for xcube server (default: 8080). Implies --server.", ) @from_saved_option @output_option @keep_option @click.argument("image", type=str) +@click.pass_context def run( + ctx: click.Context, batch: bool, - server: int, + server: False, + port: int, from_saved: bool, keep: bool, image: str, output: pathlib.Path, ) -> None: runner = ContainerRunner(image=image, output_dir=output) + port_specified_explicitly = ( + ctx.get_parameter_source("port") + is not click.core.ParameterSource.DEFAULT + ) + actual_port = port if server or port_specified_explicitly else None runner.run( - run_batch=batch, server_port=server, from_saved=from_saved, keep=keep + run_batch=batch, + host_port=actual_port, + from_saved=from_saved, + keep=keep, ) diff --git a/xcengine/core.py b/xcengine/core.py index f6020d5..2f71466 100755 --- a/xcengine/core.py +++ b/xcengine/core.py @@ -306,25 +306,25 @@ def client(self): return self._client def run( - self, run_batch: bool, server_port: int, from_saved: bool, keep: bool + self, + run_batch: bool, + host_port: int | None, + from_saved: bool, + keep: bool, ): LOGGER.info(f"Running container from image {self.image.short_id}") LOGGER.info(f"Image tags: {' '.join(self.image.tags)}") command = ( ["python", "execute.py"] + (["--batch"] if run_batch else []) - + (["--server"] if server_port > -1 else []) + + (["--server"] if host_port is not None else []) + (["--from-saved"] if from_saved else []) ) run_args = dict( - image=self.image, - command=command, - remove=False, - detach=True + image=self.image, command=command, remove=False, detach=True ) - if server_port > -1: - run_args["ports"] = {"8080": server_port} - print(run_args) + if host_port is not None: + run_args["ports"] = {"8080": host_port} container: Container = self.client.containers.run(**run_args) LOGGER.info(f"Waiting for container {container.short_id} to complete.") while container.status in {"created", "running"}: @@ -341,7 +341,7 @@ def run( ) self.extract_output_from_container(container) LOGGER.info(f"Results copied.") - if server_port == -1 and not keep: + if host_port is None and not keep: LOGGER.info(f"Removing container {container.short_id}...") container.remove(force=True) LOGGER.info(f"Container {container.short_id} removed.") diff --git a/xcengine/wrapper.py b/xcengine/wrapper.py index acd7a8b..2025733 100644 --- a/xcengine/wrapper.py +++ b/xcengine/wrapper.py @@ -25,10 +25,13 @@ def __xce_set_params(): ) globals().update(params.read_params_combined(sys.argv)) + if "XC_USER_CODE_PATH" in os.environ: __user_code_path = pathlib.Path(os.environ["XC_USER_CODE_PATH"]) else: - __user_code_path = pathlib.Path(__file__).with_name("user_code.py").resolve() + __user_code_path = ( + pathlib.Path(__file__).with_name("user_code.py").resolve() + ) with __user_code_path.open() as fh: user_code = fh.read() From 3d7e1e6a3bf59c500d2b101308804ba921887fab Mon Sep 17 00:00:00 2001 From: Pontus Lurcock Date: Thu, 27 Mar 2025 16:11:24 +0100 Subject: [PATCH 6/9] Improve cli.make_script test coverage --- test/test_cli.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/test_cli.py b/test/test_cli.py index f69832a..2b84576 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -1,5 +1,4 @@ from unittest.mock import patch - import pytest from click.testing import CliRunner @@ -10,7 +9,12 @@ @patch("xcengine.core.ScriptCreator.convert_notebook_to_script") @patch("subprocess.run") @pytest.mark.parametrize("verbose_arg", [[], ["--verbose"]]) -def test_make_script(run_mock, convert_mock, init_mock, tmp_path, verbose_arg): +@pytest.mark.parametrize("batch_arg", [[], ["--batch"]]) +@pytest.mark.parametrize("server_arg", [[], ["--server"]]) +@pytest.mark.parametrize("from_saved_arg", [[], ["--from-saved"]]) +def test_make_script(run_mock, convert_mock, init_mock, tmp_path, verbose_arg, batch_arg, server_arg, from_saved_arg): + from xcengine.cli import logging + logging.getLogger().setLevel(logging.WARN) nb_path = tmp_path / "foo.ipynb" nb_path.touch() output_dir = tmp_path / "bar" @@ -20,25 +24,21 @@ def test_make_script(run_mock, convert_mock, init_mock, tmp_path, verbose_arg): cli, verbose_arg + [ - "make-script", - "--batch", - "--server", - "--from-saved", + "make-script"] + + batch_arg + server_arg + from_saved_arg + +[ str(nb_path), str(output_dir), ], ) convert_mock.assert_called() init_mock.assert_called() - run_mock.assert_called_with( - [ - "python3", - output_dir / "execute.py", - "--batch", - "--server", - "--from-saved", - ] - ) - from xcengine.cli import logging + if batch_arg or server_arg: + run_mock.assert_called_with( + [ + "python3", + output_dir / "execute.py" ] + + batch_arg + server_arg + from_saved_arg + ) assert logging.getLogger().getEffectiveLevel() == (logging.DEBUG if "--verbose" in verbose_arg else logging.WARNING) assert result.exit_code == 0 From 0e397ee4dc62827a65fc1f15752e19d6460dcbd0 Mon Sep 17 00:00:00 2001 From: Pontus Lurcock Date: Thu, 27 Mar 2025 16:55:59 +0100 Subject: [PATCH 7/9] Add basic test for cli.build --- test/test_cli.py | 58 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/test/test_cli.py b/test/test_cli.py index 2b84576..2e74dc6 100644 --- a/test/test_cli.py +++ b/test/test_cli.py @@ -1,4 +1,4 @@ -from unittest.mock import patch +from unittest.mock import patch, ANY import pytest from click.testing import CliRunner @@ -12,8 +12,18 @@ @pytest.mark.parametrize("batch_arg", [[], ["--batch"]]) @pytest.mark.parametrize("server_arg", [[], ["--server"]]) @pytest.mark.parametrize("from_saved_arg", [[], ["--from-saved"]]) -def test_make_script(run_mock, convert_mock, init_mock, tmp_path, verbose_arg, batch_arg, server_arg, from_saved_arg): +def test_make_script( + run_mock, + convert_mock, + init_mock, + tmp_path, + verbose_arg, + batch_arg, + server_arg, + from_saved_arg, +): from xcengine.cli import logging + logging.getLogger().setLevel(logging.WARN) nb_path = tmp_path / "foo.ipynb" nb_path.touch() @@ -22,23 +32,41 @@ def test_make_script(run_mock, convert_mock, init_mock, tmp_path, verbose_arg, b runner = CliRunner() result = runner.invoke( cli, - verbose_arg + - [ - "make-script"] + - batch_arg + server_arg + from_saved_arg + -[ + verbose_arg + + ["make-script"] + + batch_arg + + server_arg + + from_saved_arg + + [ str(nb_path), str(output_dir), ], ) - convert_mock.assert_called() - init_mock.assert_called() + convert_mock.assert_called_once_with( + output_dir=output_dir, clear_output=False + ) + init_mock.assert_called_once_with(nb_path) if batch_arg or server_arg: - run_mock.assert_called_with( - [ - "python3", - output_dir / "execute.py" ] + - batch_arg + server_arg + from_saved_arg + run_mock.assert_called_once_with( + ["python3", output_dir / "execute.py"] + + batch_arg + + server_arg + + from_saved_arg ) - assert logging.getLogger().getEffectiveLevel() == (logging.DEBUG if "--verbose" in verbose_arg else logging.WARNING) + assert logging.getLogger().getEffectiveLevel() == ( + logging.DEBUG if "--verbose" in verbose_arg else logging.WARNING + ) assert result.exit_code == 0 + + +@patch("xcengine.core.ImageBuilder.__init__") +@patch("xcengine.core.ImageBuilder.build") +def test_image_build(build_mock, init_mock, tmp_path): + nb_path = tmp_path / "foo.ipynb" + nb_path.touch() + runner = CliRunner() + tag = "foo" + result = runner.invoke(cli, ["image", "build", "--tag", tag, str(nb_path)]) + init_mock.assert_called_once_with( + notebook=nb_path, environment=None, tag=tag, build_dir=ANY + ) From 38a46ee65356f0f1e9e041c152404af3e6a6aca4 Mon Sep 17 00:00:00 2001 From: Pontus Lurcock Date: Thu, 27 Mar 2025 17:25:55 +0100 Subject: [PATCH 8/9] Remove accidentally added "staging" notebook --- examples/staging.ipynb | 100 ----------------------------------------- 1 file changed, 100 deletions(-) delete mode 100644 examples/staging.ipynb diff --git a/examples/staging.ipynb b/examples/staging.ipynb deleted file mode 100644 index 57f0206..0000000 --- a/examples/staging.ipynb +++ /dev/null @@ -1,100 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "a7055ada-b79a-467f-bbc8-48b744367324", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "source": [ - "Parameters cell" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "fbb2fa57-fb9c-4b67-86c4-6fc02cfe9e12", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [ - "parameters" - ] - }, - "outputs": [], - "source": [ - "import xcube.core.new\n", - "\n", - "periods = 10\n", - "cube1 = xcube.core.new.new_cube(\n", - " variables={\"v\": lambda x, y, t: (x + y + t) % 10},\n", - " time_periods=periods\n", - ")\n", - "cube2 = xcube.core.new.new_cube(\n", - " variables={\"v\": lambda x, y, t: (x - y + t) % 10},\n", - " time_periods=periods\n", - ")\n", - "\n", - "del xcube" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "df9686d6-395b-4bfd-bd10-c7e03df5cf38", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [ - "cube1.attrs[\"title\"] = \"Cube 1\"\n", - "cube2.attrs[\"title\"] = \"Cube 2\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5fb0b2d6-364a-4875-aa80-37e9f4e76abf", - "metadata": { - "editable": true, - "slideshow": { - "slide_type": "" - }, - "tags": [] - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.12.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 1395291f138622b546b76a126c61b5635c88ab0e Mon Sep 17 00:00:00 2001 From: Pontus Lurcock Date: Thu, 27 Mar 2025 17:27:47 +0100 Subject: [PATCH 9/9] Remove Python version pin The version incompatibility has been solved by a Python 3.13 compatible chartlets release. --- examples/environment.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/environment.yml b/examples/environment.yml index 6a9e275..c4d8b4f 100644 --- a/examples/environment.yml +++ b/examples/environment.yml @@ -2,6 +2,6 @@ name: xce-example-1 channels: - conda-forge dependencies: - - python >=3.10,<3.13 - - xcube >=1.7.1 + - python >=3.10 + - xcube >=1.8.3 - matplotlib-base