starbash 0.2.3__tar.gz → 0.2.5__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 (65) hide show
  1. {starbash-0.2.3 → starbash-0.2.5}/PKG-INFO +4 -2
  2. {starbash-0.2.3 → starbash-0.2.5}/pyproject.toml +7 -7
  3. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/app.py +26 -17
  4. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/doit.py +4 -3
  5. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/dwarf3.py +7 -0
  6. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/templates/userconfig.toml +5 -0
  7. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/tool/__init__.py +6 -2
  8. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/tool/base.py +21 -0
  9. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/tool/siril.py +3 -3
  10. {starbash-0.2.3 → starbash-0.2.5}/LICENSE +0 -0
  11. {starbash-0.2.3 → starbash-0.2.5}/README.md +0 -0
  12. {starbash-0.2.3 → starbash-0.2.5}/src/repo/__init__.py +0 -0
  13. {starbash-0.2.3 → starbash-0.2.5}/src/repo/http_client.py +0 -0
  14. {starbash-0.2.3 → starbash-0.2.5}/src/repo/manager.py +0 -0
  15. {starbash-0.2.3 → starbash-0.2.5}/src/repo/repo.py +0 -0
  16. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/__init__.py +0 -0
  17. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/aliases.py +0 -0
  18. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/analytics.py +0 -0
  19. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/check_version.py +0 -0
  20. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/commands/__init__.py +0 -0
  21. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/commands/info.py +0 -0
  22. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/commands/process.py +0 -0
  23. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/commands/repo.py +0 -0
  24. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/commands/select.py +0 -0
  25. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/commands/user.py +0 -0
  26. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/database.py +0 -0
  27. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/defaults/__init__.py +0 -0
  28. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/defaults/starbash.toml +0 -0
  29. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/doit_types.py +0 -0
  30. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/exception.py +0 -0
  31. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/filtering.py +0 -0
  32. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/icon.py +0 -0
  33. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/linux.py +0 -0
  34. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/main.py +0 -0
  35. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/os.py +0 -0
  36. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/parameters.py +0 -0
  37. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/paths.py +0 -0
  38. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/processed_target.py +0 -0
  39. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/processing.py +0 -0
  40. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/processing_like.py +0 -0
  41. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/recipes/README.md +0 -0
  42. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/recipes/__init__.py +0 -0
  43. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/recipes/osc.py +0 -0
  44. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/rich.py +0 -0
  45. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/safety.py +0 -0
  46. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/score.py +0 -0
  47. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/selection.py +0 -0
  48. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/sim_siril/__init__.py +0 -0
  49. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/sim_siril/connection.py +0 -0
  50. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/sim_siril/enums.py +0 -0
  51. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/sim_siril/utility.py +0 -0
  52. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/stage_utils.py +0 -0
  53. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/stages.py +0 -0
  54. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/templates/__init__.py +0 -0
  55. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/templates/repo/master.toml +0 -0
  56. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/templates/repo/processed.toml +0 -0
  57. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/templates/target/master.toml +0 -0
  58. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/templates/target/processed.toml +0 -0
  59. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/toml.py +0 -0
  60. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/tool/context.py +0 -0
  61. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/tool/graxpert.py +0 -0
  62. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/tool/python.py +0 -0
  63. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/ui/main.py +0 -0
  64. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/url.py +0 -0
  65. {starbash-0.2.3 → starbash-0.2.5}/src/starbash/windows.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: starbash
3
- Version: 0.2.3
3
+ Version: 0.2.5
4
4
  Summary: A tool for automating/standardizing/sharing astrophotography workflows.
5
5
  License-File: LICENSE
6
6
  Author: Kevin Hester
@@ -12,9 +12,11 @@ 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
+ Requires-Dist: numpy (==2.2.6)
17
18
  Requires-Dist: platformdirs (>=4.5.0,<5.0.0)
19
+ Requires-Dist: pyqt6 (>=6.10.1,<7.0.0)
18
20
  Requires-Dist: requests-cache (>=1.2.1,<2.0.0)
19
21
  Requires-Dist: restrictedpython (>=8.1,<9.0)
20
22
  Requires-Dist: rich (>=14.2.0,<15.0.0)
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "starbash"
3
- version = "0.2.3"
3
+ version = "0.2.5"
4
4
  description = "A tool for automating/standardizing/sharing astrophotography workflows."
5
5
  authors = ["Kevin Hester <kevinh@geeksville.com>"]
6
6
  readme = "README.md"
@@ -29,12 +29,12 @@ textual = "^6.8.0"
29
29
 
30
30
  # Note: to use graxpert from the local tree rather than pypi use:
31
31
  # graxpert = {path = "GraXpert", extras = ["cpuonly"], develop = true}
32
- graxpert = {version = "^3.2.0a1", extras = ["cpuonly"]}
32
+ graxpert = {version = "^3.2.0a2", extras = ["cpuonly"]}
33
33
 
34
- # The following two libs are only needed for the experiment of running siril scripts directly...
34
+ # The following two libs are only needed for the (temporary) experiment of running siril scripts directly...
35
35
  # experimenting with siril-scripts/processing/VeraLux_HyperMetric_Stretch.py
36
- #numpy = "2.2.6"
37
- #pyqt6 = "^6.10.1"
36
+ numpy = "2.2.6"
37
+ pyqt6 = "^6.10.1"
38
38
 
39
39
  [tool.poetry.group.dev.dependencies]
40
40
  pytest = ">=8.4.2,<9.0.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
- # -rA shows summary of all test outcomes at end
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 -rA --ignore=GraXpert --ignore=textual --ignore=starbash-recipes"
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
@@ -44,7 +44,7 @@ from starbash.paths import get_user_config_dir, get_user_config_path
44
44
  from starbash.score import ScoredCandidate, score_candidates
45
45
  from starbash.selection import Selection, build_search_conditions
46
46
  from starbash.toml import toml_from_template
47
- from starbash.tool import preflight_tools
47
+ from starbash.tool import init_tools
48
48
  from starbash.windows import windows_init
49
49
 
50
50
  critical_keys = [Database.DATE_OBS_KEY, Database.IMAGETYP_KEY]
@@ -129,11 +129,13 @@ def remap_expected_errors(exc: BaseException | None) -> BaseException | None:
129
129
  return None
130
130
 
131
131
  # Some OSErrors definitely don't indicate a code level bug...
132
- expected_errors = [ "Read-only file system" ]
132
+ expected_errors = [ "Read-only file system", "No space left on device" ]
133
+ # Update: I give up, keep seeing misc reports from field. I think all OSErrors should be considered
134
+ # 'not a bug' until proven otherwise.
133
135
 
134
136
  if isinstance(exc, OperationalError):
135
137
  return NonSoftwareError(f"[red]Database IO error:[/red] {exc}")
136
- elif isinstance(exc, FileNotFoundError):
138
+ elif isinstance(exc, OSError): # Was FileNotFoundError
137
139
  return NonSoftwareError(f"[red]OS error:[/red] {exc}")
138
140
  elif isinstance(exc, OSError):
139
141
  exc_str = str(exc)
@@ -197,7 +199,8 @@ class Starbash:
197
199
 
198
200
  # Initialize selection state (stored in user config repo)
199
201
  self.selection = Selection(self.user_repo)
200
- preflight_tools()
202
+ tool_prefs: dict[str, Any] = self.user_repo.get("tool", {})
203
+ init_tools(tool_prefs) # Preflight check all known tools to see if they are available
201
204
 
202
205
  def _install_local_recipes(self) -> bool:
203
206
  """Use our local github submodule for recipes during development.
@@ -697,14 +700,16 @@ class Starbash:
697
700
 
698
701
  # Convert absolute path to relative path within repo
699
702
  relative_path = f.relative_to(path)
703
+ # Use POSIX-style forward slashes for consistency across platforms
704
+ relative_path_str = relative_path.as_posix()
700
705
 
701
- found = self.db.get_image(repo.url, str(relative_path))
706
+ found = self.db.get_image(repo.url, relative_path_str)
702
707
 
703
708
  # for debugging sometimes we want to limit scanning to a single directory or file
704
709
  # debug_target = "masters-raw/2025-09-09/DARK"
705
710
  debug_target = None
706
711
  if debug_target:
707
- if str(relative_path).startswith(debug_target):
712
+ if relative_path_str.startswith(debug_target):
708
713
  logging.error("Debugging %s...", f)
709
714
  found = False
710
715
  else:
@@ -730,8 +735,8 @@ class Starbash:
730
735
  for key, value in extra_metadata.items():
731
736
  headers.setdefault(key, value)
732
737
 
733
- # Store relative path in database
734
- headers["path"] = str(relative_path)
738
+ # Store relative path in database (use POSIX-style forward slashes for consistency)
739
+ headers["path"] = relative_path_str
735
740
  if self._extend_image_header(headers, f):
736
741
  image_doc_id = self.db.upsert_image(headers, repo.url)
737
742
  headers[Database.ID_KEY] = image_doc_id
@@ -770,18 +775,22 @@ class Starbash:
770
775
  # used to debug
771
776
 
772
777
  # Find all FITS files under this repo path
778
+ all_files = list(path.rglob("*.fit")) + list(path.rglob("*.fits"))
773
779
  for f in track(
774
- list(path.rglob("*.fit*")),
780
+ all_files,
775
781
  description=f"Indexing {repo.url}...",
776
782
  ):
777
- # progress.console.print(f"Indexing {f}...")
778
- if repo_kind == "master":
779
- # for master repos we only add to the image table
780
- self.add_image(repo, f, force=True)
781
- elif repo_kind == "processed":
782
- pass # we never add processed images to our db
783
- else:
784
- self.add_image_and_session(repo, f, force=starbash.force_regen)
783
+ try:
784
+ # progress.console.print(f"Indexing {f}...")
785
+ if repo_kind == "master":
786
+ # for master repos we only add to the image table
787
+ self.add_image(repo, f, force=True)
788
+ elif repo_kind == "processed":
789
+ pass # we never add processed images to our db
790
+ else:
791
+ self.add_image_and_session(repo, f, force=starbash.force_regen)
792
+ except OSError as e:
793
+ logging.error(f'Skipping file due to "{f}": {e}')
785
794
 
786
795
  def reindex_repos(self):
787
796
  """Reindex all repositories managed by the RepoManager."""
@@ -181,8 +181,9 @@ def merge_to(base_name: str, fi: FileInfo) -> None:
181
181
  # If it's a .seq file, find all FITS files with that prefix
182
182
  if path.suffix == ".seq":
183
183
  seq_prefix = path.stem
184
- pattern = str(base_dir / f"{seq_prefix}*.fit*")
185
- matching_files = sorted(glob.glob(pattern))
184
+ pattern1 = str(base_dir / f"{seq_prefix}*.fit")
185
+ pattern2 = str(base_dir / f"{seq_prefix}*.fits")
186
+ matching_files = sorted(glob.glob(pattern1) + glob.glob(pattern2))
186
187
  collected_files.extend([Path(f) for f in matching_files])
187
188
 
188
189
  # Create output directory and remove if it already exists
@@ -248,7 +249,7 @@ class ToolAction(BaseAction):
248
249
 
249
250
  logging.info(f"Running {self.tool.name} for {self.task.name} {desc}")
250
251
  try:
251
- with open(logfile_path, "a") as logfile:
252
+ with open(logfile_path, "a", encoding="utf-8") as logfile:
252
253
  self.result = self.tool.run(
253
254
  self.commands, context=context, cwd=self.cwd, log_out=logfile, **self.parameters
254
255
  )
@@ -10,6 +10,7 @@ from starbash.database import Database
10
10
 
11
11
  __all__ = [
12
12
  "extend_dwarf3_headers",
13
+ "_reset_monotonic_datetime",
13
14
  ]
14
15
 
15
16
 
@@ -49,6 +50,12 @@ def _make_monotonic_datetime() -> str:
49
50
  return current.strftime("%Y-%m-%dT%H:%M:%S.000")
50
51
 
51
52
 
53
+ def _reset_monotonic_datetime() -> None:
54
+ """Reset the monotonic datetime counter. Used for testing."""
55
+ if hasattr(_make_monotonic_datetime, "counter"):
56
+ _make_monotonic_datetime.counter = 0
57
+
58
+
52
59
  def extend_dwarf3_headers(headers: dict[str, Any], full_image_path: Path) -> bool:
53
60
  """Given a FITS header dictionary, if it was from a Dwarf3 extend it with additional computed fields.
54
61
 
@@ -6,6 +6,11 @@
6
6
  [repo]
7
7
  kind = "preferences"
8
8
 
9
+ [tool]
10
+ # Starbash normally finds tools automatically via your PATH. But if necessary you can define overrides here.
11
+ # siril.path = "siril"
12
+ # siril.path = "flatpak run --command=siril-cli org.siril.Siril" # To use the flatpak version of siril
13
+
9
14
  #[aliases]
10
15
  # aliases can be used to map non standard (or non english) frame names to standard terms
11
16
  # This is also used to map filters based on common misspellings or variations.
@@ -1,5 +1,7 @@
1
1
  """Tool management and execution for starbash processing stages."""
2
2
 
3
+ from typing import Any
4
+
3
5
  from starbash.tool.base import ExternalTool, MissingToolError, Tool, ToolError, tool_run
4
6
  from starbash.tool.context import (
5
7
  _SafeFormatter,
@@ -31,12 +33,14 @@ __all__ = [
31
33
  "PythonTool",
32
34
  "PythonScriptError",
33
35
  "tools",
34
- "preflight_tools",
36
+ "init_tools",
35
37
  ]
36
38
 
37
39
 
38
- def preflight_tools() -> None:
40
+ def init_tools(tool_prefs: dict[str, Any]) -> None:
39
41
  """Preflight check all known tools to see if they are available"""
42
+ Tool.Preferences = tool_prefs
43
+
40
44
  for tool in tools.values():
41
45
  if isinstance(tool, ExternalTool):
42
46
  tool.preflight()
@@ -26,6 +26,10 @@ __all__ = [
26
26
  "tool_run",
27
27
  ]
28
28
 
29
+ # If we want to ensure that child tools don't accidentally try to open GUI windows, we can set this flag.
30
+ # This is especially useful to ensure that the tools will work in a headless environment (such as) github CI runners.
31
+ force_no_gui = False
32
+
29
33
 
30
34
  class ToolError(UserHandledError):
31
35
  """Exception raised when a tool fails to execute properly."""
@@ -133,6 +137,13 @@ def tool_run(
133
137
 
134
138
  logger.debug(f"Running {cmd} in {cwd}: stdin={commands}")
135
139
 
140
+ # Remove DISPLAY from environment if force_no_gui is set to prevent GUI windows
141
+ env = os.environ.copy()
142
+ if force_no_gui and "DISPLAY" in os.environ:
143
+ #env.pop("DISPLAY", None)
144
+ #logger.debug("Removed DISPLAY from environment to prevent GUI windows")
145
+ pass
146
+
136
147
  # Start the process with pipes for streaming
137
148
  process = subprocess.Popen(
138
149
  cmd,
@@ -142,6 +153,7 @@ def tool_run(
142
153
  shell=True,
143
154
  text=True,
144
155
  cwd=cwd,
156
+ env=env,
145
157
  )
146
158
 
147
159
  # Wait for process to complete with timeout
@@ -198,6 +210,10 @@ def tool_run(
198
210
  class Tool:
199
211
  """A tool for stage execution"""
200
212
 
213
+ # A hierarchical dictionary of user preferences for this tool. Typical node path would be: "siril.path"
214
+ # Normally set by the app constructor based on user configuration toml.
215
+ Preferences: dict[str, Any] = {}
216
+
201
217
  # Tools and recursively invoke other tools. So it is important that if we've set a log file destination at the top
202
218
  # of our call tree, that variables get passed down to all sub-tools.
203
219
  _default_log_out: io.TextIOWrapper | None = None
@@ -332,6 +348,11 @@ class ExternalTool(Tool):
332
348
  def executable_path(self) -> str:
333
349
  """Find the correct executable path to run for the given tool"""
334
350
 
351
+ # Did the user manually specify a path
352
+ pref_path = Tool.Preferences.get(self.name.lower(), {}).get("path")
353
+ if pref_path:
354
+ return pref_path
355
+
335
356
  paths: list[None | str] = [None] # None means use system PATH
336
357
 
337
358
  if self.extra_dirs:
@@ -43,9 +43,9 @@ class SirilTool(ExternalTool):
43
43
  # siril_path = "/home/kevinh/packages/Siril-1.4.0~beta3-x86_64.AppImage"
44
44
  # Possible siril commands, with preferred option first
45
45
  commands: list[str] = [
46
- "siril-cli",
47
- "siril",
46
+ "siril-cli", # We prefer the top two options because they work even without a Gtk accessible GUI
48
47
  "org.siril.Siril",
48
+ "siril",
49
49
  "Siril",
50
50
  ]
51
51
 
@@ -66,7 +66,7 @@ class SirilTool(ExternalTool):
66
66
 
67
67
  siril_path = self.executable_path
68
68
  if siril_path == "org.siril.Siril":
69
- siril_path = "flatpak run org.siril.Siril"
69
+ siril_path = "flatpak run --command=siril-cli org.siril.Siril"
70
70
 
71
71
  link_or_copy_to_dir(input_files, temp_dir)
72
72
 
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