datatrail-cli 0.12.0__tar.gz → 0.13.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.
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/.github/workflows/continuous-deployment.yml +3 -6
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/.github/workflows/continuous-integration.yml +28 -16
- datatrail_cli-0.13.0/.release-please-manifest.json +3 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/CHANGELOG.md +132 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/PKG-INFO +1 -1
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/cli.py +8 -3
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/scout.py +21 -4
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/src/functions.py +24 -8
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/utilities/cadcclient.py +6 -2
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/utilities/utilities.py +11 -2
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/pyproject.toml +6 -1
- datatrail_cli-0.13.0/release-please-config.json +15 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/tests/test_cli.py +28 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/tests/test_functions.py +24 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/uv.lock +1 -1
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/.github/workflows/docs.yml +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/.github/workflows/stale.yml +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/.gitignore +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/.pre-commit-config.yaml +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/LICENSE +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/README.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/clear.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/cli.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/commands.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/images/Datatrail-logo.png +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/index.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/initialising.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/install.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/list.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/ps.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/pull.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/scout.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/unregistered.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/docs/user_guide.md +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/__init__.py +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/clear.py +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/config.py +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/config.yaml +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/ls.py +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/ps.py +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/pull.py +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/dtcli/unregistered.py +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/mkdocs.yml +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/tests/test_utils.py +0 -0
- {datatrail_cli-0.12.0 → datatrail_cli-0.13.0}/tox.ini +0 -0
|
@@ -9,20 +9,17 @@ jobs:
|
|
|
9
9
|
steps:
|
|
10
10
|
- name: Create release
|
|
11
11
|
id: release-please
|
|
12
|
-
uses:
|
|
13
|
-
with:
|
|
14
|
-
release-type: python
|
|
15
|
-
package-name: datatrail-cli
|
|
12
|
+
uses: googleapis/release-please-action@v5
|
|
16
13
|
|
|
17
14
|
- name: Checkout code
|
|
18
15
|
if: ${{ steps.release-please.outputs.release_created }}
|
|
19
|
-
uses: actions/checkout@
|
|
16
|
+
uses: actions/checkout@v7
|
|
20
17
|
with:
|
|
21
18
|
fetch-depth: 1
|
|
22
19
|
|
|
23
20
|
- name: Install uv
|
|
24
21
|
if: ${{ steps.release-please.outputs.release_created }}
|
|
25
|
-
uses: astral-sh/setup-uv@
|
|
22
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
26
23
|
with:
|
|
27
24
|
enable-cache: false
|
|
28
25
|
python-version: "3.13"
|
|
@@ -15,10 +15,10 @@ jobs:
|
|
|
15
15
|
Pre-commit-checks:
|
|
16
16
|
runs-on: ubuntu-latest
|
|
17
17
|
steps:
|
|
18
|
-
- uses: actions/checkout@
|
|
18
|
+
- uses: actions/checkout@v7
|
|
19
19
|
|
|
20
20
|
- name: Set up Python 3.13
|
|
21
|
-
uses: actions/setup-python@
|
|
21
|
+
uses: actions/setup-python@v7
|
|
22
22
|
with:
|
|
23
23
|
python-version: 3.13
|
|
24
24
|
|
|
@@ -30,6 +30,8 @@ jobs:
|
|
|
30
30
|
Testing:
|
|
31
31
|
needs: pre-commit-checks
|
|
32
32
|
runs-on: ubuntu-latest
|
|
33
|
+
env:
|
|
34
|
+
RUN_CADC_TESTS: ${{ github.repository == 'CHIMEFRB/datatrail-cli' && github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
|
33
35
|
strategy:
|
|
34
36
|
fail-fast: false
|
|
35
37
|
matrix:
|
|
@@ -41,10 +43,10 @@ jobs:
|
|
|
41
43
|
- "3.13"
|
|
42
44
|
- "3.14"
|
|
43
45
|
steps:
|
|
44
|
-
- uses: actions/checkout@
|
|
46
|
+
- uses: actions/checkout@v7
|
|
45
47
|
|
|
46
48
|
- name: Install uv
|
|
47
|
-
uses: astral-sh/setup-uv@
|
|
49
|
+
uses: astral-sh/setup-uv@v10.0.1
|
|
48
50
|
with:
|
|
49
51
|
enable-cache: true
|
|
50
52
|
cache-dependency-glob: "uv.lock"
|
|
@@ -52,30 +54,40 @@ jobs:
|
|
|
52
54
|
python-version: ${{ matrix.python-version }}
|
|
53
55
|
|
|
54
56
|
- name: Installation
|
|
55
|
-
run: uv sync
|
|
57
|
+
run: uv sync --locked
|
|
56
58
|
|
|
57
59
|
- name: Create NETRC file
|
|
60
|
+
if: env.RUN_CADC_TESTS == 'true'
|
|
61
|
+
env:
|
|
62
|
+
CANFAR_NETRC: ${{ secrets.CANFAR_NETRC }}
|
|
58
63
|
run: |
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
64
|
+
umask 077
|
|
65
|
+
test -n "$CANFAR_NETRC"
|
|
66
|
+
printf '%s\n' "$CANFAR_NETRC" > "$RUNNER_TEMP/CANFAR_NETRC"
|
|
62
67
|
|
|
63
68
|
- name: Obtain CADC certificate
|
|
69
|
+
if: env.RUN_CADC_TESTS == 'true'
|
|
64
70
|
run: |
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
umask 077
|
|
72
|
+
mkdir -p "$HOME/.ssl"
|
|
73
|
+
uv run --no-sync cadc-get-cert --netrc-file "$RUNNER_TEMP/CANFAR_NETRC" --days-valid 1 --cert-filename "$HOME/.ssl/cadcproxy.pem"
|
|
74
|
+
test -s "$HOME/.ssl/cadcproxy.pem"
|
|
75
|
+
openssl x509 -in "$HOME/.ssl/cadcproxy.pem" -noout -checkend 0
|
|
68
76
|
|
|
69
|
-
- name: Run
|
|
77
|
+
- name: Run tests
|
|
78
|
+
if: env.RUN_CADC_TESTS == 'true'
|
|
70
79
|
run: |
|
|
71
80
|
uv run --no-sync pytest tests/ --cov . --cov-report=lcov --cov-report=xml
|
|
72
81
|
|
|
82
|
+
- name: Run tests without CADC credentials
|
|
83
|
+
if: env.RUN_CADC_TESTS != 'true'
|
|
84
|
+
run: |
|
|
85
|
+
uv run --no-sync pytest tests/ -m "not cadc" --cov . --cov-report=lcov --cov-report=xml
|
|
86
|
+
|
|
73
87
|
- name: Remove NETRC file and CADC certificate
|
|
88
|
+
if: ${{ always() && env.RUN_CADC_TESTS == 'true' }}
|
|
74
89
|
run: |
|
|
75
|
-
|
|
76
|
-
rm $CANFAR_NETRC_FILE
|
|
77
|
-
echo "Removing file: "$CADC_CERT
|
|
78
|
-
rm $CADC_CERT
|
|
90
|
+
rm -f -- "$RUNNER_TEMP/CANFAR_NETRC" "$HOME/.ssl/cadcproxy.pem"
|
|
79
91
|
|
|
80
92
|
- name: Upload coverage to Coveralls
|
|
81
93
|
uses: coverallsapp/github-action@v2
|
|
@@ -1,5 +1,137 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.13.0](https://github.com/CHIMEFRB/datatrail-cli/compare/datatrail-cli-v0.12.0...datatrail-cli-v0.13.0) (2026-08-25)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **clear:** command to unstage data locally or at arc ([#16](https://github.com/CHIMEFRB/datatrail-cli/issues/16)) ([737c781](https://github.com/CHIMEFRB/datatrail-cli/commit/737c7811a6112a46e842bc135d94d035a9bf301f))
|
|
9
|
+
* **clear:** remove empty parent dirs ([#20](https://github.com/CHIMEFRB/datatrail-cli/issues/20)) ([1559608](https://github.com/CHIMEFRB/datatrail-cli/commit/1559608de9d18d1b16a069c5b6b8136afb388fab))
|
|
10
|
+
* **cli:** add unregistered command ([d9a97a5](https://github.com/CHIMEFRB/datatrail-cli/commit/d9a97a53b6f87321c50aec34339d6b5959b5e713))
|
|
11
|
+
* **cli:** add unregistered command ([b33a6fa](https://github.com/CHIMEFRB/datatrail-cli/commit/b33a6fae57ff2bdad6c26f0ed5402994fdef7650))
|
|
12
|
+
* **cli:** aliases ([73ede83](https://github.com/CHIMEFRB/datatrail-cli/commit/73ede838133b54ef0ba8f45eda453547d601a180))
|
|
13
|
+
* **cli:** check scope exists ([f14589b](https://github.com/CHIMEFRB/datatrail-cli/commit/f14589bc539ec3448348d1d6bc9b1b32d864d7ea))
|
|
14
|
+
* **config:** added datatrail config module ([fe04ee1](https://github.com/CHIMEFRB/datatrail-cli/commit/fe04ee1af77e3d416c103e9ef73a7d79a4b616d5))
|
|
15
|
+
* **gh-actions:** ci and cd ([ebb7a96](https://github.com/CHIMEFRB/datatrail-cli/commit/ebb7a966836d2a4f57287191b9396d9b72cb3cfe))
|
|
16
|
+
* **ls & ps:** add --json flag for machine readable output ([75dac4d](https://github.com/CHIMEFRB/datatrail-cli/commit/75dac4da4fc172adebe2b518cf0b6136e201d94d))
|
|
17
|
+
* **ls & ps:** add --json flag for machine readable output ([c4742a0](https://github.com/CHIMEFRB/datatrail-cli/commit/c4742a0dfe43823ce8e68f21e26e146b90db958c)), closes [#159](https://github.com/CHIMEFRB/datatrail-cli/issues/159)
|
|
18
|
+
* **ls,-pull:** partially implemented ([6689d11](https://github.com/CHIMEFRB/datatrail-cli/commit/6689d119782d1e251935050c508fb14969ff33d2))
|
|
19
|
+
* **ls,pull:** fully implemented ([2105f5a](https://github.com/CHIMEFRB/datatrail-cli/commit/2105f5a86dc42a0618903d0e315bc6490fd633ed))
|
|
20
|
+
* **ls:** option to write ls datasets to disk ([513d665](https://github.com/CHIMEFRB/datatrail-cli/commit/513d665a843bb4aa1f6f92e54ab020ee4f1477ab))
|
|
21
|
+
* **ls:** show datasets in given parent dataset ([15f7da1](https://github.com/CHIMEFRB/datatrail-cli/commit/15f7da1aa76a2a0c75f9229e445f96886b353a1f))
|
|
22
|
+
* **ls:** show larger datasets ([344e230](https://github.com/CHIMEFRB/datatrail-cli/commit/344e230f9798ad8a27752431bfd70f73370488f8))
|
|
23
|
+
* **project:** boilerplate added ([43085a1](https://github.com/CHIMEFRB/datatrail-cli/commit/43085a15789c2045ea41bca9aa89c26c26182019))
|
|
24
|
+
* **ps:** function implemented ([6feedde](https://github.com/CHIMEFRB/datatrail-cli/commit/6feedde08b0dddc3c9b43aba17999e681a2c6b1e))
|
|
25
|
+
* **ps:** if no files check if dataset is in unregistered bucket and notify user ([40ed903](https://github.com/CHIMEFRB/datatrail-cli/commit/40ed903623a4ec9fd4043b4d1863626303830a54)), closes [#46](https://github.com/CHIMEFRB/datatrail-cli/issues/46)
|
|
26
|
+
* **ps:** show num files and size by default, flag to show all files ([cccbd33](https://github.com/CHIMEFRB/datatrail-cli/commit/cccbd3337289699f80112edff612abf746407f4b))
|
|
27
|
+
* **pull:** allows specific files to be pulled by designating names o… ([49f186a](https://github.com/CHIMEFRB/datatrail-cli/commit/49f186a6bcdd88e9aad0a863279b06e29b645158))
|
|
28
|
+
* **pull:** allows specific files to be pulled by designating names or paths in a local config file ([d3cfb59](https://github.com/CHIMEFRB/datatrail-cli/commit/d3cfb59906fe4cb13c8f549e8c2b6499c32e663e))
|
|
29
|
+
* **pull:** check all files were downloaded ([eea76ef](https://github.com/CHIMEFRB/datatrail-cli/commit/eea76efb91b2a35f2900be59d4484d02721322da))
|
|
30
|
+
* **pull:** check all files were downloaded ([bb1d8b6](https://github.com/CHIMEFRB/datatrail-cli/commit/bb1d8b64378fe80a27944f8eaccf6ce674ce17d0))
|
|
31
|
+
* **pull:** display size of files to be pulled before prompt ([38cffcc](https://github.com/CHIMEFRB/datatrail-cli/commit/38cffccb18dcaca41150ee7af85b4c80f6137284))
|
|
32
|
+
* **pull:** implemented multiprocessor pull ([2e7b332](https://github.com/CHIMEFRB/datatrail-cli/commit/2e7b33205789c54e4f9544223a0555d74edd464d))
|
|
33
|
+
* **scout:** able to heal missing minoc replicas ([bc3b52d](https://github.com/CHIMEFRB/datatrail-cli/commit/bc3b52d44fe7da7335279c96cec03e3deace6f9a))
|
|
34
|
+
* **scout:** add scout command to the cli ([#83](https://github.com/CHIMEFRB/datatrail-cli/issues/83)) ([5cb811f](https://github.com/CHIMEFRB/datatrail-cli/commit/5cb811f416c6fe099cf2405835ad867df125a62d))
|
|
35
|
+
* **scout:** generalised scout functionality to check for discrepanci… ([aabcad1](https://github.com/CHIMEFRB/datatrail-cli/commit/aabcad1937fef1734ef17593726d27bb673a29ad))
|
|
36
|
+
* **scout:** generalised scout functionality to check for discrepancies between all sites, not just minoc ([f3f1005](https://github.com/CHIMEFRB/datatrail-cli/commit/f3f1005722c48d4ac020b65ed13d19f6bc0bbd48))
|
|
37
|
+
* **structure:** added skeleton code ([c3e57f6](https://github.com/CHIMEFRB/datatrail-cli/commit/c3e57f63ea0e54c45f12a4c3682ed01e5d9489ec))
|
|
38
|
+
* **unregistered:** command to search for event in unregistered results bucket ([1bb4ca0](https://github.com/CHIMEFRB/datatrail-cli/commit/1bb4ca0c118e042a907f38205af5d7ed6bf9f16d))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Bug Fixes
|
|
42
|
+
|
|
43
|
+
* bound every REST call with a request timeout ([431270d](https://github.com/CHIMEFRB/datatrail-cli/commit/431270d2fb4e59acc8a875b578964d20d2aeebb4))
|
|
44
|
+
* **cadcclient:** check canfar status ([484562c](https://github.com/CHIMEFRB/datatrail-cli/commit/484562c3c8345dd032c00923d3250c1be4a12191))
|
|
45
|
+
* **cadcclient:** improve handling of stdout ([8b35e4f](https://github.com/CHIMEFRB/datatrail-cli/commit/8b35e4f5ccdaf874c706f31a608a89b0612b669d))
|
|
46
|
+
* **cadcclient:** improve handling of stdout ([320d4df](https://github.com/CHIMEFRB/datatrail-cli/commit/320d4dfcdd194aa69f9236c84f21dbfb8690068b))
|
|
47
|
+
* **cadcclient:** more robust switching of stdout ([9c90315](https://github.com/CHIMEFRB/datatrail-cli/commit/9c9031595a9e13d6471e4b5e5edc548a4d1545ad))
|
|
48
|
+
* **ci:** accept request timeout in scopes mock ([1ff9624](https://github.com/CHIMEFRB/datatrail-cli/commit/1ff9624c15045d1acdb30ad471bf6c6a9c298174))
|
|
49
|
+
* **ci:** keep fork main credential-free ([9030bfb](https://github.com/CHIMEFRB/datatrail-cli/commit/9030bfb6d971afdb557772d35b1691f531e5e0b4))
|
|
50
|
+
* **ci:** keep fork main credential-free ([73a4b02](https://github.com/CHIMEFRB/datatrail-cli/commit/73a4b029178db001025ec5442ce9b9a43911615c))
|
|
51
|
+
* **clear:** reorganise file_paths manipulation logic ([fd14f9b](https://github.com/CHIMEFRB/datatrail-cli/commit/fd14f9b714590f1cb57684565cfa23fd7bc8fc52))
|
|
52
|
+
* **clear:** reorganise file_paths manipulation logic ([80f0f2d](https://github.com/CHIMEFRB/datatrail-cli/commit/80f0f2d2bf3d9836eef16f9f6d3bed5f88c8ff05))
|
|
53
|
+
* **cli-test:** new test - marked as fix to trigger release ([aea98d0](https://github.com/CHIMEFRB/datatrail-cli/commit/aea98d07f63ee17f6d5b4acd396ea32e3aefbd11))
|
|
54
|
+
* **cli:** canfar status checks ([7f9df34](https://github.com/CHIMEFRB/datatrail-cli/commit/7f9df349ceeebb1caa7c1c2582cd3d1c54e8ec09))
|
|
55
|
+
* **cli:** catch http 503 errors when validating scope ([b6e75af](https://github.com/CHIMEFRB/datatrail-cli/commit/b6e75affe6db6508882ed5e3da1b22bdec194156))
|
|
56
|
+
* **cli:** check for luskan status ([b229549](https://github.com/CHIMEFRB/datatrail-cli/commit/b2295493c60f0f2a00a95c1c87eb64a0e926b886))
|
|
57
|
+
* **cli:** check for luskan status ([405a3c2](https://github.com/CHIMEFRB/datatrail-cli/commit/405a3c21334b5d8d96ab42436355d8c329880d74))
|
|
58
|
+
* **cli:** check minoc status ([a955ab1](https://github.com/CHIMEFRB/datatrail-cli/commit/a955ab129377dbd62215688598cc2cc434345152))
|
|
59
|
+
* **cli:** check minoc status ([6a0d6df](https://github.com/CHIMEFRB/datatrail-cli/commit/6a0d6dfc4f3490dc407c08d106d7740bb5d892e3))
|
|
60
|
+
* **cli:** print the update-available banner to stderr ([53b9fe4](https://github.com/CHIMEFRB/datatrail-cli/commit/53b9fe4560ff7835a6d7f4e4402538b64f4334aa))
|
|
61
|
+
* **cli:** print the update-available banner to stderr ([8dd6313](https://github.com/CHIMEFRB/datatrail-cli/commit/8dd63139b127cf7219932f9d271482a614dc1261))
|
|
62
|
+
* **cli:** removed pkg resources deprecation warning ([b488b02](https://github.com/CHIMEFRB/datatrail-cli/commit/b488b024c0f6904bc7f6d66ffff8281791cf59c1))
|
|
63
|
+
* **cli:** removed pkg resources deprecation warning ([2ab793d](https://github.com/CHIMEFRB/datatrail-cli/commit/2ab793d753badfd9a2c6aa53ed95010366437c3f))
|
|
64
|
+
* **cli:** updated some docs ([4a61228](https://github.com/CHIMEFRB/datatrail-cli/commit/4a61228300d5082e76081d84520fddf743cc0ebf))
|
|
65
|
+
* **cli:** wrap version check in try except ([2fc9d31](https://github.com/CHIMEFRB/datatrail-cli/commit/2fc9d3169cc28e675c4cfce51aa142b1f22466c4))
|
|
66
|
+
* **config.py:** typo ([#12](https://github.com/CHIMEFRB/datatrail-cli/issues/12)) ([279998b](https://github.com/CHIMEFRB/datatrail-cli/commit/279998bbc5a4c5bd9922db59b159a38fbfdade8b))
|
|
67
|
+
* connection errors raise correct status exit code ([9b4d7bc](https://github.com/CHIMEFRB/datatrail-cli/commit/9b4d7bcc74c6a7c6954d965f8ab421ea6181b016))
|
|
68
|
+
* **functions.py:** added specific handling for canfar site, where the… ([#66](https://github.com/CHIMEFRB/datatrail-cli/issues/66)) ([895a3ca](https://github.com/CHIMEFRB/datatrail-cli/commit/895a3ca7bdb7000847313ef12fe17e50ad7308c8))
|
|
69
|
+
* **functions.py:** changed error catching checks to be for dictionaries with error keys in them as opposed to strings ([#74](https://github.com/CHIMEFRB/datatrail-cli/issues/74)) ([6fdb244](https://github.com/CHIMEFRB/datatrail-cli/commit/6fdb244e46a62253f4654681ec5e5d76431f49f0))
|
|
70
|
+
* **functions.py:** patches deletion logic to check that the path to be deleted is greater than 3 levels deep ([#64](https://github.com/CHIMEFRB/datatrail-cli/issues/64)) ([ad43f35](https://github.com/CHIMEFRB/datatrail-cli/commit/ad43f35ce7b8fbc87210ca93df4433b3c4bbe06d))
|
|
71
|
+
* **functions:** bug ([f4e3788](https://github.com/CHIMEFRB/datatrail-cli/commit/f4e3788944e5a95f868e139369abdfac35c61caa))
|
|
72
|
+
* **functions:** changed return of find_missing_datasets to always ret… ([#76](https://github.com/CHIMEFRB/datatrail-cli/issues/76)) ([a8c0f3d](https://github.com/CHIMEFRB/datatrail-cli/commit/a8c0f3ded414c4e8d4fbca9529bfda7610531841))
|
|
73
|
+
* **init:** set valid choices for datatrail config init ([63f96c3](https://github.com/CHIMEFRB/datatrail-cli/commit/63f96c30c07be1d787381e5457021e805ea0cc6f))
|
|
74
|
+
* **ls:** other section for scopes that don't match list of sites ([0b50d79](https://github.com/CHIMEFRB/datatrail-cli/commit/0b50d790fbfb21fa0edb16eb945722189333a1c2))
|
|
75
|
+
* **ls:** report an unanswered scopes query as an error instead of leaking response text ([6eedaa3](https://github.com/CHIMEFRB/datatrail-cli/commit/6eedaa3720e1f86518fb3ba0292983020affa5af))
|
|
76
|
+
* **ls:** report an unanswered scopes query as an error instead of leaking response text ([8fb77d6](https://github.com/CHIMEFRB/datatrail-cli/commit/8fb77d6d1fbb2d724fbec73f84f4768a4d515181))
|
|
77
|
+
* **ls:** seperate scopes by site ([5bddcc7](https://github.com/CHIMEFRB/datatrail-cli/commit/5bddcc7b368fa0594128f0f7fcb0b2e26959d77e))
|
|
78
|
+
* **ls:** show all larger datasets for scope ([cda63ac](https://github.com/CHIMEFRB/datatrail-cli/commit/cda63ac3053912aa0f4f0bc4781773e3ce46ac0a)), closes [#1](https://github.com/CHIMEFRB/datatrail-cli/issues/1)
|
|
79
|
+
* **ps-and-pull:** check if namespace already prepended ([#9](https://github.com/CHIMEFRB/datatrail-cli/issues/9)) ([eba7532](https://github.com/CHIMEFRB/datatrail-cli/commit/eba7532f3a2c23854a62842f3ce54246916e0d6b))
|
|
80
|
+
* **ps-and-pull:** determination of common path ([a35bbad](https://github.com/CHIMEFRB/datatrail-cli/commit/a35bbad705b9702812281539516e2c7081a9516e)), closes [#19](https://github.com/CHIMEFRB/datatrail-cli/issues/19)
|
|
81
|
+
* **ps.py:** added error handling for returned strings ([#79](https://github.com/CHIMEFRB/datatrail-cli/issues/79)) ([0b3c5b6](https://github.com/CHIMEFRB/datatrail-cli/commit/0b3c5b6f95da361c080534f0e34132172300b956))
|
|
82
|
+
* **ps:** belongs_to cannot be none must be empty string ([#69](https://github.com/CHIMEFRB/datatrail-cli/issues/69)) ([b348dbd](https://github.com/CHIMEFRB/datatrail-cli/commit/b348dbdaa94e106f9c55be006b572566155d2be6))
|
|
83
|
+
* **ps:** bug where common path was not the parent dir of file ([3ba1969](https://github.com/CHIMEFRB/datatrail-cli/commit/3ba1969fec4aa5a57e5913a74d5d6aa10a7d86d7))
|
|
84
|
+
* **ps:** common path bug ([266cc3a](https://github.com/CHIMEFRB/datatrail-cli/commit/266cc3af3d3c397e83c9e18bad39ea5178b191f8))
|
|
85
|
+
* **ps:** controlled error if dataset doesnt exist in datatrail ([09a9d13](https://github.com/CHIMEFRB/datatrail-cli/commit/09a9d13a879971b65902ea19c3b2cda8ce7289de))
|
|
86
|
+
* **ps:** if parent dataset show only policies ([99b4bdd](https://github.com/CHIMEFRB/datatrail-cli/commit/99b4bddfbb788f6617dce408342232e0aa411156))
|
|
87
|
+
* **ps:** invalid scopes, valid scopes are now shown after error message ([5347137](https://github.com/CHIMEFRB/datatrail-cli/commit/534713782fe5105055506d55f1f43c51c110a4b4))
|
|
88
|
+
* **ps:** shows multiple larger datasets in belongs to ([6b32903](https://github.com/CHIMEFRB/datatrail-cli/commit/6b32903007a77f4d8539659870dacbcd94e67f18))
|
|
89
|
+
* **pull:** catch errors when no files at minoc ([fd34637](https://github.com/CHIMEFRB/datatrail-cli/commit/fd346373a3cdab93d0532a82cef5a8a04940aea7))
|
|
90
|
+
* **pull:** default directory ([da6a41d](https://github.com/CHIMEFRB/datatrail-cli/commit/da6a41d9c1dce3613996f735fef65ed62bbcc302))
|
|
91
|
+
* **pull:** FileNotFoundError stopping download ([#15](https://github.com/CHIMEFRB/datatrail-cli/issues/15)) ([cdee724](https://github.com/CHIMEFRB/datatrail-cli/commit/cdee7248d28a94c8bd4cabe3df9c93a337342dd3))
|
|
92
|
+
* **pull:** more processors than files bug ([0536326](https://github.com/CHIMEFRB/datatrail-cli/commit/053632632fd55cb5bba4fe7ce1d398148e0c9cba))
|
|
93
|
+
* **pull:** more processors than files bug ([e44bbe1](https://github.com/CHIMEFRB/datatrail-cli/commit/e44bbe1a14900f034f998b664c1d394fcf31c7a7)), closes [#147](https://github.com/CHIMEFRB/datatrail-cli/issues/147)
|
|
94
|
+
* **pull:** set group permissions if site is canfar ([70236ae](https://github.com/CHIMEFRB/datatrail-cli/commit/70236ae21c0e324d153be89dcead87489b77e5e5))
|
|
95
|
+
* **pull:** wrap download in tenacity retry ([ebdf5b1](https://github.com/CHIMEFRB/datatrail-cli/commit/ebdf5b10489b6a33937576850d57d05b1c1eefcb))
|
|
96
|
+
* **pull:** wrap download in tenacity retry ([8253157](https://github.com/CHIMEFRB/datatrail-cli/commit/8253157e78e1f0abb71fe71fb396b72d1ba51911))
|
|
97
|
+
* **scout:** change order of the args ([d5c33b8](https://github.com/CHIMEFRB/datatrail-cli/commit/d5c33b8ab8a5204fb63f1eb9744d1aa6d5c1f5d1))
|
|
98
|
+
* **scout:** change the order of the arguments ([c7ab294](https://github.com/CHIMEFRB/datatrail-cli/commit/c7ab29459707be153d12f1ff562cf46b984ed519))
|
|
99
|
+
* **scout:** improve error handling ([#87](https://github.com/CHIMEFRB/datatrail-cli/issues/87)) ([1937e9b](https://github.com/CHIMEFRB/datatrail-cli/commit/1937e9bbedfda0ab11919428b0b1b027900f594d))
|
|
100
|
+
* **test:** changed docstring expected in help test ([fed9342](https://github.com/CHIMEFRB/datatrail-cli/commit/fed9342df20b6843171a8cb4b288899ada74e261))
|
|
101
|
+
* **timeout:** bound every REST call with a request timeout ([fb533a2](https://github.com/CHIMEFRB/datatrail-cli/commit/fb533a2487c744fd18da4857b9ab74bea4615459))
|
|
102
|
+
* **unregistered:** improve pattern matching ([22ff11a](https://github.com/CHIMEFRB/datatrail-cli/commit/22ff11aa6d8aa390e465bf0ef62065f288f05bac))
|
|
103
|
+
* **unregistered:** improve way info displayed ([21e19a7](https://github.com/CHIMEFRB/datatrail-cli/commit/21e19a7ea239667ac882b1d8fbff57a145989227))
|
|
104
|
+
* **unregistered:** improve way info displayed ([c5f0fca](https://github.com/CHIMEFRB/datatrail-cli/commit/c5f0fca6f6f53e5004e1f1868517100572d68d1a))
|
|
105
|
+
* Update cadcdata to version 2.5 ([#58](https://github.com/CHIMEFRB/datatrail-cli/issues/58)) ([8ed6ad3](https://github.com/CHIMEFRB/datatrail-cli/commit/8ed6ad3914850483d147f0605809c1dd76363403))
|
|
106
|
+
* **version:** color ([ac2c7be](https://github.com/CHIMEFRB/datatrail-cli/commit/ac2c7bea886f48cc5fa5b84443999fb6e3809461))
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
### Documentation
|
|
110
|
+
|
|
111
|
+
* add unregistered command ([d8dd35b](https://github.com/CHIMEFRB/datatrail-cli/commit/d8dd35b22069b69ff7e3e76b6dc935696f8c2840))
|
|
112
|
+
* **all-docs:** revamp and additional content ([697fa6f](https://github.com/CHIMEFRB/datatrail-cli/commit/697fa6f2d2e150414c034c9d45a461808cd87381))
|
|
113
|
+
* **cli:** started docs ([f1838d5](https://github.com/CHIMEFRB/datatrail-cli/commit/f1838d5864cfed16e5221e9b5affaebb39ec108d))
|
|
114
|
+
* **gh-action:** build docs ([0698516](https://github.com/CHIMEFRB/datatrail-cli/commit/0698516e1670fb7a019ac271707d1d40fa4c5904))
|
|
115
|
+
* **gh-action:** install without dev ([0ea4a92](https://github.com/CHIMEFRB/datatrail-cli/commit/0ea4a92395c4eb04e6e6913679c3fd9b1b0cbd56))
|
|
116
|
+
* **gh-actions:** fix python version ([6db8c76](https://github.com/CHIMEFRB/datatrail-cli/commit/6db8c76298da316b7614d9ce794154ce75b83939))
|
|
117
|
+
* **index.md:** allow comments ([c680000](https://github.com/CHIMEFRB/datatrail-cli/commit/c6800007925c5794a5f7c29a63934c904cdaea07))
|
|
118
|
+
* **index:** add clear command ([01fcfb5](https://github.com/CHIMEFRB/datatrail-cli/commit/01fcfb5df89a8c567f743c26cc2342ccad93c632))
|
|
119
|
+
* **index:** badge ([09c637e](https://github.com/CHIMEFRB/datatrail-cli/commit/09c637eea007d0176a0ca0abe7524ca9f5c8a667))
|
|
120
|
+
* **index:** rewording ([6e7b2d1](https://github.com/CHIMEFRB/datatrail-cli/commit/6e7b2d1985233595374dc6d311b7b34389f92344))
|
|
121
|
+
* **index:** small fixes ([6483813](https://github.com/CHIMEFRB/datatrail-cli/commit/6483813033d71281a973dc52d250ae4e37a2df9e))
|
|
122
|
+
* **index:** update commands available ([aec676d](https://github.com/CHIMEFRB/datatrail-cli/commit/aec676d576082e288ee7144c39e34eb289dc8946))
|
|
123
|
+
* **index:** update install instructions ([fd7f51c](https://github.com/CHIMEFRB/datatrail-cli/commit/fd7f51c64d8f4b97f23d2b2b5897b34809a1bee3))
|
|
124
|
+
* **list:** test terminal plug in ([2cb4bc0](https://github.com/CHIMEFRB/datatrail-cli/commit/2cb4bc00ae89bdd1a7321ca2bd887da556225641))
|
|
125
|
+
* **README-and-index:** updated ([97353b3](https://github.com/CHIMEFRB/datatrail-cli/commit/97353b3c7f94a199363853b1622b930064ea085f))
|
|
126
|
+
* **scout:** added for new cli command ([be4f2bf](https://github.com/CHIMEFRB/datatrail-cli/commit/be4f2bfda25000b453b9696b2137e6bf0e8e4dd6))
|
|
127
|
+
* **scout:** reflect changes to cli in docs ([797eeac](https://github.com/CHIMEFRB/datatrail-cli/commit/797eeac4874619298c22f8f8a7623e079ac6542d))
|
|
128
|
+
* **scout:** typos ([7f633b1](https://github.com/CHIMEFRB/datatrail-cli/commit/7f633b17d514303d260990e1ece849d1c489ef91))
|
|
129
|
+
* **style:** use termynal ([e908d47](https://github.com/CHIMEFRB/datatrail-cli/commit/e908d4786e63972bef9f712b6c740088c8ac7906))
|
|
130
|
+
* update mkdocs config + ci/cd ([3a1014e](https://github.com/CHIMEFRB/datatrail-cli/commit/3a1014e75b0639f991cb49baf826bd925455b2f4))
|
|
131
|
+
* update mkdocs config + ci/cd ([0e4bee0](https://github.com/CHIMEFRB/datatrail-cli/commit/0e4bee0efbf9cd28fe4964497b5b0b7492efc3c2))
|
|
132
|
+
* **user-guide:** command highlights ([6813964](https://github.com/CHIMEFRB/datatrail-cli/commit/6813964e361391a8cbd4558b7c9bcda32c42cd7c))
|
|
133
|
+
* **user-guide:** completed ([a25ac76](https://github.com/CHIMEFRB/datatrail-cli/commit/a25ac767f8fee8bb22d100358481090c186f8e1f))
|
|
134
|
+
|
|
3
135
|
## [0.12.0](https://github.com/CHIMEFRB/datatrail-cli/compare/v0.11.1...v0.12.0) (2026-08-24)
|
|
4
136
|
|
|
5
137
|
|
|
@@ -11,6 +11,7 @@ from dtcli.utilities import utilities
|
|
|
11
11
|
|
|
12
12
|
pretty.install()
|
|
13
13
|
terminal = console.Console()
|
|
14
|
+
terminal_stderr = console.Console(stderr=True)
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
# Main CLI
|
|
@@ -50,15 +51,19 @@ cli.add_command(unregistered.unregistered)
|
|
|
50
51
|
|
|
51
52
|
|
|
52
53
|
def check_version() -> None:
|
|
53
|
-
"""Check if CLI is latest release.
|
|
54
|
+
"""Check if CLI is latest release.
|
|
55
|
+
|
|
56
|
+
The banner goes to stderr so that stdout stays parseable, e.g. for
|
|
57
|
+
`--json` output piped into another tool.
|
|
58
|
+
"""
|
|
54
59
|
if not utilities.cli_is_latest_release():
|
|
55
60
|
current_version = package_version("datatrail-cli")
|
|
56
61
|
latest_version = utilities.get_latest_released_version()
|
|
57
|
-
|
|
62
|
+
terminal_stderr.print(
|
|
58
63
|
f"A new release of datatrail-cli is available: {current_version} → {latest_version}", # noqa: E501
|
|
59
64
|
style="bold yellow",
|
|
60
65
|
)
|
|
61
|
-
|
|
66
|
+
terminal_stderr.print()
|
|
62
67
|
|
|
63
68
|
|
|
64
69
|
if __name__ == "__main__":
|
|
@@ -13,7 +13,12 @@ from rich.table import Table
|
|
|
13
13
|
from dtcli.config import procure
|
|
14
14
|
from dtcli.ls import list as ls
|
|
15
15
|
from dtcli.utilities import cadcclient
|
|
16
|
-
from dtcli.utilities.utilities import
|
|
16
|
+
from dtcli.utilities.utilities import (
|
|
17
|
+
REQUEST_TIMEOUT,
|
|
18
|
+
check_canfar_status,
|
|
19
|
+
set_log_level,
|
|
20
|
+
validate_scope,
|
|
21
|
+
)
|
|
17
22
|
|
|
18
23
|
logger = logging.getLogger("scout")
|
|
19
24
|
|
|
@@ -89,7 +94,11 @@ def scout( # noqa: C901
|
|
|
89
94
|
)
|
|
90
95
|
url = server + endpoint
|
|
91
96
|
logger.debug(f"URL: {url}")
|
|
92
|
-
|
|
97
|
+
try:
|
|
98
|
+
response = requests.get(url, timeout=REQUEST_TIMEOUT)
|
|
99
|
+
except requests.exceptions.Timeout:
|
|
100
|
+
error_console.print("Error: Datatrail server timed out.")
|
|
101
|
+
return None
|
|
93
102
|
try:
|
|
94
103
|
data = response.json()
|
|
95
104
|
logger.debug(f"Data: {data}")
|
|
@@ -160,14 +169,22 @@ def scout( # noqa: C901
|
|
|
160
169
|
+ "/query/datasset/scout/md5sums"
|
|
161
170
|
+ f"?basepath={basepath}&site={se}&filetype={file_type}"
|
|
162
171
|
)
|
|
163
|
-
|
|
172
|
+
try:
|
|
173
|
+
response = requests.get(md5_url, timeout=REQUEST_TIMEOUT)
|
|
174
|
+
except requests.exceptions.Timeout:
|
|
175
|
+
error_console.print(f"{scope} - Healing timed out; skipping.")
|
|
176
|
+
continue
|
|
164
177
|
file_md5s = response.json()
|
|
165
178
|
url = (
|
|
166
179
|
server
|
|
167
180
|
+ "/commit/dataset/scout/sync"
|
|
168
181
|
+ f"?name={dataset}&scope={scope}&replicate_to={se}"
|
|
169
182
|
)
|
|
170
|
-
|
|
183
|
+
try:
|
|
184
|
+
response = requests.post(url, json=file_md5s, timeout=REQUEST_TIMEOUT)
|
|
185
|
+
except requests.exceptions.Timeout:
|
|
186
|
+
error_console.print(f"{scope} - Healing timed out; skipping.")
|
|
187
|
+
continue
|
|
171
188
|
if response.status_code == 200:
|
|
172
189
|
console.print(f"{scope} - Healing successful.")
|
|
173
190
|
else:
|
|
@@ -7,6 +7,7 @@ import shutil
|
|
|
7
7
|
import subprocess
|
|
8
8
|
import time
|
|
9
9
|
from collections import Counter
|
|
10
|
+
from collections.abc import Sequence
|
|
10
11
|
from pathlib import Path
|
|
11
12
|
from typing import Any, Dict, List, Optional, Tuple
|
|
12
13
|
|
|
@@ -54,10 +55,21 @@ def list( # noqa: C901
|
|
|
54
55
|
logger.info("Finding all scopes in Datatrail.")
|
|
55
56
|
try:
|
|
56
57
|
url = server + "/query/dataset/scopes"
|
|
57
|
-
r = requests.get(url)
|
|
58
|
+
r = requests.get(url, timeout=utilities.REQUEST_TIMEOUT)
|
|
58
59
|
response = utilities.decode_response(r)
|
|
60
|
+
if isinstance(response, str) or not isinstance(response, Sequence):
|
|
61
|
+
# decode_response passes a non-JSON body (a proxy error page,
|
|
62
|
+
# a 5xx message) through as text; report it, or any other
|
|
63
|
+
# non-list shape, as an error instead of presenting it as
|
|
64
|
+
# the scopes list. NB: the builtin list is shadowed by this
|
|
65
|
+
# module's list(), hence the Sequence check.
|
|
66
|
+
logger.error(f"Scopes query not answered: {response}")
|
|
67
|
+
return {"error": "Datatrail did not answer the scopes query."}
|
|
59
68
|
return {"scopes": response}
|
|
60
|
-
except
|
|
69
|
+
except (
|
|
70
|
+
requests.exceptions.ConnectionError,
|
|
71
|
+
requests.exceptions.Timeout,
|
|
72
|
+
) as e:
|
|
61
73
|
logger.error(e)
|
|
62
74
|
return {"error": "Datatrail Server at CHIME is not responding."}
|
|
63
75
|
|
|
@@ -69,13 +81,16 @@ def list( # noqa: C901
|
|
|
69
81
|
logger.info("Finding all larger datasets in Datatrail.")
|
|
70
82
|
try:
|
|
71
83
|
url = server + f"/query/dataset/larger?scope={scope}"
|
|
72
|
-
r = requests.get(url)
|
|
84
|
+
r = requests.get(url, timeout=utilities.REQUEST_TIMEOUT)
|
|
73
85
|
response = utilities.decode_response(r)
|
|
74
86
|
if isinstance(response, dict):
|
|
75
87
|
return response
|
|
76
88
|
else:
|
|
77
89
|
raise requests.exceptions.ConnectionError(response)
|
|
78
|
-
except
|
|
90
|
+
except (
|
|
91
|
+
requests.exceptions.ConnectionError,
|
|
92
|
+
requests.exceptions.Timeout,
|
|
93
|
+
) as error:
|
|
79
94
|
logger.error(error)
|
|
80
95
|
return {"error": f"{error}"}
|
|
81
96
|
|
|
@@ -85,7 +100,7 @@ def list( # noqa: C901
|
|
|
85
100
|
try:
|
|
86
101
|
url = server + f"/query/dataset/children/{scope}/{dataset}"
|
|
87
102
|
logger.debug(f"URL: {url}")
|
|
88
|
-
r = requests.get(url)
|
|
103
|
+
r = requests.get(url, timeout=utilities.REQUEST_TIMEOUT)
|
|
89
104
|
logger.debug(f"Status: {r.status_code}.")
|
|
90
105
|
response = utilities.decode_response(r)
|
|
91
106
|
logger.debug(f"Reponse: {response}")
|
|
@@ -143,7 +158,7 @@ def ps(
|
|
|
143
158
|
logger.info(f"Getting policy for {dataset} in {scope}.")
|
|
144
159
|
url: str = str(base_url) + f"/query/dataset/{scope}/{dataset}"
|
|
145
160
|
logger.debug(f"URL: {url}")
|
|
146
|
-
r = requests.get(url)
|
|
161
|
+
r = requests.get(url, timeout=utilities.REQUEST_TIMEOUT)
|
|
147
162
|
logger.debug(f"Status: {r.status_code}.")
|
|
148
163
|
policy_response = utilities.decode_response(r)
|
|
149
164
|
utilities.validate_request_response(policy_response, dataset, scope)
|
|
@@ -192,7 +207,7 @@ def get_dataset_file_info(
|
|
|
192
207
|
logger.debug(f"Payload: {payload}")
|
|
193
208
|
url = str(base_url) + "/query/dataset/find"
|
|
194
209
|
logger.debug(f"URL: {url}")
|
|
195
|
-
r = requests.post(url, json=payload)
|
|
210
|
+
r = requests.post(url, json=payload, timeout=utilities.REQUEST_TIMEOUT)
|
|
196
211
|
logger.debug(f"Status: {r.status_code}.")
|
|
197
212
|
logger.debug("Decoding response.")
|
|
198
213
|
response = utilities.decode_response(r)
|
|
@@ -403,7 +418,7 @@ def find_dataset_common_path(
|
|
|
403
418
|
url = server + "/query/dataset/find"
|
|
404
419
|
logger.debug(f"URL: {url}")
|
|
405
420
|
try:
|
|
406
|
-
r = requests.post(url, json=payload)
|
|
421
|
+
r = requests.post(url, json=payload, timeout=utilities.REQUEST_TIMEOUT)
|
|
407
422
|
dataset_locations = utilities.decode_response(r) # type: ignore
|
|
408
423
|
utilities.validate_request_response(dataset_locations, dataset, scope)
|
|
409
424
|
except ConnectionError:
|
|
@@ -455,6 +470,7 @@ def view_results(
|
|
|
455
470
|
"projection": projection,
|
|
456
471
|
"limit": limit,
|
|
457
472
|
},
|
|
473
|
+
timeout=utilities.REQUEST_TIMEOUT,
|
|
458
474
|
)
|
|
459
475
|
return response.json()
|
|
460
476
|
|
|
@@ -416,15 +416,19 @@ def status(
|
|
|
416
416
|
certfile = procure(key="vospace_certfile")
|
|
417
417
|
|
|
418
418
|
def check_url(url: str) -> bool:
|
|
419
|
-
response = requests.get(url, cert=certfile, allow_redirects=True)
|
|
420
419
|
try:
|
|
420
|
+
# Health probe: fail fast, and read a wedged or unreachable
|
|
421
|
+
# endpoint as "down" rather than crashing the caller.
|
|
422
|
+
response = requests.get(
|
|
423
|
+
url, cert=certfile, allow_redirects=True, timeout=(10, 30)
|
|
424
|
+
)
|
|
421
425
|
response.raise_for_status()
|
|
422
426
|
authorised = response.headers.get("x-vo-authenticated")
|
|
423
427
|
if isinstance(authorised, str):
|
|
424
428
|
return True
|
|
425
429
|
else:
|
|
426
430
|
raise TypeError
|
|
427
|
-
except HTTPError as error:
|
|
431
|
+
except (HTTPError, requests.exceptions.RequestException) as error:
|
|
428
432
|
logger.warning(error)
|
|
429
433
|
logger.warning(f"{url.split('/')[3]} is down.")
|
|
430
434
|
return False
|
|
@@ -13,6 +13,11 @@ try:
|
|
|
13
13
|
except ImportError:
|
|
14
14
|
from pip._vendor.packaging.version import parse
|
|
15
15
|
|
|
16
|
+
# Bound every REST call: a wedged connection should fail, not hang forever.
|
|
17
|
+
# (connect, read): fail an unreachable host quickly; keep the read bound
|
|
18
|
+
# generous, because some server-side queries are legitimately slow.
|
|
19
|
+
REQUEST_TIMEOUT: Tuple[float, float] = (10.0, 300.0)
|
|
20
|
+
|
|
16
21
|
|
|
17
22
|
def set_log_level(logger: logging.Logger, verbose: int = 0, quiet: bool = False) -> None:
|
|
18
23
|
"""Set log level."""
|
|
@@ -98,7 +103,10 @@ def validate_scope(scope: str) -> bool:
|
|
|
98
103
|
Returns:
|
|
99
104
|
bool: True if scope is valid.
|
|
100
105
|
"""
|
|
101
|
-
resp = requests.get(
|
|
106
|
+
resp = requests.get(
|
|
107
|
+
"https://frb.chimenet.ca/datatrail/query/dataset/scopes",
|
|
108
|
+
timeout=REQUEST_TIMEOUT,
|
|
109
|
+
)
|
|
102
110
|
scopes = decode_response(resp)
|
|
103
111
|
return scope in scopes
|
|
104
112
|
|
|
@@ -116,7 +124,8 @@ def get_latest_released_version(
|
|
|
116
124
|
Returns:
|
|
117
125
|
str: Latest released version.
|
|
118
126
|
"""
|
|
119
|
-
|
|
127
|
+
# Short timeout: this runs at CLI startup and must not delay it.
|
|
128
|
+
req = requests.get(url_pattern.format(package=package), timeout=5)
|
|
120
129
|
version = parse("0")
|
|
121
130
|
if req.status_code == requests.codes.ok:
|
|
122
131
|
j = json.loads(req.text.encode(req.encoding)) # type: ignore
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "datatrail-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.13.0"
|
|
4
4
|
description = "CHIME/FRB Datatrail CLI"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "CHIME FRB Project Office" },
|
|
@@ -57,6 +57,11 @@ ignore = "E203"
|
|
|
57
57
|
[tool.isort]
|
|
58
58
|
profile = "black"
|
|
59
59
|
|
|
60
|
+
[tool.pytest.ini_options]
|
|
61
|
+
markers = [
|
|
62
|
+
"cadc: tests that require CADC credentials",
|
|
63
|
+
]
|
|
64
|
+
|
|
60
65
|
[build-system]
|
|
61
66
|
requires = ["hatchling"]
|
|
62
67
|
build-backend = "hatchling.build"
|
|
@@ -366,6 +366,7 @@ def test_cli_list_children(runner: CliRunner) -> None:
|
|
|
366
366
|
assert "289007650" in result.output
|
|
367
367
|
|
|
368
368
|
|
|
369
|
+
@pytest.mark.cadc
|
|
369
370
|
def test_cli_ps(runner: CliRunner) -> None:
|
|
370
371
|
"""Test for CLI ps command.
|
|
371
372
|
|
|
@@ -376,6 +377,7 @@ def test_cli_ps(runner: CliRunner) -> None:
|
|
|
376
377
|
assert result.exit_code == 0
|
|
377
378
|
|
|
378
379
|
|
|
380
|
+
@pytest.mark.cadc
|
|
379
381
|
def test_cli_pull_no(runner: CliRunner) -> None:
|
|
380
382
|
"""Test for CLI pull command.
|
|
381
383
|
|
|
@@ -397,6 +399,7 @@ def test_cli_pull_no(runner: CliRunner) -> None:
|
|
|
397
399
|
assert expect in result.output
|
|
398
400
|
|
|
399
401
|
|
|
402
|
+
@pytest.mark.cadc
|
|
400
403
|
def test_cli_pull_yes(
|
|
401
404
|
runner: CliRunner, directory: Path, list_specific_files: Path
|
|
402
405
|
) -> None:
|
|
@@ -427,6 +430,7 @@ def test_cli_pull_yes(
|
|
|
427
430
|
).exists()
|
|
428
431
|
|
|
429
432
|
|
|
433
|
+
@pytest.mark.cadc
|
|
430
434
|
def test_cli_clear_no(runner: CliRunner, directory: Path) -> None:
|
|
431
435
|
"""Test for CLI clear command.
|
|
432
436
|
|
|
@@ -450,6 +454,7 @@ def test_cli_clear_no(runner: CliRunner, directory: Path) -> None:
|
|
|
450
454
|
assert "Roger roger, no files deleted" in result.output
|
|
451
455
|
|
|
452
456
|
|
|
457
|
+
@pytest.mark.cadc
|
|
453
458
|
def test_cli_clear_yes(runner: CliRunner, directory: Path) -> None:
|
|
454
459
|
"""Test for CLI clear command.
|
|
455
460
|
|
|
@@ -479,6 +484,7 @@ def test_cli_clear_yes(runner: CliRunner, directory: Path) -> None:
|
|
|
479
484
|
).exists()
|
|
480
485
|
|
|
481
486
|
|
|
487
|
+
@pytest.mark.cadc
|
|
482
488
|
def test_cli_pull_force(
|
|
483
489
|
runner: CliRunner, directory: Path, list_specific_files: Path
|
|
484
490
|
) -> None:
|
|
@@ -509,6 +515,7 @@ def test_cli_pull_force(
|
|
|
509
515
|
).exists()
|
|
510
516
|
|
|
511
517
|
|
|
518
|
+
@pytest.mark.cadc
|
|
512
519
|
def test_cli_clear_force(runner: CliRunner, directory: Path) -> None:
|
|
513
520
|
"""Test for CLI clear command.
|
|
514
521
|
|
|
@@ -538,6 +545,7 @@ def test_cli_clear_force(runner: CliRunner, directory: Path) -> None:
|
|
|
538
545
|
).exists()
|
|
539
546
|
|
|
540
547
|
|
|
548
|
+
@pytest.mark.cadc
|
|
541
549
|
def test_cli_pull_force_2cores(runner: CliRunner, directory: Path) -> None:
|
|
542
550
|
"""Test for CLI pull command.
|
|
543
551
|
|
|
@@ -674,6 +682,7 @@ def test_cli_list_children_json(runner: CliRunner) -> None:
|
|
|
674
682
|
assert "289007650" in output_data["datasets"]
|
|
675
683
|
|
|
676
684
|
|
|
685
|
+
@pytest.mark.cadc
|
|
677
686
|
def test_cli_ps_json(runner: CliRunner) -> None:
|
|
678
687
|
"""Test for CLI ps command with JSON output.
|
|
679
688
|
|
|
@@ -698,3 +707,22 @@ def test_cli_ps_json(runner: CliRunner) -> None:
|
|
|
698
707
|
assert "policies" in output_data
|
|
699
708
|
assert output_data["dataset"] == "289007650"
|
|
700
709
|
assert output_data["scope"] == "chime.event.baseband.raw"
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
def test_check_version_banner_on_stderr(monkeypatch, capsys) -> None:
|
|
713
|
+
"""Test the update banner goes to stderr, keeping stdout parseable.
|
|
714
|
+
|
|
715
|
+
Args:
|
|
716
|
+
monkeypatch: Pytest monkeypatch fixture.
|
|
717
|
+
capsys: Pytest capture fixture.
|
|
718
|
+
"""
|
|
719
|
+
from dtcli import cli as cli_module
|
|
720
|
+
|
|
721
|
+
monkeypatch.setattr(cli_module.utilities, "cli_is_latest_release", lambda: False)
|
|
722
|
+
monkeypatch.setattr(
|
|
723
|
+
cli_module.utilities, "get_latest_released_version", lambda: "99.0.0"
|
|
724
|
+
)
|
|
725
|
+
cli_module.check_version()
|
|
726
|
+
captured = capsys.readouterr()
|
|
727
|
+
assert "A new release of datatrail-cli is available" in captured.err
|
|
728
|
+
assert "A new release of datatrail-cli is available" not in captured.out
|
|
@@ -5,6 +5,7 @@ from typing import Any, Dict, List, Optional
|
|
|
5
5
|
|
|
6
6
|
import pytest
|
|
7
7
|
|
|
8
|
+
from dtcli.src import functions
|
|
8
9
|
from dtcli.src.functions import (
|
|
9
10
|
find_unregistered_datasets,
|
|
10
11
|
get_unregistered_dataset,
|
|
@@ -88,3 +89,26 @@ def test_find_unregistered_datasets() -> None:
|
|
|
88
89
|
def test_find_unregistered_datasets_no_match() -> None:
|
|
89
90
|
"""Test find_unregistered_datasets with an event that is not unregistered."""
|
|
90
91
|
assert find_unregistered_datasets("not-an-event") == []
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def test_list_scopes_unanswered(monkeypatch) -> None:
|
|
95
|
+
"""Test a non-list scopes response becomes an error, not a payload."""
|
|
96
|
+
|
|
97
|
+
class _TextResponse:
|
|
98
|
+
status_code = 502
|
|
99
|
+
text = "Bad Gateway"
|
|
100
|
+
|
|
101
|
+
class _DictResponse:
|
|
102
|
+
status_code = 200
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def json() -> Dict[str, Any]:
|
|
106
|
+
return {"detail": "unexpected shape"}
|
|
107
|
+
|
|
108
|
+
monkeypatch.setattr(functions, "procure", lambda: {"server": "http://testserver"})
|
|
109
|
+
for response in (_TextResponse(), _DictResponse()):
|
|
110
|
+
monkeypatch.setattr(
|
|
111
|
+
functions.requests, "get", lambda url, timeout, _r=response: _r
|
|
112
|
+
)
|
|
113
|
+
results: Dict[str, Any] = functions.list()
|
|
114
|
+
assert results == {"error": "Datatrail did not answer the scopes query."}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|