starbash 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl

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.

starbash/repo/manager.py CHANGED
@@ -5,20 +5,24 @@ Manages the repository of processing recipes and configurations.
5
5
  from __future__ import annotations
6
6
  import logging
7
7
  from pathlib import Path
8
+ from importlib import resources
8
9
 
9
10
  import tomlkit
11
+ from tomlkit.toml_file import TOMLFile
10
12
  from tomlkit.items import AoT
11
13
  from multidict import MultiDict
12
14
 
13
15
 
14
16
  repo_suffix = "starbash.toml"
15
17
 
18
+ REPO_REF = "repo-ref"
19
+
16
20
 
17
21
  class Repo:
18
22
  """
19
23
  Represents a single starbash repository."""
20
24
 
21
- def __init__(self, manager: RepoManager, url: str, config: str | None = None):
25
+ def __init__(self, manager: RepoManager, url: str):
22
26
  """
23
27
  Initializes a Repo instance.
24
28
 
@@ -27,15 +31,14 @@ class Repo:
27
31
  """
28
32
  self.manager = manager
29
33
  self.url = url
30
- self.config = tomlkit.parse(config) if config else self._load_config()
31
- self.manager.add_all_repos(self.config, self.get_path())
34
+ self.config = self._load_config()
32
35
 
33
36
  def __str__(self) -> str:
34
37
  """Return a concise one-line description of this repo.
35
38
 
36
39
  Example: "Repo(kind=recipe, local=True, url=file:///path/to/repo)"
37
40
  """
38
- return f"Repo(kind={self.kind}, local={self.is_local}, url={self.url})"
41
+ return f"Repo(kind={self.kind}, url={self.url})"
39
42
 
40
43
  __repr__ = __str__
41
44
 
@@ -49,8 +52,37 @@ class Repo:
49
52
  """
50
53
  return str(self.get("repo.kind", "unknown"))
51
54
 
52
- @property
53
- def is_local(self) -> bool:
55
+ def add_repo_ref(self, dir: str) -> None:
56
+ aot = self.config.get(REPO_REF, None)
57
+ if aot is None:
58
+ aot = tomlkit.aot()
59
+ else:
60
+ self.config.remove(
61
+ REPO_REF
62
+ ) # We want to completely replace it at the end of the file
63
+
64
+ ref = {"dir": dir}
65
+ aot.append(ref)
66
+ self.config[REPO_REF] = aot
67
+ self.add_from_ref(ref)
68
+
69
+ def write_config(self) -> None:
70
+ """
71
+ Writes the current (possibly modified) configuration back to the repository's config file.
72
+
73
+ Raises:
74
+ ValueError: If the repository is not a local file repository.
75
+ """
76
+ base_path = self.get_path()
77
+ if base_path is None:
78
+ raise ValueError("Cannot resolve path for non-local repository")
79
+
80
+ config_path = base_path / repo_suffix
81
+ # FIXME, be more careful to write the file atomically (by writing to a temp file and renaming)
82
+ TOMLFile(config_path).write(self.config)
83
+ logging.debug(f"Wrote config to {config_path}")
84
+
85
+ def is_scheme(self, scheme: str = "file") -> bool:
54
86
  """
55
87
  Read-only attribute indicating whether the repository URL points to a
56
88
  local file system path (file:// scheme).
@@ -58,7 +90,7 @@ class Repo:
58
90
  Returns:
59
91
  bool: True if the URL is a local file path, False otherwise.
60
92
  """
61
- return self.url.startswith("file://")
93
+ return self.url.startswith(f"{scheme}://")
62
94
 
63
95
  def get_path(self) -> Path | None:
64
96
  """
@@ -70,12 +102,39 @@ class Repo:
70
102
  Returns:
71
103
  A Path object if the URL is a local file, otherwise None.
72
104
  """
73
- if self.is_local:
105
+ if self.is_scheme("file"):
74
106
  return Path(self.url[len("file://") :])
75
107
 
76
108
  return None
77
109
 
78
- def read(self, filepath: str) -> str:
110
+ def add_from_ref(self, ref: dict) -> None:
111
+ """
112
+ Adds a repository based on a repo-ref dictionary.
113
+ """
114
+ if "url" in ref:
115
+ url = ref["url"]
116
+ elif "dir" in ref:
117
+ path = Path(ref["dir"])
118
+ base_path = self.get_path()
119
+ if base_path and not path.is_absolute():
120
+ # Resolve relative to the current TOML file's directory
121
+ path = (base_path / path).resolve()
122
+ else:
123
+ # Expand ~ and resolve from CWD
124
+ path = path.expanduser().resolve()
125
+ url = f"file://{path}"
126
+ else:
127
+ raise ValueError(f"Invalid repo reference: {ref}")
128
+ self.manager.add_repo(url)
129
+
130
+ def add_by_repo_refs(self) -> None:
131
+ """Add all repos mentioned by repo-refs in this repo's config."""
132
+ repo_refs = self.config.get(REPO_REF, [])
133
+
134
+ for ref in repo_refs:
135
+ self.add_from_ref(ref)
136
+
137
+ def _read_file(self, filepath: str) -> str:
79
138
  """
80
139
  Read a filepath relative to the base of this repo. Return the contents in a string.
81
140
 
@@ -96,7 +155,31 @@ class Repo:
96
155
 
97
156
  return target_path.read_text()
98
157
 
99
- def _load_config(self) -> dict:
158
+ def _read_resource(self, filepath: str) -> str:
159
+ """
160
+ Read a resource from the installed starbash package using a pkg:// URL.
161
+
162
+ Assumptions (simplified per project constraints):
163
+ - All pkg URLs point somewhere inside the already-imported 'starbash' package.
164
+ - The URL is treated as a path relative to the starbash package root.
165
+
166
+ Examples:
167
+ url: pkg://defaults + filepath: "starbash.toml"
168
+ -> reads starbash/defaults/starbash.toml
169
+
170
+ Args:
171
+ filepath: Path within the base resource directory for this repo.
172
+
173
+ Returns:
174
+ The content of the resource as a string (UTF-8).
175
+ """
176
+ # Path portion after pkg://, interpreted relative to the 'starbash' package
177
+ subpath = self.url[len("pkg://") :].strip("/")
178
+
179
+ res = resources.files("starbash").joinpath(subpath).joinpath(filepath)
180
+ return res.read_text()
181
+
182
+ def _load_config(self) -> tomlkit.TOMLDocument:
100
183
  """
101
184
  Loads the repository's configuration file (e.g., repo.sb.toml).
102
185
 
@@ -106,12 +189,19 @@ class Repo:
106
189
  A dictionary containing the parsed configuration.
107
190
  """
108
191
  try:
109
- config_content = self.read(repo_suffix)
192
+ if self.is_scheme("file"):
193
+ config_content = self._read_file(repo_suffix)
194
+ elif self.is_scheme("pkg"):
195
+ config_content = self._read_resource(repo_suffix)
196
+ else:
197
+ raise ValueError(f"Unsupported URL scheme for repo: {self.url}")
110
198
  logging.debug(f"Loading repo config from {repo_suffix}")
111
199
  return tomlkit.parse(config_content)
112
200
  except FileNotFoundError:
113
- logging.warning(f"No {repo_suffix} found")
114
- return {}
201
+ logging.debug(
202
+ f"No {repo_suffix} found"
203
+ ) # we currently make it optional to have the config file at root
204
+ return tomlkit.TOMLDocument() # empty placeholder
115
205
 
116
206
  def get(self, key: str, default=None):
117
207
  """
@@ -142,42 +232,31 @@ class RepoManager:
142
232
  files (like appdefaults.sb.toml).
143
233
  """
144
234
 
145
- def __init__(self, app_defaults: str):
235
+ def __init__(self):
146
236
  """
147
237
  Initializes the RepoManager by loading the application default repos.
148
238
  """
149
239
  self.repos = []
150
240
 
151
241
  # We expose the app default preferences as a special root repo with a private URL
152
- root_repo = Repo(self, "pkg://starbash-defaults", config=app_defaults)
153
- self.repos.append(root_repo)
242
+ # root_repo = Repo(self, "pkg://starbash-defaults", config=app_defaults)
243
+ # self.repos.append(root_repo)
154
244
 
155
245
  # Most users will just want to read from merged
156
- self.merged = self._union()
246
+ self.merged = MultiDict()
157
247
 
158
- def add_all_repos(self, toml: dict, base_path: Path | None = None) -> None:
159
- # From appdefaults.sb.toml, repo.ref is a list of tables
160
- repo_refs = toml.get("repo", {}).get("ref", [])
248
+ def add_repo(self, url: str) -> Repo:
249
+ logging.debug(f"Adding repo: {url}")
250
+ r = Repo(self, url)
251
+ self.repos.append(r)
161
252
 
162
- for ref in repo_refs:
163
- if "url" in ref:
164
- url = ref["url"]
165
- elif "dir" in ref:
166
- path = Path(ref["dir"])
167
- if base_path and not path.is_absolute():
168
- # Resolve relative to the current TOML file's directory
169
- path = (base_path / path).resolve()
170
- else:
171
- # Expand ~ and resolve from CWD
172
- path = path.expanduser().resolve()
173
- url = f"file://{path}"
174
- else:
175
- raise ValueError(f"Invalid repo reference: {ref}")
176
- self.add_repo(url)
253
+ # FIXME, generate the merged dict lazily
254
+ self._add_merged(r)
177
255
 
178
- def add_repo(self, url: str) -> None:
179
- logging.debug(f"Adding repo: {url}")
180
- self.repos.append(Repo(self, url))
256
+ # if this new repo has sub-repos, add them too
257
+ r.add_by_repo_refs()
258
+
259
+ return r
181
260
 
182
261
  def get(self, key: str, default=None):
183
262
  """
@@ -214,32 +293,18 @@ class RepoManager:
214
293
  # For a debug dump, a simple string representation is usually sufficient.
215
294
  logging.info(f" %s: %s", key, value)
216
295
 
217
- def _union(self) -> MultiDict:
218
- """
219
- Merges the top-level keys from all repository configurations into a MultiDict.
220
-
221
- This method iterates through all loaded repositories in their original order
222
- and combines their top-level configuration keys. If a key exists in multiple
223
- repositories, all of its values will be present in the returned MultiDict.
224
-
225
- Returns:
226
- A MultiDict containing the union of all top-level keys.
227
- """
228
- merged_dict = MultiDict()
229
- for repo in self.repos:
230
- for key, value in repo.config.items():
231
- # if the toml object is an AoT type, monkey patch each element in the array instead
232
- if isinstance(value, AoT):
233
- for v in value:
234
- setattr(v, "source", repo)
296
+ def _add_merged(self, repo: Repo) -> None:
297
+ for key, value in repo.config.items():
298
+ # if the toml object is an AoT type, monkey patch each element in the array instead
299
+ if isinstance(value, AoT):
300
+ for v in value:
301
+ setattr(v, "source", repo)
235
302
  else:
236
303
  # We monkey patch source into any object that came from a repo, so that users can
237
304
  # find the source repo (for attribution, URL relative resolution, whatever...)
238
305
  setattr(value, "source", repo)
239
306
 
240
- merged_dict.add(key, value)
241
-
242
- return merged_dict
307
+ self.merged.add(key, value)
243
308
 
244
309
  def __str__(self):
245
310
  lines = [f"RepoManager with {len(self.repos)} repositories:"]
starbash/selection.py ADDED
@@ -0,0 +1,215 @@
1
+ """Selection state management for filtering sessions and targets."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ import logging
7
+ from pathlib import Path
8
+ from typing import Any, Optional
9
+ from datetime import datetime
10
+
11
+
12
+ class Selection:
13
+ """Manages the current selection state for filtering sessions and targets.
14
+
15
+ This class maintains persistent state about what the user has selected:
16
+ - Target names
17
+ - Date ranges
18
+ - Filters
19
+ - Image types
20
+
21
+ The selection state is saved to disk and can be used to build database queries.
22
+ """
23
+
24
+ def __init__(self, state_file: Path):
25
+ """Initialize the Selection with a state file path.
26
+
27
+ Args:
28
+ state_file: Path to the JSON file where selection state is persisted
29
+ """
30
+ self.state_file = state_file
31
+ self.targets: list[str] = []
32
+ self.date_start: Optional[str] = None
33
+ self.date_end: Optional[str] = None
34
+ self.filters: list[str] = []
35
+ self.image_types: list[str] = []
36
+
37
+ # Load existing state if it exists
38
+ self._load()
39
+
40
+ def _load(self) -> None:
41
+ """Load selection state from disk."""
42
+ if self.state_file.exists():
43
+ try:
44
+ with open(self.state_file, "r") as f:
45
+ data = json.load(f)
46
+ self.targets = data.get("targets", [])
47
+ self.date_start = data.get("date_start")
48
+ self.date_end = data.get("date_end")
49
+ self.filters = data.get("filters", [])
50
+ self.image_types = data.get("image_types", [])
51
+ logging.debug(f"Loaded selection state from {self.state_file}")
52
+ except Exception as e:
53
+ logging.warning(f"Failed to load selection state: {e}")
54
+
55
+ def _save(self) -> None:
56
+ """Save selection state to disk."""
57
+ try:
58
+ # Ensure parent directory exists
59
+ self.state_file.parent.mkdir(parents=True, exist_ok=True)
60
+
61
+ data = {
62
+ "targets": self.targets,
63
+ "date_start": self.date_start,
64
+ "date_end": self.date_end,
65
+ "filters": self.filters,
66
+ "image_types": self.image_types,
67
+ }
68
+
69
+ with open(self.state_file, "w") as f:
70
+ json.dump(data, f, indent=2)
71
+ logging.debug(f"Saved selection state to {self.state_file}")
72
+ except Exception as e:
73
+ logging.error(f"Failed to save selection state: {e}")
74
+
75
+ def clear(self) -> None:
76
+ """Clear all selection criteria (select everything)."""
77
+ self.targets = []
78
+ self.date_start = None
79
+ self.date_end = None
80
+ self.filters = []
81
+ self.image_types = []
82
+ self._save()
83
+
84
+ def add_target(self, target: str) -> None:
85
+ """Add a target to the selection.
86
+
87
+ Args:
88
+ target: Target name to add to the selection
89
+ """
90
+ if target not in self.targets:
91
+ self.targets.append(target)
92
+ self._save()
93
+
94
+ def remove_target(self, target: str) -> None:
95
+ """Remove a target from the selection.
96
+
97
+ Args:
98
+ target: Target name to remove from the selection
99
+ """
100
+ if target in self.targets:
101
+ self.targets.remove(target)
102
+ self._save()
103
+
104
+ def set_date_range(
105
+ self, start: Optional[str] = None, end: Optional[str] = None
106
+ ) -> None:
107
+ """Set the date range for the selection.
108
+
109
+ Args:
110
+ start: ISO format date string for start of range (inclusive)
111
+ end: ISO format date string for end of range (inclusive)
112
+ """
113
+ self.date_start = start
114
+ self.date_end = end
115
+ self._save()
116
+
117
+ def add_filter(self, filter_name: str) -> None:
118
+ """Add a filter to the selection.
119
+
120
+ Args:
121
+ filter_name: Filter name to add to the selection
122
+ """
123
+ if filter_name not in self.filters:
124
+ self.filters.append(filter_name)
125
+ self._save()
126
+
127
+ def remove_filter(self, filter_name: str) -> None:
128
+ """Remove a filter from the selection.
129
+
130
+ Args:
131
+ filter_name: Filter name to remove from the selection
132
+ """
133
+ if filter_name in self.filters:
134
+ self.filters.remove(filter_name)
135
+ self._save()
136
+
137
+ def is_empty(self) -> bool:
138
+ """Check if the selection has any criteria set.
139
+
140
+ Returns:
141
+ True if no selection criteria are active (selecting everything)
142
+ """
143
+ return (
144
+ not self.targets
145
+ and self.date_start is None
146
+ and self.date_end is None
147
+ and not self.filters
148
+ and not self.image_types
149
+ )
150
+
151
+ def get_query_conditions(self) -> dict[str, Any]:
152
+ """Build query conditions based on the current selection.
153
+
154
+ Returns:
155
+ Dictionary of query conditions that can be used with Database methods.
156
+ Special keys:
157
+ - 'date_start': ISO date string for start of range
158
+ - 'date_end': ISO date string for end of range
159
+ """
160
+ conditions = {}
161
+
162
+ # Note: This returns a simplified conditions dict.
163
+ # The actual query building will be enhanced later to support
164
+ # complex queries with date ranges, multiple targets, etc.
165
+
166
+ if self.targets:
167
+ # For now, just use the first target
168
+ # TODO: Support multiple targets in queries
169
+ conditions["OBJECT"] = self.targets[0] if len(self.targets) == 1 else None
170
+
171
+ if self.filters:
172
+ # For now, just use the first filter
173
+ # TODO: Support multiple filters in queries
174
+ conditions["FILTER"] = self.filters[0] if len(self.filters) == 1 else None
175
+
176
+ # Add date range conditions
177
+ if self.date_start:
178
+ conditions["date_start"] = self.date_start
179
+ if self.date_end:
180
+ conditions["date_end"] = self.date_end
181
+
182
+ return conditions
183
+
184
+ def summary(self) -> dict[str, Any]:
185
+ """Get a summary of the current selection state.
186
+
187
+ Returns:
188
+ Dictionary with human-readable summary of selection criteria
189
+ """
190
+ if self.is_empty():
191
+ return {
192
+ "status": "all",
193
+ "message": "No filters active - selecting all sessions",
194
+ }
195
+
196
+ summary = {"status": "filtered", "criteria": []}
197
+
198
+ if self.targets:
199
+ summary["criteria"].append(f"Targets: {', '.join(self.targets)}")
200
+
201
+ if self.date_start or self.date_end:
202
+ date_range = []
203
+ if self.date_start:
204
+ date_range.append(f"from {self.date_start}")
205
+ if self.date_end:
206
+ date_range.append(f"to {self.date_end}")
207
+ summary["criteria"].append(f"Date: {' '.join(date_range)}")
208
+
209
+ if self.filters:
210
+ summary["criteria"].append(f"Filters: {', '.join(self.filters)}")
211
+
212
+ if self.image_types:
213
+ summary["criteria"].append(f"Image types: {', '.join(self.image_types)}")
214
+
215
+ return summary
File without changes
@@ -0,0 +1,21 @@
1
+ # This is your Starbash user configuration file. It can be used to provide default settings
2
+ # to workflows.
3
+
4
+ # (or wherever is appropriate for the user's platform).
5
+
6
+ [repo]
7
+ kind = "preferences"
8
+
9
+ [analytics]
10
+ # enabled = true # default is true - change to false if you don't want any analytics/crash-reports
11
+ # include_user = false # default is false - change to true if you'd like your email added to crash reports/analytics
12
+
13
+ [user]
14
+ # default author info
15
+ # name = "Your Name"
16
+ # email = "youremail@somedomain.com"
17
+ # website = "https://yourwebsite"
18
+ # license = "FIXME eventually applied as the default license for generated images Creative commons etc..."
19
+
20
+ # DO NOT edit below this line, they are managed automatically via
21
+ # the "sb repo add" etc... commands.
starbash/url.py ADDED
@@ -0,0 +1,9 @@
1
+ project = "https://github.com/geeksville/starbash"
2
+ analytics_docs = f"{project}/blob/main/doc/analytics.md"
3
+
4
+
5
+ def new_issue(report_id: str | None = None) -> str:
6
+ if report_id:
7
+ return f"{project}/issues/new?body=Please%20describe%20the%20problem%2C%20but%20include%20this%3A%0ACrash%20ID%20{report_id}"
8
+ else:
9
+ return f"{project}/issues/new?body=Please%20describe%20the%20problem"
@@ -1,24 +1,31 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: starbash
3
- Version: 0.1.0
3
+ Version: 0.1.1
4
4
  Summary:
5
+ License-File: LICENSE
5
6
  Author: Kevin Hester
6
7
  Author-email: kevinh@geeksville.com
7
8
  Requires-Python: >=3.12,<3.15
8
9
  Classifier: Programming Language :: Python :: 3
9
10
  Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
10
13
  Requires-Dist: astropy (>=7.1.1,<8.0.0)
11
14
  Requires-Dist: multidict (>=6.7.0,<7.0.0)
12
15
  Requires-Dist: platformdirs (>=4.5.0,<5.0.0)
13
16
  Requires-Dist: restrictedpython (>=8.1,<9.0)
14
17
  Requires-Dist: rich (>=14.2.0,<15.0.0)
15
- Requires-Dist: tinydb (>=4.8.2,<5.0.0)
18
+ Requires-Dist: sentry-sdk (>=2.42.1,<3.0.0)
16
19
  Requires-Dist: tomlkit (>=0.13.3,<0.14.0)
17
20
  Requires-Dist: typer (>=0.20.0,<0.21.0)
18
21
  Description-Content-Type: text/markdown
19
22
 
20
23
  # Starbash
21
- ![app icon](img/icon.png "Starbash: Astrophotography workflows simplified")
24
+
25
+ ![PyPI - Version](https://img.shields.io/pypi/v/starbash)
26
+ ![GitHub branch check runs](https://img.shields.io/github/check-runs/geeksville/starbash/main)
27
+
28
+ ![app icon](https://github.com/geeksville/starbash/blob/main/img/icon.png "Starbash: Astrophotography workflows simplified")
22
29
 
23
30
  A tool for automating/standardizing/sharing astrophotography workflows.
24
31
 
@@ -48,20 +55,27 @@ See my personal [TODO](TODO.md) file. I'll be looking for pre-alpha testers/fee
48
55
  * repo list
49
56
  * repo reindex REPONAME|REPONUM|all
50
57
 
51
- * target list
52
- * target select TARGETNAME
58
+ * user analytics on|off - turn analytics collection on/off
59
+ * user name "Your Name" - used for attribution in generated images
60
+ * user email "foo@blah.com" - used for attribution in generated images
61
+
62
+ * selection any - remove any filters on sessions, etc...
63
+ * selection target TARGETNAME - limit the current selection to only the named targets
64
+ * selection date op DATE - limit to sessions in the specified date range
65
+ * selection - list information about the current selection
66
+
67
+ * target - list targets (filtered based on the current selection)
53
68
 
54
- * reset - remove any filters on targets, sessions, etc...
69
+ * session- list sessions (filtered based on the current selection)
55
70
 
56
- * session list
57
- * session date after DATE
58
- * session date before DATE
71
+ * instrument - list instruments (filtered based on the current selection)
59
72
 
60
- * instrument list
73
+ * filter - list all filters found in current selection
61
74
 
62
75
  * export dirs|BIAS|LIGHT|DARK|FLAT [DIRLOC]
63
76
 
64
77
  * process auto
78
+ * process masters - generate master flats, darks, biases from any raws that are available
65
79
 
66
80
  ## Supported tools
67
81
 
@@ -0,0 +1,24 @@
1
+ starbash/__init__.py,sha256=co39eIssQlFxWfO3cDhp52reRy6qEyJX5u5K8OsxiDk,138
2
+ starbash/analytics.py,sha256=0TfiZthKRMqW38Jg1VJDjpykZXBrK33tNKuhQibkCK0,3579
3
+ starbash/app.py,sha256=sYEgemSDZEX7yih2p_aFlrsCypWjx2zNDsNHJ_DNF0E,13319
4
+ starbash/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ starbash/commands/repo.py,sha256=WuOg15p9LnJ6aIWIXYCKY9guRIUCq3XapyO7oi1v3hQ,1874
6
+ starbash/commands/selection.py,sha256=4bpjYWne9ekg1EIOJS15Ymj2Hyr-jc2Te4N4mXepkpI,3941
7
+ starbash/commands/user.py,sha256=JpwYa9cYxm2gkekcxrj7CsbJO7fgbGwRxmjvpua0BOY,1598
8
+ starbash/database.py,sha256=jQyuZ-sFwbAIv6Wtn4VnPVQChQMP4y1rVjrEgp2iLoA,13513
9
+ starbash/defaults/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
+ starbash/defaults/starbash.toml,sha256=RVfYikW5xhpZUt83U5k7O2hprswgFvDFykCWkHL37QU,2384
11
+ starbash/main.py,sha256=7N28XCu43IUijIaTrT9ZY_aWxEmJGDdTLWdfhw_omOc,5084
12
+ starbash/paths.py,sha256=BKKnSXt3tOh16o7ljDcQLtWKIiepEmud9JFtzRwDHtg,1317
13
+ starbash/repo/__init__.py,sha256=TqspuLjPSNnO38tvCGa0fJvvasgecHl6fE7m0-Lj8ho,148
14
+ starbash/repo/manager.py,sha256=XBiZXMgVKd7faddwugtWVbeR8XuJF8sZi8yAiDxT6wM,10701
15
+ starbash/selection.py,sha256=4u4h30VeC_e8PWFdtNWA9C7AyYrcAgg3BEagSynaxMM,7111
16
+ starbash/templates/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
+ starbash/templates/userconfig.toml,sha256=NinuXl8L0xxSvI4FFZD8ye836yv8TaUP0a5VMEc-w1w,757
18
+ starbash/tool.py,sha256=S1kOTbeHTrA0meqwftgL0SA4VhJdZWWx2h1Wtwu1Izg,8749
19
+ starbash/url.py,sha256=lorxQJ27jSfzsKCb0QvpcvLiPZG55Dkd_c1JPFbni4I,402
20
+ starbash-0.1.1.dist-info/METADATA,sha256=EjekS6hjvRkPf-Ka0ZUa0_XhRp50YwABIjOBlStvyH4,3539
21
+ starbash-0.1.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
22
+ starbash-0.1.1.dist-info/entry_points.txt,sha256=REQyWs8e5TJsNK7JVVWowKVoytMmKlUwuFHLTmSX4hc,67
23
+ starbash-0.1.1.dist-info/licenses/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
24
+ starbash-0.1.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.9.0
2
+ Generator: poetry-core 2.2.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,15 +0,0 @@
1
- starbash/__init__.py,sha256=co39eIssQlFxWfO3cDhp52reRy6qEyJX5u5K8OsxiDk,138
2
- starbash/app.py,sha256=8f1OSJPlgSMri8kMFrQ6nac5M1gAgPl-FRnuXeOWMAQ,8754
3
- starbash/appdefaults.sb.toml,sha256=YTUwTqg2DcDFs9VDB1gqchNqk-hg_cGlpaa134hLOJU,2606
4
- starbash/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
- starbash/commands/repo.py,sha256=Xg9aaaURrv45bJF5w4rsD2X5_FdeM4dp9d9xbGaG4Ds,985
6
- starbash/database.py,sha256=HFJI0CAQIFfKGx3yTS7anREAcvjiNZhObwyAbD5WD48,2254
7
- starbash/main.py,sha256=VNV2y8pz_NMbGXjIDuFIDbbS0Q0B5GMqKTXitFf1tb4,579
8
- starbash/repo/__init__.py,sha256=TqspuLjPSNnO38tvCGa0fJvvasgecHl6fE7m0-Lj8ho,148
9
- starbash/repo/manager.py,sha256=jOhN-Rx60rtueLsHLoVdvcyWTDOqfUGZN6nbbJzRntI,8586
10
- starbash/tool.py,sha256=S1kOTbeHTrA0meqwftgL0SA4VhJdZWWx2h1Wtwu1Izg,8749
11
- starbash-0.1.0.dist-info/LICENSE,sha256=ixuiBLtpoK3iv89l7ylKkg9rs2GzF9ukPH7ynZYzK5s,35148
12
- starbash-0.1.0.dist-info/METADATA,sha256=N1fSGzjmBFEWL5V7uxbwcGbS3X_UExpxja4cZjA3KIE,2564
13
- starbash-0.1.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
14
- starbash-0.1.0.dist-info/entry_points.txt,sha256=REQyWs8e5TJsNK7JVVWowKVoytMmKlUwuFHLTmSX4hc,67
15
- starbash-0.1.0.dist-info/RECORD,,