code-analysis-client 1.6.65__tar.gz → 1.6.67__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.
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/PKG-INFO +28 -3
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/README.md +27 -2
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/__init__.py +12 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/client.py +241 -21
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/queue_wait.py +52 -0
- code_analysis_client-1.6.67/code_analysis_client/version.txt +1 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client.egg-info/PKG-INFO +28 -3
- code_analysis_client-1.6.65/code_analysis_client/version.txt +0 -1
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/commands_proxy.py +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/config.py +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/exceptions.py +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/file_session.py +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/py.typed +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/responses.py +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/server_api.py +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/server_schema.py +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/universal_file.py +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/validation.py +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client.egg-info/SOURCES.txt +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client.egg-info/dependency_links.txt +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client.egg-info/requires.txt +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client.egg-info/top_level.txt +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/pyproject.toml +0 -0
- {code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-analysis-client
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.67
|
|
4
4
|
Summary: Async JSON-RPC client for the code-analysis MCP server (mcp-proxy-adapter JsonRpcClient)
|
|
5
5
|
Author-email: Vasiliy Zdanovskiy <vasilyvz@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -85,9 +85,34 @@ counterparts): `timeout` (seconds, default `None` = wait until terminal),
|
|
|
85
85
|
`poll_interval` (seconds between polls, default `1.0`), `status_hook` (sync or
|
|
86
86
|
async callable invoked with each poll's status dict).
|
|
87
87
|
|
|
88
|
+
`call` / `call_validated` also take `auto_poll` (default `True`, matching the
|
|
89
|
+
behavior above exactly). Pass `auto_poll=False` to opt out of automatic
|
|
90
|
+
polling: a non-queued response still comes back as the plain domain result,
|
|
91
|
+
but a queued-job response comes back immediately as a `QueuedJob` handle
|
|
92
|
+
instead of blocking until the job finishes.
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from code_analysis_client import QueuedJob
|
|
96
|
+
|
|
97
|
+
result = await client.call("some_long_running_command", {...}, auto_poll=False)
|
|
98
|
+
if isinstance(result, QueuedJob):
|
|
99
|
+
# do other work here, then block on it whenever you're ready
|
|
100
|
+
result = await result.wait()
|
|
101
|
+
# `result` is now the same dict shape a default (auto_poll=True) call returns
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`QueuedJob` exposes `.job_id`, `.envelope` (the raw queue-service response),
|
|
105
|
+
and two async methods: `.wait(timeout=None, poll_interval=1.0, status_hook=None)`
|
|
106
|
+
— polls to completion and returns/raises exactly like the default path — and
|
|
107
|
+
`.status()` — a single `queue_get_job_status` fetch without polling to
|
|
108
|
+
completion.
|
|
109
|
+
|
|
88
110
|
`call_unified` / `call_unified_validated` are kept as **deprecated aliases** of
|
|
89
|
-
`call` / `call_validated` for backward compatibility
|
|
90
|
-
`
|
|
111
|
+
`call` / `call_validated` for backward compatibility and emit
|
|
112
|
+
`DeprecationWarning` on every call. `expect_queue` remains accepted-and-ignored
|
|
113
|
+
(documented no-op). `auto_poll` is the one canonical switch and is forwarded
|
|
114
|
+
straight through to `call` / `call_validated` — `auto_poll=False` on an alias
|
|
115
|
+
returns a `QueuedJob` the same way it does on the non-deprecated method.
|
|
91
116
|
Prefer `call` / `call_validated` directly.
|
|
92
117
|
|
|
93
118
|
## Validation using the server schema
|
|
@@ -73,9 +73,34 @@ counterparts): `timeout` (seconds, default `None` = wait until terminal),
|
|
|
73
73
|
`poll_interval` (seconds between polls, default `1.0`), `status_hook` (sync or
|
|
74
74
|
async callable invoked with each poll's status dict).
|
|
75
75
|
|
|
76
|
+
`call` / `call_validated` also take `auto_poll` (default `True`, matching the
|
|
77
|
+
behavior above exactly). Pass `auto_poll=False` to opt out of automatic
|
|
78
|
+
polling: a non-queued response still comes back as the plain domain result,
|
|
79
|
+
but a queued-job response comes back immediately as a `QueuedJob` handle
|
|
80
|
+
instead of blocking until the job finishes.
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from code_analysis_client import QueuedJob
|
|
84
|
+
|
|
85
|
+
result = await client.call("some_long_running_command", {...}, auto_poll=False)
|
|
86
|
+
if isinstance(result, QueuedJob):
|
|
87
|
+
# do other work here, then block on it whenever you're ready
|
|
88
|
+
result = await result.wait()
|
|
89
|
+
# `result` is now the same dict shape a default (auto_poll=True) call returns
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`QueuedJob` exposes `.job_id`, `.envelope` (the raw queue-service response),
|
|
93
|
+
and two async methods: `.wait(timeout=None, poll_interval=1.0, status_hook=None)`
|
|
94
|
+
— polls to completion and returns/raises exactly like the default path — and
|
|
95
|
+
`.status()` — a single `queue_get_job_status` fetch without polling to
|
|
96
|
+
completion.
|
|
97
|
+
|
|
76
98
|
`call_unified` / `call_unified_validated` are kept as **deprecated aliases** of
|
|
77
|
-
`call` / `call_validated` for backward compatibility
|
|
78
|
-
`
|
|
99
|
+
`call` / `call_validated` for backward compatibility and emit
|
|
100
|
+
`DeprecationWarning` on every call. `expect_queue` remains accepted-and-ignored
|
|
101
|
+
(documented no-op). `auto_poll` is the one canonical switch and is forwarded
|
|
102
|
+
straight through to `call` / `call_validated` — `auto_poll=False` on an alias
|
|
103
|
+
returns a `QueuedJob` the same way it does on the non-deprecated method.
|
|
79
104
|
Prefer `call` / `call_validated` directly.
|
|
80
105
|
|
|
81
106
|
## Validation using the server schema
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/__init__.py
RENAMED
|
@@ -24,6 +24,13 @@ from code_analysis_client.exceptions import (
|
|
|
24
24
|
QueueJobError,
|
|
25
25
|
)
|
|
26
26
|
from code_analysis_client.file_session import FileSessionClient, SessionNotFoundError
|
|
27
|
+
from code_analysis_client.queue_wait import (
|
|
28
|
+
QueuedJob,
|
|
29
|
+
extract_job_id,
|
|
30
|
+
is_queued_envelope,
|
|
31
|
+
unwrap_job_result,
|
|
32
|
+
wait_for_job,
|
|
33
|
+
)
|
|
27
34
|
from code_analysis_client.server_api import (
|
|
28
35
|
CLIENT_FACADE_COMMANDS,
|
|
29
36
|
CST_REMOVED_COMMANDS,
|
|
@@ -57,6 +64,7 @@ __all__ = [
|
|
|
57
64
|
"JobTimeoutError",
|
|
58
65
|
"LEGACY_REMOVED_COMMANDS",
|
|
59
66
|
"QueueJobError",
|
|
67
|
+
"QueuedJob",
|
|
60
68
|
"REMOVED_COMMANDS",
|
|
61
69
|
"SessionNotFoundError",
|
|
62
70
|
"TRANSFER_FACADE_METHODS",
|
|
@@ -65,11 +73,15 @@ __all__ = [
|
|
|
65
73
|
"ValidatedCommandsProxy",
|
|
66
74
|
"adapter_settings_from_server_config",
|
|
67
75
|
"adapter_settings_to_jsonrpc_kwargs",
|
|
76
|
+
"extract_job_id",
|
|
68
77
|
"fetch_command_schema_from_server",
|
|
78
|
+
"is_queued_envelope",
|
|
69
79
|
"load_server_config",
|
|
70
80
|
"parse_schema_from_help_payload",
|
|
71
81
|
"prepare_params_for_schema",
|
|
82
|
+
"unwrap_job_result",
|
|
72
83
|
"validate_params_against_schema",
|
|
84
|
+
"wait_for_job",
|
|
73
85
|
]
|
|
74
86
|
|
|
75
87
|
|
|
@@ -7,8 +7,9 @@ email: vasilyvz@gmail.com
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
import warnings
|
|
10
11
|
from pathlib import Path
|
|
11
|
-
from typing import Any, Dict, Mapping, Optional
|
|
12
|
+
from typing import Any, Dict, Literal, Mapping, Optional, Union, overload
|
|
12
13
|
|
|
13
14
|
try:
|
|
14
15
|
from mcp_proxy_adapter.client.jsonrpc_client.client import JsonRpcClient
|
|
@@ -23,6 +24,7 @@ from code_analysis_client.config import (
|
|
|
23
24
|
)
|
|
24
25
|
from code_analysis_client.file_session import FileSessionClient
|
|
25
26
|
from code_analysis_client.queue_wait import (
|
|
27
|
+
QueuedJob,
|
|
26
28
|
StatusHook,
|
|
27
29
|
extract_job_id,
|
|
28
30
|
is_queued_envelope,
|
|
@@ -154,19 +156,28 @@ class CodeAnalysisAsyncClient:
|
|
|
154
156
|
params: Optional[Dict[str, Any]] = None,
|
|
155
157
|
*,
|
|
156
158
|
use_cmd_endpoint: bool = False,
|
|
159
|
+
auto_poll: bool = True,
|
|
157
160
|
timeout: Optional[float] = None,
|
|
158
161
|
poll_interval: float = 1.0,
|
|
159
162
|
status_hook: Optional[StatusHook] = None,
|
|
160
|
-
) -> Dict[str, Any]:
|
|
163
|
+
) -> Union[Dict[str, Any], QueuedJob]:
|
|
161
164
|
"""Single queue-aware core every public entry point routes through.
|
|
162
165
|
|
|
163
166
|
Runs ``command`` via the raw adapter ``execute_command``. If the
|
|
164
167
|
immediate response is a queue-service envelope
|
|
165
|
-
(:func:`code_analysis_client.queue_wait.is_queued_envelope`)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
168
|
+
(:func:`code_analysis_client.queue_wait.is_queued_envelope`):
|
|
169
|
+
|
|
170
|
+
* ``auto_poll=True`` (default, unchanged behavior) — polls the job to
|
|
171
|
+
completion (:func:`~code_analysis_client.queue_wait.wait_for_job`)
|
|
172
|
+
and returns the unwrapped inner result
|
|
173
|
+
(:func:`~code_analysis_client.queue_wait.unwrap_job_result`), raising
|
|
174
|
+
on failure.
|
|
175
|
+
* ``auto_poll=False`` — returns a
|
|
176
|
+
:class:`~code_analysis_client.queue_wait.QueuedJob` handle
|
|
177
|
+
immediately instead of polling; call ``await handle.wait(...)`` to
|
|
178
|
+
get the same result the default path would have returned.
|
|
179
|
+
|
|
180
|
+
A non-queued response is returned unchanged regardless of ``auto_poll``.
|
|
170
181
|
"""
|
|
171
182
|
resp = await self._rpc.execute_command(
|
|
172
183
|
command,
|
|
@@ -177,6 +188,9 @@ class CodeAnalysisAsyncClient:
|
|
|
177
188
|
return resp
|
|
178
189
|
|
|
179
190
|
job_id = extract_job_id(resp)
|
|
191
|
+
if not auto_poll:
|
|
192
|
+
return QueuedJob(job_id=job_id, envelope=resp, rpc=self._rpc)
|
|
193
|
+
|
|
180
194
|
status = await wait_for_job(
|
|
181
195
|
self._rpc,
|
|
182
196
|
job_id,
|
|
@@ -186,6 +200,7 @@ class CodeAnalysisAsyncClient:
|
|
|
186
200
|
)
|
|
187
201
|
return await unwrap_job_result(status, rpc=self._rpc)
|
|
188
202
|
|
|
203
|
+
@overload
|
|
189
204
|
async def call_validated(
|
|
190
205
|
self,
|
|
191
206
|
command: str,
|
|
@@ -193,11 +208,58 @@ class CodeAnalysisAsyncClient:
|
|
|
193
208
|
*,
|
|
194
209
|
use_cmd_endpoint: bool = False,
|
|
195
210
|
refresh_schema: bool = False,
|
|
211
|
+
auto_poll: Literal[True] = True,
|
|
196
212
|
timeout: Optional[float] = None,
|
|
197
213
|
poll_interval: float = 1.0,
|
|
198
214
|
status_hook: Optional[StatusHook] = None,
|
|
199
|
-
) -> Dict[str, Any]:
|
|
200
|
-
|
|
215
|
+
) -> Dict[str, Any]: ...
|
|
216
|
+
|
|
217
|
+
@overload
|
|
218
|
+
async def call_validated(
|
|
219
|
+
self,
|
|
220
|
+
command: str,
|
|
221
|
+
params: Optional[Dict[str, Any]] = None,
|
|
222
|
+
*,
|
|
223
|
+
use_cmd_endpoint: bool = False,
|
|
224
|
+
refresh_schema: bool = False,
|
|
225
|
+
auto_poll: Literal[False],
|
|
226
|
+
timeout: Optional[float] = None,
|
|
227
|
+
poll_interval: float = 1.0,
|
|
228
|
+
status_hook: Optional[StatusHook] = None,
|
|
229
|
+
) -> QueuedJob: ...
|
|
230
|
+
|
|
231
|
+
@overload
|
|
232
|
+
async def call_validated(
|
|
233
|
+
self,
|
|
234
|
+
command: str,
|
|
235
|
+
params: Optional[Dict[str, Any]] = None,
|
|
236
|
+
*,
|
|
237
|
+
use_cmd_endpoint: bool = False,
|
|
238
|
+
refresh_schema: bool = False,
|
|
239
|
+
auto_poll: bool,
|
|
240
|
+
timeout: Optional[float] = None,
|
|
241
|
+
poll_interval: float = 1.0,
|
|
242
|
+
status_hook: Optional[StatusHook] = None,
|
|
243
|
+
) -> Union[Dict[str, Any], QueuedJob]: ...
|
|
244
|
+
|
|
245
|
+
async def call_validated(
|
|
246
|
+
self,
|
|
247
|
+
command: str,
|
|
248
|
+
params: Optional[Dict[str, Any]] = None,
|
|
249
|
+
*,
|
|
250
|
+
use_cmd_endpoint: bool = False,
|
|
251
|
+
refresh_schema: bool = False,
|
|
252
|
+
auto_poll: bool = True,
|
|
253
|
+
timeout: Optional[float] = None,
|
|
254
|
+
poll_interval: float = 1.0,
|
|
255
|
+
status_hook: Optional[StatusHook] = None,
|
|
256
|
+
) -> Union[Dict[str, Any], QueuedJob]:
|
|
257
|
+
"""``help`` → schema on server, shallow local validation, then the queue-aware core.
|
|
258
|
+
|
|
259
|
+
``auto_poll`` (default ``True``) forwards to :meth:`_execute`: set it
|
|
260
|
+
to ``False`` to get a :class:`~code_analysis_client.queue_wait.QueuedJob`
|
|
261
|
+
handle back instead of blocking until a queued job completes.
|
|
262
|
+
"""
|
|
201
263
|
schema = await self.get_command_schema(command, refresh=refresh_schema)
|
|
202
264
|
merged = dict(params or {})
|
|
203
265
|
prepared = prepare_params_for_schema(merged, schema)
|
|
@@ -206,11 +268,57 @@ class CodeAnalysisAsyncClient:
|
|
|
206
268
|
command,
|
|
207
269
|
prepared,
|
|
208
270
|
use_cmd_endpoint=use_cmd_endpoint,
|
|
271
|
+
auto_poll=auto_poll,
|
|
209
272
|
timeout=timeout,
|
|
210
273
|
poll_interval=poll_interval,
|
|
211
274
|
status_hook=status_hook,
|
|
212
275
|
)
|
|
213
276
|
|
|
277
|
+
@overload
|
|
278
|
+
async def call_unified_validated(
|
|
279
|
+
self,
|
|
280
|
+
command: str,
|
|
281
|
+
params: Optional[Dict[str, Any]] = None,
|
|
282
|
+
*,
|
|
283
|
+
refresh_schema: bool = False,
|
|
284
|
+
use_cmd_endpoint: bool = False,
|
|
285
|
+
expect_queue: Optional[bool] = None,
|
|
286
|
+
auto_poll: Literal[True] = True,
|
|
287
|
+
poll_interval: float = 1.0,
|
|
288
|
+
timeout: Optional[float] = None,
|
|
289
|
+
status_hook: Optional[StatusHook] = None,
|
|
290
|
+
) -> Dict[str, Any]: ...
|
|
291
|
+
|
|
292
|
+
@overload
|
|
293
|
+
async def call_unified_validated(
|
|
294
|
+
self,
|
|
295
|
+
command: str,
|
|
296
|
+
params: Optional[Dict[str, Any]] = None,
|
|
297
|
+
*,
|
|
298
|
+
refresh_schema: bool = False,
|
|
299
|
+
use_cmd_endpoint: bool = False,
|
|
300
|
+
expect_queue: Optional[bool] = None,
|
|
301
|
+
auto_poll: Literal[False],
|
|
302
|
+
poll_interval: float = 1.0,
|
|
303
|
+
timeout: Optional[float] = None,
|
|
304
|
+
status_hook: Optional[StatusHook] = None,
|
|
305
|
+
) -> QueuedJob: ...
|
|
306
|
+
|
|
307
|
+
@overload
|
|
308
|
+
async def call_unified_validated(
|
|
309
|
+
self,
|
|
310
|
+
command: str,
|
|
311
|
+
params: Optional[Dict[str, Any]] = None,
|
|
312
|
+
*,
|
|
313
|
+
refresh_schema: bool = False,
|
|
314
|
+
use_cmd_endpoint: bool = False,
|
|
315
|
+
expect_queue: Optional[bool] = None,
|
|
316
|
+
auto_poll: bool,
|
|
317
|
+
poll_interval: float = 1.0,
|
|
318
|
+
timeout: Optional[float] = None,
|
|
319
|
+
status_hook: Optional[StatusHook] = None,
|
|
320
|
+
) -> Union[Dict[str, Any], QueuedJob]: ...
|
|
321
|
+
|
|
214
322
|
async def call_unified_validated(
|
|
215
323
|
self,
|
|
216
324
|
command: str,
|
|
@@ -223,14 +331,25 @@ class CodeAnalysisAsyncClient:
|
|
|
223
331
|
poll_interval: float = 1.0,
|
|
224
332
|
timeout: Optional[float] = None,
|
|
225
333
|
status_hook: Optional[StatusHook] = None,
|
|
226
|
-
) -> Dict[str, Any]:
|
|
334
|
+
) -> Union[Dict[str, Any], QueuedJob]:
|
|
227
335
|
"""Deprecated alias for :meth:`call_validated`.
|
|
228
336
|
|
|
229
|
-
``expect_queue``
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
337
|
+
``expect_queue`` remains accepted-and-ignored (documented no-op, kept
|
|
338
|
+
only for signature compatibility). ``auto_poll`` is now LIVE again and
|
|
339
|
+
forwards straight to the shared :meth:`_execute` core: ``auto_poll=False``
|
|
340
|
+
returns a :class:`~code_analysis_client.queue_wait.QueuedJob` handle
|
|
341
|
+
instead of a plain dict when the response is a queued envelope — a
|
|
342
|
+
return-type change versus the previous era where this parameter was
|
|
343
|
+
silently ignored and every path always blocked until completion.
|
|
344
|
+
Prefer :meth:`call_validated` directly; this alias emits
|
|
345
|
+
``DeprecationWarning`` on every call.
|
|
233
346
|
"""
|
|
347
|
+
warnings.warn(
|
|
348
|
+
"call_unified_validated is deprecated; use call_validated() "
|
|
349
|
+
"directly (its 'auto_poll' keyword works the same way).",
|
|
350
|
+
DeprecationWarning,
|
|
351
|
+
stacklevel=2,
|
|
352
|
+
)
|
|
234
353
|
schema = await self.get_command_schema(command, refresh=refresh_schema)
|
|
235
354
|
merged = dict(params or {})
|
|
236
355
|
prepared = prepare_params_for_schema(merged, schema)
|
|
@@ -239,31 +358,121 @@ class CodeAnalysisAsyncClient:
|
|
|
239
358
|
command,
|
|
240
359
|
prepared,
|
|
241
360
|
use_cmd_endpoint=use_cmd_endpoint,
|
|
361
|
+
auto_poll=auto_poll,
|
|
242
362
|
timeout=timeout,
|
|
243
363
|
poll_interval=poll_interval,
|
|
244
364
|
status_hook=status_hook,
|
|
245
365
|
)
|
|
246
366
|
|
|
367
|
+
@overload
|
|
247
368
|
async def call(
|
|
248
369
|
self,
|
|
249
370
|
command: str,
|
|
250
371
|
params: Optional[Dict[str, Any]] = None,
|
|
251
372
|
*,
|
|
252
373
|
use_cmd_endpoint: bool = False,
|
|
374
|
+
auto_poll: Literal[True] = True,
|
|
253
375
|
timeout: Optional[float] = None,
|
|
254
376
|
poll_interval: float = 1.0,
|
|
255
377
|
status_hook: Optional[StatusHook] = None,
|
|
256
|
-
) -> Dict[str, Any]:
|
|
257
|
-
|
|
378
|
+
) -> Dict[str, Any]: ...
|
|
379
|
+
|
|
380
|
+
@overload
|
|
381
|
+
async def call(
|
|
382
|
+
self,
|
|
383
|
+
command: str,
|
|
384
|
+
params: Optional[Dict[str, Any]] = None,
|
|
385
|
+
*,
|
|
386
|
+
use_cmd_endpoint: bool = False,
|
|
387
|
+
auto_poll: Literal[False],
|
|
388
|
+
timeout: Optional[float] = None,
|
|
389
|
+
poll_interval: float = 1.0,
|
|
390
|
+
status_hook: Optional[StatusHook] = None,
|
|
391
|
+
) -> QueuedJob: ...
|
|
392
|
+
|
|
393
|
+
@overload
|
|
394
|
+
async def call(
|
|
395
|
+
self,
|
|
396
|
+
command: str,
|
|
397
|
+
params: Optional[Dict[str, Any]] = None,
|
|
398
|
+
*,
|
|
399
|
+
use_cmd_endpoint: bool = False,
|
|
400
|
+
auto_poll: bool,
|
|
401
|
+
timeout: Optional[float] = None,
|
|
402
|
+
poll_interval: float = 1.0,
|
|
403
|
+
status_hook: Optional[StatusHook] = None,
|
|
404
|
+
) -> Union[Dict[str, Any], QueuedJob]: ...
|
|
405
|
+
|
|
406
|
+
async def call(
|
|
407
|
+
self,
|
|
408
|
+
command: str,
|
|
409
|
+
params: Optional[Dict[str, Any]] = None,
|
|
410
|
+
*,
|
|
411
|
+
use_cmd_endpoint: bool = False,
|
|
412
|
+
auto_poll: bool = True,
|
|
413
|
+
timeout: Optional[float] = None,
|
|
414
|
+
poll_interval: float = 1.0,
|
|
415
|
+
status_hook: Optional[StatusHook] = None,
|
|
416
|
+
) -> Union[Dict[str, Any], QueuedJob]:
|
|
417
|
+
"""Run any registered server command; queued jobs are polled to completion by default.
|
|
418
|
+
|
|
419
|
+
Pass ``auto_poll=False`` to get a
|
|
420
|
+
:class:`~code_analysis_client.queue_wait.QueuedJob` handle back
|
|
421
|
+
immediately instead (call ``await handle.wait(...)`` when you're
|
|
422
|
+
ready to block on it).
|
|
423
|
+
"""
|
|
258
424
|
return await self._execute(
|
|
259
425
|
command,
|
|
260
426
|
params,
|
|
261
427
|
use_cmd_endpoint=use_cmd_endpoint,
|
|
428
|
+
auto_poll=auto_poll,
|
|
262
429
|
timeout=timeout,
|
|
263
430
|
poll_interval=poll_interval,
|
|
264
431
|
status_hook=status_hook,
|
|
265
432
|
)
|
|
266
433
|
|
|
434
|
+
@overload
|
|
435
|
+
async def call_unified(
|
|
436
|
+
self,
|
|
437
|
+
command: str,
|
|
438
|
+
params: Optional[Dict[str, Any]] = None,
|
|
439
|
+
*,
|
|
440
|
+
use_cmd_endpoint: bool = False,
|
|
441
|
+
expect_queue: Optional[bool] = None,
|
|
442
|
+
auto_poll: Literal[True] = True,
|
|
443
|
+
poll_interval: float = 1.0,
|
|
444
|
+
timeout: Optional[float] = None,
|
|
445
|
+
status_hook: Optional[StatusHook] = None,
|
|
446
|
+
) -> Dict[str, Any]: ...
|
|
447
|
+
|
|
448
|
+
@overload
|
|
449
|
+
async def call_unified(
|
|
450
|
+
self,
|
|
451
|
+
command: str,
|
|
452
|
+
params: Optional[Dict[str, Any]] = None,
|
|
453
|
+
*,
|
|
454
|
+
use_cmd_endpoint: bool = False,
|
|
455
|
+
expect_queue: Optional[bool] = None,
|
|
456
|
+
auto_poll: Literal[False],
|
|
457
|
+
poll_interval: float = 1.0,
|
|
458
|
+
timeout: Optional[float] = None,
|
|
459
|
+
status_hook: Optional[StatusHook] = None,
|
|
460
|
+
) -> QueuedJob: ...
|
|
461
|
+
|
|
462
|
+
@overload
|
|
463
|
+
async def call_unified(
|
|
464
|
+
self,
|
|
465
|
+
command: str,
|
|
466
|
+
params: Optional[Dict[str, Any]] = None,
|
|
467
|
+
*,
|
|
468
|
+
use_cmd_endpoint: bool = False,
|
|
469
|
+
expect_queue: Optional[bool] = None,
|
|
470
|
+
auto_poll: bool,
|
|
471
|
+
poll_interval: float = 1.0,
|
|
472
|
+
timeout: Optional[float] = None,
|
|
473
|
+
status_hook: Optional[StatusHook] = None,
|
|
474
|
+
) -> Union[Dict[str, Any], QueuedJob]: ...
|
|
475
|
+
|
|
267
476
|
async def call_unified(
|
|
268
477
|
self,
|
|
269
478
|
command: str,
|
|
@@ -275,18 +484,29 @@ class CodeAnalysisAsyncClient:
|
|
|
275
484
|
poll_interval: float = 1.0,
|
|
276
485
|
timeout: Optional[float] = None,
|
|
277
486
|
status_hook: Optional[StatusHook] = None,
|
|
278
|
-
) -> Dict[str, Any]:
|
|
487
|
+
) -> Union[Dict[str, Any], QueuedJob]:
|
|
279
488
|
"""Deprecated alias for :meth:`call`.
|
|
280
489
|
|
|
281
|
-
``expect_queue``
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
490
|
+
``expect_queue`` remains accepted-and-ignored (documented no-op).
|
|
491
|
+
``auto_poll`` is now LIVE again and forwards straight to the shared
|
|
492
|
+
:meth:`_execute` core: ``auto_poll=False`` returns a
|
|
493
|
+
:class:`~code_analysis_client.queue_wait.QueuedJob` handle instead of
|
|
494
|
+
a plain dict when the response is a queued envelope — a return-type
|
|
495
|
+
change versus the previous era where this parameter was silently
|
|
496
|
+
ignored. Prefer :meth:`call` directly; this alias emits
|
|
497
|
+
``DeprecationWarning`` on every call.
|
|
285
498
|
"""
|
|
499
|
+
warnings.warn(
|
|
500
|
+
"call_unified is deprecated; use call() directly (its "
|
|
501
|
+
"'auto_poll' keyword works the same way).",
|
|
502
|
+
DeprecationWarning,
|
|
503
|
+
stacklevel=2,
|
|
504
|
+
)
|
|
286
505
|
return await self._execute(
|
|
287
506
|
command,
|
|
288
507
|
params,
|
|
289
508
|
use_cmd_endpoint=use_cmd_endpoint,
|
|
509
|
+
auto_poll=auto_poll,
|
|
290
510
|
timeout=timeout,
|
|
291
511
|
poll_interval=poll_interval,
|
|
292
512
|
status_hook=status_hook,
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/queue_wait.py
RENAMED
|
@@ -11,6 +11,7 @@ from __future__ import annotations
|
|
|
11
11
|
import asyncio
|
|
12
12
|
import inspect
|
|
13
13
|
import time
|
|
14
|
+
from dataclasses import dataclass, field
|
|
14
15
|
from typing import Any, Awaitable, Callable, Dict, Optional, Union
|
|
15
16
|
|
|
16
17
|
from code_analysis_client.exceptions import (
|
|
@@ -254,3 +255,54 @@ async def unwrap_job_result(
|
|
|
254
255
|
raise CommandFailedError(command, job_id, inner)
|
|
255
256
|
|
|
256
257
|
return inner if isinstance(inner, dict) else {"result": inner}
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
@dataclass
|
|
261
|
+
class QueuedJob:
|
|
262
|
+
"""Handle for a queued job returned when ``auto_poll=False`` opts out of automatic polling.
|
|
263
|
+
|
|
264
|
+
Returned by the client's queue-aware core (``CodeAnalysisAsyncClient._execute``)
|
|
265
|
+
in place of polling to completion when the immediate server response is a
|
|
266
|
+
queued-job envelope (:func:`is_queued_envelope`) and the caller passed
|
|
267
|
+
``auto_poll=False``. Encapsulates all envelope-shape quirks (the job id may
|
|
268
|
+
live top-level or nested under ``data``, see :func:`extract_job_id`) behind
|
|
269
|
+
:meth:`wait` / :meth:`status` so callers never need to touch the raw envelope.
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
job_id: str
|
|
273
|
+
envelope: Dict[str, Any]
|
|
274
|
+
rpc: Any = field(repr=False)
|
|
275
|
+
|
|
276
|
+
async def wait(
|
|
277
|
+
self,
|
|
278
|
+
*,
|
|
279
|
+
timeout: Optional[float] = None,
|
|
280
|
+
poll_interval: float = 1.0,
|
|
281
|
+
status_hook: Optional[StatusHook] = None,
|
|
282
|
+
) -> Dict[str, Any]:
|
|
283
|
+
"""Poll the job to completion and return what ``_execute`` would have returned.
|
|
284
|
+
|
|
285
|
+
Delegates to the same :func:`wait_for_job` + :func:`unwrap_job_result`
|
|
286
|
+
pair the auto-polling path uses, so failures raise the identical
|
|
287
|
+
:class:`~code_analysis_client.exceptions.JobFailedError` /
|
|
288
|
+
:class:`~code_analysis_client.exceptions.CommandFailedError` /
|
|
289
|
+
:class:`~code_analysis_client.exceptions.JobTimeoutError`.
|
|
290
|
+
"""
|
|
291
|
+
status = await wait_for_job(
|
|
292
|
+
self.rpc,
|
|
293
|
+
self.job_id,
|
|
294
|
+
timeout=timeout,
|
|
295
|
+
poll_interval=poll_interval,
|
|
296
|
+
status_hook=status_hook,
|
|
297
|
+
)
|
|
298
|
+
return await unwrap_job_result(status, rpc=self.rpc)
|
|
299
|
+
|
|
300
|
+
async def status(self) -> Dict[str, Any]:
|
|
301
|
+
"""One-shot ``queue_get_job_status`` fetch (no polling to completion)."""
|
|
302
|
+
resp = await self.rpc.execute_command(
|
|
303
|
+
"queue_get_job_status", {"job_id": self.job_id}
|
|
304
|
+
)
|
|
305
|
+
data = resp.get("data") if isinstance(resp, dict) else None
|
|
306
|
+
if not isinstance(data, dict):
|
|
307
|
+
data = resp if isinstance(resp, dict) else {}
|
|
308
|
+
return data
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.6.67
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: code-analysis-client
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.67
|
|
4
4
|
Summary: Async JSON-RPC client for the code-analysis MCP server (mcp-proxy-adapter JsonRpcClient)
|
|
5
5
|
Author-email: Vasiliy Zdanovskiy <vasilyvz@gmail.com>
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -85,9 +85,34 @@ counterparts): `timeout` (seconds, default `None` = wait until terminal),
|
|
|
85
85
|
`poll_interval` (seconds between polls, default `1.0`), `status_hook` (sync or
|
|
86
86
|
async callable invoked with each poll's status dict).
|
|
87
87
|
|
|
88
|
+
`call` / `call_validated` also take `auto_poll` (default `True`, matching the
|
|
89
|
+
behavior above exactly). Pass `auto_poll=False` to opt out of automatic
|
|
90
|
+
polling: a non-queued response still comes back as the plain domain result,
|
|
91
|
+
but a queued-job response comes back immediately as a `QueuedJob` handle
|
|
92
|
+
instead of blocking until the job finishes.
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
from code_analysis_client import QueuedJob
|
|
96
|
+
|
|
97
|
+
result = await client.call("some_long_running_command", {...}, auto_poll=False)
|
|
98
|
+
if isinstance(result, QueuedJob):
|
|
99
|
+
# do other work here, then block on it whenever you're ready
|
|
100
|
+
result = await result.wait()
|
|
101
|
+
# `result` is now the same dict shape a default (auto_poll=True) call returns
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`QueuedJob` exposes `.job_id`, `.envelope` (the raw queue-service response),
|
|
105
|
+
and two async methods: `.wait(timeout=None, poll_interval=1.0, status_hook=None)`
|
|
106
|
+
— polls to completion and returns/raises exactly like the default path — and
|
|
107
|
+
`.status()` — a single `queue_get_job_status` fetch without polling to
|
|
108
|
+
completion.
|
|
109
|
+
|
|
88
110
|
`call_unified` / `call_unified_validated` are kept as **deprecated aliases** of
|
|
89
|
-
`call` / `call_validated` for backward compatibility
|
|
90
|
-
`
|
|
111
|
+
`call` / `call_validated` for backward compatibility and emit
|
|
112
|
+
`DeprecationWarning` on every call. `expect_queue` remains accepted-and-ignored
|
|
113
|
+
(documented no-op). `auto_poll` is the one canonical switch and is forwarded
|
|
114
|
+
straight through to `call` / `call_validated` — `auto_poll=False` on an alias
|
|
115
|
+
returns a `QueuedJob` the same way it does on the non-deprecated method.
|
|
91
116
|
Prefer `call` / `call_validated` directly.
|
|
92
117
|
|
|
93
118
|
## Validation using the server schema
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.6.65
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/commands_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/exceptions.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/file_session.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/responses.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/server_api.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/server_schema.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/universal_file.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.65 → code_analysis_client-1.6.67}/code_analysis_client/validation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|