maxc-cli 0.9.3__tar.gz → 0.9.5b1__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.
Files changed (143) hide show
  1. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/PKG-INFO +13 -2
  2. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/README.md +12 -1
  3. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/__init__.py +1 -1
  4. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/app.py +20 -2
  5. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/auth.py +80 -20
  6. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/catalog.py +6 -2
  7. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/odps.py +40 -3
  8. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/semantic.py +48 -15
  9. maxc_cli-0.9.5b1/src/maxc_cli/catalog_endpoint.py +42 -0
  10. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/cli.py +4 -2
  11. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/semantic_management.py +1 -1
  12. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/semantic-packages.md +5 -2
  13. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli.egg-info/PKG-INFO +13 -2
  14. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli.egg-info/SOURCES.txt +2 -0
  15. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_query_result_csv_fallback.py +110 -0
  16. maxc_cli-0.9.5b1/tests/test_semantic_identity_endpoints.py +93 -0
  17. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_semantic_management.py +14 -2
  18. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/MANIFEST.in +0 -0
  19. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/pyproject.toml +0 -0
  20. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/scripts/pyinstaller_entry.py +0 -0
  21. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/scripts/regression_test.py +0 -0
  22. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/setup.cfg +0 -0
  23. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/setup.py +0 -0
  24. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/__main__.py +0 -0
  25. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/_samples.py +0 -0
  26. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/agent_platforms.py +0 -0
  27. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/audit.py +0 -0
  28. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/auth_continuation.py +0 -0
  29. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/auth_providers.py +0 -0
  30. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/__init__.py +0 -0
  31. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/data.py +0 -0
  32. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/job.py +0 -0
  33. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/mcp.py +0 -0
  34. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/meta.py +0 -0
  35. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/backend/query.py +0 -0
  36. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/cache.py +0 -0
  37. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/catalog_bootstrap.py +0 -0
  38. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/config.py +0 -0
  39. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/enterprise_tls.py +0 -0
  40. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/exceptions.py +0 -0
  41. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/function_metadata.py +0 -0
  42. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/help_format.py +0 -0
  43. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/helpers.py +0 -0
  44. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/job_ids.py +0 -0
  45. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/masking.py +0 -0
  46. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/mcp_serve.py +0 -0
  47. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/models.py +0 -0
  48. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/oauth.py +0 -0
  49. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/odps_runtime.py +0 -0
  50. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/output.py +0 -0
  51. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/proxy_auth.py +0 -0
  52. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/semantic.py +0 -0
  53. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/setting_parser.py +0 -0
  54. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/SKILL.md +0 -0
  55. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/agents/openai.yaml +0 -0
  56. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/bootstrap-auth.md +0 -0
  57. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/bootstrap-flow.md +0 -0
  58. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/command-patterns.md +0 -0
  59. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/json-output-format.md +0 -0
  60. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/maxcompute-select-guide.md +0 -0
  61. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/maxcompute-sql-notes.md +0 -0
  62. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/partition-guide.md +0 -0
  63. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/red-lines.md +0 -0
  64. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/registered-functions.md +0 -0
  65. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/setup-install.md +0 -0
  66. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/sql-common-errors.md +0 -0
  67. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/sql-query-patterns.md +0 -0
  68. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/skills/references/text2sql-principles.md +0 -0
  69. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/state_permissions.py +0 -0
  70. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/store.py +0 -0
  71. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli/utils.py +0 -0
  72. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli.egg-info/dependency_links.txt +0 -0
  73. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli.egg-info/entry_points.txt +0 -0
  74. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli.egg-info/requires.txt +0 -0
  75. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/src/maxc_cli.egg-info/top_level.txt +0 -0
  76. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_agent_hints_and_cli.py +0 -0
  77. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_agent_platforms.py +0 -0
  78. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_agent_skill_commands.py +0 -0
  79. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_agent_skill_commands_context.py +0 -0
  80. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_ai_native_contract_regressions.py +0 -0
  81. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_auth_logout.py +0 -0
  82. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_backend_auth.py +0 -0
  83. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_backend_data.py +0 -0
  84. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_backend_data_serialization.py +0 -0
  85. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_backend_mcp.py +0 -0
  86. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_backend_meta.py +0 -0
  87. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_backend_query_cost.py +0 -0
  88. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_build_release_archive_compat.py +0 -0
  89. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_build_release_script.py +0 -0
  90. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_cache.py +0 -0
  91. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_catalog.py +0 -0
  92. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_catalog_bootstrap.py +0 -0
  93. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_cli_arg_validation.py +0 -0
  94. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_cli_mock.py +0 -0
  95. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_cli_query_parse_and_sanitize.py +0 -0
  96. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_compat.py +0 -0
  97. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_config_atomic_write.py +0 -0
  98. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_connection_bootstrap.py +0 -0
  99. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_e2e_smoke.py +0 -0
  100. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_effective_hints_contract.py +0 -0
  101. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_enterprise_tls.py +0 -0
  102. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_envelope_shape.py +0 -0
  103. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_error_self_correction.py +0 -0
  104. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_error_translation.py +0 -0
  105. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_exit_codes.py +0 -0
  106. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_external_auth.py +0 -0
  107. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_flag_hoist.py +0 -0
  108. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_help_format.py +0 -0
  109. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_help_version_e2e.py +0 -0
  110. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_helpers.py +0 -0
  111. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_helpers_csv.py +0 -0
  112. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_installer_contracts.py +0 -0
  113. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_integration.py +0 -0
  114. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_integration_real.py +0 -0
  115. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_job_improvements.py +0 -0
  116. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_job_inspection.py +0 -0
  117. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_job_store_durability.py +0 -0
  118. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_kb_commands.py +0 -0
  119. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_manifest_runtime_contract.py +0 -0
  120. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_masking.py +0 -0
  121. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_mcp_serve.py +0 -0
  122. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_meta_schema_and_partition_cols.py +0 -0
  123. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_oauth.py +0 -0
  124. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_odps_runtime.py +0 -0
  125. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_output_action_safety.py +0 -0
  126. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_output_format_contract.py +0 -0
  127. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_packaging_metadata.py +0 -0
  128. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_phase1_improvements.py +0 -0
  129. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_proxy_auth.py +0 -0
  130. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_pyinstaller_bundle.py +0 -0
  131. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_python39_compat.py +0 -0
  132. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_query_auto_promote.py +0 -0
  133. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_query_namespace_settings.py +0 -0
  134. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_registered_functions.py +0 -0
  135. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_semantic_scope.py +0 -0
  136. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_semantic_transport.py +0 -0
  137. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_setting_parser.py +0 -0
  138. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_skill_cli_consistency.py +0 -0
  139. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_skill_eval.py +0 -0
  140. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_skill_renderer.py +0 -0
  141. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_startup_imports.py +0 -0
  142. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_state_permissions.py +0 -0
  143. {maxc_cli-0.9.3 → maxc_cli-0.9.5b1}/tests/test_state_portability.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maxc-cli
3
- Version: 0.9.3
3
+ Version: 0.9.5b1
4
4
  Summary: Agent-native MaxCompute CLI for external coding agents
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: Programming Language :: Python :: 3.9
@@ -304,7 +304,7 @@ To return to local signing, explicitly run the appropriate `auth login` command.
304
304
  ## Versioned semantic packages
305
305
 
306
306
  `maxc semantic` manages remote Catalog packages using the current connection.
307
- Specify the verified main-account ID with `--namespace`. Available operations:
307
+ The namespace is auto-discovered from verified authenticated account identity when possible; otherwise pass an independently verified main-account ID with `--namespace`. Available operations:
308
308
  `list`, `get`, `revisions`, `export`, `create`, `diff`, `apply`, `publish`, `delete`.
309
309
  `meta semantic` continues to manage local annotations.
310
310
 
@@ -324,6 +324,7 @@ write must be reconciled before retrying. Publication checks are not SQL or
324
324
  business validation. History lists the latest 20 summaries, and an immutable
325
325
  revision read does not guarantee historical DataBridge analysis.
326
326
 
327
+
327
328
  ### Task metrics and worker logs
328
329
 
329
330
  ```bash
@@ -338,3 +339,13 @@ Task detail preserves the service payload (including `mapReduce.jsonSummary`).
338
339
  Select `log_id` from `data.workers`; logs are returned as `data.content` in the JSON
339
340
  envelope. The requested size defaults to 1 MiB and must be positive; returned logs
340
341
  may be partial. Use `--project` to select the owning project explicitly.
342
+
343
+ Source-specific dbt semantic conversion is maintained by dbt-maxcompute (`dbt run-operation dbt_maxcompute.export_semantic_package`). maxc supplies generic package management and `meta describe --metadata-only` for live schema inspection.
344
+
345
+ ## 语义包试用版
346
+
347
+ ```bash
348
+ python -m pip install 'maxc-cli==0.9.5b1'
349
+ ```
350
+
351
+ 0.9.5b1 支持从可信账号身份解析 namespace,兼容旧版 PyODPS 返回的 Catalog 域名,并提供 `meta describe --metadata-only`。参见[语义包中文指南](docs/semantic-packages.zh-CN.md)。dbt 转换使用适配器自带的 `dbt run-operation dbt_maxcompute.export_semantic_package` 宏。
@@ -282,7 +282,7 @@ To return to local signing, explicitly run the appropriate `auth login` command.
282
282
  ## Versioned semantic packages
283
283
 
284
284
  `maxc semantic` manages remote Catalog packages using the current connection.
285
- Specify the verified main-account ID with `--namespace`. Available operations:
285
+ The namespace is auto-discovered from verified authenticated account identity when possible; otherwise pass an independently verified main-account ID with `--namespace`. Available operations:
286
286
  `list`, `get`, `revisions`, `export`, `create`, `diff`, `apply`, `publish`, `delete`.
287
287
  `meta semantic` continues to manage local annotations.
288
288
 
@@ -302,6 +302,7 @@ write must be reconciled before retrying. Publication checks are not SQL or
302
302
  business validation. History lists the latest 20 summaries, and an immutable
303
303
  revision read does not guarantee historical DataBridge analysis.
304
304
 
305
+
305
306
  ### Task metrics and worker logs
306
307
 
307
308
  ```bash
@@ -316,3 +317,13 @@ Task detail preserves the service payload (including `mapReduce.jsonSummary`).
316
317
  Select `log_id` from `data.workers`; logs are returned as `data.content` in the JSON
317
318
  envelope. The requested size defaults to 1 MiB and must be positive; returned logs
318
319
  may be partial. Use `--project` to select the owning project explicitly.
320
+
321
+ Source-specific dbt semantic conversion is maintained by dbt-maxcompute (`dbt run-operation dbt_maxcompute.export_semantic_package`). maxc supplies generic package management and `meta describe --metadata-only` for live schema inspection.
322
+
323
+ ## 语义包试用版
324
+
325
+ ```bash
326
+ python -m pip install 'maxc-cli==0.9.5b1'
327
+ ```
328
+
329
+ 0.9.5b1 支持从可信账号身份解析 namespace,兼容旧版 PyODPS 返回的 Catalog 域名,并提供 `meta describe --metadata-only`。参见[语义包中文指南](docs/semantic-packages.zh-CN.md)。dbt 转换使用适配器自带的 `dbt run-operation dbt_maxcompute.export_semantic_package` 宏。
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.9.3"
5
+ __version__ = "0.9.5b1"
@@ -2412,6 +2412,7 @@ class MaxCApp:
2412
2412
  project: 'str | None' = None,
2413
2413
  *,
2414
2414
  schema: 'str | None' = None,
2415
+ metadata_only: bool = False,
2415
2416
  ) -> 'Envelope':
2416
2417
  started = monotonic()
2417
2418
  (
@@ -2422,6 +2423,23 @@ class MaxCApp:
2422
2423
  qualified_name,
2423
2424
  ) = self._resolve_table_scope(table_name, project=project, schema=schema)
2424
2425
 
2426
+ if metadata_only:
2427
+ table = self.backend.describe_table_metadata(
2428
+ target_table, project=target_project, schema=effective_schema,
2429
+ )
2430
+ payload = {
2431
+ "table_name": table.name,
2432
+ "schema_name": effective_schema,
2433
+ "project": target_project,
2434
+ "columns": [{"name": c.name, "type": c.type} for c in table.columns],
2435
+ "partition_columns": [{"name": c.name, "type": c.type} for c in table.partition_columns or []],
2436
+ "has_more_columns": False,
2437
+ }
2438
+ envelope = Envelope(command="meta.describe", status="success", data=payload,
2439
+ metadata={"source": "live", "metadata_only": True})
2440
+ self.log("meta.describe", envelope.status, envelope.metadata)
2441
+ return envelope
2442
+
2425
2443
  # Try to get from cache first
2426
2444
  cached_table = self.cache.get_cached_table(
2427
2445
  target_project,
@@ -2931,14 +2949,14 @@ class MaxCApp:
2931
2949
  raise ValidationError("--schema must not be empty.")
2932
2950
  return target_project, target_schema
2933
2951
 
2934
- def semantic_manage(self, operation: str, *, namespace: str, **options) -> 'Envelope':
2952
+ def semantic_manage(self, operation: str, *, namespace: 'str | None' = None, **options) -> 'Envelope':
2935
2953
  """Run a remote SemanticSpec workflow, separate from local annotations."""
2936
2954
  from .semantic_management import SemanticManager
2937
2955
 
2938
2956
  manager = SemanticManager(self.backend, namespace)
2939
2957
  data = manager.execute(operation, **options)
2940
2958
  command = "semantic." + operation
2941
- metadata = {"namespace": namespace}
2959
+ metadata = {"namespace": manager.namespace}
2942
2960
  envelope = Envelope(command=command, status="success", data=data,
2943
2961
  metadata=metadata, agent_hints=AgentHints(warnings=manager.warnings))
2944
2962
  self.log(command, envelope.status, metadata)
@@ -1,6 +1,7 @@
1
1
  """Auth-related mixin for OdpsBackend."""
2
2
 
3
3
  import json
4
+ import re
4
5
  from typing import Any
5
6
  from urllib.parse import quote
6
7
  from xml.etree import ElementTree
@@ -14,10 +15,52 @@ from ..helpers import (
14
15
  )
15
16
 
16
17
 
18
+ def semantic_account_identity(result):
19
+ """Resolve only server-verified IDs; never infer ownership from a project."""
20
+ raw = result if isinstance(result, dict) else {}
21
+
22
+ def numeric(value):
23
+ return value if isinstance(value, str) and re.fullmatch(r"[0-9]{1,32}", value) else None
24
+
25
+ raw_id = raw.get("ID")
26
+ display = raw.get("DisplayName")
27
+ display = display if isinstance(display, str) else ""
28
+ is_main = bool(re.fullmatch(r"ALIYUN\$[^$:\s]+", display))
29
+ is_ram = display.startswith("RAM$")
30
+ composite = (
31
+ re.fullmatch(r"([0-9]{1,32}):([0-9]{1,32}|role/[A-Za-z0-9_+=,.@-]{1,128})", raw_id)
32
+ if isinstance(raw_id, str)
33
+ else None
34
+ )
35
+ principal = raw_id if composite else numeric(raw_id)
36
+ kind = (
37
+ "MAIN_ACCOUNT"
38
+ if is_main
39
+ else ("RAM_ROLE" if is_ram and ":role/" in display else "RAM_USER" if is_ram else "UNKNOWN")
40
+ )
41
+ account = numeric(raw.get("AccountId"))
42
+ source = "whoami.AccountId" if account else None
43
+ resolved = numeric(raw_id) if is_main else composite.group(1) if is_ram and composite else None
44
+ if resolved:
45
+ if account and account != resolved:
46
+ raise ValidationError(
47
+ "Conflicting account identity returned by whoami; namespace discovery stopped."
48
+ )
49
+ account = resolved
50
+ source = "whoami.main_account.ID" if is_main else "whoami.RAM.ID.account_prefix"
51
+ return {
52
+ "principal_id": principal,
53
+ "principal_type": kind,
54
+ "account_id": account,
55
+ "semantic_namespace": account,
56
+ "semantic_namespace_source": source,
57
+ }
58
+
59
+
17
60
  class AuthMixin:
18
61
  """Mixin providing authentication and authorization methods."""
19
62
 
20
- def whoami_info(self, *, project: 'str | None' = None) -> 'tuple[dict[str, Any], list[str]]':
63
+ def whoami_info(self, *, project: "str | None" = None) -> "tuple[dict[str, Any], list[str]]":
21
64
  """Get current identity info by executing ``whoami`` security query.
22
65
 
23
66
  Calls ``client.execute_security_query("whoami")`` to verify the
@@ -38,7 +81,7 @@ class AuthMixin:
38
81
  owner_display_name = result.get("DisplayName") if isinstance(result, dict) else None
39
82
  if owner_display_name:
40
83
  self._owner_display_name = owner_display_name
41
- return build_odps_identity_payload(
84
+ payload, warnings = build_odps_identity_payload(
42
85
  client=self.client,
43
86
  settings=self.settings,
44
87
  allowed_operations=self.config.allowed_operations,
@@ -48,16 +91,33 @@ class AuthMixin:
48
91
  project=target_project,
49
92
  owner_display_name=owner_display_name,
50
93
  )
94
+ identity = semantic_account_identity(result)
95
+ payload.update(identity)
96
+ if identity["semantic_namespace"] is None:
97
+ warnings.append(
98
+ "Main-account namespace could not be verified; pass an independently verified --namespace for semantic commands."
99
+ )
100
+ return payload, warnings
101
+
102
+ def semantic_namespace(self):
103
+ """Return the verified account namespace, or require an explicit override."""
104
+ payload, _ = self.whoami_info()
105
+ value = payload.get("semantic_namespace")
106
+ if not value:
107
+ raise ValidationError(
108
+ "Cannot verify the main-account namespace for this identity. Pass --namespace with an independently verified main-account ID; do not use a RAM principal ID or project tenant ID."
109
+ )
110
+ return value
51
111
 
52
112
  def _check_permission(
53
113
  self,
54
114
  *,
55
- object_name: 'str',
56
- object_type: 'str',
57
- action: 'str',
58
- project: 'str',
59
- schema: 'str | None' = None,
60
- ) -> 'tuple[bool, str]':
115
+ object_name: "str",
116
+ object_type: "str",
117
+ action: "str",
118
+ project: "str",
119
+ schema: "str | None" = None,
120
+ ) -> "tuple[bool, str]":
61
121
  """Call the schema-aware MaxCompute checkPermission REST API.
62
122
 
63
123
  This mirrors the current Java SDK ``SecurityManager#checkPermission``
@@ -128,11 +188,11 @@ class AuthMixin:
128
188
  def _resolve_permission_target(
129
189
  self,
130
190
  *,
131
- object_name: 'str',
132
- object_type: 'str',
133
- project: 'str | None',
134
- schema: 'str | None',
135
- ) -> 'tuple[str, str, str | None, str]':
191
+ object_name: "str",
192
+ object_type: "str",
193
+ project: "str | None",
194
+ schema: "str | None",
195
+ ) -> "tuple[str, str, str | None, str]":
136
196
  """Resolve a permission target without relying on server error guesses.
137
197
 
138
198
  Table-like names accept ``table``, ``schema.table`` and
@@ -233,12 +293,12 @@ class AuthMixin:
233
293
  def can_i_info(
234
294
  self,
235
295
  *,
236
- object_name: 'str',
237
- object_type: 'str' = "Table",
238
- operation: 'str',
239
- project: 'str | None' = None,
240
- schema: 'str | None' = None,
241
- ) -> 'tuple[dict[str, Any], list[str]]':
296
+ object_name: "str",
297
+ object_type: "str" = "Table",
298
+ operation: "str",
299
+ project: "str | None" = None,
300
+ schema: "str | None" = None,
301
+ ) -> "tuple[dict[str, Any], list[str]]":
242
302
  """Check if a specific operation is allowed on an object.
243
303
 
244
304
  Calls the MaxCompute checkPermission REST API directly.
@@ -292,7 +352,7 @@ class AuthMixin:
292
352
  [],
293
353
  )
294
354
 
295
- def _get_owner_display_name(self) -> 'str | None':
355
+ def _get_owner_display_name(self) -> "str | None":
296
356
  """Get the current user's display name (e.g., 'ALIYUN$xxx' or 'RAM$xxx')."""
297
357
  if self._owner_display_name is not None:
298
358
  return self._owner_display_name
@@ -24,6 +24,8 @@ import json
24
24
  import logging
25
25
  from typing import Any
26
26
 
27
+ from ..catalog_endpoint import normalize_catalog_endpoint
28
+
27
29
  logger = logging.getLogger(__name__)
28
30
 
29
31
  # KV store keys — scoped by project to handle multi-tenant setups
@@ -117,14 +119,16 @@ class CatalogMixin:
117
119
  max_age_hours=_CACHE_TTL_HOURS,
118
120
  )
119
121
  if cached is not None:
120
- self._catalog_ep_cached = cached
121
- return cached
122
+ self._catalog_ep_cached = normalize_catalog_endpoint(cached)
123
+ return self._catalog_ep_cached
122
124
 
123
125
  # Network call via pyodps auto-routing
124
126
  try:
125
127
  odps = self.client
126
128
  if odps is not None:
127
129
  ep = odps.catalog_endpoint
130
+ if ep is not None:
131
+ ep = normalize_catalog_endpoint(ep)
128
132
  if ep is not None and cache is not None:
129
133
  cache.set_kv(self._cache_key(_CATALOG_EP_KEY), ep)
130
134
  self._catalog_ep_cached = ep
@@ -13,7 +13,7 @@ from ..helpers import (
13
13
  translate_odps_error,
14
14
  )
15
15
  from ..models import QueryResult
16
- from ..utils import detect_operation, extract_table_names
16
+ from ..utils import detect_operation, extract_table_names, sql_keyword_tokens, sql_statements
17
17
  from .auth import AuthMixin
18
18
  from .catalog import CatalogMixin
19
19
  from .data import DataMixin
@@ -75,6 +75,26 @@ def _raw_task_result_rows(task_results: 'dict[str, Any]') -> 'list[dict[str, Any
75
75
  ]
76
76
 
77
77
 
78
+ def _is_show_partitions(sql: 'str') -> 'bool':
79
+ statements = sql_statements(sql)
80
+ return len(statements) == 1 and sql_keyword_tokens(statements[0])[:2] == ["SHOW", "PARTITIONS"]
81
+
82
+
83
+ def _show_partition_rows(task_results: 'Any') -> 'list[dict[str, str]]':
84
+ """SHOW PARTITIONS emits headerless lines, not a CSV table with a header."""
85
+ if not isinstance(task_results, dict):
86
+ raise ValueError("SHOW PARTITIONS returned invalid task results")
87
+ rows = []
88
+ for text in task_results.values():
89
+ if text is None:
90
+ continue
91
+ if not isinstance(text, str):
92
+ raise ValueError("SHOW PARTITIONS returned invalid task result text")
93
+ # Split only protocol line endings; Unicode separators may be values.
94
+ rows.extend({"partition": line.removesuffix("\r")} for line in text.split("\n") if line.removesuffix("\r"))
95
+ return rows
96
+
97
+
78
98
  class OdpsBackend(
79
99
  JobMixin, # JobMixin extends QueryMixin
80
100
  CatalogMixin,
@@ -123,11 +143,12 @@ class OdpsBackend(
123
143
  ) -> 'QueryResult':
124
144
  """Convert ODPS instance to QueryResult."""
125
145
  fallback_warnings: list[str] = []
146
+ show_partitions = _is_show_partitions(sql)
126
147
  statement_operation = _write_operation(sql)
127
148
  instance_is_select = getattr(instance, "_is_select", None)
128
149
  confirmed_task_results = None
129
150
  resultless_statement = statement_operation is not None and instance_is_select is not True
130
- if not resultless_statement and instance_is_select is False:
151
+ if not show_partitions and not resultless_statement and instance_is_select is False:
131
152
  try:
132
153
  task_results = instance.get_task_results()
133
154
  except Exception:
@@ -140,7 +161,23 @@ class OdpsBackend(
140
161
  resultless_statement = not any(str(value or "").strip() for value in task_results.values())
141
162
  if resultless_statement and sql.strip():
142
163
  statement_operation = detect_operation(sql)
143
- if resultless_statement:
164
+ if show_partitions:
165
+ try:
166
+ # The generic CSV reader consumes the first partition as a
167
+ # header and raises on an empty body. Read this known textual
168
+ # result directly, retaining lookup failures as real errors.
169
+ all_rows = _show_partition_rows(instance.get_task_results())
170
+ except Exception as exc:
171
+ error = translate_odps_error(exc)
172
+ error.instance_id = instance.id
173
+ error.logview = self._safe_logview(instance)
174
+ raise error from exc
175
+ schema = [{"name": "partition", "type": "string", "comment": ""}]
176
+ rows = all_rows[offset : offset + max_rows]
177
+ total_rows = len(all_rows)
178
+ degraded_reason = None
179
+ resultless_statement = False
180
+ elif resultless_statement:
144
181
  # Successful write statements have no tabular result. In
145
182
  # particular, PyODPS's DDL fallback reader may try to iterate a
146
183
  # missing task_results value and raise after the server job has
@@ -11,6 +11,7 @@ from urllib.parse import quote, urlsplit, urlunsplit
11
11
  import requests
12
12
  from odps import options
13
13
 
14
+ from ..catalog_endpoint import normalize_catalog_endpoint
14
15
  from ..exceptions import MaxCError, ValidationError
15
16
  from ..semantic import MAX_FILE_BYTES, SemanticError, identifier, namespace_id
16
17
 
@@ -31,12 +32,18 @@ def _failure(status, code, *, mutation):
31
32
  "InvalidArgument": "VALIDATION_ERROR",
32
33
  }
33
34
  mapped = known.get(code) or {
34
- 400: "VALIDATION_ERROR", 401: "SEMANTIC_AUTHENTICATION_FAILED",
35
- 403: "SEMANTIC_PERMISSION_DENIED", 404: "SEMANTIC_NOT_FOUND",
35
+ 400: "VALIDATION_ERROR",
36
+ 401: "SEMANTIC_AUTHENTICATION_FAILED",
37
+ 403: "SEMANTIC_PERMISSION_DENIED",
38
+ 404: "SEMANTIC_NOT_FOUND",
36
39
  409: "SEMANTIC_REVISION_CONFLICT",
37
40
  }.get(status)
38
41
  mapped = mapped or ("SEMANTIC_WRITE_UNCERTAIN" if mutation else "SEMANTIC_CONNECTION_ERROR")
39
- return SemanticError(mapped, "Catalog semantic operation failed; inspect the object before retrying.", context={"httpStatus": status})
42
+ return SemanticError(
43
+ mapped,
44
+ "Catalog semantic operation failed; inspect the object before retrying.",
45
+ context={"httpStatus": status},
46
+ )
40
47
 
41
48
 
42
49
  class SemanticMixin:
@@ -47,11 +54,10 @@ class SemanticMixin:
47
54
  try:
48
55
  endpoint = self.client.catalog_rest.endpoint.rstrip("/")
49
56
  except Exception as exc:
50
- raise SemanticError("SEMANTIC_CONNECTION_ERROR", "Catalog endpoint discovery failed.") from exc
51
- parsed = urlsplit(endpoint)
52
- if parsed.scheme not in ("https", "http") or not parsed.netloc or parsed.username or parsed.password or parsed.query or parsed.fragment:
53
- raise ValidationError("Catalog endpoint must be an HTTP(S) service URL without credentials, query, or fragment.")
54
- return endpoint
57
+ raise SemanticError(
58
+ "SEMANTIC_CONNECTION_ERROR", "Catalog endpoint discovery failed."
59
+ ) from exc
60
+ return normalize_catalog_endpoint(endpoint)
55
61
 
56
62
  def semantic_request(self, namespace, method, name=None, *, suffix="", params=None, body=None):
57
63
  namespace_id(namespace)
@@ -68,7 +74,9 @@ class SemanticMixin:
68
74
  try:
69
75
  payload = None
70
76
  if body is not None:
71
- payload = json.dumps(body, ensure_ascii=False, separators=(",", ":"), allow_nan=False).encode("utf-8")
77
+ payload = json.dumps(
78
+ body, ensure_ascii=False, separators=(",", ":"), allow_nan=False
79
+ ).encode("utf-8")
72
80
  if len(payload) > MAX_FILE_BYTES:
73
81
  raise ValidationError("Semantic request exceeds the 16 MiB limit.")
74
82
  # Reuse the account (including OAuth/STS/proxy behavior), region and
@@ -76,7 +84,9 @@ class SemanticMixin:
76
84
  headers = {"Content-Type": "application/json", "Accept": "application/json"}
77
85
  user_agent = getattr(rest, "_user_agent", "maxc-cli")
78
86
  headers.update({"User-Agent": user_agent, "x-odps-user-agent": user_agent})
79
- request = requests.Request(method, base + path, params=params or {}, data=payload, headers=headers).prepare()
87
+ request = requests.Request(
88
+ method, base + path, params=params or {}, data=payload, headers=headers
89
+ ).prepare()
80
90
  region = rest.region_name if options.enable_v4_sign else None
81
91
  # PyODPS sign_request unquotes the URL before parse_qsl unquotes
82
92
  # each query value again. Protect percent escapes for signing only,
@@ -94,14 +104,30 @@ class SemanticMixin:
94
104
  # requests' default adapters have zero retries. No redirect can
95
105
  # forward credentials or silently change a signed target/method.
96
106
  with requests.Session() as session:
97
- settings = session.merge_environment_settings(request.url, dict(getattr(rest, "_proxy", None) or {}), True, options.verify_ssl, None)
98
- with session.send(request, timeout=(options.connect_timeout, options.read_timeout), allow_redirects=False, **settings) as response:
107
+ settings = session.merge_environment_settings(
108
+ request.url,
109
+ dict(getattr(rest, "_proxy", None) or {}),
110
+ True,
111
+ options.verify_ssl,
112
+ None,
113
+ )
114
+ with session.send(
115
+ request,
116
+ timeout=(options.connect_timeout, options.read_timeout),
117
+ allow_redirects=False,
118
+ **settings,
119
+ ) as response:
99
120
  status = response.status_code
100
121
  raw = bytearray()
101
122
  for chunk in response.iter_content(64 * 1024):
102
123
  raw.extend(chunk)
103
124
  if len(raw) > MAX_FILE_BYTES:
104
- raise SemanticError("SEMANTIC_WRITE_UNCERTAIN" if mutation else "SEMANTIC_INVALID_RESPONSE", "Catalog response exceeds the 16 MiB limit.")
125
+ raise SemanticError(
126
+ "SEMANTIC_WRITE_UNCERTAIN"
127
+ if mutation
128
+ else "SEMANTIC_INVALID_RESPONSE",
129
+ "Catalog response exceeds the 16 MiB limit.",
130
+ )
105
131
  if not 200 <= status < 300:
106
132
  code = ""
107
133
  try:
@@ -112,7 +138,11 @@ class SemanticMixin:
112
138
  pass
113
139
  raise _failure(status, code, mutation=mutation)
114
140
  if method == "DELETE":
115
- return {"deleted": True, "specName": name, "expectedSemanticSpecId": (params or {}).get("expectedSemanticSpecId")}
141
+ return {
142
+ "deleted": True,
143
+ "specName": name,
144
+ "expectedSemanticSpecId": (params or {}).get("expectedSemanticSpecId"),
145
+ }
116
146
  result = json.loads(raw)
117
147
  if not isinstance(result, dict):
118
148
  raise ValueError("expected object")
@@ -121,4 +151,7 @@ class SemanticMixin:
121
151
  raise
122
152
  except Exception as exc:
123
153
  # Raw exceptions can contain signed headers, SQL, or user content.
124
- raise SemanticError("SEMANTIC_WRITE_UNCERTAIN" if mutation else "SEMANTIC_CONNECTION_ERROR", "Catalog semantic request did not produce a verifiable result. Reconcile before retrying a write.") from exc
154
+ raise SemanticError(
155
+ "SEMANTIC_WRITE_UNCERTAIN" if mutation else "SEMANTIC_CONNECTION_ERROR",
156
+ "Catalog semantic request did not produce a verifiable result. Reconcile before retrying a write.",
157
+ ) from exc
@@ -0,0 +1,42 @@
1
+ """Normalize SDK-discovered Catalog authorities without changing explicit routing."""
2
+
3
+ import re
4
+ from urllib.parse import urlsplit
5
+
6
+ from .exceptions import ValidationError
7
+
8
+ _BARE_AUTHORITY = re.compile(
9
+ r"(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+"
10
+ r"[A-Za-z0-9-]+(?::[0-9]{1,5})?"
11
+ )
12
+
13
+
14
+ def normalize_catalog_endpoint(endpoint):
15
+ if not isinstance(endpoint, str) or not endpoint:
16
+ raise ValidationError("Catalog endpoint must be a nonempty HTTP(S) service URL.")
17
+ endpoint = endpoint.rstrip("/")
18
+ if _BARE_AUTHORITY.fullmatch(endpoint):
19
+ endpoint = "https://" + endpoint
20
+ try:
21
+ parsed = urlsplit(endpoint)
22
+ valid = (
23
+ parsed.scheme in ("https", "http")
24
+ and parsed.hostname
25
+ and not parsed.username
26
+ and not parsed.password
27
+ and not parsed.query
28
+ and not parsed.fragment
29
+ and not any(c.isspace() for c in endpoint)
30
+ and "\\" not in endpoint
31
+ and "%" not in parsed.hostname
32
+ )
33
+ # Accessing port checks malformed/non-numeric/out-of-range values.
34
+ if parsed.port is not None and not 1 <= parsed.port <= 65535:
35
+ valid = False
36
+ except ValueError:
37
+ valid = False
38
+ if not valid:
39
+ raise ValidationError(
40
+ "Catalog endpoint must be an HTTP(S) service URL without credentials, query, or fragment."
41
+ )
42
+ return endpoint
@@ -453,6 +453,7 @@ def build_parser() -> argparse.ArgumentParser:
453
453
  meta_describe.add_argument("--project", help="Target MaxCompute project")
454
454
  meta_describe.add_argument("--json", action="store_true", help="Output as JSON envelope")
455
455
  meta_describe.add_argument("--full", action="store_true", help="Show full column list (default is summary mode)")
456
+ meta_describe.add_argument("--metadata-only", action="store_true", help="Read live table schema only, without rows, partition values or cache fallback")
456
457
  meta_describe.set_defaults(handler=_handle_meta_describe)
457
458
 
458
459
  meta_functions = _make_parser(meta_subparsers, "list-functions", "meta.list-functions", help="List registered functions")
@@ -1158,7 +1159,7 @@ def build_parser() -> argparse.ArgumentParser:
1158
1159
  child = _make_parser(semantic_commands, operation, "semantic." + operation, help=summary)
1159
1160
  if operation != "list":
1160
1161
  child.add_argument("name", help="Exact semantic package name")
1161
- child.add_argument("--namespace", required=True, help="Verified main-account ID (not project tenant ID)")
1162
+ child.add_argument("--namespace", help="Verified main-account ID; auto-discovered from authenticated account identity when omitted")
1162
1163
  child.add_argument("--json", action="store_true", help="Output JSON envelope")
1163
1164
  if operation == "list":
1164
1165
  child.add_argument("--page-size", type=positive_int, default=20)
@@ -2152,6 +2153,7 @@ def _handle_meta_describe(app: MaxCApp, args: argparse.Namespace, stdout: TextIO
2152
2153
  full = args.full or _is_json_mode(args)
2153
2154
  envelope = app.meta_describe(
2154
2155
  args.table_name,
2156
+ metadata_only=getattr(args, "metadata_only", False),
2155
2157
  full=full,
2156
2158
  project=args.project,
2157
2159
  schema=getattr(args, "schema", None),
@@ -2940,7 +2942,7 @@ def _manifest_effects(command: str) -> list[dict[str, Any]]:
2940
2942
  when=_manifest_condition("yes", equals=True), confirmation="--yes with exact target/version; apply also requires --plan-digest"))
2941
2943
  if operation in {"create", "diff", "apply"}:
2942
2944
  effects.append(_manifest_effect("local", "read", "semantic_json_file"))
2943
- if operation == "export":
2945
+ if operation in {"export"}:
2944
2946
  effects.append(_manifest_effect("local", "create", "semantic_json_file", when=_manifest_condition("overwrite", equals=False)))
2945
2947
  effects.append(_manifest_effect("local", "replace", "semantic_json_file", when=_manifest_condition("overwrite", equals=True), confirmation="--overwrite"))
2946
2948
  return _with_manifest_audit_effect(command, effects)
@@ -19,7 +19,7 @@ from .semantic import (
19
19
  class SemanticManager:
20
20
  def __init__(self, backend, namespace):
21
21
  self.backend = backend
22
- self.namespace = namespace_id(namespace)
22
+ self.namespace = namespace_id(namespace if namespace is not None else backend.semantic_namespace())
23
23
  self.warnings = []
24
24
 
25
25
  def request(self, method, name=None, **kwargs):
@@ -6,8 +6,11 @@ Read the live help/manifest before choosing arguments.
6
6
 
7
7
  ## Discover and read
8
8
 
9
- Use the verified main-account ID as `--namespace`; a project's tenant ID is not
10
- an interchangeable identifier. The active authentication and Catalog endpoint
9
+ Omit `--namespace` to resolve it from verified authenticated account identity.
10
+ If discovery cannot prove the parent account, pass an independently verified
11
+ main-account ID; neither a standalone RAM principal ID nor a project tenant ID
12
+ is interchangeable with this namespace. `auth whoami` exposes the resolution
13
+ under `data.identity.semantic_namespace` and its source. The active authentication and Catalog endpoint
11
14
  select the caller and region. Follow `nextPageToken` with `--page-token` until
12
15
  the intended exact name is found. Authorization remains server-enforced.
13
16
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maxc-cli
3
- Version: 0.9.3
3
+ Version: 0.9.5b1
4
4
  Summary: Agent-native MaxCompute CLI for external coding agents
5
5
  Classifier: Programming Language :: Python :: 3
6
6
  Classifier: Programming Language :: Python :: 3.9
@@ -304,7 +304,7 @@ To return to local signing, explicitly run the appropriate `auth login` command.
304
304
  ## Versioned semantic packages
305
305
 
306
306
  `maxc semantic` manages remote Catalog packages using the current connection.
307
- Specify the verified main-account ID with `--namespace`. Available operations:
307
+ The namespace is auto-discovered from verified authenticated account identity when possible; otherwise pass an independently verified main-account ID with `--namespace`. Available operations:
308
308
  `list`, `get`, `revisions`, `export`, `create`, `diff`, `apply`, `publish`, `delete`.
309
309
  `meta semantic` continues to manage local annotations.
310
310
 
@@ -324,6 +324,7 @@ write must be reconciled before retrying. Publication checks are not SQL or
324
324
  business validation. History lists the latest 20 summaries, and an immutable
325
325
  revision read does not guarantee historical DataBridge analysis.
326
326
 
327
+
327
328
  ### Task metrics and worker logs
328
329
 
329
330
  ```bash
@@ -338,3 +339,13 @@ Task detail preserves the service payload (including `mapReduce.jsonSummary`).
338
339
  Select `log_id` from `data.workers`; logs are returned as `data.content` in the JSON
339
340
  envelope. The requested size defaults to 1 MiB and must be positive; returned logs
340
341
  may be partial. Use `--project` to select the owning project explicitly.
342
+
343
+ Source-specific dbt semantic conversion is maintained by dbt-maxcompute (`dbt run-operation dbt_maxcompute.export_semantic_package`). maxc supplies generic package management and `meta describe --metadata-only` for live schema inspection.
344
+
345
+ ## 语义包试用版
346
+
347
+ ```bash
348
+ python -m pip install 'maxc-cli==0.9.5b1'
349
+ ```
350
+
351
+ 0.9.5b1 支持从可信账号身份解析 namespace,兼容旧版 PyODPS 返回的 Catalog 域名,并提供 `meta describe --metadata-only`。参见[语义包中文指南](docs/semantic-packages.zh-CN.md)。dbt 转换使用适配器自带的 `dbt run-operation dbt_maxcompute.export_semantic_package` 宏。