starbash 0.2.0__tar.gz → 0.2.4__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 (66) hide show
  1. {starbash-0.2.0 → starbash-0.2.4}/PKG-INFO +6 -4
  2. {starbash-0.2.0 → starbash-0.2.4}/README.md +3 -2
  3. {starbash-0.2.0 → starbash-0.2.4}/pyproject.toml +28 -4
  4. {starbash-0.2.0 → starbash-0.2.4}/src/repo/repo.py +6 -1
  5. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/__init__.py +1 -1
  6. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/analytics.py +3 -3
  7. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/app.py +36 -6
  8. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/commands/process.py +1 -1
  9. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/commands/user.py +2 -4
  10. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/doit.py +1 -2
  11. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/exception.py +11 -4
  12. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/paths.py +7 -2
  13. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/processed_target.py +4 -102
  14. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/processing.py +39 -90
  15. starbash-0.2.4/src/starbash/sim_siril/__init__.py +6 -0
  16. starbash-0.2.4/src/starbash/sim_siril/connection.py +79 -0
  17. starbash-0.2.4/src/starbash/sim_siril/enums.py +316 -0
  18. starbash-0.2.4/src/starbash/sim_siril/utility.py +32 -0
  19. starbash-0.2.4/src/starbash/stage_utils.py +45 -0
  20. starbash-0.2.4/src/starbash/stages.py +260 -0
  21. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/tool/context.py +74 -3
  22. starbash-0.2.4/src/starbash/tool/python.py +204 -0
  23. starbash-0.2.4/src/starbash/ui/main.py +92 -0
  24. starbash-0.2.0/src/starbash/tool/python.py +0 -84
  25. {starbash-0.2.0 → starbash-0.2.4}/LICENSE +0 -0
  26. {starbash-0.2.0 → starbash-0.2.4}/src/repo/__init__.py +0 -0
  27. {starbash-0.2.0 → starbash-0.2.4}/src/repo/http_client.py +0 -0
  28. {starbash-0.2.0 → starbash-0.2.4}/src/repo/manager.py +0 -0
  29. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/aliases.py +0 -0
  30. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/check_version.py +0 -0
  31. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/commands/__init__.py +0 -0
  32. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/commands/info.py +0 -0
  33. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/commands/repo.py +0 -0
  34. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/commands/select.py +0 -0
  35. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/database.py +0 -0
  36. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/defaults/__init__.py +0 -0
  37. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/defaults/starbash.toml +0 -0
  38. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/doit_types.py +0 -0
  39. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/dwarf3.py +0 -0
  40. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/filtering.py +0 -0
  41. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/icon.py +0 -0
  42. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/linux.py +0 -0
  43. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/main.py +0 -0
  44. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/os.py +0 -0
  45. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/parameters.py +0 -0
  46. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/processing_like.py +0 -0
  47. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/recipes/README.md +0 -0
  48. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/recipes/__init__.py +0 -0
  49. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/recipes/osc.py +0 -0
  50. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/rich.py +0 -0
  51. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/safety.py +0 -0
  52. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/score.py +0 -0
  53. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/selection.py +0 -0
  54. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/templates/__init__.py +0 -0
  55. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/templates/repo/master.toml +0 -0
  56. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/templates/repo/processed.toml +0 -0
  57. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/templates/target/master.toml +0 -0
  58. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/templates/target/processed.toml +0 -0
  59. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/templates/userconfig.toml +0 -0
  60. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/toml.py +0 -0
  61. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/tool/__init__.py +0 -0
  62. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/tool/base.py +0 -0
  63. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/tool/graxpert.py +0 -0
  64. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/tool/siril.py +0 -0
  65. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/url.py +0 -0
  66. {starbash-0.2.0 → starbash-0.2.4}/src/starbash/windows.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: starbash
3
- Version: 0.2.0
3
+ Version: 0.2.4
4
4
  Summary: A tool for automating/standardizing/sharing astrophotography workflows.
5
5
  License-File: LICENSE
6
6
  Author: Kevin Hester
@@ -12,13 +12,14 @@ Classifier: Programming Language :: Python :: 3.13
12
12
  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
- Requires-Dist: graxpert[cpuonly] (>=3.2.0a1,<4.0.0)
15
+ Requires-Dist: graxpert[cpuonly] (>=3.2.0a2,<4.0.0)
16
16
  Requires-Dist: multidict (>=6.7.0,<7.0.0)
17
17
  Requires-Dist: platformdirs (>=4.5.0,<5.0.0)
18
18
  Requires-Dist: requests-cache (>=1.2.1,<2.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
+ Requires-Dist: textual (>=6.8.0,<7.0.0)
22
23
  Requires-Dist: tomlkit (>=0.13.3,<0.14.0)
23
24
  Requires-Dist: typer (>=0.20.0,<0.21.0)
24
25
  Requires-Dist: update-checker (>=0.18.0,<0.19.0)
@@ -40,7 +41,7 @@ A tool for automating/standardizing/sharing astrophotography workflows.
40
41
  <img src="https://raw.githubusercontent.com/geeksville/starbash/refs/heads/main/doc/img/icon.jpg" alt="Starbash: Astrophotography workflows simplified" width="30%" align="right" style="margin-bottom: 20px;">
41
42
 
42
43
  * Automatic - with sensible defaults that you can change as needed. Just a few keystrokes to preprocess an entire repo of raw images.
43
- * Easy - provides a 'seestar-like' autoprocessing all your sessions (by default). You can optionally do manual postprocessing with all this 'grunt work' preprocessing.
44
+ * Easy - provides a 'seestar-like' autoprocessing all your sessions (by default). You can optionally do manual postprocessing with all this 'grunt work' preprocessing automated.
44
45
  * Fast<sup>1</sup> - even with large image repositories. Automatic master bias and flat generation. Automatic preprocessing/ stacking/background-elimination with reasonable defaults.
45
46
  * Multi-session - by default. So your workflows can stack from multiple nights (and still use the correct flats etc...).
46
47
  * Shareable - you can share/use recipes for image preprocessing flows. The eventual goal is a transition away from opaque burried scripts. Recipes can come from multiple repos and you or other orgs can host recipes.
@@ -85,7 +86,7 @@ If you are interested in alpha-testing we ❤️ you. This README should have e
85
86
  * Automatically performs **complete** preprocessing on OSC (broadband, narrowband, or dual Duo filter). i.e., gives you 'seestar-level' auto-preprocessing, so you only need to do the (optional) custom post-processing.
86
87
  * Uses Siril recipes for its pre-processing operations (support for Pixinsight-based recipes will probably be coming at some point...).
87
88
 
88
- ### From the alpha 2 (0.2.0) release (2025/12/12 ish)
89
+ ### From the alpha 2 (0.2.0) release (2025/12/12)
89
90
  * Include a stretched 'thumbnail'(FIXME/link/example/thumbnail) jpg proof-of-concept render in the output directories
90
91
  * Generates a per-target [report/config file](doc/toml/example/processed-repo/example-m20.toml) which can be customized if the detected defaults or preprocessing are not what you want.
91
92
  * '[Recipes](https://github.com/geeksville/starbash-recipes)' are now user-editable - provides repeatable/human-[readable](doc/toml/example/processed-repo/example-m20.toml)/shareable descriptions of all processing steps. [example Siril OSC stacking](https://github.com/geeksville/starbash-recipes/blob/6d255f48591c4991ddc1168ffa5c38050a500771/osc/osc_simple.toml), [example Graxpert BGE](https://github.com/geeksville/starbash-recipes/blob/6d255f48591c4991ddc1168ffa5c38050a500771/graxpert/background.toml), [example thumbnail generation](https://github.com/geeksville/starbash-recipes/blob/6d255f48591c4991ddc1168ffa5c38050a500771/common/thumbnail.toml)...
@@ -248,6 +249,7 @@ Starbash is a tool agnostic workflow manager. But it wouldn't be possible witho
248
249
  * [@codegistics](https://github.com/codegistics) for kindly donating Dwarf3 test data and invaluable debugging assistance.
249
250
  * The developers of Siril and Graxpert - which are wonderful tools.
250
251
  * The [doit](https://pydoit.org/) an **amazing** automation building tool, which substantially simiplified this tool's development.
252
+ * Any parts of the user interface that look good are probably due to the awesome [rich](https://github.com/Textualize/rich) library.
251
253
 
252
254
  ## Development
253
255
 
@@ -11,7 +11,7 @@ A tool for automating/standardizing/sharing astrophotography workflows.
11
11
  <img src="https://raw.githubusercontent.com/geeksville/starbash/refs/heads/main/doc/img/icon.jpg" alt="Starbash: Astrophotography workflows simplified" width="30%" align="right" style="margin-bottom: 20px;">
12
12
 
13
13
  * Automatic - with sensible defaults that you can change as needed. Just a few keystrokes to preprocess an entire repo of raw images.
14
- * Easy - provides a 'seestar-like' autoprocessing all your sessions (by default). You can optionally do manual postprocessing with all this 'grunt work' preprocessing.
14
+ * Easy - provides a 'seestar-like' autoprocessing all your sessions (by default). You can optionally do manual postprocessing with all this 'grunt work' preprocessing automated.
15
15
  * Fast<sup>1</sup> - even with large image repositories. Automatic master bias and flat generation. Automatic preprocessing/ stacking/background-elimination with reasonable defaults.
16
16
  * Multi-session - by default. So your workflows can stack from multiple nights (and still use the correct flats etc...).
17
17
  * Shareable - you can share/use recipes for image preprocessing flows. The eventual goal is a transition away from opaque burried scripts. Recipes can come from multiple repos and you or other orgs can host recipes.
@@ -56,7 +56,7 @@ If you are interested in alpha-testing we ❤️ you. This README should have e
56
56
  * Automatically performs **complete** preprocessing on OSC (broadband, narrowband, or dual Duo filter). i.e., gives you 'seestar-level' auto-preprocessing, so you only need to do the (optional) custom post-processing.
57
57
  * Uses Siril recipes for its pre-processing operations (support for Pixinsight-based recipes will probably be coming at some point...).
58
58
 
59
- ### From the alpha 2 (0.2.0) release (2025/12/12 ish)
59
+ ### From the alpha 2 (0.2.0) release (2025/12/12)
60
60
  * Include a stretched 'thumbnail'(FIXME/link/example/thumbnail) jpg proof-of-concept render in the output directories
61
61
  * Generates a per-target [report/config file](doc/toml/example/processed-repo/example-m20.toml) which can be customized if the detected defaults or preprocessing are not what you want.
62
62
  * '[Recipes](https://github.com/geeksville/starbash-recipes)' are now user-editable - provides repeatable/human-[readable](doc/toml/example/processed-repo/example-m20.toml)/shareable descriptions of all processing steps. [example Siril OSC stacking](https://github.com/geeksville/starbash-recipes/blob/6d255f48591c4991ddc1168ffa5c38050a500771/osc/osc_simple.toml), [example Graxpert BGE](https://github.com/geeksville/starbash-recipes/blob/6d255f48591c4991ddc1168ffa5c38050a500771/graxpert/background.toml), [example thumbnail generation](https://github.com/geeksville/starbash-recipes/blob/6d255f48591c4991ddc1168ffa5c38050a500771/common/thumbnail.toml)...
@@ -219,6 +219,7 @@ Starbash is a tool agnostic workflow manager. But it wouldn't be possible witho
219
219
  * [@codegistics](https://github.com/codegistics) for kindly donating Dwarf3 test data and invaluable debugging assistance.
220
220
  * The developers of Siril and Graxpert - which are wonderful tools.
221
221
  * The [doit](https://pydoit.org/) an **amazing** automation building tool, which substantially simiplified this tool's development.
222
+ * Any parts of the user interface that look good are probably due to the awesome [rich](https://github.com/Textualize/rich) library.
222
223
 
223
224
  ## Development
224
225
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "starbash"
3
- version = "0.2.0"
3
+ version = "0.2.4"
4
4
  description = "A tool for automating/standardizing/sharing astrophotography workflows."
5
5
  authors = ["Kevin Hester <kevinh@geeksville.com>"]
6
6
  readme = "README.md"
@@ -25,10 +25,16 @@ sentry-sdk = "^2.42.1"
25
25
  update-checker = "^0.18.0"
26
26
  requests-cache = "^1.2.1"
27
27
  doit = "^0.36.0"
28
+ textual = "^6.8.0"
28
29
 
29
30
  # Note: to use graxpert from the local tree rather than pypi use:
30
31
  # graxpert = {path = "GraXpert", extras = ["cpuonly"], develop = true}
31
- graxpert = {version = "^3.2.0a1", extras = ["cpuonly"]}
32
+ graxpert = {version = "^3.2.0a2", extras = ["cpuonly"]}
33
+
34
+ # The following two libs are only needed for the experiment of running siril scripts directly...
35
+ # experimenting with siril-scripts/processing/VeraLux_HyperMetric_Stretch.py
36
+ #numpy = "2.2.6"
37
+ #pyqt6 = "^6.10.1"
32
38
 
33
39
  [tool.poetry.group.dev.dependencies]
34
40
  pytest = ">=8.4.2,<9.0.0"
@@ -37,6 +43,7 @@ pytest-xdist = "^3.8.0"
37
43
  pre-commit = "^4.3.0"
38
44
  ruff = "^0.14.4"
39
45
  basedpyright = "^1.33.0"
46
+ textual-dev = "^1.8.0"
40
47
 
41
48
  # We don't currently use this text based sql client
42
49
  # harlequin = "^2.4.1"
@@ -56,7 +63,7 @@ markers = [
56
63
  # --tb=short shows shorter tracebacks
57
64
  # -rA shows summary of all test outcomes at end
58
65
  # --ignore excludes third-party test directories
59
- addopts = "-m 'not slow and not integration' -n auto --tb=short -rA --ignore=GraXpert"
66
+ addopts = "-m 'not slow and not integration' -n auto --tb=short -rA --ignore=GraXpert --ignore=textual --ignore=starbash-recipes"
60
67
 
61
68
  # Note: To limit captured output further, you can:
62
69
  # 1. Use --tb=line for minimal tracebacks
@@ -88,7 +95,24 @@ line-length = 100
88
95
  target-version = "py312"
89
96
 
90
97
  # Exclude a variety of commonly ignored directories
91
- exclude = [".git", ".venv", "__pycache__", "build", "dist"]
98
+ exclude = [".git", ".venv", "__pycache__", "build", "dist", "reference", "siril-scripts"]
99
+
100
+ [tool.ruff.format]
101
+ # Only format files in src/ and tests/ - exclude everything else
102
+ exclude = [
103
+ "doc/**",
104
+ "examples/**",
105
+ "siril-scripts/**",
106
+ "htmlcov/**",
107
+ "images/**",
108
+ "reference/**",
109
+ "starbash-recipes/**",
110
+ "test-data/**",
111
+ "GraXpert/**",
112
+ "textual/**",
113
+ "bin/**",
114
+ "*.py" # Exclude root-level Python files
115
+ ]
92
116
 
93
117
  [tool.ruff.lint]
94
118
  # Enable these rule sets
@@ -505,7 +505,12 @@ class Repo:
505
505
  """
506
506
  # Construct the full URL by joining the base URL with the filepath
507
507
  if filepath:
508
- url = self.url.rstrip("/") + "/" + filepath.lstrip("/")
508
+ # If the URL points to a .toml file, strip the filename to get the directory
509
+ base_url = self.url
510
+ if self._is_direct_toml_file():
511
+ # Strip the .toml filename to get the parent directory URL
512
+ base_url = base_url.rsplit("/", 1)[0]
513
+ url = base_url.rstrip("/") + "/" + filepath.lstrip("/")
509
514
  else:
510
515
  url = self.url
511
516
 
@@ -7,7 +7,7 @@ from rich.console import Console
7
7
 
8
8
  # Common type aliases for clarity
9
9
  type StageDict = dict[str, Any] # a processing stage definition from our toml
10
- type InputDef = dict[str, Any] # an input definition within a stage
10
+ type InputDef = dict[Any, Any] # an input definition within a stage
11
11
  type OutputDef = dict[str, Any] # an output definition within a stage
12
12
  type RequireDef = dict[str, Any] # a requires definition within an input
13
13
  type Metadata = dict[str, Any] # image metadata dictionary
@@ -47,9 +47,9 @@ def analytics_setup(allowed: bool = False, user_email: str | None = None) -> Non
47
47
  ], # This line removes the aggressive unhandled exception catcher
48
48
  integrations=[
49
49
  LoggingIntegration(
50
- level=starbash.log_filter_level, # Capture INFO and above as breadcrumbs
50
+ level=starbash.log_filter_level, # Capture INFO and above as breadcrumbs (used for exception reports)
51
51
  event_level=None, # Don't automatically convert error messages to sentry events
52
- sentry_logs_level=starbash.log_filter_level, # Capture INFO and above as logs
52
+ sentry_logs_level=logging.INFO, # Capture INFO and above as logs (general usage)
53
53
  ),
54
54
  ],
55
55
  )
@@ -85,7 +85,7 @@ def is_development_environment() -> bool:
85
85
  return False
86
86
 
87
87
 
88
- def analytics_exception(exc: Exception) -> bool:
88
+ def analytics_exception(exc: BaseException) -> bool:
89
89
  """Report an exception to the analytics service, if enabled.
90
90
  return True to suppress exception propagation/log messages"""
91
91
 
@@ -3,6 +3,7 @@ import logging
3
3
  import sys
4
4
  from importlib.metadata import version
5
5
  from pathlib import Path
6
+ from sqlite3 import OperationalError
6
7
  from string import Template
7
8
  from typing import Any
8
9
 
@@ -36,7 +37,7 @@ from starbash.database import (
36
37
  get_column_name,
37
38
  )
38
39
  from starbash.dwarf3 import extend_dwarf3_headers
39
- from starbash.exception import UserHandledError, raise_missing_repo
40
+ from starbash.exception import NonSoftwareError, UserHandledError, raise_missing_repo
40
41
  from starbash.linux import linux_init
41
42
  from starbash.os import symlink_or_copy
42
43
  from starbash.paths import get_user_config_dir, get_user_config_path
@@ -121,6 +122,28 @@ def copy_images_to_dir(images: list[ImageRow], output_dir: Path) -> None:
121
122
  console.print(f" [red]Errors: {error_count} files[/red]")
122
123
 
123
124
 
125
+ def remap_expected_errors(exc: BaseException | None) -> BaseException | None:
126
+ """Remap certain expected exceptions to UserHandledError for consistent handling."""
127
+
128
+ if exc is None:
129
+ return None
130
+
131
+ # Some OSErrors definitely don't indicate a code level bug...
132
+ expected_errors = [ "Read-only file system" ]
133
+
134
+ if isinstance(exc, OperationalError):
135
+ return NonSoftwareError(f"[red]Database IO error:[/red] {exc}")
136
+ elif isinstance(exc, FileNotFoundError):
137
+ return NonSoftwareError(f"[red]OS error:[/red] {exc}")
138
+ elif isinstance(exc, OSError):
139
+ exc_str = str(exc)
140
+ if any(err in exc_str for err in expected_errors):
141
+ return NonSoftwareError(f"[red]OS error:[/red] {exc}")
142
+ # Add more remappings as needed
143
+
144
+ return exc
145
+
146
+
124
147
  class Starbash:
125
148
  """The main Starbash application class."""
126
149
 
@@ -161,7 +184,8 @@ class Starbash:
161
184
  self._init_repos()
162
185
  self._init_analytics(cmd) # after init repos so we have user prefs
163
186
 
164
- logging.info("Starbash starting")
187
+ app_version = version("starbash")
188
+ logging.info(f"🚀 Starbash {app_version} starting!")
165
189
 
166
190
  check_version()
167
191
  self._init_aliases()
@@ -274,12 +298,18 @@ class Starbash:
274
298
  from starbash import _is_test_env
275
299
  from starbash.exception import UserHandledError
276
300
 
301
+ exc = remap_expected_errors(exc)
302
+
277
303
  handled = False
278
304
  # Don't suppress typer.Exit - it's used for controlled exit codes
279
305
  if exc and not isinstance(exc, typer.Exit) and not isinstance(exc, KeyboardInterrupt):
280
- # For UserHandledError, call ask_user_handled() and don't suppress
281
- if isinstance(exc, UserHandledError):
282
- exc.ask_user_handled()
306
+ # For errors we expect, just print error message and exit cleanly
307
+ if isinstance(exc, NonSoftwareError):
308
+ # For UserHandledError, call ask_user_handled() and don't suppress
309
+ if isinstance(exc, UserHandledError):
310
+ exc.ask_user_handled()
311
+ else:
312
+ starbash.console.print(exc)
283
313
  self.close()
284
314
  # Raise typer.Exit to ensure proper exit code
285
315
  raise typer.Exit(code=1)
@@ -288,7 +318,7 @@ class Starbash:
288
318
  self.close()
289
319
  if not handled:
290
320
  # Show the full exception for developers
291
- starbash.console.print_exception(show_locals=True)
321
+ starbash.console.print_exception(show_locals=False) # Locals are too verbose
292
322
 
293
323
  # In test environments, let exceptions propagate naturally for better test diagnostics
294
324
  if not _is_test_env:
@@ -229,7 +229,7 @@ def auto(
229
229
 
230
230
  if session_num is not None:
231
231
  console.print(
232
- f"[read]Session number base filtering not yet implemented: {session_num}...[/red]"
232
+ f"[red]Session number base filtering not yet implemented: {session_num}...[/red]"
233
233
  )
234
234
  else:
235
235
  console.print("[yellow]Auto-processing all selected sessions...[/yellow]")
@@ -178,11 +178,9 @@ def do_reinit(sb: Starbash) -> None:
178
178
  Recommended next steps (to get your first auto-generated images):
179
179
  1. Add your source raw image repositories (starbash will only READ from these):
180
180
  [cyan]sb repo add /path/to/your/raw_images[/cyan]
181
- 2. Ask starbash to auto-generate 'master' darks, biases and flats:
182
- [cyan]sb process masters[/cyan]
183
- 3. Process your images using automated workflows:
181
+ 2. Process your images using automated workflows:
184
182
  [cyan]sb process auto[/cyan]
185
- 4. (Highly recommended) Tell your shell to auto-complete starbash commands:
183
+ 3. (Highly recommended) Tell your shell to auto-complete starbash commands:
186
184
  [cyan]sb shell-complete --install-completion[/cyan]
187
185
 
188
186
  This project is currently very 'alpha' but we are eager to have it work for you.
@@ -252,11 +252,10 @@ class ToolAction(BaseAction):
252
252
  self.result = self.tool.run(
253
253
  self.commands, context=context, cwd=self.cwd, log_out=logfile, **self.parameters
254
254
  )
255
- except ValueError as e:
255
+ except Exception as e:
256
256
  # We pass back any exceptions in task.meta - so that our ConsoleReporter can pick them up (doit normally strips exceptions)
257
257
  self.task.meta["exception"] = e
258
258
  return TaskFailed("tool failed")
259
- # raise e # Let doit do its normal exception handling though
260
259
 
261
260
  self.values = {} # doit requires this attribute to be set
262
261
 
@@ -1,7 +1,17 @@
1
1
  from typing import Any, NoReturn
2
2
 
3
3
 
4
- class UserHandledError(ValueError):
4
+ class NonSoftwareError(Exception):
5
+ """An error outside the control of the software, exit the app with an error code, but no need to
6
+ report it as a software bug.
7
+
8
+ Used for OS errors etc after we've determined we can't do anything more useful."""
9
+
10
+ def __rich__(self) -> Any:
11
+ return self.__str__() # At least this is something readable...
12
+
13
+
14
+ class UserHandledError(NonSoftwareError):
5
15
  """An exception that terminates processing of the current file, but we want to help the user fix the problem."""
6
16
 
7
17
  def ask_user_handled(self) -> bool:
@@ -14,9 +24,6 @@ class UserHandledError(ValueError):
14
24
  console.print(f"Error: {self}")
15
25
  return False
16
26
 
17
- def __rich__(self) -> Any:
18
- return self.__str__() # At least this is something readable...
19
-
20
27
 
21
28
  def raise_missing_repo(kind: str) -> NoReturn:
22
29
  """Raise a UserHandledError indicating that a repository of the given kind is missing."""
@@ -64,8 +64,13 @@ def get_user_data_dir() -> Path:
64
64
 
65
65
 
66
66
  def get_user_cache_dir() -> Path:
67
- """Get the user cache directory. Returns test override if set, otherwise the real user directory."""
68
- dir_to_use = _override_cache_dir if _override_cache_dir is not None else cache_dir
67
+ """Get the user cache directory. Returns test override if set, otherwise checks STARBASH_CACHE_DIR env var, otherwise the real user directory."""
68
+ if _override_cache_dir is not None:
69
+ dir_to_use = _override_cache_dir
70
+ elif env_cache_dir := os.getenv("STARBASH_CACHE_DIR"):
71
+ dir_to_use = Path(env_cache_dir)
72
+ else:
73
+ dir_to_use = cache_dir
69
74
  os.makedirs(dir_to_use, exist_ok=True)
70
75
  return dir_to_use
71
76
 
@@ -10,117 +10,17 @@ import tomlkit
10
10
 
11
11
  from repo import Repo, repo_suffix
12
12
  from starbash import StageDict, to_shortdate
13
- from starbash.database import SessionRow
14
- from starbash.doit_types import TaskDict, cleanup_old_contexts, get_processing_dir
13
+ from starbash.doit_types import cleanup_old_contexts, get_processing_dir
15
14
  from starbash.parameters import ParameterStore
16
15
  from starbash.processing_like import ProcessingLike
17
16
  from starbash.safety import get_safe
18
- from starbash.toml import CommentedString, toml_from_list, toml_from_template
17
+ from starbash.toml import toml_from_template
19
18
 
20
19
  __all__ = [
21
20
  "ProcessedTarget",
22
21
  ]
23
22
 
24
23
 
25
- def stage_with_comment(stage: StageDict) -> CommentedString:
26
- """Create a CommentedString for the given stage."""
27
- name = stage.get("name", "unnamed_stage")
28
- description = stage.get("description", None)
29
- return CommentedString(value=name, comment=description)
30
-
31
-
32
- def set_used(self: dict, used_stages: list[StageDict]) -> None:
33
- """Set the used lists for the given section."""
34
- name = "stages"
35
- used = [stage_with_comment(s) for s in used_stages]
36
- node = self.setdefault(name, {})
37
- node["used"] = toml_from_list(used)
38
-
39
-
40
- def set_excluded(self: dict, stages_to_exclude: list[StageDict]) -> None:
41
- """Set the excluded lists for the given section."""
42
- name = "stages"
43
- excluded = [stage_with_comment(s) for s in stages_to_exclude]
44
-
45
- node = self.setdefault(name, {})
46
- node["excluded"] = toml_from_list(excluded)
47
-
48
-
49
- def get_from_toml(self: dict, key_name: str) -> list[str]:
50
- """Any consumers of this function probably just want the raw string (key_name is usually excluded or used)"""
51
- dict_name = "stages"
52
- node = self.setdefault(dict_name, {})
53
- excluded: list[CommentedString] = node.get(key_name, [])
54
- return [a.value for a in excluded]
55
-
56
-
57
- def task_to_stage(task: TaskDict) -> StageDict:
58
- """Extract the stage from the given task's context."""
59
- return task["meta"]["stage"]
60
-
61
-
62
- def task_to_session(task: TaskDict) -> SessionRow | None:
63
- """Extract the session from the given task's context."""
64
- context = task["meta"]["context"]
65
- session = context.get("session")
66
- return session
67
-
68
-
69
- def tasks_to_stages(tasks: list[TaskDict]) -> list[StageDict]:
70
- """Extract unique stages from the given list of tasks, sorted by priority."""
71
- stage_dict: dict[str, StageDict] = {}
72
- for task in tasks:
73
- stage = task["meta"]["stage"]
74
- stage_dict[stage["name"]] = stage
75
-
76
- # Sort stages by priority (if priority not present assume 0), higher priority first
77
- stages = sorted(stage_dict.values(), key=lambda s: s.get("priority", 0), reverse=True)
78
- logging.debug(f"Stages in priority order: {[s.get('name') for s in stages]}")
79
- return stages
80
-
81
-
82
- def set_used_stages_from_tasks(tasks: list[dict]) -> None:
83
- """Given a list of tasks, set the used stages in each session touched by those tasks."""
84
-
85
- # Inside each session we touched, collect a list of used stages (initially as a list of strings but then in the final)
86
- # cleanup converted into toml lists with set_used.
87
- # We rely on the fact that a single session row instance is shared between all tasks for that session.
88
-
89
- if not tasks:
90
- return
91
-
92
- typ_task = tasks[0]
93
- pt: ProcessedTarget | None = typ_task["meta"]["processed_target"]
94
- assert pt, "ProcessedTarget must be set in Processing for sessionless tasks"
95
-
96
- # step 1: clear our temp lists
97
- default_stages: list[StageDict] = []
98
- for task in tasks:
99
- session = task_to_session(task)
100
- if session:
101
- session["_temp_used_stages"] = []
102
-
103
- # step 2: collect used stages
104
- for task in tasks:
105
- stage = task_to_stage(task)
106
- session = task_to_session(task)
107
- used = session["_temp_used_stages"] if session else default_stages
108
- if stage not in used:
109
- used.append(stage)
110
-
111
- # step 3: commit used stages to toml (and remove temp lists)
112
- for task in tasks:
113
- session = task_to_session(task)
114
- if session:
115
- used_stages: list[StageDict] = session.pop("_temp_used_stages", [])
116
- if used_stages:
117
- set_used(session, used_stages)
118
-
119
- # Commit our default used stages too
120
- if default_stages:
121
- set_used(pt.default_stages, default_stages)
122
-
123
-
124
24
  class ProcessedTarget:
125
25
  """The repo file based config for a single processed target.
126
26
 
@@ -223,6 +123,8 @@ class ProcessedTarget:
223
123
 
224
124
  def _set_default_stages(self) -> None:
225
125
  """If we have newly discovered stages which should be excluded by default, add them now."""
126
+ from starbash.stage_utils import get_from_toml, set_excluded
127
+
226
128
  excluded = get_from_toml(self.default_stages, "excluded")
227
129
  used: list[str] = get_from_toml(self.default_stages, "used")
228
130