frogml-cli 0.0.1__py3-none-any.whl
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.
- frogml_cli/__init__.py +10 -0
- frogml_cli/cli.py +40 -0
- frogml_cli/commands/__init__.py +0 -0
- frogml_cli/commands/_logic/__init__.py +0 -0
- frogml_cli/commands/_logic/tools.py +6 -0
- frogml_cli/commands/alerts/__init__.py +0 -0
- frogml_cli/commands/alerts/alerts_commnad_group.py +18 -0
- frogml_cli/commands/alerts/delete/__init__.py +0 -0
- frogml_cli/commands/alerts/delete/_logic.py +5 -0
- frogml_cli/commands/alerts/delete/ui.py +10 -0
- frogml_cli/commands/alerts/list/__init__.py +0 -0
- frogml_cli/commands/alerts/list/_logic.py +23 -0
- frogml_cli/commands/alerts/list/ui.py +17 -0
- frogml_cli/commands/alerts/register/__init__.py +0 -0
- frogml_cli/commands/alerts/register/_logic.py +72 -0
- frogml_cli/commands/alerts/register/ui.py +30 -0
- frogml_cli/commands/audience/__init__.py +0 -0
- frogml_cli/commands/audience/_logic/__init__.py +0 -0
- frogml_cli/commands/audience/_logic/config/__init__.py +0 -0
- frogml_cli/commands/audience/_logic/config/config_base.py +15 -0
- frogml_cli/commands/audience/_logic/config/parser.py +30 -0
- frogml_cli/commands/audience/_logic/config/v1/__init__.py +0 -0
- frogml_cli/commands/audience/_logic/config/v1/audience_config.py +25 -0
- frogml_cli/commands/audience/_logic/config/v1/conditions_config.py +59 -0
- frogml_cli/commands/audience/_logic/config/v1/config_v1.py +23 -0
- frogml_cli/commands/audience/_logic/config/v1/route_config.py +15 -0
- frogml_cli/commands/audience/_logic/config/v1/spec.py +9 -0
- frogml_cli/commands/audience/audience_api_dump.py +86 -0
- frogml_cli/commands/audience/audience_commands_group.py +30 -0
- frogml_cli/commands/audience/create/__init__.py +0 -0
- frogml_cli/commands/audience/create/logic.py +41 -0
- frogml_cli/commands/audience/create/ui.py +21 -0
- frogml_cli/commands/audience/delete/__init__.py +0 -0
- frogml_cli/commands/audience/delete/logic.py +13 -0
- frogml_cli/commands/audience/delete/ui.py +17 -0
- frogml_cli/commands/audience/get/__init__.py +0 -0
- frogml_cli/commands/audience/get/logic.py +14 -0
- frogml_cli/commands/audience/get/ui.py +25 -0
- frogml_cli/commands/audience/list/__init__.py +0 -0
- frogml_cli/commands/audience/list/logic.py +16 -0
- frogml_cli/commands/audience/list/ui.py +26 -0
- frogml_cli/commands/audience/update/__init__.py +0 -0
- frogml_cli/commands/audience/update/logic.py +37 -0
- frogml_cli/commands/audience/update/ui.py +26 -0
- frogml_cli/commands/auto_scalling/__init__.py +0 -0
- frogml_cli/commands/auto_scalling/_logic/__init__.py +0 -0
- frogml_cli/commands/auto_scalling/_logic/config/__init__.py +3 -0
- frogml_cli/commands/auto_scalling/_logic/config/config.py +152 -0
- frogml_cli/commands/auto_scalling/_logic/config/parser.py +21 -0
- frogml_cli/commands/auto_scalling/attach/__init__.py +0 -0
- frogml_cli/commands/auto_scalling/attach/_logic.py +43 -0
- frogml_cli/commands/auto_scalling/attach/ui.py +21 -0
- frogml_cli/commands/auto_scalling/autoscaling_commands_group.py +15 -0
- frogml_cli/commands/automations/__init__.py +0 -0
- frogml_cli/commands/automations/automations_commands_group.py +30 -0
- frogml_cli/commands/automations/delete/__init__.py +0 -0
- frogml_cli/commands/automations/delete/_logic.py +6 -0
- frogml_cli/commands/automations/delete/ui.py +23 -0
- frogml_cli/commands/automations/executions/__init__.py +0 -0
- frogml_cli/commands/automations/executions/executions_commands_group.py +14 -0
- frogml_cli/commands/automations/executions/list/__init__.py +0 -0
- frogml_cli/commands/automations/executions/list/_logic.py +8 -0
- frogml_cli/commands/automations/executions/list/ui.py +27 -0
- frogml_cli/commands/automations/list/__init__.py +0 -0
- frogml_cli/commands/automations/list/_logic.py +36 -0
- frogml_cli/commands/automations/list/ui.py +21 -0
- frogml_cli/commands/automations/register/__init__.py +0 -0
- frogml_cli/commands/automations/register/_logic.py +43 -0
- frogml_cli/commands/automations/register/ui.py +44 -0
- frogml_cli/commands/config/__init__.py +0 -0
- frogml_cli/commands/config/add/__init__.py +0 -0
- frogml_cli/commands/config/add/ui.py +62 -0
- frogml_cli/commands/config/config_commands_group.py +11 -0
- frogml_cli/commands/feature_store/__init__.py +0 -0
- frogml_cli/commands/feature_store/backfill/__init__.py +0 -0
- frogml_cli/commands/feature_store/backfill/_logic.py +140 -0
- frogml_cli/commands/feature_store/backfill/ui.py +129 -0
- frogml_cli/commands/feature_store/delete/__init__.py +0 -0
- frogml_cli/commands/feature_store/delete/_logic.py +107 -0
- frogml_cli/commands/feature_store/delete/ui.py +40 -0
- frogml_cli/commands/feature_store/execution/__init__.py +0 -0
- frogml_cli/commands/feature_store/execution/ui.py +19 -0
- frogml_cli/commands/feature_store/feature_store_command_group.py +29 -0
- frogml_cli/commands/feature_store/list/__init__.py +0 -0
- frogml_cli/commands/feature_store/list/ui.py +140 -0
- frogml_cli/commands/feature_store/pause/__init__.py +0 -0
- frogml_cli/commands/feature_store/pause/ui.py +18 -0
- frogml_cli/commands/feature_store/register/__init__.py +0 -0
- frogml_cli/commands/feature_store/register/_logic.py +369 -0
- frogml_cli/commands/feature_store/register/ui.py +111 -0
- frogml_cli/commands/feature_store/resume/__init__.py +0 -0
- frogml_cli/commands/feature_store/resume/ui.py +18 -0
- frogml_cli/commands/feature_store/trigger/__init__.py +0 -0
- frogml_cli/commands/feature_store/trigger/ui.py +39 -0
- frogml_cli/commands/models/__init__.py +0 -0
- frogml_cli/commands/models/build/__init__.py +0 -0
- frogml_cli/commands/models/build/_logic/__init__.py +0 -0
- frogml_cli/commands/models/build/_logic/build_steps.py +42 -0
- frogml_cli/commands/models/build/_logic/client_logs/__init__.py +0 -0
- frogml_cli/commands/models/build/_logic/client_logs/cli_phase_run_handler.py +123 -0
- frogml_cli/commands/models/build/_logic/client_logs/cli_trigger_build_logger.py +19 -0
- frogml_cli/commands/models/build/_logic/client_logs/logger.py +88 -0
- frogml_cli/commands/models/build/_logic/client_logs/messages.py +36 -0
- frogml_cli/commands/models/build/_logic/client_logs/spinner.py +14 -0
- frogml_cli/commands/models/build/_logic/client_logs/trigger_build_logger.py +54 -0
- frogml_cli/commands/models/build/_logic/client_logs/utils.py +12 -0
- frogml_cli/commands/models/build/_logic/phase/__init__.py +0 -0
- frogml_cli/commands/models/build/_logic/phase/a_fetch_model_code/__init__.py +20 -0
- frogml_cli/commands/models/build/_logic/phase/a_fetch_model_code/get_sdk_version_step.py +15 -0
- frogml_cli/commands/models/build/_logic/phase/b_remote_register_frogml_build/__init__.py +16 -0
- frogml_cli/commands/models/build/_logic/phase/c_deploy/__init__.py +6 -0
- frogml_cli/commands/models/build/_logic/phase/c_deploy/build_polling_status.py +55 -0
- frogml_cli/commands/models/build/_logic/phase/c_deploy/deploy_build.py +61 -0
- frogml_cli/commands/models/build/_logic/util/__init__.py +0 -0
- frogml_cli/commands/models/build/_logic/util/protobuf_factory.py +45 -0
- frogml_cli/commands/models/build/_logic/util/step_decorator.py +60 -0
- frogml_cli/commands/models/build/_logic/util/text.py +9 -0
- frogml_cli/commands/models/build/_logic/wait_until_finished.py +27 -0
- frogml_cli/commands/models/build/ui.py +337 -0
- frogml_cli/commands/models/builds/__init__.py +0 -0
- frogml_cli/commands/models/builds/builds_commands_group.py +16 -0
- frogml_cli/commands/models/builds/cancel/__init__.py +0 -0
- frogml_cli/commands/models/builds/cancel/_logic.py +5 -0
- frogml_cli/commands/models/builds/cancel/ui.py +15 -0
- frogml_cli/commands/models/builds/logs/__init__.py +0 -0
- frogml_cli/commands/models/builds/logs/ui.py +35 -0
- frogml_cli/commands/models/builds/status/__init__.py +0 -0
- frogml_cli/commands/models/builds/status/_logic.py +6 -0
- frogml_cli/commands/models/builds/status/ui.py +39 -0
- frogml_cli/commands/models/create/__init__.py +0 -0
- frogml_cli/commands/models/create/_logic.py +40 -0
- frogml_cli/commands/models/create/ui.py +46 -0
- frogml_cli/commands/models/delete/__init__.py +0 -0
- frogml_cli/commands/models/delete/_logic.py +18 -0
- frogml_cli/commands/models/delete/ui.py +25 -0
- frogml_cli/commands/models/deployments/__init__.py +0 -0
- frogml_cli/commands/models/deployments/deploy/__init__.py +0 -0
- frogml_cli/commands/models/deployments/deploy/_logic/__init__.py +0 -0
- frogml_cli/commands/models/deployments/deploy/_logic/advance_deployment_options_handler.py +31 -0
- frogml_cli/commands/models/deployments/deploy/_logic/base_deploy_executor.py +70 -0
- frogml_cli/commands/models/deployments/deploy/_logic/deploy_config.py +261 -0
- frogml_cli/commands/models/deployments/deploy/_logic/deployment.py +407 -0
- frogml_cli/commands/models/deployments/deploy/_logic/deployment_message_helpers.py +116 -0
- frogml_cli/commands/models/deployments/deploy/_logic/deployment_response_handler.py +156 -0
- frogml_cli/commands/models/deployments/deploy/_logic/deployment_size_mapper.py +98 -0
- frogml_cli/commands/models/deployments/deploy/_logic/get_latest_successful_build.py +28 -0
- frogml_cli/commands/models/deployments/deploy/_logic/local_deployment.py +193 -0
- frogml_cli/commands/models/deployments/deploy/batch/__init__.py +0 -0
- frogml_cli/commands/models/deployments/deploy/batch/_logic/__init__.py +0 -0
- frogml_cli/commands/models/deployments/deploy/batch/_logic/advanced_deployment_mapper.py +15 -0
- frogml_cli/commands/models/deployments/deploy/batch/_logic/deploy_executor.py +24 -0
- frogml_cli/commands/models/deployments/deploy/batch/ui.py +119 -0
- frogml_cli/commands/models/deployments/deploy/deploy_commands_group.py +19 -0
- frogml_cli/commands/models/deployments/deploy/realtime/__init__.py +0 -0
- frogml_cli/commands/models/deployments/deploy/realtime/_logic/__init__.py +0 -0
- frogml_cli/commands/models/deployments/deploy/realtime/_logic/advanced_deployment_mapper.py +21 -0
- frogml_cli/commands/models/deployments/deploy/realtime/_logic/deploy_executor.py +24 -0
- frogml_cli/commands/models/deployments/deploy/realtime/_logic/serving_strategy_mapper.py +75 -0
- frogml_cli/commands/models/deployments/deploy/realtime/ui.py +202 -0
- frogml_cli/commands/models/deployments/deploy/streaming/__init__.py +0 -0
- frogml_cli/commands/models/deployments/deploy/streaming/_logic/__init__.py +0 -0
- frogml_cli/commands/models/deployments/deploy/streaming/_logic/deploy_executor.py +24 -0
- frogml_cli/commands/models/deployments/deploy/streaming/_logic/serving_strategy_mapper.py +38 -0
- frogml_cli/commands/models/deployments/deploy/streaming/ui.py +206 -0
- frogml_cli/commands/models/deployments/undeploy/__init__.py +0 -0
- frogml_cli/commands/models/deployments/undeploy/_logic/__init__.py +0 -0
- frogml_cli/commands/models/deployments/undeploy/_logic/request_undeploy.py +249 -0
- frogml_cli/commands/models/deployments/undeploy/ui.py +61 -0
- frogml_cli/commands/models/describe/__init__.py +0 -0
- frogml_cli/commands/models/describe/_logic.py +169 -0
- frogml_cli/commands/models/describe/ui.py +35 -0
- frogml_cli/commands/models/executions/__init__.py +0 -0
- frogml_cli/commands/models/executions/cancel/__init__.py +0 -0
- frogml_cli/commands/models/executions/cancel/_logic.py +9 -0
- frogml_cli/commands/models/executions/cancel/ui.py +27 -0
- frogml_cli/commands/models/executions/execution_commands_group.py +24 -0
- frogml_cli/commands/models/executions/report/__init__.py +0 -0
- frogml_cli/commands/models/executions/report/_logic.py +14 -0
- frogml_cli/commands/models/executions/report/ui.py +43 -0
- frogml_cli/commands/models/executions/start/__init__.py +0 -0
- frogml_cli/commands/models/executions/start/_logic.py +83 -0
- frogml_cli/commands/models/executions/start/ui.py +208 -0
- frogml_cli/commands/models/executions/status/__init__.py +0 -0
- frogml_cli/commands/models/executions/status/_logic.py +13 -0
- frogml_cli/commands/models/executions/status/ui.py +27 -0
- frogml_cli/commands/models/init/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/initialize_model_structure.py +40 -0
- frogml_cli/commands/models/init/_logic/template/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/churn/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/churn/cookiecutter.json +3 -0
- frogml_cli/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- frogml_cli/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/conda.yml +10 -0
- frogml_cli/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/data.csv +1001 -0
- frogml_cli/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/main/model.py +99 -0
- frogml_cli/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/churn/{{cookiecutter.model_directory}}/tests/it/test_churn.py +32 -0
- frogml_cli/commands/models/init/_logic/template/credit_risk/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/credit_risk/cookiecutter.json +3 -0
- frogml_cli/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- frogml_cli/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/conda.yml +11 -0
- frogml_cli/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/data.csv +1001 -0
- frogml_cli/commands/models/init/_logic/template/credit_risk/{{cookiecutter.model_directory}}/main/model.py +108 -0
- frogml_cli/commands/models/init/_logic/template/general/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/general/cookiecutter.json +6 -0
- frogml_cli/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/__init__.py +5 -0
- frogml_cli/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/conda.yml +8 -0
- frogml_cli/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.main_directory}}/model.py +66 -0
- frogml_cli/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.test_directory}}/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/general/{{cookiecutter.model_directory}}/{{cookiecutter.test_directory}}/test_qwak_model.py +5 -0
- frogml_cli/commands/models/init/_logic/template/titanic/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/titanic/cookiecutter.json +3 -0
- frogml_cli/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- frogml_cli/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/conda.yml +11 -0
- frogml_cli/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/main/model.py +98 -0
- frogml_cli/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/titanic/{{cookiecutter.model_directory}}/tests/it/test_titanic.py +24 -0
- frogml_cli/commands/models/init/_logic/template/titanic_poetry/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/titanic_poetry/cookiecutter.json +3 -0
- frogml_cli/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/__init__.py +5 -0
- frogml_cli/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/model.py +98 -0
- frogml_cli/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/main/pyproject.toml +20 -0
- frogml_cli/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/it/__init__.py +0 -0
- frogml_cli/commands/models/init/_logic/template/titanic_poetry/{{cookiecutter.model_directory}}/tests/it/test_titanic.py +25 -0
- frogml_cli/commands/models/init/ui.py +61 -0
- frogml_cli/commands/models/list/__init__.py +0 -0
- frogml_cli/commands/models/list/_logic.py +5 -0
- frogml_cli/commands/models/list/ui.py +41 -0
- frogml_cli/commands/models/list_models/__init__.py +0 -0
- frogml_cli/commands/models/list_models/_logic.py +11 -0
- frogml_cli/commands/models/list_models/ui.py +60 -0
- frogml_cli/commands/models/metadata/__init__.py +0 -0
- frogml_cli/commands/models/metadata/_logic.py +12 -0
- frogml_cli/commands/models/metadata/ui.py +60 -0
- frogml_cli/commands/models/models_command_group.py +44 -0
- frogml_cli/commands/models/runtime/__init__.py +0 -0
- frogml_cli/commands/models/runtime/logs/__init__.py +0 -0
- frogml_cli/commands/models/runtime/logs/ui.py +63 -0
- frogml_cli/commands/models/runtime/runtime_commands_group.py +17 -0
- frogml_cli/commands/models/runtime/update/__init__.py +0 -0
- frogml_cli/commands/models/runtime/update/_logic.py +9 -0
- frogml_cli/commands/models/runtime/update/ui.py +17 -0
- frogml_cli/commands/secrets/__init__.py +0 -0
- frogml_cli/commands/secrets/delete/__init__.py +0 -0
- frogml_cli/commands/secrets/delete/_logic.py +5 -0
- frogml_cli/commands/secrets/delete/ui.py +21 -0
- frogml_cli/commands/secrets/get/__init__.py +0 -0
- frogml_cli/commands/secrets/get/_logic.py +5 -0
- frogml_cli/commands/secrets/get/ui.py +17 -0
- frogml_cli/commands/secrets/secrets_commands_group.py +19 -0
- frogml_cli/commands/secrets/set/__init__.py +0 -0
- frogml_cli/commands/secrets/set/_logic.py +5 -0
- frogml_cli/commands/secrets/set/ui.py +16 -0
- frogml_cli/commands/ui_tools.py +18 -0
- frogml_cli/exceptions/__init__.py +14 -0
- frogml_cli/exceptions/frogml_command_exception.py +2 -0
- frogml_cli/exceptions/frogml_deploy_new_build_failed.py +5 -0
- frogml_cli/exceptions/frogml_resource_not_found.py +2 -0
- frogml_cli/inner/__init__.py +0 -0
- frogml_cli/inner/file_registry.py +98 -0
- frogml_cli/inner/tools/__init__.py +0 -0
- frogml_cli/inner/tools/cli_tools.py +179 -0
- frogml_cli/inner/tools/config_handler.py +29 -0
- frogml_cli/inner/tools/dataclasses_utils.py +21 -0
- frogml_cli/inner/tools/logger/__init__.py +3 -0
- frogml_cli/inner/tools/logger/logger.py +278 -0
- frogml_cli/inner/tools/logger/logging.yml +79 -0
- frogml_cli/inner/tools/tracking.py +47 -0
- frogml_cli/main.py +9 -0
- frogml_cli/tools/__init__.py +0 -0
- frogml_cli/tools/colors.py +13 -0
- frogml_cli/tools/const.py +3 -0
- frogml_cli/tools/files.py +63 -0
- frogml_cli/tools/log_handling.py +159 -0
- frogml_cli/tools/utils.py +45 -0
- frogml_cli-0.0.1.dist-info/METADATA +51 -0
- frogml_cli-0.0.1.dist-info/RECORD +287 -0
- frogml_cli-0.0.1.dist-info/WHEEL +4 -0
- frogml_cli-0.0.1.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,140 @@
|
|
1
|
+
from datetime import datetime
|
2
|
+
from typing import List, Tuple
|
3
|
+
|
4
|
+
import click
|
5
|
+
from frogml._proto.qwak.feature_store.features.feature_set_pb2 import (
|
6
|
+
FeaturesetSchedulingState,
|
7
|
+
FeatureStatus,
|
8
|
+
)
|
9
|
+
from frogml._proto.qwak.feature_store.features.feature_set_service_pb2 import (
|
10
|
+
GetFeaturesetSchedulingStateResponse,
|
11
|
+
ListFeatureSetsResponse,
|
12
|
+
)
|
13
|
+
from frogml.core.clients.feature_store import FeatureRegistryClient
|
14
|
+
from tabulate import tabulate
|
15
|
+
|
16
|
+
from frogml_cli.inner.tools.cli_tools import FrogMLCommand
|
17
|
+
|
18
|
+
|
19
|
+
def _pts_to_datetime(pts) -> datetime:
|
20
|
+
return datetime.fromtimestamp(pts.seconds + pts.nanos / 1e9)
|
21
|
+
|
22
|
+
|
23
|
+
def _datetime_to_str(dt: datetime) -> str:
|
24
|
+
return dt.strftime("%Y-%b-%d %H:%M:%S")
|
25
|
+
|
26
|
+
|
27
|
+
def get_featureset_scheduling_state_as_str(
|
28
|
+
registry_client: FeatureRegistryClient,
|
29
|
+
featureset_name: str,
|
30
|
+
) -> str:
|
31
|
+
try:
|
32
|
+
resp: GetFeaturesetSchedulingStateResponse = (
|
33
|
+
registry_client.get_feature_set_scheduling_state(
|
34
|
+
featureset_name=featureset_name
|
35
|
+
)
|
36
|
+
)
|
37
|
+
if resp.state == FeaturesetSchedulingState.SCHEDULING_STATE_PAUSED:
|
38
|
+
return "Paused"
|
39
|
+
elif resp.state == FeaturesetSchedulingState.SCHEDULING_STATE_ENABLED:
|
40
|
+
return "Enabled"
|
41
|
+
else:
|
42
|
+
return "Unknown"
|
43
|
+
except Exception:
|
44
|
+
return "Unknown"
|
45
|
+
|
46
|
+
|
47
|
+
def _list_feature_sets_verbose(
|
48
|
+
resp: ListFeatureSetsResponse, registry_client: FeatureRegistryClient
|
49
|
+
) -> Tuple[List[str], List[str]]:
|
50
|
+
columns = [
|
51
|
+
"Name",
|
52
|
+
"Type",
|
53
|
+
"Status",
|
54
|
+
"Scheduling state",
|
55
|
+
"Owner",
|
56
|
+
"Description",
|
57
|
+
"Creation date",
|
58
|
+
"Last updated",
|
59
|
+
"Featureset id",
|
60
|
+
]
|
61
|
+
data = []
|
62
|
+
for feature_set in resp.feature_families:
|
63
|
+
definition = feature_set.feature_set_definition
|
64
|
+
spec = definition.feature_set_spec
|
65
|
+
metadata = feature_set.metadata
|
66
|
+
if not (spec.feature_set_type.WhichOneof("set_type")):
|
67
|
+
feature_set_type = ""
|
68
|
+
else:
|
69
|
+
feature_set_type = (
|
70
|
+
spec.feature_set_type.WhichOneof("set_type")
|
71
|
+
.replace("_", " ")
|
72
|
+
.capitalize()
|
73
|
+
)
|
74
|
+
|
75
|
+
sched_state: str = "Enabled"
|
76
|
+
if spec.feature_set_type.WhichOneof("set_type") in {
|
77
|
+
"batch_feature_set",
|
78
|
+
"batch_feature_set_v1",
|
79
|
+
}:
|
80
|
+
sched_state = get_featureset_scheduling_state_as_str(
|
81
|
+
registry_client, spec.name
|
82
|
+
)
|
83
|
+
|
84
|
+
data.append(
|
85
|
+
[
|
86
|
+
spec.name,
|
87
|
+
feature_set_type,
|
88
|
+
FeatureStatus.Name(definition.status),
|
89
|
+
sched_state,
|
90
|
+
spec.metadata.owner,
|
91
|
+
spec.metadata.description,
|
92
|
+
_datetime_to_str(_pts_to_datetime(metadata.created_at)),
|
93
|
+
_datetime_to_str(_pts_to_datetime(metadata.last_modified_at)),
|
94
|
+
definition.feature_set_id,
|
95
|
+
]
|
96
|
+
)
|
97
|
+
|
98
|
+
return (data, columns)
|
99
|
+
|
100
|
+
|
101
|
+
def _list_feature_sets(
|
102
|
+
resp: ListFeatureSetsResponse, registry_client: FeatureRegistryClient
|
103
|
+
) -> Tuple[List[str], List[str]]:
|
104
|
+
desired_columns = [
|
105
|
+
"Name",
|
106
|
+
"Type",
|
107
|
+
"Status",
|
108
|
+
"Scheduling state",
|
109
|
+
"Last updated",
|
110
|
+
]
|
111
|
+
verbose_data, verbose_columns = _list_feature_sets_verbose(resp, registry_client)
|
112
|
+
col_indexes = [verbose_columns.index(c) for c in desired_columns]
|
113
|
+
|
114
|
+
def project_lst(lst: List[str]) -> List[str]:
|
115
|
+
return [lst[idx] for idx in col_indexes]
|
116
|
+
|
117
|
+
data = [project_lst(d) for d in verbose_data]
|
118
|
+
|
119
|
+
return (data, desired_columns)
|
120
|
+
|
121
|
+
|
122
|
+
@click.command("list", cls=FrogMLCommand, help="List registered feature sets")
|
123
|
+
@click.option(
|
124
|
+
"--verbose",
|
125
|
+
"-v",
|
126
|
+
default=False,
|
127
|
+
is_flag=True,
|
128
|
+
metavar="FLAG",
|
129
|
+
help="Verbose output",
|
130
|
+
)
|
131
|
+
def list_feature_sets(verbose: bool, **kwargs):
|
132
|
+
registry_client = FeatureRegistryClient()
|
133
|
+
response = registry_client.list_feature_sets()
|
134
|
+
|
135
|
+
if verbose:
|
136
|
+
data, columns = _list_feature_sets_verbose(response, registry_client)
|
137
|
+
else:
|
138
|
+
data, columns = _list_feature_sets(response, registry_client)
|
139
|
+
|
140
|
+
print(tabulate(data, headers=columns))
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import click
|
2
|
+
from frogml.core.clients.feature_store import FeatureRegistryClient
|
3
|
+
from frogml.core.exceptions import FrogmlException
|
4
|
+
|
5
|
+
from frogml_cli.inner.tools.cli_tools import FrogMLCommand
|
6
|
+
from frogml_cli.tools.colors import Color
|
7
|
+
|
8
|
+
|
9
|
+
@click.command("pause", cls=FrogMLCommand, help="Pause a running feature set")
|
10
|
+
@click.argument("name")
|
11
|
+
def pause_feature_set(name, **kwargs):
|
12
|
+
try:
|
13
|
+
FeatureRegistryClient().pause_feature_set(feature_set_name=name)
|
14
|
+
except Exception as e:
|
15
|
+
print(f"{Color.RED} Failed to pause feature set {name} {Color.END}")
|
16
|
+
raise FrogmlException(f"Failed to pause feature set {name}") from e
|
17
|
+
|
18
|
+
print(f"{Color.GREEN}Successfully paused feature set {Color.YELLOW}{name}")
|
File without changes
|
@@ -0,0 +1,369 @@
|
|
1
|
+
from pathlib import Path
|
2
|
+
from typing import List, Optional, Tuple, cast
|
3
|
+
|
4
|
+
from frogml._proto.qwak.feature_store.entities.entity_pb2 import (
|
5
|
+
EntityDefinition as ProtoEntityDefinition,
|
6
|
+
)
|
7
|
+
from frogml._proto.qwak.feature_store.features.feature_set_pb2 import (
|
8
|
+
Feature as ProtoFeature,
|
9
|
+
)
|
10
|
+
from frogml._proto.qwak.feature_store.features.feature_set_service_pb2 import (
|
11
|
+
GetFeatureSetByNameResponse as ProtoGetFeatureSetByNameResponse,
|
12
|
+
)
|
13
|
+
from frogml.core.clients.feature_store import FeatureRegistryClient
|
14
|
+
from frogml.core.exceptions import FrogmlException
|
15
|
+
from frogml.core.feature_store.entities.entity import Entity
|
16
|
+
from frogml.core.feature_store.validations.validation_options import (
|
17
|
+
FeatureSetValidationOptions,
|
18
|
+
)
|
19
|
+
from frogml.core.feature_store.validations.validation_response import (
|
20
|
+
SuccessValidationResponse,
|
21
|
+
ValidationResponse,
|
22
|
+
)
|
23
|
+
from frogml.feature_store.data_sources.base import BaseSource
|
24
|
+
from frogml.feature_store.feature_sets.base_feature_set import BaseFeatureSet
|
25
|
+
from tabulate import tabulate
|
26
|
+
|
27
|
+
from frogml_cli.inner.file_registry import extract_class_objects
|
28
|
+
from frogml_cli.inner.tools.cli_tools import ask_yesno
|
29
|
+
from frogml_cli.tools.utils import frogml_spinner
|
30
|
+
|
31
|
+
DELIMITER = "----------------------------------------"
|
32
|
+
|
33
|
+
|
34
|
+
def _register_entities(
|
35
|
+
qwak_python_files: List[Tuple[str, str]],
|
36
|
+
registry: FeatureRegistryClient,
|
37
|
+
force: bool,
|
38
|
+
):
|
39
|
+
"""
|
40
|
+
Register Feature Store Entity Objects
|
41
|
+
|
42
|
+
Args:
|
43
|
+
qwak_python_files: a list of python files containing qwak package imports
|
44
|
+
registry: FeatureRegistryClient
|
45
|
+
force: boolean determining if to force register all encountered Entity objects
|
46
|
+
"""
|
47
|
+
with frogml_spinner(
|
48
|
+
begin_text="Finding Entities to register", print_callback=print
|
49
|
+
):
|
50
|
+
qwak_entities: List[Tuple[Entity, str]] = extract_class_objects(
|
51
|
+
qwak_python_files, Entity
|
52
|
+
)
|
53
|
+
|
54
|
+
print(f"👀 Found {len(qwak_entities)} Entities")
|
55
|
+
for entity, source_file_path in qwak_entities:
|
56
|
+
existing_entity = registry.get_entity_by_name(entity.name)
|
57
|
+
if existing_entity:
|
58
|
+
if ask_yesno(
|
59
|
+
f"Update existing Entity '{entity.name}' from source file '{source_file_path}'?",
|
60
|
+
force,
|
61
|
+
):
|
62
|
+
registry.update_entity(
|
63
|
+
existing_entity.entity.entity_definition.entity_id,
|
64
|
+
entity._to_proto(),
|
65
|
+
)
|
66
|
+
else:
|
67
|
+
if ask_yesno(
|
68
|
+
f"Create new Entity '{entity.name}' from source file '{source_file_path}'?",
|
69
|
+
force,
|
70
|
+
):
|
71
|
+
registry.create_entity(entity._to_proto())
|
72
|
+
print(DELIMITER)
|
73
|
+
|
74
|
+
|
75
|
+
def _register_data_sources(
|
76
|
+
qwak_python_files: List[Tuple[str, str]],
|
77
|
+
registry: FeatureRegistryClient,
|
78
|
+
force: bool,
|
79
|
+
no_validation: bool,
|
80
|
+
ignore_validation_errors: bool,
|
81
|
+
):
|
82
|
+
"""
|
83
|
+
Register Feature Store Data Source Objects
|
84
|
+
|
85
|
+
Args:
|
86
|
+
qwak_python_files: a list of python files containing qwak package imports
|
87
|
+
registry: FeatureRegistryClient
|
88
|
+
force: boolean determining if to force register all encountered Data Source objects
|
89
|
+
no_validation: whether to validate entities
|
90
|
+
ignore_validation_errors: whether to ignore and continue registering objects after encountering validation errors
|
91
|
+
"""
|
92
|
+
with frogml_spinner(
|
93
|
+
begin_text="Finding Data Sources to register", print_callback=print
|
94
|
+
):
|
95
|
+
qwak_sources: List[Tuple[BaseSource, str]] = extract_class_objects(
|
96
|
+
qwak_python_files, BaseSource
|
97
|
+
)
|
98
|
+
|
99
|
+
print(f"👀 Found {len(qwak_sources)} Data Sources")
|
100
|
+
for data_source, source_file_path in qwak_sources:
|
101
|
+
validation_failed = False
|
102
|
+
artifact_url: Optional[str] = None
|
103
|
+
|
104
|
+
if no_validation:
|
105
|
+
print("Skipping data source validation")
|
106
|
+
else:
|
107
|
+
try:
|
108
|
+
artifact_url = _handle_data_source_validation(data_source)
|
109
|
+
except Exception as e:
|
110
|
+
print(str(e))
|
111
|
+
validation_failed = True
|
112
|
+
|
113
|
+
if validation_failed and not ignore_validation_errors:
|
114
|
+
print("Not continuing to registration due to failure in validation")
|
115
|
+
exit(1)
|
116
|
+
|
117
|
+
existing_source = registry.get_data_source_by_name(data_source.name)
|
118
|
+
if existing_source:
|
119
|
+
if ask_yesno(
|
120
|
+
f"Update existing Data Source '{data_source.name}' from source file '{source_file_path}'?",
|
121
|
+
force,
|
122
|
+
):
|
123
|
+
data_source_proto, _ = data_source._prepare_and_get(
|
124
|
+
artifact_url=artifact_url,
|
125
|
+
source_definition_path=Path(source_file_path),
|
126
|
+
)
|
127
|
+
registry.update_data_source(
|
128
|
+
existing_source.data_source.data_source_definition.data_source_id,
|
129
|
+
data_source_proto,
|
130
|
+
)
|
131
|
+
else:
|
132
|
+
if ask_yesno(
|
133
|
+
f"Create Data Source '{data_source.name}' from source file '{source_file_path}'?",
|
134
|
+
force,
|
135
|
+
):
|
136
|
+
data_source_proto, _ = data_source._prepare_and_get(
|
137
|
+
artifact_url=artifact_url,
|
138
|
+
source_definition_path=Path(source_file_path),
|
139
|
+
)
|
140
|
+
registry.create_data_source(data_source_proto)
|
141
|
+
print(DELIMITER)
|
142
|
+
|
143
|
+
|
144
|
+
def _handle_data_source_validation(
|
145
|
+
data_source: BaseSource,
|
146
|
+
) -> Optional[str]:
|
147
|
+
print(f"Validating '{data_source.name}' data source")
|
148
|
+
with frogml_spinner(begin_text="", print_callback=print):
|
149
|
+
from frogml.feature_store.validations.validator import FeaturesOperatorValidator
|
150
|
+
|
151
|
+
v = FeaturesOperatorValidator()
|
152
|
+
response: ValidationResponse
|
153
|
+
artifact_url: Optional[str]
|
154
|
+
|
155
|
+
response, artifact_url = v.validate_data_source(data_source=data_source)
|
156
|
+
if isinstance(response, SuccessValidationResponse):
|
157
|
+
print_validation_outputs(response.stdout, response.stderr)
|
158
|
+
print("✅ Validation completed successfully, got data source columns:")
|
159
|
+
|
160
|
+
table = [(x.feature_name, x.feature_type) for x in response.features]
|
161
|
+
print(tabulate(table, headers=["column name", "type"]))
|
162
|
+
|
163
|
+
return artifact_url
|
164
|
+
else:
|
165
|
+
raise FrogmlException(f"🧨 Validation failed: \n{response}")
|
166
|
+
|
167
|
+
|
168
|
+
def _register_features_sets(
|
169
|
+
qwak_python_files: List[Tuple[str, str]],
|
170
|
+
registry: FeatureRegistryClient,
|
171
|
+
force: bool,
|
172
|
+
git_commit: str,
|
173
|
+
no_validation: bool,
|
174
|
+
ignore_validation_errors: bool,
|
175
|
+
data_source_limit: Optional[int] = None,
|
176
|
+
):
|
177
|
+
"""
|
178
|
+
Register Feature Store Feature Set Objects
|
179
|
+
|
180
|
+
Args:
|
181
|
+
qwak_python_files: a list of python files containing qwak package imports
|
182
|
+
registry: FeatureRegistryClient
|
183
|
+
force: boolean determining if to force register all encountered Feature Set objects
|
184
|
+
git_commit: the git commit of the parent folder
|
185
|
+
no_validation: whether to validate entities
|
186
|
+
ignore_validation_errors: whether to ignore and continue registering objects after encountering validation errors
|
187
|
+
"""
|
188
|
+
with frogml_spinner(
|
189
|
+
begin_text="Finding Feature Sets to register", print_callback=print
|
190
|
+
):
|
191
|
+
qwak_feature_sets = extract_class_objects(qwak_python_files, BaseFeatureSet)
|
192
|
+
|
193
|
+
print(f"👀 Found {len(qwak_feature_sets)} Feature Set(s)")
|
194
|
+
|
195
|
+
for featureset, source_file_path in qwak_feature_sets:
|
196
|
+
featureset = cast(BaseFeatureSet, featureset)
|
197
|
+
existing_feature_set: ProtoGetFeatureSetByNameResponse = (
|
198
|
+
registry.get_feature_set_by_name(featureset.name)
|
199
|
+
)
|
200
|
+
|
201
|
+
registration: bool = False
|
202
|
+
if existing_feature_set:
|
203
|
+
# Provide entity information of registered feature set before any other operation
|
204
|
+
if featureset.key:
|
205
|
+
featureset.entity = (
|
206
|
+
existing_feature_set.feature_set.feature_set_definition.feature_set_spec.entity.entity_spec.name
|
207
|
+
)
|
208
|
+
|
209
|
+
registration = ask_yesno(
|
210
|
+
f"Update existing feature set '{featureset.name}' from source file '{source_file_path}'?", # nosec B608
|
211
|
+
force,
|
212
|
+
)
|
213
|
+
else:
|
214
|
+
registration = ask_yesno(
|
215
|
+
f"Create new feature set '{featureset.name}' from source file '{source_file_path}'?",
|
216
|
+
force,
|
217
|
+
)
|
218
|
+
|
219
|
+
if registration:
|
220
|
+
features: Optional[List[ProtoFeature]] = []
|
221
|
+
artifact_url: Optional[str] = None
|
222
|
+
|
223
|
+
features, artifact_url = _validate_featureset(
|
224
|
+
featureset=featureset,
|
225
|
+
no_validation=no_validation,
|
226
|
+
ignore_validation_errors=ignore_validation_errors,
|
227
|
+
data_source_limit=data_source_limit,
|
228
|
+
)
|
229
|
+
|
230
|
+
proto_feature_set, _ = featureset._to_proto(
|
231
|
+
git_commit=git_commit,
|
232
|
+
features=features,
|
233
|
+
feature_registry=registry,
|
234
|
+
artifact_url=artifact_url,
|
235
|
+
)
|
236
|
+
|
237
|
+
if existing_feature_set:
|
238
|
+
registry.update_feature_set(
|
239
|
+
existing_feature_set.feature_set.feature_set_definition.feature_set_id,
|
240
|
+
proto_feature_set,
|
241
|
+
)
|
242
|
+
else:
|
243
|
+
_register_new_feature_set(
|
244
|
+
new_feature_set=featureset,
|
245
|
+
entity_key=proto_feature_set.entity,
|
246
|
+
registry=registry,
|
247
|
+
git_commit=git_commit,
|
248
|
+
features=features,
|
249
|
+
artifact_url=artifact_url,
|
250
|
+
)
|
251
|
+
|
252
|
+
|
253
|
+
def _register_new_feature_set(
|
254
|
+
new_feature_set: BaseFeatureSet,
|
255
|
+
entity_key: ProtoEntityDefinition,
|
256
|
+
registry: FeatureRegistryClient,
|
257
|
+
git_commit: str,
|
258
|
+
features: Optional[List[ProtoFeature]],
|
259
|
+
artifact_url: Optional[str] = None,
|
260
|
+
):
|
261
|
+
# Create entity for the defined key and set it as the fs's entity
|
262
|
+
if new_feature_set.key:
|
263
|
+
new_entity: Entity = Entity._from_proto(proto=entity_key)
|
264
|
+
try:
|
265
|
+
new_entity.register()
|
266
|
+
except FrogmlException:
|
267
|
+
raise FrogmlException(
|
268
|
+
f"Failed to create key for {new_feature_set.name}, "
|
269
|
+
f"aborting feature set creation"
|
270
|
+
)
|
271
|
+
new_feature_set.entity = new_entity.name
|
272
|
+
|
273
|
+
# this is done to retrieve the entities metadata
|
274
|
+
proto_feature_set, _ = new_feature_set._to_proto(
|
275
|
+
git_commit, features, registry, artifact_url=artifact_url
|
276
|
+
)
|
277
|
+
|
278
|
+
try:
|
279
|
+
registry.create_feature_set(proto_feature_set)
|
280
|
+
# rollback entity creation in case fs registration failed
|
281
|
+
except FrogmlException as e1:
|
282
|
+
try:
|
283
|
+
if new_feature_set.key:
|
284
|
+
registry.delete_entity(entity_id=proto_feature_set.entity.entity_id)
|
285
|
+
except FrogmlException:
|
286
|
+
raise e1
|
287
|
+
raise e1
|
288
|
+
|
289
|
+
|
290
|
+
def _handle_featureset_validation(
|
291
|
+
featureset: BaseFeatureSet,
|
292
|
+
data_source_limit: Optional[int] = None,
|
293
|
+
) -> Tuple[List[ProtoFeature], Optional[str]]:
|
294
|
+
print(f"Validating '{featureset.name}' feature set")
|
295
|
+
with frogml_spinner(begin_text="", print_callback=print):
|
296
|
+
from frogml.feature_store.validations.validator import FeaturesOperatorValidator
|
297
|
+
|
298
|
+
v = FeaturesOperatorValidator()
|
299
|
+
response: ValidationResponse
|
300
|
+
artifact_url: Optional[str]
|
301
|
+
validation_options = FeatureSetValidationOptions(
|
302
|
+
data_source_limit=data_source_limit
|
303
|
+
)
|
304
|
+
|
305
|
+
response, artifact_url = v.validate_featureset(
|
306
|
+
featureset=featureset, validation_options=validation_options
|
307
|
+
)
|
308
|
+
if isinstance(response, SuccessValidationResponse):
|
309
|
+
print_validation_outputs(response.stdout, response.stderr)
|
310
|
+
print("✅ Validation completed successfully, got data source columns:")
|
311
|
+
table = [(x.feature_name, x.feature_type) for x in response.features]
|
312
|
+
print(tabulate(table, headers=["column name", "type"]))
|
313
|
+
return response.features, artifact_url
|
314
|
+
else:
|
315
|
+
raise FrogmlException(f"🧨 Validation failed: \n{response}")
|
316
|
+
|
317
|
+
|
318
|
+
def _validate_featureset(
|
319
|
+
featureset: BaseFeatureSet,
|
320
|
+
no_validation: bool,
|
321
|
+
ignore_validation_errors: bool,
|
322
|
+
data_source_limit: Optional[int] = None,
|
323
|
+
) -> Tuple[List[ProtoFeature], Optional[str]]:
|
324
|
+
"""
|
325
|
+
Validates featureset transformation
|
326
|
+
Args:
|
327
|
+
featureset: BaseFeatureSet featureset
|
328
|
+
no_validation: skip validation
|
329
|
+
operator: Operator client
|
330
|
+
registry: Registry client
|
331
|
+
Returns:
|
332
|
+
Optional list of features returned from validation
|
333
|
+
"""
|
334
|
+
features: List[ProtoFeature] = []
|
335
|
+
artifact_url: Optional[str] = None
|
336
|
+
if not no_validation:
|
337
|
+
try:
|
338
|
+
features, artifact_url = _handle_featureset_validation(
|
339
|
+
featureset=featureset, data_source_limit=data_source_limit
|
340
|
+
)
|
341
|
+
except Exception as e:
|
342
|
+
print(str(e))
|
343
|
+
|
344
|
+
if not ignore_validation_errors:
|
345
|
+
print("Not continuing to registration due to failure in validation")
|
346
|
+
exit(1)
|
347
|
+
else:
|
348
|
+
print("Ignoring validation errors")
|
349
|
+
else:
|
350
|
+
print(f"Skipping validation for '{featureset.name}' feature set")
|
351
|
+
return features, artifact_url
|
352
|
+
|
353
|
+
|
354
|
+
def print_validation_outputs(stdout: str, stderr: str) -> bool:
|
355
|
+
did_print = False
|
356
|
+
|
357
|
+
if stdout or stderr:
|
358
|
+
message = "Validation outputs: "
|
359
|
+
|
360
|
+
if stdout:
|
361
|
+
message += f"stdout: {stdout}\n "
|
362
|
+
|
363
|
+
if stderr:
|
364
|
+
message += f"stderr: {stderr}"
|
365
|
+
|
366
|
+
print(message)
|
367
|
+
did_print = True
|
368
|
+
|
369
|
+
return did_print
|
@@ -0,0 +1,111 @@
|
|
1
|
+
import os
|
2
|
+
from pathlib import Path
|
3
|
+
from typing import List, Optional, Tuple
|
4
|
+
|
5
|
+
import click
|
6
|
+
from frogml.core.clients.feature_store import FeatureRegistryClient
|
7
|
+
|
8
|
+
from frogml_cli.commands.feature_store.register._logic import (
|
9
|
+
_register_data_sources,
|
10
|
+
_register_entities,
|
11
|
+
_register_features_sets,
|
12
|
+
)
|
13
|
+
from frogml_cli.inner.file_registry import list_qwak_python_files
|
14
|
+
from frogml_cli.inner.tools.cli_tools import FrogMLCommand
|
15
|
+
from frogml_cli.tools.utils import frogml_spinner
|
16
|
+
|
17
|
+
|
18
|
+
@click.command(
|
19
|
+
"register",
|
20
|
+
cls=FrogMLCommand,
|
21
|
+
help="Register and deploy all feature store object under the given path. Registered "
|
22
|
+
"features will be visible on the Frogml management platform after registration",
|
23
|
+
)
|
24
|
+
@click.option(
|
25
|
+
"--path",
|
26
|
+
"-p",
|
27
|
+
type=click.Path(exists=True),
|
28
|
+
metavar="PATH",
|
29
|
+
help="Directory / module where frogml feature store objects are stored",
|
30
|
+
)
|
31
|
+
@click.option(
|
32
|
+
"--force",
|
33
|
+
"-f",
|
34
|
+
default=False,
|
35
|
+
is_flag=True,
|
36
|
+
metavar="FLAG",
|
37
|
+
help="Force register all found frogml Feature Store objects",
|
38
|
+
)
|
39
|
+
@click.option(
|
40
|
+
"--no-validation",
|
41
|
+
"-nv",
|
42
|
+
default=False,
|
43
|
+
is_flag=True,
|
44
|
+
metavar="FLAG",
|
45
|
+
help="Skip validation for all found frogml Feature Store objects",
|
46
|
+
)
|
47
|
+
@click.option(
|
48
|
+
"--ignore-validation-errors",
|
49
|
+
"-ive",
|
50
|
+
default=False,
|
51
|
+
is_flag=True,
|
52
|
+
metavar="FLAG",
|
53
|
+
help="Ignore validation errors. Continue registering even if an error occurs",
|
54
|
+
)
|
55
|
+
@click.option(
|
56
|
+
"--fs-validation-ds-limit",
|
57
|
+
type=click.IntRange(1, 10000),
|
58
|
+
help="Limit the number of records to be fetched from each datasource during featureset validation",
|
59
|
+
)
|
60
|
+
def register_fs_objects(
|
61
|
+
path: Path,
|
62
|
+
force: bool,
|
63
|
+
no_validation: bool,
|
64
|
+
ignore_validation_errors: bool,
|
65
|
+
fs_validation_ds_limit: Optional[int],
|
66
|
+
**kwargs,
|
67
|
+
):
|
68
|
+
qwak_python_files: List[Tuple[str, str]]
|
69
|
+
|
70
|
+
if not path:
|
71
|
+
path = Path.cwd()
|
72
|
+
else:
|
73
|
+
path = Path(path)
|
74
|
+
|
75
|
+
if path.is_file():
|
76
|
+
qwak_python_files = [(str(path), os.path.abspath(path))]
|
77
|
+
elif Path.is_dir(path):
|
78
|
+
with frogml_spinner(
|
79
|
+
begin_text="Recursively looking for python files in input dir",
|
80
|
+
print_callback=print,
|
81
|
+
) as sp:
|
82
|
+
qwak_python_files = list_qwak_python_files(path, sp)
|
83
|
+
|
84
|
+
try:
|
85
|
+
import git
|
86
|
+
|
87
|
+
git_commit = git.Repo(path, search_parent_directories=True).head.commit.hexsha
|
88
|
+
except Exception:
|
89
|
+
# be super defensive on Git errors. Failing to fetch anything git related should not fail the registration
|
90
|
+
git_commit = None
|
91
|
+
|
92
|
+
registry_client = FeatureRegistryClient()
|
93
|
+
_register_entities(qwak_python_files, registry_client, force)
|
94
|
+
|
95
|
+
_register_data_sources(
|
96
|
+
qwak_python_files,
|
97
|
+
registry_client,
|
98
|
+
force,
|
99
|
+
no_validation,
|
100
|
+
ignore_validation_errors,
|
101
|
+
)
|
102
|
+
|
103
|
+
_register_features_sets(
|
104
|
+
qwak_python_files,
|
105
|
+
registry_client,
|
106
|
+
force,
|
107
|
+
git_commit,
|
108
|
+
no_validation,
|
109
|
+
ignore_validation_errors,
|
110
|
+
fs_validation_ds_limit,
|
111
|
+
)
|
File without changes
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import click
|
2
|
+
from frogml.core.clients.feature_store import FeatureRegistryClient
|
3
|
+
from frogml.core.exceptions import FrogmlException
|
4
|
+
|
5
|
+
from frogml_cli.inner.tools.cli_tools import FrogMLCommand
|
6
|
+
from frogml_cli.tools.colors import Color
|
7
|
+
|
8
|
+
|
9
|
+
@click.command("resume", cls=FrogMLCommand, help="Resume a paused feature set")
|
10
|
+
@click.argument("name")
|
11
|
+
def resume_feature_set(name, **kwargs):
|
12
|
+
try:
|
13
|
+
FeatureRegistryClient().resume_feature_set(feature_set_name=name)
|
14
|
+
except Exception as e:
|
15
|
+
print(f"{Color.RED} Failed to resume feature set {name} {Color.END}")
|
16
|
+
raise FrogmlException(f"Failed to resume feature set {name}") from e
|
17
|
+
|
18
|
+
print(f"{Color.GREEN}Successfully resume feature set {Color.YELLOW}{name}")
|
File without changes
|