@qingflow-tech/qingflow-cli 1.1.47 → 1.1.48-beta.1

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.
@@ -1,6 +1,5 @@
1
1
  from __future__ import annotations
2
2
 
3
- import csv
4
3
  import html
5
4
  import mimetypes
6
5
  import json
@@ -34,6 +33,7 @@ from ..list_type_labels import (
34
33
  )
35
34
  from .base import ToolBase
36
35
  from .directory_tools import _directory_has_more, _directory_items
36
+ from .csv_export import CsvShardWriter
37
37
 
38
38
 
39
39
  DEFAULT_QUERY_PAGE_SIZE = 50
@@ -2263,57 +2263,22 @@ class RecordTools(ToolBase):
2263
2263
  }
2264
2264
 
2265
2265
  run_dir = _record_access_run_dir()
2266
- run_dir.mkdir(parents=True, exist_ok=True)
2267
2266
  header = ["record_id"] + [str(field["column_name"]) for field in fields_payload]
2268
- files: list[JSONObject] = []
2269
- shard_part = 0
2270
- shard_rows = 0
2271
- row_count = 0
2272
- file_handle: Any | None = None
2273
- writer: Any | None = None
2274
-
2275
- def close_shard() -> None:
2276
- nonlocal file_handle, writer, shard_rows
2277
- if file_handle is None:
2278
- return
2279
- path = Path(file_handle.name)
2280
- file_handle.close()
2281
- files.append(
2282
- {
2283
- "local_path": str(path),
2284
- "row_count": shard_rows,
2285
- "part": len(files) + 1,
2286
- }
2287
- )
2288
- file_handle = None
2289
- writer = None
2290
- shard_rows = 0
2291
-
2292
- def ensure_writer() -> Any:
2293
- nonlocal file_handle, writer, shard_part
2294
- if writer is not None:
2295
- return writer
2296
- shard_part += 1
2297
- path = run_dir / f"records-{shard_part:04d}.csv"
2298
- file_handle = path.open("w", newline="", encoding="utf-8-sig")
2299
- writer = csv.writer(file_handle)
2300
- writer.writerow(header)
2301
- return writer
2267
+ shard_writer = CsvShardWriter(
2268
+ output_dir=run_dir,
2269
+ file_prefix="records",
2270
+ header=header,
2271
+ shard_rows=DEFAULT_RECORD_ACCESS_SHARD_ROWS,
2272
+ )
2302
2273
 
2303
2274
  def write_record(apply_id: int | None, answer_list: list[JSONValue]) -> None:
2304
- nonlocal row_count, shard_rows
2305
2275
  if apply_id is None:
2306
2276
  return
2307
- if shard_rows >= DEFAULT_RECORD_ACCESS_SHARD_ROWS:
2308
- close_shard()
2309
- csv_writer = ensure_writer()
2310
2277
  values: list[str] = [_public_record_id_text(apply_id) or ""]
2311
2278
  for field in selected_fields:
2312
2279
  answer = _find_answer_for_field(answer_list, field)
2313
2280
  values.append(_record_access_csv_cell(_normalize_answer_field_value_for_output(answer, field)))
2314
- csv_writer.writerow(values)
2315
- row_count += 1
2316
- shard_rows += 1
2281
+ shard_writer.write(values)
2317
2282
 
2318
2283
  current_page = 1
2319
2284
  has_more = False
@@ -2353,7 +2318,7 @@ class RecordTools(ToolBase):
2353
2318
  break
2354
2319
  page = fetch_page(current_page, BACKEND_RECORD_ACCESS_PAGE_SIZE)
2355
2320
  finally:
2356
- close_shard()
2321
+ shard_writer.close_shard()
2357
2322
 
2358
2323
  if stopped_reason == "TIME_BUDGET_EXCEEDED":
2359
2324
  warnings.append(_record_access_time_budget_warning(reported_total=reported_total, fetched_pages=fetched_pages))
@@ -2378,11 +2343,11 @@ class RecordTools(ToolBase):
2378
2343
  "view_id": view_route.view_id,
2379
2344
  "format": "csv",
2380
2345
  "local_dir": str(run_dir),
2381
- "row_count": row_count,
2346
+ "row_count": shard_writer.row_count,
2382
2347
  "complete": complete,
2383
2348
  "truncated": not complete,
2384
2349
  "safe_for_final_conclusion": safe_for_final_conclusion,
2385
- "files": files,
2350
+ "files": shard_writer.files,
2386
2351
  "fields": fields_payload,
2387
2352
  "warnings": warnings,
2388
2353
  "verification": verification_payload,
@@ -6,6 +6,7 @@ from typing import Any
6
6
  from ..errors import QingflowApiError, backend_code_int, is_auth_like_error, raise_tool_error
7
7
  from ..json_types import JSONObject
8
8
  from ..list_type_labels import SYSTEM_VIEW_DEFINITIONS
9
+ from ..resource_uri import try_build_resource_uri
9
10
  from ..solution.compiler.icon_utils import workspace_icon_config
10
11
  from .app_tools import _analysis_supported_for_view_type
11
12
  from .base import ToolBase
@@ -227,6 +228,17 @@ class ResourceReadTools(ToolBase):
227
228
  "message": f"view_get supports exporting `{view_id}`, but the export call still needs an explicit `app_key` from the parent app context.",
228
229
  }
229
230
  )
231
+ uri = None
232
+ if resolved_app_key:
233
+ uri, uri_warning = try_build_resource_uri(
234
+ ws_id=session_profile.selected_ws_id,
235
+ resource_type="view",
236
+ app_key=resolved_app_key,
237
+ view_kind="custom",
238
+ view_key=view_key,
239
+ )
240
+ if uri_warning:
241
+ warnings.append(uri_warning)
230
242
  return {
231
243
  "profile": profile,
232
244
  "ws_id": session_profile.selected_ws_id,
@@ -249,6 +261,7 @@ class ResourceReadTools(ToolBase):
249
261
  ],
250
262
  "analysis_supported": _analysis_supported_for_view_type(raw_view_type or None),
251
263
  "export_capability": export_capability,
264
+ **({"uri": uri} if uri else {}),
252
265
  },
253
266
  }
254
267