mainsequence 4.0.0__tar.gz → 4.0.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.0.0 → mainsequence-4.0.5}/PKG-INFO +1 -1
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md +67 -10
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/bootstrap.py +2 -1
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/api.py +139 -31
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/cli.py +250 -221
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/config.py +117 -58
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/project_status.py +30 -6
- mainsequence-4.0.5/mainsequence/client/__init__.py +16 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/models_tdag.py +71 -55
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/utils.py +0 -16
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/data_nodes/build_operations.py +3 -3
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/meta_tables/__init__.py +9 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/meta_tables/hashing.py +54 -0
- mainsequence-4.0.5/mainsequence/tdag/meta_tables/sqlalchemy_contracts.py +1066 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence.egg-info/PKG-INFO +1 -1
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence.egg-info/SOURCES.txt +0 -1
- {mainsequence-4.0.0 → mainsequence-4.0.5}/pyproject.toml +1 -1
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_cli.py +235 -81
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_data_node_update_flow.py +34 -0
- mainsequence-4.0.5/tests/test_meta_tables_sqlalchemy_contracts.py +551 -0
- mainsequence-4.0.5/tests/test_pod_project_resolution.py +177 -0
- mainsequence-4.0.0/mainsequence/client/__init__.py +0 -8
- mainsequence-4.0.0/mainsequence/client/data_sources_interfaces/timescale.py +0 -524
- mainsequence-4.0.0/mainsequence/tdag/meta_tables/sqlalchemy_contracts.py +0 -476
- mainsequence-4.0.0/tests/test_meta_tables_sqlalchemy_contracts.py +0 -209
- mainsequence-4.0.0/tests/test_pod_project_resolution.py +0 -98
- {mainsequence-4.0.0 → mainsequence-4.0.5}/LICENSE +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/README.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/AGENTS.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/a2a_communication/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/application_surfaces/api_surfaces/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/command_center/adapter_from_api/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/command_center/api_mock_prototyping/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/command_center/app_components/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/command_center/connections/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/command_center/workspace_analysis/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/command_center/workspace_builder/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/command_center/workspace_design/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/dashboards/streamlit/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/data_access/exploration/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/data_publishing/data_nodes/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/maintenance/bug_auditor/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/maintenance/local_journal/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/platform_operations/access_control_and_sharing/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/platform_operations/orchestration_and_releases/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/project_builder/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/project_to_agent/SKILL.md +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/__init__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/__main__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/browser_auth.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/cli/ui.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/agent_runtime_models.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/base.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/client.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/command_center/__init__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/command_center/app_component.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/command_center/connections.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/command_center/data_models.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/command_center/workspace.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/command_center/workspace_snapshot.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/fastapi/__init__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/fastapi/auth.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/models_metatables.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/client/models_user.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/compute_validation.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/defaults.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/logconf.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/__init__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/__main__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/base_persist_managers.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/config.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/configuration_models.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/data_nodes/__init__.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/data_nodes/data_nodes.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/data_nodes/filters.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/data_nodes/models.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/data_nodes/namespacing.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/data_nodes/persist_managers.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/data_nodes/run_operations.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/data_nodes/utils.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/filters.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/future_registry.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/meta_tables/compiled_sql.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/pydantic_metadata.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence/tdag/utils.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/setup.cfg +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_auth_precedence.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_build_operations_hashing.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_cli_browser_auth.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_client.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_command_center_app_component_models.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_command_center_data_models.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_command_center_models.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_data_access_mixin_dimension_audit.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_data_node_search_join_filters.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_data_node_storage_dimension_queries.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_dependency_extras.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_filter_normalization.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_logconf.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_meta_tables_client_models.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_models_user_request_bound_auth.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_project_batch_jobs_from_file.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_run_configuration.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_source_table_configuration.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_update_runner_uid_runtime.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_update_statistics.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_update_uid_guards.py +0 -0
- {mainsequence-4.0.0 → mainsequence-4.0.5}/tests/test_workspace_snapshot.py +0 -0
{mainsequence-4.0.0 → mainsequence-4.0.5}/agent_scaffold/skills/data_publishing/meta_tables/SKILL.md
RENAMED
|
@@ -15,7 +15,8 @@ This skill is for schema-driven application tables registered through TS Manager
|
|
|
15
15
|
|
|
16
16
|
- define SQLAlchemy/Core or ORM table models for `MetaTable` registration
|
|
17
17
|
- choose `platform_managed` or `external_registered` management mode
|
|
18
|
-
-
|
|
18
|
+
- register platform-managed tables through the model class API
|
|
19
|
+
- build registration requests from resolved SQLAlchemy metadata when inspection is useful
|
|
19
20
|
- define indexes and foreign keys in the table contract
|
|
20
21
|
- design governed compiled SQL read and write operations
|
|
21
22
|
- review table contracts for physical-name, namespace, and identifier issues
|
|
@@ -67,7 +68,7 @@ Before changing code, collect or infer:
|
|
|
67
68
|
- expected read patterns
|
|
68
69
|
- expected mutation patterns
|
|
69
70
|
- whether TS Manager should create the physical table
|
|
70
|
-
- the target `DynamicTableDataSource` UID
|
|
71
|
+
- for `external_registered`, the target `DynamicTableDataSource` UID
|
|
71
72
|
|
|
72
73
|
If ownership of the physical table lifecycle is unclear, stop before choosing a management mode.
|
|
73
74
|
|
|
@@ -92,15 +93,67 @@ Do not hand-build contract fragments when the SQLAlchemy helper can derive them.
|
|
|
92
93
|
|
|
93
94
|
### 2. Use storage-hash physical names for backend-managed tables
|
|
94
95
|
|
|
95
|
-
For `platform_managed`,
|
|
96
|
+
For `platform_managed`, inherit from `PlatformManagedMetaTable`.
|
|
96
97
|
|
|
97
|
-
The
|
|
98
|
+
The mixin derives the SQLAlchemy physical table name from storage-relevant configuration and table shape. Do not hand-write `__tablename__` for normal backend-managed tables.
|
|
99
|
+
|
|
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
|
+
|
|
102
|
+
Register through the class API:
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
account_meta_table = Account.register(
|
|
106
|
+
description="Example account table.",
|
|
107
|
+
labels=["sdk-example"],
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
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
|
+
|
|
113
|
+
Only call `build_registration_request()` when the task explicitly needs to inspect or validate the payload before registration.
|
|
114
|
+
|
|
115
|
+
For SDK examples, use a plain namespace constant:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
NAMESPACE = "sdk-examples"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Do not add an environment variable for namespace in examples.
|
|
122
|
+
|
|
123
|
+
Do not add generic labels such as `"meta-table"` or `"platform-managed"` to examples. Keep labels specific to the example or domain.
|
|
124
|
+
|
|
125
|
+
Do not add a `MAINSEQUENCE_META_TABLE_REGISTER` toggle in registration examples. Registration examples should register directly.
|
|
98
126
|
|
|
99
127
|
### 3. Register parent tables before child tables
|
|
100
128
|
|
|
101
129
|
Foreign-key contracts reference the target `MetaTable` UID.
|
|
102
130
|
|
|
103
|
-
|
|
131
|
+
For `PlatformManagedMetaTable`, register parent tables first and then register child tables normally. The SDK inspects SQLAlchemy foreign-key constraints and resolves each target `MetaTable` by looking up the already registered table in the same data source, schema, and physical table name.
|
|
132
|
+
|
|
133
|
+
Example registration order:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
account_meta_table = Account.register(...)
|
|
137
|
+
asset_meta_table = Asset.register(...)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The child registration will fail if the parent table has not already been registered, because there is no target `MetaTable.uid` for the backend FK contract.
|
|
141
|
+
|
|
142
|
+
Do not pass `target_meta_tables` or `target_meta_table_uid_by_fullname` in the normal platform-managed path. Use explicit FK target mappings only for edge cases where automatic lookup is ambiguous or impossible.
|
|
143
|
+
|
|
144
|
+
For `external_registered`, there is no platform-managed parent lookup through the model class. Register the parent first, then build the child registration request with the parent UID mapped by target table fullname:
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
account_meta_table = MetaTable.register(account_request)
|
|
148
|
+
asset_request = external_registered_registration_request_from_sqlalchemy_model(
|
|
149
|
+
Asset,
|
|
150
|
+
data_source_uid=data_source_uid,
|
|
151
|
+
target_meta_table_uid_by_fullname={
|
|
152
|
+
Account.__table__.fullname: account_meta_table.uid,
|
|
153
|
+
},
|
|
154
|
+
)
|
|
155
|
+
asset_meta_table = MetaTable.register(asset_request)
|
|
156
|
+
```
|
|
104
157
|
|
|
105
158
|
### 4. Governed operations declare scope
|
|
106
159
|
|
|
@@ -119,9 +172,12 @@ Do not hardcode platform-managed physical names manually.
|
|
|
119
172
|
When reviewing an existing MetaTable workflow, look for:
|
|
120
173
|
|
|
121
174
|
- missing namespace or identifier
|
|
122
|
-
- backend-managed models that do not
|
|
175
|
+
- backend-managed models that do not inherit `PlatformManagedMetaTable`
|
|
176
|
+
- backend-managed examples that use namespace environment variables instead of a plain `sdk-examples` namespace
|
|
177
|
+
- duplicate schema sources outside SQLAlchemy table metadata
|
|
123
178
|
- external tables registered with unstable physical names
|
|
124
|
-
-
|
|
179
|
+
- platform-managed child tables that are registered before parent tables
|
|
180
|
+
- external child registrations that do not map foreign-key targets to registered parent `MetaTable.uid` values
|
|
125
181
|
- compiled SQL operations without complete table scope
|
|
126
182
|
- raw SQL that hardcodes stale physical names
|
|
127
183
|
- a table that should really be modeled as a DataNode instead
|
|
@@ -132,7 +188,7 @@ Do not claim success until you have checked:
|
|
|
132
188
|
|
|
133
189
|
- the table contract matches the intended row contract
|
|
134
190
|
- indexes are intentional
|
|
135
|
-
- foreign keys
|
|
191
|
+
- foreign keys resolve to the correct dependency targets
|
|
136
192
|
- management mode is correct
|
|
137
193
|
- backend-managed physical names match the storage hash
|
|
138
194
|
- registration returns a `MetaTable.uid`
|
|
@@ -141,13 +197,14 @@ Do not claim success until you have checked:
|
|
|
141
197
|
For related tables, also check:
|
|
142
198
|
|
|
143
199
|
- aliases are readable
|
|
144
|
-
- parent
|
|
200
|
+
- platform-managed parent tables are registered before child tables
|
|
201
|
+
- external child registration requests map FK targets to the registered parent UIDs
|
|
145
202
|
- query results still match the expected response contract
|
|
146
203
|
|
|
147
204
|
## This Skill Must Stop And Escalate When
|
|
148
205
|
|
|
149
206
|
- physical table lifecycle ownership is unclear
|
|
150
|
-
- the target data source is unknown
|
|
207
|
+
- the target data source is unknown for an `external_registered` workflow
|
|
151
208
|
- the task really requires a time-series published table
|
|
152
209
|
- the workflow requires direct database credentials outside TS Manager governance
|
|
153
210
|
- the task is actually an API or orchestration problem
|
|
@@ -20,7 +20,7 @@ def _read_local_env_values(env_path: pathlib.Path) -> dict[str, str]:
|
|
|
20
20
|
return {}
|
|
21
21
|
|
|
22
22
|
values: dict[str, str] = {}
|
|
23
|
-
for key in ("MAINSEQUENCE_ENDPOINT", "MAIN_SEQUENCE_PROJECT_ID"):
|
|
23
|
+
for key in ("MAINSEQUENCE_ENDPOINT", "MAIN_SEQUENCE_PROJECT_UID", "MAIN_SEQUENCE_PROJECT_ID"):
|
|
24
24
|
match = re.search(rf"(?m)^{re.escape(key)}=(.+?)\s*$", content)
|
|
25
25
|
if match:
|
|
26
26
|
values[key] = match.group(1).strip()
|
|
@@ -35,6 +35,7 @@ def prime_runtime_env() -> None:
|
|
|
35
35
|
local_values = _read_local_env_values(pathlib.Path.cwd() / ".env")
|
|
36
36
|
|
|
37
37
|
_set_if_missing("MAINSEQUENCE_ENDPOINT", local_values.get("MAINSEQUENCE_ENDPOINT"))
|
|
38
|
+
_set_if_missing("MAIN_SEQUENCE_PROJECT_UID", local_values.get("MAIN_SEQUENCE_PROJECT_UID"))
|
|
38
39
|
_set_if_missing("MAIN_SEQUENCE_PROJECT_ID", local_values.get("MAIN_SEQUENCE_PROJECT_ID"))
|
|
39
40
|
|
|
40
41
|
try:
|
|
@@ -432,6 +432,7 @@ def _run_sdk_model_operation(
|
|
|
432
432
|
class_name: str,
|
|
433
433
|
operation,
|
|
434
434
|
project_id_env: int | str | None = None,
|
|
435
|
+
project_uid_env: str | None = None,
|
|
435
436
|
):
|
|
436
437
|
tokens = get_tokens()
|
|
437
438
|
access = (tokens.get("access") or "").strip()
|
|
@@ -447,6 +448,7 @@ def _run_sdk_model_operation(
|
|
|
447
448
|
"MAINSEQUENCE_ACCESS_TOKEN": os.environ.get("MAINSEQUENCE_ACCESS_TOKEN"),
|
|
448
449
|
"MAINSEQUENCE_REFRESH_TOKEN": os.environ.get("MAINSEQUENCE_REFRESH_TOKEN"),
|
|
449
450
|
"MAINSEQUENCE_ENDPOINT": os.environ.get("MAINSEQUENCE_ENDPOINT"),
|
|
451
|
+
"MAIN_SEQUENCE_PROJECT_UID": os.environ.get("MAIN_SEQUENCE_PROJECT_UID"),
|
|
450
452
|
"MAIN_SEQUENCE_PROJECT_ID": os.environ.get("MAIN_SEQUENCE_PROJECT_ID"),
|
|
451
453
|
}
|
|
452
454
|
|
|
@@ -464,6 +466,12 @@ def _run_sdk_model_operation(
|
|
|
464
466
|
else:
|
|
465
467
|
os.environ.pop("MAINSEQUENCE_REFRESH_TOKEN", None)
|
|
466
468
|
os.environ["MAINSEQUENCE_ENDPOINT"] = endpoint
|
|
469
|
+
if project_uid_env is not None:
|
|
470
|
+
os.environ["MAIN_SEQUENCE_PROJECT_UID"] = str(project_uid_env)
|
|
471
|
+
elif project_id_env is not None and not str(project_id_env).strip().isdigit():
|
|
472
|
+
os.environ["MAIN_SEQUENCE_PROJECT_UID"] = str(project_id_env)
|
|
473
|
+
else:
|
|
474
|
+
os.environ.pop("MAIN_SEQUENCE_PROJECT_UID", None)
|
|
467
475
|
if project_id_env is not None:
|
|
468
476
|
os.environ["MAIN_SEQUENCE_PROJECT_ID"] = str(project_id_env)
|
|
469
477
|
else:
|
|
@@ -521,20 +529,30 @@ def _run_sdk_model_operation(
|
|
|
521
529
|
|
|
522
530
|
def get_current_user_profile() -> dict:
|
|
523
531
|
"""
|
|
524
|
-
Return current user profile (username + organization name) via
|
|
532
|
+
Return current user profile (username + organization name) via the canonical user-details endpoint.
|
|
525
533
|
|
|
526
534
|
Returns:
|
|
527
535
|
dict: {"username": "...", "organization": "..."} or {}
|
|
528
536
|
"""
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
if not
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
537
|
+
details = authed("GET", "/user/api/user/get_user_details/")
|
|
538
|
+
payload = details.json() if details.ok else {}
|
|
539
|
+
user = payload.get("user") if isinstance(payload, dict) else {}
|
|
540
|
+
if not isinstance(user, dict):
|
|
541
|
+
user = {}
|
|
542
|
+
organization = user.get("organization") if isinstance(user, dict) else {}
|
|
543
|
+
if not isinstance(organization, dict):
|
|
544
|
+
organization = {}
|
|
545
|
+
payload_organization = payload.get("organization") if isinstance(payload, dict) else {}
|
|
546
|
+
if not isinstance(payload_organization, dict):
|
|
547
|
+
payload_organization = {}
|
|
548
|
+
org_name = (
|
|
549
|
+
organization.get("name")
|
|
550
|
+
or payload_organization.get("name")
|
|
551
|
+
or payload.get("organization_name")
|
|
552
|
+
or payload.get("organization")
|
|
553
|
+
or ""
|
|
554
|
+
)
|
|
555
|
+
return {"username": user.get("username") or payload.get("username") or "", "organization": org_name}
|
|
538
556
|
|
|
539
557
|
|
|
540
558
|
def get_logged_user_details() -> dict[str, Any]:
|
|
@@ -676,6 +694,65 @@ def get_projects() -> list[dict]:
|
|
|
676
694
|
return data.get("results") or []
|
|
677
695
|
|
|
678
696
|
|
|
697
|
+
def _normalize_project_reference(project_ref: int | str) -> str:
|
|
698
|
+
normalized = str(project_ref).strip()
|
|
699
|
+
if not normalized:
|
|
700
|
+
raise ApiError("Project UID is required.")
|
|
701
|
+
return normalized
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
def _project_matches_reference(project_payload: dict[str, Any], project_ref: str) -> bool:
|
|
705
|
+
return (
|
|
706
|
+
str(project_payload.get("uid") or "").strip() == project_ref
|
|
707
|
+
or str(project_payload.get("id") or "").strip() == project_ref
|
|
708
|
+
)
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
def resolve_project(project_ref: int | str) -> dict[str, Any]:
|
|
712
|
+
normalized_ref = _normalize_project_reference(project_ref)
|
|
713
|
+
|
|
714
|
+
try:
|
|
715
|
+
payload = get_project(normalized_ref)
|
|
716
|
+
if isinstance(payload, dict) and payload:
|
|
717
|
+
return payload
|
|
718
|
+
except ApiError:
|
|
719
|
+
pass
|
|
720
|
+
|
|
721
|
+
for project_payload in get_projects():
|
|
722
|
+
if isinstance(project_payload, dict) and _project_matches_reference(project_payload, normalized_ref):
|
|
723
|
+
return project_payload
|
|
724
|
+
|
|
725
|
+
raise ApiError(f"Project not found: {normalized_ref}")
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
def resolve_project_uid(project_ref: int | str) -> str:
|
|
729
|
+
normalized_ref = _normalize_project_reference(project_ref)
|
|
730
|
+
if normalized_ref.isdigit():
|
|
731
|
+
return normalized_ref
|
|
732
|
+
|
|
733
|
+
payload = resolve_project(project_ref)
|
|
734
|
+
normalized_uid = str(payload.get("uid") or "").strip()
|
|
735
|
+
if normalized_uid:
|
|
736
|
+
return normalized_uid
|
|
737
|
+
if not normalized_ref.isdigit():
|
|
738
|
+
return normalized_ref
|
|
739
|
+
raise ApiError(f"Project UID is not available for project reference: {normalized_ref}")
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
def resolve_project_row_id(project_ref: int | str) -> int:
|
|
743
|
+
normalized_ref = _normalize_project_reference(project_ref)
|
|
744
|
+
if normalized_ref.isdigit():
|
|
745
|
+
return int(normalized_ref)
|
|
746
|
+
|
|
747
|
+
payload = resolve_project(project_ref)
|
|
748
|
+
row_id = payload.get("id")
|
|
749
|
+
if row_id is None:
|
|
750
|
+
if normalized_ref.isdigit():
|
|
751
|
+
return int(normalized_ref)
|
|
752
|
+
raise ApiError(f"Backend row id is not available for project reference: {normalized_ref}")
|
|
753
|
+
return int(row_id)
|
|
754
|
+
|
|
755
|
+
|
|
679
756
|
def search_projects(
|
|
680
757
|
q: str,
|
|
681
758
|
*,
|
|
@@ -1395,7 +1472,7 @@ def get_agent_run(
|
|
|
1395
1472
|
|
|
1396
1473
|
def get_project(project_id: int | str) -> dict:
|
|
1397
1474
|
"""
|
|
1398
|
-
Fetch a single project by
|
|
1475
|
+
Fetch a single project by public reference.
|
|
1399
1476
|
"""
|
|
1400
1477
|
r = authed("GET", f"/orm/api/pods/projects/{project_id}/")
|
|
1401
1478
|
if not r.ok:
|
|
@@ -1748,6 +1825,7 @@ def get_project_data_node_updates(project_id: int | str, *, timeout: int | None
|
|
|
1748
1825
|
"MAINSEQUENCE_ACCESS_TOKEN": os.environ.get("MAINSEQUENCE_ACCESS_TOKEN"),
|
|
1749
1826
|
"MAINSEQUENCE_REFRESH_TOKEN": os.environ.get("MAINSEQUENCE_REFRESH_TOKEN"),
|
|
1750
1827
|
"MAINSEQUENCE_ENDPOINT": os.environ.get("MAINSEQUENCE_ENDPOINT"),
|
|
1828
|
+
"MAIN_SEQUENCE_PROJECT_UID": os.environ.get("MAIN_SEQUENCE_PROJECT_UID"),
|
|
1751
1829
|
"MAIN_SEQUENCE_PROJECT_ID": os.environ.get("MAIN_SEQUENCE_PROJECT_ID"),
|
|
1752
1830
|
}
|
|
1753
1831
|
|
|
@@ -1765,7 +1843,10 @@ def get_project_data_node_updates(project_id: int | str, *, timeout: int | None
|
|
|
1765
1843
|
else:
|
|
1766
1844
|
os.environ.pop("MAINSEQUENCE_REFRESH_TOKEN", None)
|
|
1767
1845
|
os.environ["MAINSEQUENCE_ENDPOINT"] = endpoint
|
|
1768
|
-
|
|
1846
|
+
project_uid = resolve_project_uid(project_id)
|
|
1847
|
+
project_row_id = resolve_project_row_id(project_id)
|
|
1848
|
+
os.environ["MAIN_SEQUENCE_PROJECT_UID"] = project_uid
|
|
1849
|
+
os.environ["MAIN_SEQUENCE_PROJECT_ID"] = str(project_row_id)
|
|
1769
1850
|
|
|
1770
1851
|
from mainsequence.client import utils as _client_utils
|
|
1771
1852
|
from mainsequence.client.base import BaseObjectOrm
|
|
@@ -1782,7 +1863,7 @@ def get_project_data_node_updates(project_id: int | str, *, timeout: int | None
|
|
|
1782
1863
|
BaseObjectOrm.ROOT_URL = root_url
|
|
1783
1864
|
ClientProject.ROOT_URL = root_url
|
|
1784
1865
|
|
|
1785
|
-
project = ClientProject.get(pk=
|
|
1866
|
+
project = ClientProject.get(pk=project_uid, timeout=timeout)
|
|
1786
1867
|
updates = project.get_data_nodes_updates(timeout=timeout)
|
|
1787
1868
|
|
|
1788
1869
|
out: list[dict[str, Any]] = []
|
|
@@ -1839,14 +1920,16 @@ def sync_project_after_commit(project_id: int | str, *, timeout: int | None = No
|
|
|
1839
1920
|
- delegates request behavior and payload parsing to `Project.sync_project_after_commit()`
|
|
1840
1921
|
"""
|
|
1841
1922
|
try:
|
|
1923
|
+
project_uid = resolve_project_uid(project_id)
|
|
1842
1924
|
payload = _run_sdk_model_operation(
|
|
1843
1925
|
module_name="mainsequence.client.models_tdag",
|
|
1844
1926
|
class_name="Project",
|
|
1845
1927
|
operation=lambda ClientProject: ClientProject.sync_project_after_commit(
|
|
1846
|
-
|
|
1928
|
+
project_uid,
|
|
1847
1929
|
timeout=timeout,
|
|
1848
1930
|
),
|
|
1849
|
-
project_id_env=project_id,
|
|
1931
|
+
project_id_env=resolve_project_row_id(project_id),
|
|
1932
|
+
project_uid_env=project_uid,
|
|
1850
1933
|
)
|
|
1851
1934
|
if payload is None:
|
|
1852
1935
|
return None
|
|
@@ -1911,6 +1994,7 @@ def create_project_image(
|
|
|
1911
1994
|
"MAINSEQUENCE_ACCESS_TOKEN": os.environ.get("MAINSEQUENCE_ACCESS_TOKEN"),
|
|
1912
1995
|
"MAINSEQUENCE_REFRESH_TOKEN": os.environ.get("MAINSEQUENCE_REFRESH_TOKEN"),
|
|
1913
1996
|
"MAINSEQUENCE_ENDPOINT": os.environ.get("MAINSEQUENCE_ENDPOINT"),
|
|
1997
|
+
"MAIN_SEQUENCE_PROJECT_UID": os.environ.get("MAIN_SEQUENCE_PROJECT_UID"),
|
|
1914
1998
|
"MAIN_SEQUENCE_PROJECT_ID": os.environ.get("MAIN_SEQUENCE_PROJECT_ID"),
|
|
1915
1999
|
}
|
|
1916
2000
|
|
|
@@ -1927,7 +2011,10 @@ def create_project_image(
|
|
|
1927
2011
|
else:
|
|
1928
2012
|
os.environ.pop("MAINSEQUENCE_REFRESH_TOKEN", None)
|
|
1929
2013
|
os.environ["MAINSEQUENCE_ENDPOINT"] = endpoint
|
|
1930
|
-
|
|
2014
|
+
project_uid = resolve_project_uid(related_project_id)
|
|
2015
|
+
project_row_id = resolve_project_row_id(related_project_id)
|
|
2016
|
+
os.environ["MAIN_SEQUENCE_PROJECT_UID"] = project_uid
|
|
2017
|
+
os.environ["MAIN_SEQUENCE_PROJECT_ID"] = str(project_row_id)
|
|
1931
2018
|
|
|
1932
2019
|
from mainsequence.client import utils as _client_utils
|
|
1933
2020
|
from mainsequence.client.base import BaseObjectOrm
|
|
@@ -1946,7 +2033,7 @@ def create_project_image(
|
|
|
1946
2033
|
|
|
1947
2034
|
created = ClientProjectImage.create(
|
|
1948
2035
|
project_repo_hash=project_repo_hash,
|
|
1949
|
-
related_project_id=
|
|
2036
|
+
related_project_id=project_row_id,
|
|
1950
2037
|
base_image_id=base_image_id,
|
|
1951
2038
|
timeout=timeout,
|
|
1952
2039
|
)
|
|
@@ -2018,6 +2105,7 @@ def list_project_images(
|
|
|
2018
2105
|
"MAINSEQUENCE_ACCESS_TOKEN": os.environ.get("MAINSEQUENCE_ACCESS_TOKEN"),
|
|
2019
2106
|
"MAINSEQUENCE_REFRESH_TOKEN": os.environ.get("MAINSEQUENCE_REFRESH_TOKEN"),
|
|
2020
2107
|
"MAINSEQUENCE_ENDPOINT": os.environ.get("MAINSEQUENCE_ENDPOINT"),
|
|
2108
|
+
"MAIN_SEQUENCE_PROJECT_UID": os.environ.get("MAIN_SEQUENCE_PROJECT_UID"),
|
|
2021
2109
|
"MAIN_SEQUENCE_PROJECT_ID": os.environ.get("MAIN_SEQUENCE_PROJECT_ID"),
|
|
2022
2110
|
}
|
|
2023
2111
|
|
|
@@ -2034,7 +2122,10 @@ def list_project_images(
|
|
|
2034
2122
|
else:
|
|
2035
2123
|
os.environ.pop("MAINSEQUENCE_REFRESH_TOKEN", None)
|
|
2036
2124
|
os.environ["MAINSEQUENCE_ENDPOINT"] = endpoint
|
|
2037
|
-
|
|
2125
|
+
project_uid = resolve_project_uid(related_project_id)
|
|
2126
|
+
project_row_id = resolve_project_row_id(related_project_id)
|
|
2127
|
+
os.environ["MAIN_SEQUENCE_PROJECT_UID"] = project_uid
|
|
2128
|
+
os.environ["MAIN_SEQUENCE_PROJECT_ID"] = str(project_row_id)
|
|
2038
2129
|
|
|
2039
2130
|
from mainsequence.client import utils as _client_utils
|
|
2040
2131
|
from mainsequence.client.base import BaseObjectOrm
|
|
@@ -2052,7 +2143,7 @@ def list_project_images(
|
|
|
2052
2143
|
ClientProjectImage.ROOT_URL = root_url
|
|
2053
2144
|
|
|
2054
2145
|
merged_filters = dict(filters or {})
|
|
2055
|
-
merged_filters["related_project__id__in"] = [
|
|
2146
|
+
merged_filters["related_project__id__in"] = [project_row_id]
|
|
2056
2147
|
images = ClientProjectImage.filter(timeout=timeout, **merged_filters)
|
|
2057
2148
|
|
|
2058
2149
|
out: list[dict[str, Any]] = []
|
|
@@ -2243,6 +2334,7 @@ def list_project_jobs(
|
|
|
2243
2334
|
"MAINSEQUENCE_ACCESS_TOKEN": os.environ.get("MAINSEQUENCE_ACCESS_TOKEN"),
|
|
2244
2335
|
"MAINSEQUENCE_REFRESH_TOKEN": os.environ.get("MAINSEQUENCE_REFRESH_TOKEN"),
|
|
2245
2336
|
"MAINSEQUENCE_ENDPOINT": os.environ.get("MAINSEQUENCE_ENDPOINT"),
|
|
2337
|
+
"MAIN_SEQUENCE_PROJECT_UID": os.environ.get("MAIN_SEQUENCE_PROJECT_UID"),
|
|
2246
2338
|
"MAIN_SEQUENCE_PROJECT_ID": os.environ.get("MAIN_SEQUENCE_PROJECT_ID"),
|
|
2247
2339
|
}
|
|
2248
2340
|
|
|
@@ -2259,7 +2351,10 @@ def list_project_jobs(
|
|
|
2259
2351
|
else:
|
|
2260
2352
|
os.environ.pop("MAINSEQUENCE_REFRESH_TOKEN", None)
|
|
2261
2353
|
os.environ["MAINSEQUENCE_ENDPOINT"] = endpoint
|
|
2262
|
-
|
|
2354
|
+
project_uid = resolve_project_uid(project_id)
|
|
2355
|
+
project_row_id = resolve_project_row_id(project_id)
|
|
2356
|
+
os.environ["MAIN_SEQUENCE_PROJECT_UID"] = project_uid
|
|
2357
|
+
os.environ["MAIN_SEQUENCE_PROJECT_ID"] = str(project_row_id)
|
|
2263
2358
|
|
|
2264
2359
|
from mainsequence.client import utils as _client_utils
|
|
2265
2360
|
from mainsequence.client.base import BaseObjectOrm
|
|
@@ -2279,7 +2374,7 @@ def list_project_jobs(
|
|
|
2279
2374
|
extra_filters = dict(filters or {})
|
|
2280
2375
|
jobs = ClientJob.filter(
|
|
2281
2376
|
timeout=timeout,
|
|
2282
|
-
**{**extra_filters, "project__id":
|
|
2377
|
+
**{**extra_filters, "project__id": project_row_id},
|
|
2283
2378
|
)
|
|
2284
2379
|
|
|
2285
2380
|
out: list[dict[str, Any]] = []
|
|
@@ -2355,6 +2450,7 @@ def list_project_resources(
|
|
|
2355
2450
|
"MAINSEQUENCE_ACCESS_TOKEN": os.environ.get("MAINSEQUENCE_ACCESS_TOKEN"),
|
|
2356
2451
|
"MAINSEQUENCE_REFRESH_TOKEN": os.environ.get("MAINSEQUENCE_REFRESH_TOKEN"),
|
|
2357
2452
|
"MAINSEQUENCE_ENDPOINT": os.environ.get("MAINSEQUENCE_ENDPOINT"),
|
|
2453
|
+
"MAIN_SEQUENCE_PROJECT_UID": os.environ.get("MAIN_SEQUENCE_PROJECT_UID"),
|
|
2358
2454
|
"MAIN_SEQUENCE_PROJECT_ID": os.environ.get("MAIN_SEQUENCE_PROJECT_ID"),
|
|
2359
2455
|
}
|
|
2360
2456
|
|
|
@@ -2371,7 +2467,10 @@ def list_project_resources(
|
|
|
2371
2467
|
else:
|
|
2372
2468
|
os.environ.pop("MAINSEQUENCE_REFRESH_TOKEN", None)
|
|
2373
2469
|
os.environ["MAINSEQUENCE_ENDPOINT"] = endpoint
|
|
2374
|
-
|
|
2470
|
+
project_uid = resolve_project_uid(project_id)
|
|
2471
|
+
project_row_id = resolve_project_row_id(project_id)
|
|
2472
|
+
os.environ["MAIN_SEQUENCE_PROJECT_UID"] = project_uid
|
|
2473
|
+
os.environ["MAIN_SEQUENCE_PROJECT_ID"] = str(project_row_id)
|
|
2375
2474
|
|
|
2376
2475
|
from mainsequence.client import utils as _client_utils
|
|
2377
2476
|
from mainsequence.client.base import BaseObjectOrm
|
|
@@ -2391,7 +2490,7 @@ def list_project_resources(
|
|
|
2391
2490
|
merged_filters: dict[str, Any] = dict(filters or {})
|
|
2392
2491
|
merged_filters.update(
|
|
2393
2492
|
{
|
|
2394
|
-
"project__id":
|
|
2493
|
+
"project__id": project_row_id,
|
|
2395
2494
|
"repo_commit_sha": str(repo_commit_sha).strip(),
|
|
2396
2495
|
}
|
|
2397
2496
|
)
|
|
@@ -4210,6 +4309,7 @@ def create_project_job(
|
|
|
4210
4309
|
"MAINSEQUENCE_ACCESS_TOKEN": os.environ.get("MAINSEQUENCE_ACCESS_TOKEN"),
|
|
4211
4310
|
"MAINSEQUENCE_REFRESH_TOKEN": os.environ.get("MAINSEQUENCE_REFRESH_TOKEN"),
|
|
4212
4311
|
"MAINSEQUENCE_ENDPOINT": os.environ.get("MAINSEQUENCE_ENDPOINT"),
|
|
4312
|
+
"MAIN_SEQUENCE_PROJECT_UID": os.environ.get("MAIN_SEQUENCE_PROJECT_UID"),
|
|
4213
4313
|
"MAIN_SEQUENCE_PROJECT_ID": os.environ.get("MAIN_SEQUENCE_PROJECT_ID"),
|
|
4214
4314
|
}
|
|
4215
4315
|
|
|
@@ -4226,7 +4326,10 @@ def create_project_job(
|
|
|
4226
4326
|
else:
|
|
4227
4327
|
os.environ.pop("MAINSEQUENCE_REFRESH_TOKEN", None)
|
|
4228
4328
|
os.environ["MAINSEQUENCE_ENDPOINT"] = endpoint
|
|
4229
|
-
|
|
4329
|
+
project_uid = resolve_project_uid(project_id)
|
|
4330
|
+
project_row_id = resolve_project_row_id(project_id)
|
|
4331
|
+
os.environ["MAIN_SEQUENCE_PROJECT_UID"] = project_uid
|
|
4332
|
+
os.environ["MAIN_SEQUENCE_PROJECT_ID"] = str(project_row_id)
|
|
4230
4333
|
|
|
4231
4334
|
from mainsequence.client import utils as _client_utils
|
|
4232
4335
|
from mainsequence.client.base import BaseObjectOrm
|
|
@@ -4245,7 +4348,7 @@ def create_project_job(
|
|
|
4245
4348
|
|
|
4246
4349
|
created = ClientJob.create(
|
|
4247
4350
|
name=name,
|
|
4248
|
-
project_id=
|
|
4351
|
+
project_id=project_row_id,
|
|
4249
4352
|
execution_path=execution_path,
|
|
4250
4353
|
app_name=app_name,
|
|
4251
4354
|
task_schedule=task_schedule,
|
|
@@ -4331,6 +4434,7 @@ def schedule_batch_project_jobs(
|
|
|
4331
4434
|
"MAINSEQUENCE_ACCESS_TOKEN": os.environ.get("MAINSEQUENCE_ACCESS_TOKEN"),
|
|
4332
4435
|
"MAINSEQUENCE_REFRESH_TOKEN": os.environ.get("MAINSEQUENCE_REFRESH_TOKEN"),
|
|
4333
4436
|
"MAINSEQUENCE_ENDPOINT": os.environ.get("MAINSEQUENCE_ENDPOINT"),
|
|
4437
|
+
"MAIN_SEQUENCE_PROJECT_UID": os.environ.get("MAIN_SEQUENCE_PROJECT_UID"),
|
|
4334
4438
|
"MAIN_SEQUENCE_PROJECT_ID": os.environ.get("MAIN_SEQUENCE_PROJECT_ID"),
|
|
4335
4439
|
}
|
|
4336
4440
|
|
|
@@ -4347,7 +4451,10 @@ def schedule_batch_project_jobs(
|
|
|
4347
4451
|
else:
|
|
4348
4452
|
os.environ.pop("MAINSEQUENCE_REFRESH_TOKEN", None)
|
|
4349
4453
|
os.environ["MAINSEQUENCE_ENDPOINT"] = endpoint
|
|
4350
|
-
|
|
4454
|
+
project_uid = resolve_project_uid(project_id)
|
|
4455
|
+
project_row_id = resolve_project_row_id(project_id)
|
|
4456
|
+
os.environ["MAIN_SEQUENCE_PROJECT_UID"] = project_uid
|
|
4457
|
+
os.environ["MAIN_SEQUENCE_PROJECT_ID"] = str(project_row_id)
|
|
4351
4458
|
|
|
4352
4459
|
from mainsequence.client import utils as _client_utils
|
|
4353
4460
|
from mainsequence.client.base import BaseObjectOrm
|
|
@@ -4366,7 +4473,7 @@ def schedule_batch_project_jobs(
|
|
|
4366
4473
|
|
|
4367
4474
|
created = ClientJob.bulk_get_or_create(
|
|
4368
4475
|
yaml_file=file_path,
|
|
4369
|
-
project_id=
|
|
4476
|
+
project_id=project_row_id,
|
|
4370
4477
|
strict=bool(strict),
|
|
4371
4478
|
timeout=timeout,
|
|
4372
4479
|
)
|
|
@@ -4866,13 +4973,14 @@ def create_project(
|
|
|
4866
4973
|
|
|
4867
4974
|
def delete_project(project_id: int | str, *, delete_repositories: bool = False) -> dict[str, Any] | None:
|
|
4868
4975
|
"""
|
|
4869
|
-
Delete a project by
|
|
4976
|
+
Delete a project by public reference.
|
|
4870
4977
|
|
|
4871
4978
|
Mirrors backend behavior:
|
|
4872
|
-
- DELETE /orm/api/pods/projects/{
|
|
4979
|
+
- DELETE /orm/api/pods/projects/{uid}/
|
|
4873
4980
|
- optional query param delete_repositories=true
|
|
4874
4981
|
"""
|
|
4875
|
-
|
|
4982
|
+
project_uid = resolve_project_uid(project_id)
|
|
4983
|
+
path = f"/orm/api/pods/projects/{project_uid}/"
|
|
4876
4984
|
if delete_repositories:
|
|
4877
4985
|
path = f"{path}?delete_repositories=true"
|
|
4878
4986
|
|
|
@@ -4942,7 +5050,7 @@ def add_deploy_key(project_id: int | str, key_title: str, public_key: str) -> No
|
|
|
4942
5050
|
"""
|
|
4943
5051
|
r = authed(
|
|
4944
5052
|
"POST",
|
|
4945
|
-
f"/orm/api/pods/projects/{project_id}/add_deploy_key/",
|
|
5053
|
+
f"/orm/api/pods/projects/{resolve_project_uid(project_id)}/add_deploy_key/",
|
|
4946
5054
|
{"key_title": key_title, "public_key": public_key},
|
|
4947
5055
|
)
|
|
4948
5056
|
r.raise_for_status()
|