mainsequence 8.1.19__tar.gz → 8.1.20.dev2__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.
- {mainsequence-8.1.19/mainsequence.egg-info → mainsequence-8.1.20.dev2}/PKG-INFO +1 -1
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2/mainsequence.egg-info}/PKG-INFO +1 -1
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence.egg-info/SOURCES.txt +1 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/pyproject.toml +18 -1
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_client.py +5 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_code_repository_batch_jobs_from_file.py +26 -0
- mainsequence-8.1.20.dev2/tests/test_dev_release_version.py +118 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_meta_tables_client_models.py +45 -1
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_time_index_table_update_configuration_client.py +43 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/LICENSE +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/MANIFEST.in +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/README.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/a2a_sdk_execution/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/data_publishing/meta_table_migrations/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/data_publishing/time_index_table_updates/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/maintenance/code_repository_maintenance/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/sdk_code_repository_execution/SKILL.md +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/__main__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/bootstrap.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/api.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/cli.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/code_repository_status.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/config.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/migrations.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/cli/ui.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/base.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/client.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/compute_validation.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/github_issues.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/metatables/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/metatables/core.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/models_foundry.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/models_user.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/observability.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/utils.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/code_repository_context.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/code_repository_skills.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/defaults.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/logconf.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/__main__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/future_registry.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/hashing.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/alembic.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/env.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/provider.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/registry.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/scaffold.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/templates/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/templates/env.py.mako +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/templates/script.py.mako +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/schema_names.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/sqlalchemy_contracts.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_refs.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_updates/__init__.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_updates/configuration.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_updates/dependencies.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_updates/managers.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_updates/namespacing.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_updates/runner.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_updates/updaters.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_updates/utils.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/repository_identity_security.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/scaffold_skills.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/setup.cfg +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/fixtures/time_index_table_update_hash_v2_golden.json +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_auth_precedence.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_canonical_api_route_contract.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_cli.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_cli_migrations.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_code_repository_branch_contract.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_code_repository_documentation_contract.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_code_repository_runtime_context.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_code_repository_skills.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_dependency_extras.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_duckdb_interface_dimensions.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_environment_resource_context.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_environment_response_contracts.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_filter_normalization.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_github_issues_client.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_instrumentation.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_local_ops.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_logconf.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_meta_table_migrations.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_meta_tables_sqlalchemy_contracts.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_notification_uid_contract.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_observability_client.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_pod_project_resolution.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_scaffold_skills.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_schema_names.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_secret_client_model.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_source_table_configuration.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_sqlite_interface_dimensions.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_ssh_utils.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_time_index_table_access_dimension_audit.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_time_index_table_dimension_queries.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_time_index_table_update_configuration.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_time_index_table_update_flow.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_time_index_table_update_hard_cut.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_update_statistics.py +0 -0
- {mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_update_uid_guards.py +0 -0
|
@@ -105,6 +105,7 @@ tests/test_code_repository_documentation_contract.py
|
|
|
105
105
|
tests/test_code_repository_runtime_context.py
|
|
106
106
|
tests/test_code_repository_skills.py
|
|
107
107
|
tests/test_dependency_extras.py
|
|
108
|
+
tests/test_dev_release_version.py
|
|
108
109
|
tests/test_duckdb_interface_dimensions.py
|
|
109
110
|
tests/test_environment_resource_context.py
|
|
110
111
|
tests/test_environment_response_contracts.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mainsequence"
|
|
7
|
-
version = "8.1.
|
|
7
|
+
version = "8.1.20.dev2"
|
|
8
8
|
description = "Main Sequence SDK "
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13"
|
|
@@ -95,6 +95,23 @@ publish-url = "https://test.pypi.org/legacy/"
|
|
|
95
95
|
explicit = true
|
|
96
96
|
|
|
97
97
|
|
|
98
|
+
# --------------------
|
|
99
|
+
# Testing (pytest)
|
|
100
|
+
# --------------------
|
|
101
|
+
[tool.pytest.ini_options]
|
|
102
|
+
testpaths = ["tests"]
|
|
103
|
+
# Put the repository root on sys.path so tests can import `scripts`. `pytest`
|
|
104
|
+
# invoked as `python -m pytest` gets this from the CWD, but the `pytest`
|
|
105
|
+
# entrypoint (what `uv run pytest` and CI use) does not.
|
|
106
|
+
pythonpath = ["."]
|
|
107
|
+
# `live` tests talk to a real backend and need credentials, so they are
|
|
108
|
+
# deselected by default. CI and a plain `pytest` therefore run offline.
|
|
109
|
+
# Run them explicitly with `pytest -m live`.
|
|
110
|
+
addopts = "-m 'not live'"
|
|
111
|
+
markers = [
|
|
112
|
+
"live: talks to a live Main Sequence backend and needs credentials; deselected unless `-m live` is passed",
|
|
113
|
+
]
|
|
114
|
+
|
|
98
115
|
# --------------------
|
|
99
116
|
# Formatting (Black)
|
|
100
117
|
# --------------------
|
|
@@ -4,6 +4,11 @@ import pytest
|
|
|
4
4
|
|
|
5
5
|
import mainsequence.client as msc
|
|
6
6
|
|
|
7
|
+
# Every test in this module drives a real backend over the network and needs
|
|
8
|
+
# SDK credentials, so none of them can run in CI. See `[tool.pytest.ini_options]`
|
|
9
|
+
# in pyproject.toml: `pytest` deselects them, `pytest -m live` runs them.
|
|
10
|
+
pytestmark = pytest.mark.live
|
|
11
|
+
|
|
7
12
|
|
|
8
13
|
def test_create_code_repository():
|
|
9
14
|
ds = msc.DataSource.filter(status=msc.DataSource.STATUS_AVAILABLE)[0]
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_code_repository_batch_jobs_from_file.py
RENAMED
|
@@ -6,6 +6,32 @@ import types
|
|
|
6
6
|
import pytest
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
def _snapshot_mainsequence_modules() -> dict[str, types.ModuleType]:
|
|
10
|
+
return {
|
|
11
|
+
name: module
|
|
12
|
+
for name, module in sys.modules.items()
|
|
13
|
+
if name == "mainsequence" or name.startswith("mainsequence.")
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@pytest.fixture(autouse=True)
|
|
18
|
+
def _restore_mainsequence_modules():
|
|
19
|
+
"""Undo the stub packages this module installs into ``sys.modules``.
|
|
20
|
+
|
|
21
|
+
``_load_models_helpers_module`` replaces the real ``mainsequence`` packages
|
|
22
|
+
with stubs so ``models_helpers`` can be imported without the heavy client
|
|
23
|
+
stack. Without this fixture the stubs leak into every test module that runs
|
|
24
|
+
afterwards, and ``monkeypatch.setattr("mainsequence.client....")`` there
|
|
25
|
+
fails with ``module 'mainsequence' has no attribute 'client'``.
|
|
26
|
+
"""
|
|
27
|
+
snapshot = _snapshot_mainsequence_modules()
|
|
28
|
+
yield
|
|
29
|
+
for name in tuple(sys.modules):
|
|
30
|
+
if name == "mainsequence" or name.startswith("mainsequence."):
|
|
31
|
+
sys.modules.pop(name, None)
|
|
32
|
+
sys.modules.update(snapshot)
|
|
33
|
+
|
|
34
|
+
|
|
9
35
|
def _load_models_helpers_module():
|
|
10
36
|
repo_root = pathlib.Path(__file__).resolve().parents[1]
|
|
11
37
|
pkg_root = repo_root / "mainsequence"
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Contract for the development-release version computed by the publish workflow.
|
|
2
|
+
|
|
3
|
+
The standard these tests pin down is documented in
|
|
4
|
+
`docs/knowledge/release_process.md`.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import pytest
|
|
10
|
+
from packaging.version import Version
|
|
11
|
+
|
|
12
|
+
from scripts import dev_release_version
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def _files(*, yanked: bool = False) -> list[dict[str, object]]:
|
|
16
|
+
return [{"filename": "mainsequence-x-py3-none-any.whl", "yanked": yanked}]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_latest_final_ignores_development_and_pre_releases():
|
|
20
|
+
releases = {
|
|
21
|
+
"8.1.19": _files(),
|
|
22
|
+
"8.1.20.dev41": _files(),
|
|
23
|
+
"8.2.0rc1": _files(),
|
|
24
|
+
"8.1.19.post1": _files(),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
assert dev_release_version.latest_final_version(releases) == Version("8.1.19")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_latest_final_ignores_releases_with_no_installable_file():
|
|
31
|
+
releases = {
|
|
32
|
+
"8.1.19": _files(),
|
|
33
|
+
"9.0.0": [],
|
|
34
|
+
"9.1.0": _files(yanked=True),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
assert dev_release_version.latest_final_version(releases) == Version("8.1.19")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def test_latest_final_keeps_a_release_with_one_file_left():
|
|
41
|
+
releases = {
|
|
42
|
+
"8.1.19": _files(),
|
|
43
|
+
"8.2.0": [
|
|
44
|
+
{"filename": "mainsequence-8.2.0.tar.gz", "yanked": True},
|
|
45
|
+
{"filename": "mainsequence-8.2.0-py3-none-any.whl", "yanked": False},
|
|
46
|
+
],
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
assert dev_release_version.latest_final_version(releases) == Version("8.2.0")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def test_latest_final_orders_numerically_not_lexically():
|
|
53
|
+
releases = {"8.1.9": _files(), "8.1.10": _files(), "8.1.2": _files()}
|
|
54
|
+
|
|
55
|
+
assert dev_release_version.latest_final_version(releases) == Version("8.1.10")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def test_latest_final_skips_unparseable_versions():
|
|
59
|
+
releases = {"8.1.19": _files(), "not-a-version": _files()}
|
|
60
|
+
|
|
61
|
+
assert dev_release_version.latest_final_version(releases) == Version("8.1.19")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def test_latest_final_requires_at_least_one_installable_release():
|
|
65
|
+
with pytest.raises(dev_release_version.DevVersionError):
|
|
66
|
+
dev_release_version.latest_final_version({"9.0.0": []})
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_dev_version_carries_the_next_patch_number():
|
|
70
|
+
assert dev_release_version.dev_version(Version("8.1.19"), 41) == "8.1.20.dev41"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def test_dev_version_sorts_between_the_current_and_the_next_release():
|
|
74
|
+
computed = Version(dev_release_version.dev_version(Version("8.1.19"), 41))
|
|
75
|
+
|
|
76
|
+
assert Version("8.1.19") < computed < Version("8.1.20")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def test_dev_version_is_a_development_release_so_pip_skips_it_by_default():
|
|
80
|
+
computed = Version(dev_release_version.dev_version(Version("8.1.19"), 41))
|
|
81
|
+
|
|
82
|
+
assert computed.is_devrelease
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def test_dev_version_rejects_a_negative_run_number():
|
|
86
|
+
with pytest.raises(dev_release_version.DevVersionError):
|
|
87
|
+
dev_release_version.dev_version(Version("8.1.19"), -1)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def test_apply_version_rewrites_only_the_project_version():
|
|
91
|
+
pyproject = '[project]\nname = "mainsequence"\nversion = "8.1.19"\n\n[tool.other]\nversion = "1.0.0"\n'
|
|
92
|
+
|
|
93
|
+
rewritten = dev_release_version.apply_version(pyproject, "8.1.20.dev41")
|
|
94
|
+
|
|
95
|
+
assert 'version = "8.1.20.dev41"' in rewritten
|
|
96
|
+
assert rewritten.count('version = "1.0.0"') == 1
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_apply_version_refuses_a_pyproject_without_a_project_version():
|
|
100
|
+
with pytest.raises(dev_release_version.DevVersionError):
|
|
101
|
+
dev_release_version.apply_version('[project]\nname = "mainsequence"\n', "8.1.20.dev41")
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_read_declared_version_reports_the_repository_version():
|
|
105
|
+
text = dev_release_version.PYPROJECT.read_text(encoding="utf-8")
|
|
106
|
+
|
|
107
|
+
declared = dev_release_version.read_declared_version(text)
|
|
108
|
+
|
|
109
|
+
assert declared is not None
|
|
110
|
+
Version(declared)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_the_repository_pyproject_accepts_a_rewritten_version():
|
|
114
|
+
text = dev_release_version.PYPROJECT.read_text(encoding="utf-8")
|
|
115
|
+
|
|
116
|
+
rewritten = dev_release_version.apply_version(text, "8.1.20.dev41")
|
|
117
|
+
|
|
118
|
+
assert dev_release_version.read_declared_version(rewritten) == "8.1.20.dev41"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import datetime
|
|
4
|
+
import pathlib
|
|
4
5
|
from types import SimpleNamespace
|
|
5
6
|
|
|
6
7
|
import pytest
|
|
@@ -12,6 +13,8 @@ from mainsequence.client.exceptions import ConflictError, PermissionDeniedError
|
|
|
12
13
|
from mainsequence.meta_tables.compiled_sql.v1 import build_operation, compile_sqlalchemy_statement
|
|
13
14
|
|
|
14
15
|
ENVIRONMENT_UID = "bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb"
|
|
16
|
+
CODE_REPOSITORY_UID = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa"
|
|
17
|
+
CODE_REPOSITORY_BRANCH_UID = "22222222-2222-4222-8222-222222222222"
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
@pytest.fixture(autouse=True)
|
|
@@ -23,6 +26,47 @@ def _resolved_environment(monkeypatch):
|
|
|
23
26
|
)
|
|
24
27
|
|
|
25
28
|
|
|
29
|
+
@pytest.fixture(autouse=True)
|
|
30
|
+
def _resolved_code_repository_context(monkeypatch):
|
|
31
|
+
"""Lock a Git CodeRepository context so client calls never reach the backend.
|
|
32
|
+
|
|
33
|
+
``MetaTable`` write paths ask ``get_code_repository_context()`` whether they
|
|
34
|
+
run on an authenticated runtime before they build a payload. Left alone that
|
|
35
|
+
resolves the real Git context by POSTing to the backend, so these tests hang
|
|
36
|
+
on request retries instead of exercising the payload they assert on.
|
|
37
|
+
"""
|
|
38
|
+
code_repository_context._reset_code_repository_context()
|
|
39
|
+
source = code_repository_context.GitCodeRepositorySourceContext(
|
|
40
|
+
repository_root=pathlib.Path.cwd().resolve(),
|
|
41
|
+
canonical_repository_identity="github.com/mainsequence-sdk/meta-tables-client-models",
|
|
42
|
+
repository_branch="main",
|
|
43
|
+
repository_ref="refs/heads/main",
|
|
44
|
+
commit_sha="a" * 40,
|
|
45
|
+
)
|
|
46
|
+
monkeypatch.setattr(
|
|
47
|
+
code_repository_context,
|
|
48
|
+
"_resolve_git_source_context",
|
|
49
|
+
lambda code_repository_dir: source,
|
|
50
|
+
)
|
|
51
|
+
code_repository_context.get_code_repository_context(
|
|
52
|
+
_code_repository_branch_context_loader=lambda resolved_source: SimpleNamespace(
|
|
53
|
+
canonical_repository_identity=resolved_source.canonical_repository_identity,
|
|
54
|
+
repository_branch=resolved_source.repository_branch,
|
|
55
|
+
repository_ref=resolved_source.repository_ref,
|
|
56
|
+
commit_sha=resolved_source.commit_sha,
|
|
57
|
+
code_repository_branch=SimpleNamespace(
|
|
58
|
+
uid=CODE_REPOSITORY_BRANCH_UID,
|
|
59
|
+
code_repository_uid=CODE_REPOSITORY_UID,
|
|
60
|
+
repository_branch=resolved_source.repository_branch,
|
|
61
|
+
organization_environment_uid=None,
|
|
62
|
+
metatables_data_source=None,
|
|
63
|
+
),
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
yield
|
|
67
|
+
code_repository_context._reset_code_repository_context()
|
|
68
|
+
|
|
69
|
+
|
|
26
70
|
class _Response:
|
|
27
71
|
def __init__(self, payload, status_code: int = 200):
|
|
28
72
|
self._payload = payload
|
|
@@ -85,7 +129,7 @@ def _meta_table_response(**overrides):
|
|
|
85
129
|
|
|
86
130
|
def _code_repository_context():
|
|
87
131
|
return meta_table_models.MetaTableCodeRepositoryContextRequest(
|
|
88
|
-
code_repository_branch_uid=
|
|
132
|
+
code_repository_branch_uid=CODE_REPOSITORY_BRANCH_UID,
|
|
89
133
|
)
|
|
90
134
|
|
|
91
135
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import os
|
|
3
|
+
import pathlib
|
|
3
4
|
import threading
|
|
4
5
|
from types import SimpleNamespace
|
|
5
6
|
|
|
@@ -12,6 +13,7 @@ from pydantic import ValidationError
|
|
|
12
13
|
|
|
13
14
|
import mainsequence.client.metatables as models_metatables
|
|
14
15
|
import mainsequence.client.models_foundry as models_foundry
|
|
16
|
+
import mainsequence.code_repository_context as code_repository_context
|
|
15
17
|
import mainsequence.meta_tables.time_index_table_updates.updaters as updaters_module
|
|
16
18
|
from mainsequence.client.metatables import (
|
|
17
19
|
MetaTable,
|
|
@@ -33,6 +35,47 @@ from mainsequence.meta_tables.time_index_table_updates.managers import (
|
|
|
33
35
|
from mainsequence.meta_tables.time_index_table_updates.runner import UpdateRunner
|
|
34
36
|
|
|
35
37
|
|
|
38
|
+
@pytest.fixture(autouse=True)
|
|
39
|
+
def _resolved_code_repository_context(monkeypatch):
|
|
40
|
+
"""Lock a Git CodeRepository context so these tests never reach the backend.
|
|
41
|
+
|
|
42
|
+
Building an update manager asks ``get_code_repository_context()`` for the
|
|
43
|
+
current Git context, which otherwise POSTs to the real backend and retries.
|
|
44
|
+
The resolution is cached per process, so exactly one test paid for it — but
|
|
45
|
+
that one test made a live outbound request from an offline suite.
|
|
46
|
+
"""
|
|
47
|
+
code_repository_context._reset_code_repository_context()
|
|
48
|
+
source = code_repository_context.GitCodeRepositorySourceContext(
|
|
49
|
+
repository_root=pathlib.Path.cwd().resolve(),
|
|
50
|
+
canonical_repository_identity="github.com/mainsequence-sdk/time-index-table-updates",
|
|
51
|
+
repository_branch="main",
|
|
52
|
+
repository_ref="refs/heads/main",
|
|
53
|
+
commit_sha="a" * 40,
|
|
54
|
+
)
|
|
55
|
+
monkeypatch.setattr(
|
|
56
|
+
code_repository_context,
|
|
57
|
+
"_resolve_git_source_context",
|
|
58
|
+
lambda code_repository_dir: source,
|
|
59
|
+
)
|
|
60
|
+
code_repository_context.get_code_repository_context(
|
|
61
|
+
_code_repository_branch_context_loader=lambda resolved_source: SimpleNamespace(
|
|
62
|
+
canonical_repository_identity=resolved_source.canonical_repository_identity,
|
|
63
|
+
repository_branch=resolved_source.repository_branch,
|
|
64
|
+
repository_ref=resolved_source.repository_ref,
|
|
65
|
+
commit_sha=resolved_source.commit_sha,
|
|
66
|
+
code_repository_branch=SimpleNamespace(
|
|
67
|
+
uid="22222222-2222-4222-8222-222222222222",
|
|
68
|
+
code_repository_uid="aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
|
|
69
|
+
repository_branch=resolved_source.repository_branch,
|
|
70
|
+
organization_environment_uid=None,
|
|
71
|
+
metatables_data_source=None,
|
|
72
|
+
),
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
yield
|
|
76
|
+
code_repository_context._reset_code_repository_context()
|
|
77
|
+
|
|
78
|
+
|
|
36
79
|
def _canonical_build_configuration(**values: object) -> dict[str, object]:
|
|
37
80
|
configuration: dict[str, object] = {
|
|
38
81
|
"configuration_schema_version": 2,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/agent_scaffold/skills/a2a_sdk_execution/SKILL.md
RENAMED
|
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
|
|
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
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/client/agent_runtime_models.py
RENAMED
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/compiled_sql/__init__.py
RENAMED
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/compiled_sql/v1.py
RENAMED
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/future_registry.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/__init__.py
RENAMED
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/alembic.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/provider.py
RENAMED
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/registry.py
RENAMED
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/migrations/scaffold.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/pydantic_metadata.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/sqlalchemy_contracts.py
RENAMED
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/meta_tables/time_index_table_refs.py
RENAMED
|
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
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/mainsequence/repository_identity_security.py
RENAMED
|
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
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_code_repository_branch_contract.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_code_repository_runtime_context.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_environment_response_contracts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_meta_tables_sqlalchemy_contracts.py
RENAMED
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_models_user_request_bound_auth.py
RENAMED
|
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
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_time_index_table_dimension_queries.py
RENAMED
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_time_index_table_update_configuration.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-8.1.19 → mainsequence-8.1.20.dev2}/tests/test_time_index_table_update_hard_cut.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|