esgpull 0.9.0__tar.gz → 0.9.1__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.
- {esgpull-0.9.0 → esgpull-0.9.1}/PKG-INFO +18 -3
- {esgpull-0.9.0 → esgpull-0.9.1}/README.md +17 -2
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/index.md +4 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/installation.md +17 -36
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/remove.py +9 -3
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/self.py +1 -1
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/update.py +38 -38
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/config.py +1 -1
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/database.py +12 -4
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/fs.py +9 -20
- esgpull-0.9.1/esgpull/migrations/versions/0.9.1_update_tables.py +28 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/sql.py +8 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/pyproject.toml +43 -49
- {esgpull-0.9.0 → esgpull-0.9.1}/requirements-dev.lock +17 -19
- {esgpull-0.9.0 → esgpull-0.9.1}/requirements.lock +7 -8
- esgpull-0.9.1/tests/cli/test_remove.py +76 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_fs.py +43 -41
- {esgpull-0.9.0 → esgpull-0.9.1}/uv.lock +676 -990
- esgpull-0.9.0/recipe/meta.yaml +0 -60
- esgpull-0.9.0/recipe/recipe.yaml +0 -58
- {esgpull-0.9.0 → esgpull-0.9.1}/.github/workflows/ci.yml +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/.github/workflows/doc.yml +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/.github/workflows/pypi-publish.yml +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/.gitignore +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/.pre-commit-config.yaml +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/CITATION.cff +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/LICENSE +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/alembic.ini +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/configuration.md +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/download.md +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/glossary.md +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/download_1.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/download_2.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/download_3.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/download_4.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/download_5.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/download_6.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/intro_1.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/intro_2.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/intro_3.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/intro_4.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/intro_5.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/intro_6.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/quickstart_1.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/search_1.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/search_2.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/search_3.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/search_4.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/search_5.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/search_6.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/search_7.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/images/search_ignore.svg +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/plugins.md +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/queries.md +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/quickstart.md +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/search.md +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/docs/stylesheets/extra.css +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/includes/abbreviations.md +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/docs/mkdocs.yml +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/__init__.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/auth.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/__init__.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/add.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/autoremove.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/config.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/convert.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/decorators.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/download.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/facet.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/get.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/install.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/login.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/plugins.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/retry.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/search.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/show.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/status.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/track.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/cli/utils.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/constants.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/context.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/download.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/esgpull.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/exceptions.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/graph.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/install_config.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/README +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/env.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/script.py.mako +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.3.0_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.3.1_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.3.2_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.3.3_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.3.4_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.3.5_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.3.6_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.3.7_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.3.8_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.4.0_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.5.0_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.5.1_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.5.2_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.5.3_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.5.4_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.5.5_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.6.0_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.6.1_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.6.2_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.6.3_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.6.4_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.6.5_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.7.0_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.7.1_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.7.2_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.7.3_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.8.0_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/0.9.0_update_tables.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/14c72daea083_query_add_column_updated_at.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/c7c8541fa741_query_add_column_added_at.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/d14f179e553c_file_add_composite_index_dataset_id_.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/migrations/versions/e7edab5d4e4b_add_dataset_tracking.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/__init__.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/base.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/dataset.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/facet.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/file.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/options.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/query.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/selection.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/synda_file.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/tag.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/models/utils.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/plugin.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/processor.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/py.typed +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/result.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/tui.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/utils.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/esgpull/version.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/pdm.lock +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/__init__.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/assets/error_plugin.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/assets/incompatible_plugin.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/assets/priority_test_plugin.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/assets/sample_plugin.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/cli/__init__.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/cli/test_dataset.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/cli/test_parse.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/cli/test_plugin_cli.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/cli/test_show_dates.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/cli/test_update.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/conftest.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_auth.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_config.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_context.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_dataset.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_db.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_esgpull.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_graph.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_plugin.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_processor.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_query.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_selection.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_synda.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/test_utils.py +0 -0
- {esgpull-0.9.0 → esgpull-0.9.1}/tests/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: esgpull
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.1
|
|
4
4
|
Summary: ESGF data discovery, download, replication tool
|
|
5
5
|
Project-URL: Repository, https://github.com/ESGF/esgf-download
|
|
6
6
|
Project-URL: Documentation, https://esgf.github.io/esgf-download/
|
|
@@ -63,14 +63,29 @@ for dataset in datasets:
|
|
|
63
63
|
|
|
64
64
|
## Installation
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
`esgpull` is distributed via PyPI:
|
|
67
67
|
|
|
68
68
|
```shell
|
|
69
69
|
pip install esgpull
|
|
70
|
+
esgpull --help
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
For isolated installation, [`uv`](https://github.com/astral-sh/uv) or
|
|
74
|
+
[`pipx`](https://github.com/pypa/pipx) are recommended:
|
|
75
|
+
|
|
76
|
+
```shell
|
|
77
|
+
# with uv
|
|
78
|
+
uv tool install esgpull
|
|
79
|
+
esgpull --help
|
|
80
|
+
|
|
81
|
+
# alternatively, uvx enables running without explicit installation (comes with uv)
|
|
82
|
+
uvx esgpull --help
|
|
70
83
|
```
|
|
71
84
|
|
|
72
85
|
```shell
|
|
73
|
-
|
|
86
|
+
# with pipx
|
|
87
|
+
pipx install esgpull
|
|
88
|
+
esgpull --help
|
|
74
89
|
```
|
|
75
90
|
|
|
76
91
|
## Usage
|
|
@@ -27,14 +27,29 @@ for dataset in datasets:
|
|
|
27
27
|
|
|
28
28
|
## Installation
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
`esgpull` is distributed via PyPI:
|
|
31
31
|
|
|
32
32
|
```shell
|
|
33
33
|
pip install esgpull
|
|
34
|
+
esgpull --help
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For isolated installation, [`uv`](https://github.com/astral-sh/uv) or
|
|
38
|
+
[`pipx`](https://github.com/pypa/pipx) are recommended:
|
|
39
|
+
|
|
40
|
+
```shell
|
|
41
|
+
# with uv
|
|
42
|
+
uv tool install esgpull
|
|
43
|
+
esgpull --help
|
|
44
|
+
|
|
45
|
+
# alternatively, uvx enables running without explicit installation (comes with uv)
|
|
46
|
+
uvx esgpull --help
|
|
34
47
|
```
|
|
35
48
|
|
|
36
49
|
```shell
|
|
37
|
-
|
|
50
|
+
# with pipx
|
|
51
|
+
pipx install esgpull
|
|
52
|
+
esgpull --help
|
|
38
53
|
```
|
|
39
54
|
|
|
40
55
|
## Usage
|
|
@@ -76,6 +76,10 @@ Have a look at the [Installation page](installation) for more ways to install.
|
|
|
76
76
|
|
|
77
77
|
Jump directly to the [Quickstart guide](quickstart) to get to know how to use `esgpull`.
|
|
78
78
|
|
|
79
|
+
## How to Cite
|
|
80
|
+
|
|
81
|
+
If you use esgpull in your research, please cite it using the information provided in our [CITATION.cff](https://github.com/ESGF/esgf-download/blob/main/CITATION.cff) file.
|
|
82
|
+
|
|
79
83
|
|
|
80
84
|
<!-- [ESGF portal]: https://esgf-node.ipsl.upmc.fr/search/cmip6-ipsl -->
|
|
81
85
|
[ESGF Search API]: https://esgf.github.io/esg-search/ESGF_Search_RESTful_API.html
|
|
@@ -7,50 +7,31 @@ This document covers a few ways to install `esgpull`, a necessary first step int
|
|
|
7
7
|
!!! note "Supporting lower python versions could be done with future releases, do not hesitate to ask for it."
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
##
|
|
10
|
+
## Installation
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
`esgpull` is distributed via PyPI:
|
|
13
13
|
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
For `mamba` users:
|
|
19
|
-
|
|
20
|
-
```sh
|
|
21
|
-
mamba create --name my_env_name esgpull --channel ipsl --channel conda-forge
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
You can start using `esgpull` after activating the environment:
|
|
25
|
-
|
|
26
|
-
```sh
|
|
27
|
-
conda activate my_env_name
|
|
28
|
-
esgpull --version
|
|
14
|
+
```shell
|
|
15
|
+
pip install esgpull
|
|
16
|
+
esgpull --help
|
|
29
17
|
```
|
|
30
18
|
|
|
19
|
+
For isolated installation, [`uv`](https://github.com/astral-sh/uv) or
|
|
20
|
+
[`pipx`](https://github.com/pypa/pipx) are recommended:
|
|
31
21
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
```shell
|
|
23
|
+
# with uv
|
|
24
|
+
uv tool install esgpull
|
|
25
|
+
esgpull --help
|
|
35
26
|
|
|
36
|
-
|
|
37
|
-
|
|
27
|
+
# alternatively, uvx enables running without explicit installation (comes with uv)
|
|
28
|
+
uvx esgpull --help
|
|
38
29
|
```
|
|
39
30
|
|
|
40
|
-
|
|
41
|
-
## Install from source
|
|
42
|
-
|
|
43
|
-
Esgpull is developed and maintained on GitHub, you can clone the public repository with:
|
|
44
|
-
|
|
45
31
|
```shell
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
And then install with `pip`:
|
|
50
|
-
|
|
51
|
-
```
|
|
52
|
-
cd esg-pull
|
|
53
|
-
python -m pip install .
|
|
32
|
+
# with pipx
|
|
33
|
+
pipx install esgpull
|
|
34
|
+
esgpull --help
|
|
54
35
|
```
|
|
55
36
|
|
|
56
37
|
|
|
@@ -93,4 +74,4 @@ Installing `esgpull` is the first step to using it, but not the only one.
|
|
|
93
74
|
|
|
94
75
|
## Configuration
|
|
95
76
|
|
|
96
|
-
`esgpull` is highly configurable, and it is recommended to take a look at the [configuration](configuration.md) page to learn more about it.
|
|
77
|
+
`esgpull` is highly configurable, and it is recommended to take a look at the [configuration](configuration.md) page to learn more about it.
|
|
@@ -15,11 +15,13 @@ from esgpull.utils import format_size
|
|
|
15
15
|
@args.query_id
|
|
16
16
|
@opts.tag
|
|
17
17
|
@opts.children
|
|
18
|
+
@opts.yes
|
|
18
19
|
@opts.verbosity
|
|
19
20
|
def remove(
|
|
20
21
|
query_id: str | None,
|
|
21
22
|
tag: str | None,
|
|
22
23
|
children: bool,
|
|
24
|
+
yes: bool,
|
|
23
25
|
verbosity: Verbosity,
|
|
24
26
|
) -> None:
|
|
25
27
|
"""
|
|
@@ -49,7 +51,7 @@ def remove(
|
|
|
49
51
|
graph.add(*queries)
|
|
50
52
|
esg.ui.print(graph)
|
|
51
53
|
msg = f"Remove {nb} quer{ies}?"
|
|
52
|
-
if not esg.ui.ask(msg, default=True):
|
|
54
|
+
if not yes and not esg.ui.ask(msg, default=True):
|
|
53
55
|
raise Abort
|
|
54
56
|
for query in queries:
|
|
55
57
|
if query.has_files:
|
|
@@ -59,14 +61,18 @@ def remove(
|
|
|
59
61
|
f":stop_sign: {query.rich_name} is linked"
|
|
60
62
|
f" to {nb} downloaded files ({format_size(size)})."
|
|
61
63
|
)
|
|
62
|
-
if not esg.ui.ask(
|
|
64
|
+
if not yes and not esg.ui.ask(
|
|
65
|
+
"Delete anyway?", default=False
|
|
66
|
+
):
|
|
63
67
|
raise Abort
|
|
64
68
|
if not children and esg.graph.get_children(query.sha):
|
|
65
69
|
esg.ui.print(
|
|
66
70
|
":stop_sign: Some queries block"
|
|
67
71
|
f" removal of {query.rich_name}."
|
|
68
72
|
)
|
|
69
|
-
if esg.ui.ask(
|
|
73
|
+
if not yes and esg.ui.ask(
|
|
74
|
+
"Show blocking queries?", default=False
|
|
75
|
+
):
|
|
70
76
|
esg.ui.print(esg.graph.subgraph(query, children=True))
|
|
71
77
|
raise Exit(1)
|
|
72
78
|
esg.db.delete(*queries)
|
|
@@ -199,7 +199,7 @@ def delete():
|
|
|
199
199
|
TempUI.print(f"Deleting {path} from config...")
|
|
200
200
|
TempUI.print("To remove all files from this install, run:\n")
|
|
201
201
|
config = Config.load(path=path)
|
|
202
|
-
for p in config.paths:
|
|
202
|
+
for p in config.paths.values():
|
|
203
203
|
if not p.is_relative_to(path):
|
|
204
204
|
TempUI.print(f"$ rm -rf {p}")
|
|
205
205
|
TempUI.print(f"$ rm -rf {path}")
|
|
@@ -11,7 +11,7 @@ from esgpull.cli.utils import get_queries, init_esgpull, valid_name_tag
|
|
|
11
11
|
from esgpull.context import HintsDict, ResultSearch
|
|
12
12
|
from esgpull.exceptions import UnsetOptionsError
|
|
13
13
|
from esgpull.models import Dataset, File, FileStatus, Query
|
|
14
|
-
from esgpull.tui import Verbosity
|
|
14
|
+
from esgpull.tui import Verbosity
|
|
15
15
|
from esgpull.utils import format_size
|
|
16
16
|
|
|
17
17
|
|
|
@@ -177,26 +177,37 @@ def update(
|
|
|
177
177
|
for qf, qf_files in zip(qfs, files):
|
|
178
178
|
qf.files = qf_files
|
|
179
179
|
for qf in qfs:
|
|
180
|
-
new_files = [f for f in qf.files if f not in esg.db]
|
|
181
|
-
new_datasets = [d for d in qf.datasets if d not in esg.db]
|
|
182
|
-
nb_datasets = len(new_datasets)
|
|
183
|
-
nb_files = len(new_files)
|
|
184
180
|
if not qf.query.tracked:
|
|
185
181
|
esg.db.add(qf.query)
|
|
186
182
|
continue
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
183
|
+
with esg.db.commit_context():
|
|
184
|
+
unregistered_datasets = [
|
|
185
|
+
f for f in qf.datasets if f not in esg.db
|
|
186
|
+
]
|
|
187
|
+
if len(unregistered_datasets) > 0:
|
|
188
|
+
esg.ui.print(
|
|
189
|
+
f"Adding {len(unregistered_datasets)} new datasets to database."
|
|
190
|
+
)
|
|
191
|
+
esg.db.session.add_all(unregistered_datasets)
|
|
192
|
+
files_from_db = [
|
|
193
|
+
esg.db.get(File, f.sha) for f in qf.files if f in esg.db
|
|
194
|
+
]
|
|
195
|
+
registered_files = [f for f in files_from_db if f is not None]
|
|
196
|
+
unregistered_files = [f for f in qf.files if f not in esg.db]
|
|
197
|
+
if len(unregistered_files) > 0:
|
|
198
|
+
esg.ui.print(
|
|
199
|
+
f"Adding {len(unregistered_files)} new files to database."
|
|
200
|
+
)
|
|
201
|
+
esg.db.session.add_all(unregistered_files)
|
|
202
|
+
files = registered_files + unregistered_files
|
|
203
|
+
not_done_files = [
|
|
204
|
+
file for file in files if file.status != FileStatus.Done
|
|
205
|
+
]
|
|
206
|
+
download_size = sum(file.size for file in not_done_files)
|
|
195
207
|
msg = (
|
|
196
|
-
f"\n{qf.query.rich_name}: {
|
|
197
|
-
f" files
|
|
198
|
-
f"
|
|
199
|
-
f"\nUpdate the database{queue_msg}?"
|
|
208
|
+
f"\n{qf.query.rich_name}: {len(not_done_files)} "
|
|
209
|
+
f" files ({format_size(download_size)}) to download."
|
|
210
|
+
f"\nLink to query and send to download queue?"
|
|
200
211
|
)
|
|
201
212
|
if yes:
|
|
202
213
|
choice = "y"
|
|
@@ -212,30 +223,19 @@ def update(
|
|
|
212
223
|
if choice == "y":
|
|
213
224
|
legacy = esg.legacy_query
|
|
214
225
|
has_legacy = legacy.state.persistent
|
|
226
|
+
applied_changes = False
|
|
215
227
|
with esg.db.commit_context():
|
|
216
|
-
for dataset in esg.ui.track(
|
|
217
|
-
new_datasets,
|
|
218
|
-
description=f"{qf.query.rich_name} (datasets)",
|
|
219
|
-
):
|
|
220
|
-
esg.db.session.add(dataset)
|
|
221
228
|
for file in esg.ui.track(
|
|
222
|
-
|
|
223
|
-
description=f"{qf.query.rich_name}
|
|
229
|
+
files,
|
|
230
|
+
description=f"{qf.query.rich_name}",
|
|
224
231
|
):
|
|
225
|
-
|
|
226
|
-
if file_db is None:
|
|
227
|
-
if esg.db.has_file_id(file):
|
|
228
|
-
logger.error(
|
|
229
|
-
"File id already exists in database, "
|
|
230
|
-
"there might be an error with its checksum"
|
|
231
|
-
f"\n{file}"
|
|
232
|
-
)
|
|
233
|
-
continue
|
|
232
|
+
if file.status != FileStatus.Done:
|
|
234
233
|
file.status = FileStatus.Queued
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
234
|
+
if has_legacy and legacy in file.queries:
|
|
235
|
+
_ = esg.db.unlink(query=legacy, file=file)
|
|
236
|
+
changed = esg.db.link(query=qf.query, file=file)
|
|
237
|
+
applied_changes = applied_changes or changed
|
|
238
|
+
if applied_changes:
|
|
239
|
+
qf.query.updated_at = datetime.now(timezone.utc)
|
|
240
240
|
esg.db.session.add(qf.query)
|
|
241
241
|
esg.ui.raise_maybe_record(Exit(0))
|
|
@@ -147,11 +147,19 @@ class Database:
|
|
|
147
147
|
for item in items:
|
|
148
148
|
make_transient(item)
|
|
149
149
|
|
|
150
|
-
def link(self, query: Query, file: File):
|
|
151
|
-
self.session.
|
|
150
|
+
def link(self, query: Query, file: File) -> bool:
|
|
151
|
+
if not self.session.scalar(sql.query_file.is_linked(query, file)):
|
|
152
|
+
self.session.execute(sql.query_file.link(query, file))
|
|
153
|
+
return True
|
|
154
|
+
else:
|
|
155
|
+
return False
|
|
152
156
|
|
|
153
|
-
def unlink(self, query: Query, file: File):
|
|
154
|
-
self.session.
|
|
157
|
+
def unlink(self, query: Query, file: File) -> bool:
|
|
158
|
+
if self.session.scalar(sql.query_file.is_linked(query, file)):
|
|
159
|
+
self.session.execute(sql.query_file.unlink(query, file))
|
|
160
|
+
return True
|
|
161
|
+
else:
|
|
162
|
+
return False
|
|
155
163
|
|
|
156
164
|
def __contains__(self, item: Base | BaseNoSHA) -> bool:
|
|
157
165
|
mapper = inspect(item.__class__)
|
|
@@ -10,7 +10,7 @@ from shutil import copyfile
|
|
|
10
10
|
import aiofiles
|
|
11
11
|
from aiofiles.threadpool.binary import AsyncBufferedIOBase
|
|
12
12
|
|
|
13
|
-
from esgpull.config import Config
|
|
13
|
+
from esgpull.config import Config, Paths
|
|
14
14
|
from esgpull.models import File
|
|
15
15
|
from esgpull.result import Err, Ok, Result
|
|
16
16
|
from esgpull.tui import logger
|
|
@@ -63,45 +63,34 @@ class Digest:
|
|
|
63
63
|
|
|
64
64
|
@dataclass
|
|
65
65
|
class Filesystem:
|
|
66
|
-
|
|
67
|
-
data: Path
|
|
68
|
-
db: Path
|
|
69
|
-
log: Path
|
|
70
|
-
tmp: Path
|
|
66
|
+
paths: Paths
|
|
71
67
|
disable_checksum: bool = False
|
|
72
68
|
install: InitVar[bool] = True
|
|
73
69
|
|
|
74
70
|
@staticmethod
|
|
75
71
|
def from_config(config: Config, install: bool = False) -> Filesystem:
|
|
76
72
|
return Filesystem(
|
|
77
|
-
|
|
78
|
-
data=config.paths.data,
|
|
79
|
-
db=config.paths.db,
|
|
80
|
-
log=config.paths.log,
|
|
81
|
-
tmp=config.paths.tmp,
|
|
73
|
+
paths=config.paths,
|
|
82
74
|
disable_checksum=config.download.disable_checksum,
|
|
83
75
|
install=install,
|
|
84
76
|
)
|
|
85
77
|
|
|
86
78
|
def __post_init__(self, install: bool = True) -> None:
|
|
87
79
|
if install:
|
|
88
|
-
self.
|
|
89
|
-
|
|
90
|
-
self.db.mkdir(parents=True, exist_ok=True)
|
|
91
|
-
self.log.mkdir(parents=True, exist_ok=True)
|
|
92
|
-
self.tmp.mkdir(parents=True, exist_ok=True)
|
|
80
|
+
for path in self.paths.values():
|
|
81
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
93
82
|
|
|
94
83
|
def __getitem__(self, file: File) -> FilePath:
|
|
95
84
|
if not isinstance(file, File):
|
|
96
85
|
raise TypeError(file)
|
|
97
86
|
return FilePath(
|
|
98
|
-
drs=self.data / file.local_path / file.filename,
|
|
99
|
-
tmp=self.tmp / f"{file.sha}.part",
|
|
87
|
+
drs=self.paths.data / file.local_path / file.filename,
|
|
88
|
+
tmp=self.paths.tmp / f"{file.sha}.part",
|
|
100
89
|
)
|
|
101
90
|
|
|
102
91
|
def glob_netcdf(self) -> Iterator[Path]:
|
|
103
|
-
for path in self.data.glob("**/*.nc"):
|
|
104
|
-
yield path.relative_to(self.data)
|
|
92
|
+
for path in self.paths.data.glob("**/*.nc"):
|
|
93
|
+
yield path.relative_to(self.paths.data)
|
|
105
94
|
|
|
106
95
|
def open(self, file: File) -> FileObject:
|
|
107
96
|
return FileObject(self[file])
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""update tables
|
|
2
|
+
|
|
3
|
+
Revision ID: 0.9.1
|
|
4
|
+
Revises: 0.9.0
|
|
5
|
+
Create Date: 2025-08-08 10:38:14.204594
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
from alembic import op
|
|
9
|
+
import sqlalchemy as sa
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# revision identifiers, used by Alembic.
|
|
13
|
+
revision = '0.9.1'
|
|
14
|
+
down_revision = '0.9.0'
|
|
15
|
+
branch_labels = None
|
|
16
|
+
depends_on = None
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def upgrade() -> None:
|
|
20
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
21
|
+
pass
|
|
22
|
+
# ### end Alembic commands ###
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def downgrade() -> None:
|
|
26
|
+
# ### commands auto generated by Alembic - please adjust! ###
|
|
27
|
+
pass
|
|
28
|
+
# ### end Alembic commands ###
|
|
@@ -301,3 +301,11 @@ class query_file:
|
|
|
301
301
|
.where(query_file_proxy.c.query_sha == query.sha)
|
|
302
302
|
.where(query_file_proxy.c.file_sha == file.sha)
|
|
303
303
|
)
|
|
304
|
+
|
|
305
|
+
@staticmethod
|
|
306
|
+
def is_linked(query: Query, file: File) -> sa.Select[tuple[bool]]:
|
|
307
|
+
return sa.select(
|
|
308
|
+
sa.exists()
|
|
309
|
+
.where(query_file_proxy.c.query_sha == query.sha)
|
|
310
|
+
.where(query_file_proxy.c.file_sha == file.sha)
|
|
311
|
+
)
|
|
@@ -4,38 +4,38 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "esgpull"
|
|
7
|
-
version = "0.9.
|
|
7
|
+
version = "0.9.1"
|
|
8
8
|
classifiers = [
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
"License :: OSI Approved :: BSD License",
|
|
10
|
+
"Programming Language :: Python :: 3",
|
|
11
|
+
"Programming Language :: Python :: 3.10",
|
|
12
|
+
"Programming Language :: Python :: 3.11",
|
|
13
|
+
"Programming Language :: Python :: 3.12",
|
|
14
14
|
]
|
|
15
15
|
description = "ESGF data discovery, download, replication tool"
|
|
16
|
-
authors = [{name = "Sven Rodriguez", email = "srodriguez@ipsl.fr"}]
|
|
16
|
+
authors = [{ name = "Sven Rodriguez", email = "srodriguez@ipsl.fr" }]
|
|
17
17
|
readme = "README.md"
|
|
18
18
|
requires-python = ">=3.10"
|
|
19
19
|
dependencies = [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
20
|
+
"MyProxyClient>=2.1.0",
|
|
21
|
+
"aiofiles>=22.1.0",
|
|
22
|
+
"alembic>=1.8.1",
|
|
23
|
+
"click>=8.1.3",
|
|
24
|
+
"click-params>=0.4.0",
|
|
25
|
+
"httpx>=0.23.0",
|
|
26
|
+
"nest-asyncio>=1.5.6",
|
|
27
|
+
"pyOpenSSL>=22.1.0",
|
|
28
|
+
"pyyaml>=6.0",
|
|
29
|
+
"tomlkit>=0.11.5",
|
|
30
|
+
"rich>=12.6.0",
|
|
31
|
+
"sqlalchemy>=2.0.0b2",
|
|
32
|
+
"setuptools>=65.4.1",
|
|
33
|
+
"aiostream>=0.4.5",
|
|
34
|
+
"attrs>=22.1.0",
|
|
35
|
+
"cattrs>=22.2.0",
|
|
36
|
+
"platformdirs>=2.6.2",
|
|
37
|
+
"pyparsing>=3.0.9",
|
|
38
|
+
"packaging>=25.0",
|
|
39
39
|
]
|
|
40
40
|
license.text = "BSD-3-Clause"
|
|
41
41
|
|
|
@@ -69,20 +69,14 @@ src_paths = ["esgpull", "tests", "migrations", "examples"]
|
|
|
69
69
|
ignore_missing_imports = true
|
|
70
70
|
|
|
71
71
|
[tool.pdm.scripts]
|
|
72
|
-
doc = {shell = "cd docs && mkdocs serve", help = "Start doc server"}
|
|
72
|
+
doc = { shell = "cd docs && mkdocs serve", help = "Start doc server" }
|
|
73
73
|
|
|
74
74
|
[tool.pytest.ini_options]
|
|
75
75
|
minversion = "6.2.4"
|
|
76
|
-
filterwarnings = [
|
|
77
|
-
|
|
78
|
-
]
|
|
79
|
-
markers = [
|
|
80
|
-
"slow: mark test as slow to run"
|
|
81
|
-
]
|
|
76
|
+
filterwarnings = ["ignore::DeprecationWarning"]
|
|
77
|
+
markers = ["slow: mark test as slow to run"]
|
|
82
78
|
addopts = "-r aR -n auto --cov=esgpull --cov-config=pyproject.toml --cov-report term-missing:skip-covered --mypy"
|
|
83
|
-
testpaths = [
|
|
84
|
-
"tests/"
|
|
85
|
-
]
|
|
79
|
+
testpaths = ["tests/"]
|
|
86
80
|
|
|
87
81
|
[tool.ruff]
|
|
88
82
|
line-length = 79
|
|
@@ -94,22 +88,22 @@ extend-select = ["I"]
|
|
|
94
88
|
[tool.rye]
|
|
95
89
|
managed = true
|
|
96
90
|
dev-dependencies = [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
91
|
+
"jupyter-console>=6.6.3",
|
|
92
|
+
"typing-extensions>=4.12.2",
|
|
93
|
+
"pytest>=8.3.3",
|
|
94
|
+
"pytest-cov>=5.0.0",
|
|
95
|
+
"mkdocs-material>=9.5.34",
|
|
96
|
+
"mypy>=1.11.2",
|
|
97
|
+
"types-pyyaml>=6.0.12.20240808",
|
|
98
|
+
"types-aiofiles>=24.1.0.20240626",
|
|
99
|
+
"pytest-mypy>=0.10.3",
|
|
100
|
+
"pytest-xdist>=3.6.1",
|
|
101
|
+
"ipdb>=0.13.13",
|
|
102
|
+
"orjson>=3.10.7",
|
|
109
103
|
]
|
|
110
104
|
|
|
111
105
|
[tool.rye.scripts]
|
|
112
|
-
esg = {cmd = "esgpull", env-file = ".env"}
|
|
106
|
+
esg = { cmd = "esgpull", env-file = ".env" }
|
|
113
107
|
|
|
114
108
|
[dependency-groups]
|
|
115
109
|
dev = [
|