code-analysis-client 1.6.57__tar.gz → 1.6.59__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.57 → code_analysis_client-1.6.59}/PKG-INFO +1 -1
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/client.py +1 -1
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/queue_wait.py +66 -2
- code_analysis_client-1.6.59/code_analysis_client/version.txt +1 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client.egg-info/PKG-INFO +1 -1
- code_analysis_client-1.6.57/code_analysis_client/version.txt +0 -1
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/README.md +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/__init__.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/commands_proxy.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/config.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/exceptions.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/file_session.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/py.typed +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/responses.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/server_api.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/server_schema.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/universal_file.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/validation.py +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client.egg-info/SOURCES.txt +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client.egg-info/dependency_links.txt +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client.egg-info/requires.txt +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client.egg-info/top_level.txt +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/pyproject.toml +0 -0
- {code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/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.59
|
|
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
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/queue_wait.py
RENAMED
|
@@ -155,7 +155,55 @@ async def wait_for_job(
|
|
|
155
155
|
await asyncio.sleep(poll_interval)
|
|
156
156
|
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
_JOB_FAILED_REFETCH_ATTEMPTS = 4
|
|
159
|
+
_JOB_FAILED_REFETCH_SLEEP_SECONDS = 0.5
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _extract_inner_command_error(status_data: Dict[str, Any]) -> Any:
|
|
163
|
+
"""Pull the failed command's own structured error out of a job status dict.
|
|
164
|
+
|
|
165
|
+
Looks at ``status_data["result"]["result"]["error"]`` first (outer
|
|
166
|
+
``result`` is the queue wrapper, inner ``result`` is the command's own
|
|
167
|
+
result envelope), falling back to ``status_data["result"]["error"]``.
|
|
168
|
+
Returns ``None`` when neither is present.
|
|
169
|
+
"""
|
|
170
|
+
result_field = status_data.get("result")
|
|
171
|
+
if not isinstance(result_field, dict):
|
|
172
|
+
return None
|
|
173
|
+
inner_result = result_field.get("result")
|
|
174
|
+
if isinstance(inner_result, dict) and inner_result.get("error") is not None:
|
|
175
|
+
return inner_result["error"]
|
|
176
|
+
if result_field.get("error") is not None:
|
|
177
|
+
return result_field["error"]
|
|
178
|
+
return None
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
async def _refetch_inner_command_error(rpc: Any, job_id: str) -> Any:
|
|
182
|
+
"""Re-poll ``queue_get_job_status`` hunting for the inner structured error.
|
|
183
|
+
|
|
184
|
+
Write-order gotcha: the queue store writes the job's terminal ``status``
|
|
185
|
+
slightly BEFORE it writes the ``result`` payload. A caller that reads the
|
|
186
|
+
status the instant it turns ``failed`` can therefore observe a terminal
|
|
187
|
+
status with no ``result`` (and no nested inner error) yet, even though the
|
|
188
|
+
failed command DID record a structured error - it just hasn't landed in
|
|
189
|
+
the store. Re-fetching a few times with a short sleep gives that second
|
|
190
|
+
write time to land instead of silently downgrading to ``None``.
|
|
191
|
+
"""
|
|
192
|
+
for _ in range(_JOB_FAILED_REFETCH_ATTEMPTS):
|
|
193
|
+
await asyncio.sleep(_JOB_FAILED_REFETCH_SLEEP_SECONDS)
|
|
194
|
+
resp = await rpc.execute_command("queue_get_job_status", {"job_id": job_id})
|
|
195
|
+
data = resp.get("data") if isinstance(resp, dict) else None
|
|
196
|
+
if not isinstance(data, dict):
|
|
197
|
+
data = resp if isinstance(resp, dict) else {}
|
|
198
|
+
inner_error = _extract_inner_command_error(data)
|
|
199
|
+
if inner_error is not None:
|
|
200
|
+
return inner_error
|
|
201
|
+
return None
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
async def unwrap_job_result(
|
|
205
|
+
status_data: Dict[str, Any], *, rpc: Any = None
|
|
206
|
+
) -> Dict[str, Any]:
|
|
159
207
|
"""Extract the inner command result from a terminal job status ``data`` dict.
|
|
160
208
|
|
|
161
209
|
Raises :class:`JobFailedError` when the job itself failed/stopped/cancelled
|
|
@@ -163,13 +211,29 @@ def unwrap_job_result(status_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
163
211
|
completed but the inner command result is itself an error envelope.
|
|
164
212
|
Otherwise returns the inner result dict, in the same shape a sync call
|
|
165
213
|
would have returned.
|
|
214
|
+
|
|
215
|
+
On job failure, before raising, this tries to attach the failed command's
|
|
216
|
+
OWN structured error (nested at ``data.result.result.error``, falling
|
|
217
|
+
back to ``data.result.error``) to ``JobFailedError.error`` instead of the
|
|
218
|
+
bare queue-level ``error`` field. When that nested error is not yet
|
|
219
|
+
present in ``status_data`` and ``rpc`` was supplied, it re-fetches the job
|
|
220
|
+
status up to :data:`_JOB_FAILED_REFETCH_ATTEMPTS` times (see
|
|
221
|
+
:func:`_refetch_inner_command_error` for the write-order race this rides
|
|
222
|
+
out). The queue-level ``error`` field is used as a fallback when no
|
|
223
|
+
structured inner error is ever found; ``JobFailedError.error`` is ``None``
|
|
224
|
+
only when genuinely nothing was found either way.
|
|
166
225
|
"""
|
|
167
226
|
job_id = status_data.get("job_id")
|
|
168
227
|
status = str(status_data.get("status", "")).strip().lower()
|
|
169
228
|
error = status_data.get("error")
|
|
170
229
|
|
|
171
230
|
if status in _FAILED_JOB_STATUSES or error:
|
|
172
|
-
|
|
231
|
+
inner_error = _extract_inner_command_error(status_data)
|
|
232
|
+
if inner_error is None and rpc is not None and job_id:
|
|
233
|
+
inner_error = await _refetch_inner_command_error(rpc, str(job_id))
|
|
234
|
+
raise JobFailedError(
|
|
235
|
+
job_id, inner_error if inner_error is not None else error, status=status
|
|
236
|
+
)
|
|
173
237
|
|
|
174
238
|
result_field = status_data.get("result")
|
|
175
239
|
if isinstance(result_field, dict) and "result" in result_field:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.6.59
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/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.59
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.6.57
|
|
File without changes
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/__init__.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/commands_proxy.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/exceptions.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/file_session.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/responses.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/server_api.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/server_schema.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/code_analysis_client/universal_file.py
RENAMED
|
File without changes
|
{code_analysis_client-1.6.57 → code_analysis_client-1.6.59}/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
|