mainsequence 4.1.3__tar.gz → 4.1.5__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.3 → mainsequence-4.1.5}/PKG-INFO +1 -1
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +7 -26
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/ms-markets/SKILL.md +2 -2
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/cli.py +1 -1
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/base.py +10 -32
- {mainsequence-4.1.3/mainsequence → mainsequence-4.1.5/mainsequence/client}/compute_validation.py +6 -2
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/data_sources_interfaces/duckdb.py +4 -86
- mainsequence-4.1.5/mainsequence/client/data_sources_interfaces/local_paths.py +14 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/data_sources_interfaces/sqlite.py +3 -73
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/models_foundry.py +5 -4
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/models_helpers.py +2 -2
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/models_metatables.py +8 -279
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/utils.py +0 -3
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/logconf.py +22 -36
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/__init__.py +0 -11
- mainsequence-4.1.5/mainsequence/meta_tables/compiled_sql/__init__.py +5 -0
- mainsequence-4.1.3/mainsequence/meta_tables/compiled_sql.py → mainsequence-4.1.5/mainsequence/meta_tables/compiled_sql/v1.py +3 -3
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/data_nodes/__init__.py +0 -2
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/data_nodes/data_nodes.py +8 -29
- mainsequence-4.1.5/mainsequence/meta_tables/data_nodes/models.py +33 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/data_nodes/namespacing.py +2 -2
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/sqlalchemy_contracts.py +3 -3
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/runtime_flags.py +2 -2
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence.egg-info/PKG-INFO +1 -1
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence.egg-info/SOURCES.txt +4 -5
- {mainsequence-4.1.3 → mainsequence-4.1.5}/pyproject.toml +1 -1
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_auth_precedence.py +5 -9
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_build_operations_hashing.py +13 -14
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_cli.py +1 -1
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_data_access_mixin_dimension_audit.py +0 -55
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_data_node_storage_dimension_queries.py +2 -60
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_data_node_update_flow.py +13 -42
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_duckdb_interface_dimensions.py +0 -18
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_filter_normalization.py +8 -24
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_logconf.py +26 -11
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_meta_tables_client_models.py +4 -7
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_meta_tables_sqlalchemy_contracts.py +1 -2
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_run_configuration.py +19 -13
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_source_table_configuration.py +1 -71
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_sqlite_interface_dimensions.py +0 -18
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_update_statistics.py +1 -4
- mainsequence-4.1.3/mainsequence/meta_tables/config.py +0 -128
- mainsequence-4.1.3/mainsequence/meta_tables/configuration_models.py +0 -5
- mainsequence-4.1.3/mainsequence/meta_tables/data_nodes/models.py +0 -106
- mainsequence-4.1.3/mainsequence/meta_tables/utils.py +0 -45
- {mainsequence-4.1.3 → mainsequence-4.1.5}/LICENSE +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/README.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/__init__.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/__main__.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/bootstrap.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/api.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/config.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/cli/ui.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/__init__.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/client.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/command_center/__init__.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/command_center/app_component.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/command_center/connections.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/command_center/data_models.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/command_center/workspace.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/dtype_codec.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/fastapi/__init__.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/fastapi/auth.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/models_user.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/defaults.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/__main__.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/data_nodes/build_operations.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/data_nodes/persist_managers.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/data_nodes/run_operations.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/data_nodes/utils.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/future_registry.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/hashing.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/meta_tables/pydantic_metadata.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/setup.cfg +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_client.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_command_center_app_component_models.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_command_center_data_models.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_command_center_models.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_dependency_extras.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_pod_project_resolution.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_secret_client_model.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_update_uid_guards.py +0 -0
- {mainsequence-4.1.3 → mainsequence-4.1.5}/tests/test_workspace_snapshot.py +0 -0
{mainsequence-4.1.3 → mainsequence-4.1.5}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md
RENAMED
|
@@ -30,8 +30,7 @@ Canonical workflow:
|
|
|
30
30
|
- `dependencies()`
|
|
31
31
|
- `update()`
|
|
32
32
|
- `prepare_update_statistics()`
|
|
33
|
-
|
|
34
|
-
- design single-index or `(time_index, unique_identifier)` DataFrame outputs
|
|
33
|
+
- design single-index or multidimensional time-first DataFrame outputs
|
|
35
34
|
- validate output shape against a `PlatformTimeIndexMetaData` storage contract
|
|
36
35
|
- define explicit `hash_namespace(...)` validation strategy
|
|
37
36
|
- write or review DataNode smoke tests
|
|
@@ -80,7 +79,6 @@ Before changing code, collect or infer:
|
|
|
80
79
|
- expected time index and identity index shape
|
|
81
80
|
- expected columns and dtypes from the storage class
|
|
82
81
|
- upstream dependencies
|
|
83
|
-
- whether the update is asset scoped
|
|
84
82
|
- first-run or backfill bounds
|
|
85
83
|
- whether the change must preserve the existing table contract
|
|
86
84
|
|
|
@@ -302,30 +300,19 @@ changing it changes the dependency graph and update identity.
|
|
|
302
300
|
|
|
303
301
|
Do not construct dependency graphs dynamically inside `update()`.
|
|
304
302
|
|
|
305
|
-
### 8.
|
|
306
|
-
|
|
307
|
-
If the node emits `(time_index, unique_identifier)`:
|
|
308
|
-
|
|
309
|
-
- `unique_identifier` should represent an Asset identity
|
|
310
|
-
- asset scope should live in update configuration when it affects the updater
|
|
311
|
-
- `get_asset_list()` must reflect the effective updater asset scope when the
|
|
312
|
-
workflow uses that hook
|
|
313
|
-
- missing assets should be resolved or registered by the relevant workflow
|
|
314
|
-
|
|
315
|
-
### 9. Foreign Keys Belong To The Storage Contract
|
|
303
|
+
### 8. Foreign Keys Belong To The Storage Contract
|
|
316
304
|
|
|
317
305
|
For new code, model foreign keys on the `PlatformTimeIndexMetaData` storage
|
|
318
306
|
class or route the storage-contract work to the MetaTable skill.
|
|
319
307
|
|
|
320
308
|
Do not add DataNode configuration fields just to mutate storage metadata.
|
|
321
309
|
|
|
322
|
-
###
|
|
310
|
+
### 9. Metadata Belongs To Storage
|
|
323
311
|
|
|
324
312
|
Production-quality table identifiers, descriptions, labels, column docs, and
|
|
325
313
|
foreign-key metadata belong to the storage class/MetaTable registration path.
|
|
326
314
|
|
|
327
|
-
Do not
|
|
328
|
-
surface for new DataNode work.
|
|
315
|
+
Do not put schema or published table metadata on the DataNode configuration.
|
|
329
316
|
|
|
330
317
|
## Review Rules
|
|
331
318
|
|
|
@@ -333,7 +320,7 @@ When reviewing an existing DataNode, look for:
|
|
|
333
320
|
|
|
334
321
|
- output storage contract hidden in `DataNodeConfiguration`
|
|
335
322
|
- dependency storage table passed as an ad hoc constructor argument
|
|
336
|
-
-
|
|
323
|
+
- schema or published table metadata hidden in DataNode configuration
|
|
337
324
|
- `update_only`, `runtime_only`, or `ignore_from_storage_hash`
|
|
338
325
|
- `test_node=True`
|
|
339
326
|
- missing explicit `storage_table`
|
|
@@ -342,7 +329,7 @@ When reviewing an existing DataNode, look for:
|
|
|
342
329
|
- misuse of `hash_namespace`
|
|
343
330
|
- non-incremental `update()` behavior
|
|
344
331
|
- hidden dependency creation inside `update()`
|
|
345
|
-
- invalid
|
|
332
|
+
- invalid identity-indexed output shape
|
|
346
333
|
- `time_index` dtype that is not exactly `datetime64[ns, UTC]`
|
|
347
334
|
- DataFrame columns that do not match the `PlatformTimeIndexMetaData` class
|
|
348
335
|
|
|
@@ -363,17 +350,11 @@ Do not claim success until you have checked:
|
|
|
363
350
|
- non-empty outputs have first index level `time_index` with dtype `datetime64[ns, UTC]`
|
|
364
351
|
- the first validation run uses explicit `hash_namespace(...)` when it touches a shared backend
|
|
365
352
|
|
|
366
|
-
For asset-scoped updates, also check:
|
|
367
|
-
|
|
368
|
-
- `get_asset_list()` is correct when used
|
|
369
|
-
- no duplicate `(time_index, unique_identifier)` rows are emitted
|
|
370
|
-
- assets exist or are registered idempotently when needed
|
|
371
|
-
|
|
372
353
|
## This Skill Must Stop And Escalate When
|
|
373
354
|
|
|
374
355
|
- the change may break an existing published table contract and the versioning decision is unclear
|
|
375
356
|
- the intended storage class or MetaTable registration path is unclear
|
|
376
|
-
- the node needs
|
|
357
|
+
- the node needs identity dimensions but the coordinate strategy is unclear
|
|
377
358
|
- the task is actually an API, MetaTable, orchestration, or sharing problem
|
|
378
359
|
- docs, skill instructions, and code disagree on hashing or runtime behavior
|
|
379
360
|
|
|
@@ -6,8 +6,8 @@ description: Use this skill when a Main Sequence project needs financial markets
|
|
|
6
6
|
# Main Sequence ms-markets
|
|
7
7
|
|
|
8
8
|
`ms-markets` is the Main Sequence supported library for financial markets workflows.
|
|
9
|
-
Use it for market assets, market MetaTables,
|
|
10
|
-
|
|
9
|
+
Use it for market assets, market MetaTables, portfolios, orders, trades, and
|
|
10
|
+
related market-domain APIs.
|
|
11
11
|
|
|
12
12
|
This SDK scaffold skill is intentionally tiny. It does not own market-domain
|
|
13
13
|
implementation rules. Install `ms-markets` and copy its packaged skills into the
|
|
@@ -45,7 +45,7 @@ import click
|
|
|
45
45
|
import typer
|
|
46
46
|
import yaml
|
|
47
47
|
|
|
48
|
-
from ..compute_validation import decimal_to_storage, parse_cpu_request, parse_memory_request
|
|
48
|
+
from ..client.compute_validation import decimal_to_storage, parse_cpu_request, parse_memory_request
|
|
49
49
|
from . import config as cfg
|
|
50
50
|
from .api import (
|
|
51
51
|
ApiError,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
import os
|
|
3
|
-
import warnings
|
|
4
3
|
from collections.abc import Callable, Iterable
|
|
5
4
|
from datetime import datetime
|
|
6
5
|
from typing import Any, ClassVar
|
|
@@ -85,7 +84,6 @@ class BaseObjectOrm:
|
|
|
85
84
|
"MultiIndexMetadata": "orm/multi_index_metadata",
|
|
86
85
|
"ContinuousAggMultiIndex": "ts_manager/cont_agg_multi_ind",
|
|
87
86
|
"TimeIndexMetaData": "ts_manager/dynamic_table",
|
|
88
|
-
# "LocalTimeSerieNodesMethods": "ogm/local_time_serie",
|
|
89
87
|
"LocalTimeSerieNodesMethods": "ts_manager/local_time_serie",
|
|
90
88
|
"DataNodeUpdate": "ts_manager/local_time_serie",
|
|
91
89
|
"DataNodeUpdateDetails": "ts_manager/local_time_serie_update_details",
|
|
@@ -98,13 +96,12 @@ class BaseObjectOrm:
|
|
|
98
96
|
"JobRun": "pods/job-run",
|
|
99
97
|
"Constant": "pods/constant",
|
|
100
98
|
"Secret": "pods/secret",
|
|
101
|
-
"ProjectBaseImage":"pods/project-base-image",
|
|
102
|
-
"ProjectImage":"pods/project-image",
|
|
99
|
+
"ProjectBaseImage": "pods/project-base-image",
|
|
100
|
+
"ProjectImage": "pods/project-image",
|
|
103
101
|
"GithubOrganization": "pods/github-organization",
|
|
104
|
-
"ProjectResource":"pods/project-resource",
|
|
105
|
-
"ResourceRelease":"pods/resource-release",
|
|
106
|
-
"Bucket":"pods/bucket",
|
|
107
|
-
|
|
102
|
+
"ProjectResource": "pods/project-resource",
|
|
103
|
+
"ResourceRelease": "pods/resource-release",
|
|
104
|
+
"Bucket": "pods/bucket",
|
|
108
105
|
}
|
|
109
106
|
ROOT_URL = API_ENDPOINT
|
|
110
107
|
LOADERS = loaders
|
|
@@ -527,7 +524,6 @@ class BaseObjectOrm:
|
|
|
527
524
|
)
|
|
528
525
|
raise_for_response(r)
|
|
529
526
|
|
|
530
|
-
|
|
531
527
|
data = r.json()
|
|
532
528
|
data["orm_class"] = cls.__name__
|
|
533
529
|
return cls(**data)
|
|
@@ -540,7 +536,6 @@ class BaseObjectOrm:
|
|
|
540
536
|
if len(candidates) > 1:
|
|
541
537
|
raise ApiError(f"Multiple objects returned for {cls.__name__} with filters={filters}")
|
|
542
538
|
|
|
543
|
-
|
|
544
539
|
return candidates[0]
|
|
545
540
|
|
|
546
541
|
@classmethod
|
|
@@ -556,8 +551,6 @@ class BaseObjectOrm:
|
|
|
556
551
|
|
|
557
552
|
@staticmethod
|
|
558
553
|
def serialize_for_json(kwargs):
|
|
559
|
-
|
|
560
|
-
|
|
561
554
|
return serialize_to_json(kwargs)
|
|
562
555
|
|
|
563
556
|
@classmethod
|
|
@@ -598,15 +591,6 @@ class BaseObjectOrm:
|
|
|
598
591
|
|
|
599
592
|
return cls(**r.json())
|
|
600
593
|
|
|
601
|
-
@classmethod
|
|
602
|
-
def _warn_internal_id_compatibility(cls, method_name: str, replacement_name: str) -> None:
|
|
603
|
-
warnings.warn(
|
|
604
|
-
f"{cls.__name__}.{method_name}() is an internal-only compatibility shim; "
|
|
605
|
-
f"use {cls.__name__}.{replacement_name}() with uid instead.",
|
|
606
|
-
DeprecationWarning,
|
|
607
|
-
stacklevel=3,
|
|
608
|
-
)
|
|
609
|
-
|
|
610
594
|
@classmethod
|
|
611
595
|
def _destroy_by_reference(cls, public_reference, *args, timeout=None, **kwargs):
|
|
612
596
|
base_url = cls.get_object_url()
|
|
@@ -632,11 +616,6 @@ class BaseObjectOrm:
|
|
|
632
616
|
if r.status_code != 204:
|
|
633
617
|
raise_for_response(r)
|
|
634
618
|
|
|
635
|
-
@classmethod
|
|
636
|
-
def _destroy_by_id_compat(cls, instance_id, *args, timeout=None, **kwargs):
|
|
637
|
-
cls._warn_internal_id_compatibility("_destroy_by_id_compat", "destroy_by_uid")
|
|
638
|
-
return cls._destroy_by_reference(instance_id, *args, timeout=timeout, **kwargs)
|
|
639
|
-
|
|
640
619
|
@classmethod
|
|
641
620
|
def destroy_by_uid(cls, uid: str, *args, timeout=None, **kwargs):
|
|
642
621
|
return cls._destroy_by_reference(uid, *args, timeout=timeout, **kwargs)
|
|
@@ -679,7 +658,11 @@ class BaseObjectOrm:
|
|
|
679
658
|
aliases.add(choice)
|
|
680
659
|
else:
|
|
681
660
|
path = getattr(validation_alias, "path", None)
|
|
682
|
-
if
|
|
661
|
+
if (
|
|
662
|
+
isinstance(path, (list, tuple))
|
|
663
|
+
and len(path) == 1
|
|
664
|
+
and isinstance(path[0], str)
|
|
665
|
+
):
|
|
683
666
|
aliases.add(path[0])
|
|
684
667
|
|
|
685
668
|
return aliases
|
|
@@ -734,11 +717,6 @@ class BaseObjectOrm:
|
|
|
734
717
|
# Otherwise return a new instance
|
|
735
718
|
return cls(**body)
|
|
736
719
|
|
|
737
|
-
@classmethod
|
|
738
|
-
def _patch_by_id_compat(cls, instance_id, *args, _into=None, **kwargs):
|
|
739
|
-
cls._warn_internal_id_compatibility("_patch_by_id_compat", "patch_by_uid")
|
|
740
|
-
return cls._patch_by_reference(instance_id, *args, _into=_into, **kwargs)
|
|
741
|
-
|
|
742
720
|
@classmethod
|
|
743
721
|
def patch_by_uid(cls, uid: str, *args, _into=None, **kwargs):
|
|
744
722
|
return cls._patch_by_reference(uid, *args, _into=_into, **kwargs)
|
{mainsequence-4.1.3/mainsequence → mainsequence-4.1.5/mainsequence/client}/compute_validation.py
RENAMED
|
@@ -114,7 +114,9 @@ def parse_gpu_request(value: Any, *, field_name: str = "gpu_request") -> int | N
|
|
|
114
114
|
raise ValueError(f"{field_name} must be a valid integer.") from exc
|
|
115
115
|
|
|
116
116
|
|
|
117
|
-
def format_cpu_request(
|
|
117
|
+
def format_cpu_request(
|
|
118
|
+
value: Decimal | None, *, output_format: Literal["decimal", "k8s"] = "decimal"
|
|
119
|
+
) -> str | None:
|
|
118
120
|
if value is None:
|
|
119
121
|
return None
|
|
120
122
|
if output_format == "decimal":
|
|
@@ -129,7 +131,9 @@ def format_cpu_request(value: Decimal | None, *, output_format: Literal["decimal
|
|
|
129
131
|
return decimal_to_storage(value)
|
|
130
132
|
|
|
131
133
|
|
|
132
|
-
def format_memory_request(
|
|
134
|
+
def format_memory_request(
|
|
135
|
+
value: Decimal | None, *, output_format: Literal["decimal", "k8s"] = "decimal"
|
|
136
|
+
) -> str | None:
|
|
133
137
|
if value is None:
|
|
134
138
|
return None
|
|
135
139
|
if output_format == "decimal":
|
{mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/data_sources_interfaces/duckdb.py
RENAMED
|
@@ -22,7 +22,8 @@ from ..dtype_codec import (
|
|
|
22
22
|
token_to_pandas_dtype,
|
|
23
23
|
token_to_pandas_series,
|
|
24
24
|
)
|
|
25
|
-
from ..utils import DataFrequency
|
|
25
|
+
from ..utils import DataFrequency
|
|
26
|
+
from .local_paths import local_data_path
|
|
26
27
|
|
|
27
28
|
|
|
28
29
|
def get_logger():
|
|
@@ -53,12 +54,10 @@ class DuckDBInterface:
|
|
|
53
54
|
environment variable or 'analytics.duckdb'
|
|
54
55
|
in the current directory if the variable is not set.
|
|
55
56
|
"""
|
|
56
|
-
from mainsequence.meta_tables.config import META_TABLES_DATA_PATH
|
|
57
|
-
|
|
58
57
|
# ── choose default & normalise to string ───────────────────────────
|
|
59
58
|
default_path = os.getenv(
|
|
60
59
|
"DUCKDB_PATH",
|
|
61
|
-
os.
|
|
60
|
+
os.fspath(local_data_path() / "duck_db"),
|
|
62
61
|
)
|
|
63
62
|
db_uri = str(db_path or default_path).rstrip("/")
|
|
64
63
|
|
|
@@ -711,8 +710,6 @@ class DuckDBInterface:
|
|
|
711
710
|
dimension_filters: dict[str, list[Any]] | None = None,
|
|
712
711
|
index_coordinates: list[dict[str, Any]] | None = None,
|
|
713
712
|
dimension_range_map: list[dict[str, Any]] | None = None,
|
|
714
|
-
ids: list[str] | None = None,
|
|
715
|
-
unique_identifier_range_map: dict[str, dict[str, Any]] | None = None,
|
|
716
713
|
max_rows: int | None = None,
|
|
717
714
|
now: datetime.datetime | None = None,
|
|
718
715
|
) -> tuple[
|
|
@@ -971,45 +968,6 @@ class DuckDBInterface:
|
|
|
971
968
|
f"time_index_name {time_index_name!r} must be present in index_names {index_names!r}"
|
|
972
969
|
)
|
|
973
970
|
|
|
974
|
-
identity_dimensions = [name for name in index_names if name != time_index_name]
|
|
975
|
-
uses_legacy_unique_identifier = identity_dimensions == ["unique_identifier"]
|
|
976
|
-
|
|
977
|
-
if ids is not None and unique_identifier_range_map is not None:
|
|
978
|
-
raise ValueError("Cannot provide both 'ids' and 'unique_identifier_range_map'.")
|
|
979
|
-
if ids is not None and not uses_legacy_unique_identifier:
|
|
980
|
-
raise ValueError("Legacy 'ids' reads are valid only for unique_identifier tables.")
|
|
981
|
-
if unique_identifier_range_map is not None and not uses_legacy_unique_identifier:
|
|
982
|
-
raise ValueError(
|
|
983
|
-
"Legacy 'unique_identifier_range_map' reads are valid only for "
|
|
984
|
-
"unique_identifier tables."
|
|
985
|
-
)
|
|
986
|
-
if unique_identifier_range_map is not None and normalized_dimension_range_map is not None:
|
|
987
|
-
raise ValueError(
|
|
988
|
-
"Cannot provide both 'unique_identifier_range_map' and 'dimension_range_map'."
|
|
989
|
-
)
|
|
990
|
-
|
|
991
|
-
# If ids are given without a range map, create a simple one from start/end
|
|
992
|
-
if ids and (normalized_dimension_range_map is None):
|
|
993
|
-
normalized_dimension_range_map = [
|
|
994
|
-
{
|
|
995
|
-
"coordinate": {"unique_identifier": uid},
|
|
996
|
-
"start_date": start_ts.to_pydatetime() if start_ts is not None else None,
|
|
997
|
-
"start_date_operand": ">=",
|
|
998
|
-
"end_date": (
|
|
999
|
-
(end_ts or _to_utc_ts(now)).to_pydatetime()
|
|
1000
|
-
if (end_ts or now) is not None
|
|
1001
|
-
else None
|
|
1002
|
-
),
|
|
1003
|
-
"end_date_operand": "<=",
|
|
1004
|
-
}
|
|
1005
|
-
for uid in ids
|
|
1006
|
-
]
|
|
1007
|
-
if unique_identifier_range_map is not None:
|
|
1008
|
-
normalized_dimension_range_map = [
|
|
1009
|
-
{"coordinate": {"unique_identifier": uid}, **dict(info)}
|
|
1010
|
-
for uid, info in unique_identifier_range_map.items()
|
|
1011
|
-
]
|
|
1012
|
-
|
|
1013
971
|
# Compute global window from inputs
|
|
1014
972
|
if normalized_dimension_range_map:
|
|
1015
973
|
eff_start = _effective_start_from_range_map(normalized_dimension_range_map)
|
|
@@ -1192,10 +1150,7 @@ class DuckDBInterface:
|
|
|
1192
1150
|
dimension_filters: dict[str, list[Any]] | None = None,
|
|
1193
1151
|
index_coordinates: list[dict[str, Any]] | None = None,
|
|
1194
1152
|
dimension_range_map: list[dict[str, Any]] | None = None,
|
|
1195
|
-
ids: list[str] | None = None,
|
|
1196
1153
|
columns: list[str] | None = None,
|
|
1197
|
-
unique_identifier_range_map: UniqueIdentifierRangeMap | None = None,
|
|
1198
|
-
column_range_descriptor: dict[str, UniqueIdentifierRangeMap] | None = None,
|
|
1199
1154
|
) -> pd.DataFrame:
|
|
1200
1155
|
"""
|
|
1201
1156
|
Reads data from the specified table, with optional filtering.
|
|
@@ -1207,18 +1162,10 @@ class DuckDBInterface:
|
|
|
1207
1162
|
end (Optional[datetime.datetime]): Maximum temporal-column filter.
|
|
1208
1163
|
great_or_equal (bool): If True, use >= for start date comparison. Defaults to True.
|
|
1209
1164
|
less_or_equal (bool): If True, use <= for end date comparison. Defaults to True.
|
|
1210
|
-
ids (Optional[List[str]]): List of specific unique_identifiers to include.
|
|
1211
1165
|
columns (Optional[List[str]]): Specific columns to select. Reads all if None.
|
|
1212
|
-
unique_identifier_range_map (Optional[UniqueIdentifierRangeMap]):
|
|
1213
|
-
A map where keys are unique_identifiers and values are dicts specifying
|
|
1214
|
-
date ranges (start_date, end_date, start_date_operand, end_date_operand)
|
|
1215
|
-
for that identifier. Mutually exclusive with 'ids'.
|
|
1216
1166
|
|
|
1217
1167
|
Returns:
|
|
1218
1168
|
pd.DataFrame: The queried data, or an empty DataFrame if the table doesn't exist.
|
|
1219
|
-
|
|
1220
|
-
Raises:
|
|
1221
|
-
ValueError: If both `ids` and `unique_identifier_range_map` are provided.
|
|
1222
1169
|
"""
|
|
1223
1170
|
|
|
1224
1171
|
def qident(name: str) -> str:
|
|
@@ -1248,39 +1195,10 @@ class DuckDBInterface:
|
|
|
1248
1195
|
f"time_index_name {time_index_name!r} must be present in index_names {index_names!r}"
|
|
1249
1196
|
)
|
|
1250
1197
|
identity_dimensions = [name for name in index_names if name != time_index_name]
|
|
1251
|
-
uses_legacy_unique_identifier = identity_dimensions == ["unique_identifier"]
|
|
1252
|
-
|
|
1253
|
-
if ids is not None and unique_identifier_range_map is not None:
|
|
1254
|
-
raise ValueError("Cannot provide both 'ids' and 'unique_identifier_range_map'.")
|
|
1255
|
-
if ids is not None and not uses_legacy_unique_identifier:
|
|
1256
|
-
raise ValueError("Legacy 'ids' reads are valid only for unique_identifier tables.")
|
|
1257
|
-
if unique_identifier_range_map is not None and not uses_legacy_unique_identifier:
|
|
1258
|
-
raise ValueError(
|
|
1259
|
-
"Legacy 'unique_identifier_range_map' reads are valid only for "
|
|
1260
|
-
"unique_identifier tables."
|
|
1261
|
-
)
|
|
1262
|
-
if unique_identifier_range_map is not None and dimension_range_map is not None:
|
|
1263
|
-
raise ValueError(
|
|
1264
|
-
"Cannot provide both 'unique_identifier_range_map' and 'dimension_range_map'."
|
|
1265
|
-
)
|
|
1266
|
-
if column_range_descriptor is not None:
|
|
1267
|
-
raise NotImplementedError("DuckDB column_range_descriptor reads are not supported.")
|
|
1268
|
-
|
|
1269
|
-
if ids:
|
|
1270
|
-
dimension_filters = dict(dimension_filters or {})
|
|
1271
|
-
if "unique_identifier" in dimension_filters:
|
|
1272
|
-
raise ValueError("Cannot provide both 'ids' and a unique_identifier filter.")
|
|
1273
|
-
dimension_filters["unique_identifier"] = list(ids)
|
|
1274
|
-
|
|
1275
|
-
if unique_identifier_range_map is not None:
|
|
1276
|
-
dimension_range_map = [
|
|
1277
|
-
{"coordinate": {"unique_identifier": uid}, **dict(info)}
|
|
1278
|
-
for uid, info in unique_identifier_range_map.items()
|
|
1279
|
-
]
|
|
1280
1198
|
|
|
1281
1199
|
logger.debug(
|
|
1282
1200
|
f"Duck DB: Reading from table '{table}' with filters: start={start}, end={end}, "
|
|
1283
|
-
f"
|
|
1201
|
+
f"columns={columns}, range_map={dimension_range_map is not None}"
|
|
1284
1202
|
)
|
|
1285
1203
|
|
|
1286
1204
|
if not self.table_exists(table):
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def local_data_path() -> Path:
|
|
8
|
+
configured = (os.getenv("MAINSEQUENCE_LOCAL_DATA_PATH") or "").strip()
|
|
9
|
+
if configured:
|
|
10
|
+
return Path(configured).expanduser()
|
|
11
|
+
return Path.home() / "meta_tables" / "data"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = ["local_data_path"]
|
{mainsequence-4.1.3 → mainsequence-4.1.5}/mainsequence/client/data_sources_interfaces/sqlite.py
RENAMED
|
@@ -16,7 +16,7 @@ from ..dtype_codec import (
|
|
|
16
16
|
token_to_backend_type,
|
|
17
17
|
token_to_pandas_series,
|
|
18
18
|
)
|
|
19
|
-
from
|
|
19
|
+
from .local_paths import local_data_path
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def get_logger():
|
|
@@ -33,11 +33,9 @@ class SQLiteInterface:
|
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
35
|
def __init__(self, db_path: str | Path | None = None):
|
|
36
|
-
from mainsequence.meta_tables.config import META_TABLES_DATA_PATH
|
|
37
|
-
|
|
38
36
|
default_path = os.getenv(
|
|
39
37
|
"SQLITE_PATH",
|
|
40
|
-
os.
|
|
38
|
+
os.fspath(local_data_path() / "sqlite"),
|
|
41
39
|
)
|
|
42
40
|
raw_path = Path(str(db_path or default_path)).expanduser()
|
|
43
41
|
if raw_path.suffix in {".db", ".sqlite", ".sqlite3"}:
|
|
@@ -192,7 +190,6 @@ class SQLiteInterface:
|
|
|
192
190
|
*,
|
|
193
191
|
index_names: list[str],
|
|
194
192
|
time_index_name: str,
|
|
195
|
-
**_: Any,
|
|
196
193
|
) -> None:
|
|
197
194
|
self._validate_index(index_names, time_index_name)
|
|
198
195
|
if df.empty:
|
|
@@ -254,8 +251,6 @@ class SQLiteInterface:
|
|
|
254
251
|
dimension_filters: dict[str, list[Any]] | None = None,
|
|
255
252
|
index_coordinates: list[dict[str, Any]] | None = None,
|
|
256
253
|
dimension_range_map: list[dict[str, Any]] | None = None,
|
|
257
|
-
ids: list[str] | None = None,
|
|
258
|
-
unique_identifier_range_map: dict[str, dict[str, Any]] | None = None,
|
|
259
254
|
max_rows: int | None = None,
|
|
260
255
|
now: datetime.datetime | None = None,
|
|
261
256
|
) -> tuple[
|
|
@@ -265,42 +260,9 @@ class SQLiteInterface:
|
|
|
265
260
|
dict[str, Any],
|
|
266
261
|
]:
|
|
267
262
|
self._validate_index(index_names, time_index_name)
|
|
268
|
-
identity_dimensions = [name for name in index_names if name != time_index_name]
|
|
269
|
-
uses_legacy_unique_identifier = identity_dimensions == ["unique_identifier"]
|
|
270
|
-
|
|
271
|
-
if ids is not None and unique_identifier_range_map is not None:
|
|
272
|
-
raise ValueError("Cannot provide both 'ids' and 'unique_identifier_range_map'.")
|
|
273
|
-
if ids is not None and not uses_legacy_unique_identifier:
|
|
274
|
-
raise ValueError("Legacy 'ids' reads are valid only for unique_identifier tables.")
|
|
275
|
-
if unique_identifier_range_map is not None and not uses_legacy_unique_identifier:
|
|
276
|
-
raise ValueError(
|
|
277
|
-
"Legacy 'unique_identifier_range_map' reads are valid only for "
|
|
278
|
-
"unique_identifier tables."
|
|
279
|
-
)
|
|
280
|
-
if unique_identifier_range_map is not None and dimension_range_map is not None:
|
|
281
|
-
raise ValueError(
|
|
282
|
-
"Cannot provide both 'unique_identifier_range_map' and 'dimension_range_map'."
|
|
283
|
-
)
|
|
284
|
-
|
|
285
263
|
normalized_dimension_range_map = (
|
|
286
264
|
None if dimension_range_map is None else [dict(item) for item in dimension_range_map]
|
|
287
265
|
)
|
|
288
|
-
if ids and normalized_dimension_range_map is None:
|
|
289
|
-
normalized_dimension_range_map = [
|
|
290
|
-
{
|
|
291
|
-
"coordinate": {"unique_identifier": uid},
|
|
292
|
-
"start_date": start,
|
|
293
|
-
"start_date_operand": ">=",
|
|
294
|
-
"end_date": end or now,
|
|
295
|
-
"end_date_operand": "<=",
|
|
296
|
-
}
|
|
297
|
-
for uid in ids
|
|
298
|
-
]
|
|
299
|
-
if unique_identifier_range_map is not None:
|
|
300
|
-
normalized_dimension_range_map = [
|
|
301
|
-
{"coordinate": {"unique_identifier": uid}, **dict(info)}
|
|
302
|
-
for uid, info in unique_identifier_range_map.items()
|
|
303
|
-
]
|
|
304
266
|
|
|
305
267
|
diagnostics = {
|
|
306
268
|
"limited": False,
|
|
@@ -324,42 +286,9 @@ class SQLiteInterface:
|
|
|
324
286
|
dimension_filters: dict[str, list[Any]] | None = None,
|
|
325
287
|
index_coordinates: list[dict[str, Any]] | None = None,
|
|
326
288
|
dimension_range_map: list[dict[str, Any]] | None = None,
|
|
327
|
-
ids: list[str] | None = None,
|
|
328
289
|
columns: list[str] | None = None,
|
|
329
|
-
unique_identifier_range_map: UniqueIdentifierRangeMap | None = None,
|
|
330
|
-
column_range_descriptor: dict[str, UniqueIdentifierRangeMap] | None = None,
|
|
331
|
-
**_: Any,
|
|
332
290
|
) -> pd.DataFrame:
|
|
333
291
|
self._validate_index(index_names, time_index_name)
|
|
334
|
-
identity_dimensions = [name for name in index_names if name != time_index_name]
|
|
335
|
-
uses_legacy_unique_identifier = identity_dimensions == ["unique_identifier"]
|
|
336
|
-
|
|
337
|
-
if ids is not None and unique_identifier_range_map is not None:
|
|
338
|
-
raise ValueError("Cannot provide both 'ids' and 'unique_identifier_range_map'.")
|
|
339
|
-
if ids is not None and not uses_legacy_unique_identifier:
|
|
340
|
-
raise ValueError("Legacy 'ids' reads are valid only for unique_identifier tables.")
|
|
341
|
-
if unique_identifier_range_map is not None and not uses_legacy_unique_identifier:
|
|
342
|
-
raise ValueError(
|
|
343
|
-
"Legacy 'unique_identifier_range_map' reads are valid only for "
|
|
344
|
-
"unique_identifier tables."
|
|
345
|
-
)
|
|
346
|
-
if unique_identifier_range_map is not None and dimension_range_map is not None:
|
|
347
|
-
raise ValueError(
|
|
348
|
-
"Cannot provide both 'unique_identifier_range_map' and 'dimension_range_map'."
|
|
349
|
-
)
|
|
350
|
-
if column_range_descriptor is not None:
|
|
351
|
-
raise NotImplementedError("SQLite column_range_descriptor reads are not supported.")
|
|
352
|
-
|
|
353
|
-
if ids:
|
|
354
|
-
dimension_filters = dict(dimension_filters or {})
|
|
355
|
-
if "unique_identifier" in dimension_filters:
|
|
356
|
-
raise ValueError("Cannot provide both 'ids' and a unique_identifier filter.")
|
|
357
|
-
dimension_filters["unique_identifier"] = list(ids)
|
|
358
|
-
if unique_identifier_range_map is not None:
|
|
359
|
-
dimension_range_map = [
|
|
360
|
-
{"coordinate": {"unique_identifier": uid}, **dict(info)}
|
|
361
|
-
for uid, info in unique_identifier_range_map.items()
|
|
362
|
-
]
|
|
363
292
|
|
|
364
293
|
if not self.table_exists(table):
|
|
365
294
|
logger.warning(f"Table '{table}' does not exist in {self.db_path}.")
|
|
@@ -382,6 +311,7 @@ class SQLiteInterface:
|
|
|
382
311
|
sql_parts = [f"SELECT {select_sql} FROM {self._qident(table)}"]
|
|
383
312
|
where_clauses: list[str] = []
|
|
384
313
|
params: list[Any] = []
|
|
314
|
+
identity_dimensions = [name for name in index_names if name != time_index_name]
|
|
385
315
|
|
|
386
316
|
def validate_dimension_name(name: str) -> None:
|
|
387
317
|
if name not in identity_dimensions:
|
|
@@ -760,10 +760,11 @@ def add_created_object_to_jobrun(
|
|
|
760
760
|
Returns:
|
|
761
761
|
A dictionary representing the created record.
|
|
762
762
|
"""
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
763
|
+
job_run_uid = (os.getenv("JOB_RUN_UID") or "").strip()
|
|
764
|
+
if not job_run_uid:
|
|
765
|
+
raise RuntimeError("JOB_RUN_UID is required to attach created objects to a job run.")
|
|
766
|
+
|
|
767
|
+
url = MAINSEQUENCE_ENDPOINT + f"/orm/api/pods/job-run/{job_run_uid}/add_created_object/"
|
|
767
768
|
payload = {"json": {"app_label": app_label, "model_name": model_name, "object_id": object_id}}
|
|
768
769
|
|
|
769
770
|
r = make_request(
|
|
@@ -13,12 +13,12 @@ from uuid import UUID
|
|
|
13
13
|
import yaml
|
|
14
14
|
from pydantic import BaseModel, Field, PositiveInt
|
|
15
15
|
|
|
16
|
-
from
|
|
16
|
+
from .base import BaseObjectOrm, BasePydanticModel, ShareableObjectMixin
|
|
17
|
+
from .compute_validation import (
|
|
17
18
|
decimal_to_storage,
|
|
18
19
|
normalize_string,
|
|
19
20
|
validate_and_normalize_compute_fields,
|
|
20
21
|
)
|
|
21
|
-
from .base import BaseObjectOrm, BasePydanticModel, ShareableObjectMixin
|
|
22
22
|
from .exceptions import raise_for_response
|
|
23
23
|
from .models_foundry import (
|
|
24
24
|
Project,
|