Skip to content

Commit 01dfb22

Browse files
committed
"linter fix"
1 parent 0316eaa commit 01dfb22

12 files changed

Lines changed: 448 additions & 233 deletions

sdks/python/sdk/src/moss/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@
2424
IndexInfo,
2525
IndexStatus,
2626
IndexStatusValues,
27-
ModelRef,
28-
MutationOptions,
29-
MutationResult,
30-
JobStatus,
3127
JobPhase,
3228
JobProgress,
29+
JobStatus,
3330
JobStatusResponse,
31+
ModelRef,
32+
MutationOptions,
33+
MutationResult,
3434
QueryResultDocumentInfo,
3535
SearchResult,
3636
)

sdks/python/sdk/src/moss/__init__.pyi

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,89 +2,73 @@ from __future__ import annotations
22

33
from typing import ClassVar, Dict, List, Optional, Sequence
44

5-
65
class MossClient:
76
"""Semantic search client for vector similarity operations."""
87

98
DEFAULT_MODEL_ID: ClassVar[str]
109

1110
def __init__(self, project_id: str, project_key: str) -> None: ...
12-
1311
async def create_index(
1412
self,
1513
name: str,
1614
docs: List[DocumentInfo],
1715
model_id: Optional[str] = ...,
1816
) -> MutationResult: ...
19-
2017
async def add_docs(
2118
self,
2219
name: str,
2320
docs: List[DocumentInfo],
2421
options: Optional[MutationOptions] = None,
2522
) -> MutationResult: ...
26-
2723
async def delete_docs(
2824
self,
2925
name: str,
3026
doc_ids: List[str],
3127
) -> MutationResult: ...
32-
3328
async def get_job_status(self, job_id: str) -> JobStatusResponse: ...
34-
3529
async def get_index(self, name: str) -> IndexInfo: ...
36-
3730
async def list_indexes(self) -> List[IndexInfo]: ...
38-
3931
async def delete_index(self, name: str) -> bool: ...
40-
4132
async def get_docs(
4233
self,
4334
name: str,
4435
options: Optional[GetDocumentsOptions] = None,
4536
) -> List[DocumentInfo]: ...
46-
4737
async def load_index(
4838
self,
4939
name: str,
5040
auto_refresh: bool = False,
5141
polling_interval_in_seconds: int = 600,
5242
) -> str: ...
53-
5443
async def unload_index(self, name: str) -> None: ...
55-
5644
async def query(
5745
self,
5846
name: str,
5947
query: str,
6048
options: Optional[QueryOptions] = None,
6149
) -> SearchResult: ...
6250

63-
6451
class MutationResult:
6552
"""Return value from create_index/add_docs/delete_docs."""
6653

6754
job_id: str
6855
index_name: str
6956
doc_count: int
7057

71-
7258
class MutationOptions:
7359
"""Options for add_docs (e.g. upsert behavior)."""
7460

7561
upsert: Optional[bool]
7662

7763
def __init__(self, upsert: Optional[bool] = None) -> None: ...
7864

79-
8065
class GetDocumentsOptions:
8166
"""Options for get_docs (e.g. filter by document IDs)."""
8267

8368
doc_ids: Optional[List[str]]
8469

8570
def __init__(self, doc_ids: Optional[List[str]] = None) -> None: ...
8671

87-
8872
class JobStatus:
8973
"""Enum-like class for job status values."""
9074

@@ -96,7 +80,6 @@ class JobStatus:
9680

9781
value: str
9882

99-
10083
class JobPhase:
10184
"""Enum-like class for job phase values."""
10285

@@ -109,7 +92,6 @@ class JobPhase:
10992

11093
value: str
11194

112-
11395
class JobProgress:
11496
"""Progress update for a job."""
11597

@@ -118,7 +100,6 @@ class JobProgress:
118100
progress: float
119101
current_phase: Optional[JobPhase]
120102

121-
122103
class JobStatusResponse:
123104
"""Full status response from get_job_status."""
124105

@@ -131,13 +112,11 @@ class JobStatusResponse:
131112
updated_at: str
132113
completed_at: Optional[str]
133114

134-
135115
class ModelRef:
136116
id: str
137117
version: str
138118
def __init__(self, id: str, version: str) -> None: ...
139119

140-
141120
class QueryResultDocumentInfo:
142121
id: str
143122
text: str
@@ -151,7 +130,6 @@ class QueryResultDocumentInfo:
151130
score: float = ...,
152131
) -> None: ...
153132

154-
155133
class DocumentInfo:
156134
id: str
157135
text: str
@@ -165,7 +143,6 @@ class DocumentInfo:
165143
embedding: Optional[Sequence[float]] = ...,
166144
) -> None: ...
167145

168-
169146
class QueryOptions:
170147
embedding: Optional[Sequence[float]]
171148
top_k: Optional[int]
@@ -185,7 +162,6 @@ class QueryOptions:
185162
rerank_model: Optional[str] = ...,
186163
) -> None: ...
187164

188-
189165
class IndexInfo:
190166
id: str
191167
name: str
@@ -207,7 +183,6 @@ class IndexInfo:
207183
model: ModelRef,
208184
) -> None: ...
209185

210-
211186
class SearchResult:
212187
docs: List[QueryResultDocumentInfo]
213188
query: str
@@ -221,15 +196,13 @@ class SearchResult:
221196
time_taken_ms: Optional[int] = None,
222197
) -> None: ...
223198

224-
225199
class IndexStatus:
226200
NotStarted: ClassVar[str]
227201
Building: ClassVar[str]
228202
Ready: ClassVar[str]
229203
Failed: ClassVar[str]
230204
def __init__(self, value: str) -> None: ...
231205

232-
233206
IndexStatusValues: Dict[str, str]
234207

235208
__version__: str

sdks/python/sdk/src/moss/client/moss_client.py

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,29 @@
44
import logging
55
import os
66
import uuid
7-
from typing import Any, Dict, List, Optional
7+
from typing import Any, ClassVar, Dict, List, Optional, Sequence
88

99
import httpx
1010
from moss_core import (
1111
CLOUD_API_MANAGE_URL,
12-
ManageClient,
1312
DocumentInfo,
1413
GetDocumentsOptions,
1514
IndexInfo,
1615
IndexManager,
16+
JobStatusResponse,
17+
ManageClient,
1718
MutationOptions,
1819
MutationResult,
19-
JobStatusResponse,
2020
QueryResultDocumentInfo,
2121
SearchResult,
2222
)
2323

2424
logger = logging.getLogger(__name__)
2525

26-
from typing import Sequence
2726

2827
class QueryOptions:
2928
"""Options for search queries."""
29+
3030
def __init__(
3131
self,
3232
embedding: Optional[Sequence[float]] = None,
@@ -37,16 +37,31 @@ def __init__(
3737
rerank_top_k: Optional[int] = None,
3838
rerank_model: Optional[str] = None,
3939
):
40+
if top_k is not None and (not isinstance(top_k, int) or top_k < 1):
41+
raise ValueError("top_k must be an integer >= 1")
42+
if alpha is not None and (
43+
not isinstance(alpha, (int, float)) or not (0.0 <= alpha <= 1.0)
44+
):
45+
raise ValueError("alpha must be a float between 0.0 and 1.0")
46+
if embedding is not None:
47+
try:
48+
embedding = [float(x) for x in embedding]
49+
except (TypeError, ValueError):
50+
raise ValueError("embedding must be a sequence of numbers")
51+
if rerank_top_k is not None and (
52+
not isinstance(rerank_top_k, int) or rerank_top_k < 1
53+
):
54+
raise ValueError("rerank_top_k must be an integer >= 1")
55+
4056
self.embedding = embedding
4157
self.top_k = top_k
42-
self.alpha = alpha
58+
self.alpha = float(alpha) if alpha is not None else None
4359
self.filter = filter
44-
self.rerank = rerank
60+
self.rerank = bool(rerank)
4561
self.rerank_top_k = rerank_top_k
4662
self.rerank_model = rerank_model
4763

4864

49-
5065
def _get_manage_url() -> str:
5166
"""Manage URL, overridable via env for local development."""
5267
return os.getenv("MOSS_CLOUD_API_MANAGE_URL", CLOUD_API_MANAGE_URL)
@@ -83,6 +98,7 @@ class MossClient:
8398
"""
8499

85100
DEFAULT_MODEL_ID = "moss-minilm"
101+
_cross_encoder_cache: ClassVar[Dict[str, Any]] = {}
86102

87103
def __init__(self, project_id: str, project_key: str) -> None:
88104
self._project_id = project_id
@@ -215,8 +231,10 @@ async def query(
215231
"""
216232
is_loaded = await asyncio.to_thread(self._manager.has_index, name)
217233

218-
rerank = getattr(options, "rerank", False)
219-
override_top_k = getattr(options, "rerank_top_k", 50) if rerank else None
234+
rerank = getattr(options, "rerank", False) is True
235+
override_top_k = (
236+
(getattr(options, "rerank_top_k", None) or 50) if rerank else None
237+
)
220238

221239
if is_loaded:
222240
result = await self._query_local(name, query, options, override_top_k)
@@ -228,10 +246,10 @@ async def query(
228246
name,
229247
)
230248
result = await self._query_cloud(name, query, options, override_top_k)
231-
249+
232250
if rerank:
233251
result = await self._rerank_results(query, result, options)
234-
252+
235253
return result
236254

237255
# -- Internal ---------------------------------------------------
@@ -243,7 +261,11 @@ async def _query_local(
243261
options: Optional[QueryOptions],
244262
override_top_k: Optional[int] = None,
245263
) -> SearchResult:
246-
top_k = override_top_k if override_top_k is not None else (getattr(options, "top_k", None) or 5)
264+
top_k = (
265+
override_top_k
266+
if override_top_k is not None
267+
else (getattr(options, "top_k", None) or 5)
268+
)
247269
alpha = getattr(options, "alpha", None)
248270
if alpha is None:
249271
alpha = 0.8
@@ -286,7 +308,11 @@ async def _query_cloud(
286308
override_top_k: Optional[int] = None,
287309
) -> SearchResult:
288310
"""Fallback: query via the cloud API when the index is not loaded locally."""
289-
top_k = override_top_k if override_top_k is not None else (getattr(options, "top_k", None) or 10)
311+
top_k = (
312+
override_top_k
313+
if override_top_k is not None
314+
else (getattr(options, "top_k", None) or 10)
315+
)
290316
query_embedding = getattr(options, "embedding", None)
291317

292318
request_body: Dict[str, Any] = {
@@ -346,32 +372,37 @@ async def _rerank_results(
346372
"Install it with: pip install 'moss[rerank]'"
347373
)
348374

349-
model_name = getattr(options, "rerank_model", None) or "cross-encoder/ms-marco-MiniLM-L-6-v2"
375+
model_name = (
376+
getattr(options, "rerank_model", None)
377+
or "cross-encoder/ms-marco-MiniLM-L-6-v2"
378+
)
350379

351-
def do_rerank():
380+
def do_rerank() -> SearchResult:
352381
if not hasattr(self.__class__, "_cross_encoder_cache"):
353382
self.__class__._cross_encoder_cache = {}
354383

355384
if model_name not in self.__class__._cross_encoder_cache:
356-
self.__class__._cross_encoder_cache[model_name] = CrossEncoder(model_name)
385+
self.__class__._cross_encoder_cache[model_name] = CrossEncoder(
386+
model_name
387+
)
357388

358389
model = self.__class__._cross_encoder_cache[model_name]
359390

360-
pairs = [[query, doc.text] for doc in search_result.docs]
391+
local_docs = search_result.docs
392+
pairs = [[query, doc.text] for doc in local_docs]
361393
scores = model.predict(pairs)
362394

363-
for doc, score in zip(search_result.docs, scores):
395+
for doc, score in zip(local_docs, scores):
364396
doc.score = float(score)
365397

366-
search_result.docs.sort(key=lambda d: d.score, reverse=True)
398+
local_docs.sort(key=lambda d: d.score, reverse=True)
367399

368400
original_top_k = getattr(options, "top_k", None) or 5
369-
search_result.docs = search_result.docs[:original_top_k]
401+
search_result.docs = local_docs[:original_top_k]
370402
return search_result
371403

372404
return await asyncio.to_thread(do_rerank)
373405

374-
375406
def _resolve_model_id(
376407
self,
377408
docs: List[DocumentInfo],

sdks/python/sdk/tests/conftest.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@
66
import os
77
import warnings
88
from pathlib import Path
9-
109
from unittest.mock import MagicMock, patch
1110

12-
from moss import MossClient
13-
1411
import pytest
1512
from dotenv import load_dotenv
1613

14+
from moss import MossClient
15+
1716
# Load .env from project root.
1817
project_env_path = Path(__file__).parent.parent / ".env"
1918
load_dotenv(project_env_path)

0 commit comments

Comments
 (0)