maxc-cli 0.5.0__tar.gz → 0.5.1__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 (118) hide show
  1. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/PKG-INFO +1 -1
  2. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/__init__.py +1 -1
  3. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/state_permissions.py +11 -3
  4. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli.egg-info/PKG-INFO +1 -1
  5. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_setting_parser.py +26 -2
  6. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_state_permissions.py +31 -0
  7. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/MANIFEST.in +0 -0
  8. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/README.md +0 -0
  9. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/pyproject.toml +0 -0
  10. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/scripts/pyinstaller_entry.py +0 -0
  11. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/scripts/regression_test.py +0 -0
  12. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/setup.cfg +0 -0
  13. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/setup.py +0 -0
  14. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/__main__.py +0 -0
  15. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/_samples.py +0 -0
  16. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/agent_platforms.py +0 -0
  17. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/app.py +0 -0
  18. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/audit.py +0 -0
  19. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/auth_continuation.py +0 -0
  20. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/auth_providers.py +0 -0
  21. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/backend/__init__.py +0 -0
  22. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/backend/auth.py +0 -0
  23. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/backend/catalog.py +0 -0
  24. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/backend/data.py +0 -0
  25. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/backend/job.py +0 -0
  26. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/backend/meta.py +0 -0
  27. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/backend/odps.py +0 -0
  28. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/backend/query.py +0 -0
  29. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/cache.py +0 -0
  30. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/catalog_bootstrap.py +0 -0
  31. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/cli.py +0 -0
  32. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/config.py +0 -0
  33. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/exceptions.py +0 -0
  34. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/help_format.py +0 -0
  35. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/helpers.py +0 -0
  36. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/job_ids.py +0 -0
  37. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/masking.py +0 -0
  38. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/models.py +0 -0
  39. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/oauth.py +0 -0
  40. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/odps_runtime.py +0 -0
  41. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/output.py +0 -0
  42. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/setting_parser.py +0 -0
  43. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/SKILL.md +0 -0
  44. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/agents/openai.yaml +0 -0
  45. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/bootstrap-auth.md +0 -0
  46. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/bootstrap-flow.md +0 -0
  47. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/command-patterns.md +0 -0
  48. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/json-output-format.md +0 -0
  49. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/maxcompute-select-guide.md +0 -0
  50. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/maxcompute-sql-notes.md +0 -0
  51. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/partition-guide.md +0 -0
  52. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/red-lines.md +0 -0
  53. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/setup-install.md +0 -0
  54. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/sql-common-errors.md +0 -0
  55. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/sql-query-patterns.md +0 -0
  56. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/skills/references/text2sql-principles.md +0 -0
  57. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/store.py +0 -0
  58. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli/utils.py +0 -0
  59. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli.egg-info/SOURCES.txt +0 -0
  60. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli.egg-info/dependency_links.txt +0 -0
  61. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli.egg-info/entry_points.txt +0 -0
  62. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli.egg-info/requires.txt +0 -0
  63. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/src/maxc_cli.egg-info/top_level.txt +0 -0
  64. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_agent_hints_and_cli.py +0 -0
  65. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_agent_platforms.py +0 -0
  66. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_agent_skill_commands.py +0 -0
  67. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_agent_skill_commands_context.py +0 -0
  68. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_ai_native_contract_regressions.py +0 -0
  69. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_auth_logout.py +0 -0
  70. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_backend_auth.py +0 -0
  71. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_backend_data.py +0 -0
  72. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_backend_data_serialization.py +0 -0
  73. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_backend_meta.py +0 -0
  74. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_build_release_archive_compat.py +0 -0
  75. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_build_release_script.py +0 -0
  76. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_cache.py +0 -0
  77. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_catalog.py +0 -0
  78. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_catalog_bootstrap.py +0 -0
  79. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_cli_arg_validation.py +0 -0
  80. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_cli_mock.py +0 -0
  81. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_cli_query_parse_and_sanitize.py +0 -0
  82. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_compat.py +0 -0
  83. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_config_atomic_write.py +0 -0
  84. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_e2e_smoke.py +0 -0
  85. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_envelope_shape.py +0 -0
  86. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_error_self_correction.py +0 -0
  87. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_error_translation.py +0 -0
  88. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_exit_codes.py +0 -0
  89. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_external_auth.py +0 -0
  90. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_flag_hoist.py +0 -0
  91. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_help_format.py +0 -0
  92. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_help_version_e2e.py +0 -0
  93. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_helpers.py +0 -0
  94. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_helpers_csv.py +0 -0
  95. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_installer_contracts.py +0 -0
  96. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_integration.py +0 -0
  97. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_integration_real.py +0 -0
  98. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_job_improvements.py +0 -0
  99. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_job_store_durability.py +0 -0
  100. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_manifest_runtime_contract.py +0 -0
  101. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_masking.py +0 -0
  102. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_meta_schema_and_partition_cols.py +0 -0
  103. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_oauth.py +0 -0
  104. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_odps_runtime.py +0 -0
  105. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_output_action_safety.py +0 -0
  106. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_output_format_contract.py +0 -0
  107. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_packaging_metadata.py +0 -0
  108. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_phase1_improvements.py +0 -0
  109. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_pyinstaller_bundle.py +0 -0
  110. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_python39_compat.py +0 -0
  111. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_query_auto_promote.py +0 -0
  112. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_query_result_csv_fallback.py +0 -0
  113. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_semantic_scope.py +0 -0
  114. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_skill_cli_consistency.py +0 -0
  115. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_skill_eval.py +0 -0
  116. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_skill_renderer.py +0 -0
  117. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/tests/test_startup_imports.py +0 -0
  118. {maxc_cli-0.5.0 → maxc_cli-0.5.1}/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.5.0
3
+ Version: 0.5.1
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
@@ -2,4 +2,4 @@
2
2
 
3
3
  __all__ = ["__version__"]
4
4
 
5
- __version__ = "0.5.0"
5
+ __version__ = "0.5.1"
@@ -135,10 +135,18 @@ def open_private_directory(
135
135
  except FileNotFoundError:
136
136
  if not create:
137
137
  raise
138
- os.mkdir(component, PRIVATE_DIRECTORY_MODE, dir_fd=descriptor)
138
+ try:
139
+ os.mkdir(component, PRIVATE_DIRECTORY_MODE, dir_fd=descriptor)
140
+ except FileExistsError:
141
+ # Another process may have created the same component
142
+ # after our open() observed it missing. Re-open it with
143
+ # O_DIRECTORY/O_NOFOLLOW below so the usual ownership and
144
+ # link checks still apply.
145
+ pass
146
+ else:
147
+ if is_leaf:
148
+ created_leaf = True
139
149
  next_descriptor = os.open(component, flags, dir_fd=descriptor)
140
- if is_leaf:
141
- created_leaf = True
142
150
  os.close(descriptor)
143
151
  descriptor = next_descriptor
144
152
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maxc-cli
3
- Version: 0.5.0
3
+ Version: 0.5.1
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
@@ -366,17 +366,37 @@ def test_translate_odps_error_type_error_not_readonly():
366
366
  assert not isinstance(result, ReadOnlyError)
367
367
 
368
368
 
369
- def test_cli_readonly_error_has_agent_hints():
369
+ def test_cli_readonly_error_has_agent_hints(tmp_path):
370
370
  """Verify that client-side write detection returns WRITE_OPERATION_REQUIRES_FORCE with hints."""
371
371
  import io
372
372
  import json
373
373
 
374
374
  from maxc_cli.cli import run
375
375
 
376
+ config_path = tmp_path / "config.yaml"
377
+ config_path.write_text(
378
+ "default_project: test_project\n"
379
+ f"state_dir: {tmp_path / 'state'}\n"
380
+ f"cache_dir: {tmp_path / 'cache'}\n"
381
+ "auth:\n"
382
+ " provider: access_key\n"
383
+ " access_id: test_access_id\n"
384
+ " secret_access_key: test_secret\n"
385
+ " project: test_project\n"
386
+ " endpoint: https://service.example.invalid/api\n",
387
+ encoding="utf-8",
388
+ )
376
389
  stdout = io.StringIO()
377
390
 
378
391
  exit_code = run(
379
- ["query", "CREATE TABLE t (id BIGINT)", "--json"],
392
+ [
393
+ "--config",
394
+ str(config_path),
395
+ "query",
396
+ "CREATE TABLE t (id BIGINT)",
397
+ "--json",
398
+ ],
399
+ cwd=tmp_path,
380
400
  stdout=stdout,
381
401
  )
382
402
 
@@ -386,3 +406,7 @@ def test_cli_readonly_error_has_agent_hints():
386
406
  assert output["error"]["recoverable"] is False
387
407
  assert "--force" not in output["error"].get("suggestion", "")
388
408
  assert "outside" in output["error"].get("suggestion", "")
409
+ assert any(
410
+ "SELECT-only" in warning
411
+ for warning in output["agent_hints"].get("warnings", [])
412
+ )
@@ -11,6 +11,7 @@ import pytest
11
11
 
12
12
  import maxc_cli.audit as audit_module
13
13
  import maxc_cli.cache as cache_module
14
+ import maxc_cli.state_permissions as state_permissions
14
15
  from maxc_cli.app import MaxCApp
15
16
  from maxc_cli.audit import AuditLogger
16
17
  from maxc_cli.cache import LocalCache
@@ -161,6 +162,36 @@ def test_new_cache_and_state_directories_are_private(tmp_path: Path) -> None:
161
162
  assert _mode(state_dir / "jobs.json") == 0o600
162
163
 
163
164
 
165
+ @pytest.mark.skipif(
166
+ not state_permissions._USE_DIRECTORY_FDS,
167
+ reason="exercises descriptor-relative directory creation",
168
+ )
169
+ def test_private_directory_accepts_a_concurrently_created_component(
170
+ tmp_path: Path,
171
+ monkeypatch,
172
+ ) -> None:
173
+ target = tmp_path / "state"
174
+ original_mkdir = state_permissions.os.mkdir
175
+ raced = False
176
+
177
+ def racing_mkdir(path, mode=0o777, *, dir_fd=None):
178
+ nonlocal raced
179
+ if path == target.name and dir_fd is not None and not raced:
180
+ raced = True
181
+ original_mkdir(path, mode, dir_fd=dir_fd)
182
+ raise FileExistsError(path)
183
+ return original_mkdir(path, mode, dir_fd=dir_fd)
184
+
185
+ monkeypatch.setattr(state_permissions.os, "mkdir", racing_mkdir)
186
+
187
+ directory = state_permissions.open_private_directory(target)
188
+ state_permissions.close_private_directory(directory)
189
+
190
+ assert raced is True
191
+ assert target.is_dir()
192
+ assert _mode(target) == 0o700
193
+
194
+
164
195
  def test_custom_audit_path_does_not_chmod_existing_shared_parent(tmp_path: Path) -> None:
165
196
  shared_dir = tmp_path / "shared"
166
197
  shared_dir.mkdir(mode=0o755)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes