starbash 0.2.4__tar.gz → 0.2.6__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.
- {starbash-0.2.4 → starbash-0.2.6}/PKG-INFO +4 -4
- {starbash-0.2.4 → starbash-0.2.6}/pyproject.toml +26 -22
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/__init__.py +6 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/analytics.py +12 -5
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/app.py +35 -25
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/check_version.py +2 -2
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/commands/info.py +6 -6
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/commands/process.py +6 -6
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/commands/repo.py +10 -9
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/commands/select.py +12 -11
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/commands/user.py +5 -5
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/database.py +2 -1
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/doit.py +68 -22
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/dwarf3.py +13 -6
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/linux.py +1 -1
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/main.py +1 -1
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/parameters.py +3 -2
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/paths.py +2 -2
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/processed_target.py +7 -5
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/processing.py +8 -2
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/recipes/osc.py +4 -4
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/score.py +8 -8
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/selection.py +2 -1
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/sim_siril/connection.py +3 -2
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/templates/userconfig.toml +5 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/tool/__init__.py +9 -3
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/tool/base.py +152 -46
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/tool/context.py +13 -11
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/tool/graxpert.py +6 -1
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/tool/python.py +14 -8
- starbash-0.2.6/src/starbash/tool/rcastro.py +162 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/tool/siril.py +19 -5
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/windows.py +1 -1
- starbash-0.2.4/src/repo/__init__.py +0 -8
- starbash-0.2.4/src/repo/http_client.py +0 -5
- starbash-0.2.4/src/repo/manager.py +0 -146
- starbash-0.2.4/src/repo/repo.py +0 -693
- {starbash-0.2.4 → starbash-0.2.6}/LICENSE +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/README.md +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/aliases.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/commands/__init__.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/defaults/__init__.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/defaults/starbash.toml +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/doit_types.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/exception.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/filtering.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/icon.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/os.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/processing_like.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/recipes/README.md +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/recipes/__init__.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/rich.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/safety.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/sim_siril/__init__.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/sim_siril/enums.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/sim_siril/utility.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/stage_utils.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/stages.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/templates/__init__.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/templates/repo/master.toml +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/templates/repo/processed.toml +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/templates/target/master.toml +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/templates/target/processed.toml +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/toml.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/ui/main.py +0 -0
- {starbash-0.2.4 → starbash-0.2.6}/src/starbash/url.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: starbash
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: A tool for automating/standardizing/sharing astrophotography workflows.
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Author: Kevin Hester
|
|
@@ -13,14 +13,14 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
13
13
|
Requires-Dist: astropy (>=7.1.1,<8.0.0)
|
|
14
14
|
Requires-Dist: doit (>=0.36.0,<0.37.0)
|
|
15
15
|
Requires-Dist: graxpert[cpuonly] (>=3.2.0a2,<4.0.0)
|
|
16
|
-
Requires-Dist:
|
|
16
|
+
Requires-Dist: numpy (==2.2.6)
|
|
17
17
|
Requires-Dist: platformdirs (>=4.5.0,<5.0.0)
|
|
18
|
-
Requires-Dist:
|
|
18
|
+
Requires-Dist: pyqt6 (>=6.10.1,<7.0.0)
|
|
19
19
|
Requires-Dist: restrictedpython (>=8.1,<9.0)
|
|
20
20
|
Requires-Dist: rich (>=14.2.0,<15.0.0)
|
|
21
21
|
Requires-Dist: sentry-sdk (>=2.42.1,<3.0.0)
|
|
22
22
|
Requires-Dist: textual (>=6.8.0,<7.0.0)
|
|
23
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: toml-repo (>=0.1.2,<0.2.0)
|
|
24
24
|
Requires-Dist: typer (>=0.20.0,<0.21.0)
|
|
25
25
|
Requires-Dist: update-checker (>=0.18.0,<0.19.0)
|
|
26
26
|
Project-URL: Documentation, https://github.com/geeksville/starbash/blob/main/README.md
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "starbash"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.6"
|
|
4
4
|
description = "A tool for automating/standardizing/sharing astrophotography workflows."
|
|
5
5
|
authors = ["Kevin Hester <kevinh@geeksville.com>"]
|
|
6
6
|
readme = "README.md"
|
|
@@ -9,13 +9,13 @@ repository = "https://github.com/geeksville/starbash"
|
|
|
9
9
|
documentation = "https://github.com/geeksville/starbash/blob/main/README.md" # FIXME provide something better
|
|
10
10
|
packages = [
|
|
11
11
|
{ include = "starbash", from = "src" },
|
|
12
|
-
{ include = "repo", from = "src" },
|
|
13
12
|
]
|
|
14
13
|
|
|
15
14
|
[tool.poetry.dependencies]
|
|
16
15
|
python = ">=3.12,<3.15" # RestrictedPython doesn't yet work on 3.15
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
|
|
17
|
+
# Note: to use toml-repo from the local submodule rather than pypi use:
|
|
18
|
+
# toml-repo = {path = "toml-repo", develop = true}
|
|
19
19
|
rich = ">=14.2.0,<15.0.0"
|
|
20
20
|
restrictedpython = ">=8.1,<9.0"
|
|
21
21
|
astropy = ">=7.1.1,<8.0.0"
|
|
@@ -23,7 +23,6 @@ platformdirs = ">=4.5.0,<5.0.0"
|
|
|
23
23
|
typer = "^0.20.0"
|
|
24
24
|
sentry-sdk = "^2.42.1"
|
|
25
25
|
update-checker = "^0.18.0"
|
|
26
|
-
requests-cache = "^1.2.1"
|
|
27
26
|
doit = "^0.36.0"
|
|
28
27
|
textual = "^6.8.0"
|
|
29
28
|
|
|
@@ -31,13 +30,14 @@ textual = "^6.8.0"
|
|
|
31
30
|
# graxpert = {path = "GraXpert", extras = ["cpuonly"], develop = true}
|
|
32
31
|
graxpert = {version = "^3.2.0a2", extras = ["cpuonly"]}
|
|
33
32
|
|
|
34
|
-
# The following two libs are only needed for the experiment of running siril scripts directly...
|
|
33
|
+
# The following two libs are only needed for the (temporary) experiment of running siril scripts directly...
|
|
35
34
|
# experimenting with siril-scripts/processing/VeraLux_HyperMetric_Stretch.py
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
numpy = "2.2.6"
|
|
36
|
+
pyqt6 = "^6.10.1"
|
|
37
|
+
toml-repo = "^0.1.2"
|
|
38
38
|
|
|
39
39
|
[tool.poetry.group.dev.dependencies]
|
|
40
|
-
pytest = ">=8.4.2,<
|
|
40
|
+
pytest = ">=8.4.2,<10.0.0"
|
|
41
41
|
pytest-cov = "^6.0.0"
|
|
42
42
|
pytest-xdist = "^3.8.0"
|
|
43
43
|
pre-commit = "^4.3.0"
|
|
@@ -61,9 +61,9 @@ markers = [
|
|
|
61
61
|
# By default, exclude slow and integration tests
|
|
62
62
|
# --tb=line shows minimal tracebacks (just one line per failure)
|
|
63
63
|
# --tb=short shows shorter tracebacks
|
|
64
|
-
# -
|
|
64
|
+
# -rfE shows summary of failed and error test outcomes at end (not passed)
|
|
65
65
|
# --ignore excludes third-party test directories
|
|
66
|
-
addopts = "-m 'not slow and not integration' -n auto --tb=short -
|
|
66
|
+
addopts = "-m 'not slow and not integration' -n auto --tb=short -rfE --ignore=GraXpert --ignore=textual --ignore=starbash-recipes"
|
|
67
67
|
|
|
68
68
|
# Note: To limit captured output further, you can:
|
|
69
69
|
# 1. Use --tb=line for minimal tracebacks
|
|
@@ -117,19 +117,22 @@ exclude = [
|
|
|
117
117
|
[tool.ruff.lint]
|
|
118
118
|
# Enable these rule sets
|
|
119
119
|
select = [
|
|
120
|
-
"E",
|
|
121
|
-
"F",
|
|
122
|
-
"I",
|
|
123
|
-
"W",
|
|
124
|
-
"UP",
|
|
125
|
-
"B",
|
|
120
|
+
"E", # pycodestyle errors
|
|
121
|
+
"F", # pyflakes
|
|
122
|
+
"I", # isort (import sorting)
|
|
123
|
+
"W", # pycodestyle warnings
|
|
124
|
+
"UP", # pyupgrade
|
|
125
|
+
"B", # flake8-bugbear
|
|
126
|
+
"ANN", # flake8-annotations (type annotation enforcement)
|
|
126
127
|
]
|
|
127
128
|
|
|
128
129
|
# Ignore specific rules that are too noisy for this codebase
|
|
129
130
|
ignore = [
|
|
130
|
-
"E501",
|
|
131
|
-
"B904",
|
|
132
|
-
"B006",
|
|
131
|
+
"E501", # Line too long (handled by formatter)
|
|
132
|
+
"B904", # Within an `except` clause, raise exceptions with `raise ... from err`
|
|
133
|
+
"B006", # Do not use mutable data structures for argument defaults
|
|
134
|
+
"ANN401", # Dynamically typed expressions (Any) are sometimes necessary
|
|
135
|
+
"ANN204", # Missing return type for __init__ / __new__ / __post_init__
|
|
133
136
|
]
|
|
134
137
|
|
|
135
138
|
[tool.ruff.lint.per-file-ignores]
|
|
@@ -142,14 +145,15 @@ ignore = [
|
|
|
142
145
|
"F401", # Imported but unused
|
|
143
146
|
"F841", # Local variable assigned but never used
|
|
144
147
|
"PLC0415", # Import should be at top of file
|
|
148
|
+
"ANN", # Type annotations not required in tests
|
|
145
149
|
]
|
|
146
150
|
|
|
147
151
|
[tool.basedpyright]
|
|
148
152
|
# Enable import validation to catch runtime import errors at analysis time
|
|
149
153
|
include = ["src"]
|
|
150
154
|
exclude = ["**/__pycache__", ".venv", "build", "dist"]
|
|
151
|
-
extraPaths = ["GraXpert"] # Include local
|
|
152
|
-
typeCheckingMode = "
|
|
155
|
+
extraPaths = ["GraXpert", "toml-repo"] # Include local sources for type checking
|
|
156
|
+
typeCheckingMode = "standard" # Standard type checking: catches type errors, missing annotations, etc.
|
|
153
157
|
reportMissingImports = true
|
|
154
158
|
reportImportCycles = true
|
|
155
159
|
reportUndefinedVariable = true
|
|
@@ -5,6 +5,12 @@ from typing import Any
|
|
|
5
5
|
|
|
6
6
|
from rich.console import Console
|
|
7
7
|
|
|
8
|
+
# Configure toml_repo for starbash's conventions before any repo operations
|
|
9
|
+
from toml_repo import set_config_suffix, set_pkg_resource_root
|
|
10
|
+
|
|
11
|
+
set_config_suffix("starbash.toml")
|
|
12
|
+
set_pkg_resource_root("starbash")
|
|
13
|
+
|
|
8
14
|
# Common type aliases for clarity
|
|
9
15
|
type StageDict = dict[str, Any] # a processing stage definition from our toml
|
|
10
16
|
type InputDef = dict[Any, Any] # an input definition within a stage
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
3
|
import platform
|
|
4
|
+
import types
|
|
5
|
+
from typing import Any
|
|
4
6
|
|
|
5
7
|
from sentry_sdk.integrations.excepthook import ExcepthookIntegration
|
|
6
8
|
|
|
@@ -121,17 +123,22 @@ def analytics_exception(exc: BaseException) -> bool:
|
|
|
121
123
|
class NopAnalytics:
|
|
122
124
|
"""Used when users have disabled analytics/crash reporting."""
|
|
123
125
|
|
|
124
|
-
def __enter__(self):
|
|
126
|
+
def __enter__(self) -> "NopAnalytics":
|
|
125
127
|
return self
|
|
126
128
|
|
|
127
|
-
def __exit__(
|
|
129
|
+
def __exit__(
|
|
130
|
+
self,
|
|
131
|
+
exc_type: type[BaseException] | None,
|
|
132
|
+
exc_value: BaseException | None,
|
|
133
|
+
traceback: types.TracebackType | None,
|
|
134
|
+
) -> bool:
|
|
128
135
|
return False
|
|
129
136
|
|
|
130
|
-
def set_data(self, key, value):
|
|
137
|
+
def set_data(self, key: str, value: Any) -> None:
|
|
131
138
|
pass
|
|
132
139
|
|
|
133
140
|
|
|
134
|
-
def analytics_start_span(**kwargs):
|
|
141
|
+
def analytics_start_span(**kwargs: Any) -> Any:
|
|
135
142
|
"""Start an analytics/tracing span if analytics is enabled, otherwise return a no-op context manager."""
|
|
136
143
|
if analytics_allowed:
|
|
137
144
|
import sentry_sdk
|
|
@@ -141,7 +148,7 @@ def analytics_start_span(**kwargs):
|
|
|
141
148
|
return NopAnalytics()
|
|
142
149
|
|
|
143
150
|
|
|
144
|
-
def analytics_start_transaction(**kwargs):
|
|
151
|
+
def analytics_start_transaction(**kwargs: Any) -> Any:
|
|
145
152
|
"""Start an analytics/tracing transaction if analytics is enabled, otherwise return a no-op context manager."""
|
|
146
153
|
if analytics_allowed:
|
|
147
154
|
import sentry_sdk
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import faulthandler
|
|
2
2
|
import logging
|
|
3
3
|
import sys
|
|
4
|
+
import types
|
|
4
5
|
from importlib.metadata import version
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from sqlite3 import OperationalError
|
|
@@ -12,9 +13,9 @@ import typer
|
|
|
12
13
|
from astropy.io import fits
|
|
13
14
|
from rich.logging import RichHandler
|
|
14
15
|
from rich.progress import track
|
|
16
|
+
from toml_repo import Repo, RepoManager, get_config_suffix
|
|
15
17
|
|
|
16
18
|
import starbash
|
|
17
|
-
from repo import Repo, RepoManager, repo_suffix
|
|
18
19
|
from starbash.aliases import (
|
|
19
20
|
Aliases,
|
|
20
21
|
get_aliases,
|
|
@@ -44,7 +45,7 @@ from starbash.paths import get_user_config_dir, get_user_config_path
|
|
|
44
45
|
from starbash.score import ScoredCandidate, score_candidates
|
|
45
46
|
from starbash.selection import Selection, build_search_conditions
|
|
46
47
|
from starbash.toml import toml_from_template
|
|
47
|
-
from starbash.tool import
|
|
48
|
+
from starbash.tool import init_tools
|
|
48
49
|
from starbash.windows import windows_init
|
|
49
50
|
|
|
50
51
|
critical_keys = [Database.DATE_OBS_KEY, Database.IMAGETYP_KEY]
|
|
@@ -52,7 +53,7 @@ critical_keys = [Database.DATE_OBS_KEY, Database.IMAGETYP_KEY]
|
|
|
52
53
|
force_local_recipes = False # Set to True to always use local recipes for testing
|
|
53
54
|
|
|
54
55
|
|
|
55
|
-
def setup_logging(console: rich.console.Console):
|
|
56
|
+
def setup_logging(console: rich.console.Console) -> None:
|
|
56
57
|
"""
|
|
57
58
|
Configures basic logging.
|
|
58
59
|
"""
|
|
@@ -129,11 +130,13 @@ def remap_expected_errors(exc: BaseException | None) -> BaseException | None:
|
|
|
129
130
|
return None
|
|
130
131
|
|
|
131
132
|
# Some OSErrors definitely don't indicate a code level bug...
|
|
132
|
-
expected_errors = [ "Read-only file system" ]
|
|
133
|
+
expected_errors = [ "Read-only file system", "No space left on device" ]
|
|
134
|
+
# Update: I give up, keep seeing misc reports from field. I think all OSErrors should be considered
|
|
135
|
+
# 'not a bug' until proven otherwise.
|
|
133
136
|
|
|
134
137
|
if isinstance(exc, OperationalError):
|
|
135
138
|
return NonSoftwareError(f"[red]Database IO error:[/red] {exc}")
|
|
136
|
-
elif isinstance(exc,
|
|
139
|
+
elif isinstance(exc, OSError): # Was FileNotFoundError
|
|
137
140
|
return NonSoftwareError(f"[red]OS error:[/red] {exc}")
|
|
138
141
|
elif isinstance(exc, OSError):
|
|
139
142
|
exc_str = str(exc)
|
|
@@ -197,7 +200,8 @@ class Starbash:
|
|
|
197
200
|
|
|
198
201
|
# Initialize selection state (stored in user config repo)
|
|
199
202
|
self.selection = Selection(self.user_repo)
|
|
200
|
-
|
|
203
|
+
tool_prefs: dict[str, Any] = self.user_repo.get("tool", {})
|
|
204
|
+
init_tools(tool_prefs) # Preflight check all known tools to see if they are available
|
|
201
205
|
|
|
202
206
|
def _install_local_recipes(self) -> bool:
|
|
203
207
|
"""Use our local github submodule for recipes during development.
|
|
@@ -294,7 +298,7 @@ class Starbash:
|
|
|
294
298
|
def __enter__(self) -> "Starbash":
|
|
295
299
|
return self
|
|
296
300
|
|
|
297
|
-
def __exit__(self, exc_type, exc, tb) -> bool:
|
|
301
|
+
def __exit__(self, exc_type: type[BaseException] | None, exc: BaseException | None, tb: types.TracebackType | None) -> bool:
|
|
298
302
|
from starbash import _is_test_env
|
|
299
303
|
from starbash.exception import UserHandledError
|
|
300
304
|
|
|
@@ -376,7 +380,7 @@ class Starbash:
|
|
|
376
380
|
p = Path(path)
|
|
377
381
|
console = starbash.console
|
|
378
382
|
|
|
379
|
-
repo_toml = p /
|
|
383
|
+
repo_toml = p / get_config_suffix() # the starbash.toml file at the root of the repo
|
|
380
384
|
if repo_toml.exists():
|
|
381
385
|
logging.debug("Using existing repository config file: %s", repo_toml)
|
|
382
386
|
else:
|
|
@@ -384,7 +388,7 @@ class Starbash:
|
|
|
384
388
|
console.print(f"Creating {repo_type} repository: {p}")
|
|
385
389
|
toml_from_template(
|
|
386
390
|
f"repo/{repo_type}",
|
|
387
|
-
p /
|
|
391
|
+
p / get_config_suffix(),
|
|
388
392
|
overrides={
|
|
389
393
|
"REPO_TYPE": repo_type,
|
|
390
394
|
"REPO_PATH": str(p),
|
|
@@ -697,14 +701,16 @@ class Starbash:
|
|
|
697
701
|
|
|
698
702
|
# Convert absolute path to relative path within repo
|
|
699
703
|
relative_path = f.relative_to(path)
|
|
704
|
+
# Use POSIX-style forward slashes for consistency across platforms
|
|
705
|
+
relative_path_str = relative_path.as_posix()
|
|
700
706
|
|
|
701
|
-
found = self.db.get_image(repo.url,
|
|
707
|
+
found = self.db.get_image(repo.url, relative_path_str)
|
|
702
708
|
|
|
703
709
|
# for debugging sometimes we want to limit scanning to a single directory or file
|
|
704
710
|
# debug_target = "masters-raw/2025-09-09/DARK"
|
|
705
711
|
debug_target = None
|
|
706
712
|
if debug_target:
|
|
707
|
-
if
|
|
713
|
+
if relative_path_str.startswith(debug_target):
|
|
708
714
|
logging.error("Debugging %s...", f)
|
|
709
715
|
found = False
|
|
710
716
|
else:
|
|
@@ -730,8 +736,8 @@ class Starbash:
|
|
|
730
736
|
for key, value in extra_metadata.items():
|
|
731
737
|
headers.setdefault(key, value)
|
|
732
738
|
|
|
733
|
-
# Store relative path in database
|
|
734
|
-
headers["path"] =
|
|
739
|
+
# Store relative path in database (use POSIX-style forward slashes for consistency)
|
|
740
|
+
headers["path"] = relative_path_str
|
|
735
741
|
if self._extend_image_header(headers, f):
|
|
736
742
|
image_doc_id = self.db.upsert_image(headers, repo.url)
|
|
737
743
|
headers[Database.ID_KEY] = image_doc_id
|
|
@@ -753,7 +759,7 @@ class Starbash:
|
|
|
753
759
|
# (otherwise invariants will get messed up)
|
|
754
760
|
self._add_session(headers)
|
|
755
761
|
|
|
756
|
-
def reindex_repo(self, repo: Repo, subdir: str | None = None):
|
|
762
|
+
def reindex_repo(self, repo: Repo, subdir: str | None = None) -> None:
|
|
757
763
|
"""Reindex all repositories managed by the RepoManager."""
|
|
758
764
|
|
|
759
765
|
# make sure this new repo is listed in the repos table
|
|
@@ -770,20 +776,24 @@ class Starbash:
|
|
|
770
776
|
# used to debug
|
|
771
777
|
|
|
772
778
|
# Find all FITS files under this repo path
|
|
779
|
+
all_files = list(path.rglob("*.fit")) + list(path.rglob("*.fits"))
|
|
773
780
|
for f in track(
|
|
774
|
-
|
|
781
|
+
all_files,
|
|
775
782
|
description=f"Indexing {repo.url}...",
|
|
776
783
|
):
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
784
|
+
try:
|
|
785
|
+
# progress.console.print(f"Indexing {f}...")
|
|
786
|
+
if repo_kind == "master":
|
|
787
|
+
# for master repos we only add to the image table
|
|
788
|
+
self.add_image(repo, f, force=True)
|
|
789
|
+
elif repo_kind == "processed":
|
|
790
|
+
pass # we never add processed images to our db
|
|
791
|
+
else:
|
|
792
|
+
self.add_image_and_session(repo, f, force=starbash.force_regen)
|
|
793
|
+
except OSError as e:
|
|
794
|
+
logging.error(f'Skipping "{f}" due to: [red]{e}[/red]')
|
|
795
|
+
|
|
796
|
+
def reindex_repos(self) -> None:
|
|
787
797
|
"""Reindex all repositories managed by the RepoManager."""
|
|
788
798
|
logging.debug("Reindexing all repositories...")
|
|
789
799
|
|
|
@@ -11,7 +11,7 @@ __all__ = [
|
|
|
11
11
|
_is_connected: bool | None = None
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def is_connected(host="8.8.8.8", port=53, timeout=3) -> bool:
|
|
14
|
+
def is_connected(host: str = "8.8.8.8", port: int = 53, timeout: int = 3) -> bool:
|
|
15
15
|
"""
|
|
16
16
|
Host: 1.1.1.1 (Cloudflare DNS) or 8.8.8.8 (Google DNS) (it is important to not use domain names)
|
|
17
17
|
Port: 53/tcp
|
|
@@ -37,7 +37,7 @@ def is_connected(host="8.8.8.8", port=53, timeout=3) -> bool:
|
|
|
37
37
|
socket.setdefaulttimeout(old_timeout)
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def check_version():
|
|
40
|
+
def check_version() -> None:
|
|
41
41
|
"""Check if a newer version of starbash is available on PyPI."""
|
|
42
42
|
try:
|
|
43
43
|
if is_connected():
|
|
@@ -62,21 +62,21 @@ def dump_column(sb: Starbash, human_name: str, column_name: str) -> None:
|
|
|
62
62
|
|
|
63
63
|
|
|
64
64
|
@app.command()
|
|
65
|
-
def target():
|
|
65
|
+
def target() -> None:
|
|
66
66
|
"""List targets (filtered based on the current selection)."""
|
|
67
67
|
with Starbash("info.target") as sb:
|
|
68
68
|
dump_column(sb, "Target", Database.OBJECT_KEY)
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
@app.command()
|
|
72
|
-
def telescope():
|
|
72
|
+
def telescope() -> None:
|
|
73
73
|
"""List telescopes/instruments (filtered based on the current selection)."""
|
|
74
74
|
with Starbash("info.telescope") as sb:
|
|
75
75
|
dump_column(sb, "Telescope", Database.TELESCOP_KEY)
|
|
76
76
|
|
|
77
77
|
|
|
78
78
|
@app.command()
|
|
79
|
-
def filter():
|
|
79
|
+
def filter() -> None:
|
|
80
80
|
"""List all filters (filtered based on the current selection)."""
|
|
81
81
|
with Starbash("info.filter") as sb:
|
|
82
82
|
dump_column(sb, "Filter", Database.FILTER_KEY)
|
|
@@ -93,7 +93,7 @@ def master(
|
|
|
93
93
|
str | None,
|
|
94
94
|
kind_arg,
|
|
95
95
|
] = None,
|
|
96
|
-
):
|
|
96
|
+
) -> None:
|
|
97
97
|
"""List all precalculated master images (darks, biases, flats)."""
|
|
98
98
|
with Starbash("info.master") as sb:
|
|
99
99
|
from starbash import console
|
|
@@ -146,13 +146,13 @@ def masters(
|
|
|
146
146
|
str | None,
|
|
147
147
|
kind_arg,
|
|
148
148
|
] = None,
|
|
149
|
-
):
|
|
149
|
+
) -> None:
|
|
150
150
|
"""Alias for 'info master' command."""
|
|
151
151
|
master(kind)
|
|
152
152
|
|
|
153
153
|
|
|
154
154
|
@app.callback(invoke_without_command=True)
|
|
155
|
-
def main_callback(ctx: typer.Context):
|
|
155
|
+
def main_callback(ctx: typer.Context) -> None:
|
|
156
156
|
"""Show user preferences location and other app info.
|
|
157
157
|
|
|
158
158
|
This is the default command when no subcommand is specified.
|
|
@@ -39,7 +39,7 @@ def siril(
|
|
|
39
39
|
help="Automatically launch Siril GUI after generating directory tree",
|
|
40
40
|
),
|
|
41
41
|
] = False,
|
|
42
|
-
):
|
|
42
|
+
) -> None:
|
|
43
43
|
"""Generate Siril directory tree and optionally run Siril GUI.
|
|
44
44
|
|
|
45
45
|
Creates a properly structured directory tree for Siril processing with
|
|
@@ -64,7 +64,7 @@ def siril(
|
|
|
64
64
|
|
|
65
65
|
# Get images for this session
|
|
66
66
|
|
|
67
|
-
def session_to_dir(src_session: SessionRow, subdir_name: str):
|
|
67
|
+
def session_to_dir(src_session: SessionRow, subdir_name: str) -> None:
|
|
68
68
|
"""Copy the images from the specified session to the subdir"""
|
|
69
69
|
img_dir = output_dir / subdir_name
|
|
70
70
|
img_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -196,7 +196,7 @@ def auto(
|
|
|
196
196
|
help="Don't automatically generated master frames",
|
|
197
197
|
),
|
|
198
198
|
] = False,
|
|
199
|
-
):
|
|
199
|
+
) -> None:
|
|
200
200
|
"""Automatic processing with sensible defaults.
|
|
201
201
|
|
|
202
202
|
If session number is specified, processes only that session.
|
|
@@ -254,7 +254,7 @@ def auto(
|
|
|
254
254
|
)
|
|
255
255
|
def doit(
|
|
256
256
|
ctx: typer.Context,
|
|
257
|
-
):
|
|
257
|
+
) -> None:
|
|
258
258
|
"""(private) for developer debugging of the underlying 'doit' dependency system.
|
|
259
259
|
|
|
260
260
|
You probably don't need to use this - unless you are a starbash developer.
|
|
@@ -268,7 +268,7 @@ def doit(
|
|
|
268
268
|
|
|
269
269
|
|
|
270
270
|
@app.command()
|
|
271
|
-
def masters():
|
|
271
|
+
def masters() -> None:
|
|
272
272
|
"""Generate master flats, darks, and biases from selected raw frames.
|
|
273
273
|
|
|
274
274
|
Analyzes the current selection to find all available calibration frames
|
|
@@ -289,7 +289,7 @@ def masters():
|
|
|
289
289
|
|
|
290
290
|
|
|
291
291
|
@app.callback(invoke_without_command=True)
|
|
292
|
-
def main_callback(ctx: typer.Context):
|
|
292
|
+
def main_callback(ctx: typer.Context) -> None:
|
|
293
293
|
"""Process images using automated workflows.
|
|
294
294
|
|
|
295
295
|
These commands handle calibration, registration, stacking, and
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from collections.abc import Generator
|
|
2
3
|
from textwrap import dedent
|
|
3
4
|
from typing import Annotated
|
|
4
5
|
|
|
5
6
|
import typer
|
|
7
|
+
from toml_repo import Repo
|
|
6
8
|
|
|
7
9
|
import starbash
|
|
8
|
-
from repo import Repo
|
|
9
10
|
from starbash import console
|
|
10
11
|
from starbash.app import Starbash
|
|
11
12
|
from starbash.paths import get_user_documents_dir
|
|
@@ -13,7 +14,7 @@ from starbash.paths import get_user_documents_dir
|
|
|
13
14
|
app = typer.Typer(invoke_without_command=True)
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
def repo_enumeration(sb: Starbash):
|
|
17
|
+
def repo_enumeration(sb: Starbash) -> dict[int, Repo]:
|
|
17
18
|
"""return a dict of int (1 based) to Repo instances"""
|
|
18
19
|
verbose = False # assume not verbose for enum picking
|
|
19
20
|
repos = sb.repo_manager.repos if verbose else sb.repo_manager.regular_repos
|
|
@@ -21,7 +22,7 @@ def repo_enumeration(sb: Starbash):
|
|
|
21
22
|
return {i + 1: repo for i, repo in enumerate(repos)}
|
|
22
23
|
|
|
23
24
|
|
|
24
|
-
def complete_repo_by_num(incomplete: str):
|
|
25
|
+
def complete_repo_by_num(incomplete: str) -> Generator[tuple[str, str], None, None]:
|
|
25
26
|
# We need to use stderr_logging to prevent confusing the bash completion parser
|
|
26
27
|
starbash.log_filter_level = logging.ERROR # avoid showing output while doing completion
|
|
27
28
|
with Starbash("repo.complete.num", stderr_logging=True) as sb:
|
|
@@ -30,7 +31,7 @@ def complete_repo_by_num(incomplete: str):
|
|
|
30
31
|
yield (str(num), repo.url)
|
|
31
32
|
|
|
32
33
|
|
|
33
|
-
def complete_repo_by_url(incomplete: str):
|
|
34
|
+
def complete_repo_by_url(incomplete: str) -> Generator[tuple[str, str], None, None]:
|
|
34
35
|
# We need to use stderr_logging to prevent confusing the bash completion parser
|
|
35
36
|
starbash.log_filter_level = logging.ERROR # avoid showing output while doing completion
|
|
36
37
|
with Starbash("repo.complete.url", stderr_logging=True) as sb:
|
|
@@ -42,7 +43,7 @@ def complete_repo_by_url(incomplete: str):
|
|
|
42
43
|
|
|
43
44
|
|
|
44
45
|
@app.command()
|
|
45
|
-
def list():
|
|
46
|
+
def list() -> None:
|
|
46
47
|
"""
|
|
47
48
|
lists all repositories.
|
|
48
49
|
"""
|
|
@@ -64,7 +65,7 @@ def list():
|
|
|
64
65
|
@app.callback()
|
|
65
66
|
def main(
|
|
66
67
|
ctx: typer.Context,
|
|
67
|
-
):
|
|
68
|
+
) -> None:
|
|
68
69
|
"""
|
|
69
70
|
Manage repositories.
|
|
70
71
|
|
|
@@ -88,7 +89,7 @@ def add(
|
|
|
88
89
|
"--processed",
|
|
89
90
|
help="Mark this new repository for processed output files.",
|
|
90
91
|
),
|
|
91
|
-
):
|
|
92
|
+
) -> None:
|
|
92
93
|
"""
|
|
93
94
|
Add a repository. path is either a local path or a remote URL.
|
|
94
95
|
"""
|
|
@@ -155,7 +156,7 @@ def remove(
|
|
|
155
156
|
str,
|
|
156
157
|
typer.Argument(help="Repository number or URL", autocompletion=complete_repo_by_url),
|
|
157
158
|
],
|
|
158
|
-
):
|
|
159
|
+
) -> None:
|
|
159
160
|
"""
|
|
160
161
|
Remove a repository by number (from list).
|
|
161
162
|
Use 'starbash repo' to see the repository numbers.
|
|
@@ -182,7 +183,7 @@ def reindex(
|
|
|
182
183
|
autocompletion=complete_repo_by_url,
|
|
183
184
|
),
|
|
184
185
|
] = None,
|
|
185
|
-
):
|
|
186
|
+
) -> None:
|
|
186
187
|
"""
|
|
187
188
|
Reindex a repository by number.
|
|
188
189
|
If no number is given, reindex all repositories.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
from collections import Counter
|
|
5
|
+
from collections.abc import Generator
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import Annotated, Any
|
|
7
8
|
|
|
@@ -35,7 +36,7 @@ def get_column(sb: Starbash, column_name: str) -> Counter:
|
|
|
35
36
|
return all_counts
|
|
36
37
|
|
|
37
38
|
|
|
38
|
-
def complete_date(incomplete: str, column_name: str):
|
|
39
|
+
def complete_date(incomplete: str, column_name: str) -> Generator[tuple[str, str], None, None]:
|
|
39
40
|
"""calls get_column() and assumes the returned str->count object has iso datetime strings as the keys
|
|
40
41
|
it merges the counts for all dates that are on the same local timezone day.
|
|
41
42
|
in the returned str->count, just include the date portion (YYYY-MM-DD)."""
|
|
@@ -58,7 +59,7 @@ def complete_date(incomplete: str, column_name: str):
|
|
|
58
59
|
yield (date, f"{count} sessions")
|
|
59
60
|
|
|
60
61
|
|
|
61
|
-
def complete_column(incomplete: str, column_name: str):
|
|
62
|
+
def complete_column(incomplete: str, column_name: str) -> Generator[tuple[str, str], None, None]:
|
|
62
63
|
# We need to use stderr_logging to prevent confusing the bash completion parser
|
|
63
64
|
starbash.log_filter_level = logging.ERROR # avoid showing output while doing completion
|
|
64
65
|
with Starbash("repo.complete.column", stderr_logging=True) as sb:
|
|
@@ -70,7 +71,7 @@ def complete_column(incomplete: str, column_name: str):
|
|
|
70
71
|
|
|
71
72
|
|
|
72
73
|
@app.command(name="any")
|
|
73
|
-
def clear():
|
|
74
|
+
def clear() -> None:
|
|
74
75
|
"""Remove any filters on sessions, etc... (select everything)."""
|
|
75
76
|
with Starbash("selection.clear") as sb:
|
|
76
77
|
sb.selection.clear()
|
|
@@ -87,7 +88,7 @@ def target(
|
|
|
87
88
|
autocompletion=lambda incomplete: complete_column(incomplete, Database.OBJECT_KEY),
|
|
88
89
|
),
|
|
89
90
|
],
|
|
90
|
-
):
|
|
91
|
+
) -> None:
|
|
91
92
|
"""Limit the current selection to only the named target."""
|
|
92
93
|
with Starbash("selection.target") as sb:
|
|
93
94
|
# For now, replace existing targets with this one
|
|
@@ -107,7 +108,7 @@ def telescope(
|
|
|
107
108
|
autocompletion=lambda incomplete: complete_column(incomplete, Database.TELESCOP_KEY),
|
|
108
109
|
),
|
|
109
110
|
],
|
|
110
|
-
):
|
|
111
|
+
) -> None:
|
|
111
112
|
"""Limit the current selection to only the named telescope."""
|
|
112
113
|
with Starbash("selection.telescope") as sb:
|
|
113
114
|
# For now, replace existing telescopes with this one
|
|
@@ -118,7 +119,7 @@ def telescope(
|
|
|
118
119
|
do_list_sessions(sb, brief=not starbash.verbose_output)
|
|
119
120
|
|
|
120
121
|
|
|
121
|
-
def complete_name(incomplete: str, names: list[str]):
|
|
122
|
+
def complete_name(incomplete: str, names: list[str]) -> Generator[str, None, None]:
|
|
122
123
|
"""Return typer style autocompletion from a list of string constants."""
|
|
123
124
|
for name in names:
|
|
124
125
|
if name.startswith(incomplete):
|
|
@@ -150,7 +151,7 @@ def date(
|
|
|
150
151
|
autocompletion=lambda incomplete: complete_date(incomplete, Database.START_KEY),
|
|
151
152
|
),
|
|
152
153
|
] = None,
|
|
153
|
-
):
|
|
154
|
+
) -> None:
|
|
154
155
|
"""Limit to sessions in the specified date range.
|
|
155
156
|
|
|
156
157
|
Examples:
|
|
@@ -184,7 +185,7 @@ def date(
|
|
|
184
185
|
do_list_sessions(sb, brief=not starbash.verbose_output)
|
|
185
186
|
|
|
186
187
|
|
|
187
|
-
def do_list_sessions(sb: Starbash, brief: bool = False):
|
|
188
|
+
def do_list_sessions(sb: Starbash, brief: bool = False) -> None:
|
|
188
189
|
"""List sessions (filtered based on the current selection)"""
|
|
189
190
|
|
|
190
191
|
sessions = sb.search_session()
|
|
@@ -308,7 +309,7 @@ def list_sessions(
|
|
|
308
309
|
"--brief",
|
|
309
310
|
help="If there are many sessions, show only a few.",
|
|
310
311
|
),
|
|
311
|
-
):
|
|
312
|
+
) -> None:
|
|
312
313
|
"""List sessions (filtered based on the current selection)"""
|
|
313
314
|
|
|
314
315
|
with Starbash("selection.list") as sb:
|
|
@@ -351,7 +352,7 @@ def export(
|
|
|
351
352
|
str,
|
|
352
353
|
typer.Argument(help="Directory path to export to (if it doesn't exist it will be created)"),
|
|
353
354
|
],
|
|
354
|
-
):
|
|
355
|
+
) -> None:
|
|
355
356
|
"""Export the images for the indicated session number.
|
|
356
357
|
|
|
357
358
|
Uses symbolic links when possible, otherwise copies files.
|
|
@@ -377,7 +378,7 @@ def export(
|
|
|
377
378
|
|
|
378
379
|
|
|
379
380
|
@app.callback(invoke_without_command=True)
|
|
380
|
-
def show_selection(ctx: typer.Context):
|
|
381
|
+
def show_selection(ctx: typer.Context) -> None:
|
|
381
382
|
"""List information about the current selection.
|
|
382
383
|
|
|
383
384
|
This is the default command when no subcommand is specified.
|