starbash 0.1.4__tar.gz → 0.1.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.

Potentially problematic release.


This version of starbash might be problematic. Click here for more details.

Files changed (33) hide show
  1. {starbash-0.1.4 → starbash-0.1.5}/PKG-INFO +1 -1
  2. {starbash-0.1.4 → starbash-0.1.5}/pyproject.toml +1 -1
  3. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/analytics.py +1 -1
  4. starbash-0.1.5/src/starbash/commands/__init__.py +15 -0
  5. starbash-0.1.5/src/starbash/commands/info.py +92 -0
  6. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/commands/select.py +2 -15
  7. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/database.py +47 -35
  8. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/main.py +2 -1
  9. starbash-0.1.4/src/starbash/templates/__init__.py +0 -0
  10. {starbash-0.1.4 → starbash-0.1.5}/LICENSE +0 -0
  11. {starbash-0.1.4 → starbash-0.1.5}/README.md +0 -0
  12. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/__init__.py +0 -0
  13. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/app.py +0 -0
  14. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/commands/repo.py +0 -0
  15. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/commands/user.py +0 -0
  16. {starbash-0.1.4/src/starbash/commands → starbash-0.1.5/src/starbash/defaults}/__init__.py +0 -0
  17. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/defaults/starbash.toml +0 -0
  18. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/paths.py +0 -0
  19. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/recipes/README.md +0 -0
  20. {starbash-0.1.4/src/starbash/defaults → starbash-0.1.5/src/starbash/recipes}/__init__.py +0 -0
  21. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/recipes/master_bias/starbash.toml +0 -0
  22. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/recipes/master_flat/starbash.toml +0 -0
  23. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/recipes/osc_dual_duo/starbash.py +0 -0
  24. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/recipes/osc_dual_duo/starbash.toml +0 -0
  25. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/recipes/osc_single_duo/starbash.toml +0 -0
  26. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/recipes/starbash.toml +0 -0
  27. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/repo/__init__.py +0 -0
  28. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/repo/manager.py +0 -0
  29. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/selection.py +0 -0
  30. {starbash-0.1.4/src/starbash/recipes → starbash-0.1.5/src/starbash/templates}/__init__.py +0 -0
  31. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/templates/userconfig.toml +0 -0
  32. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/tool.py +0 -0
  33. {starbash-0.1.4 → starbash-0.1.5}/src/starbash/url.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: starbash
3
- Version: 0.1.4
3
+ Version: 0.1.5
4
4
  Summary: A tool for automating/standardizing/sharing astrophotography workflows.
5
5
  License-File: LICENSE
6
6
  Author: Kevin Hester
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "starbash"
3
- version = "0.1.4"
3
+ version = "0.1.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"
@@ -60,7 +60,7 @@ def is_development_environment() -> bool:
60
60
  """Detect if running in a development environment."""
61
61
 
62
62
  # Check for explicit environment variable
63
- if os.getenv("STARBASH_ENV") == "development":
63
+ if os.getenv("SENTRY_ENVIRONMENT") == "development":
64
64
  return True
65
65
 
66
66
  # Check if running under VS Code
@@ -0,0 +1,15 @@
1
+ """Shared utilities for starbash commands."""
2
+
3
+
4
+ def format_duration(seconds: int | float) -> str:
5
+ """Format seconds as a human-readable duration string."""
6
+ if seconds < 60:
7
+ return f"{int(seconds)}s"
8
+ elif seconds < 120:
9
+ minutes = int(seconds // 60)
10
+ secs = int(seconds % 60)
11
+ return f"{minutes}m {secs}s" if secs else f"{minutes}m"
12
+ else:
13
+ hours = int(seconds // 3600)
14
+ minutes = int((seconds % 3600) // 60)
15
+ return f"{hours}h {minutes}m" if minutes else f"{hours}h"
@@ -0,0 +1,92 @@
1
+ """Info commands for displaying system and data information."""
2
+
3
+ import typer
4
+ from typing_extensions import Annotated
5
+
6
+ from starbash.app import Starbash
7
+ from starbash import console
8
+ from starbash.database import Database
9
+ from starbash.paths import get_user_config_dir, get_user_data_dir
10
+ from starbash.commands import format_duration
11
+
12
+ app = typer.Typer()
13
+
14
+
15
+ @app.command()
16
+ def target():
17
+ """List targets (filtered based on the current selection)."""
18
+ with Starbash("info.target") as sb:
19
+ console.print("[yellow]Not yet implemented[/yellow]")
20
+ console.print(
21
+ "This command will list all unique targets in the current selection."
22
+ )
23
+
24
+
25
+ @app.command()
26
+ def telescope():
27
+ """List telescopes/instruments (filtered based on the current selection)."""
28
+ with Starbash("info.telescope") as sb:
29
+ console.print("[yellow]Not yet implemented[/yellow]")
30
+ console.print(
31
+ "This command will list all unique telescopes in the current selection."
32
+ )
33
+
34
+
35
+ @app.command()
36
+ def filter():
37
+ """List all filters found in current selection."""
38
+ with Starbash("info.filter") as sb:
39
+ console.print("[yellow]Not yet implemented[/yellow]")
40
+ console.print(
41
+ "This command will list all unique filters in the current selection."
42
+ )
43
+
44
+
45
+ @app.callback(invoke_without_command=True)
46
+ def main_callback(ctx: typer.Context):
47
+ """Show user preferences location and other app info.
48
+
49
+ This is the default command when no subcommand is specified.
50
+ """
51
+ if ctx.invoked_subcommand is None:
52
+ with Starbash("info") as sb:
53
+ from rich.table import Table
54
+
55
+ table = Table(title="Starbash Information")
56
+ table.add_column("Setting", style="cyan", no_wrap=True)
57
+ table.add_column("Value", style="green")
58
+
59
+ # Show config and data directories
60
+ table.add_row("Config Directory", str(get_user_config_dir()))
61
+ table.add_row("Data Directory", str(get_user_data_dir()))
62
+
63
+ # Show user preferences if set
64
+ user_name = sb.user_repo.get("user.name")
65
+ if user_name:
66
+ table.add_row("User Name", str(user_name))
67
+
68
+ user_email = sb.user_repo.get("user.email")
69
+ if user_email:
70
+ table.add_row("User Email", str(user_email))
71
+
72
+ # Show analytics setting
73
+ analytics_enabled = sb.user_repo.get("analytics.enabled", True)
74
+ table.add_row("Analytics", "Enabled" if analytics_enabled else "Disabled")
75
+
76
+ # Show number of repos
77
+ table.add_row("Total Repositories", str(len(sb.repo_manager.repos)))
78
+ table.add_row("User Repositories", str(len(sb.repo_manager.regular_repos)))
79
+
80
+ # Show database stats
81
+ table.add_row(
82
+ "Sessions Indexed", str(sb.db.len_table(Database.SESSIONS_TABLE))
83
+ )
84
+
85
+ table.add_row("Images Indexed", str(sb.db.len_table(Database.IMAGES_TABLE)))
86
+
87
+ total_exptime = sb.db.sum_column(Database.SESSIONS_TABLE, "exptime_total")
88
+ table.add_row(
89
+ "Total image time",
90
+ format_duration(total_exptime),
91
+ )
92
+ console.print(table)
@@ -10,6 +10,7 @@ from rich.table import Table
10
10
  from starbash.app import Starbash, copy_images_to_dir
11
11
  from starbash.database import Database
12
12
  from starbash import console
13
+ from starbash.commands import format_duration
13
14
 
14
15
  app = typer.Typer()
15
16
 
@@ -114,20 +115,6 @@ def date(
114
115
  raise typer.Exit(1)
115
116
 
116
117
 
117
- def format_duration(seconds: int):
118
- """Format seconds as a human-readable duration string."""
119
- if seconds < 60:
120
- return f"{int(seconds)}s"
121
- elif seconds < 120:
122
- minutes = int(seconds // 60)
123
- secs = int(seconds % 60)
124
- return f"{minutes}m {secs}s" if secs else f"{minutes}m"
125
- else:
126
- hours = int(seconds // 3600)
127
- minutes = int((seconds % 3600) // 60)
128
- return f"{hours}h {minutes}m" if minutes else f"{hours}h"
129
-
130
-
131
118
  @app.command(name="list")
132
119
  def list_sessions():
133
120
  """List sessions (filtered based on the current selection)"""
@@ -135,7 +122,7 @@ def list_sessions():
135
122
  with Starbash("selection.list") as sb:
136
123
  sessions = sb.search_session()
137
124
  if sessions and isinstance(sessions, list):
138
- len_all = sb.db.len_session()
125
+ len_all = sb.db.len_table(Database.SESSIONS_TABLE)
139
126
  table = Table(title=f"Sessions ({len(sessions)} selected out of {len_all})")
140
127
  sb.analytics.set_data("session.num_selected", len(sessions))
141
128
  sb.analytics.set_data("session.num_total", len_all)
@@ -33,6 +33,9 @@ class Database:
33
33
  OBJECT_KEY = "OBJECT"
34
34
  TELESCOP_KEY = "TELESCOP"
35
35
 
36
+ SESSIONS_TABLE = "sessions"
37
+ IMAGES_TABLE = "images"
38
+
36
39
  def __init__(
37
40
  self,
38
41
  base_dir: Optional[Path] = None,
@@ -59,8 +62,8 @@ class Database:
59
62
 
60
63
  # Create images table with DATE-OBS and DATE as indexed columns
61
64
  cursor.execute(
62
- """
63
- CREATE TABLE IF NOT EXISTS images (
65
+ f"""
66
+ CREATE TABLE IF NOT EXISTS {self.IMAGES_TABLE} (
64
67
  id INTEGER PRIMARY KEY AUTOINCREMENT,
65
68
  path TEXT UNIQUE NOT NULL,
66
69
  date_obs TEXT,
@@ -72,29 +75,29 @@ class Database:
72
75
 
73
76
  # Create index on path for faster lookups
74
77
  cursor.execute(
75
- """
76
- CREATE INDEX IF NOT EXISTS idx_images_path ON images(path)
78
+ f"""
79
+ CREATE INDEX IF NOT EXISTS idx_images_path ON {self.IMAGES_TABLE}(path)
77
80
  """
78
81
  )
79
82
 
80
83
  # Create index on date_obs for efficient date range queries
81
84
  cursor.execute(
82
- """
83
- CREATE INDEX IF NOT EXISTS idx_images_date_obs ON images(date_obs)
85
+ f"""
86
+ CREATE INDEX IF NOT EXISTS idx_images_date_obs ON {self.IMAGES_TABLE}(date_obs)
84
87
  """
85
88
  )
86
89
 
87
90
  # Create index on date for queries using DATE field
88
91
  cursor.execute(
89
- """
90
- CREATE INDEX IF NOT EXISTS idx_images_date ON images(date)
92
+ f"""
93
+ CREATE INDEX IF NOT EXISTS idx_images_date ON {self.IMAGES_TABLE}(date)
91
94
  """
92
95
  )
93
96
 
94
97
  # Create sessions table
95
98
  cursor.execute(
96
- """
97
- CREATE TABLE IF NOT EXISTS sessions (
99
+ f"""
100
+ CREATE TABLE IF NOT EXISTS {self.SESSIONS_TABLE} (
98
101
  id INTEGER PRIMARY KEY AUTOINCREMENT,
99
102
  start TEXT NOT NULL,
100
103
  end TEXT NOT NULL,
@@ -111,9 +114,9 @@ class Database:
111
114
 
112
115
  # Create index on session attributes for faster queries
113
116
  cursor.execute(
114
- """
117
+ f"""
115
118
  CREATE INDEX IF NOT EXISTS idx_sessions_lookup
116
- ON sessions(filter, imagetyp, object, telescop, start, end)
119
+ ON {self.SESSIONS_TABLE}(filter, imagetyp, object, telescop, start, end)
117
120
  """
118
121
  )
119
122
 
@@ -141,8 +144,8 @@ class Database:
141
144
 
142
145
  cursor = self._db.cursor()
143
146
  cursor.execute(
144
- """
145
- INSERT INTO images (path, date_obs, date, metadata) VALUES (?, ?, ?, ?)
147
+ f"""
148
+ INSERT INTO {self.IMAGES_TABLE} (path, date_obs, date, metadata) VALUES (?, ?, ?, ?)
146
149
  ON CONFLICT(path) DO UPDATE SET
147
150
  date_obs = excluded.date_obs,
148
151
  date = excluded.date,
@@ -154,7 +157,7 @@ class Database:
154
157
  self._db.commit()
155
158
 
156
159
  # Get the rowid of the inserted/updated record
157
- cursor.execute("SELECT id FROM images WHERE path = ?", (path,))
160
+ cursor.execute(f"SELECT id FROM {self.IMAGES_TABLE} WHERE path = ?", (path,))
158
161
  result = cursor.fetchone()
159
162
  if result:
160
163
  return result[0]
@@ -190,7 +193,7 @@ class Database:
190
193
  params.append(date_end)
191
194
 
192
195
  # Build the query
193
- query = "SELECT id, path, date_obs, date, metadata FROM images"
196
+ query = f"SELECT id, path, date_obs, date, metadata FROM {self.IMAGES_TABLE}"
194
197
  if where_clauses:
195
198
  query += " WHERE " + " AND ".join(where_clauses)
196
199
 
@@ -236,10 +239,10 @@ class Database:
236
239
 
237
240
  cursor = self._db.cursor()
238
241
  cursor.execute(
239
- """
242
+ f"""
240
243
  SELECT id, start, end, filter, imagetyp, object, telescop,
241
244
  num_images, exptime_total, image_doc_id
242
- FROM sessions
245
+ FROM {self.SESSIONS_TABLE}
243
246
  """
244
247
  )
245
248
 
@@ -286,17 +289,17 @@ class Database:
286
289
 
287
290
  return results if results else None
288
291
 
289
- def len_session(self) -> int:
290
- """Return the total number of sessions."""
292
+ def len_table(self, table_name: str) -> int:
293
+ """Return the total number of rows in the specified table."""
291
294
  cursor = self._db.cursor()
292
- cursor.execute("SELECT COUNT(*) FROM sessions")
295
+ cursor.execute(f"SELECT COUNT(*) FROM {table_name}")
293
296
  result = cursor.fetchone()
294
297
  return result[0] if result else 0
295
298
 
296
- def get_column(self, column_name: str, table_name: str = "sessions") -> list[Any]:
299
+ def get_column(self, table_name: str, column_name: str) -> list[Any]:
297
300
  """Return all values from a specific column in the specified table."""
298
301
  cursor = self._db.cursor()
299
- cursor.execute(f"SELECT {column_name} FROM {table_name}")
302
+ cursor.execute(f'SELECT "{column_name}" FROM {table_name}')
300
303
 
301
304
  results = []
302
305
  for row in cursor.fetchall():
@@ -304,11 +307,18 @@ class Database:
304
307
 
305
308
  return results
306
309
 
310
+ def sum_column(self, table_name: str, column_name: str) -> float:
311
+ """Return the SUM of all values in a specific column in the specified table."""
312
+ cursor = self._db.cursor()
313
+ cursor.execute(f'SELECT SUM("{column_name}") FROM {table_name}')
314
+ result = cursor.fetchone()
315
+ return result[0] if result and result[0] is not None else 0
316
+
307
317
  def get_image(self, path: str) -> dict[str, Any] | None:
308
318
  """Get an image record by path."""
309
319
  cursor = self._db.cursor()
310
320
  cursor.execute(
311
- "SELECT id, path, date_obs, date, metadata FROM images WHERE path = ?",
321
+ f"SELECT id, path, date_obs, date, metadata FROM {self.IMAGES_TABLE} WHERE path = ?",
312
322
  (path,),
313
323
  )
314
324
  row = cursor.fetchone()
@@ -331,7 +341,9 @@ class Database:
331
341
  def all_images(self) -> list[dict[str, Any]]:
332
342
  """Return all image records."""
333
343
  cursor = self._db.cursor()
334
- cursor.execute("SELECT id, path, date_obs, date, metadata FROM images")
344
+ cursor.execute(
345
+ f"SELECT id, path, date_obs, date, metadata FROM {self.IMAGES_TABLE}"
346
+ )
335
347
 
336
348
  results = []
337
349
  for row in cursor.fetchall():
@@ -353,10 +365,10 @@ class Database:
353
365
  """Return all session records."""
354
366
  cursor = self._db.cursor()
355
367
  cursor.execute(
356
- """
368
+ f"""
357
369
  SELECT id, start, end, filter, imagetyp, object, telescop,
358
370
  num_images, exptime_total, image_doc_id
359
- FROM sessions
371
+ FROM {self.SESSIONS_TABLE}
360
372
  """
361
373
  )
362
374
 
@@ -389,10 +401,10 @@ class Database:
389
401
  """
390
402
  cursor = self._db.cursor()
391
403
  cursor.execute(
392
- """
404
+ f"""
393
405
  SELECT id, start, end, filter, imagetyp, object, telescop,
394
406
  num_images, exptime_total, image_doc_id
395
- FROM sessions
407
+ FROM {self.SESSIONS_TABLE}
396
408
  WHERE id = ?
397
409
  """,
398
410
  (session_id,),
@@ -443,10 +455,10 @@ class Database:
443
455
  # comparison aligns with chronological ordering for a uniform format.
444
456
  cursor = self._db.cursor()
445
457
  cursor.execute(
446
- """
458
+ f"""
447
459
  SELECT id, start, end, filter, imagetyp, object, telescop,
448
460
  num_images, exptime_total, image_doc_id
449
- FROM sessions
461
+ FROM {self.SESSIONS_TABLE}
450
462
  WHERE filter = ? AND imagetyp = ? AND object = ? AND telescop = ?
451
463
  AND start >= ? AND start <= ?
452
464
  LIMIT 1
@@ -489,8 +501,8 @@ class Database:
489
501
  ) + new.get(Database.EXPTIME_TOTAL_KEY, 0)
490
502
 
491
503
  cursor.execute(
492
- """
493
- UPDATE sessions
504
+ f"""
505
+ UPDATE {self.SESSIONS_TABLE}
494
506
  SET start = ?, end = ?, num_images = ?, exptime_total = ?
495
507
  WHERE id = ?
496
508
  """,
@@ -505,8 +517,8 @@ class Database:
505
517
  else:
506
518
  # Insert new session
507
519
  cursor.execute(
508
- """
509
- INSERT INTO sessions
520
+ f"""
521
+ INSERT INTO {self.SESSIONS_TABLE}
510
522
  (start, end, filter, imagetyp, object, telescop, num_images, exptime_total, image_doc_id)
511
523
  VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
512
524
  """,
@@ -6,7 +6,7 @@ import starbash.url as url
6
6
  import starbash
7
7
 
8
8
  from .app import Starbash, get_user_config_path, setup_logging
9
- from .commands import repo, select, user
9
+ from .commands import info, repo, select, user
10
10
  from . import console
11
11
 
12
12
  app = typer.Typer(
@@ -16,6 +16,7 @@ app = typer.Typer(
16
16
  app.add_typer(user.app, name="user", help="Manage user settings.")
17
17
  app.add_typer(repo.app, name="repo", help="Manage Starbash repositories.")
18
18
  app.add_typer(select.app, name="select", help="Manage session and target selection.")
19
+ app.add_typer(info.app, name="info", help="Display system and data information.")
19
20
 
20
21
 
21
22
  @app.callback(invoke_without_command=True)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes