cuiman 0.1.2__tar.gz → 0.2.0.dev1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/PKG-INFO +3 -7
  2. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/__init__.py +3 -0
  3. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/__init__.py +3 -0
  4. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/async_client.py +5 -3
  5. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/client.py +5 -3
  6. cuiman-0.2.0.dev1/cuiman/api/client_app_mixin.py +104 -0
  7. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/config.py +0 -147
  8. cuiman-0.2.0.dev1/cuiman/api/jobs.py +304 -0
  9. cuiman-0.2.0.dev1/cuiman/api/service_client.py +372 -0
  10. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/transport/args.py +21 -11
  11. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/transport/httpx.py +11 -6
  12. {cuiman-0.1.2/cuiman/gui/panels/jobs_panel → cuiman-0.2.0.dev1/cuiman/app}/__init__.py +4 -5
  13. cuiman-0.2.0.dev1/cuiman/app/app.py +124 -0
  14. cuiman-0.2.0.dev1/cuiman/app/display.py +110 -0
  15. cuiman-0.2.0.dev1/cuiman/app/dist/assets/index-CEQarI7F.js +84 -0
  16. cuiman-0.2.0.dev1/cuiman/app/dist/assets/index-DKE7nU5k.css +1 -0
  17. cuiman-0.2.0.dev1/cuiman/app/dist/eozilla-small.svg +5 -0
  18. cuiman-0.2.0.dev1/cuiman/app/dist/eozilla.svg +3 -0
  19. cuiman-0.2.0.dev1/cuiman/app/dist/index.html +14 -0
  20. cuiman-0.2.0.dev1/cuiman/app/dist/privacy.md +23 -0
  21. cuiman-0.2.0.dev1/cuiman/app/serve.py +68 -0
  22. cuiman-0.2.0.dev1/cuiman/app/service.py +96 -0
  23. cuiman-0.2.0.dev1/cuiman/app/url.py +77 -0
  24. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/cli/cli.py +89 -21
  25. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/cli/config.py +22 -19
  26. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/pyproject.toml +3 -7
  27. cuiman-0.1.2/cuiman/gui/__init__.py +0 -11
  28. cuiman-0.1.2/cuiman/gui/client.py +0 -151
  29. cuiman-0.1.2/cuiman/gui/ipy_helper.py +0 -63
  30. cuiman-0.1.2/cuiman/gui/jobs_event_bus.py +0 -76
  31. cuiman-0.1.2/cuiman/gui/jobs_observer.py +0 -32
  32. cuiman-0.1.2/cuiman/gui/panels/__init__.py +0 -15
  33. cuiman-0.1.2/cuiman/gui/panels/job_info_panel.py +0 -113
  34. cuiman-0.1.2/cuiman/gui/panels/jobs_panel/view.py +0 -99
  35. cuiman-0.1.2/cuiman/gui/panels/jobs_panel/viewmodel.py +0 -196
  36. cuiman-0.1.2/cuiman/gui/panels/main_panel/__init__.py +0 -11
  37. cuiman-0.1.2/cuiman/gui/panels/main_panel/settings.py +0 -21
  38. cuiman-0.1.2/cuiman/gui/panels/main_panel/view.py +0 -417
  39. cuiman-0.1.2/cuiman/gui/panels/main_panel/viewmodel.py +0 -307
  40. cuiman-0.1.2/cuiman/gui/panels/util.py +0 -259
  41. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/.gitignore +0 -0
  42. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/LICENSE +0 -0
  43. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/README.md +0 -0
  44. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/async_client_mixin.py +0 -0
  45. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/auth/__init__.py +0 -0
  46. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/auth/config.py +0 -0
  47. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/auth/login.py +0 -0
  48. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/auth/login_async.py +0 -0
  49. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/client_mixin.py +0 -0
  50. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/defaults.py +0 -0
  51. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/exceptions.py +0 -0
  52. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/ishell.py +0 -0
  53. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/__init__.py +0 -0
  54. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/context.py +0 -0
  55. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/errors.py +0 -0
  56. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/impl/__init__.py +0 -0
  57. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/impl/_gpd.py +0 -0
  58. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/impl/_image.py +0 -0
  59. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/impl/_pd.py +0 -0
  60. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/impl/_xr.py +0 -0
  61. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/impl/base.py +0 -0
  62. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/impl/openers.py +0 -0
  63. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/opener.py +0 -0
  64. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/opener/registry.py +0 -0
  65. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/transport/__init__.py +0 -0
  66. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/api/transport/transport.py +0 -0
  67. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/cli/__init__.py +0 -0
  68. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/cli/client.py +0 -0
  69. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/cli/output.py +0 -0
  70. {cuiman-0.1.2 → cuiman-0.2.0.dev1}/cuiman/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cuiman
3
- Version: 0.1.2
3
+ Version: 0.2.0.dev1
4
4
  Summary: Provides a client Python API, GUI, and CLI for servers compliant with OGC API - Processes
5
5
  Project-URL: Documentation, https://eo-tools.github.io/eozilla
6
6
  Project-URL: Repository, https://github.com/eo-tools/eozilla
@@ -27,17 +27,13 @@ Classifier: Topic :: Scientific/Engineering
27
27
  Classifier: Topic :: Software Development
28
28
  Classifier: Typing :: Typed
29
29
  Requires-Python: >=3.10
30
- Requires-Dist: click
31
- Requires-Dist: gavicore>=0.1.2
30
+ Requires-Dist: gavicore>=0.2.0.dev1
32
31
  Requires-Dist: httpx
33
- Requires-Dist: ipyfilechooser
34
- Requires-Dist: ipyleaflet
35
- Requires-Dist: panel
36
32
  Requires-Dist: pydantic
37
33
  Requires-Dist: pydantic-settings
38
34
  Requires-Dist: pyyaml
39
35
  Requires-Dist: remotestate<1,>=0.3.1
40
- Requires-Dist: typer
36
+ Requires-Dist: typer<1,>=0.26.0
41
37
  Requires-Dist: uri-template
42
38
  Description-Content-Type: text/markdown
43
39
 
@@ -8,6 +8,7 @@ from .api.async_client import AsyncClient
8
8
  from .api.client import Client
9
9
  from .api.config import ClientConfig
10
10
  from .api.exceptions import ClientError
11
+ from .api.jobs import JobMonitor, JobOptions
11
12
 
12
13
  __version__ = version("cuiman")
13
14
 
@@ -16,5 +17,7 @@ __all__ = [
16
17
  "Client",
17
18
  "ClientConfig",
18
19
  "ClientError",
20
+ "JobMonitor",
21
+ "JobOptions",
19
22
  "__version__",
20
23
  ]
@@ -6,10 +6,13 @@ from .async_client import AsyncClient
6
6
  from .client import Client
7
7
  from .config import ClientConfig
8
8
  from .exceptions import ClientError
9
+ from .jobs import JobMonitor, JobOptions
9
10
 
10
11
  __all__ = [
11
12
  "AsyncClient",
12
13
  "Client",
13
14
  "ClientConfig",
14
15
  "ClientError",
16
+ "JobMonitor",
17
+ "JobOptions",
15
18
  ]
@@ -1,6 +1,6 @@
1
1
  # generated by gen_client.py:
2
2
  # filename: async_client.py:
3
- # timestamp: 2026-07-08T13:06:46.295496
3
+ # timestamp: 2026-07-15T17:16:03.217600
4
4
 
5
5
 
6
6
  from typing import Any, Optional
@@ -18,13 +18,14 @@ from gavicore.models import (
18
18
  )
19
19
 
20
20
  from .async_client_mixin import AsyncClientMixin
21
+ from .client_app_mixin import ClientAppMixin
21
22
  from .config import ClientConfig
22
23
  from .ishell import has_ishell as _ # noqa F401
23
24
  from .transport import AsyncTransport, TransportArgs
24
25
  from .transport.httpx import HttpxTransport
25
26
 
26
27
 
27
- class AsyncClient(AsyncClientMixin):
28
+ class AsyncClient(ClientAppMixin, AsyncClientMixin):
28
29
  """
29
30
  The client API for the web service (asynchronous mode).
30
31
 
@@ -56,8 +57,9 @@ class AsyncClient(AsyncClientMixin):
56
57
  raise ValueError("Required setting 'api_url' not configured")
57
58
  self._transport = (
58
59
  HttpxTransport(
59
- api_url=self._config.api_url,
60
+ api_url=f"{self._config.api_url.rstrip('/')}/",
60
61
  headers=self._config.auth_headers,
62
+ return_type_map=self._config.return_type_map,
61
63
  async_token_refresher=self._config._make_async_token_refresher(),
62
64
  debug=_debug,
63
65
  )
@@ -1,6 +1,6 @@
1
1
  # generated by gen_client.py:
2
2
  # filename: client.py:
3
- # timestamp: 2026-07-08T13:06:43.275607
3
+ # timestamp: 2026-07-15T17:16:02.527617
4
4
 
5
5
 
6
6
  from typing import Any, Optional
@@ -17,6 +17,7 @@ from gavicore.models import (
17
17
  ProcessRequest,
18
18
  )
19
19
 
20
+ from .client_app_mixin import ClientAppMixin
20
21
  from .client_mixin import ClientMixin
21
22
  from .config import ClientConfig
22
23
  from .ishell import has_ishell as _ # noqa F401
@@ -24,7 +25,7 @@ from .transport import Transport, TransportArgs
24
25
  from .transport.httpx import HttpxTransport
25
26
 
26
27
 
27
- class Client(ClientMixin):
28
+ class Client(ClientAppMixin, ClientMixin):
28
29
  """
29
30
  The client API for the web service (synchronous mode).
30
31
 
@@ -56,8 +57,9 @@ class Client(ClientMixin):
56
57
  raise ValueError("Required setting 'api_url' not configured")
57
58
  self._transport = (
58
59
  HttpxTransport(
59
- api_url=self._config.api_url,
60
+ api_url=f"{self._config.api_url.rstrip('/')}/",
60
61
  headers=self._config.auth_headers,
62
+ return_type_map=self._config.return_type_map,
61
63
  token_refresher=self._config._maybe_make_token_refresher(),
62
64
  debug=_debug,
63
65
  )
@@ -0,0 +1,104 @@
1
+ # Copyright (c) 2025-2026 by the Eozilla team and contributors
2
+ # Permissions are hereby granted under the terms of the Apache 2.0 License:
3
+ # https://opensource.org/license/apache-2-0.
4
+
5
+ from abc import ABC, abstractmethod
6
+ from typing import TYPE_CHECKING, Literal
7
+
8
+ from cuiman.api.ishell import has_ishell
9
+
10
+ from .config import ClientConfig
11
+
12
+ if TYPE_CHECKING:
13
+ from cuiman.app import App
14
+
15
+
16
+ class ClientAppMixin(ABC):
17
+ """
18
+ Extra methods for the Client App.
19
+ """
20
+
21
+ @property
22
+ @abstractmethod
23
+ def config(self) -> ClientConfig:
24
+ """Will be overridden by the actual client class."""
25
+
26
+ def show_app(
27
+ self,
28
+ *,
29
+ compact: bool | None = None,
30
+ debug: bool = False,
31
+ scheme: Literal["dark", "light", "auto"] = "auto",
32
+ width: int | str = "100%",
33
+ height: int | str = 600,
34
+ display: Literal["browser", "notebook", "auto"] = "auto",
35
+ ) -> "App":
36
+ """
37
+ Show the Cuiman app for this client.
38
+
39
+ The app connects to this client's API configuration, renders the app GUI,
40
+ and returns an object that provides the serve result and a shared
41
+ [app state][cuiman.app.AppState], which you can interact with.
42
+
43
+ The app state currently only manages the process requests being
44
+ edited and executed by a user. The requests are a mapping from process IDs
45
+ to process requests.
46
+
47
+ Display the app and get the app instance:
48
+
49
+ ```
50
+ app = client.show_app()
51
+ ```
52
+
53
+ You can get and set process requests using the methods
54
+
55
+ - ``app.get_process_request(process_id)``
56
+ - ``app.set_process_request(process_id, process_request)``
57
+
58
+ where ``process_id`` is the process ID and ``process_request`` is a dict
59
+ or a ``ProcessRequest`` object that comprises basically two attributes:
60
+
61
+ - ``inputs``: a mapping from input name to an input's value.
62
+ - ``outputs``: the outputs to be generated. Just used to detect
63
+ whether an output is included or now.
64
+
65
+ Another convenient way to work with the nested app state is the
66
+ ``process_requests`` property:
67
+
68
+ - ``app.process_requests.my_process.inputs.threshold = 0.75``
69
+ - ``app.process_requests.my_process = {"inputs": {...}}``
70
+
71
+ Args:
72
+ compact: Compact mode. Defaults to True, if ``display`` is "notebook".
73
+ debug: Enable app debug mode.
74
+ scheme: Color scheme to use in the app. ``"auto"`` follows the
75
+ surrounding notebook theme when the app is embedded.
76
+ width: Width of the notebook iframe.
77
+ height: Height of the notebook iframe.
78
+ display: Where to show the app. ``"auto"`` embeds it in notebooks
79
+ and opens it in a browser otherwise.
80
+ Return:
81
+ An ``App`` instance.
82
+ """
83
+ from cuiman.app import App, serve
84
+
85
+ display_ = (
86
+ ("notebook" if has_ishell else "browser") if display == "auto" else display
87
+ )
88
+ compact_ = compact if isinstance(compact, bool) else display_ == "notebook"
89
+
90
+ remote_store = App.create_remote_store()
91
+
92
+ # noinspection PyTypeChecker
93
+ serve_result = serve(
94
+ self.config,
95
+ remote_store,
96
+ compact=compact_,
97
+ debug=debug,
98
+ scheme=scheme,
99
+ width=width,
100
+ height=height,
101
+ display=display_,
102
+ )
103
+
104
+ return App(remote_store, serve_result)
@@ -16,10 +16,8 @@ from typing import (
16
16
  import yaml
17
17
  from pydantic import Field, HttpUrl, field_validator
18
18
  from pydantic_settings import BaseSettings, SettingsConfigDict
19
- from typing_extensions import deprecated
20
19
 
21
20
  from gavicore.models import InputDescription, ProcessDescription, ProcessSummary
22
- from gavicore.ui import FieldFactoryRegistry, FieldMeta
23
21
 
24
22
  from .auth import AuthConfig
25
23
  from .defaults import DEFAULT_API_URL
@@ -155,124 +153,6 @@ class ClientConfig(AuthConfig, BaseSettings):
155
153
  def validate_api_url(cls, v: str | None) -> str | None:
156
154
  return None if v is None or v == "" else str(HttpUrl(v))
157
155
 
158
- # noinspection PyUnusedLocal
159
- @classmethod
160
- @deprecated(
161
- "ClientConfig.accept_process() is deprecated, only used by the legacy "
162
- "cuiman.gui client, and will not work in newer Eozilla versions."
163
- )
164
- def accept_process(
165
- cls, process_summary: ProcessSummary, **filter_kwargs: Any
166
- ) -> bool:
167
- """
168
- Predicate function that is used to filter the list of processes.
169
- The function is intended to be overridden by subclasses in order to allow
170
- for evaluating the given `process_summary` in an application-specific way.
171
- This includes the using custom fields in the given
172
- [ProcessSummary][gavicore.models.ProcessSummary] instance.
173
-
174
- Applications may use the [extend_model()][gavicore.util.model.extend_model]
175
- function to enhance existing model classes by their custom fields.
176
-
177
- The default implementation unconditionally returns `True`.
178
-
179
- Args:
180
- process_summary: A process summary.
181
- filter_kwargs: Implementation specific arguments passed
182
- by a user of this class.
183
-
184
- Returns:
185
- `True` to accept the given process, otherwise `False`.
186
- """
187
- return True
188
-
189
- # noinspection PyUnusedLocal
190
- @classmethod
191
- @deprecated(
192
- "ClientConfig.accept_input() is deprecated, only used by the legacy "
193
- "cuiman.gui client, and will not work in newer Eozilla versions."
194
- )
195
- def accept_input(
196
- cls,
197
- process_description: ProcessDescription,
198
- input_name: str,
199
- input_description: InputDescription,
200
- **filter_kwargs: Any,
201
- ) -> bool:
202
- """
203
- Predicate function that is used to filter the list of inputs of a process.
204
- The function is intended to be overridden by subclasses in order to allow
205
- for evaluating the given `input_description` in an application-specific way.
206
- This includes the using custom fields in the given
207
- [InputDescription][gavicore.models.InputDescription] instance.
208
-
209
- Applications may use the [extend_model()][gavicore.util.model.extend_model]
210
- function to enhance existing model classes by their custom fields.
211
-
212
- The default implementation unconditionally returns `True`.
213
-
214
- Args:
215
- process_description: The process description.
216
- input_name: The input's name.
217
- input_description: A description of an
218
- input of the given `process_description`.
219
- filter_kwargs: Implementation specific arguments passed
220
- by a user of this class.
221
-
222
- Returns:
223
- `True` to accept the given input, otherwise `False`.
224
- """
225
- return True
226
-
227
- # noinspection PyUnusedLocal
228
- @classmethod
229
- @deprecated(
230
- "ClientConfig.is_advanced_input() is deprecated, only used by the legacy "
231
- "cuiman.gui client, and will not work in newer Eozilla versions."
232
- )
233
- def is_advanced_input(
234
- cls,
235
- process_description: ProcessDescription,
236
- input_name: str,
237
- input_description: InputDescription,
238
- ) -> bool:
239
- """
240
- Experimental method, do not use!
241
-
242
- Designed to be overridden by a custom `ClientConfig` class
243
- from which an instance will be assigned to `ClientConfig.default_config`
244
- to become effective.
245
-
246
- The default implementations checks if the given `input_description`
247
- has `additionalParameters`, and if so, if a parameter with name
248
- `"level"` has value `["advanced"]` (a list!).
249
-
250
- Args:
251
- process_description: The process description.
252
- input_name: The input's name.
253
- input_description: A description of an
254
- input of the given `process_description`.
255
-
256
- Returns:
257
- `True` if the input is advanced
258
- (e.g. for advanced process users only).
259
- """
260
- # The following approach uses additionalParameters but its use
261
- # is discouraged. (We receive such metadata currently from
262
- # the TAO Process API).
263
- additional_parameters = input_description.additionalParameters
264
- if additional_parameters:
265
- parameters = additional_parameters.parameters
266
- if parameters:
267
- for p in parameters:
268
- if p.name == "level" and p.value == ["advanced"]:
269
- return True
270
- # The way it should be done is using "x-ui" properties.
271
- # Ideally, we should pass an already parsed FieldMeta into the
272
- # is_advanced_input() method.
273
- field_meta = FieldMeta.from_input_description(input_name, input_description)
274
- return field_meta.advanced or field_meta.level == "advanced"
275
-
276
156
  @classmethod
277
157
  def register_job_result_opener(
278
158
  cls, opener_type: type[JobResultOpener]
@@ -299,33 +179,6 @@ class ClientConfig(AuthConfig, BaseSettings):
299
179
  """
300
180
  return JobResultOpenerRegistry.create_default()
301
181
 
302
- @classmethod
303
- @cache
304
- def get_field_factory_registry(cls) -> FieldFactoryRegistry:
305
- """
306
- Get the registry for factories that generate UI fields from
307
- process inputs.
308
-
309
- Used in the GUI client `cuiman.gui.Client`. Use it to register
310
- factories that customize the way the client GUI is generated.
311
-
312
- The default registry contains factories that creates UI fields for
313
- the [Panel](https://panel.holoviz.org/) library as this is the primary
314
- library used in the GUI client.
315
-
316
- The default registry type is
317
- `gavicore.ui.panel.PanelFieldFactoryRegistry`.
318
-
319
- The type of registered field factories is
320
- `gavicore.ui.panel.PanelFieldFactory`.
321
-
322
- The type of the field instances created by the factories must be
323
- `gavicore.ui.panel.PanelField`.
324
- """
325
- from gavicore.ui.panel import PanelFieldFactoryRegistry
326
-
327
- return PanelFieldFactoryRegistry.create_default()
328
-
329
182
 
330
183
  # Set Eozilla defaults.
331
184
  # Cuiman applications might want to change them.