mainsequence 3.16.0__tar.gz → 3.17.0__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-3.16.0 → mainsequence-3.17.0}/PKG-INFO +1 -1
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/api.py +83 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/cli.py +170 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/__init__.py +1 -1
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/base.py +54 -8
- mainsequence-3.17.0/mainsequence/client/models_simple_tables.py +1107 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/models_tdag.py +144 -126
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/models_user.py +0 -1
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/utils.py +38 -16
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/logconf.py +11 -7
- mainsequence-3.17.0/mainsequence/tdag/__init__.py +38 -0
- mainsequence-3.17.0/mainsequence/tdag/base_persist_managers.py +545 -0
- mainsequence-3.17.0/mainsequence/tdag/configuration_models.py +23 -0
- mainsequence-3.17.0/mainsequence/tdag/data_nodes/__init__.py +31 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/data_nodes/build_operations.py +23 -105
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/data_nodes/data_nodes.py +143 -161
- mainsequence-3.17.0/mainsequence/tdag/data_nodes/filters.py +72 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/data_nodes/models.py +3 -11
- mainsequence-3.17.0/mainsequence/tdag/data_nodes/persist_managers.py +114 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/data_nodes/run_operations.py +74 -79
- mainsequence-3.17.0/mainsequence/tdag/filters.py +201 -0
- mainsequence-3.17.0/mainsequence/tdag/pydantic_metadata.py +122 -0
- mainsequence-3.17.0/mainsequence/tdag/simple_tables/__init__.py +15 -0
- mainsequence-3.17.0/mainsequence/tdag/simple_tables/filters.py +329 -0
- mainsequence-3.17.0/mainsequence/tdag/simple_tables/models.py +115 -0
- mainsequence-3.17.0/mainsequence/tdag/simple_tables/persist_managers.py +184 -0
- mainsequence-3.17.0/mainsequence/tdag/simple_tables/schema.py +259 -0
- mainsequence-3.17.0/mainsequence/tdag/simple_tables/table_nodes.py +479 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence.egg-info/PKG-INFO +1 -1
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence.egg-info/SOURCES.txt +17 -2
- {mainsequence-3.16.0 → mainsequence-3.17.0}/pyproject.toml +1 -1
- mainsequence-3.17.0/tests/test_auth_precedence.py +106 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/tests/test_cli.py +131 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/tests/test_filter_normalization.py +92 -1
- mainsequence-3.17.0/tests/test_run_configuration.py +34 -0
- mainsequence-3.17.0/tests/test_simple_tables_configuration_hashing.py +145 -0
- mainsequence-3.17.0/tests/test_simple_tables_persistence.py +1327 -0
- mainsequence-3.16.0/mainsequence/client/data_filters.py +0 -298
- mainsequence-3.16.0/mainsequence/tdag/__init__.py +0 -12
- mainsequence-3.16.0/mainsequence/tdag/data_nodes/__init__.py +0 -8
- mainsequence-3.16.0/mainsequence/tdag/data_nodes/persist_managers.py +0 -775
- {mainsequence-3.16.0 → mainsequence-3.17.0}/LICENSE +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/README.md +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/__main__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/bootstrap.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/config.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/docker_utils.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/doctor.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/local_ops.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/model_filters.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/project_status.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/pydantic_cli.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/sdk_utils.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/ssh_utils.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/cli/ui.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/agent.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/client.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/data_sources_interfaces/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/data_sources_interfaces/duckdb.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/data_sources_interfaces/timescale.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/exceptions.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/models_helpers.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/client/models_vam.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/compute_validation.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/custom_api/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/custom_api/base.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/custom_api/cli.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/assets/config.toml +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/assets/favicon.png +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/assets/image_1_base64.txt +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/assets/image_2_base64.txt +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/assets/image_3_base64.txt +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/assets/image_4_base64.txt +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/assets/image_5_base64.txt +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/assets/logo.png +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/components/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/components/asset_select.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/components/date_settings.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/components/logged_user.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/core/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/core/theme.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/instruments/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/instruments/streamlit_form_factory.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/pages/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/dashboards/streamlit/scaffold.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instrumentation/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instrumentation/utils.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/data_interface/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/data_interface/data_interface.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/instruments/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/instruments/base_instrument.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/instruments/bond.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/instruments/callability.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/instruments/interest_rate_swap.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/instruments/json_codec.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/instruments/position.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/instruments/ql_fields.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/interest_rates/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/interest_rates/etl/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/interest_rates/etl/curve_codec.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/interest_rates/etl/nodes.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/interest_rates/etl/registry.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/pricing_models/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/pricing_models/bond_pricer.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/pricing_models/indices.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/pricing_models/indices_builders.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/pricing_models/swap_pricer.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/settings.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/instruments/utils.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/runtime_flags.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/__main__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/config.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/data_nodes/namespacing.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/data_nodes/utils.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/future_registry.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/tdag/utils.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/data_nodes/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/data_nodes/external_weights.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/data_nodes/intraday_trend.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/data_nodes/market_cap.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/data_nodes/mock_signal.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/data_nodes/portfolio_replicator.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/prices/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/prices/data_nodes.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/prices/utils.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/rebalance_strategies/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/contrib/rebalance_strategies/rebalance_strategies.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/enums.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/models.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/portfolio_nodes.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/resource_factory/__init__.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/resource_factory/rebalance_factory.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/resource_factory/signal_factory.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence/virtualfundbuilder/utils.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence.egg-info/dependency_links.txt +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence.egg-info/entry_points.txt +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence.egg-info/requires.txt +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/mainsequence.egg-info/top_level.txt +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/setup.cfg +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/tests/test_build_operations_hashing.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/tests/test_client.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/tests/test_instruments.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/tests/test_logconf.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/tests/test_logged_user_components.py +0 -0
- {mainsequence-3.16.0 → mainsequence-3.17.0}/tests/test_project_batch_jobs_from_file.py +0 -0
|
@@ -1958,6 +1958,89 @@ def list_data_node_storages(
|
|
|
1958
1958
|
raise ApiError(f"Data node storages fetch failed: {e}")
|
|
1959
1959
|
|
|
1960
1960
|
|
|
1961
|
+
def list_simple_table_storages(
|
|
1962
|
+
*,
|
|
1963
|
+
filters: dict[str, Any] | None = None,
|
|
1964
|
+
timeout: int | None = None,
|
|
1965
|
+
) -> list[dict[str, Any]]:
|
|
1966
|
+
"""
|
|
1967
|
+
List simple table storages via SDK client model.
|
|
1968
|
+
|
|
1969
|
+
Single source of truth:
|
|
1970
|
+
- delegates filtering and payload parsing to `SimpleTableStorage.filter()`
|
|
1971
|
+
"""
|
|
1972
|
+
try:
|
|
1973
|
+
storages = _run_sdk_model_operation(
|
|
1974
|
+
module_name="mainsequence.client.models_simple_tables",
|
|
1975
|
+
class_name="SimpleTableStorage",
|
|
1976
|
+
operation=lambda ClientSimpleTableStorage: ClientSimpleTableStorage.filter(
|
|
1977
|
+
timeout=timeout,
|
|
1978
|
+
**dict(filters or {}),
|
|
1979
|
+
),
|
|
1980
|
+
)
|
|
1981
|
+
return [_sdk_object_to_dict(storage) for storage in storages]
|
|
1982
|
+
except Exception as e:
|
|
1983
|
+
if isinstance(e, (ApiError, NotLoggedIn)):
|
|
1984
|
+
raise
|
|
1985
|
+
raise ApiError(f"Simple table storages fetch failed: {e}")
|
|
1986
|
+
|
|
1987
|
+
|
|
1988
|
+
def get_simple_table_storage(
|
|
1989
|
+
storage_id: int | str,
|
|
1990
|
+
*,
|
|
1991
|
+
timeout: int | None = None,
|
|
1992
|
+
) -> dict[str, Any]:
|
|
1993
|
+
"""
|
|
1994
|
+
Retrieve one simple table storage via SDK client model.
|
|
1995
|
+
"""
|
|
1996
|
+
try:
|
|
1997
|
+
storage = _run_sdk_model_operation(
|
|
1998
|
+
module_name="mainsequence.client.models_simple_tables",
|
|
1999
|
+
class_name="SimpleTableStorage",
|
|
2000
|
+
operation=lambda ClientSimpleTableStorage: ClientSimpleTableStorage.get(
|
|
2001
|
+
pk=int(storage_id),
|
|
2002
|
+
timeout=timeout,
|
|
2003
|
+
),
|
|
2004
|
+
)
|
|
2005
|
+
return _sdk_object_to_dict(storage)
|
|
2006
|
+
except Exception as e:
|
|
2007
|
+
err_name = type(e).__name__
|
|
2008
|
+
if err_name == "NotFoundError":
|
|
2009
|
+
raise ApiError(f"Simple table storage not found: {storage_id}")
|
|
2010
|
+
if isinstance(e, (ApiError, NotLoggedIn)):
|
|
2011
|
+
raise
|
|
2012
|
+
raise ApiError(f"Simple table storage fetch failed: {e}")
|
|
2013
|
+
|
|
2014
|
+
|
|
2015
|
+
def delete_simple_table_storage(
|
|
2016
|
+
storage_id: int | str,
|
|
2017
|
+
*,
|
|
2018
|
+
timeout: int | None = None,
|
|
2019
|
+
) -> dict[str, Any]:
|
|
2020
|
+
"""
|
|
2021
|
+
Delete one simple table storage via SDK client model.
|
|
2022
|
+
"""
|
|
2023
|
+
try:
|
|
2024
|
+
def _delete(ClientSimpleTableStorage):
|
|
2025
|
+
storage = ClientSimpleTableStorage.get(pk=int(storage_id), timeout=timeout)
|
|
2026
|
+
payload = _sdk_object_to_dict(storage)
|
|
2027
|
+
storage.delete(timeout=timeout)
|
|
2028
|
+
return payload
|
|
2029
|
+
|
|
2030
|
+
return _run_sdk_model_operation(
|
|
2031
|
+
module_name="mainsequence.client.models_simple_tables",
|
|
2032
|
+
class_name="SimpleTableStorage",
|
|
2033
|
+
operation=_delete,
|
|
2034
|
+
)
|
|
2035
|
+
except Exception as e:
|
|
2036
|
+
err_name = type(e).__name__
|
|
2037
|
+
if err_name == "NotFoundError":
|
|
2038
|
+
raise ApiError(f"Simple table storage not found: {storage_id}")
|
|
2039
|
+
if isinstance(e, (ApiError, NotLoggedIn)):
|
|
2040
|
+
raise
|
|
2041
|
+
raise ApiError(f"Simple table storage deletion failed: {e}")
|
|
2042
|
+
|
|
2043
|
+
|
|
1961
2044
|
def list_data_node_org_unique_identifiers(
|
|
1962
2045
|
*,
|
|
1963
2046
|
timeout: int | None = None,
|
|
@@ -79,6 +79,7 @@ from .api import (
|
|
|
79
79
|
delete_project_image,
|
|
80
80
|
delete_resource_release,
|
|
81
81
|
delete_secret,
|
|
82
|
+
delete_simple_table_storage,
|
|
82
83
|
fetch_project_env_text,
|
|
83
84
|
get_constant,
|
|
84
85
|
get_current_user_profile,
|
|
@@ -93,6 +94,7 @@ from .api import (
|
|
|
93
94
|
get_projects,
|
|
94
95
|
get_resource_release,
|
|
95
96
|
get_secret,
|
|
97
|
+
get_simple_table_storage,
|
|
96
98
|
list_constant_users_can_edit,
|
|
97
99
|
list_constant_users_can_view,
|
|
98
100
|
list_constants,
|
|
@@ -116,6 +118,7 @@ from .api import (
|
|
|
116
118
|
list_secret_users_can_edit,
|
|
117
119
|
list_secret_users_can_view,
|
|
118
120
|
list_secrets,
|
|
121
|
+
list_simple_table_storages,
|
|
119
122
|
list_team_users_can_edit,
|
|
120
123
|
list_team_users_can_view,
|
|
121
124
|
prime_sync_project_after_commit_sdk,
|
|
@@ -185,6 +188,7 @@ app = typer.Typer(help="MainSequence CLI (login + project operations)")
|
|
|
185
188
|
|
|
186
189
|
constants = typer.Typer(help="Constant commands")
|
|
187
190
|
secrets = typer.Typer(help="Secret commands")
|
|
191
|
+
simple_table = typer.Typer(help="Simple table commands")
|
|
188
192
|
organization = typer.Typer(help="Organization commands")
|
|
189
193
|
organization_teams_group = typer.Typer(help="Organization team commands")
|
|
190
194
|
markets = typer.Typer(help="Markets commands")
|
|
@@ -203,6 +207,10 @@ sdk = typer.Typer(help="SDK utilities (latest version, status)")
|
|
|
203
207
|
|
|
204
208
|
app.add_typer(constants, name="constants")
|
|
205
209
|
app.add_typer(secrets, name="secrets")
|
|
210
|
+
app.add_typer(simple_table, name="simple_table")
|
|
211
|
+
app.add_typer(simple_table, name="simple-table", hidden=True)
|
|
212
|
+
app.add_typer(simple_table, name="simple_tables", hidden=True)
|
|
213
|
+
app.add_typer(simple_table, name="simple-tables", hidden=True)
|
|
206
214
|
app.add_typer(organization, name="organization")
|
|
207
215
|
app.add_typer(markets, name="markets")
|
|
208
216
|
app.add_typer(data_node_storage_group, name="data-node")
|
|
@@ -236,6 +244,7 @@ PROJECT_RESOURCE_MODEL_REF = "mainsequence.client.models_helpers.ProjectResource
|
|
|
236
244
|
DATA_NODE_STORAGE_MODEL_REF = "mainsequence.client.models_tdag.DataNodeStorage"
|
|
237
245
|
CONSTANT_MODEL_REF = "mainsequence.client.models_tdag.Constant"
|
|
238
246
|
SECRET_MODEL_REF = "mainsequence.client.models_tdag.Secret"
|
|
247
|
+
SIMPLE_TABLE_STORAGE_MODEL_REF = "mainsequence.client.models_simple_tables.SimpleTableStorage"
|
|
239
248
|
TEAM_MODEL_REF = "mainsequence.client.models_user.Team"
|
|
240
249
|
PORTFOLIO_MODEL_REF = "mainsequence.client.models_vam.Portfolio"
|
|
241
250
|
ASSET_TRANSLATION_TABLE_MODEL_REF = "mainsequence.client.models_vam.AssetTranslationTable"
|
|
@@ -2916,6 +2925,129 @@ def _secrets_delete_impl(
|
|
|
2916
2925
|
print_kv("Deleted Secret", _format_secret_preview(deleted))
|
|
2917
2926
|
|
|
2918
2927
|
|
|
2928
|
+
def _format_simple_table_storage_preview(storage: dict[str, object]) -> list[tuple[str, str]]:
|
|
2929
|
+
columns = storage.get("columns")
|
|
2930
|
+
foreign_keys = storage.get("foreign_keys")
|
|
2931
|
+
incoming_fks = storage.get("incoming_fks")
|
|
2932
|
+
indexes_meta = storage.get("indexes_meta")
|
|
2933
|
+
return [
|
|
2934
|
+
("ID", str(storage.get("id") or "-")),
|
|
2935
|
+
("Source Class", str(storage.get("source_class_name") or "-")),
|
|
2936
|
+
("Data Source", _format_data_node_storage_data_source(storage.get("data_source"))),
|
|
2937
|
+
("Columns", str(len(columns)) if isinstance(columns, list) else "-"),
|
|
2938
|
+
("Foreign Keys", str(len(foreign_keys)) if isinstance(foreign_keys, list) else "-"),
|
|
2939
|
+
("Incoming FKs", str(len(incoming_fks)) if isinstance(incoming_fks, list) else "-"),
|
|
2940
|
+
("Indexes", str(len(indexes_meta)) if isinstance(indexes_meta, list) else "-"),
|
|
2941
|
+
("Open For Everyone", str(storage.get("open_for_everyone"))),
|
|
2942
|
+
("Creation Date", str(storage.get("creation_date") or "-")),
|
|
2943
|
+
]
|
|
2944
|
+
|
|
2945
|
+
|
|
2946
|
+
def _simple_tables_list_impl(
|
|
2947
|
+
timeout: int | None,
|
|
2948
|
+
filter_entries: list[str] | None,
|
|
2949
|
+
show_filters: bool,
|
|
2950
|
+
) -> None:
|
|
2951
|
+
filters = _resolve_cli_list_filters(
|
|
2952
|
+
model_ref=SIMPLE_TABLE_STORAGE_MODEL_REF,
|
|
2953
|
+
filter_entries=filter_entries,
|
|
2954
|
+
show_filters=show_filters,
|
|
2955
|
+
command_label="Simple Tables",
|
|
2956
|
+
)
|
|
2957
|
+
_require_login()
|
|
2958
|
+
|
|
2959
|
+
try:
|
|
2960
|
+
storages = list_simple_table_storages(timeout=timeout, filters=filters)
|
|
2961
|
+
except ApiError as e:
|
|
2962
|
+
error(f"Simple tables fetch failed: {e}")
|
|
2963
|
+
raise typer.Exit(1)
|
|
2964
|
+
|
|
2965
|
+
rows: list[list[str]] = []
|
|
2966
|
+
for storage in storages:
|
|
2967
|
+
columns = storage.get("columns")
|
|
2968
|
+
rows.append(
|
|
2969
|
+
[
|
|
2970
|
+
str(storage.get("id") or "-"),
|
|
2971
|
+
str(storage.get("source_class_name") or "-"),
|
|
2972
|
+
_format_data_node_storage_data_source(storage.get("data_source")),
|
|
2973
|
+
str(len(columns)) if isinstance(columns, list) else "-",
|
|
2974
|
+
str(storage.get("open_for_everyone")),
|
|
2975
|
+
str(storage.get("creation_date") or "-"),
|
|
2976
|
+
]
|
|
2977
|
+
)
|
|
2978
|
+
|
|
2979
|
+
if rows:
|
|
2980
|
+
print_table(
|
|
2981
|
+
"Simple Tables",
|
|
2982
|
+
["ID", "Source Class", "Data Source", "Columns", "Open", "Creation Date"],
|
|
2983
|
+
rows,
|
|
2984
|
+
)
|
|
2985
|
+
else:
|
|
2986
|
+
info("No simple tables.")
|
|
2987
|
+
info(f"Total simple tables: {len(storages)}")
|
|
2988
|
+
|
|
2989
|
+
|
|
2990
|
+
def _simple_tables_detail_impl(
|
|
2991
|
+
*,
|
|
2992
|
+
storage_id: int,
|
|
2993
|
+
timeout: int | None,
|
|
2994
|
+
) -> None:
|
|
2995
|
+
_require_login()
|
|
2996
|
+
|
|
2997
|
+
try:
|
|
2998
|
+
storage = get_simple_table_storage(storage_id, timeout=timeout)
|
|
2999
|
+
except ApiError as e:
|
|
3000
|
+
error(f"Simple table fetch failed: {e}")
|
|
3001
|
+
raise typer.Exit(1)
|
|
3002
|
+
|
|
3003
|
+
print_kv("Simple Table", _format_simple_table_storage_preview(storage))
|
|
3004
|
+
print_kv(
|
|
3005
|
+
"Simple Table Details",
|
|
3006
|
+
[
|
|
3007
|
+
("Schema", _format_json_value(storage.get("schema") or storage.get("simple_table_schema"))),
|
|
3008
|
+
("Build Configuration", _format_json_value(storage.get("build_configuration"))),
|
|
3009
|
+
("Source Code Git Hash", str(storage.get("time_serie_source_code_git_hash") or "-")),
|
|
3010
|
+
("Organization Owner", str(storage.get("organization_owner") or "-")),
|
|
3011
|
+
("Created By User", str(storage.get("created_by_user") or "-")),
|
|
3012
|
+
("Columns Payload", _format_json_value(storage.get("columns"))),
|
|
3013
|
+
("Foreign Keys Payload", _format_json_value(storage.get("foreign_keys"))),
|
|
3014
|
+
("Incoming FKs Payload", _format_json_value(storage.get("incoming_fks"))),
|
|
3015
|
+
("Indexes Payload", _format_json_value(storage.get("indexes_meta"))),
|
|
3016
|
+
],
|
|
3017
|
+
)
|
|
3018
|
+
|
|
3019
|
+
|
|
3020
|
+
def _simple_tables_delete_impl(
|
|
3021
|
+
*,
|
|
3022
|
+
storage_id: int,
|
|
3023
|
+
timeout: int | None,
|
|
3024
|
+
) -> None:
|
|
3025
|
+
_require_login()
|
|
3026
|
+
|
|
3027
|
+
try:
|
|
3028
|
+
storage = get_simple_table_storage(storage_id, timeout=timeout)
|
|
3029
|
+
except ApiError as e:
|
|
3030
|
+
error(f"Simple table fetch failed: {e}")
|
|
3031
|
+
raise typer.Exit(1)
|
|
3032
|
+
|
|
3033
|
+
verification_value = str(storage.get("source_class_name") or storage.get("id") or storage_id)
|
|
3034
|
+
_require_delete_verification(
|
|
3035
|
+
preview_title="Simple Table Delete Preview",
|
|
3036
|
+
preview_items=_format_simple_table_storage_preview(storage),
|
|
3037
|
+
verification_value=verification_value,
|
|
3038
|
+
verification_label="source class name" if storage.get("source_class_name") else "simple table id",
|
|
3039
|
+
)
|
|
3040
|
+
|
|
3041
|
+
try:
|
|
3042
|
+
deleted = delete_simple_table_storage(storage_id, timeout=timeout)
|
|
3043
|
+
except ApiError as e:
|
|
3044
|
+
error(f"Simple table deletion failed: {e}")
|
|
3045
|
+
raise typer.Exit(1)
|
|
3046
|
+
|
|
3047
|
+
success(f"Simple table deleted: id={storage_id}")
|
|
3048
|
+
print_kv("Deleted Simple Table", _format_simple_table_storage_preview(deleted))
|
|
3049
|
+
|
|
3050
|
+
|
|
2919
3051
|
def _data_node_storage_list_impl(
|
|
2920
3052
|
timeout: int | None,
|
|
2921
3053
|
filter_entries: list[str] | None,
|
|
@@ -3086,6 +3218,44 @@ def _print_data_node_storage_search_section(
|
|
|
3086
3218
|
return len(storages)
|
|
3087
3219
|
|
|
3088
3220
|
|
|
3221
|
+
@simple_table.command("list")
|
|
3222
|
+
def simple_tables_list_cmd(
|
|
3223
|
+
filter_entries: list[str] | None = typer.Option(None, "--filter", help=LIST_FILTER_OPTION_HELP),
|
|
3224
|
+
show_filters: bool = typer.Option(False, "--show-filters", help="Show the filters supported by this list command and exit."),
|
|
3225
|
+
timeout: int | None = typer.Option(None, "--timeout", help="Request timeout in seconds"),
|
|
3226
|
+
):
|
|
3227
|
+
"""
|
|
3228
|
+
List simple table storages visible to the authenticated user.
|
|
3229
|
+
"""
|
|
3230
|
+
_simple_tables_list_impl(
|
|
3231
|
+
timeout=timeout,
|
|
3232
|
+
filter_entries=filter_entries,
|
|
3233
|
+
show_filters=show_filters,
|
|
3234
|
+
)
|
|
3235
|
+
|
|
3236
|
+
|
|
3237
|
+
@simple_table.command("detail")
|
|
3238
|
+
def simple_tables_detail_cmd(
|
|
3239
|
+
storage_id: int = typer.Argument(..., help="Simple table storage ID."),
|
|
3240
|
+
timeout: int | None = typer.Option(None, "--timeout", help="Request timeout in seconds"),
|
|
3241
|
+
):
|
|
3242
|
+
"""
|
|
3243
|
+
Show one simple table storage in detail.
|
|
3244
|
+
"""
|
|
3245
|
+
_simple_tables_detail_impl(storage_id=storage_id, timeout=timeout)
|
|
3246
|
+
|
|
3247
|
+
|
|
3248
|
+
@simple_table.command("delete")
|
|
3249
|
+
def simple_tables_delete_cmd(
|
|
3250
|
+
storage_id: int = typer.Argument(..., help="Simple table storage ID."),
|
|
3251
|
+
timeout: int | None = typer.Option(None, "--timeout", help="Request timeout in seconds"),
|
|
3252
|
+
):
|
|
3253
|
+
"""
|
|
3254
|
+
Delete one simple table storage.
|
|
3255
|
+
"""
|
|
3256
|
+
_simple_tables_delete_impl(storage_id=storage_id, timeout=timeout)
|
|
3257
|
+
|
|
3258
|
+
|
|
3089
3259
|
@constants.command("list")
|
|
3090
3260
|
def constants_list_cmd(
|
|
3091
3261
|
filter_entries: list[str] | None = typer.Option(None, "--filter", help=LIST_FILTER_OPTION_HELP),
|
|
@@ -6,8 +6,6 @@ from typing import Any, ClassVar
|
|
|
6
6
|
|
|
7
7
|
from pydantic import BaseModel, ConfigDict
|
|
8
8
|
|
|
9
|
-
from mainsequence import logger
|
|
10
|
-
|
|
11
9
|
from .exceptions import ApiError, raise_for_response
|
|
12
10
|
from .utils import (
|
|
13
11
|
API_ENDPOINT,
|
|
@@ -632,21 +630,69 @@ class BaseObjectOrm:
|
|
|
632
630
|
|
|
633
631
|
body = r.json()
|
|
634
632
|
|
|
635
|
-
def
|
|
633
|
+
def _iter_field_aliases(field_info) -> set[str]:
|
|
634
|
+
aliases: set[str] = set()
|
|
635
|
+
|
|
636
|
+
for attr_name in ("alias", "serialization_alias"):
|
|
637
|
+
alias_value = getattr(field_info, attr_name, None)
|
|
638
|
+
if isinstance(alias_value, str) and alias_value:
|
|
639
|
+
aliases.add(alias_value)
|
|
640
|
+
|
|
641
|
+
validation_alias = getattr(field_info, "validation_alias", None)
|
|
642
|
+
if isinstance(validation_alias, str) and validation_alias:
|
|
643
|
+
aliases.add(validation_alias)
|
|
644
|
+
elif validation_alias is not None:
|
|
645
|
+
choices = getattr(validation_alias, "choices", None)
|
|
646
|
+
if choices is not None:
|
|
647
|
+
for choice in choices:
|
|
648
|
+
if isinstance(choice, str) and choice:
|
|
649
|
+
aliases.add(choice)
|
|
650
|
+
else:
|
|
651
|
+
path = getattr(validation_alias, "path", None)
|
|
652
|
+
if isinstance(path, (list, tuple)) and len(path) == 1 and isinstance(path[0], str):
|
|
653
|
+
aliases.add(path[0])
|
|
654
|
+
|
|
655
|
+
return aliases
|
|
656
|
+
|
|
657
|
+
def _resolve_model_field_name(obj, raw_key: str) -> str:
|
|
658
|
+
if not isinstance(obj, BaseModel):
|
|
659
|
+
return raw_key
|
|
660
|
+
|
|
661
|
+
model_fields = getattr(type(obj), "model_fields", {})
|
|
662
|
+
if raw_key in model_fields:
|
|
663
|
+
return raw_key
|
|
664
|
+
|
|
665
|
+
for field_name, field_info in model_fields.items():
|
|
666
|
+
if raw_key in _iter_field_aliases(field_info):
|
|
667
|
+
return field_name
|
|
668
|
+
|
|
669
|
+
return raw_key
|
|
670
|
+
|
|
671
|
+
def recursive_update(obj, update_dict, path=()):
|
|
636
672
|
for k, v in update_dict.items():
|
|
673
|
+
current_path = (*path, k)
|
|
674
|
+
field_name = _resolve_model_field_name(obj, k)
|
|
637
675
|
# Get the existing nested object, defaulting to None if it doesn't exist
|
|
638
|
-
nested_obj = getattr(obj,
|
|
676
|
+
nested_obj = getattr(obj, field_name, None)
|
|
639
677
|
|
|
640
678
|
# Only recurse if the update value is a dict AND the existing
|
|
641
679
|
# attribute is an instance of a Pydantic model.
|
|
642
680
|
if isinstance(v, dict) and isinstance(nested_obj, BaseModel):
|
|
643
|
-
recursive_update(nested_obj, v)
|
|
681
|
+
recursive_update(nested_obj, v, path=current_path)
|
|
644
682
|
else:
|
|
645
683
|
# Otherwise, just set the value directly.
|
|
646
684
|
try:
|
|
647
|
-
setattr(obj,
|
|
648
|
-
except Exception as
|
|
649
|
-
|
|
685
|
+
setattr(obj, field_name, v)
|
|
686
|
+
except Exception as exc:
|
|
687
|
+
field_path = ".".join(current_path)
|
|
688
|
+
response_fragment = repr({k: v})
|
|
689
|
+
if len(response_fragment) > 300:
|
|
690
|
+
response_fragment = f"{response_fragment[:297]}..."
|
|
691
|
+
raise ValueError(
|
|
692
|
+
f"Failed to apply PATCH response to {type(obj).__name__} at field "
|
|
693
|
+
f"'{field_path}'. Response fragment: {response_fragment}. "
|
|
694
|
+
f"Original error: {exc}"
|
|
695
|
+
) from exc
|
|
650
696
|
|
|
651
697
|
return obj
|
|
652
698
|
|