xconv2 0.0.0__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.
- xconv2-0.0.0/LICENSE +21 -0
- xconv2-0.0.0/PKG-INFO +141 -0
- xconv2-0.0.0/README.md +112 -0
- xconv2-0.0.0/pyproject.toml +68 -0
- xconv2-0.0.0/setup.cfg +4 -0
- xconv2-0.0.0/tests/test_animation_protocol.py +247 -0
- xconv2-0.0.0/tests/test_animation_router.py +209 -0
- xconv2-0.0.0/tests/test_animation_session.py +223 -0
- xconv2-0.0.0/tests/test_cache_utils.py +84 -0
- xconv2-0.0.0/tests/test_cf_interface.py +1515 -0
- xconv2-0.0.0/tests/test_contour.py +535 -0
- xconv2-0.0.0/tests/test_contour_options_dialog.py +161 -0
- xconv2-0.0.0/tests/test_coordinate_flow.py +1961 -0
- xconv2-0.0.0/tests/test_field_metadata_controller.py +151 -0
- xconv2-0.0.0/tests/test_filter_options_dialog.py +67 -0
- xconv2-0.0.0/tests/test_gui_cli.py +61 -0
- xconv2-0.0.0/tests/test_https_integration.py +74 -0
- xconv2-0.0.0/tests/test_lineplot.py +407 -0
- xconv2-0.0.0/tests/test_load_selected_file.py +2519 -0
- xconv2-0.0.0/tests/test_log_viewer_dialog.py +132 -0
- xconv2-0.0.0/tests/test_pyfive_remote_s3_cache.py +157 -0
- xconv2-0.0.0/tests/test_remote_access.py +403 -0
- xconv2-0.0.0/tests/test_remote_auth_flow.py +306 -0
- xconv2-0.0.0/tests/test_remote_configuration_dialog.py +464 -0
- xconv2-0.0.0/tests/test_remote_file_navigator.py +339 -0
- xconv2-0.0.0/tests/test_remote_fs.py +548 -0
- xconv2-0.0.0/tests/test_science_environment.py +200 -0
- xconv2-0.0.0/tests/test_science_stack_dialog.py +131 -0
- xconv2-0.0.0/tests/test_selection_controller.py +108 -0
- xconv2-0.0.0/tests/test_service_helpers.py +137 -0
- xconv2-0.0.0/tests/test_settings_store.py +36 -0
- xconv2-0.0.0/tests/test_worker_message_router.py +223 -0
- xconv2-0.0.0/tests/test_worker_remote_integration.py +1358 -0
- xconv2-0.0.0/tests/test_worker_remote_tasks.py +618 -0
- xconv2-0.0.0/tests/test_worker_save_script.py +84 -0
- xconv2-0.0.0/tests/test_workflow_provenance.py +179 -0
- xconv2-0.0.0/xconv2/__init__.py +19 -0
- xconv2-0.0.0/xconv2/aaa/aaa_config.py +64 -0
- xconv2-0.0.0/xconv2/animation_protocol.py +189 -0
- xconv2-0.0.0/xconv2/animation_session.py +165 -0
- xconv2-0.0.0/xconv2/assets/Pyfive-logo.png +0 -0
- xconv2-0.0.0/xconv2/assets/UoR-logo.png +0 -0
- xconv2-0.0.0/xconv2/assets/cf-logo-t.svg +30367 -0
- xconv2-0.0.0/xconv2/assets/cf-logo.svg +30375 -0
- xconv2-0.0.0/xconv2/assets/clipster.svg +71 -0
- xconv2-0.0.0/xconv2/assets/dask-logo.svg +13 -0
- xconv2-0.0.0/xconv2/assets/info-ncas.svg +5 -0
- xconv2-0.0.0/xconv2/assets/ncas-logo.png +0 -0
- xconv2-0.0.0/xconv2/assets/tooltip.svg +1 -0
- xconv2-0.0.0/xconv2/assets/under-construction.svg +9 -0
- xconv2-0.0.0/xconv2/cache_utils.py +293 -0
- xconv2-0.0.0/xconv2/cell_method_handler.py +92 -0
- xconv2-0.0.0/xconv2/cf_interface/__init__.py +76 -0
- xconv2-0.0.0/xconv2/cf_interface/filtering.py +183 -0
- xconv2-0.0.0/xconv2/cf_interface/lineplot.py +262 -0
- xconv2-0.0.0/xconv2/cf_interface/maths.py +344 -0
- xconv2-0.0.0/xconv2/cf_interface/metadata_operations.py +663 -0
- xconv2-0.0.0/xconv2/cf_interface/plot_layout_helpers.py +139 -0
- xconv2-0.0.0/xconv2/cf_interface/plotting.py +533 -0
- xconv2-0.0.0/xconv2/cf_interface/regridding.py +189 -0
- xconv2-0.0.0/xconv2/cf_templates.py +511 -0
- xconv2-0.0.0/xconv2/colour_scales.py +82 -0
- xconv2-0.0.0/xconv2/coordinate_subspace.py +87 -0
- xconv2-0.0.0/xconv2/core_window.py +2651 -0
- xconv2-0.0.0/xconv2/gui.py +128 -0
- xconv2-0.0.0/xconv2/logging_utils.py +145 -0
- xconv2-0.0.0/xconv2/main_window.py +2232 -0
- xconv2-0.0.0/xconv2/main_window_components/__init__.py +1 -0
- xconv2-0.0.0/xconv2/main_window_components/plot_ops.py +327 -0
- xconv2-0.0.0/xconv2/main_window_components/remote_auth_ops.py +440 -0
- xconv2-0.0.0/xconv2/main_window_components/remote_flow_ops.py +746 -0
- xconv2-0.0.0/xconv2/main_window_components/replay_ops.py +474 -0
- xconv2-0.0.0/xconv2/remote_access.py +758 -0
- xconv2-0.0.0/xconv2/remote_fs.py +791 -0
- xconv2-0.0.0/xconv2/science_environment.py +115 -0
- xconv2-0.0.0/xconv2/tooltips.py +104 -0
- xconv2-0.0.0/xconv2/ui/__init__.py +19 -0
- xconv2-0.0.0/xconv2/ui/contour_options_controller.py +758 -0
- xconv2-0.0.0/xconv2/ui/dialogs.py +2991 -0
- xconv2-0.0.0/xconv2/ui/field_metadata_controller.py +378 -0
- xconv2-0.0.0/xconv2/ui/lineplot_options_controller.py +176 -0
- xconv2-0.0.0/xconv2/ui/menu_controller.py +224 -0
- xconv2-0.0.0/xconv2/ui/plot_options_shared.py +258 -0
- xconv2-0.0.0/xconv2/ui/plot_view_controller.py +831 -0
- xconv2-0.0.0/xconv2/ui/remote_file_navigator.py +1226 -0
- xconv2-0.0.0/xconv2/ui/science_stack_dialog.py +21 -0
- xconv2-0.0.0/xconv2/ui/selection_controller.py +623 -0
- xconv2-0.0.0/xconv2/ui/settings_store.py +297 -0
- xconv2-0.0.0/xconv2/ui/vector_options_controller.py +197 -0
- xconv2-0.0.0/xconv2/worker.py +1566 -0
- xconv2-0.0.0/xconv2/worker_message_router.py +478 -0
- xconv2-0.0.0/xconv2/workflow/provenance_export.py +416 -0
- xconv2-0.0.0/xconv2/workflow/xconv_workflow_to_prov.py +301 -0
- xconv2-0.0.0/xconv2.egg-info/PKG-INFO +141 -0
- xconv2-0.0.0/xconv2.egg-info/SOURCES.txt +97 -0
- xconv2-0.0.0/xconv2.egg-info/dependency_links.txt +1 -0
- xconv2-0.0.0/xconv2.egg-info/entry_points.txt +5 -0
- xconv2-0.0.0/xconv2.egg-info/requires.txt +21 -0
- xconv2-0.0.0/xconv2.egg-info/top_level.txt +1 -0
xconv2-0.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NCAS University of Reading
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
xconv2-0.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xconv2
|
|
3
|
+
Version: 0.0.0
|
|
4
|
+
Summary: High-performance data viewer and simple data converter
|
|
5
|
+
Requires-Python: >=3.12
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: cf-plot>=3.5.0
|
|
9
|
+
Requires-Dist: cf-python>=3.21.0
|
|
10
|
+
Requires-Dist: fsspec
|
|
11
|
+
Requires-Dist: numpy
|
|
12
|
+
Requires-Dist: pandas
|
|
13
|
+
Requires-Dist: paramiko
|
|
14
|
+
Requires-Dist: pillow
|
|
15
|
+
Requires-Dist: prov
|
|
16
|
+
Requires-Dist: pyfive>=1.2.0
|
|
17
|
+
Requires-Dist: PySide6
|
|
18
|
+
Requires-Dist: pystac-client
|
|
19
|
+
Requires-Dist: rdflib
|
|
20
|
+
Requires-Dist: s3fs
|
|
21
|
+
Requires-Dist: setuptools>80
|
|
22
|
+
Requires-Dist: superqt
|
|
23
|
+
Requires-Dist: umfive>=0.2.2
|
|
24
|
+
Requires-Dist: zarr
|
|
25
|
+
Provides-Extra: test
|
|
26
|
+
Requires-Dist: cryptography; extra == "test"
|
|
27
|
+
Requires-Dist: pytest; extra == "test"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# xconv2
|
|
31
|
+
|
|
32
|
+
xconv2 provides (or will provide) a graphical interface to local and remote weather and climate data. It is a replacement for the venerable [xconv](https://ncas-cms.github.io/xconv-doc/html/index.html) package that has been supported by NCAS CMS for decades.
|
|
33
|
+
|
|
34
|
+
<table>
|
|
35
|
+
<tr>
|
|
36
|
+
<td style="vertical-align: middle; padding: 2px;">
|
|
37
|
+
<img src="xconv2/assets/under-construction.svg" alt="Under construction icon" height="128px" />
|
|
38
|
+
</td>
|
|
39
|
+
<td style="vertical-align: middle;">
|
|
40
|
+
This version is under development. If you encounter something that looks like it should work, but doesn't, please
|
|
41
|
+
raise a bug issue at the address found in the About menu. If there is function that you would like to see, feel
|
|
42
|
+
free to raise an enhancement request at the same location.
|
|
43
|
+
</td>
|
|
44
|
+
</tr>
|
|
45
|
+
</table>
|
|
46
|
+
|
|
47
|
+
## Installation
|
|
48
|
+
|
|
49
|
+
We intend to release this as a standalone executable for linux and macos, but for the moment you should use a Python 3.12 (or later) environment with
|
|
50
|
+
udunits2 and cartopy installed (from conda-forge), then you can pip install from the source using one of these:
|
|
51
|
+
|
|
52
|
+
### Alpha
|
|
53
|
+
|
|
54
|
+
We intend to release this as a standalone application (an "app") eventually, but meanwhile, you will likely need a dedicated (or up-to-date) mamba environment with a Python 3.12 (or later) environment with `cartopy` and `udunits2` installed, then you can pip install from PyPI. Here's an example:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
conda create -n xconv2
|
|
58
|
+
conda activate xconv2
|
|
59
|
+
mamba install -c conda-forge pip cartopy udunits2
|
|
60
|
+
pip install xconv2
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
and then you should have `xconv2` available on your command line in that environment. You could of course pip install into your own environment, but you will need to ensure it has cartopy and udunits2 in it (both via conda or mamba).
|
|
64
|
+
|
|
65
|
+
### Conda Environments
|
|
66
|
+
|
|
67
|
+
- `environment.yml`: base development/runtime environment.
|
|
68
|
+
- `environment-integration.yml`: optional integration-test environment, including
|
|
69
|
+
pytest and cryptography for local HTTPS tests, and conda-forge SeaweedFS 4.48
|
|
70
|
+
(the native `weed` binary) for S3 integration tests. No Docker engine, CLI, or Python
|
|
71
|
+
Docker/MinIO packages are needed by the application or tests.
|
|
72
|
+
|
|
73
|
+
See [Running tests](docs/dev_notes.md#running-tests) for setup and skip conditions.
|
|
74
|
+
|
|
75
|
+
### Optional SSH support
|
|
76
|
+
|
|
77
|
+
SSH browsing requires the optional `p5rem` package. It is not a dependency of
|
|
78
|
+
the PyPI package or the base Conda environment. Install it explicitly into the
|
|
79
|
+
environment used to run xconv2:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pip install p5rem
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Without `p5rem`, the SSH tab is greyed out in the remote browsing and
|
|
86
|
+
configuration dialogs. Clicking it displays installation guidance; S3 and
|
|
87
|
+
HTTPS remain available.
|
|
88
|
+
|
|
89
|
+
## Documentation
|
|
90
|
+
|
|
91
|
+
No user documentation is yet available, but it is designed to be intuitive
|
|
92
|
+
and basic usage should be possible without documentation once it is installed.
|
|
93
|
+
|
|
94
|
+
### Raising issues
|
|
95
|
+
|
|
96
|
+
Please raise any issues using the github link from the
|
|
97
|
+
help menu. In doing so, it would be helpful to report
|
|
98
|
+
the science stack used from the science stack report
|
|
99
|
+
also available from the help menu.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
### Developer Documentation
|
|
104
|
+
|
|
105
|
+
Limited developer documentation is available. For the moment it is
|
|
106
|
+
limited to the following:
|
|
107
|
+
|
|
108
|
+
#### UML Diagrams
|
|
109
|
+
|
|
110
|
+
Rendered diagrams (GitHub-friendly):
|
|
111
|
+
|
|
112
|
+
- `docs/uml/svg/CoreWindowCurrentClass.svg`
|
|
113
|
+
- `docs/uml/svg/MainWindowComponentMap.svg`
|
|
114
|
+
- `docs/uml/svg/CoreWindowGuiWorkerSignals.svg`
|
|
115
|
+
- `docs/uml/svg/CoreWindowPhase3OptionsSequence.svg`
|
|
116
|
+
- `docs/uml/svg/RemoteWorkerWarmupSequence.svg`
|
|
117
|
+
- `docs/uml/svg/RemoteAccessModuleCurrent.svg`
|
|
118
|
+
|
|
119
|
+
PlantUML sources:
|
|
120
|
+
|
|
121
|
+
- `docs/uml/alpha_core_window.pu`
|
|
122
|
+
- `docs/uml/main_window_component_map.pu`
|
|
123
|
+
- `docs/uml/core_window_gui_worker_signals.puml`
|
|
124
|
+
- `docs/uml/core_window_options_sequence.puml`
|
|
125
|
+
- `docs/uml/remote_worker_warmup_sequence.puml`
|
|
126
|
+
- `docs/uml/remote_access_module.puml`
|
|
127
|
+
|
|
128
|
+
Regenerate SVGs after editing source diagrams:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
./tools/generate_uml_svgs.sh
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Architecture Notes
|
|
135
|
+
|
|
136
|
+
- `docs/architecture/core_window_refactor.md`
|
|
137
|
+
- `docs/architecture/remote_navigation_and_worker_warmup.md`
|
|
138
|
+
|
|
139
|
+
## License
|
|
140
|
+
|
|
141
|
+
This project is licensed under the MIT License. See `LICENSE`.
|
xconv2-0.0.0/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# xconv2
|
|
2
|
+
|
|
3
|
+
xconv2 provides (or will provide) a graphical interface to local and remote weather and climate data. It is a replacement for the venerable [xconv](https://ncas-cms.github.io/xconv-doc/html/index.html) package that has been supported by NCAS CMS for decades.
|
|
4
|
+
|
|
5
|
+
<table>
|
|
6
|
+
<tr>
|
|
7
|
+
<td style="vertical-align: middle; padding: 2px;">
|
|
8
|
+
<img src="xconv2/assets/under-construction.svg" alt="Under construction icon" height="128px" />
|
|
9
|
+
</td>
|
|
10
|
+
<td style="vertical-align: middle;">
|
|
11
|
+
This version is under development. If you encounter something that looks like it should work, but doesn't, please
|
|
12
|
+
raise a bug issue at the address found in the About menu. If there is function that you would like to see, feel
|
|
13
|
+
free to raise an enhancement request at the same location.
|
|
14
|
+
</td>
|
|
15
|
+
</tr>
|
|
16
|
+
</table>
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
We intend to release this as a standalone executable for linux and macos, but for the moment you should use a Python 3.12 (or later) environment with
|
|
21
|
+
udunits2 and cartopy installed (from conda-forge), then you can pip install from the source using one of these:
|
|
22
|
+
|
|
23
|
+
### Alpha
|
|
24
|
+
|
|
25
|
+
We intend to release this as a standalone application (an "app") eventually, but meanwhile, you will likely need a dedicated (or up-to-date) mamba environment with a Python 3.12 (or later) environment with `cartopy` and `udunits2` installed, then you can pip install from PyPI. Here's an example:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
conda create -n xconv2
|
|
29
|
+
conda activate xconv2
|
|
30
|
+
mamba install -c conda-forge pip cartopy udunits2
|
|
31
|
+
pip install xconv2
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
and then you should have `xconv2` available on your command line in that environment. You could of course pip install into your own environment, but you will need to ensure it has cartopy and udunits2 in it (both via conda or mamba).
|
|
35
|
+
|
|
36
|
+
### Conda Environments
|
|
37
|
+
|
|
38
|
+
- `environment.yml`: base development/runtime environment.
|
|
39
|
+
- `environment-integration.yml`: optional integration-test environment, including
|
|
40
|
+
pytest and cryptography for local HTTPS tests, and conda-forge SeaweedFS 4.48
|
|
41
|
+
(the native `weed` binary) for S3 integration tests. No Docker engine, CLI, or Python
|
|
42
|
+
Docker/MinIO packages are needed by the application or tests.
|
|
43
|
+
|
|
44
|
+
See [Running tests](docs/dev_notes.md#running-tests) for setup and skip conditions.
|
|
45
|
+
|
|
46
|
+
### Optional SSH support
|
|
47
|
+
|
|
48
|
+
SSH browsing requires the optional `p5rem` package. It is not a dependency of
|
|
49
|
+
the PyPI package or the base Conda environment. Install it explicitly into the
|
|
50
|
+
environment used to run xconv2:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install p5rem
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Without `p5rem`, the SSH tab is greyed out in the remote browsing and
|
|
57
|
+
configuration dialogs. Clicking it displays installation guidance; S3 and
|
|
58
|
+
HTTPS remain available.
|
|
59
|
+
|
|
60
|
+
## Documentation
|
|
61
|
+
|
|
62
|
+
No user documentation is yet available, but it is designed to be intuitive
|
|
63
|
+
and basic usage should be possible without documentation once it is installed.
|
|
64
|
+
|
|
65
|
+
### Raising issues
|
|
66
|
+
|
|
67
|
+
Please raise any issues using the github link from the
|
|
68
|
+
help menu. In doing so, it would be helpful to report
|
|
69
|
+
the science stack used from the science stack report
|
|
70
|
+
also available from the help menu.
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### Developer Documentation
|
|
75
|
+
|
|
76
|
+
Limited developer documentation is available. For the moment it is
|
|
77
|
+
limited to the following:
|
|
78
|
+
|
|
79
|
+
#### UML Diagrams
|
|
80
|
+
|
|
81
|
+
Rendered diagrams (GitHub-friendly):
|
|
82
|
+
|
|
83
|
+
- `docs/uml/svg/CoreWindowCurrentClass.svg`
|
|
84
|
+
- `docs/uml/svg/MainWindowComponentMap.svg`
|
|
85
|
+
- `docs/uml/svg/CoreWindowGuiWorkerSignals.svg`
|
|
86
|
+
- `docs/uml/svg/CoreWindowPhase3OptionsSequence.svg`
|
|
87
|
+
- `docs/uml/svg/RemoteWorkerWarmupSequence.svg`
|
|
88
|
+
- `docs/uml/svg/RemoteAccessModuleCurrent.svg`
|
|
89
|
+
|
|
90
|
+
PlantUML sources:
|
|
91
|
+
|
|
92
|
+
- `docs/uml/alpha_core_window.pu`
|
|
93
|
+
- `docs/uml/main_window_component_map.pu`
|
|
94
|
+
- `docs/uml/core_window_gui_worker_signals.puml`
|
|
95
|
+
- `docs/uml/core_window_options_sequence.puml`
|
|
96
|
+
- `docs/uml/remote_worker_warmup_sequence.puml`
|
|
97
|
+
- `docs/uml/remote_access_module.puml`
|
|
98
|
+
|
|
99
|
+
Regenerate SVGs after editing source diagrams:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
./tools/generate_uml_svgs.sh
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
#### Architecture Notes
|
|
106
|
+
|
|
107
|
+
- `docs/architecture/core_window_refactor.md`
|
|
108
|
+
- `docs/architecture/remote_navigation_and_worker_warmup.md`
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
|
|
112
|
+
This project is licensed under the MIT License. See `LICENSE`.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=80"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "xconv2"
|
|
7
|
+
description = "High-performance data viewer and simple data converter"
|
|
8
|
+
requires-python = ">=3.12"
|
|
9
|
+
dependencies = [
|
|
10
|
+
"cf-plot>=3.5.0",
|
|
11
|
+
"cf-python>=3.21.0",
|
|
12
|
+
"fsspec",
|
|
13
|
+
"numpy",
|
|
14
|
+
"pandas",
|
|
15
|
+
"paramiko",
|
|
16
|
+
"pillow",
|
|
17
|
+
"prov",
|
|
18
|
+
"pyfive>=1.2.0",
|
|
19
|
+
"PySide6",
|
|
20
|
+
"pystac-client",
|
|
21
|
+
"rdflib",
|
|
22
|
+
"s3fs",
|
|
23
|
+
"setuptools>80", # cf-plot imports distutils
|
|
24
|
+
"superqt",
|
|
25
|
+
"umfive>=0.2.2",
|
|
26
|
+
"zarr",
|
|
27
|
+
]
|
|
28
|
+
dynamic = [
|
|
29
|
+
"readme",
|
|
30
|
+
"version",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
test = [
|
|
35
|
+
"cryptography",
|
|
36
|
+
"pytest",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.gui-scripts]
|
|
40
|
+
# This creates an 'xconv2' command that launches your GUI
|
|
41
|
+
xconv2 = "xconv2.gui:main"
|
|
42
|
+
|
|
43
|
+
[project.scripts]
|
|
44
|
+
# This creates a 'cf-worker' command for the backend process
|
|
45
|
+
cf-worker = "xconv2.worker:main"
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
where = ["."]
|
|
49
|
+
include = ["xconv2*"]
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.package-data]
|
|
52
|
+
xconv2 = ["assets/*.svg", "assets/*.png"]
|
|
53
|
+
|
|
54
|
+
[tool.setuptools.dynamic]
|
|
55
|
+
readme = {file = "README.md", content-type = "text/markdown"}
|
|
56
|
+
|
|
57
|
+
[tool.setuptools_scm]
|
|
58
|
+
version_scheme = "release-branch-semver"
|
|
59
|
+
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
testpaths = ["tests"]
|
|
62
|
+
markers = [
|
|
63
|
+
"integration: tests exercising local HTTPS or native SeaweedFS S3 services (no Docker)",
|
|
64
|
+
]
|
|
65
|
+
filterwarnings = [
|
|
66
|
+
"ignore:distutils Version classes are deprecated. Use packaging.version instead.:DeprecationWarning:cfplot.cfplot",
|
|
67
|
+
"ignore:'maxsplit' is passed as positional argument:DeprecationWarning:cf.functions",
|
|
68
|
+
]
|
xconv2-0.0.0/setup.cfg
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""Tests for animation protocol encoding and decoding."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import base64
|
|
6
|
+
import pickle
|
|
7
|
+
import time
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
|
|
11
|
+
from xconv2.animation_protocol import (
|
|
12
|
+
AnimationEnd,
|
|
13
|
+
AnimationError,
|
|
14
|
+
AnimationFrame,
|
|
15
|
+
AnimationMetadata,
|
|
16
|
+
AnimationStart,
|
|
17
|
+
decode_payload,
|
|
18
|
+
encode_payload,
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestAnimationMetadata:
|
|
23
|
+
"""Tests for AnimationMetadata serialization."""
|
|
24
|
+
|
|
25
|
+
def test_metadata_to_dict(self) -> None:
|
|
26
|
+
meta = AnimationMetadata(
|
|
27
|
+
session_id="sess-123",
|
|
28
|
+
total_frames=10,
|
|
29
|
+
fps_hint=12.0,
|
|
30
|
+
title_template="{title} [{frame}]",
|
|
31
|
+
plot_kind="contour",
|
|
32
|
+
levels_locked=True,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
data = meta.to_dict()
|
|
36
|
+
|
|
37
|
+
assert data["session_id"] == "sess-123"
|
|
38
|
+
assert data["total_frames"] == 10
|
|
39
|
+
assert data["fps_hint"] == 12.0
|
|
40
|
+
assert data["title_template"] == "{title} [{frame}]"
|
|
41
|
+
assert data["plot_kind"] == "contour"
|
|
42
|
+
assert data["levels_locked"] is True
|
|
43
|
+
|
|
44
|
+
def test_metadata_from_dict(self) -> None:
|
|
45
|
+
data = {
|
|
46
|
+
"session_id": "sess-123",
|
|
47
|
+
"total_frames": 10,
|
|
48
|
+
"fps_hint": 12.0,
|
|
49
|
+
"title_template": "{title} [{frame}]",
|
|
50
|
+
"plot_kind": "contour",
|
|
51
|
+
"levels_locked": True,
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
meta = AnimationMetadata.from_dict(data)
|
|
55
|
+
|
|
56
|
+
assert meta.session_id == "sess-123"
|
|
57
|
+
assert meta.total_frames == 10
|
|
58
|
+
assert meta.fps_hint == 12.0
|
|
59
|
+
assert meta.title_template == "{title} [{frame}]"
|
|
60
|
+
assert meta.plot_kind == "contour"
|
|
61
|
+
assert meta.levels_locked is True
|
|
62
|
+
|
|
63
|
+
def test_metadata_from_dict_partial(self) -> None:
|
|
64
|
+
data = {"session_id": "sess-123"}
|
|
65
|
+
|
|
66
|
+
meta = AnimationMetadata.from_dict(data)
|
|
67
|
+
|
|
68
|
+
assert meta.session_id == "sess-123"
|
|
69
|
+
assert meta.total_frames is None
|
|
70
|
+
assert meta.fps_hint is None
|
|
71
|
+
assert meta.plot_kind == "contour"
|
|
72
|
+
assert meta.levels_locked is False
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class TestAnimationFrame:
|
|
76
|
+
"""Tests for AnimationFrame serialization."""
|
|
77
|
+
|
|
78
|
+
def test_frame_to_dict(self) -> None:
|
|
79
|
+
now = time.time()
|
|
80
|
+
png_data = b"PNG\x89\x01\x02\x03"
|
|
81
|
+
|
|
82
|
+
frame = AnimationFrame(
|
|
83
|
+
request_id="req-123",
|
|
84
|
+
session_id="sess-123",
|
|
85
|
+
frame_index=5,
|
|
86
|
+
total_frames=10,
|
|
87
|
+
png_bytes=png_data,
|
|
88
|
+
frame_value_label="frame 5",
|
|
89
|
+
emitted_at=now,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
data = frame.to_dict()
|
|
93
|
+
|
|
94
|
+
assert data["request_id"] == "req-123"
|
|
95
|
+
assert data["session_id"] == "sess-123"
|
|
96
|
+
assert data["frame_index"] == 5
|
|
97
|
+
assert data["total_frames"] == 10
|
|
98
|
+
assert data["png_bytes"] == png_data
|
|
99
|
+
assert data["frame_value_label"] == "frame 5"
|
|
100
|
+
assert data["emitted_at"] == now
|
|
101
|
+
|
|
102
|
+
def test_frame_from_dict(self) -> None:
|
|
103
|
+
now = time.time()
|
|
104
|
+
png_data = b"PNG\x89\x01\x02\x03"
|
|
105
|
+
|
|
106
|
+
data = {
|
|
107
|
+
"request_id": "req-123",
|
|
108
|
+
"session_id": "sess-123",
|
|
109
|
+
"frame_index": 5,
|
|
110
|
+
"total_frames": 10,
|
|
111
|
+
"png_bytes": png_data,
|
|
112
|
+
"frame_value_label": "frame 5",
|
|
113
|
+
"emitted_at": now,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
frame = AnimationFrame.from_dict(data)
|
|
117
|
+
|
|
118
|
+
assert frame.request_id == "req-123"
|
|
119
|
+
assert frame.session_id == "sess-123"
|
|
120
|
+
assert frame.frame_index == 5
|
|
121
|
+
assert frame.total_frames == 10
|
|
122
|
+
assert frame.png_bytes == png_data
|
|
123
|
+
assert frame.frame_value_label == "frame 5"
|
|
124
|
+
assert frame.emitted_at == now
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class TestAnimationStart:
|
|
128
|
+
"""Tests for AnimationStart serialization."""
|
|
129
|
+
|
|
130
|
+
def test_start_to_dict(self) -> None:
|
|
131
|
+
now = time.time()
|
|
132
|
+
|
|
133
|
+
start = AnimationStart(
|
|
134
|
+
request_id="req-123",
|
|
135
|
+
session_id="sess-123",
|
|
136
|
+
total_frames=10,
|
|
137
|
+
fps_hint=12.0,
|
|
138
|
+
title_template="{title} [{frame}]",
|
|
139
|
+
started_at=now,
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
data = start.to_dict()
|
|
143
|
+
|
|
144
|
+
assert data["request_id"] == "req-123"
|
|
145
|
+
assert data["session_id"] == "sess-123"
|
|
146
|
+
assert data["total_frames"] == 10
|
|
147
|
+
assert data["fps_hint"] == 12.0
|
|
148
|
+
assert data["title_template"] == "{title} [{frame}]"
|
|
149
|
+
assert data["started_at"] == now
|
|
150
|
+
|
|
151
|
+
def test_start_from_dict(self) -> None:
|
|
152
|
+
now = time.time()
|
|
153
|
+
|
|
154
|
+
data = {
|
|
155
|
+
"request_id": "req-123",
|
|
156
|
+
"session_id": "sess-123",
|
|
157
|
+
"total_frames": 10,
|
|
158
|
+
"fps_hint": 12.0,
|
|
159
|
+
"title_template": "{title} [{frame}]",
|
|
160
|
+
"started_at": now,
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
start = AnimationStart.from_dict(data)
|
|
164
|
+
|
|
165
|
+
assert start.request_id == "req-123"
|
|
166
|
+
assert start.session_id == "sess-123"
|
|
167
|
+
assert start.total_frames == 10
|
|
168
|
+
assert start.fps_hint == 12.0
|
|
169
|
+
assert start.title_template == "{title} [{frame}]"
|
|
170
|
+
assert start.started_at == now
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class TestAnimationEnd:
|
|
174
|
+
"""Tests for AnimationEnd serialization."""
|
|
175
|
+
|
|
176
|
+
def test_end_to_dict(self) -> None:
|
|
177
|
+
now = time.time()
|
|
178
|
+
|
|
179
|
+
end = AnimationEnd(
|
|
180
|
+
request_id="req-123",
|
|
181
|
+
session_id="sess-123",
|
|
182
|
+
frames_emitted=10,
|
|
183
|
+
completed_at=now,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
data = end.to_dict()
|
|
187
|
+
|
|
188
|
+
assert data["request_id"] == "req-123"
|
|
189
|
+
assert data["session_id"] == "sess-123"
|
|
190
|
+
assert data["frames_emitted"] == 10
|
|
191
|
+
assert data["completed_at"] == now
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
class TestAnimationError:
|
|
195
|
+
"""Tests for AnimationError serialization."""
|
|
196
|
+
|
|
197
|
+
def test_error_to_dict(self) -> None:
|
|
198
|
+
now = time.time()
|
|
199
|
+
|
|
200
|
+
error = AnimationError(
|
|
201
|
+
request_id="req-123",
|
|
202
|
+
session_id="sess-123",
|
|
203
|
+
frame_index=5,
|
|
204
|
+
error="Contour failed",
|
|
205
|
+
failed_at=now,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
data = error.to_dict()
|
|
209
|
+
|
|
210
|
+
assert data["request_id"] == "req-123"
|
|
211
|
+
assert data["session_id"] == "sess-123"
|
|
212
|
+
assert data["frame_index"] == 5
|
|
213
|
+
assert data["error"] == "Contour failed"
|
|
214
|
+
assert data["failed_at"] == now
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class TestPayloadEncoding:
|
|
218
|
+
"""Tests for payload encoding and decoding."""
|
|
219
|
+
|
|
220
|
+
def test_encode_decode_roundtrip(self) -> None:
|
|
221
|
+
payload = {
|
|
222
|
+
"request_id": "req-123",
|
|
223
|
+
"session_id": "sess-123",
|
|
224
|
+
"frame_index": 5,
|
|
225
|
+
"data": "test",
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
encoded = encode_payload(payload)
|
|
229
|
+
|
|
230
|
+
assert isinstance(encoded, str)
|
|
231
|
+
assert encoded == base64.b64encode(pickle.dumps(payload)).decode("ascii")
|
|
232
|
+
|
|
233
|
+
decoded = decode_payload(encoded)
|
|
234
|
+
|
|
235
|
+
assert decoded == payload
|
|
236
|
+
|
|
237
|
+
def test_encode_with_binary_data(self) -> None:
|
|
238
|
+
payload = {
|
|
239
|
+
"png_bytes": b"PNG\x89\x01\x02\x03",
|
|
240
|
+
"request_id": "req-123",
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
encoded = encode_payload(payload)
|
|
244
|
+
decoded = decode_payload(encoded)
|
|
245
|
+
|
|
246
|
+
assert decoded["png_bytes"] == b"PNG\x89\x01\x02\x03"
|
|
247
|
+
assert decoded["request_id"] == "req-123"
|