mst-python 0.5.0__cp311-cp311-macosx_26_0_universal2.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.
- mst/__init__.py +68 -0
- mst/_mst.cpython-311-darwin.so +0 -0
- mst/_mst.so +0 -0
- mst_python-0.5.0.dist-info/METADATA +136 -0
- mst_python-0.5.0.dist-info/RECORD +7 -0
- mst_python-0.5.0.dist-info/WHEEL +5 -0
- mst_python-0.5.0.dist-info/top_level.txt +1 -0
mst/__init__.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""mst: CGO Python bindings for mst (Meta-Search Tool).
|
|
2
|
+
|
|
3
|
+
Concurrent multi-engine web search with RRF ranking, zero subprocess overhead.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
import mst
|
|
7
|
+
|
|
8
|
+
result = mst.search("rust async runtime comparison")
|
|
9
|
+
for item in result["results"]:
|
|
10
|
+
print(f"{item['rank']}. {item['title']}")
|
|
11
|
+
|
|
12
|
+
engines = mst.list_engines()
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import asyncio
|
|
16
|
+
|
|
17
|
+
from ._mst import MSTError, list_engines, search
|
|
18
|
+
|
|
19
|
+
__all__ = ["search", "search_async", "list_engines", "MSTError"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
async def search_async(
|
|
23
|
+
query: str,
|
|
24
|
+
engines=None,
|
|
25
|
+
limit: int = 10,
|
|
26
|
+
offset: int = 0,
|
|
27
|
+
rrf_k: int = 60,
|
|
28
|
+
timeout: str = "8s",
|
|
29
|
+
weights=None,
|
|
30
|
+
) -> dict:
|
|
31
|
+
"""Async wrapper around :func:`search`.
|
|
32
|
+
|
|
33
|
+
The native CGO call is blocking (the Go runtime releases the GIL while it
|
|
34
|
+
runs), so this thin wrapper offloads it to the event loop's default executor
|
|
35
|
+
via :func:`asyncio.to_thread`. It returns the same envelope and raises the
|
|
36
|
+
same :class:`MSTError` as :func:`search`.
|
|
37
|
+
|
|
38
|
+
This is intentionally *not* a second search implementation: every argument
|
|
39
|
+
is forwarded unchanged.
|
|
40
|
+
"""
|
|
41
|
+
return await asyncio.to_thread(
|
|
42
|
+
search,
|
|
43
|
+
query,
|
|
44
|
+
engines=engines,
|
|
45
|
+
limit=limit,
|
|
46
|
+
offset=offset,
|
|
47
|
+
rrf_k=rrf_k,
|
|
48
|
+
timeout=timeout,
|
|
49
|
+
weights=weights,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
# Reflect the installed distribution version (populated by setup.py from the
|
|
53
|
+
# release tag). Falls back when run from a source tree that isn't installed.
|
|
54
|
+
try:
|
|
55
|
+
from importlib.metadata import PackageNotFoundError, version as _dist_version
|
|
56
|
+
|
|
57
|
+
# The PyPI distribution is `mst-python` while the import package is `mst`;
|
|
58
|
+
# accept either name so editable/source installs and wheels both work.
|
|
59
|
+
for _dist in ("mst-python", "mst"):
|
|
60
|
+
try:
|
|
61
|
+
__version__ = _dist_version(_dist)
|
|
62
|
+
break
|
|
63
|
+
except PackageNotFoundError:
|
|
64
|
+
continue
|
|
65
|
+
else:
|
|
66
|
+
__version__ = "0.0.0-dev"
|
|
67
|
+
except ImportError: # Python <3.8 (unsupported, but stay safe)
|
|
68
|
+
__version__ = "0.0.0-dev"
|
|
Binary file
|
mst/_mst.so
ADDED
|
Binary file
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mst-python
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: CGO Python bindings for mst (Meta-Search Tool) — concurrent multi-engine web search with RRF ranking
|
|
5
|
+
Author: mst contributors
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: Intended Audience :: Developers
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Requires-Python: >=3.11
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
15
|
+
|
|
16
|
+
# mst-python — Meta Search Tool (Python bindings)
|
|
17
|
+
|
|
18
|
+
[](https://github.com/openmtx/meta-search-tool/actions/workflows/release.yml)
|
|
19
|
+
[](https://pypi.org/project/mst-python/)
|
|
20
|
+
[](https://pypi.org/project/mst-python/)
|
|
21
|
+
|
|
22
|
+
CGO Python bindings for **mst** — a concurrent multi-engine web search tool with
|
|
23
|
+
transparent RRF ranking. Fan out to 12+ engines in parallel, get merged JSON
|
|
24
|
+
results with scores. No server, no setup.
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import mst
|
|
28
|
+
|
|
29
|
+
# Search across all enabled engines
|
|
30
|
+
result = mst.search("rust async runtime comparison")
|
|
31
|
+
|
|
32
|
+
# Or pick specific engines
|
|
33
|
+
result = mst.search("riscv paging", engines=["ddg", "google"], limit=10)
|
|
34
|
+
|
|
35
|
+
print(f"Found {len(result['results'])} results in {result['took_ms']}ms")
|
|
36
|
+
for r in result['results']:
|
|
37
|
+
print(f" #{r['rank']} {r['title']} (score={r['score']})")
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
- **14 engines** across general web, academic, reference, Q&A, and AI categories
|
|
43
|
+
- **Concurrent fan-out** with per-engine timeouts — a slow engine never blocks the run
|
|
44
|
+
- **RRF ranking** with configurable per-engine weights and smoothing constant
|
|
45
|
+
- **Keyless engines** work out of the box: DuckDuckGo, Google, Wikipedia, arXiv, Europe PMC, and more
|
|
46
|
+
- **Keyed engines** (Brave, Bing, Tavily, Jina) ready when you set their API keys
|
|
47
|
+
- **Async API** (`search_async`) for asyncio consumers; the native call releases the GIL
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install mst-python
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Works on Linux (manylinux_2_34 x86_64) and macOS (Apple Silicon arm64).
|
|
56
|
+
|
|
57
|
+
## Quick start
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import mst
|
|
61
|
+
|
|
62
|
+
# List all engines and their status
|
|
63
|
+
engines = mst.list_engines()
|
|
64
|
+
for e in engines:
|
|
65
|
+
print(f"{e['name']:20s} {e['status']:15s} weight={e['weight']}")
|
|
66
|
+
|
|
67
|
+
# Run a search
|
|
68
|
+
result = mst.search("python asyncio vs threading", limit=5)
|
|
69
|
+
print(result)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## API
|
|
73
|
+
|
|
74
|
+
### `mst.search(query, engines=None, limit=10, offset=0, rrf_k=60, timeout="8s", weights=None)`
|
|
75
|
+
|
|
76
|
+
| Param | Type | Default | Description |
|
|
77
|
+
|-------|------|---------|-------------|
|
|
78
|
+
| `query` | `str` | — | Search query |
|
|
79
|
+
| `engines` | `list[str]` or `None` | `None` | Engine whitelist (`None` = all enabled engines) |
|
|
80
|
+
| `limit` | `int` | `10` | Max merged results (1–100) |
|
|
81
|
+
| `offset` | `int` | `0` | Skip first N results |
|
|
82
|
+
| `rrf_k` | `int` | `60` | RRF smoothing constant |
|
|
83
|
+
| `timeout` | `str` | `"8s"` | Per-engine timeout duration |
|
|
84
|
+
| `weights` | `dict[str, float]` or `None` | `None` | Per-engine weight overrides |
|
|
85
|
+
|
|
86
|
+
Returns a dict with `query`, `took_ms`, `results` (list of ranked results).
|
|
87
|
+
|
|
88
|
+
### `await mst.search_async(...)`
|
|
89
|
+
|
|
90
|
+
Async wrapper around `mst.search()` with the same arguments, return value, and
|
|
91
|
+
`MSTError` behavior. It is **additive**: existing consumers that call
|
|
92
|
+
`asyncio.to_thread(mst.search, ...)` keep working and can adopt the wrapper
|
|
93
|
+
later without a breaking change. It forwards the blocking native call to
|
|
94
|
+
`asyncio.to_thread`, so the event loop keeps running during a search. The native
|
|
95
|
+
CGO library releases the GIL, so concurrent `search_async()` calls overlap
|
|
96
|
+
instead of serializing.
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
import asyncio
|
|
100
|
+
import mst
|
|
101
|
+
|
|
102
|
+
async def main():
|
|
103
|
+
results = await asyncio.gather(
|
|
104
|
+
mst.search_async("rust async", limit=5),
|
|
105
|
+
mst.search_async("python asyncio", limit=5),
|
|
106
|
+
mst.search_async("go concurrency", limit=5),
|
|
107
|
+
)
|
|
108
|
+
for result in results:
|
|
109
|
+
print(result["query"], len(result["results"]))
|
|
110
|
+
|
|
111
|
+
asyncio.run(main())
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Cancellation note: `asyncio.wait_for(asyncio.shield(...))` and task cancellation
|
|
115
|
+
stop the *await*, not the native call. The `timeout` argument bounds the Go-side
|
|
116
|
+
search; a cancelled worker may finish in the background, and subsequent calls
|
|
117
|
+
are unaffected.
|
|
118
|
+
|
|
119
|
+
### `mst.list_engines()`
|
|
120
|
+
|
|
121
|
+
Returns a list of engine dicts with `name`, `enabled`, `keyed`, `weight`, `category`, `status`.
|
|
122
|
+
|
|
123
|
+
### `mst.__version__`
|
|
124
|
+
|
|
125
|
+
Package version string (derived from the release tag when installed via PyPI).
|
|
126
|
+
|
|
127
|
+
## Requirements
|
|
128
|
+
|
|
129
|
+
- Python ≥ 3.11
|
|
130
|
+
- Linux (x86_64, glibc ≥ 2.34) or macOS (arm64)
|
|
131
|
+
|
|
132
|
+
No runtime dependencies — the CGO shared library is bundled in the wheel.
|
|
133
|
+
|
|
134
|
+
## License
|
|
135
|
+
|
|
136
|
+
Apache-2.0. See [`LICENSE`](https://github.com/openmtx/meta-search-tool/blob/master/LICENSE).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
mst/__init__.py,sha256=4MfzqZrtwPVQ_HelYZZtRKOMEZAH2CKB9knJhY-L30w,2018
|
|
2
|
+
mst/_mst.cpython-311-darwin.so,sha256=TIN5FQtf4L93mToIvSO5xkwl9U_-qd5-3b5gBz_0_gY,242488
|
|
3
|
+
mst/_mst.so,sha256=tgYbTzOWImAb4wLE3foaZYYd-DUp2N2fVtn5h2aC7UU,8112162
|
|
4
|
+
mst_python-0.5.0.dist-info/METADATA,sha256=7CWAWi-5VaxLhA4Q_NwLLIKYkrL978jVuV2lOLA4ons,4876
|
|
5
|
+
mst_python-0.5.0.dist-info/WHEEL,sha256=_qm6y1zAa80MnyE0XHj_erdX4-_--_YglqQ_pu58BjM,114
|
|
6
|
+
mst_python-0.5.0.dist-info/top_level.txt,sha256=wWnObFIH0CbsgenDXlDpKZv1zdBkbCM4iASswi0Vofw,4
|
|
7
|
+
mst_python-0.5.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mst
|