Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Changes in version 0.1.0 (in development)

Added GUI component support for
[PathRef](https://github.com/s2gos-dev/s2gos-utils/blob/MTR/src/s2gos_utils/io/paths.py)
object (not yet used).

Major parts of the S2GOS controller packages have been generic with respect
to the primary interface used between the client and the gateway server,
which is the
Expand Down
588 changes: 144 additions & 444 deletions notebooks/client-api.ipynb

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions notebooks/client-cli.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
"with a test configuration:\n",
"\n",
"```bash\n",
"s2gos-server run -- s2gos_server.services.testing:service\n",
"```\n",
"or\n",
"```bash\n",
"s2gos-server run -- wraptile.services.local.testing:service\n",
"```"
]
Expand Down
925 changes: 56 additions & 869 deletions notebooks/client-gui.ipynb

Large diffs are not rendered by default.

181 changes: 108 additions & 73 deletions pixi.lock

Large diffs are not rendered by default.

26 changes: 15 additions & 11 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ channels = ["conda-forge"]
platforms = ["linux-64", "win-64", "osx-64"]

[tool.pixi.dependencies]
# Eozilla dependencies
appligator = ">=0.0.8,<0.0.9"
cuiman = ">=0.0.8,<0.0.9"
gavicore = ">=0.0.8,<0.0.9"
procodile = ">=0.0.8,<0.0.9"
wraptile = ">=0.0.8,<0.0.9"
# Eozilla dependencies.
# Comment out, if using the editable versions,
# see [tool.pixi.pypi-dependencies] below.
#appligator = ">=0.0.8,<0.0.9"
#cuiman = ">=0.0.8,<0.0.9"
#gavicore = ">=0.0.8,<0.0.9"
#procodile = ">=0.0.8,<0.0.9"
#wraptile = ">=0.0.8,<0.0.9"
# Combined sub-workspace dependencies to prevent our editable
# PyPI dependencies (our project's sub-workspaces) to install
# PyPI packages instead of using conda packages.
Expand All @@ -24,6 +26,7 @@ httpx = "*"
pydantic = "*"
pyyaml = "*"
typer = "*"
universal_pathlib = ">=0.3.8,<0.4"
uri-template = "*"
uvicorn = "*"
# IDE integration
Expand Down Expand Up @@ -61,6 +64,7 @@ mkdocstrings = "*"
mkdocstrings-python = "*"
mkdocs-jupyter = "*"
nbformat = "*"
pydantic-settings = ">=2.12.0,<3"

[tool.pixi.pypi-dependencies]
# I wished we could have "no-deps=true" here,
Expand All @@ -72,11 +76,11 @@ s2gos-server = { path = "s2gos-server", editable = true }
# Uncomment the following to allow using eozilla from sources
# Note, using the wraptile server is for testing only
#
#appligator = { path = "../eozilla/appligator", editable = true }
#cuiman = { path = "../eozilla/cuiman", editable = true }
#gavicore = { path = "../eozilla/gavicore", editable = true }
#procodile = { path = "../eozilla/procodile", editable = true }
#wraptile = { path = "../eozilla/wraptile", editable = true }
appligator = { path = "../eozilla/appligator", editable = true }
cuiman = { path = "../eozilla/cuiman", editable = true }
gavicore = { path = "../eozilla/gavicore", editable = true }
procodile = { path = "../eozilla/procodile", editable = true }
wraptile = { path = "../eozilla/wraptile", editable = true }

# Airflow is only available on PyPI
apache-airflow-client = "==3.0.2"
Expand Down
11 changes: 0 additions & 11 deletions s2gos-client/src/s2gos_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@

from .api import AsyncClient, Client, ClientConfig, ClientError

from .defaults import DEFAULT_SERVER_URL, DEFAULT_USER_NAME, DEFAULT_ACCESS_TOKEN


__version__ = version("s2gos-client")

__all__ = [
Expand All @@ -18,11 +15,3 @@
"ClientError",
"__version__",
]

ClientConfig.set_default(
ClientConfig(
server_url=DEFAULT_SERVER_URL,
user_name=DEFAULT_USER_NAME,
access_token=DEFAULT_ACCESS_TOKEN,
)
)
24 changes: 23 additions & 1 deletion s2gos-client/src/s2gos_client/api.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
# Copyright (c) 2025 by ESA DTE-S2GOS team and contributors
# Copyright (c) 2026 by ESA DTE-S2GOS team and contributors
# Permissions are hereby granted under the terms of the Apache 2.0 License:
# https://opensource.org/license/apache-2-0.

from pathlib import Path

from pydantic_settings import SettingsConfigDict

from cuiman.api import AsyncClient, Client, ClientConfig, ClientError


class S2GOSConfig(ClientConfig):
model_config = SettingsConfigDict(
env_prefix="S2GOS_",
env_file=".env",
extra="allow", # ClientConfig uses "forbid"
)


ClientConfig.default_path = Path("~").expanduser() / ".sen4cap-client"
ClientConfig.default_config = S2GOSConfig(
api_url="http://localhost:8008/",
# auth_url="http://localhost:8080/auth/login",
# auth_type="token",
# use_bearer=True,
auth_type="none",
)

__all__ = [
"AsyncClient",
"Client",
Expand Down
7 changes: 6 additions & 1 deletion s2gos-client/src/s2gos_client/cli.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# Copyright (c) 2025 by ESA DTE-S2GOS team and contributors
# Copyright (c) 2026 by ESA DTE-S2GOS team and contributors
# Permissions are hereby granted under the terms of the Apache 2.0 License:
# https://opensource.org/license/apache-2-0.

from importlib import import_module

from cuiman.cli import new_cli

from s2gos_client import __version__ as version

# Force pre-configuration of Sen4CAP configuration
import_module("s2gos_client.api")

cli = new_cli(
name="s2gos-client",
version=version,
Expand Down
14 changes: 0 additions & 14 deletions s2gos-client/src/s2gos_client/defaults.py

This file was deleted.

9 changes: 0 additions & 9 deletions s2gos-client/src/s2gos_client/gui.py

This file was deleted.

18 changes: 18 additions & 0 deletions s2gos-client/src/s2gos_client/gui/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) 2026 by ESA DTE-S2GOS team and contributors
# Permissions are hereby granted under the terms of the Apache 2.0 License:
# https://opensource.org/license/apache-2-0.

from importlib import import_module

from cuiman.gui import Client
from .pathref import register_component


# Force pre-configuration of Sen4CAP configuration
import_module("s2gos_client.api")

register_component()

__all__ = [
"Client",
]
104 changes: 104 additions & 0 deletions s2gos-client/src/s2gos_client/gui/pathref.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Copyright (c) 2026 by ESA DTE-S2GOS team and contributors
# Permissions are hereby granted under the terms of the Apache 2.0 License:
# https://opensource.org/license/apache-2-0.
from typing import Any, Callable

import panel as pn
import param

from cuiman.gui.component import (
Component,
ComponentContainer,
ComponentFactoryBase,
JsonValue,
JsonSchemaDict,
)


class PathRefEditor(pn.viewable.Viewer):
title = param.String(default="")
tooltip = param.String(default=None, allow_None=True)

value = param.String(default="")
cid = param.String(default="")

disabled = param.Boolean(default=False)

def __init__(self, **params):
super().__init__(**params)

self._value_input = pn.widgets.TextInput(
name=f"{self.title} URI",
placeholder="URI or rel. path...",
value=self.value,
disabled=self.param.disabled,
width=300,
)

self._cid_input = pn.widgets.TextInput(
name=f"{self.title} CID (optional)",
placeholder="Credentials ID...",
value=self.cid,
disabled=self.param.disabled,
width=120,
)

# widget ↔ param (two-way, explicit)
self._value_input.link(self, value="value")
self._cid_input.link(self, value="cid")

# TODO: set tooltip (how?)
self.view = pn.Row(
self._value_input,
self._cid_input,
)

def __panel__(self):
return self.view


class PathRefComponent(Component):
def __init__(self, editor: PathRefEditor):
# noinspection PyTypeChecker
super().__init__(editor)

@property
def path_ref_editor(self) -> PathRefEditor:
# noinspection PyTypeChecker
return self.viewable

def get_value(self) -> dict[str, Any] | None:
value = self.path_ref_editor.value
cid = self.path_ref_editor.cid
if not (value and cid):
return None
return {"value": value, "cid": cid or None}

def set_value(self, value: dict[str, Any] | None):
self.path_ref_editor.value = value.get("value") or ""
self.path_ref_editor.cid = value.get("cid") or ""

def watch_value(self, callback: Callable[[Any], Any]):
self.path_ref_editor.param.watch(callback, ["value", "cid"])


class PathRefEditorFactory(ComponentFactoryBase):
type = "object"
format = "PathRef"

def create_component(
self, value: JsonValue, title: str, schema: JsonSchemaDict
) -> Component:
path_ref: dict[str, Any] | None = value
return PathRefComponent(
PathRefEditor(
title=title,
value=(path_ref and path_ref.get("value")) or "",
cid=(path_ref and path_ref.get("cid")) or "",
tooltip=schema.get("description"),
)
)


def register_component():
PathRefEditorFactory.register_in(ComponentContainer.registry)
11 changes: 11 additions & 0 deletions s2gos-client/tests/test_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@
# https://opensource.org/license/apache-2-0.

import s2gos_client.gui
from cuiman.gui.component import ComponentContainer, ComponentFactory


def test_gui_ok():
assert {"Client"}.issubset(dir(s2gos_client.gui))


def test_extra_gui_components_registered():
factory = ComponentContainer.registry.find_factory({"type": "object"})
assert factory is None

factory = ComponentContainer.registry.find_factory(
{"type": "object", "format": "PathRef"}
)
assert isinstance(factory, ComponentFactory)
2 changes: 2 additions & 0 deletions s2gos-server/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ dependencies = [
# Eozilla dependencies
"gavicore >=0.0.8",
"wraptile >=0.0.8",
# Other
"universal_pathlib >=0.3.8,<0.4",
]

[project.scripts]
Expand Down
Loading
Loading