osmsg 1.2.1__tar.gz → 1.2.3__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 osmsg might be problematic. Click here for more details.
- {osmsg-1.2.1 → osmsg-1.2.3}/PKG-INFO +7 -4
- {osmsg-1.2.1 → osmsg-1.2.3}/README.md +6 -3
- osmsg-1.2.3/osmsg/__version__.py +1 -0
- osmsg-1.2.3/osmsg/gui.py +231 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/pyproject.toml +4 -1
- osmsg-1.2.1/osmsg/__version__.py +0 -1
- {osmsg-1.2.1 → osmsg-1.2.3}/LICENSE +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/__init__.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/_http.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/_tick.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/auth.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/boundary.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/cli.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/db/__init__.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/db/duckdb_schema.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/db/ingest.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/db/queries.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/db/schema.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/exceptions.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/export/__init__.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/export/csv.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/export/json.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/export/markdown.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/export/parquet.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/export/psql.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/fetch.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/geofabrik.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/handlers.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/history.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/maintain/__init__.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/maintain/cli.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/maintain/convert.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/maintain/manifest.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/maintain/month.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/maintain/parquet.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/maintain/pbf_split.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/models.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/pg_schema.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/pipeline.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/py.typed +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/replication.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/tm.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/ui.py +0 -0
- {osmsg-1.2.1 → osmsg-1.2.3}/osmsg/workers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: osmsg
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: OpenStreetMap Stats Generator: Commandline
|
|
5
5
|
Keywords: osm,stats,commandline,openstreetmap
|
|
6
6
|
Author: Kshitij Raj Sharma
|
|
@@ -78,7 +78,9 @@ brew install osgeonepal/tap/osmsg # macOS / Linux (Homebrew tap)
|
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
On Windows, download `osmsg.exe` from the [latest release](https://github.com/osgeonepal/osmsg/releases)
|
|
81
|
-
and
|
|
81
|
+
and double-click it to open the desktop app. Pick a Quick range (last hour, day, week, month, year, or
|
|
82
|
+
all time) or type your own dates, set the options, click Compute, and open the output folder. The CLI
|
|
83
|
+
below is for macOS, Linux, and pip/uv users.
|
|
82
84
|
|
|
83
85
|
## Quick start
|
|
84
86
|
|
|
@@ -206,7 +208,8 @@ Same pipeline as the CLI.
|
|
|
206
208
|
osmsg --config nepal.yaml
|
|
207
209
|
```
|
|
208
210
|
|
|
209
|
-
|
|
211
|
+
Each option is a YAML key written with its underscore name: `output_dir`, `history_url`, `all_stats`,
|
|
212
|
+
`formats`, `psql_dsn`, and so on (not the dashed flag). See [docs/Manual.md](./docs/Manual.md).
|
|
210
213
|
|
|
211
214
|
## Output formats
|
|
212
215
|
|
|
@@ -237,7 +240,7 @@ docker-compose `environment:` block all reach the same setting. CLI flag wins ov
|
|
|
237
240
|
| `--history` / `--no-history` | `OSMSG_HISTORY` | on | Read covered months from the published dataset. |
|
|
238
241
|
| `--history-url` | `OSMSG_HISTORY_URL` | `osmsg-history` | Published dataset location. |
|
|
239
242
|
| `--insert` | (none) | off | Load history into the store and seed resume, then exit. No window loads all of it. |
|
|
240
|
-
| `--osh-file` / `--changeset-file` | (none) | unset | Insert from local planet history + changeset files
|
|
243
|
+
| `--osh-file` / `--changeset-file` | (none) | unset | Insert from local planet history + changeset files. |
|
|
241
244
|
| `--changeset-pad-hours` | `OSMSG_CHANGESET_PAD_HOURS` | `1` | See below. |
|
|
242
245
|
| (auto-bootstrap on `--update`) | `OSMSG_BOOTSTRAP` | `hour` | `hour`, `day`, or `week`. Used when `--update` runs against an empty DB. |
|
|
243
246
|
| (auto-bootstrap on `--update`) | `OSMSG_BOOTSTRAP_DAYS` | unset | Integer N; overrides `OSMSG_BOOTSTRAP`. |
|
|
@@ -46,7 +46,9 @@ brew install osgeonepal/tap/osmsg # macOS / Linux (Homebrew tap)
|
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
On Windows, download `osmsg.exe` from the [latest release](https://github.com/osgeonepal/osmsg/releases)
|
|
49
|
-
and
|
|
49
|
+
and double-click it to open the desktop app. Pick a Quick range (last hour, day, week, month, year, or
|
|
50
|
+
all time) or type your own dates, set the options, click Compute, and open the output folder. The CLI
|
|
51
|
+
below is for macOS, Linux, and pip/uv users.
|
|
50
52
|
|
|
51
53
|
## Quick start
|
|
52
54
|
|
|
@@ -174,7 +176,8 @@ Same pipeline as the CLI.
|
|
|
174
176
|
osmsg --config nepal.yaml
|
|
175
177
|
```
|
|
176
178
|
|
|
177
|
-
|
|
179
|
+
Each option is a YAML key written with its underscore name: `output_dir`, `history_url`, `all_stats`,
|
|
180
|
+
`formats`, `psql_dsn`, and so on (not the dashed flag). See [docs/Manual.md](./docs/Manual.md).
|
|
178
181
|
|
|
179
182
|
## Output formats
|
|
180
183
|
|
|
@@ -205,7 +208,7 @@ docker-compose `environment:` block all reach the same setting. CLI flag wins ov
|
|
|
205
208
|
| `--history` / `--no-history` | `OSMSG_HISTORY` | on | Read covered months from the published dataset. |
|
|
206
209
|
| `--history-url` | `OSMSG_HISTORY_URL` | `osmsg-history` | Published dataset location. |
|
|
207
210
|
| `--insert` | (none) | off | Load history into the store and seed resume, then exit. No window loads all of it. |
|
|
208
|
-
| `--osh-file` / `--changeset-file` | (none) | unset | Insert from local planet history + changeset files
|
|
211
|
+
| `--osh-file` / `--changeset-file` | (none) | unset | Insert from local planet history + changeset files. |
|
|
209
212
|
| `--changeset-pad-hours` | `OSMSG_CHANGESET_PAD_HOURS` | `1` | See below. |
|
|
210
213
|
| (auto-bootstrap on `--update`) | `OSMSG_BOOTSTRAP` | `hour` | `hour`, `day`, or `week`. Used when `--update` runs against an empty DB. |
|
|
211
214
|
| (auto-bootstrap on `--update`) | `OSMSG_BOOTSTRAP_DAYS` | unset | Integer N; overrides `OSMSG_BOOTSTRAP`. |
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.2.3"
|
osmsg-1.2.3/osmsg/gui.py
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"""Minimal tkinter desktop UI for running osmsg and saving the output."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import datetime as dt
|
|
6
|
+
import os
|
|
7
|
+
import queue
|
|
8
|
+
import sys
|
|
9
|
+
import threading
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from .exceptions import NoDataFoundError, OsmsgError
|
|
14
|
+
from .pipeline import RunConfig, run
|
|
15
|
+
|
|
16
|
+
UTC = dt.UTC
|
|
17
|
+
FORMATS = ["parquet", "csv", "json", "markdown"]
|
|
18
|
+
PRESETS = ["Last hour", "Last day", "Last week", "Last month", "Last year", "All time"]
|
|
19
|
+
_PRESET_DELTAS = {
|
|
20
|
+
"Last hour": dt.timedelta(hours=1),
|
|
21
|
+
"Last day": dt.timedelta(days=1),
|
|
22
|
+
"Last week": dt.timedelta(days=7),
|
|
23
|
+
"Last month": dt.timedelta(days=30),
|
|
24
|
+
"Last year": dt.timedelta(days=365),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def preset_range(name: str, now: dt.datetime | None = None) -> tuple[dt.datetime, dt.datetime]:
|
|
29
|
+
"""Resolve a quick-range label to a (start, end) window."""
|
|
30
|
+
now = now or dt.datetime.now(UTC)
|
|
31
|
+
if name == "All time":
|
|
32
|
+
return dt.datetime(2005, 1, 1, tzinfo=UTC), now
|
|
33
|
+
return now - _PRESET_DELTAS[name], now
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _fmt(when: dt.datetime) -> str:
|
|
37
|
+
return when.strftime("%Y-%m-%d %H:%M:%S")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _parse_date(value: str) -> dt.datetime | None:
|
|
41
|
+
value = value.strip()
|
|
42
|
+
if not value:
|
|
43
|
+
return None
|
|
44
|
+
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d"):
|
|
45
|
+
try:
|
|
46
|
+
return dt.datetime.strptime(value, fmt).replace(tzinfo=UTC)
|
|
47
|
+
except ValueError:
|
|
48
|
+
continue
|
|
49
|
+
raise OsmsgError(f"Unrecognized date: {value!r}. Use YYYY-MM-DD.")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _split(value: str | None) -> list[str] | None:
|
|
53
|
+
items: list[str] = [part.strip() for part in (value or "").split(",") if part.strip()]
|
|
54
|
+
return items if items else None
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def build_config(form: dict[str, object], output_dir: str) -> RunConfig:
|
|
58
|
+
"""Map the form fields to a RunConfig, raising OsmsgError on invalid input."""
|
|
59
|
+
formats = [name for name in FORMATS if form.get(name)]
|
|
60
|
+
if not formats:
|
|
61
|
+
raise OsmsgError("Pick at least one output format.")
|
|
62
|
+
start = _parse_date(str(form.get("start", "")))
|
|
63
|
+
if start is None:
|
|
64
|
+
raise OsmsgError("Start date is required (YYYY-MM-DD).")
|
|
65
|
+
return RunConfig(
|
|
66
|
+
name=str(form.get("name") or "stats"),
|
|
67
|
+
start_date=start,
|
|
68
|
+
end_date=_parse_date(str(form.get("end", ""))),
|
|
69
|
+
hashtags=_split(str(form.get("hashtags") or "")),
|
|
70
|
+
additional_tags=_split(str(form.get("tags") or "")),
|
|
71
|
+
tag_mode="all" if form.get("all_tags") else "none",
|
|
72
|
+
summary=bool(form.get("summary")),
|
|
73
|
+
formats=formats,
|
|
74
|
+
output_dir=Path(output_dir or "."),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _open_folder(path: Path) -> None:
|
|
79
|
+
if sys.platform == "win32":
|
|
80
|
+
os.startfile(path) # noqa: S606
|
|
81
|
+
elif sys.platform == "darwin":
|
|
82
|
+
import subprocess
|
|
83
|
+
|
|
84
|
+
subprocess.run(["open", str(path)], check=False)
|
|
85
|
+
else:
|
|
86
|
+
import subprocess
|
|
87
|
+
|
|
88
|
+
subprocess.run(["xdg-open", str(path)], check=False)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class _Redirector:
|
|
92
|
+
def __init__(self, sink: queue.Queue) -> None:
|
|
93
|
+
self.sink = sink
|
|
94
|
+
|
|
95
|
+
def write(self, text: str) -> None:
|
|
96
|
+
if text:
|
|
97
|
+
self.sink.put(("log", text))
|
|
98
|
+
|
|
99
|
+
def flush(self) -> None:
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
def isatty(self) -> bool:
|
|
103
|
+
return False
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class App:
|
|
107
|
+
def __init__(self) -> None:
|
|
108
|
+
import tkinter as tk
|
|
109
|
+
from tkinter import filedialog, scrolledtext, ttk
|
|
110
|
+
|
|
111
|
+
self._tk = tk
|
|
112
|
+
self._filedialog = filedialog
|
|
113
|
+
self.events: queue.Queue = queue.Queue()
|
|
114
|
+
self.out_dir = str(Path.home() / "osmsg")
|
|
115
|
+
|
|
116
|
+
self.root = tk.Tk()
|
|
117
|
+
self.root.title("osmsg")
|
|
118
|
+
self.vars: dict[str, Any] = {}
|
|
119
|
+
frame = ttk.Frame(self.root, padding=12)
|
|
120
|
+
frame.grid(sticky="nsew")
|
|
121
|
+
|
|
122
|
+
rows = [
|
|
123
|
+
("Name", "name", "stats"),
|
|
124
|
+
("Start (YYYY-MM-DD)", "start", ""),
|
|
125
|
+
("End (blank = now)", "end", ""),
|
|
126
|
+
("Hashtags (comma-sep)", "hashtags", ""),
|
|
127
|
+
("Tags (comma-sep)", "tags", ""),
|
|
128
|
+
]
|
|
129
|
+
for i, (label, key, default) in enumerate(rows):
|
|
130
|
+
ttk.Label(frame, text=label).grid(row=i, column=0, sticky="w", pady=2)
|
|
131
|
+
var = tk.StringVar(value=default)
|
|
132
|
+
ttk.Entry(frame, textvariable=var, width=40).grid(row=i, column=1, columnspan=3, sticky="we", pady=2)
|
|
133
|
+
self.vars[key] = var
|
|
134
|
+
|
|
135
|
+
preset_frame = ttk.LabelFrame(frame, text="Quick range", padding=6)
|
|
136
|
+
preset_frame.grid(row=5, column=0, columnspan=4, sticky="we", pady=6)
|
|
137
|
+
for i, name in enumerate(PRESETS):
|
|
138
|
+
ttk.Button(preset_frame, text=name, width=11, command=lambda n=name: self._apply_preset(n)).grid(
|
|
139
|
+
row=0, column=i, padx=2
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
self.vars["all_tags"] = tk.BooleanVar()
|
|
143
|
+
self.vars["summary"] = tk.BooleanVar()
|
|
144
|
+
ttk.Checkbutton(frame, text="All tags", variable=self.vars["all_tags"]).grid(row=6, column=0, sticky="w")
|
|
145
|
+
ttk.Checkbutton(frame, text="Daily summary", variable=self.vars["summary"]).grid(row=6, column=1, sticky="w")
|
|
146
|
+
|
|
147
|
+
fmt_frame = ttk.LabelFrame(frame, text="Formats", padding=6)
|
|
148
|
+
fmt_frame.grid(row=7, column=0, columnspan=4, sticky="we", pady=6)
|
|
149
|
+
for i, name in enumerate(FORMATS):
|
|
150
|
+
var = tk.BooleanVar(value=name in ("parquet", "csv"))
|
|
151
|
+
ttk.Checkbutton(fmt_frame, text=name, variable=var).grid(row=0, column=i, padx=4)
|
|
152
|
+
self.vars[name] = var
|
|
153
|
+
|
|
154
|
+
self.out_label = ttk.Label(frame, text=f"Output: {self.out_dir}")
|
|
155
|
+
self.out_label.grid(row=8, column=0, columnspan=3, sticky="w")
|
|
156
|
+
ttk.Button(frame, text="Choose folder", command=self._choose_folder).grid(row=8, column=3, sticky="e")
|
|
157
|
+
|
|
158
|
+
self.run_btn = ttk.Button(frame, text="Compute", command=self._on_run)
|
|
159
|
+
self.run_btn.grid(row=9, column=0, pady=8, sticky="w")
|
|
160
|
+
self.open_btn = ttk.Button(frame, text="Open output folder", command=lambda: _open_folder(Path(self.out_dir)))
|
|
161
|
+
self.open_btn.grid(row=9, column=1, pady=8, sticky="w")
|
|
162
|
+
self.spinner = ttk.Progressbar(frame, mode="indeterminate", length=160)
|
|
163
|
+
self.spinner.grid(row=9, column=2, columnspan=2, pady=8, sticky="we")
|
|
164
|
+
|
|
165
|
+
self.log = scrolledtext.ScrolledText(frame, width=70, height=14, state="disabled")
|
|
166
|
+
self.log.grid(row=10, column=0, columnspan=4, sticky="nsew")
|
|
167
|
+
self.root.after(120, self._drain)
|
|
168
|
+
|
|
169
|
+
def _apply_preset(self, name: str) -> None:
|
|
170
|
+
start, end = preset_range(name)
|
|
171
|
+
self.vars["start"].set(_fmt(start))
|
|
172
|
+
self.vars["end"].set(_fmt(end))
|
|
173
|
+
|
|
174
|
+
def _choose_folder(self) -> None:
|
|
175
|
+
chosen = self._filedialog.askdirectory(initialdir=self.out_dir)
|
|
176
|
+
if chosen:
|
|
177
|
+
self.out_dir = chosen
|
|
178
|
+
self.out_label.config(text=f"Output: {self.out_dir}")
|
|
179
|
+
|
|
180
|
+
def _append(self, text: str) -> None:
|
|
181
|
+
self.log.config(state="normal")
|
|
182
|
+
self.log.insert("end", text)
|
|
183
|
+
self.log.see("end")
|
|
184
|
+
self.log.config(state="disabled")
|
|
185
|
+
|
|
186
|
+
def _on_run(self) -> None:
|
|
187
|
+
try:
|
|
188
|
+
cfg = build_config({k: v.get() for k, v in self.vars.items()}, self.out_dir)
|
|
189
|
+
except OsmsgError as exc:
|
|
190
|
+
self._append(f"\n{exc}\n")
|
|
191
|
+
return
|
|
192
|
+
self.run_btn.config(state="disabled", text="Running...")
|
|
193
|
+
self.spinner.start(12)
|
|
194
|
+
self._append(f"\nComputing into {self.out_dir} ...\n")
|
|
195
|
+
threading.Thread(target=self._worker, args=(cfg,), daemon=True).start()
|
|
196
|
+
|
|
197
|
+
def _worker(self, cfg: RunConfig) -> None:
|
|
198
|
+
saved = sys.stdout, sys.stderr
|
|
199
|
+
sys.stdout = sys.stderr = _Redirector(self.events) # type: ignore[assignment]
|
|
200
|
+
try:
|
|
201
|
+
result = run(cfg)
|
|
202
|
+
self.events.put(("done", f"Done. {result['rows']} rows. Files in {self.out_dir}"))
|
|
203
|
+
except NoDataFoundError:
|
|
204
|
+
self.events.put(("done", "No data found for that range."))
|
|
205
|
+
except OsmsgError as exc:
|
|
206
|
+
self.events.put(("done", f"Error: {exc}"))
|
|
207
|
+
except Exception as exc:
|
|
208
|
+
self.events.put(("done", f"Unexpected error: {type(exc).__name__}: {exc}"))
|
|
209
|
+
finally:
|
|
210
|
+
sys.stdout, sys.stderr = saved
|
|
211
|
+
|
|
212
|
+
def _drain(self) -> None:
|
|
213
|
+
try:
|
|
214
|
+
while True:
|
|
215
|
+
kind, payload = self.events.get_nowait()
|
|
216
|
+
if kind == "log":
|
|
217
|
+
self._append(payload)
|
|
218
|
+
else:
|
|
219
|
+
self._append(f"\n{payload}\n")
|
|
220
|
+
self.spinner.stop()
|
|
221
|
+
self.run_btn.config(state="normal", text="Compute")
|
|
222
|
+
except queue.Empty:
|
|
223
|
+
pass
|
|
224
|
+
self.root.after(120, self._drain)
|
|
225
|
+
|
|
226
|
+
def run(self) -> None:
|
|
227
|
+
self.root.mainloop()
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def launch() -> None:
|
|
231
|
+
App().run()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "osmsg"
|
|
3
|
-
version = "1.2.
|
|
3
|
+
version = "1.2.3"
|
|
4
4
|
description = "OpenStreetMap Stats Generator: Commandline"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
@@ -41,6 +41,9 @@ repository = "https://github.com/osgeonepal/osmsg"
|
|
|
41
41
|
[project.scripts]
|
|
42
42
|
osmsg = "osmsg.cli:app"
|
|
43
43
|
|
|
44
|
+
[project.gui-scripts]
|
|
45
|
+
osmsg-gui = "osmsg.gui:launch"
|
|
46
|
+
|
|
44
47
|
[build-system]
|
|
45
48
|
requires = ["uv_build>=0.5.15,<0.9"]
|
|
46
49
|
build-backend = "uv_build"
|
osmsg-1.2.1/osmsg/__version__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.2.1"
|
|
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
|
|
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
|
|
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
|