dataops-sdk 0.3.0__py3-none-any.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.

Potentially problematic release.


This version of dataops-sdk might be problematic. Click here for more details.

Files changed (79) hide show
  1. dataops_sdk/__init__.py +84 -0
  2. dataops_sdk/constants.py +6 -0
  3. dataops_sdk/exceptions.py +31 -0
  4. dataops_sdk/runner/__init__.py +46 -0
  5. dataops_sdk/runner/datasource_factory.py +83 -0
  6. dataops_sdk/runner/schemas/nacos/__init__.py +5 -0
  7. dataops_sdk/runner/schemas/nacos/config.py +40 -0
  8. dataops_sdk/runner/schemas/nacos/constants.py +235 -0
  9. dataops_sdk/runner/schemas/nacos/instance.py +103 -0
  10. dataops_sdk/runner/schemas/nacos/nacos_exception.py +44 -0
  11. dataops_sdk/runner/schemas/nacos/naming_param.py +62 -0
  12. dataops_sdk/runner/schemas/nacos/naming_request.py +84 -0
  13. dataops_sdk/runner/schemas/nacos/naming_response.py +50 -0
  14. dataops_sdk/runner/schemas/nacos/preserved_metadata_key.py +10 -0
  15. dataops_sdk/runner/schemas/nacos/service.py +119 -0
  16. dataops_sdk/runner/utils/__init__.py +42 -0
  17. dataops_sdk/runner/utils/common.py +209 -0
  18. dataops_sdk/runner/utils/dbConn_base.py +256 -0
  19. dataops_sdk/runner/utils/dbConn_sync.py +485 -0
  20. dataops_sdk/runner/utils/duckdb_manager.py +203 -0
  21. dataops_sdk/runner/utils/file_transfer_base.py +307 -0
  22. dataops_sdk/runner/utils/ftp_file_transfer.py +242 -0
  23. dataops_sdk/runner/utils/log.py +50 -0
  24. dataops_sdk/runner/utils/nacos.py +96 -0
  25. dataops_sdk/runner/utils/neo4j_sync.py +236 -0
  26. dataops_sdk/runner/utils/queue_base.py +224 -0
  27. dataops_sdk/runner/utils/queue_kafka.py +150 -0
  28. dataops_sdk/runner/utils/sftp_file_transfer.py +243 -0
  29. dataops_sdk/schemas/__init__.py +32 -0
  30. dataops_sdk/schemas/alarm.py +38 -0
  31. dataops_sdk/schemas/api.py +37 -0
  32. dataops_sdk/schemas/data_table.py +437 -0
  33. dataops_sdk/schemas/datasource.py +26 -0
  34. dataops_sdk/schemas/dict_.py +13 -0
  35. dataops_sdk/schemas/enums.py +120 -0
  36. dataops_sdk/schemas/group.py +40 -0
  37. dataops_sdk/schemas/hazard.py +151 -0
  38. dataops_sdk/schemas/meta.py +175 -0
  39. dataops_sdk/schemas/query.py +175 -0
  40. dataops_sdk/schemas/report.py +22 -0
  41. dataops_sdk/schemas/skill.py +70 -0
  42. dataops_sdk/schemas/table.py +65 -0
  43. dataops_sdk/schemas/user.py +52 -0
  44. dataops_sdk/schemas/widget.py +651 -0
  45. dataops_sdk/schemas/workflow.py +63 -0
  46. dataops_sdk/services/__init__.py +110 -0
  47. dataops_sdk/services/alarm.py +324 -0
  48. dataops_sdk/services/api.py +28 -0
  49. dataops_sdk/services/auth.py +120 -0
  50. dataops_sdk/services/data_table.py +485 -0
  51. dataops_sdk/services/dataset.py +127 -0
  52. dataops_sdk/services/datasource.py +57 -0
  53. dataops_sdk/services/dict_.py +69 -0
  54. dataops_sdk/services/hazard.py +260 -0
  55. dataops_sdk/services/meta.py +523 -0
  56. dataops_sdk/services/metrics.py +42 -0
  57. dataops_sdk/services/ref.py +66 -0
  58. dataops_sdk/services/report.py +36 -0
  59. dataops_sdk/services/skill.py +276 -0
  60. dataops_sdk/services/table.py +340 -0
  61. dataops_sdk/services/widget.py +143 -0
  62. dataops_sdk/services/workflow.py +102 -0
  63. dataops_sdk/session.py +292 -0
  64. dataops_sdk/tiptap/__init__.py +30 -0
  65. dataops_sdk/tiptap/builder.py +75 -0
  66. dataops_sdk/tiptap/constants.py +133 -0
  67. dataops_sdk/tiptap/markdown_parser.py +294 -0
  68. dataops_sdk/tiptap/models.py +43 -0
  69. dataops_sdk/tiptap/parse_utils.py +889 -0
  70. dataops_sdk/tiptap/render_utils.py +846 -0
  71. dataops_sdk/tiptap/renderers.py +51 -0
  72. dataops_sdk/tiptap/tool.py +629 -0
  73. dataops_sdk/utils/__init__.py +15 -0
  74. dataops_sdk/utils/common.py +211 -0
  75. dataops_sdk/utils/utils.py +120 -0
  76. dataops_sdk-0.3.0.dist-info/METADATA +25 -0
  77. dataops_sdk-0.3.0.dist-info/RECORD +79 -0
  78. dataops_sdk-0.3.0.dist-info/WHEEL +5 -0
  79. dataops_sdk-0.3.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,523 @@
1
+ """统一的 Meta 操作模块(服务层).
2
+
3
+ 提供对 meta release 列表查询和单个获取的通用功能.
4
+ 本模块为纯服务层,不依赖 typer/Rich,可供 Python 代码直接调用。
5
+ CLI 命令请使用 meta_cli 模块。
6
+ """
7
+
8
+ from collections.abc import Mapping, Sequence
9
+
10
+ from pydantic import ConfigDict, JsonValue, TypeAdapter
11
+ from pydantic_core import to_json, to_jsonable_python
12
+
13
+ from dataops_sdk.exceptions import (
14
+ AuthenticationError,
15
+ DataOpsError,
16
+ FailedToCreateError,
17
+ NotFoundError,
18
+ )
19
+ from dataops_sdk.schemas import (
20
+ DEFAULT_META_DATA_TYPE,
21
+ META_DATA_TYPE,
22
+ InnerMetaType,
23
+ Meta,
24
+ MetaCreate,
25
+ MetaRef,
26
+ MetaRelease,
27
+ MetaType,
28
+ PageParam,
29
+ SqlQueryParam,
30
+ )
31
+ from dataops_sdk.session import get_session
32
+ from dataops_sdk.utils import encrypt_body
33
+
34
+
35
+ def release_list_list(
36
+ meta_type: MetaType | InnerMetaType | str,
37
+ filters: Sequence[dict] | None = None,
38
+ headers: dict[str, str] | None = None,
39
+ datasource: str | None = None,
40
+ extra_conditions: Sequence[dict] | None = None,
41
+ ) -> list[MetaRelease]:
42
+ """获取 Meta Release 列表.
43
+
44
+ Args:
45
+ meta_type: 元数据类型(MetaType 枚举或字符串).
46
+ filters: SQL 查询过滤条件列表.
47
+ headers: 额外的请求头.
48
+ datasource: 数据源;非空时写入 ``x-sub-system`` 头.
49
+ extra_conditions: 在默认 ``type=meta_type`` 之上追加等值条件列表,每项形如
50
+ ``{"name": "parent_id", "value": "xxx", "alias": "mrl"}``. 主要用于按
51
+ parent_id 等辅助字段过滤。
52
+
53
+ Returns:
54
+ MetaRelease 对象列表
55
+
56
+ Raises:
57
+ DataOpsError: API 返回错误时
58
+ AuthenticationError: 未认证或认证失败时
59
+ """
60
+ type_str = meta_type.value if isinstance(meta_type, (MetaType, InnerMetaType)) else meta_type
61
+ url = "/meta/release/list/list"
62
+
63
+ sql_query_param = SqlQueryParam().add_eq("type", type_str, "mrl")
64
+ for cond in extra_conditions or []:
65
+ sql_query_param.add_eq(cond["name"], cond["value"], cond.get("alias", "mrl"))
66
+
67
+ headers = headers or {}
68
+ if datasource:
69
+ headers["x-sub-system"] = datasource
70
+
71
+ body = {
72
+ "filters": to_jsonable_python(filters or []),
73
+ "pageParam": PageParam(limit=-1),
74
+ "queryParam": sql_query_param,
75
+ }
76
+
77
+ try:
78
+ with get_session() as session:
79
+ resp = session.post(url, headers=headers, content=to_json(encrypt_body(body)))
80
+ resp_body = resp.json()
81
+ if resp.status_code == 401:
82
+ raise AuthenticationError("认证失败,请先登录")
83
+ if resp.status_code != 200:
84
+ raise DataOpsError(
85
+ resp_body.get("msg", f"HTTP {resp.status_code}"), resp.status_code
86
+ )
87
+ group_nodes = TypeAdapter(
88
+ list[MetaRelease], config=ConfigDict(str_to_lower=True)
89
+ ).validate_python(resp_body["data"])
90
+ return group_nodes
91
+ except SystemExit as e:
92
+ raise AuthenticationError("认证失败,请先登录") from e
93
+
94
+
95
+ def release_list_page(
96
+ meta_type: MetaType | InnerMetaType | str,
97
+ filters: Sequence[dict] | None = None,
98
+ headers: dict[str, str] | None = None,
99
+ datasource: str | None = None,
100
+ page: int = 0,
101
+ size: int = 20,
102
+ ):
103
+ """分页获取 Meta Release 列表.
104
+
105
+ Args:
106
+ type: 类型
107
+ filters: SQL 查询过滤条件列表
108
+ headers: 额外的请求头
109
+ datasource: 数据源
110
+ page: 页码
111
+ size: 每页大小
112
+
113
+ Returns:
114
+ list[MetaRelease] 对象列表
115
+
116
+ Raises:
117
+ DataOpsError: API 返回错误时
118
+ AuthenticationError: 未认证或认证失败时
119
+ """
120
+ type_str = meta_type.value if isinstance(meta_type, (MetaType, InnerMetaType)) else meta_type
121
+ url = "/meta/release/list/page"
122
+
123
+ sql_query_param = SqlQueryParam().add_eq("type", type_str, "mrl")
124
+
125
+ if page < 0:
126
+ raise ValueError("page must be greater than or equal to 0")
127
+
128
+ headers = headers or {}
129
+ if datasource:
130
+ headers["x-sub-system"] = datasource
131
+
132
+ body = {
133
+ "filters": to_jsonable_python(filters or []),
134
+ "pageParam": PageParam(start=page * size, limit=size),
135
+ "queryParam": sql_query_param,
136
+ }
137
+
138
+ try:
139
+ with get_session() as session:
140
+ resp = session.post(url, headers=headers, content=to_json(encrypt_body(body)))
141
+ resp_body = resp.json()
142
+ if resp.status_code == 401:
143
+ raise AuthenticationError("认证失败,请先登录")
144
+ if resp.status_code != 200:
145
+ raise DataOpsError(
146
+ resp_body.get("msg", f"HTTP {resp.status_code}"), resp.status_code
147
+ )
148
+ # TODO 修改
149
+ total = resp_body["data"]["total"]
150
+ page_num = resp_body["data"]["pageNum"]
151
+ page_size = resp_body["data"]["pageSize"]
152
+ group_nodes = TypeAdapter(
153
+ list[MetaRelease], config=ConfigDict(str_to_lower=True)
154
+ ).validate_python(resp_body["data"]["records"])
155
+ return group_nodes
156
+ except SystemExit as e:
157
+ raise AuthenticationError("认证失败,请先登录") from e
158
+
159
+
160
+ def release_list_total(
161
+ meta_type: MetaType | InnerMetaType | str,
162
+ filters: Sequence[dict] | None = None,
163
+ headers: dict[str, str] | None = None,
164
+ datasource: str | None = None,
165
+ ) -> int:
166
+ """获取 Meta Release 列表总数.
167
+
168
+ Args:
169
+ meta_type: 元数据类型
170
+ filters: SQL 查询过滤条件列表
171
+ headers: 额外的请求头
172
+ datasource: 数据源
173
+
174
+ Returns:
175
+ int 总数
176
+
177
+ Raises:
178
+ DataOpsError: API 返回错误时
179
+ AuthenticationError: 未认证或认证失败时
180
+ """
181
+ type_str = meta_type.value if isinstance(meta_type, (MetaType, InnerMetaType)) else meta_type
182
+ url = "/meta/release/list/page"
183
+
184
+ sql_query_param = SqlQueryParam().add_eq("type", type_str, "mrl")
185
+
186
+ headers = headers or {}
187
+ if datasource:
188
+ headers["x-sub-system"] = datasource
189
+
190
+ body = {
191
+ "filters": to_jsonable_python(filters or []),
192
+ "queryParam": sql_query_param,
193
+ }
194
+
195
+ try:
196
+ with get_session() as session:
197
+ resp = session.post(url, headers=headers, content=to_json(encrypt_body(body)))
198
+ resp_body = resp.json()
199
+ if resp.status_code == 401:
200
+ raise AuthenticationError("认证失败,请先登录")
201
+ if resp.status_code != 200:
202
+ raise DataOpsError(
203
+ resp_body.get("msg", f"HTTP {resp.status_code}"), resp.status_code
204
+ )
205
+ return resp_body["data"]
206
+ except SystemExit as e:
207
+ raise AuthenticationError("认证失败,请先登录") from e
208
+
209
+
210
+ def release_list_get_by_code(
211
+ meta_type: MetaType | InnerMetaType | str,
212
+ code: str,
213
+ headers: dict[str, str] | None = None,
214
+ *,
215
+ _class: type[META_DATA_TYPE] = DEFAULT_META_DATA_TYPE,
216
+ ) -> Meta[META_DATA_TYPE]:
217
+ """根据编码获取 Meta Release 数据.
218
+
219
+ Args:
220
+ meta_type: 元数据类型字符串
221
+ code: 元数据编码
222
+ headers: 额外的请求头
223
+
224
+ Returns:
225
+ 包含元数据的字典
226
+
227
+ Raises:
228
+ NotFoundError: 找不到对应元数据时
229
+ DataOpsError: API 返回错误时
230
+ AuthenticationError: 未认证或认证失败时
231
+ """
232
+ type_str = meta_type.value if isinstance(meta_type, (MetaType, InnerMetaType)) else meta_type
233
+ url = f"/meta/release/list/getByCode/{type_str}/{code}"
234
+
235
+ try:
236
+ with get_session() as session:
237
+ resp = session.get(url, headers=headers)
238
+ if resp.status_code == 401:
239
+ raise AuthenticationError("认证失败,请先登录")
240
+ if resp.status_code != 200:
241
+ msg = resp.json().get("msg", f"HTTP {resp.status_code}")
242
+ raise DataOpsError(
243
+ f"fail to get {type_str} by {code}, cause by {msg}", resp.status_code
244
+ )
245
+ resp_body = resp.json()
246
+ except SystemExit as e:
247
+ raise AuthenticationError("认证失败,请先登录") from e
248
+
249
+ if resp_body.get("data") is None:
250
+ raise NotFoundError(f"无法找到 {type_str} {code} 的信息")
251
+
252
+ raw_meta = resp_body["data"]
253
+ if not isinstance(raw_meta, dict):
254
+ raise DataOpsError(f"返回的数据格式不正确, 预期为字典, 实际为 {type(raw_meta)}")
255
+
256
+ return Meta[_class].model_validate(raw_meta)
257
+
258
+
259
+ def release_list_get_by_name(
260
+ meta_type: MetaType | InnerMetaType | str,
261
+ name: str,
262
+ headers: dict[str, str] | None = None,
263
+ *,
264
+ _class: type[META_DATA_TYPE] = DEFAULT_META_DATA_TYPE,
265
+ datasource: str | None = None,
266
+ ) -> Meta[META_DATA_TYPE]:
267
+ """根据名称获取 Meta Release 数据.
268
+
269
+ Args:
270
+ meta_type: 元数据类型字符串
271
+ name: 元数据名称
272
+ headers: 额外的请求头
273
+
274
+ Returns:
275
+ 包含元数据的字典
276
+
277
+ Raises:
278
+ NotFoundError: 找不到对应元数据时
279
+ DataOpsError: API 返回错误时
280
+ AuthenticationError: 未认证或认证失败时
281
+ """
282
+ type_str = meta_type.value if isinstance(meta_type, (MetaType, InnerMetaType)) else meta_type
283
+ url = f"/meta/release/list/getByName/{type_str}/{name}"
284
+
285
+ if datasource:
286
+ headers = headers or {}
287
+ headers["x-sub-system"] = datasource
288
+
289
+ try:
290
+ with get_session() as session:
291
+ resp = session.get(url, headers=headers)
292
+ if resp.status_code == 401:
293
+ raise AuthenticationError("认证失败,请先登录")
294
+ if resp.status_code != 200:
295
+ msg = resp.json().get("msg", f"HTTP {resp.status_code}")
296
+ raise DataOpsError(
297
+ f"fail to get {type_str} by {name}, cause by {msg}", resp.status_code
298
+ )
299
+ resp_body = resp.json()
300
+ except SystemExit as e:
301
+ raise AuthenticationError("认证失败,请先登录") from e
302
+
303
+ if resp_body.get("data") is None:
304
+ raise NotFoundError(f"无法找到 {type_str} {name} 的信息")
305
+
306
+ raw_meta = resp_body["data"]
307
+ if not isinstance(raw_meta, dict):
308
+ raise DataOpsError(f"返回的数据格式不正确, 预期为字典, 实际为 {type(raw_meta)}")
309
+
310
+ return Meta[_class].model_validate(raw_meta)
311
+
312
+
313
+ def release_ref_list(
314
+ meta_type: MetaType | InnerMetaType | str,
315
+ code: str,
316
+ headers: dict[str, str] | None = None,
317
+ ) -> list[MetaRef]:
318
+ """获取 Meta Release 的正向引用列表(查询自己引用了谁).
319
+
320
+ Args:
321
+ meta_type: 元数据类型 (如 "report", "table")
322
+ code: 元数据编码
323
+ headers: 额外的请求头
324
+
325
+ Returns:
326
+ list[MetaRef] 对象列表
327
+
328
+ Raises:
329
+ NotFoundError: 找不到对应元数据时
330
+ DataOpsError: API 返回错误时
331
+ AuthenticationError: 未认证或认证失败时
332
+ """
333
+ type_str = meta_type.value if isinstance(meta_type, (MetaType, InnerMetaType)) else meta_type
334
+ url = f"/meta/release/ref/list/{type_str}/{code}"
335
+
336
+ try:
337
+ with get_session() as session:
338
+ resp = session.get(url, headers=headers)
339
+ if resp.status_code == 401:
340
+ raise AuthenticationError("认证失败,请先登录")
341
+ if resp.status_code != 200:
342
+ raise DataOpsError(f"HTTP {resp.status_code}", resp.status_code)
343
+ resp_body = resp.json()
344
+ except SystemExit as e:
345
+ raise AuthenticationError("认证失败,请先登录") from e
346
+
347
+ if resp_body.get("data") is None:
348
+ raise NotFoundError(f"无法找到 {meta_type} {code} 的信息")
349
+ results = TypeAdapter(list[MetaRef]).validate_python(resp_body["data"])
350
+ return results
351
+
352
+
353
+ def release_ref_list_by_ref(
354
+ ref_type: MetaType | InnerMetaType | str,
355
+ ref_code: str,
356
+ headers: dict[str, str] | None = None,
357
+ ) -> list[MetaRef]:
358
+ """获取 Meta Release 的反向引用列表(查询谁引用了自己).
359
+
360
+ Args:
361
+ ref_type: 引用元数据类型 (如 "report", "table")
362
+ ref_code: 引用元数据编码
363
+ headers: 额外的请求头
364
+ deduplicate: 是否去重
365
+
366
+ Returns:
367
+ list[MetaRef] 对象列表
368
+
369
+ Raises:
370
+ NotFoundError: 找不到对应元数据时
371
+ DataOpsError: API 返回错误时
372
+ AuthenticationError: 未认证或认证失败时
373
+ """
374
+ type_str = ref_type.value if isinstance(ref_type, (MetaType, InnerMetaType)) else ref_type
375
+ url = f"/meta/release/ref/listByRef/{type_str}/{ref_code}"
376
+
377
+ try:
378
+ with get_session() as session:
379
+ resp = session.get(url, headers=headers)
380
+ if resp.status_code == 401:
381
+ raise AuthenticationError("认证失败,请先登录")
382
+ if resp.status_code != 200:
383
+ raise DataOpsError(f"HTTP {resp.status_code}", resp.status_code)
384
+ resp_body = resp.json()
385
+ except SystemExit as e:
386
+ raise AuthenticationError("认证失败,请先登录") from e
387
+
388
+ if resp_body.get("data") is None:
389
+ raise NotFoundError(f"无法找到 {ref_type} {ref_code} 的引用信息")
390
+ results = TypeAdapter(list[MetaRef]).validate_python(resp_body["data"])
391
+ return results
392
+
393
+
394
+ def release_list_create(
395
+ meta: MetaCreate[META_DATA_TYPE],
396
+ params: Sequence[Mapping[str, JsonValue]] | None = None,
397
+ *,
398
+ headers: dict[str, str] | None = None,
399
+ _class: type[META_DATA_TYPE] = DEFAULT_META_DATA_TYPE,
400
+ ) -> Meta[META_DATA_TYPE]:
401
+ """创建 Meta 对象.
402
+
403
+ Args:
404
+ meta: 要创建的元数据对象
405
+ params: 可选的查询参数列表,用于模板渲染
406
+ headers: 额外的请求头
407
+ _class: 返回的 Meta 数据类类型,默认为 Meta
408
+
409
+ Returns:
410
+ 创建成功的 Meta 对象
411
+
412
+ Raises:
413
+ FailedToCreateError: 创建失败时
414
+ DataOpsError: API 返回错误时
415
+ AuthenticationError: 未认证或认证失败时
416
+ """
417
+ body = {"meta": meta, "params": params}
418
+
419
+ try:
420
+ with get_session() as session:
421
+ resp = session.post(
422
+ "/meta/release/list/create",
423
+ headers=headers,
424
+ content=to_json(encrypt_body(body)),
425
+ )
426
+ resp_body = resp.json()
427
+ if resp.status_code == 401:
428
+ raise AuthenticationError("认证失败,请先登录")
429
+ if resp.status_code != 200:
430
+ raise DataOpsError(
431
+ resp_body.get("msg", f"HTTP {resp.status_code}"), resp.status_code
432
+ )
433
+
434
+ except SystemExit as e:
435
+ raise AuthenticationError("认证失败,请先登录") from e
436
+ if resp_body.get("data") is None:
437
+ raise FailedToCreateError("创建失败")
438
+
439
+ raw_meta = resp_body["data"]
440
+ if not isinstance(raw_meta, dict):
441
+ raise DataOpsError(f"返回的数据格式不正确, 预期为字典, 实际为 {type(raw_meta)}")
442
+
443
+ return Meta[_class].model_validate(raw_meta)
444
+
445
+
446
+ def release_list_update(
447
+ meta: Meta[META_DATA_TYPE],
448
+ # origin_meta: Meta[META_DATA_TYPE],
449
+ # meta: MetaUpdate[META_DATA_TYPE],
450
+ *,
451
+ headers: dict[str, str] | None = None,
452
+ datasource: str | None = None,
453
+ _class: type[META_DATA_TYPE] = DEFAULT_META_DATA_TYPE,
454
+ ):
455
+ """更新 Meta 对象.
456
+
457
+ Args:
458
+ meta: 元数据对象
459
+ headers: 额外的请求头
460
+ _class: 返回的 Meta 数据类类型,默认为 Meta
461
+
462
+ Returns:
463
+ 更新后的 Meta 对象
464
+
465
+ Raises:
466
+ DataOpsError: API 返回错误时
467
+ AuthenticationError: 未认证或认证失败时
468
+ """
469
+ """更新 Meta 对象.
470
+
471
+ Args:
472
+ origin_meta: 原始的元数据对象(更新前的完整对象)
473
+ meta: 要更新的元数据字段(支持部分更新,仅传入需要修改的字段)
474
+ headers: 额外的请求头
475
+ _class: 返回的 Meta 数据类类型,默认为 Meta
476
+
477
+ Returns:
478
+ 更新后的 Meta 对象
479
+
480
+ Raises:
481
+ DataOpsError: API 返回错误时
482
+ AuthenticationError: 未认证或认证失败时
483
+ """
484
+ # body = dict(meta=meta)
485
+ body = dict(meta=meta.model_dump(mode="json", exclude_defaults=True))
486
+ # body = {
487
+ # "meta": deep_merge(
488
+ # origin_meta.model_dump(exclude_defaults=True), meta.model_dump(exclude_defaults=True)
489
+ # )
490
+ # }
491
+ # old: 2076921409387933698
492
+ # new: 2076921409387933698
493
+ if datasource:
494
+ headers = headers or {}
495
+ headers["x-sub-system"] = datasource
496
+ # with open('update.json', 'wb') as f:
497
+ # f.write(to_json(body, indent=2))
498
+
499
+ # try:
500
+ # with get_session() as session:
501
+ # resp = session.post(
502
+ # "/meta/release/list/update",
503
+ # headers=headers,
504
+ # content=to_json(encrypt_body(body)),
505
+ # )
506
+ # resp_body = resp.json()
507
+ # if resp.status_code == 401:
508
+ # raise AuthenticationError("认证失败,请先登录")
509
+ # if resp.status_code != 200:
510
+ # raise DataOpsError(
511
+ # resp_body.get("msg", f"HTTP {resp.status_code}"), resp.status_code
512
+ # )
513
+
514
+ # except SystemExit as e:
515
+ # raise AuthenticationError("认证失败,请先登录") from e
516
+ # if resp_body.get("data") is None:
517
+ # raise FailedToUpdateError(f"创建失败")
518
+
519
+ # raw_meta = resp_body["data"]
520
+ # if not isinstance(raw_meta, dict):
521
+ # raise DataOpsError(f"返回的数据格式不正确, 预期为字典, 实际为 {type(raw_meta)}")
522
+
523
+ # return Meta[_class].model_validate(raw_meta)
@@ -0,0 +1,42 @@
1
+ """指标服务."""
2
+
3
+ from collections.abc import Mapping
4
+
5
+ from pydantic import JsonValue
6
+
7
+ from dataops_sdk.schemas import Meta, MetaRelease, MetaType
8
+ from dataops_sdk.services.meta import release_list_get_by_code, release_list_list
9
+ from dataops_sdk.utils import filter_nodes_by_pattern
10
+
11
+ __all__ = ["service_list_metrics", "service_get_metrics"]
12
+
13
+
14
+ def service_list_metrics(query: str | None = None) -> list[MetaRelease]:
15
+ """列出指标(可选正则过滤).
16
+
17
+ Args:
18
+ query: 正则表达式,匹配 NAME / TITLE / REMARK / DIGEST
19
+
20
+ Returns:
21
+ MetaRelease 对象列表
22
+
23
+ Raises:
24
+ DataOpsError: API 请求失败时
25
+ AuthenticationError: 未认证时
26
+ """
27
+ nodes = release_list_list(MetaType.METRICS)
28
+ if query:
29
+ nodes = filter_nodes_by_pattern(nodes, query, include_digest=True)
30
+ return nodes
31
+
32
+
33
+ def service_get_metrics(code: str) -> Meta[Mapping[str, JsonValue]]:
34
+ """获取指标详情.
35
+
36
+ Args:
37
+ code: 指标编码
38
+
39
+ Returns:
40
+ 指标元数据。`meta.data` 结构详见后端指标定义。
41
+ """
42
+ return release_list_get_by_code(MetaType.METRICS, code)
@@ -0,0 +1,66 @@
1
+ from collections.abc import Sequence
2
+
3
+ from dataops_sdk.schemas import MetaRef, MetaType
4
+ from dataops_sdk.services.meta import release_ref_list, release_ref_list_by_ref
5
+
6
+ __all__ = ["service_ref_forward", "service_ref_backward"]
7
+
8
+
9
+ def service_ref_forward(
10
+ meta_type: MetaType | str,
11
+ code: str,
12
+ ref_types: Sequence[str] | None = None,
13
+ *,
14
+ deduplicate: bool = False,
15
+ ) -> list[MetaRef]:
16
+ """正向引用查询:查询自己引用了谁。
17
+
18
+ Args:
19
+ meta_type: 元数据类型 (如 "table")
20
+ code: 元数据编码
21
+ ref_types: 仅返回指定的被引用类型过滤(如 ["table", "dict"])
22
+ deduplicate: 是否去重
23
+
24
+ Returns:
25
+ MetaRef 对象列表
26
+ """
27
+ results = release_ref_list(meta_type, code)
28
+ if ref_types:
29
+ results = [r for r in results if r.refType in ref_types]
30
+ return deduplicate_refs(results) if deduplicate else results
31
+
32
+
33
+ def service_ref_backward(
34
+ meta_type: MetaType | str,
35
+ code: str,
36
+ ref_types: Sequence[str] | None = None,
37
+ *,
38
+ deduplicate: bool = False,
39
+ ) -> list[MetaRef]:
40
+ """反向引用查询:查询谁引用了自己。
41
+
42
+ Args:
43
+ meta_type: 被引用类型 (如 "table")
44
+ code: 被引用编码
45
+ ref_types: 仅返回指定的引用类型过滤(如 ["table", "dict"])
46
+ deduplicate: 是否去重
47
+
48
+ Returns:
49
+ MetaRef 对象列表
50
+ """
51
+ results = release_ref_list_by_ref(meta_type, code)
52
+ if ref_types:
53
+ results = [r for r in results if r.type in ref_types]
54
+ return deduplicate_refs(results) if deduplicate else results
55
+
56
+
57
+ def deduplicate_refs(refs: list[MetaRef]) -> list[MetaRef]:
58
+ """根据 (code, type) 去重。"""
59
+ seen: set[tuple[str, str]] = set()
60
+ deduped: list[MetaRef] = []
61
+ for r in refs:
62
+ key = (r.code, r.type)
63
+ if key not in seen:
64
+ seen.add(key)
65
+ deduped.append(r)
66
+ return deduped
@@ -0,0 +1,36 @@
1
+ from dataops_sdk.schemas import MetaRelease, MetaType, ReportMetaData
2
+ from dataops_sdk.services import release_list_get_by_code, release_list_list
3
+ from dataops_sdk.utils import filter_nodes_by_pattern
4
+
5
+ __all__ = ["service_get_report", "service_list_reports"]
6
+
7
+
8
+ def service_list_reports(query: str | None = None) -> list[MetaRelease]:
9
+ """列出文档(可选正则过滤).
10
+
11
+ Args:
12
+ query: 正则表达式,匹配 NAME / TITLE / REMARK / DIGEST
13
+
14
+ Returns:
15
+ MetaRelease 对象列表
16
+
17
+ Raises:
18
+ DataOpsError: API 请求失败时
19
+ AuthenticationError: 未认证时
20
+ """
21
+ nodes = release_list_list(MetaType.REPORT)
22
+ if query:
23
+ nodes = filter_nodes_by_pattern(nodes, query, include_digest=True)
24
+ return nodes
25
+
26
+
27
+ def service_get_report(code: str) -> ReportMetaData:
28
+ """读取文档内容并渲染为 Markdown.
29
+
30
+ Args:
31
+ code: 文档编码
32
+
33
+ Returns:
34
+ 渲染后的 Markdown 字符串
35
+ """
36
+ return release_list_get_by_code(MetaType.REPORT, code, _class=ReportMetaData)