mainsequence 4.2.37__tar.gz → 4.2.39__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-4.2.37/mainsequence.egg-info → mainsequence-4.2.39}/PKG-INFO +1 -1
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +6 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +6 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/migrations.py +16 -4
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/sqlalchemy_contracts.py +73 -1
- {mainsequence-4.2.37 → mainsequence-4.2.39/mainsequence.egg-info}/PKG-INFO +1 -1
- {mainsequence-4.2.37 → mainsequence-4.2.39}/pyproject.toml +1 -1
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_meta_table_migrations.py +13 -1
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_meta_tables_sqlalchemy_contracts.py +81 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/LICENSE +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/README.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/__main__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/bootstrap.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/api.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/cli.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/config.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/migrations.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/cli/ui.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/base.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/client.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/app_component.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/connections.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/data_models.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/workspace.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/compute_validation.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/fastapi/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/fastapi/auth.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/metatables/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/metatables/core.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/models_foundry.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/models_user.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/utils.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/defaults.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/logconf.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/__main__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/data_nodes.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/models.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/persist_managers.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/future_registry.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/hashing.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/schema_names.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence.egg-info/SOURCES.txt +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/setup.cfg +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_auth_precedence.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_build_operations_hashing.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_cli.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_cli_migrations.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_client.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_command_center_app_component_models.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_command_center_data_models.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_command_center_models.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_data_access_mixin_dimension_audit.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_data_node_storage_dimension_queries.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_data_node_update_flow.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_dependency_extras.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_duckdb_interface_dimensions.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_filter_normalization.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_logconf.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_meta_tables_client_models.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_pod_project_resolution.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_run_configuration.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_schema_names.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_secret_client_model.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_source_table_configuration.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_sqlite_interface_dimensions.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_update_statistics.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_update_uid_guards.py +0 -0
- {mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_workspace_snapshot.py +0 -0
|
@@ -191,6 +191,12 @@ MetaTable migration provider and run `mainsequence migrations upgrade --provider
|
|
|
191
191
|
... head`. Do not call `PricesTable.register()` directly and do not rely on
|
|
192
192
|
DataNode construction to register storage tables.
|
|
193
193
|
|
|
194
|
+
`__index_names__` is the full DataNode storage grain. `PlatformTimeIndexMetaData`
|
|
195
|
+
automatically adds a SQLAlchemy unique index over that tuple before Alembic
|
|
196
|
+
autogenerate runs. Do not manually repeat the full grain unique index in
|
|
197
|
+
`__table_args__`; add ordinary SQLAlchemy `Index(...)` entries only for
|
|
198
|
+
additional lookup/performance paths.
|
|
199
|
+
|
|
194
200
|
`PlatformTimeIndexMetaData.register()` remains SDK plumbing for the migration
|
|
195
201
|
workflow. Do not manually attach an existing UID, reconstruct a generic
|
|
196
202
|
`MetaTable`, or use manual bind helpers as an authoring step.
|
|
@@ -292,6 +292,12 @@ SQLAlchemy class and calling normal registration again. Shape-addressed
|
|
|
292
292
|
foreign keys, or constraints change, so new code cannot reliably recover the
|
|
293
293
|
previous shape-derived table.
|
|
294
294
|
|
|
295
|
+
Do not modify Alembic revision files that have already been implemented/applied.
|
|
296
|
+
MetaTable migrations are database-backed history: once a revision may exist in a
|
|
297
|
+
database `alembic_version` table, changing that file corrupts the relationship
|
|
298
|
+
between source history and deployed state. For any follow-up schema change,
|
|
299
|
+
create a new Alembic revision on top of the current head.
|
|
300
|
+
|
|
295
301
|
For contract evolution, define or update one selected
|
|
296
302
|
`AlembicMetaTableMigration` provider:
|
|
297
303
|
|
|
@@ -534,9 +534,15 @@ class AlembicMetaTableMigration:
|
|
|
534
534
|
table_name = target_table_names[model]
|
|
535
535
|
existing_meta_table = existing_by_table_name.get(table_name)
|
|
536
536
|
if existing_meta_table is not None:
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
537
|
+
if _meta_table_provisioning_status(existing_meta_table) == "active":
|
|
538
|
+
_bind_model_to_existing_metatable(model, existing_meta_table)
|
|
539
|
+
reserved_by_model[model] = existing_meta_table
|
|
540
|
+
continue
|
|
541
|
+
if on_metatable_reservation_status is not None:
|
|
542
|
+
on_metatable_reservation_status(
|
|
543
|
+
"Restaging existing reserved MetaTable "
|
|
544
|
+
f"table_name={table_name} with current provider contract."
|
|
545
|
+
)
|
|
540
546
|
else:
|
|
541
547
|
bound_meta_table = _bound_meta_table_for_model(model)
|
|
542
548
|
if bound_meta_table is not None:
|
|
@@ -1055,6 +1061,13 @@ def _meta_table_physical_table_name(meta_table: MetaTable) -> str | None:
|
|
|
1055
1061
|
return str(physical_table_name)
|
|
1056
1062
|
|
|
1057
1063
|
|
|
1064
|
+
def _meta_table_provisioning_status(meta_table: MetaTable) -> str | None:
|
|
1065
|
+
provisioning_status = meta_table.provisioning_status
|
|
1066
|
+
if provisioning_status in (None, ""):
|
|
1067
|
+
return None
|
|
1068
|
+
return str(provisioning_status)
|
|
1069
|
+
|
|
1070
|
+
|
|
1058
1071
|
def _meta_table_uid(meta_table: MetaTable) -> str | None:
|
|
1059
1072
|
uid = meta_table.uid
|
|
1060
1073
|
if uid in (None, ""):
|
|
@@ -1066,7 +1079,6 @@ def _finalize_table_failed(item: ManagedMetaTableFinalizeTableResult) -> bool:
|
|
|
1066
1079
|
return (
|
|
1067
1080
|
item.provisioning_status != "active"
|
|
1068
1081
|
or item.physical_table_exists is False
|
|
1069
|
-
or item.finalized is False
|
|
1070
1082
|
or item.error not in (None, "", {})
|
|
1071
1083
|
)
|
|
1072
1084
|
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/sqlalchemy_contracts.py
RENAMED
|
@@ -28,6 +28,7 @@ from mainsequence.client.metatables import (
|
|
|
28
28
|
)
|
|
29
29
|
|
|
30
30
|
from .hashing import build_meta_table_configured_storage_hash
|
|
31
|
+
from .schema_names import schema_index_name
|
|
31
32
|
|
|
32
33
|
DEFAULT_PLATFORM_MANAGED_PROVISIONING = {
|
|
33
34
|
"create_table": True,
|
|
@@ -322,7 +323,9 @@ class PlatformTimeIndexMetaData(PlatformManagedMetaTable):
|
|
|
322
323
|
|
|
323
324
|
from sqlalchemy import Table
|
|
324
325
|
|
|
325
|
-
|
|
326
|
+
table = Table(str(name), metadata, *table_items, **kwargs)
|
|
327
|
+
_ensure_time_index_unique_grain_index(table=table, index_names=index_names)
|
|
328
|
+
return table
|
|
326
329
|
|
|
327
330
|
@classmethod
|
|
328
331
|
def build_registration_request(
|
|
@@ -1391,6 +1394,75 @@ def _validate_time_index_contract(
|
|
|
1391
1394
|
)
|
|
1392
1395
|
|
|
1393
1396
|
|
|
1397
|
+
def _ensure_time_index_unique_grain_index(
|
|
1398
|
+
*,
|
|
1399
|
+
table: Any,
|
|
1400
|
+
index_names: Sequence[str],
|
|
1401
|
+
) -> None:
|
|
1402
|
+
grain_names = [str(name) for name in index_names]
|
|
1403
|
+
if _has_unique_grain_enforcement(table=table, index_names=grain_names):
|
|
1404
|
+
return
|
|
1405
|
+
|
|
1406
|
+
from sqlalchemy import Index
|
|
1407
|
+
|
|
1408
|
+
Index(
|
|
1409
|
+
schema_index_name(_table_name(table), grain_names, unique=True),
|
|
1410
|
+
*(table.c[name] for name in grain_names),
|
|
1411
|
+
unique=True,
|
|
1412
|
+
)
|
|
1413
|
+
|
|
1414
|
+
|
|
1415
|
+
def _has_unique_grain_enforcement(
|
|
1416
|
+
*,
|
|
1417
|
+
table: Any,
|
|
1418
|
+
index_names: Sequence[str],
|
|
1419
|
+
) -> bool:
|
|
1420
|
+
for index in _iter_indexes(table):
|
|
1421
|
+
if bool(getattr(index, "unique", False)) and _grain_columns_match(
|
|
1422
|
+
_index_column_names(index),
|
|
1423
|
+
index_names,
|
|
1424
|
+
):
|
|
1425
|
+
return True
|
|
1426
|
+
|
|
1427
|
+
for constraint in _iter_unique_constraints(table):
|
|
1428
|
+
if _grain_columns_match(_constraint_column_names(constraint), index_names):
|
|
1429
|
+
return True
|
|
1430
|
+
|
|
1431
|
+
return False
|
|
1432
|
+
|
|
1433
|
+
|
|
1434
|
+
def _grain_columns_match(existing_names: Sequence[str], index_names: Sequence[str]) -> bool:
|
|
1435
|
+
existing = [str(name) for name in existing_names]
|
|
1436
|
+
expected = [str(name) for name in index_names]
|
|
1437
|
+
if len(existing) != len(expected):
|
|
1438
|
+
return False
|
|
1439
|
+
return set(existing) == set(expected)
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
def _index_column_names(index: Any) -> list[str]:
|
|
1443
|
+
return [_storage_item_name(item) for item in _iter_index_items(index)]
|
|
1444
|
+
|
|
1445
|
+
|
|
1446
|
+
def _iter_unique_constraints(table: Any) -> list[Any]:
|
|
1447
|
+
from sqlalchemy import UniqueConstraint
|
|
1448
|
+
|
|
1449
|
+
constraints = getattr(table, "constraints", None)
|
|
1450
|
+
if constraints is None:
|
|
1451
|
+
return []
|
|
1452
|
+
return [
|
|
1453
|
+
constraint
|
|
1454
|
+
for constraint in constraints
|
|
1455
|
+
if isinstance(constraint, UniqueConstraint)
|
|
1456
|
+
]
|
|
1457
|
+
|
|
1458
|
+
|
|
1459
|
+
def _constraint_column_names(constraint: Any) -> list[str]:
|
|
1460
|
+
columns = getattr(constraint, "columns", None)
|
|
1461
|
+
if columns is None:
|
|
1462
|
+
return []
|
|
1463
|
+
return [_storage_item_name(column) for column in columns]
|
|
1464
|
+
|
|
1465
|
+
|
|
1394
1466
|
def _storage_identity_from_parts(
|
|
1395
1467
|
*,
|
|
1396
1468
|
columns: Sequence[Any],
|
|
@@ -1069,6 +1069,7 @@ def test_prepare_for_alembic_reserves_existing_table_name_with_provider_identity
|
|
|
1069
1069
|
def fake_bulk_create(rows, *, timeout=None, on_status=None):
|
|
1070
1070
|
reserved_payloads.extend(rows)
|
|
1071
1071
|
assert [table["identifier"] for table in rows] == [
|
|
1072
|
+
"example_assets__account",
|
|
1072
1073
|
"example_assets__asset",
|
|
1073
1074
|
]
|
|
1074
1075
|
assert all(table["migration_package"] == "sample" for table in rows)
|
|
@@ -1079,11 +1080,17 @@ def test_prepare_for_alembic_reserves_existing_table_name_with_provider_identity
|
|
|
1079
1080
|
assert not hasattr(rows[0]["table_contract"], "foreign_keys")
|
|
1080
1081
|
assert all("schema_management" not in table for table in rows)
|
|
1081
1082
|
return [
|
|
1083
|
+
_reserved_metatable(
|
|
1084
|
+
uid="aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
|
|
1085
|
+
identifier="example_assets__account",
|
|
1086
|
+
physical_table_name="example_assets__account",
|
|
1087
|
+
storage_hash=rows[0]["storage_hash"],
|
|
1088
|
+
),
|
|
1082
1089
|
_reserved_metatable(
|
|
1083
1090
|
uid="bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb",
|
|
1084
1091
|
identifier="example_assets__asset",
|
|
1085
1092
|
physical_table_name="example_assets__asset",
|
|
1086
|
-
storage_hash=rows[
|
|
1093
|
+
storage_hash=rows[1]["storage_hash"],
|
|
1087
1094
|
),
|
|
1088
1095
|
]
|
|
1089
1096
|
|
|
@@ -1106,6 +1113,7 @@ def test_prepare_for_alembic_reserves_existing_table_name_with_provider_identity
|
|
|
1106
1113
|
|
|
1107
1114
|
assert len(filter_calls) == 1
|
|
1108
1115
|
assert [payload["identifier"] for payload in reserved_payloads] == [
|
|
1116
|
+
"example_assets__account",
|
|
1109
1117
|
"example_assets__asset",
|
|
1110
1118
|
]
|
|
1111
1119
|
assert "schema_management" not in reserved_payloads[0]
|
|
@@ -1115,6 +1123,10 @@ def test_prepare_for_alembic_reserves_existing_table_name_with_provider_identity
|
|
|
1115
1123
|
]
|
|
1116
1124
|
assert Account.__table__.name == "example_assets__account"
|
|
1117
1125
|
assert Asset.__table__.name == "example_assets__asset"
|
|
1126
|
+
assert (
|
|
1127
|
+
"Restaging existing reserved MetaTable table_name=example_assets__account "
|
|
1128
|
+
"with current provider contract."
|
|
1129
|
+
) in reservation_statuses
|
|
1118
1130
|
|
|
1119
1131
|
|
|
1120
1132
|
def test_prepare_for_alembic_reserves_already_staged_existing_rows(monkeypatch):
|
|
@@ -22,6 +22,8 @@ from mainsequence.meta_tables import (
|
|
|
22
22
|
external_registered_registration_request_from_sqlalchemy_model,
|
|
23
23
|
platform_managed_migration_registration_context,
|
|
24
24
|
platform_managed_registration_request_from_sqlalchemy_model,
|
|
25
|
+
schema_index_name,
|
|
26
|
+
sqlalchemy_naming_convention,
|
|
25
27
|
table_contract_from_sqlalchemy_model,
|
|
26
28
|
time_indexed_registration_request_from_sqlalchemy_model,
|
|
27
29
|
)
|
|
@@ -1535,6 +1537,85 @@ def test_platform_managed_metatable_preserves_authored_tablename_with_sqlalchemy
|
|
|
1535
1537
|
assert not hasattr(request.table_contract, "foreign_keys")
|
|
1536
1538
|
|
|
1537
1539
|
|
|
1540
|
+
def test_time_index_metadata_generates_unique_grain_index_with_schema_name():
|
|
1541
|
+
pytest.importorskip("sqlalchemy")
|
|
1542
|
+
|
|
1543
|
+
from sqlalchemy import DateTime, Float, MetaData, String
|
|
1544
|
+
from sqlalchemy.orm import DeclarativeBase, mapped_column
|
|
1545
|
+
|
|
1546
|
+
class Base(DeclarativeBase):
|
|
1547
|
+
metadata = MetaData(naming_convention=sqlalchemy_naming_convention())
|
|
1548
|
+
|
|
1549
|
+
class Prices(PlatformTimeIndexMetaData, Base):
|
|
1550
|
+
__tablename__ = "ms_markets__prices__mainsequence_examples"
|
|
1551
|
+
__metatable_namespace__ = "mainsequence.examples"
|
|
1552
|
+
__time_index_name__ = "time_index"
|
|
1553
|
+
__index_names__ = ["time_index", "asset_identifier"]
|
|
1554
|
+
|
|
1555
|
+
time_index: Mapped[datetime.datetime] = mapped_column(
|
|
1556
|
+
DateTime(timezone=True),
|
|
1557
|
+
nullable=False,
|
|
1558
|
+
)
|
|
1559
|
+
asset_identifier: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
1560
|
+
close: Mapped[float] = mapped_column(Float, nullable=True)
|
|
1561
|
+
|
|
1562
|
+
grain_indexes = [
|
|
1563
|
+
index
|
|
1564
|
+
for index in Prices.__table__.indexes
|
|
1565
|
+
if index.unique
|
|
1566
|
+
and [column.name for column in index.columns] == ["time_index", "asset_identifier"]
|
|
1567
|
+
]
|
|
1568
|
+
|
|
1569
|
+
assert len(grain_indexes) == 1
|
|
1570
|
+
assert grain_indexes[0].name == schema_index_name(
|
|
1571
|
+
"ms_markets__prices__mainsequence_examples",
|
|
1572
|
+
["time_index", "asset_identifier"],
|
|
1573
|
+
unique=True,
|
|
1574
|
+
)
|
|
1575
|
+
|
|
1576
|
+
|
|
1577
|
+
def test_time_index_metadata_reuses_existing_unique_grain_constraint():
|
|
1578
|
+
pytest.importorskip("sqlalchemy")
|
|
1579
|
+
|
|
1580
|
+
from sqlalchemy import DateTime, Float, MetaData, String, UniqueConstraint
|
|
1581
|
+
from sqlalchemy.orm import DeclarativeBase, mapped_column
|
|
1582
|
+
|
|
1583
|
+
class Base(DeclarativeBase):
|
|
1584
|
+
metadata = MetaData(naming_convention=sqlalchemy_naming_convention())
|
|
1585
|
+
|
|
1586
|
+
class Prices(PlatformTimeIndexMetaData, Base):
|
|
1587
|
+
__tablename__ = "ms_markets__prices__mainsequence_examples"
|
|
1588
|
+
__table_args__ = (
|
|
1589
|
+
UniqueConstraint(
|
|
1590
|
+
"asset_identifier",
|
|
1591
|
+
"time_index",
|
|
1592
|
+
name="uix_custom_asset_time",
|
|
1593
|
+
),
|
|
1594
|
+
)
|
|
1595
|
+
__metatable_namespace__ = "mainsequence.examples"
|
|
1596
|
+
__time_index_name__ = "time_index"
|
|
1597
|
+
__index_names__ = ["time_index", "asset_identifier"]
|
|
1598
|
+
|
|
1599
|
+
time_index: Mapped[datetime.datetime] = mapped_column(
|
|
1600
|
+
DateTime(timezone=True),
|
|
1601
|
+
nullable=False,
|
|
1602
|
+
)
|
|
1603
|
+
asset_identifier: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
1604
|
+
close: Mapped[float] = mapped_column(Float, nullable=True)
|
|
1605
|
+
|
|
1606
|
+
assert not Prices.__table__.indexes
|
|
1607
|
+
unique_constraints = [
|
|
1608
|
+
constraint
|
|
1609
|
+
for constraint in Prices.__table__.constraints
|
|
1610
|
+
if isinstance(constraint, UniqueConstraint)
|
|
1611
|
+
]
|
|
1612
|
+
assert len(unique_constraints) == 1
|
|
1613
|
+
assert [column.name for column in unique_constraints[0].columns] == [
|
|
1614
|
+
"asset_identifier",
|
|
1615
|
+
"time_index",
|
|
1616
|
+
]
|
|
1617
|
+
|
|
1618
|
+
|
|
1538
1619
|
def test_platform_managed_register_preserves_authored_sqlalchemy_table_name(
|
|
1539
1620
|
monkeypatch,
|
|
1540
1621
|
):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/a2a_communication/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
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/dashboards/streamlit/SKILL.md
RENAMED
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/data_access/exploration/SKILL.md
RENAMED
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/agent_scaffold/skills/maintenance/bug_auditor/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
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/app_component.py
RENAMED
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/connections.py
RENAMED
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/data_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/command_center/workspace_snapshot.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/data_sources_interfaces/__init__.py
RENAMED
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/data_sources_interfaces/duckdb.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/client/data_sources_interfaces/sqlite.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
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/compiled_sql/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/build_operations.py
RENAMED
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/data_nodes.py
RENAMED
|
File without changes
|
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/namespacing.py
RENAMED
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/persist_managers.py
RENAMED
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/mainsequence/meta_tables/data_nodes/run_operations.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
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_command_center_app_component_models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mainsequence-4.2.37 → mainsequence-4.2.39}/tests/test_data_node_storage_dimension_queries.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
|