mainsequence 4.1.5__tar.gz → 4.1.7__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.1.5 → mainsequence-4.1.7}/PKG-INFO +1 -1
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +21 -11
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +19 -4
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/api.py +4 -4
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/cli.py +11 -10
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/models_metatables.py +61 -2
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/logconf.py +1 -3
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/__init__.py +0 -4
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/build_operations.py +1 -1
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/data_nodes.py +2 -2
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/persist_managers.py +2 -2
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/sqlalchemy_contracts.py +263 -66
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence.egg-info/PKG-INFO +1 -1
- {mainsequence-4.1.5 → mainsequence-4.1.7}/pyproject.toml +1 -1
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_build_operations_hashing.py +3 -3
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_cli.py +29 -17
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_logconf.py +1 -16
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_meta_tables_client_models.py +46 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_meta_tables_sqlalchemy_contracts.py +271 -26
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_run_configuration.py +3 -3
- {mainsequence-4.1.5 → mainsequence-4.1.7}/LICENSE +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/README.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/ms-markets/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/__init__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/__main__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/bootstrap.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/config.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/cli/ui.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/__init__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/base.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/client.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/command_center/__init__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/command_center/app_component.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/command_center/connections.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/command_center/data_models.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/command_center/workspace.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/compute_validation.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/data_sources_interfaces/local_paths.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/data_sources_interfaces/sqlite.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/fastapi/__init__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/fastapi/auth.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/models_foundry.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/models_user.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/client/utils.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/defaults.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/__main__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/compiled_sql/__init__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/compiled_sql/v1.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/__init__.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/models.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/namespacing.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/future_registry.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/hashing.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence.egg-info/SOURCES.txt +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/setup.cfg +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_auth_precedence.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_client.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_command_center_app_component_models.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_command_center_data_models.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_command_center_models.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_data_access_mixin_dimension_audit.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_data_node_storage_dimension_queries.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_data_node_update_flow.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_dependency_extras.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_duckdb_interface_dimensions.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_filter_normalization.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_pod_project_resolution.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_secret_client_model.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_source_table_configuration.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_sqlite_interface_dimensions.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_update_statistics.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_update_uid_guards.py +0 -0
- {mainsequence-4.1.5 → mainsequence-4.1.7}/tests/test_workspace_snapshot.py +0 -0
{mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md
RENAMED
|
@@ -15,7 +15,7 @@ is defined by a registered `PlatformTimeIndexMetaData` SQLAlchemy model.
|
|
|
15
15
|
Canonical workflow:
|
|
16
16
|
|
|
17
17
|
1. Define a `PlatformTimeIndexMetaData` storage class.
|
|
18
|
-
2. Register
|
|
18
|
+
2. Register that storage class before constructing the DataNode.
|
|
19
19
|
3. Construct the DataNode with `config=...` and `storage_table=StorageClass`.
|
|
20
20
|
4. Return a DataFrame from `update()` that matches the storage class contract.
|
|
21
21
|
|
|
@@ -91,7 +91,7 @@ For every non-trivial DataNode task, make these decisions explicitly:
|
|
|
91
91
|
|
|
92
92
|
1. Is this a new dataset or the same dataset?
|
|
93
93
|
2. Is this change storage-contract work or update-process work?
|
|
94
|
-
3. Is the storage class
|
|
94
|
+
3. Is the storage class registered through its MetaTable path, or should the MetaTable skill handle it?
|
|
95
95
|
4. Is the node single-index or MultiIndex?
|
|
96
96
|
5. Does the first validation run happen under an explicit `hash_namespace(...)`?
|
|
97
97
|
|
|
@@ -108,6 +108,10 @@ The following are storage-contract decisions:
|
|
|
108
108
|
- foreign keys
|
|
109
109
|
- table description and labels
|
|
110
110
|
|
|
111
|
+
Every storage class must include `__metatable_description__`. The description
|
|
112
|
+
should explain the table's intention, row grain, and downstream use, not only
|
|
113
|
+
list columns or schema mechanics.
|
|
114
|
+
|
|
111
115
|
Do not put those concerns in `DataNodeConfiguration`.
|
|
112
116
|
|
|
113
117
|
Minimal pattern:
|
|
@@ -128,6 +132,10 @@ class Base(DeclarativeBase):
|
|
|
128
132
|
class PricesTable(PlatformTimeIndexMetaData, Base):
|
|
129
133
|
__metatable_namespace__ = "<domain_namespace>"
|
|
130
134
|
__metatable_identifier__ = "<table_identifier>"
|
|
135
|
+
__metatable_description__ = (
|
|
136
|
+
"Daily close prices keyed by asset unique identifier for portfolio and "
|
|
137
|
+
"risk analytics."
|
|
138
|
+
)
|
|
131
139
|
__time_index_name__ = "time_index"
|
|
132
140
|
__index_names__ = ["time_index", "unique_identifier"]
|
|
133
141
|
|
|
@@ -139,17 +147,17 @@ class PricesTable(PlatformTimeIndexMetaData, Base):
|
|
|
139
147
|
close: Mapped[float] = mapped_column(Float, nullable=False)
|
|
140
148
|
```
|
|
141
149
|
|
|
142
|
-
Register
|
|
150
|
+
Register storage before constructing the DataNode:
|
|
143
151
|
|
|
144
152
|
```python
|
|
145
153
|
PricesTable.register(data_source_uid=data_source_uid)
|
|
146
154
|
```
|
|
147
155
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
156
|
+
`PlatformTimeIndexMetaData.register(...)` is the storage lifecycle path. Treat it
|
|
157
|
+
as an idempotent get-or-create operation: the platform returns the registered
|
|
158
|
+
metadata and UID, and the SDK records that metadata on the class. Do not manually
|
|
159
|
+
attach an existing UID, reconstruct a generic `MetaTable`, or use manual bind
|
|
160
|
+
helpers as an authoring step.
|
|
153
161
|
|
|
154
162
|
### 2. Keep DataNode As Update Logic
|
|
155
163
|
|
|
@@ -167,7 +175,7 @@ dependency, put that dependency storage reference in the config as
|
|
|
167
175
|
`type[PlatformTimeIndexMetaData]`. Do not add an extra constructor argument for
|
|
168
176
|
dependency storage tables. Config values of this type are hashed by the bound
|
|
169
177
|
`TimeIndexMetaData.uid` from `StorageClass.__time_index_metadata__`, so the class
|
|
170
|
-
must be registered
|
|
178
|
+
must be registered before DataNode construction.
|
|
171
179
|
|
|
172
180
|
Do not accept `test_node`. It has been removed. Use explicit
|
|
173
181
|
`hash_namespace(...)` or `hash_namespace="..."`.
|
|
@@ -319,6 +327,7 @@ Do not put schema or published table metadata on the DataNode configuration.
|
|
|
319
327
|
When reviewing an existing DataNode, look for:
|
|
320
328
|
|
|
321
329
|
- output storage contract hidden in `DataNodeConfiguration`
|
|
330
|
+
- missing `__metatable_description__` on the storage table
|
|
322
331
|
- dependency storage table passed as an ad hoc constructor argument
|
|
323
332
|
- schema or published table metadata hidden in DataNode configuration
|
|
324
333
|
- `update_only`, `runtime_only`, or `ignore_from_storage_hash`
|
|
@@ -338,9 +347,10 @@ When reviewing an existing DataNode, look for:
|
|
|
338
347
|
Do not claim success until you have checked:
|
|
339
348
|
|
|
340
349
|
- the relevant docs were read first
|
|
341
|
-
- storage is a registered
|
|
350
|
+
- storage is a registered `PlatformTimeIndexMetaData` class
|
|
351
|
+
- storage has an intention-rich `__metatable_description__`
|
|
342
352
|
- the DataNode constructor requires `storage_table`
|
|
343
|
-
- dependency storage-table references live in config and are registered
|
|
353
|
+
- dependency storage-table references live in config and are registered
|
|
344
354
|
- config fields are updater-scoped by default
|
|
345
355
|
- no removed hash metadata markers remain
|
|
346
356
|
- no `test_node` usage remains
|
{mainsequence-4.1.5 → mainsequence-4.1.7}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md
RENAMED
|
@@ -99,15 +99,28 @@ The mixin derives the SQLAlchemy physical table name from storage-relevant confi
|
|
|
99
99
|
|
|
100
100
|
Schema must come from SQLAlchemy table metadata, usually `__table_args__ = {"schema": "public"}` or the tuple form ending in `{"schema": ...}`. Do not add a separate MetaTable-specific schema attribute.
|
|
101
101
|
|
|
102
|
+
Always declare `__metatable_description__` on the model. The description must
|
|
103
|
+
explain the table's business intention, row grain, and expected use, not only
|
|
104
|
+
the schema. Column-level descriptions stay in `mapped_column(info={...})`.
|
|
105
|
+
|
|
102
106
|
Register through the class API:
|
|
103
107
|
|
|
104
108
|
```python
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
class Account(PlatformManagedMetaTable, Base):
|
|
110
|
+
__metatable_namespace__ = "sdk-examples"
|
|
111
|
+
__metatable_identifier__ = "Account"
|
|
112
|
+
__metatable_description__ = (
|
|
113
|
+
"Customer account master records used to scope balances, holdings, and "
|
|
114
|
+
"account-level limits."
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
account_meta_table = Account.register(labels=["sdk-example"])
|
|
109
119
|
```
|
|
110
120
|
|
|
121
|
+
Pass `description=...` only when the call intentionally overrides the class
|
|
122
|
+
default.
|
|
123
|
+
|
|
111
124
|
For platform-managed registration, the data source is resolved from the active Main Sequence project/session, the same way DataNode does. Do not require or thread a `data_source_uid` through normal platform-managed example code.
|
|
112
125
|
|
|
113
126
|
Only call `build_registration_request()` when the task explicitly needs to inspect or validate the payload before registration.
|
|
@@ -172,6 +185,7 @@ Do not hardcode platform-managed physical names manually.
|
|
|
172
185
|
When reviewing an existing MetaTable workflow, look for:
|
|
173
186
|
|
|
174
187
|
- missing namespace or identifier
|
|
188
|
+
- missing `__metatable_description__`, or a description that only repeats column names instead of table intention
|
|
175
189
|
- backend-managed models that do not inherit `PlatformManagedMetaTable`
|
|
176
190
|
- backend-managed examples that use namespace environment variables instead of a plain `sdk-examples` namespace
|
|
177
191
|
- duplicate schema sources outside SQLAlchemy table metadata
|
|
@@ -187,6 +201,7 @@ When reviewing an existing MetaTable workflow, look for:
|
|
|
187
201
|
Do not claim success until you have checked:
|
|
188
202
|
|
|
189
203
|
- the table contract matches the intended row contract
|
|
204
|
+
- the table has an intention-rich `__metatable_description__`
|
|
190
205
|
- indexes are intentional
|
|
191
206
|
- foreign keys resolve to the correct dependency targets
|
|
192
207
|
- management mode is correct
|
|
@@ -5136,7 +5136,7 @@ def list_project_job_runs(
|
|
|
5136
5136
|
|
|
5137
5137
|
|
|
5138
5138
|
def get_project_job_run_logs(
|
|
5139
|
-
|
|
5139
|
+
job_run_uid: str,
|
|
5140
5140
|
*,
|
|
5141
5141
|
timeout: int | None = None,
|
|
5142
5142
|
) -> dict[str, Any]:
|
|
@@ -5191,20 +5191,20 @@ def get_project_job_run_logs(
|
|
|
5191
5191
|
BaseObjectOrm.ROOT_URL = root_url
|
|
5192
5192
|
ClientJobRun.ROOT_URL = root_url
|
|
5193
5193
|
|
|
5194
|
-
job_run = ClientJobRun.get(pk=
|
|
5194
|
+
job_run = ClientJobRun.get(pk=job_run_uid, timeout=timeout)
|
|
5195
5195
|
payload = job_run.get_logs(timeout=timeout)
|
|
5196
5196
|
if isinstance(payload, dict):
|
|
5197
5197
|
return payload
|
|
5198
5198
|
if hasattr(payload, "model_dump"):
|
|
5199
5199
|
return payload.model_dump()
|
|
5200
|
-
return {"
|
|
5200
|
+
return {"job_run_uid": job_run_uid, "rows": []}
|
|
5201
5201
|
|
|
5202
5202
|
except Exception as e:
|
|
5203
5203
|
err_name = type(e).__name__
|
|
5204
5204
|
if err_name in {"AuthenticationError", "PermissionDeniedError"}:
|
|
5205
5205
|
raise NotLoggedIn(str(e) or "Not logged in.") from e
|
|
5206
5206
|
if err_name == "NotFoundError":
|
|
5207
|
-
raise ApiError(f"Job run not found: {
|
|
5207
|
+
raise ApiError(f"Job run not found: {job_run_uid}") from e
|
|
5208
5208
|
raise ApiError(f"Project job run logs fetch failed: {e}") from e
|
|
5209
5209
|
finally:
|
|
5210
5210
|
if client_utils is not None:
|
|
@@ -10196,7 +10196,7 @@ def project_jobs_run_cmd(
|
|
|
10196
10196
|
if payload:
|
|
10197
10197
|
preferred_keys = [
|
|
10198
10198
|
("Job ID", str(payload.get("job") or payload.get("job_id") or job_id)),
|
|
10199
|
-
("Job Run
|
|
10199
|
+
("Job Run UID", str(payload.get("uid") or payload.get("job_run_uid") or "-")),
|
|
10200
10200
|
("Name", str(payload.get("name") or payload.get("job_name") or "-")),
|
|
10201
10201
|
("Unique Identifier", str(payload.get("unique_identifier") or "-")),
|
|
10202
10202
|
("Status", str(payload.get("status") or "-")),
|
|
@@ -10208,7 +10208,8 @@ def project_jobs_run_cmd(
|
|
|
10208
10208
|
"job",
|
|
10209
10209
|
"job_id",
|
|
10210
10210
|
"id",
|
|
10211
|
-
"
|
|
10211
|
+
"uid",
|
|
10212
|
+
"job_run_uid",
|
|
10212
10213
|
"name",
|
|
10213
10214
|
"job_name",
|
|
10214
10215
|
"unique_identifier",
|
|
@@ -10254,8 +10255,8 @@ def project_job_runs_list_cmd(
|
|
|
10254
10255
|
|
|
10255
10256
|
@project_job_runs_group.command("logs")
|
|
10256
10257
|
def project_job_runs_logs_cmd(
|
|
10257
|
-
|
|
10258
|
-
JOB_RUN_MODEL_REF, "
|
|
10258
|
+
job_run_uid: str = pydantic_argument(
|
|
10259
|
+
JOB_RUN_MODEL_REF, "uid", ..., help="Job run UID whose logs will be shown."
|
|
10259
10260
|
),
|
|
10260
10261
|
poll_interval: int = typer.Option(
|
|
10261
10262
|
30,
|
|
@@ -10279,10 +10280,10 @@ def project_job_runs_logs_cmd(
|
|
|
10279
10280
|
Examples
|
|
10280
10281
|
--------
|
|
10281
10282
|
```bash
|
|
10282
|
-
mainsequence project jobs runs logs
|
|
10283
|
-
mainsequence project jobs runs logs
|
|
10284
|
-
mainsequence project jobs runs logs
|
|
10285
|
-
mainsequence project jobs runs logs
|
|
10283
|
+
mainsequence project jobs runs logs 4c1d77c8-8a42-42b8-a9c1-06be9a336e5d
|
|
10284
|
+
mainsequence project jobs runs logs 4c1d77c8-8a42-42b8-a9c1-06be9a336e5d --poll-interval 10
|
|
10285
|
+
mainsequence project jobs runs logs 4c1d77c8-8a42-42b8-a9c1-06be9a336e5d --max-wait-seconds 900
|
|
10286
|
+
mainsequence project jobs runs logs 4c1d77c8-8a42-42b8-a9c1-06be9a336e5d --poll-interval 0
|
|
10286
10287
|
```
|
|
10287
10288
|
"""
|
|
10288
10289
|
_require_login()
|
|
@@ -10296,7 +10297,7 @@ def project_job_runs_logs_cmd(
|
|
|
10296
10297
|
|
|
10297
10298
|
while True:
|
|
10298
10299
|
try:
|
|
10299
|
-
payload = get_project_job_run_logs(
|
|
10300
|
+
payload = get_project_job_run_logs(job_run_uid=job_run_uid, timeout=timeout)
|
|
10300
10301
|
except ApiError as e:
|
|
10301
10302
|
error(f"Project job run logs fetch failed: {e}")
|
|
10302
10303
|
raise typer.Exit(1) from e
|
|
@@ -10313,7 +10314,7 @@ def project_job_runs_logs_cmd(
|
|
|
10313
10314
|
print_kv(
|
|
10314
10315
|
"Job Run Logs",
|
|
10315
10316
|
[
|
|
10316
|
-
("Job Run
|
|
10317
|
+
("Job Run UID", str(payload.get("job_run_uid") or payload.get("uid") or job_run_uid)),
|
|
10317
10318
|
("Status", status_value),
|
|
10318
10319
|
],
|
|
10319
10320
|
)
|
|
@@ -220,7 +220,13 @@ class MetaTablePhysicalContract(BasePydanticModel):
|
|
|
220
220
|
exclude=True,
|
|
221
221
|
description=("Input-only schema alias. MetaTable uses the data source default schema."),
|
|
222
222
|
)
|
|
223
|
-
table_name: str = Field(
|
|
223
|
+
table_name: str | None = Field(
|
|
224
|
+
default=None,
|
|
225
|
+
description=(
|
|
226
|
+
"Physical database table name. Required for external_registered tables; "
|
|
227
|
+
"omitted by platform_managed client requests because the backend owns it."
|
|
228
|
+
),
|
|
229
|
+
)
|
|
224
230
|
|
|
225
231
|
model_config = ConfigDict(populate_by_name=True)
|
|
226
232
|
|
|
@@ -1090,6 +1096,55 @@ class MetaTable(BasePydanticModel, LabelableObjectMixin, ShareableObjectMixin, B
|
|
|
1090
1096
|
self.introspection_snapshot = snapshot
|
|
1091
1097
|
return response_json
|
|
1092
1098
|
|
|
1099
|
+
def get_schema_graph(
|
|
1100
|
+
self,
|
|
1101
|
+
*,
|
|
1102
|
+
depth: int = 1,
|
|
1103
|
+
include_incoming: bool = False,
|
|
1104
|
+
timeout: int | float | tuple[float, float] | None = None,
|
|
1105
|
+
) -> dict[str, Any]:
|
|
1106
|
+
"""
|
|
1107
|
+
Return the MetaTable foreign-key schema graph rooted at this table.
|
|
1108
|
+
|
|
1109
|
+
The graph is the client API for dependency analysis. Outgoing edges are
|
|
1110
|
+
foreign keys declared by this table. When ``include_incoming`` is true,
|
|
1111
|
+
the response also includes visible tables that depend on this table.
|
|
1112
|
+
|
|
1113
|
+
Args:
|
|
1114
|
+
depth: Relationship traversal depth. The backend clamps this to its
|
|
1115
|
+
supported range.
|
|
1116
|
+
include_incoming: Include inbound relationships where another
|
|
1117
|
+
visible MetaTable has a foreign key targeting this table.
|
|
1118
|
+
timeout: Optional request timeout in seconds or ``requests`` timeout
|
|
1119
|
+
tuple form.
|
|
1120
|
+
|
|
1121
|
+
Returns:
|
|
1122
|
+
A dictionary with ``root_uid``, ``depth``, ``include_incoming``,
|
|
1123
|
+
``nodes``, and ``edges``. Inbound dependencies are edges where
|
|
1124
|
+
``edge["target_uid"] == self.uid``; the dependent table UID is
|
|
1125
|
+
``edge["source_uid"]``.
|
|
1126
|
+
"""
|
|
1127
|
+
url = f"{type(self).get_object_url().rstrip('/')}/{self._public_uid()}/schema-graph/"
|
|
1128
|
+
payload = {
|
|
1129
|
+
"params": serialize_to_json(
|
|
1130
|
+
{
|
|
1131
|
+
"depth": depth,
|
|
1132
|
+
"include_incoming": include_incoming,
|
|
1133
|
+
}
|
|
1134
|
+
)
|
|
1135
|
+
}
|
|
1136
|
+
response = make_request(
|
|
1137
|
+
s=type(self).build_session(),
|
|
1138
|
+
loaders=type(self).LOADERS,
|
|
1139
|
+
r_type="GET",
|
|
1140
|
+
url=url,
|
|
1141
|
+
payload=payload,
|
|
1142
|
+
time_out=timeout,
|
|
1143
|
+
)
|
|
1144
|
+
if response.status_code != 200:
|
|
1145
|
+
raise_for_response(response, payload=payload)
|
|
1146
|
+
return response.json()
|
|
1147
|
+
|
|
1093
1148
|
def refresh_table_search_index(
|
|
1094
1149
|
self,
|
|
1095
1150
|
*,
|
|
@@ -1335,7 +1390,11 @@ class TimeIndexMetaTableRegistrationRequest(BasePydanticModel):
|
|
|
1335
1390
|
model_config = ConfigDict(extra="forbid")
|
|
1336
1391
|
|
|
1337
1392
|
data_source_uid: str = Field(..., description="Public uid of the storage data source")
|
|
1338
|
-
storage_hash: str = Field(
|
|
1393
|
+
storage_hash: str = Field(
|
|
1394
|
+
...,
|
|
1395
|
+
max_length=63,
|
|
1396
|
+
description="Canonical logical storage identity for the time-indexed MetaTable",
|
|
1397
|
+
)
|
|
1339
1398
|
identifier: str | None = Field(None, description="Optional published storage identifier")
|
|
1340
1399
|
namespace: str | None = Field(None, description="Optional published storage namespace")
|
|
1341
1400
|
description: str | None = Field(None, description="Optional storage description")
|
|
@@ -236,13 +236,11 @@ def _build_backend_bindings(
|
|
|
236
236
|
if project_id is not None:
|
|
237
237
|
bindings["project_id"] = project_id
|
|
238
238
|
bindings["data_source_id"] = startup_state.get("data_source_id")
|
|
239
|
-
bindings["job_run_id"] = startup_state.get("job_run_id")
|
|
240
239
|
bindings["job_run_uid"] = startup_state.get("job_run_uid")
|
|
241
240
|
bindings["command_id"] = startup_state.get("command_id")
|
|
242
241
|
else:
|
|
243
|
-
# your existing behavior: bind job_run_id to user_id in local-ish mode
|
|
244
242
|
if "user_id" in startup_state:
|
|
245
|
-
bindings["
|
|
243
|
+
bindings["user_id"] = startup_state.get("user_id")
|
|
246
244
|
else:
|
|
247
245
|
bindings["local_mode"] = "no_app"
|
|
248
246
|
|
|
@@ -38,10 +38,6 @@ _LAZY_IMPORTS = {
|
|
|
38
38
|
".sqlalchemy_contracts",
|
|
39
39
|
"register_external_sqlalchemy_model",
|
|
40
40
|
),
|
|
41
|
-
"register_platform_managed_sqlalchemy_model": (
|
|
42
|
-
".sqlalchemy_contracts",
|
|
43
|
-
"register_platform_managed_sqlalchemy_model",
|
|
44
|
-
),
|
|
45
41
|
"slugify_identifier": (".hashing", "slugify_identifier"),
|
|
46
42
|
"table_contract_from_sqlalchemy_model": (
|
|
47
43
|
".sqlalchemy_contracts",
|
{mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/build_operations.py
RENAMED
|
@@ -96,7 +96,7 @@ def _(value: type[Any]) -> Any:
|
|
|
96
96
|
uid = getattr(time_index_metadata, "uid", None)
|
|
97
97
|
if uid in (None, ""):
|
|
98
98
|
raise ValueError(
|
|
99
|
-
"PlatformTimeIndexMetaData config values must be registered
|
|
99
|
+
"PlatformTimeIndexMetaData config values must be registered "
|
|
100
100
|
"before they can be hashed."
|
|
101
101
|
)
|
|
102
102
|
return {
|
|
@@ -647,7 +647,7 @@ class DataNode(DataAccessMixin, ABC):
|
|
|
647
647
|
)
|
|
648
648
|
if value.get_time_index_metadata() is None:
|
|
649
649
|
raise ValueError(
|
|
650
|
-
"DataNode storage_table must be registered
|
|
650
|
+
"DataNode storage_table must be registered before construction."
|
|
651
651
|
)
|
|
652
652
|
if value.get_meta_table_uid() in (None, ""):
|
|
653
653
|
raise ValueError("DataNode storage_table must provide a MetaTable UID.")
|
|
@@ -659,7 +659,7 @@ class DataNode(DataAccessMixin, ABC):
|
|
|
659
659
|
def storage_metadata(self) -> Any:
|
|
660
660
|
storage_metadata = self.storage_table.get_time_index_metadata()
|
|
661
661
|
if storage_metadata is None:
|
|
662
|
-
raise ValueError("DataNode storage_table must be registered
|
|
662
|
+
raise ValueError("DataNode storage_table must be registered before use.")
|
|
663
663
|
return storage_metadata
|
|
664
664
|
|
|
665
665
|
def _initialize_configuration(self, init_kwargs: dict) -> None:
|
{mainsequence-4.1.5 → mainsequence-4.1.7}/mainsequence/meta_tables/data_nodes/persist_managers.py
RENAMED
|
@@ -130,7 +130,7 @@ class BasePersistManager:
|
|
|
130
130
|
storage_metadata = storage_table.get_time_index_metadata()
|
|
131
131
|
if storage_metadata is None:
|
|
132
132
|
raise ValueError(
|
|
133
|
-
"PersistManager storage_table must be registered
|
|
133
|
+
"PersistManager storage_table must be registered before "
|
|
134
134
|
"constructing the DataNode."
|
|
135
135
|
)
|
|
136
136
|
if storage_table.get_meta_table_uid() in (None, ""):
|
|
@@ -143,7 +143,7 @@ class BasePersistManager:
|
|
|
143
143
|
def storage_metadata(self) -> Any:
|
|
144
144
|
storage_metadata = self.storage_table.get_time_index_metadata()
|
|
145
145
|
if storage_metadata is None:
|
|
146
|
-
raise ValueError("PersistManager storage_table must be registered
|
|
146
|
+
raise ValueError("PersistManager storage_table must be registered before use.")
|
|
147
147
|
return storage_metadata
|
|
148
148
|
|
|
149
149
|
@property
|