arcsecond 3.12.0__tar.gz → 3.14.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.
Files changed (134) hide show
  1. {arcsecond-3.12.0 → arcsecond-3.14.0}/.github/workflows/pythonpublish.yml +5 -7
  2. {arcsecond-3.12.0 → arcsecond-3.14.0}/.github/workflows/tests.yml +15 -23
  3. {arcsecond-3.12.0 → arcsecond-3.14.0}/.gitignore +0 -3
  4. {arcsecond-3.12.0 → arcsecond-3.14.0}/PKG-INFO +11 -12
  5. arcsecond-3.14.0/README.md +30 -0
  6. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/__init__.py +0 -4
  7. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/alpaca/commands.py +3 -9
  8. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/alpaca/dome_probe.py +5 -6
  9. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/api/main.py +0 -4
  10. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cli.py +7 -7
  11. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/__init__.py +1 -3
  12. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/resources.py +0 -35
  13. arcsecond-3.14.0/arcsecond/cloud/uploader/__init__.py +8 -0
  14. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/__init__.py +1 -0
  15. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/backups.py +1 -14
  16. arcsecond-3.14.0/arcsecond/hosting/database.py +365 -0
  17. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/utils.py +14 -0
  18. arcsecond-3.14.0/arcsecond/imagesources/commands.py +527 -0
  19. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/imagesources/proxy.py +111 -7
  20. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/imagesources/registry.py +88 -1
  21. arcsecond-3.14.0/arcsecond/imagesources/sources/network.py +283 -0
  22. arcsecond-3.14.0/arcsecond/imagesources/store.py +152 -0
  23. {arcsecond-3.12.0 → arcsecond-3.14.0}/pyproject.toml +11 -1
  24. {arcsecond-3.12.0 → arcsecond-3.14.0}/sonar-project.properties +1 -1
  25. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/test_alpaca_probe.py +12 -8
  26. arcsecond-3.14.0/tests/test_hosting_database.py +330 -0
  27. arcsecond-3.14.0/tests/test_imagesources_netcam.py +418 -0
  28. arcsecond-3.14.0/tests/test_imagesources_store.py +327 -0
  29. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/utils.py +0 -27
  30. arcsecond-3.14.0/uv.lock +2488 -0
  31. arcsecond-3.12.0/.github/workflows/docsdeploy.yml +0 -28
  32. arcsecond-3.12.0/README.md +0 -31
  33. arcsecond-3.12.0/arcsecond/cloud/uploader/__init__.py +0 -13
  34. arcsecond-3.12.0/arcsecond/cloud/uploader/allskycameraimages/context.py +0 -62
  35. arcsecond-3.12.0/arcsecond/cloud/uploader/allskycameraimages/errors.py +0 -19
  36. arcsecond-3.12.0/arcsecond/cloud/uploader/allskycameraimages/uploader.py +0 -29
  37. arcsecond-3.12.0/arcsecond/cloud/uploader/allskycameraimages/utils.py +0 -54
  38. arcsecond-3.12.0/arcsecond/imagesources/commands.py +0 -206
  39. arcsecond-3.12.0/deploy.sh +0 -30
  40. arcsecond-3.12.0/docs/.vitepress/config.js +0 -36
  41. arcsecond-3.12.0/docs/.vitepress/theme/custom.css +0 -35
  42. arcsecond-3.12.0/docs/.vitepress/theme/index.js +0 -4
  43. arcsecond-3.12.0/docs/api-basics.md +0 -103
  44. arcsecond-3.12.0/docs/backups.md +0 -158
  45. arcsecond-3.12.0/docs/img/icon-logo.png +0 -0
  46. arcsecond-3.12.0/docs/index.md +0 -36
  47. arcsecond-3.12.0/docs/install-windows.md +0 -215
  48. arcsecond-3.12.0/docs/install.md +0 -85
  49. arcsecond-3.12.0/docs/public/img/icon-logo.png +0 -0
  50. arcsecond-3.12.0/docs/resources.md +0 -359
  51. arcsecond-3.12.0/docs/rotate-postgres-password.md +0 -78
  52. arcsecond-3.12.0/docs/upload.md +0 -128
  53. arcsecond-3.12.0/docs/webcam.md +0 -178
  54. arcsecond-3.12.0/examples/example_upload_images.py +0 -24
  55. arcsecond-3.12.0/package-lock.json +0 -3528
  56. arcsecond-3.12.0/package.json +0 -29
  57. arcsecond-3.12.0/poetry.lock +0 -471
  58. arcsecond-3.12.0/tests/cloud/uploader/allskycameraimages/__init__.py +0 -0
  59. arcsecond-3.12.0/tests/cloud/uploader/allskycameraimages/test_context.py +0 -115
  60. arcsecond-3.12.0/tests/cloud/uploader/allskycameraimages/test_uploader_full_process.py +0 -85
  61. arcsecond-3.12.0/tests/cloud/uploader/datafiles/__init__.py +0 -0
  62. {arcsecond-3.12.0 → arcsecond-3.14.0}/.docker/Dockerfile_postgres +0 -0
  63. {arcsecond-3.12.0 → arcsecond-3.14.0}/.docker/Dockerfile_redis +0 -0
  64. {arcsecond-3.12.0 → arcsecond-3.14.0}/.github/dependabot.yml +0 -0
  65. {arcsecond-3.12.0 → arcsecond-3.14.0}/LICENSE +0 -0
  66. {arcsecond-3.12.0 → arcsecond-3.14.0}/Makefile +0 -0
  67. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/__version__.py +0 -0
  68. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/alpaca/__init__.py +0 -0
  69. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/api/__init__.py +0 -0
  70. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/api/config.py +0 -0
  71. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/api/constants.py +0 -0
  72. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/api/endpoint.py +0 -0
  73. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/api/resources.py +0 -0
  74. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/auth.py +0 -0
  75. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/constants.py +0 -0
  76. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/context.py +0 -0
  77. {arcsecond-3.12.0/arcsecond/cloud/uploader/allskycameraimages → arcsecond-3.14.0/arcsecond/cloud/uploader/datafiles}/__init__.py +0 -0
  78. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/datafiles/context.py +0 -0
  79. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/datafiles/errors.py +0 -0
  80. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/datafiles/uploader.py +0 -0
  81. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/datafiles/utils.py +0 -0
  82. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/errors.py +0 -0
  83. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/logger.py +0 -0
  84. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/uploader.py +0 -0
  85. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/utils.py +0 -0
  86. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploader/walker.py +0 -0
  87. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/cloud/uploads.py +0 -0
  88. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/errors.py +0 -0
  89. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/checks.py +0 -0
  90. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/constants.py +0 -0
  91. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/docker/__init__.py +0 -0
  92. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/docker/constants.py +0 -0
  93. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/docker/containers.py +0 -0
  94. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/docker/docker-compose.yml +0 -0
  95. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/docker/images.py +0 -0
  96. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/docker/utils.py +0 -0
  97. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/keygen/__init__.py +0 -0
  98. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/keygen/client.py +0 -0
  99. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/keygen/utils.py +0 -0
  100. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/local.py +0 -0
  101. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/main.py +0 -0
  102. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/postgres/init-db.sh +0 -0
  103. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/setup.py +0 -0
  104. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/hosting/validation.py +0 -0
  105. {arcsecond-3.12.0/arcsecond/cloud/uploader/datafiles → arcsecond-3.14.0/arcsecond/imagesources}/__init__.py +0 -0
  106. {arcsecond-3.12.0/arcsecond/imagesources → arcsecond-3.14.0/arcsecond/imagesources/sources}/__init__.py +0 -0
  107. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/imagesources/sources/base.py +0 -0
  108. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/imagesources/sources/filewatch.py +0 -0
  109. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/imagesources/sources/opencv.py +0 -0
  110. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/options.py +0 -0
  111. {arcsecond-3.12.0 → arcsecond-3.14.0}/arcsecond/targets.py +0 -0
  112. {arcsecond-3.12.0 → arcsecond-3.14.0}/examples/example_upload_files.py +0 -0
  113. {arcsecond-3.12.0 → arcsecond-3.14.0}/requirements.txt +0 -0
  114. {arcsecond-3.12.0 → arcsecond-3.14.0}/setup.cfg +0 -0
  115. {arcsecond-3.12.0 → arcsecond-3.14.0}/setup.py +0 -0
  116. {arcsecond-3.12.0/arcsecond/imagesources/sources → arcsecond-3.14.0/tests}/__init__.py +0 -0
  117. {arcsecond-3.12.0/tests → arcsecond-3.14.0/tests/api}/__init__.py +0 -0
  118. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/api/test_api.py +0 -0
  119. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/api/test_api_endpoint.py +0 -0
  120. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/api/test_config.py +0 -0
  121. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/api/test_targets.py +0 -0
  122. {arcsecond-3.12.0/tests/api → arcsecond-3.14.0/tests/cloud}/__init__.py +0 -0
  123. {arcsecond-3.12.0/tests/cloud → arcsecond-3.14.0/tests/cloud/uploader}/__init__.py +0 -0
  124. {arcsecond-3.12.0/tests/cloud/uploader → arcsecond-3.14.0/tests/cloud/uploader/datafiles}/__init__.py +0 -0
  125. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/cloud/uploader/datafiles/test_uploader_errors.py +0 -0
  126. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/cloud/uploader/datafiles/test_uploader_full_process.py +0 -0
  127. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/cloud/uploader/datafiles/test_uploader_init.py +0 -0
  128. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/cloud/uploader/datafiles/test_uploader_prepare.py +0 -0
  129. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/cloud/uploader/datafiles/test_uploader_upload.py +0 -0
  130. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/conftest.py +0 -0
  131. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/fixtures/file1.fits +0 -0
  132. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/test_cli.py +0 -0
  133. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/test_hosting_local.py +0 -0
  134. {arcsecond-3.12.0 → arcsecond-3.14.0}/tests/test_targets_planning.py +0 -0
@@ -25,14 +25,15 @@ jobs:
25
25
 
26
26
  - uses: actions/checkout@v5
27
27
 
28
- - name: Set up Python
29
- uses: actions/setup-python@v6
28
+ - name: Install uv
29
+ uses: astral-sh/setup-uv@v6
30
30
  with:
31
31
  python-version: '3.12'
32
+ enable-cache: true
32
33
 
33
34
  - name: Validate pyproject.toml version matches tag
34
35
  run: |
35
- python - <<'PY'
36
+ uv run python - <<'PY'
36
37
  import os, pathlib, tomllib
37
38
 
38
39
  tag = os.environ["GITHUB_REF_NAME"]
@@ -45,10 +46,7 @@ jobs:
45
46
  PY
46
47
 
47
48
  - name: Build distributions
48
- run: |
49
- python -m pip install --upgrade pip
50
- pip install build
51
- python -m build
49
+ run: uv build
52
50
 
53
51
  - name: Publish to PyPI (OIDC)
54
52
  uses: pypa/gh-action-pypi-publish@release/v1
@@ -16,26 +16,22 @@ jobs:
16
16
  steps:
17
17
  - uses: actions/checkout@v5
18
18
 
19
- - name: Set up Python ${{ matrix.python-version }}
20
- uses: actions/setup-python@v6
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v6
21
21
  with:
22
22
  python-version: ${{ matrix.python-version }}
23
+ enable-cache: true
23
24
 
24
25
  - name: Install dependencies
25
- run: |
26
- python -m pip install --upgrade pip
27
- if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
28
- pip install pytest pytest-cov respx
29
- pip install -e .
26
+ run: uv sync --extra webcam --group dev
30
27
 
31
28
  - name: Test with coverage (only on 3.12)
32
29
  if: matrix.python-version == '3.12'
33
- run: |
34
- pytest -vvs tests/ --cov=arcsecond --cov-report=xml:coverage.xml
30
+ run: uv run pytest -vvs tests/ --cov=arcsecond --cov-report=xml:coverage.xml
35
31
 
36
32
  - name: Test without coverage
37
33
  if: matrix.python-version != '3.12'
38
- run: pytest -vvs tests/
34
+ run: uv run pytest -vvs tests/
39
35
 
40
36
  - name: Upload coverage artifact (only on 3.12)
41
37
  if: matrix.python-version == '3.12'
@@ -58,7 +54,7 @@ jobs:
58
54
  path: .
59
55
 
60
56
  - name: SonarQube Scan
61
- uses: SonarSource/sonarqube-scan-action@v5
57
+ uses: SonarSource/sonarqube-scan-action@v6
62
58
  env:
63
59
  SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
64
60
 
@@ -67,24 +63,20 @@ jobs:
67
63
  steps:
68
64
  - uses: actions/checkout@v5
69
65
 
70
- - name: Set up Python
71
- uses: actions/setup-python@v6
66
+ - name: Install uv
67
+ uses: astral-sh/setup-uv@v6
72
68
  with:
73
69
  python-version: '3.12'
70
+ enable-cache: true
74
71
 
75
- - name: Install dependencies
76
- run: |
77
- python -m pip install --upgrade pip
78
- pip install flake8 black isort
72
+ - name: Install dev dependencies
73
+ run: uv sync --group dev
79
74
 
80
75
  - name: Lint with flake8
81
- run: |
82
- flake8 arcsecond tests --count --select=E9,F63,F7,F82 --show-source --statistics
76
+ run: uv run flake8 arcsecond tests --count --select=E9,F63,F7,F82 --show-source --statistics
83
77
 
84
78
  - name: Check formatting with black
85
- run: |
86
- black --check arcsecond tests
79
+ run: uv run black --check arcsecond tests
87
80
 
88
81
  - name: Check imports with isort
89
- run: |
90
- isort --check-only --profile black arcsecond tests
82
+ run: uv run isort --check-only --profile black arcsecond tests
@@ -12,9 +12,6 @@ build/
12
12
  venv
13
13
  /env
14
14
  .DS_Store
15
- node_modules
16
-
17
- /docs/.vitepress/cache
18
15
 
19
16
  *.tar
20
17
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arcsecond
3
- Version: 3.12.0
3
+ Version: 3.14.0
4
4
  Summary: CLI for arcsecond.io
5
5
  Project-URL: Homepage, https://github.com/arcsecond-io/cli
6
6
  Project-URL: Issues, https://github.com/arcsecond-io/cli/issues
@@ -49,7 +49,7 @@ Requires-Dist: aiohttp>=3.9; extra == 'webcam'
49
49
  Requires-Dist: opencv-python-headless<5,>=4.10; extra == 'webcam'
50
50
  Description-Content-Type: text/markdown
51
51
 
52
- [![Deploy Docs](https://github.com/arcsecond-io/cli/actions/workflows/docsdeploy.yml/badge.svg)](https://github.com/arcsecond-io/cli/actions/workflows/docsdeploy.yml) [![Downloads](http://pepy.tech/badge/arcsecond)](http://pepy.tech/project/arcsecond)
52
+ [![Downloads](http://pepy.tech/badge/arcsecond)](http://pepy.tech/project/arcsecond)
53
53
  [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Farcsecond-io%2Fcli.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Farcsecond-io%2Fcli?ref=badge_shield)
54
54
 
55
55
  # Arcsecond CLI
@@ -62,20 +62,19 @@ public and private ones.
62
62
 
63
63
  # Development
64
64
 
65
- To start developing the arcsecond CLI, fork the project, `git clone` it,
66
- then, in the arcsecond-cli folder, do
67
- (assuming [virtualenv](https://virtualenv.pypa.io/en/stable/) is installed):
65
+ The project uses [uv](https://docs.astral.sh/uv/) for environment and
66
+ dependency management. After forking and cloning:
68
67
 
69
68
  ```bash
70
69
  $ cd ~/arcsecond-cli
71
- $ virtualenv --python=pythonX.Y env
72
- $ source env/bin/activate
73
- $ pip install -e .
74
- ```
70
+ $ uv sync --extra webcam --group dev
71
+ $ uv run arcsecond --help
72
+ $ uv run pytest
73
+ ```
75
74
 
76
- The last line ensure you can call the "locally installed" version of the
77
- code of that folder. Once done one first time, only the `source
78
- env/bin/activate` is needed when you restart a debugging session.
75
+ `uv sync` creates `.venv/` and installs the project with its `webcam` extra
76
+ and the `dev` dependency group (pytest, black, flake8, isort). Prefix
77
+ commands with `uv run` or activate the venv with `source .venv/bin/activate`.
79
78
 
80
79
 
81
80
  ## License
@@ -0,0 +1,30 @@
1
+ [![Downloads](http://pepy.tech/badge/arcsecond)](http://pepy.tech/project/arcsecond)
2
+ [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Farcsecond-io%2Fcli.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Farcsecond-io%2Fcli?ref=badge_shield)
3
+
4
+ # Arcsecond CLI
5
+
6
+ The Command-line interface (CLI) for Arcsecond. It can be used as Python
7
+ module too. The CLI makes it easy to login/register and access Arcsecond resources,
8
+ public and private ones.
9
+
10
+ [Read the docs](https://docs.arcsecond.io/cli)
11
+
12
+ # Development
13
+
14
+ The project uses [uv](https://docs.astral.sh/uv/) for environment and
15
+ dependency management. After forking and cloning:
16
+
17
+ ```bash
18
+ $ cd ~/arcsecond-cli
19
+ $ uv sync --extra webcam --group dev
20
+ $ uv run arcsecond --help
21
+ $ uv run pytest
22
+ ```
23
+
24
+ `uv sync` creates `.venv/` and installs the project with its `webcam` extra
25
+ and the `dev` dependency group (pytest, black, flake8, isort). Prefix
26
+ commands with `uv run` or activate the venv with `source .venv/bin/activate`.
27
+
28
+
29
+ ## License
30
+ [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Farcsecond-io%2Fcli.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Farcsecond-io%2Fcli?ref=badge_large)
@@ -5,8 +5,6 @@ from .api import (
5
5
  ArcsecondTargetListsResource,
6
6
  )
7
7
  from .cloud.uploader import (
8
- AllSkyCameraImageFileUploader,
9
- AllSkyCameraImageUploadContext,
10
8
  DatasetFileUploader,
11
9
  DatasetUploadContext,
12
10
  )
@@ -25,8 +23,6 @@ __all__ = [
25
23
  "ArcsecondTargetPayloadPlan",
26
24
  "DatasetUploadContext",
27
25
  "DatasetFileUploader",
28
- "AllSkyCameraImageFileUploader",
29
- "AllSkyCameraImageUploadContext",
30
26
  "plan_target_payload",
31
27
  "walk_folder_and_upload_files",
32
28
  ]
@@ -167,20 +167,14 @@ def probe_dome_cmd(
167
167
  json.dump(result.report, fp, indent=2, sort_keys=False)
168
168
  fp.write("\n")
169
169
  except OSError as exc:
170
- raise ArcsecondError(
171
- f"Could not write report to {output_path}: {exc}"
172
- ) from exc
170
+ raise ArcsecondError(f"Could not write report to {output_path}: {exc}") from exc
173
171
 
174
172
  counts = result.counts
175
173
  supported = result.report.get("supported_actions", {})
176
- supported_n = (
177
- len(supported.get("value") or []) if supported.get("ok") else 0
178
- )
174
+ supported_n = len(supported.get("value") or []) if supported.get("ok") else 0
179
175
 
180
176
  click.echo("")
181
177
  click.echo(click.style("Summary", bold=True))
182
178
  click.echo(f" Probes: {counts.ok}/{counts.total} OK")
183
179
  click.echo(f" SupportedActions: {supported_n} entries")
184
- click.echo(
185
- f" Report written to {click.style(os.fspath(output_path), fg='cyan')}"
186
- )
180
+ click.echo(f" Report written to {click.style(os.fspath(output_path), fg='cyan')}")
@@ -71,9 +71,7 @@ _READ_ONLY_COMMANDS: tuple[str, ...] = (
71
71
  # Active commands: kept separate and only sent when allow_active=True.
72
72
  # ``XQ#STATUS`` jumps to a label called STATUS if it exists; whether that
73
73
  # label has side effects depends on the driver, hence "active".
74
- _ACTIVE_COMMANDS: tuple[str, ...] = (
75
- "XQ#STATUS",
76
- )
74
+ _ACTIVE_COMMANDS: tuple[str, ...] = ("XQ#STATUS",)
77
75
 
78
76
  _RESPONSE_TRUNCATE = 2000
79
77
 
@@ -116,6 +114,7 @@ def _coerce_jsonable(value: Any) -> Any:
116
114
  # IntEnum is a subclass of int, so check it *before* the primitive branch.
117
115
  # We want {"name": "shutterClosed", "value": 1} not just 1.
118
116
  from enum import Enum
117
+
119
118
  if isinstance(value, Enum):
120
119
  return {"name": value.name, "value": value.value}
121
120
  if isinstance(value, (str, int, float, bool)) or value is None:
@@ -384,15 +383,15 @@ def probe_dome(
384
383
  raise RuntimeError(
385
384
  f"Could not construct Alpaca Dome client for "
386
385
  f"{protocol}://{address} (device {device_number}): "
387
- f"{type(exc).__name__}: {exc}\n"
388
- + traceback.format_exc()
386
+ f"{type(exc).__name__}: {exc}\n" + traceback.format_exc()
389
387
  ) from exc
390
388
 
391
389
  connected_outcome = _capture(lambda: dome.Connected)
392
390
  counts.total += 1
393
391
  counts.ok += 1 if connected_outcome["ok"] else 0
394
392
  progress.emit(
395
- "Connected", connected_outcome["ok"],
393
+ "Connected",
394
+ connected_outcome["ok"],
396
395
  connected_outcome.get("error") or str(connected_outcome.get("value")),
397
396
  )
398
397
 
@@ -52,10 +52,6 @@ class ArcsecondAPI(object):
52
52
  self.datasets = ArcsecondAPIEndpoint(self.config, "datasets", self.subdomain)
53
53
  self.datafiles = ArcsecondAPIEndpoint(self.config, "datafiles", self.subdomain)
54
54
 
55
- self.allskycameras = ArcsecondAPIEndpoint(
56
- self.config, "allskycameras", self.subdomain
57
- )
58
-
59
55
  def login(self, username, access_key=None, upload_key=None):
60
56
  assert access_key or upload_key
61
57
  assert not (access_key and upload_key)
@@ -2,7 +2,6 @@ import click
2
2
 
3
3
  from arcsecond.alpaca.commands import alpaca_group
4
4
  from arcsecond.cloud import (
5
- allskycameras,
6
5
  api,
7
6
  datasets,
8
7
  login,
@@ -10,7 +9,7 @@ from arcsecond.cloud import (
10
9
  telescopes,
11
10
  upload_data,
12
11
  )
13
- from arcsecond.hosting import backups, setup
12
+ from arcsecond.hosting import backups, db, setup
14
13
  from arcsecond.imagesources import commands as imagesources
15
14
 
16
15
  from . import __version__
@@ -53,9 +52,6 @@ main.add_command(datasets)
53
52
  # Read the list of existing telescopes (for upload purposes).
54
53
  main.add_command(telescopes)
55
54
 
56
- # Read the list of existing allskycameras (for upload purposes).
57
- main.add_command(allskycameras)
58
-
59
55
  # Upload a folder of files to a given dataset.
60
56
  main.add_command(upload_data)
61
57
 
@@ -65,10 +61,14 @@ main.add_command(setup)
65
61
  # Browse and restore Arcsecond.local DB backups.
66
62
  main.add_command(backups)
67
63
 
68
- # Native live-image proxy — exposes USB webcams and all-sky cameras to
69
- # Arcsecond.local Docker containers via host.docker.internal.
64
+ # Manage the Arcsecond.local database (e.g. `arcsecond db set-password`).
65
+ main.add_command(db)
66
+
67
+ # Native live-image proxy — exposes USB webcams, all-sky cameras and network
68
+ # cameras to Arcsecond.local Docker containers via host.docker.internal.
70
69
  main.add_command(imagesources.webcam)
71
70
  main.add_command(imagesources.allsky)
71
+ main.add_command(imagesources.netcam)
72
72
 
73
73
  # Local ASCOM Alpaca diagnostics (e.g. `arcsecond alpaca probe dome ...`).
74
74
  main.add_command(alpaca_group)
@@ -1,8 +1,6 @@
1
1
  from .auth import api, login, me
2
- from .resources import allskycameras, datasets, telescopes
2
+ from .resources import datasets, telescopes
3
3
  from .uploader import (
4
- AllSkyCameraImageFileUploader,
5
- AllSkyCameraImageUploadContext,
6
4
  DatasetFileUploader,
7
5
  DatasetUploadContext,
8
6
  )
@@ -78,38 +78,3 @@ def telescopes(state, portal=None):
78
78
  s += f"(uuid: {telescope_dict['uuid']}) "
79
79
  s += f"[ObservingSite UUID: {telescope_dict['observing_site']}]"
80
80
  click.echo(s)
81
-
82
-
83
- @click.command(help="Display the list of (portal) all-sky cameras.")
84
- @click.option(
85
- "-p",
86
- "--portal",
87
- required=False,
88
- nargs=1,
89
- help="The portal subdomain, if uploading for an Observatory Portal.",
90
- )
91
- @basic_options
92
- @pass_state
93
- def allskycameras(state, portal=None):
94
- org_subdomain = portal or ""
95
- if org_subdomain:
96
- click.echo(f" • Fetching allskycameras for portal '{org_subdomain}'...")
97
- else:
98
- click.echo(" • Fetching allskycameras...")
99
-
100
- cameras_list, error = ArcsecondAPI(
101
- ArcsecondConfig.from_state(state), org_subdomain
102
- ).allskycameras.list()
103
- if error is not None:
104
- raise ArcsecondError(str(error))
105
-
106
- if isinstance(cameras_list, dict) and "results" in cameras_list.keys():
107
- cameras_list = cameras_list["results"]
108
-
109
- click.echo(
110
- f" • Found {len(cameras_list)} all-sky camera{'s' if len(cameras_list) > 1 else ''}."
111
- )
112
- for camera_list in cameras_list:
113
- s = f" 💾 \"{camera_list['name']}\" "
114
- s += f"(uuid: {camera_list['uuid']}) "
115
- click.echo(s)
@@ -0,0 +1,8 @@
1
+ from .datafiles.context import DatasetUploadContext
2
+ from .datafiles.uploader import DatasetFileUploader
3
+ from .datafiles.utils import display_upload_datafiles_command_summary
4
+
5
+ __all__ = [
6
+ "DatasetUploadContext",
7
+ "DatasetFileUploader",
8
+ ]
@@ -1,3 +1,4 @@
1
1
  # from .main import install, status, stop
2
2
  from .backups import backups
3
+ from .database import db
3
4
  from .local import setup
@@ -12,7 +12,7 @@ import click
12
12
 
13
13
  from arcsecond.options import basic_options
14
14
 
15
- from .utils import _read_env_value
15
+ from .utils import _container_running, _read_env_value
16
16
 
17
17
  DB_CONTAINER = "arcsecond-db"
18
18
  API_CONTAINER = "arcsecond-api"
@@ -105,19 +105,6 @@ def _human_size(num_bytes):
105
105
  return f"{num_bytes:.1f} PB"
106
106
 
107
107
 
108
- def _container_running(name):
109
- try:
110
- out = subprocess.run(
111
- ["docker", "inspect", "-f", "{{.State.Running}}", name],
112
- capture_output=True,
113
- text=True,
114
- check=False,
115
- )
116
- except FileNotFoundError:
117
- return False
118
- return out.returncode == 0 and out.stdout.strip() == "true"
119
-
120
-
121
108
  def _classify_dump_health(backup_path):
122
109
  """Quick check that a dump file looks usable before we try to parse it.
123
110