mltrackr 0.3.0__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.
- mltrackr-0.3.0.dist-info/METADATA +358 -0
- mltrackr-0.3.0.dist-info/RECORD +11 -0
- mltrackr-0.3.0.dist-info/WHEEL +5 -0
- mltrackr-0.3.0.dist-info/entry_points.txt +2 -0
- mltrackr-0.3.0.dist-info/top_level.txt +1 -0
- trainlog/__init__.py +14 -0
- trainlog/cli.py +575 -0
- trainlog/core.py +1045 -0
- trainlog/dashboard/__init__.py +0 -0
- trainlog/dashboard/server.py +157 -0
- trainlog/dashboard/templates/index.html +847 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mltrackr
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Zero-setup ML experiment tracker with live dashboard, anomaly detection, and hyperparameter suggestions
|
|
5
|
+
License: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/naialorente/datalog
|
|
7
|
+
Project-URL: Issues, https://github.com/naialorente/datalog/issues
|
|
8
|
+
Keywords: machine-learning,experiment-tracking,mlops,data-science,pytorch,scikit-learn,keras,huggingface,tensorflow,hyperparameter-tuning,model-monitoring,local-first,research,jupyter,kaggle,anomaly-detection,dashboard,experiment-logger,ml-tracker,training-monitor
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Intended Audience :: Education
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
15
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
16
|
+
Classifier: Topic :: Database
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Operating System :: OS Independent
|
|
25
|
+
Classifier: Environment :: Console
|
|
26
|
+
Classifier: Environment :: Web Environment
|
|
27
|
+
Requires-Python: >=3.8
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
Requires-Dist: flask>=2.0
|
|
30
|
+
Requires-Dist: click>=8.0
|
|
31
|
+
Requires-Dist: rich>=13.0
|
|
32
|
+
|
|
33
|
+
# trainlog
|
|
34
|
+
|
|
35
|
+
> Track ML experiments in 2 lines of code. No server. No account. No config.
|
|
36
|
+
|
|
37
|
+
[](https://github.com/NaiaLorente/datalog/actions/workflows/ci.yml)
|
|
38
|
+
[](https://pypi.org/project/mltrackr/)
|
|
39
|
+
[](https://pypi.org/project/mltrackr/)
|
|
40
|
+
[](LICENSE)
|
|
41
|
+
[](https://github.com/NaiaLorente/datalog)
|
|
42
|
+
|
|
43
|
+
You're running a training loop. You want to know which hyperparameters worked best. You don't want to:
|
|
44
|
+
|
|
45
|
+
- Set up a tracking server
|
|
46
|
+
- Create an account on any service
|
|
47
|
+
- Write to a cloud API
|
|
48
|
+
- Configure environment variables
|
|
49
|
+
- Install 47 dependencies
|
|
50
|
+
|
|
51
|
+
**trainlog is the answer.** Install it, wrap your loop, open a beautiful local dashboard. Done.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Quickstart (5 steps)
|
|
56
|
+
|
|
57
|
+
**1. Install**
|
|
58
|
+
```bash
|
|
59
|
+
pip install mltrackr
|
|
60
|
+
```
|
|
61
|
+
> This installs the `trainlog` command and `import trainlog` Python package.
|
|
62
|
+
|
|
63
|
+
**2. Generate a ready-to-run example**
|
|
64
|
+
```bash
|
|
65
|
+
python -m trainlog.cli init --framework plain -o demo.py
|
|
66
|
+
```
|
|
67
|
+
> On most systems `trainlog init` works directly. If not, use `python -m trainlog.cli` instead.
|
|
68
|
+
|
|
69
|
+
**3. Run the demo (creates 6 fake training runs)**
|
|
70
|
+
```bash
|
|
71
|
+
python demo.py
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**4. Inspect results in the terminal**
|
|
75
|
+
```bash
|
|
76
|
+
python -m trainlog.cli list
|
|
77
|
+
python -m trainlog.cli best accuracy
|
|
78
|
+
python -m trainlog.cli suggest accuracy
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**5. Open the visual dashboard**
|
|
82
|
+
```bash
|
|
83
|
+
python -m trainlog.cli ui
|
|
84
|
+
```
|
|
85
|
+
Then open **http://localhost:7000** in your browser. Press `Ctrl+C` to stop.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Your first real experiment
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
import trainlog
|
|
93
|
+
|
|
94
|
+
with trainlog.run("resnet-baseline", tags=["cv", "baseline"]):
|
|
95
|
+
trainlog.log(lr=1e-3, batch_size=64, optimizer="adam")
|
|
96
|
+
|
|
97
|
+
for epoch in range(50):
|
|
98
|
+
loss, acc = train_one_epoch(model, dataloader)
|
|
99
|
+
trainlog.log(loss=loss, accuracy=acc, epoch=epoch)
|
|
100
|
+
|
|
101
|
+
trainlog.note("Solid baseline - try lr=5e-4 next")
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# If 'trainlog' works directly on your system:
|
|
106
|
+
trainlog ui
|
|
107
|
+
trainlog list
|
|
108
|
+
trainlog best accuracy
|
|
109
|
+
trainlog suggest accuracy
|
|
110
|
+
trainlog report
|
|
111
|
+
|
|
112
|
+
# If not (e.g. Windows), use:
|
|
113
|
+
python -m trainlog.cli ui
|
|
114
|
+
python -m trainlog.cli list
|
|
115
|
+
python -m trainlog.cli best accuracy
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Everything is saved locally in `~/.trainlog/experiments.db`. A single SQLite file. Copy it, back it up, open it in any SQLite browser.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Why trainlog?
|
|
123
|
+
|
|
124
|
+
**The real problem:** you're hacking on a model, you want to log some metrics, but setting up MLflow takes 15 minutes and W&B wants you to create an account and send your data to the cloud. So you end up writing metrics to a text file or just... not tracking anything. Then you forget which hyperparameters worked. Then you run the same failed experiment again.
|
|
125
|
+
|
|
126
|
+
**trainlog is the experiment tracker that's actually available when you need it.**
|
|
127
|
+
|
|
128
|
+
| | **trainlog** | **MLflow** | **Weights & Biases** |
|
|
129
|
+
|---|---|---|---|
|
|
130
|
+
| Setup time | **5 seconds** | ~15 minutes | ~5 minutes |
|
|
131
|
+
| Requires account | ❌ No | ❌ No | ✅ Yes |
|
|
132
|
+
| Requires running server | ❌ No | ✅ Yes | ❌ No (cloud) |
|
|
133
|
+
| Works offline | ✅ Always | ⚠️ Partial | ❌ No |
|
|
134
|
+
| Data stays local | ✅ Always | ✅ Yes | ❌ No |
|
|
135
|
+
| Live anomaly detection | ✅ Built-in | ❌ No | ⚠️ Paid |
|
|
136
|
+
| Hyperparameter suggestions | ✅ Built-in | ❌ No | ⚠️ Paid |
|
|
137
|
+
| Auto-generated reports | ✅ Built-in | ❌ No | ❌ No |
|
|
138
|
+
| Free forever | ✅ MIT | ✅ Apache | ⚠️ Usage limits |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Features you'll actually use
|
|
143
|
+
|
|
144
|
+
### ✅ Zero-friction tracking
|
|
145
|
+
Wrap any loop. Log any value. Works with every framework.
|
|
146
|
+
```python
|
|
147
|
+
import trainlog
|
|
148
|
+
|
|
149
|
+
with trainlog.run("gpt-finetune", tags=["nlp", "v3"]):
|
|
150
|
+
trainlog.log(lr=2e-5, epochs=3, model="gpt2")
|
|
151
|
+
for step, batch in enumerate(dataloader):
|
|
152
|
+
loss = model.train_step(batch)
|
|
153
|
+
trainlog.log(loss=loss.item(), step=step)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### ✅ Beautiful live dashboard
|
|
157
|
+
```bash
|
|
158
|
+
trainlog ui
|
|
159
|
+
```
|
|
160
|
+
Opens at `http://localhost:7000` — a fast, dark-mode single-page app with:
|
|
161
|
+
- Searchable run list with **inline sparkline charts** in the sidebar
|
|
162
|
+
- **Trend indicators** (↑ ↓) showing whether each metric is improving
|
|
163
|
+
- **Side-by-side comparison** of any runs you select (best value highlighted)
|
|
164
|
+
- **Auto-generated time-series charts** with gradient fills
|
|
165
|
+
- **Metric progress bars** showing where the latest value sits in its historical range
|
|
166
|
+
- Global statistics view — success rate, most-logged metrics, run timeline
|
|
167
|
+
- Auto-refresh every 5 seconds — open while training, watch it update
|
|
168
|
+
|
|
169
|
+
### ✅ Live anomaly detection — catch bad runs early
|
|
170
|
+
```python
|
|
171
|
+
trainlog.configure_watch(nan_check=True, divergence_window=5, plateau_window=15)
|
|
172
|
+
|
|
173
|
+
with trainlog.run("training"):
|
|
174
|
+
for epoch in range(100):
|
|
175
|
+
trainlog.log(loss=compute_loss())
|
|
176
|
+
# Automatically warns if: loss → NaN, loss diverges for 5 epochs,
|
|
177
|
+
# loss plateaus for 15 epochs (and suggests adjusting LR)
|
|
178
|
+
```
|
|
179
|
+
Stop wasting GPU hours on runs that are already failing.
|
|
180
|
+
|
|
181
|
+
### ✅ Hyperparameter suggestions
|
|
182
|
+
```bash
|
|
183
|
+
trainlog suggest accuracy
|
|
184
|
+
```
|
|
185
|
+
Analyzes your run history and tells you which hyperparameter values are statistically correlated with better results. No black box — plain English insights like:
|
|
186
|
+
```
|
|
187
|
+
Best config: lr=0.001 → avg accuracy 0.943 (vs 0.871 for other values, +8.2%)
|
|
188
|
+
Next experiment: try batch_size=128 — larger batches correlated with +5.1% accuracy
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### ✅ Auto-generated experiment reports
|
|
192
|
+
```bash
|
|
193
|
+
trainlog report --output results.md
|
|
194
|
+
```
|
|
195
|
+
Generates a thesis-ready markdown report with:
|
|
196
|
+
- Summary statistics (total runs, completion rate, best configurations)
|
|
197
|
+
- Chronological experiment timeline
|
|
198
|
+
- Key findings (computed automatically)
|
|
199
|
+
- Notes from all your runs
|
|
200
|
+
- Optional AI narrative: `trainlog report --ai` (uses local Ollama, no API keys)
|
|
201
|
+
|
|
202
|
+
### ✅ Generate a ready-to-run example
|
|
203
|
+
```bash
|
|
204
|
+
trainlog init # plain Python example
|
|
205
|
+
trainlog init --framework pytorch # PyTorch training loop
|
|
206
|
+
trainlog init --framework sklearn # scikit-learn grid search
|
|
207
|
+
trainlog init --framework keras # Keras callback
|
|
208
|
+
```
|
|
209
|
+
Generates a complete working script you can run immediately.
|
|
210
|
+
|
|
211
|
+
### ✅ Works with every framework
|
|
212
|
+
|
|
213
|
+
| Framework | How |
|
|
214
|
+
|-----------|-----|
|
|
215
|
+
| **PyTorch** | `trainlog.log(loss=loss.item(), acc=acc)` inside the training loop |
|
|
216
|
+
| **scikit-learn** | `trainlog.log(**params, cv_score=score)` in your hyperparam loop |
|
|
217
|
+
| **Keras / TF** | One-file `TrainlogCallback` for `model.fit()` |
|
|
218
|
+
| **HuggingFace** | Custom `TrainerCallback` — see `examples/huggingface_example.py` |
|
|
219
|
+
| **XGBoost / LightGBM** | Log in the eval callback |
|
|
220
|
+
| **JAX / Flax** | Log at end of each training step |
|
|
221
|
+
| **Plain Python** | Anything that produces a number |
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Full API reference
|
|
226
|
+
|
|
227
|
+
### Python API
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
import trainlog
|
|
231
|
+
|
|
232
|
+
# ── Tracking ──────────────────────────────────────────────────────────────────
|
|
233
|
+
with trainlog.run("name", tags=["tag1", "tag2"]) as run_id:
|
|
234
|
+
trainlog.log(accuracy=0.95, loss=0.05) # log any key-value pairs
|
|
235
|
+
trainlog.note("Cosine LR schedule helped a lot") # attach plain-text notes
|
|
236
|
+
|
|
237
|
+
trainlog.tag(run_id, "production") # add tags after the fact
|
|
238
|
+
trainlog.tag("experiment-name", "best") # also works by name
|
|
239
|
+
|
|
240
|
+
# ── Querying ──────────────────────────────────────────────────────────────────
|
|
241
|
+
runs = trainlog.get_runs() # all runs, newest first
|
|
242
|
+
best = trainlog.get_best_run("accuracy") # highest final value
|
|
243
|
+
best_low = trainlog.get_best_run("loss", mode="min") # lowest final value
|
|
244
|
+
cmp = trainlog.compare_runs(1, 2, 3) # list of run dicts
|
|
245
|
+
|
|
246
|
+
# ── Anomaly detection ─────────────────────────────────────────────────────────
|
|
247
|
+
trainlog.configure_watch(
|
|
248
|
+
nan_check=True, # warn on NaN/Inf values
|
|
249
|
+
divergence_window=5, # warn if metric diverges for N steps
|
|
250
|
+
plateau_window=15, # warn if metric plateaus for N steps
|
|
251
|
+
enabled=True,
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# Or temporarily with a context manager:
|
|
255
|
+
with trainlog.watch(divergence_window=3):
|
|
256
|
+
# stricter watch for this block
|
|
257
|
+
trainlog.log(loss=0.5)
|
|
258
|
+
|
|
259
|
+
# ── Export & analysis ─────────────────────────────────────────────────────────
|
|
260
|
+
trainlog.export_csv("results.csv")
|
|
261
|
+
trainlog.export_json("results.json")
|
|
262
|
+
trainlog.generate_report("report.md", use_ollama=False)
|
|
263
|
+
suggestions = trainlog.suggest("accuracy", mode="max", top_n=3)
|
|
264
|
+
trainlog.clear_all() # deletes everything (irreversible)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### CLI reference
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# Dashboard
|
|
271
|
+
trainlog ui # open at localhost:7000
|
|
272
|
+
trainlog ui --port 8080 --no-browser # custom port, no auto-open
|
|
273
|
+
|
|
274
|
+
# Inspect runs
|
|
275
|
+
trainlog list # rich table, newest first
|
|
276
|
+
trainlog list --limit 50
|
|
277
|
+
trainlog compare 1 2 3 # side-by-side metric comparison
|
|
278
|
+
trainlog best accuracy # best run for a metric
|
|
279
|
+
trainlog best loss --mode min
|
|
280
|
+
|
|
281
|
+
# Annotate
|
|
282
|
+
trainlog tag 42 production tuned # add tags to run #42
|
|
283
|
+
trainlog note 42 "Try cosine annealing" # add note to run #42
|
|
284
|
+
|
|
285
|
+
# Analyse
|
|
286
|
+
trainlog stats # aggregate statistics
|
|
287
|
+
trainlog suggest accuracy # hyperparameter recommendations
|
|
288
|
+
trainlog suggest loss --mode min --top 5
|
|
289
|
+
|
|
290
|
+
# Generate
|
|
291
|
+
trainlog report # write report.md
|
|
292
|
+
trainlog report -o results.md --ai # with Ollama AI narrative
|
|
293
|
+
trainlog init --framework pytorch # generate example script
|
|
294
|
+
|
|
295
|
+
# Export / clean
|
|
296
|
+
trainlog export --format csv -o data.csv
|
|
297
|
+
trainlog export --format json -o data.json
|
|
298
|
+
trainlog clear # delete all (asks confirmation)
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## How it works
|
|
304
|
+
|
|
305
|
+
- **SQLite** — `~/.trainlog/experiments.db`. One file. No server. Inspect it with any SQLite browser. Back it up with `cp`.
|
|
306
|
+
- **Flask** — the dashboard is a local Flask server. Vanilla JS, Chart.js, zero npm, zero build step.
|
|
307
|
+
- **Thread-local state** — each training job in its own thread gets an isolated run context. Concurrent experiments just work.
|
|
308
|
+
- **Git-aware** — captures the current commit hash via `git rev-parse HEAD`. Silently skipped outside a git repo.
|
|
309
|
+
- **Watch hooks** — anomaly detection runs inside every `log()` call. Zero external services, works offline.
|
|
310
|
+
|
|
311
|
+
---
|
|
312
|
+
|
|
313
|
+
## Quickstart with examples
|
|
314
|
+
|
|
315
|
+
```bash
|
|
316
|
+
trainlog init --framework pytorch -o train.py
|
|
317
|
+
python train.py
|
|
318
|
+
trainlog ui
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
That's the whole flow. Five commands. Zero config.
|
|
322
|
+
|
|
323
|
+
---
|
|
324
|
+
|
|
325
|
+
## Roadmap
|
|
326
|
+
|
|
327
|
+
**Done ✅**
|
|
328
|
+
- Live anomaly detection (`configure_watch`)
|
|
329
|
+
- Auto-generated experiment reports (`trainlog report`, Ollama support)
|
|
330
|
+
- Hyperparameter suggestions (`trainlog suggest`)
|
|
331
|
+
- Quick-start example generator (`trainlog init`)
|
|
332
|
+
- Sparkline charts in sidebar with trend indicators
|
|
333
|
+
- Metric progress bars and trend arrows in detail view
|
|
334
|
+
- Framework examples: PyTorch, scikit-learn, Keras, HuggingFace
|
|
335
|
+
|
|
336
|
+
**Coming up**
|
|
337
|
+
- [ ] `trainlog.log_artifact("model.pt")` — save file paths alongside metrics
|
|
338
|
+
- [ ] Native PyTorch `TrainlogCallback` (pip-installable plugin)
|
|
339
|
+
- [ ] VS Code extension — inline run summary on hover
|
|
340
|
+
- [ ] `trainlog serve` — shareable read-only dashboard URL (ngrok/localtunnel)
|
|
341
|
+
- [ ] Team sync via shared git-tracked SQLite
|
|
342
|
+
- [ ] Slack / Discord webhook on run completion
|
|
343
|
+
|
|
344
|
+
Have an idea? [Open a feature request](https://github.com/NaiaLorente/datalog/issues/new) — or submit a PR.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Contributing
|
|
349
|
+
|
|
350
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md). TL;DR: `pip install -e .`, make your change, open a PR.
|
|
351
|
+
|
|
352
|
+
All contributions welcome — typos, docs, features, bug fixes.
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## License
|
|
357
|
+
|
|
358
|
+
MIT — use it however you want, forever.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
trainlog/__init__.py,sha256=ZXSeUsbzPhBdAja9AVUDcOewknZ-Ab4bFB6Kcgf8_8g,447
|
|
2
|
+
trainlog/cli.py,sha256=RhDtsfSNrciidL2bak6gUp4x_pSeBdVrogzUdH0Lcjo,20927
|
|
3
|
+
trainlog/core.py,sha256=LJx52c6X-tod2IV-rpJxdgTOvqZv2bpniqTVSsaCWS8,38849
|
|
4
|
+
trainlog/dashboard/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
trainlog/dashboard/server.py,sha256=EME-fZAjRCsaSJc7Zfu1IlwEYHWXXBnRe47I1grLs7A,5709
|
|
6
|
+
trainlog/dashboard/templates/index.html,sha256=3XsHJoBhmx7ttNROMHqdAkETARci_ayfFYW1QtP_12A,51787
|
|
7
|
+
mltrackr-0.3.0.dist-info/METADATA,sha256=L-GjoaJXSTiSOVMsxm57BIEhzIxhNLrmQxvLkgkMKdw,14097
|
|
8
|
+
mltrackr-0.3.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
9
|
+
mltrackr-0.3.0.dist-info/entry_points.txt,sha256=sOTYOsdc3BBNu5qqQsOScAFRbjN-YyO4ReGQLdfs3tM,46
|
|
10
|
+
mltrackr-0.3.0.dist-info/top_level.txt,sha256=q9N7aVrJR-Ox3UAxVZBBAmgmRGIa6qfitE-kpS_j5_A,9
|
|
11
|
+
mltrackr-0.3.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
trainlog
|
trainlog/__init__.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .core import (
|
|
2
|
+
run, log, note, tag,
|
|
3
|
+
get_runs, get_best_run, compare_runs, get_stats,
|
|
4
|
+
export_csv, export_json, clear_all,
|
|
5
|
+
generate_report, configure_watch, watch, suggest,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"run", "log", "note", "tag",
|
|
10
|
+
"get_runs", "get_best_run", "compare_runs", "get_stats",
|
|
11
|
+
"export_csv", "export_json", "clear_all",
|
|
12
|
+
"generate_report", "configure_watch", "watch", "suggest",
|
|
13
|
+
]
|
|
14
|
+
__version__ = "0.3.0"
|