expops 0.1.19.dev0__tar.gz → 0.1.22.dev0__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.
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/.github/workflows/release.yml +1 -1
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/PKG-INFO +3 -2
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/README.md +2 -1
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/caching.md +23 -4
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/reporting.md +9 -7
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/getting-started/creating-a-project.md +29 -2
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/getting-started/quick-start.md +1 -1
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/project-structure/configuration.md +2 -0
- expops-0.1.22.dev0/docs/project-structure/overview.md +59 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/templates/premier-league.md +20 -6
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/templates/sklearn-basic.md +22 -8
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/pyproject.toml +7 -4
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/__main__.py +1 -1
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/_version.py +3 -3
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/__init__.py +1 -1
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/config_schema.py +0 -1
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/custom/custom_adapter.py +70 -16
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/plugin_manager.py +2 -2
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/cluster/controller.py +65 -30
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/cluster/process_runner.py +5 -5
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/cluster/providers.py +3 -1
- expops-0.1.22.dev0/src/expops/core/__init__.py +106 -0
- expops-0.1.22.dev0/src/expops/core/cache_probe/__init__.py +13 -0
- expops-0.1.22.dev0/src/expops/core/cache_probe/cache_layout.py +101 -0
- expops-0.1.22.dev0/src/expops/core/cache_probe/probe_path.py +60 -0
- expops-0.1.22.dev0/src/expops/core/cache_probe/probe_path_selectors.py +317 -0
- expops-0.1.22.dev0/src/expops/core/execution/__init__.py +12 -0
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/execution}/dask_networkx_executor.py +158 -94
- expops-0.1.22.dev0/src/expops/core/execution/executor_worker.py +2553 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/executor_worker.py +132 -119
- expops-0.1.22.dev0/src/expops/core/graph/__init__.py +18 -0
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/graph}/graph_expansion.py +32 -16
- expops-0.1.22.dev0/src/expops/core/graph/networkx_parser.py +230 -0
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/graph}/pipeline_tree.py +131 -43
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/graph}/pipeline_utils.py +61 -7
- expops-0.1.22.dev0/src/expops/core/hashing/__init__.py +12 -0
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/hashing}/data_hashing.py +1 -1
- expops-0.1.22.dev0/src/expops/core/hashing/process_hashing.py +293 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/networkx_parser.py +13 -35
- expops-0.1.22.dev0/src/expops/core/parallelism_utils.py +148 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/probe_path_selectors.py +38 -56
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/process_hashing.py +16 -59
- expops-0.1.22.dev0/src/expops/core/runtime/__init__.py +14 -0
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/runtime}/payload_spill.py +65 -44
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/runtime}/step_state_manager.py +135 -102
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/runtime}/step_system.py +63 -35
- expops-0.1.22.dev0/src/expops/core/step_system.py +2 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/workspace.py +17 -3
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/conda_manager.py +2 -2
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/setup_env.py +1 -1
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/utils.py +50 -2
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/venv_manager.py +44 -3
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/main.py +154 -43
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/managers/project_manager.py +111 -151
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/managers/reproducibility_manager.py +38 -6
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/platform.py +215 -135
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/context.py +1 -30
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/entrypoint.py +21 -2
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/kv_utils.py +3 -3
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/registry.py +1 -1
- expops-0.1.22.dev0/src/expops/runtime/context.py +66 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/runtime/env_export.py +14 -6
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/gcp_kv_store.py +35 -8
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/gcs_object_store.py +8 -1
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/factory.py +42 -15
- expops-0.1.22.dev0/src/expops/templates/premier-league/.gitignore +21 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/premier-league/configs/compute_config.yaml +1 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/premier-league/configs/project_config.yaml +7 -8
- expops-0.1.19.dev0/src/mlops/templates/premier-league/charts/requirements.txt → expops-0.1.22.dev0/src/expops/templates/premier-league/requirements-charts.txt +0 -3
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/premier-league/requirements.txt +1 -1
- expops-0.1.22.dev0/src/expops/templates/premier-league/src/plot_metrics.py +207 -0
- {expops-0.1.19.dev0/src/mlops/templates/premier-league/models → expops-0.1.22.dev0/src/expops/templates/premier-league/src}/premier_league_model.py +232 -199
- expops-0.1.22.dev0/src/expops/templates/sklearn-basic/.gitignore +21 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/sklearn-basic/configs/compute_config.yaml +1 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/sklearn-basic/configs/project_config.yaml +4 -5
- expops-0.1.22.dev0/src/expops/templates/sklearn-basic/requirements-charts.txt +3 -0
- {expops-0.1.19.dev0/src/mlops/templates/sklearn-basic/models → expops-0.1.22.dev0/src/expops/templates/sklearn-basic/src}/model.py +22 -1
- {expops-0.1.19.dev0/src/mlops/templates/sklearn-basic/charts → expops-0.1.22.dev0/src/expops/templates/sklearn-basic/src}/plot_metrics.py +4 -3
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/server.py +63 -23
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/ui/mlops-charts.js +0 -5
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/ui/script.js +16 -12
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/PKG-INFO +3 -2
- expops-0.1.22.dev0/src/expops.egg-info/SOURCES.txt +169 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/top_level.txt +0 -1
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/conftest.py +2 -2
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/testing-plan.md +27 -24
- expops-0.1.22.dev0/tests/unit/test_cli/test_expops_run_infer_project.py +107 -0
- expops-0.1.22.dev0/tests/unit/test_cli/test_main_create_in_place.py +63 -0
- expops-0.1.22.dev0/tests/unit/test_core/test_cache_layout.py +83 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_dask_networkx_executor.py +100 -19
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_data_hashing.py +1 -1
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_executor_worker.py +159 -16
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_graph_expansion.py +79 -45
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_networkx_parser.py +1 -1
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_networkx_parser_code_field.py +1 -1
- expops-0.1.22.dev0/tests/unit/test_core/test_parallelism_utils.py +29 -0
- expops-0.1.22.dev0/tests/unit/test_core/test_payload_spill.py +126 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_pipeline_tree_steps.py +57 -4
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_prepare_runner_kwargs.py +1 -1
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_probe_path_selectors_xpath.py +82 -6
- expops-0.1.22.dev0/tests/unit/test_core/test_process_hashing.py +189 -0
- expops-0.1.22.dev0/tests/unit/test_core/test_step_state_manager.py +192 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_step_system.py +61 -5
- expops-0.1.22.dev0/tests/unit/test_environment_paths.py +92 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_managers/test_reproducibility_manager.py +1 -1
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_platform/test_dynamic_js_charts.py +76 -13
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_platform/test_project_metadata_resilience.py +21 -15
- expops-0.1.22.dev0/tests/unit/test_projects/test_custom_adapter_object_store.py +111 -0
- expops-0.1.22.dev0/tests/unit/test_projects/test_new_project_layout.py +42 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_reporting/test_entrypoint.py +31 -2
- expops-0.1.22.dev0/tests/unit/test_runtime/__init__.py +1 -0
- expops-0.1.22.dev0/tests/unit/test_runtime/test_context.py +58 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/test_factory.py +12 -14
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/test_gcp_kv_store.py +78 -15
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/test_gcs_object_store.py +7 -7
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/test_sqlite_store.py +1 -3
- expops-0.1.22.dev0/tests/unit/test_storage/test_step_state_manager_layout.py +51 -0
- expops-0.1.22.dev0/tests/unit/test_web/test_chart_config.py +51 -0
- expops-0.1.19.dev0/docs/project-structure/overview.md +0 -55
- expops-0.1.19.dev0/src/expops/__init__.py +0 -37
- expops-0.1.19.dev0/src/expops/__main__.py +0 -8
- expops-0.1.19.dev0/src/expops/core/__init__.py +0 -15
- expops-0.1.19.dev0/src/expops/main.py +0 -13
- expops-0.1.19.dev0/src/expops/reporting/__init__.py +0 -5
- expops-0.1.19.dev0/src/expops/reporting/context.py +0 -5
- expops-0.1.19.dev0/src/expops/reporting/registry.py +0 -5
- expops-0.1.19.dev0/src/expops/web/__init__.py +0 -3
- expops-0.1.19.dev0/src/expops/web/server.py +0 -17
- expops-0.1.19.dev0/src/expops.egg-info/SOURCES.txt +0 -153
- expops-0.1.19.dev0/src/mlops/core/__init__.py +0 -95
- expops-0.1.19.dev0/src/mlops/runtime/context.py +0 -37
- expops-0.1.19.dev0/src/mlops/templates/premier-league/charts/plot_metrics.py +0 -201
- expops-0.1.19.dev0/src/mlops/templates/sklearn-basic/README.md +0 -22
- expops-0.1.19.dev0/src/mlops/templates/sklearn-basic/charts/requirements.txt +0 -3
- expops-0.1.19.dev0/tests/unit/test_core/test_payload_spill.py +0 -80
- expops-0.1.19.dev0/tests/unit/test_core/test_process_hashing.py +0 -77
- expops-0.1.19.dev0/tests/unit/test_core/test_step_state_manager.py +0 -90
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/.github/workflows/ci.yml +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/.gitignore +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/LICENSE +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/advanced/backends.md +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/data-parallelism.md +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/distributed.md +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/environments.md +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/pipelines.md +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/seed-parallelism.md +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/index.md +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/project-structure/model-code.md +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/requirements.txt +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/web-ui/local-ui.md +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/setup.cfg +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/base.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/custom/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/sklearn/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/sklearn/adapter.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/cluster/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/compute_config.py +0 -0
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/graph}/graph_types.py +0 -0
- {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/runtime}/custom_model_base.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/base.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/factory.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/pyenv_manager.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/system_manager.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/runtime/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/memory_store.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/redis_store.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/sqlite_store.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/interfaces/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/interfaces/kv_store.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/path_utils.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/premier-league/data/England CSV.csv +0 -0
- {expops-0.1.19.dev0/src/mlops/templates/premier-league/charts → expops-0.1.22.dev0/src/expops/templates/premier-league/src}/plot_metrics.js +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/sklearn-basic/data/train.csv +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/sklearn-basic/requirements.txt +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/__init__.py +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/ui/index.html +0 -0
- {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/ui/styles.css +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/dependency_links.txt +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/entry_points.txt +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/requires.txt +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/__init__.py +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/__init__.py +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_managers/__init__.py +0 -0
- {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: expops
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.22.dev0
|
|
4
4
|
Summary: MLOps Platform with step-based pipeline execution
|
|
5
5
|
License: GNU GENERAL PUBLIC LICENSE
|
|
6
6
|
Version 3, 29 June 2007
|
|
@@ -722,6 +722,7 @@ The installed CLI command is **`expops`**.
|
|
|
722
722
|
|
|
723
723
|
### Prerequisites
|
|
724
724
|
|
|
725
|
+
- Python 3.10
|
|
725
726
|
- Git installed and configured
|
|
726
727
|
- Access to the project repository
|
|
727
728
|
- Required dependencies installed
|
|
@@ -731,7 +732,7 @@ The installed CLI command is **`expops`**.
|
|
|
731
732
|
```bash
|
|
732
733
|
# Clone the repository
|
|
733
734
|
git clone <repository-url>
|
|
734
|
-
cd
|
|
735
|
+
cd expops-platform
|
|
735
736
|
|
|
736
737
|
# Create and activate a virtual environment
|
|
737
738
|
python -m venv .venv
|
|
@@ -16,6 +16,7 @@ The installed CLI command is **`expops`**.
|
|
|
16
16
|
|
|
17
17
|
### Prerequisites
|
|
18
18
|
|
|
19
|
+
- Python 3.10
|
|
19
20
|
- Git installed and configured
|
|
20
21
|
- Access to the project repository
|
|
21
22
|
- Required dependencies installed
|
|
@@ -25,7 +26,7 @@ The installed CLI command is **`expops`**.
|
|
|
25
26
|
```bash
|
|
26
27
|
# Clone the repository
|
|
27
28
|
git clone <repository-url>
|
|
28
|
-
cd
|
|
29
|
+
cd expops-platform
|
|
29
30
|
|
|
30
31
|
# Create and activate a virtual environment
|
|
31
32
|
python -m venv .venv
|
|
@@ -7,12 +7,12 @@ ExpOps provides intelligent multi-level caching and reproducibility guarantees.
|
|
|
7
7
|
When caching is enabled, the platform separates **lightweight manifests** from **heavy artifacts**:
|
|
8
8
|
|
|
9
9
|
- **Step/process manifests (`.pkl` files)**:
|
|
10
|
-
-
|
|
10
|
+
- In GCS, stored under a project-scoped cache path: `gs://<bucket>/<project_id>/cache/steps/<run_id>/...`.
|
|
11
11
|
- Contain small Python dictionaries describing the result of a step or process.
|
|
12
12
|
- Heavy artifacts (models, large arrays) are represented as *references* rather than inlined objects.
|
|
13
|
-
- **Models (`
|
|
13
|
+
- **Models (`model_spill/` prefix)**:
|
|
14
14
|
- Any recognized model object (for example, most `sklearn` and `xgboost` estimators) is always serialized separately.
|
|
15
|
-
- Stored as `.joblib` blobs under a `
|
|
15
|
+
- Stored as `.joblib` blobs under a `model_spill/<process_name>/...` path.
|
|
16
16
|
- **Payloads (`payloads/` prefix)**:
|
|
17
17
|
- Large array-like payloads (NumPy arrays, lists/tuples coercible to arrays) above a small size threshold are stored as compressed `.npz` blobs.
|
|
18
18
|
|
|
@@ -66,7 +66,26 @@ Remote backend for shared caching:
|
|
|
66
66
|
- Persistent storage.
|
|
67
67
|
- Requires GCP credentials.
|
|
68
68
|
|
|
69
|
-
When an object store is configured, manifests are written as `.pkl` blobs and heavy artifacts are written under the `
|
|
69
|
+
When an object store is configured, manifests are written as `.pkl` blobs and heavy artifacts are written under the `model_spill/` and `payloads/` prefixes in the same bucket. When no object store is configured, all of these artifacts are stored on the local filesystem under the project cache directory.
|
|
70
|
+
|
|
71
|
+
With GCS enabled, the layout within the bucket is project-scoped:
|
|
72
|
+
|
|
73
|
+
- Step/process manifests are stored under `gs://<bucket>/<project_id>/cache/steps/<run_id>/...`.
|
|
74
|
+
- Spilled models are stored under `gs://<bucket>/<project_id>/model_spill/<process_name>/...`.
|
|
75
|
+
- Spilled large payloads are stored under `gs://<bucket>/<project_id>/payloads/<run_id>/<process_name>/...`.
|
|
76
|
+
|
|
77
|
+
When no object store is configured, manifests and heavy artifacts are stored on the local filesystem under the project's hidden runtime cache directory, typically under:
|
|
78
|
+
|
|
79
|
+
- `.<project_id>/cache/<version_hash>/<encoded_probe_path>/steps/` for step/process manifests.
|
|
80
|
+
- `.<project_id>/cache/<version_hash>/<encoded_probe_path>/model_spill/` for spilled models.
|
|
81
|
+
- `.<project_id>/cache/<version_hash>/<encoded_probe_path>/payloads/` for spilled large payloads.
|
|
82
|
+
|
|
83
|
+
**Artifacts** (charts, reproducibility outputs) use the same version/probe layout for consistency:
|
|
84
|
+
|
|
85
|
+
- **Local**: `.<project_id>/artifacts/<version_hash>/<encoded_probe_path>/<filename>.png`
|
|
86
|
+
- **GCS**: `gs://<bucket>/<project_id>/artifacts/<version_hash>/<encoded_probe_path>/<filename>.png`
|
|
87
|
+
|
|
88
|
+
Both cache and artifacts share the same `version_hash` (from project config + scripts) and `encoded_probe_path` (from process/step identity).
|
|
70
89
|
|
|
71
90
|
## Configuration
|
|
72
91
|
|
|
@@ -16,8 +16,8 @@ Functions decorated with `@chart()` generate visualizations. **Chart functions h
|
|
|
16
16
|
|
|
17
17
|
**Every static chart function MUST:**
|
|
18
18
|
1. Accept `metrics` as the first parameter (Dict[str, Any])
|
|
19
|
-
2. Accept `ctx` as the second parameter (ChartContext)
|
|
20
|
-
3. Use `
|
|
19
|
+
2. Accept `ctx` as the second parameter (ChartContext), for metrics and optional context
|
|
20
|
+
3. Use `plt.savefig()` to save figures (the process runs with cwd set to the output directory; all files written there are synced to artifacts)
|
|
21
21
|
|
|
22
22
|
```python
|
|
23
23
|
from expops.reporting import chart, ChartContext
|
|
@@ -29,7 +29,7 @@ def plot_metrics(metrics: Dict[str, Any], ctx: ChartContext) -> None:
|
|
|
29
29
|
"""
|
|
30
30
|
Chart function signature requirements:
|
|
31
31
|
- metrics: Dict containing metrics from probe_paths (REQUIRED)
|
|
32
|
-
- ctx: ChartContext for
|
|
32
|
+
- ctx: ChartContext for metrics and run context (REQUIRED)
|
|
33
33
|
- Returns: None (void function)
|
|
34
34
|
"""
|
|
35
35
|
# Access metrics directly from the metrics dict
|
|
@@ -45,8 +45,8 @@ def plot_metrics(metrics: Dict[str, Any], ctx: ChartContext) -> None:
|
|
|
45
45
|
fig, ax = plt.subplots(figsize=(10, 6))
|
|
46
46
|
# ... plotting code ...
|
|
47
47
|
|
|
48
|
-
#
|
|
49
|
-
|
|
48
|
+
# Use plt.savefig() with a relative path; cwd is the process output dir
|
|
49
|
+
plt.savefig('plot_metrics.png', dpi=150)
|
|
50
50
|
plt.close(fig)
|
|
51
51
|
```
|
|
52
52
|
|
|
@@ -77,6 +77,7 @@ The chart function receives:
|
|
|
77
77
|
```python
|
|
78
78
|
@chart()
|
|
79
79
|
def my_chart(metrics: Dict[str, Any], ctx: ChartContext) -> None:
|
|
80
|
+
import matplotlib.pyplot as plt
|
|
80
81
|
# metrics['train'] contains metrics from train_model process
|
|
81
82
|
train_data = metrics.get('train', {})
|
|
82
83
|
|
|
@@ -113,10 +114,11 @@ Common patterns:
|
|
|
113
114
|
|
|
114
115
|
### Output
|
|
115
116
|
|
|
116
|
-
Static charts produce image files (PNG) saved
|
|
117
|
+
Static charts produce image files (PNG) saved under the unified artifacts layout:
|
|
117
118
|
```
|
|
118
|
-
artifacts
|
|
119
|
+
.<project_id>/artifacts/<version_hash>/<encoded_probe_path>/<chart_name>.png
|
|
119
120
|
```
|
|
121
|
+
In GCS: `gs://<bucket>/<project_id>/artifacts/<version_hash>/<encoded_probe_path>/<chart_name>.png`
|
|
120
122
|
|
|
121
123
|
## Dynamic Charts
|
|
122
124
|
|
|
@@ -10,6 +10,13 @@ Templates provide a pre-configured project structure with example code:
|
|
|
10
10
|
expops create my-project --template sklearn-basic
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
+
You can also create *in the current directory* (project name inferred from the folder name):
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
mkdir my-project && cd my-project
|
|
17
|
+
expops create --template sklearn-basic
|
|
18
|
+
```
|
|
19
|
+
|
|
13
20
|
Available templates:
|
|
14
21
|
- `sklearn-basic`: Runnable project skeleton with a tiny sklearn model
|
|
15
22
|
- `premier-league`: Comprehensive ML project with cluster config and dynamic charts
|
|
@@ -26,6 +33,13 @@ expops create my-project
|
|
|
26
33
|
|
|
27
34
|
This creates a minimal project structure that you can customize.
|
|
28
35
|
|
|
36
|
+
You can also create *in the current directory* (project name inferred from the folder name):
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
mkdir my-project && cd my-project
|
|
40
|
+
expops create
|
|
41
|
+
```
|
|
42
|
+
|
|
29
43
|
## Project Structure
|
|
30
44
|
|
|
31
45
|
After creation, your project will have the following structure:
|
|
@@ -33,15 +47,28 @@ After creation, your project will have the following structure:
|
|
|
33
47
|
```
|
|
34
48
|
my-project/
|
|
35
49
|
├── .gitignore
|
|
50
|
+
├── .my-project/
|
|
51
|
+
│ ├── envs/
|
|
52
|
+
│ ├── logs/
|
|
53
|
+
│ ├── cache/<version_hash>/<encoded_probe_path>/
|
|
54
|
+
│ ├── artifacts/<version_hash>/<encoded_probe_path>/
|
|
55
|
+
│ └── metrics.sqlite
|
|
36
56
|
├── configs/
|
|
37
57
|
│ └── project_config.yaml
|
|
38
|
-
├──
|
|
39
|
-
├──
|
|
58
|
+
├── src/
|
|
59
|
+
│ ├── models/
|
|
60
|
+
│ └── charts/
|
|
40
61
|
├── data/
|
|
41
62
|
├── requirements.txt
|
|
42
63
|
└── ...
|
|
43
64
|
```
|
|
44
65
|
|
|
66
|
+
The `.my-project/envs/` directory holds the Python virtual environments for
|
|
67
|
+
this project (for example `.my-project/envs/my-project-env`). Older versions
|
|
68
|
+
of the platform used a workspace-level `.venvs/` folder; that location is now
|
|
69
|
+
deprecated for project runs, and new environments are created only under each
|
|
70
|
+
project’s hidden `.my-project/envs/` directory.
|
|
71
|
+
|
|
45
72
|
## Configuration Notes
|
|
46
73
|
|
|
47
74
|
### Caching and Web UI
|
|
@@ -67,7 +67,7 @@ experiment:
|
|
|
67
67
|
# object_store:
|
|
68
68
|
# type: gcs
|
|
69
69
|
# bucket: <your-gcs-bucket-name>
|
|
70
|
-
#
|
|
70
|
+
# # Manifests will be stored under gs://<bucket>/<project_id>/cache/steps/ automatically.
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
**Setup steps for GCP (Firestore)**:
|
|
@@ -20,6 +20,7 @@ environment: # Named environments (requirements/env files + type)
|
|
|
20
20
|
reproducibility: # Random seed configuration
|
|
21
21
|
data: # Data sources and data path for hashing
|
|
22
22
|
experiment: # Model framework, paths, parameters, pipeline, cache
|
|
23
|
+
execution: # Optional: e.g. execution.workspace.base_dir (temp dir; default tmp)
|
|
23
24
|
reporting: # Chart entrypoints, probe paths, reporting environment
|
|
24
25
|
```
|
|
25
26
|
|
|
@@ -36,6 +37,7 @@ reporting: # Chart entrypoints, probe paths, reporting environment
|
|
|
36
37
|
- See [Caching & Reproducibility](../features/caching.md) and [Backends](../advanced/backends.md) for details
|
|
37
38
|
- **`reporting`**: Chart entrypoints and chart definitions
|
|
38
39
|
- See [Reporting Features](../features/reporting.md) for details
|
|
40
|
+
- **`execution.workspace`**: Optional. Per-process temporary workspace base path. Set `base_dir` to control where process run directories are created (e.g. `base_dir: "/tmp"`). Default is `tmp` (i.e. `/tmp` on Unix).
|
|
39
41
|
|
|
40
42
|
### Defaults that reduce config
|
|
41
43
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Project Structure Overview
|
|
2
|
+
|
|
3
|
+
Each ExpOps project follows a standardized directory structure that organizes configuration, code, data, and artifacts.
|
|
4
|
+
|
|
5
|
+
## Directory Layout
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
my-project/
|
|
9
|
+
├── configs/
|
|
10
|
+
│ ├── project_config.yaml # Main project configuration
|
|
11
|
+
│ └── compute_config.yaml # Optional cluster configuration
|
|
12
|
+
├── src/
|
|
13
|
+
│ ├── <model_name>.py # Model implementation (main script)
|
|
14
|
+
│ ├── plot_metrics.py # Static chart generation
|
|
15
|
+
│ ├── plot_metrics.js # Optional dynamic chart generation
|
|
16
|
+
│ └── ... # Other project modules
|
|
17
|
+
├── data/ # Input datasets
|
|
18
|
+
├── requirements.txt # Main project dependencies
|
|
19
|
+
├── requirements-charts.txt # Chart/reporting dependencies
|
|
20
|
+
└── .<project_id>/ # Runtime directory (hidden)
|
|
21
|
+
├── envs/ # Project virtual environments
|
|
22
|
+
├── logs/ # Execution logs
|
|
23
|
+
├── cache/ # Step/process cache
|
|
24
|
+
│ └── <version_hash>/<encoded_probe_path>/
|
|
25
|
+
└── artifacts/ # Charts and other artifacts
|
|
26
|
+
└── <version_hash>/<encoded_probe_path>/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For GCP-backed backends (e.g. Firestore), set the path to your credentials file in your config (e.g. `credentials_json: src/firestore.json` or `credentials_json: firestore.json`).
|
|
30
|
+
|
|
31
|
+
## Key Components
|
|
32
|
+
|
|
33
|
+
### Configuration Files
|
|
34
|
+
|
|
35
|
+
The `configs/` directory contains all project configuration:
|
|
36
|
+
- **project_config.yaml**: Main configuration (required)
|
|
37
|
+
- **compute_config.yaml**: Cluster execution settings (optional)
|
|
38
|
+
|
|
39
|
+
See [Configuration Files](configuration.md) for details.
|
|
40
|
+
|
|
41
|
+
### Model Code
|
|
42
|
+
|
|
43
|
+
The `src/` directory contains your ML pipeline and reporting scripts. The main model script (e.g. `<model_name>.py`) is referenced in `project_config.yaml` under `scripts.main`:
|
|
44
|
+
- Process definitions with `@process()` decorator
|
|
45
|
+
- Step functions with `@step()` decorator
|
|
46
|
+
- Pipeline logic and data transformations
|
|
47
|
+
|
|
48
|
+
See [Model Code](model-code.md) for details.
|
|
49
|
+
|
|
50
|
+
### Chart Generation
|
|
51
|
+
|
|
52
|
+
Chart scripts live under `src/` and are referenced in config (`scripts.reporting`, `scripts.reporting_js`):
|
|
53
|
+
- **plot_metrics.py**: Static PNG chart generation
|
|
54
|
+
- **plot_metrics.js**: Optional dynamic interactive charts
|
|
55
|
+
|
|
56
|
+
### Dependencies
|
|
57
|
+
|
|
58
|
+
- **requirements.txt**: Main dependencies for training/inference
|
|
59
|
+
- **requirements-charts.txt**: Reporting/chart dependencies
|
|
@@ -20,19 +20,33 @@ expops create my-project --template premier-league
|
|
|
20
20
|
|
|
21
21
|
```
|
|
22
22
|
my-project/
|
|
23
|
+
├── .my-project/
|
|
24
|
+
│ ├── envs/
|
|
25
|
+
│ ├── logs/
|
|
26
|
+
│ ├── cache/<version_hash>/<encoded_probe_path>/
|
|
27
|
+
│ ├── artifacts/<version_hash>/<encoded_probe_path>/
|
|
28
|
+
│ └── metrics.sqlite
|
|
23
29
|
├── configs/
|
|
24
30
|
│ ├── project_config.yaml
|
|
25
31
|
│ └── compute_config.yaml
|
|
26
|
-
├──
|
|
27
|
-
│
|
|
28
|
-
|
|
29
|
-
│
|
|
30
|
-
│
|
|
31
|
-
│
|
|
32
|
+
├── src/
|
|
33
|
+
│ ├── models/
|
|
34
|
+
│ │ └── premier_league_model.py
|
|
35
|
+
│ └── charts/
|
|
36
|
+
│ ├── plot_metrics.py
|
|
37
|
+
│ └── plot_metrics.js
|
|
32
38
|
├── requirements.txt
|
|
39
|
+
├── requirements-charts.txt
|
|
33
40
|
└── data/
|
|
41
|
+
└── England CSV.csv
|
|
34
42
|
```
|
|
35
43
|
|
|
44
|
+
When you run the template, its virtual environments are created under the
|
|
45
|
+
project-local hidden `.my-project/envs/` directory (for example
|
|
46
|
+
`.my-project/envs/premier-league-env`). The older workspace-level `.venvs/`
|
|
47
|
+
directory is kept only for legacy, non-project usage and is no longer used
|
|
48
|
+
for project runs.
|
|
49
|
+
|
|
36
50
|
## Features Demonstrated
|
|
37
51
|
|
|
38
52
|
### Distributed Execution
|
|
@@ -20,17 +20,31 @@ expops create my-project --template sklearn-basic
|
|
|
20
20
|
|
|
21
21
|
```
|
|
22
22
|
my-project/
|
|
23
|
+
├── .my-project/
|
|
24
|
+
│ ├── envs/
|
|
25
|
+
│ ├── logs/
|
|
26
|
+
│ ├── cache/<version_hash>/<encoded_probe_path>/
|
|
27
|
+
│ ├── artifacts/<version_hash>/<encoded_probe_path>/
|
|
28
|
+
│ └── metrics.sqlite
|
|
23
29
|
├── configs/
|
|
24
30
|
│ └── project_config.yaml
|
|
25
|
-
├──
|
|
26
|
-
│
|
|
27
|
-
|
|
28
|
-
│
|
|
29
|
-
│
|
|
31
|
+
├── src/
|
|
32
|
+
│ ├── models/
|
|
33
|
+
│ │ └── model.py
|
|
34
|
+
│ └── charts/
|
|
35
|
+
│ └── plot_metrics.py
|
|
30
36
|
├── requirements.txt
|
|
37
|
+
├── requirements-charts.txt
|
|
31
38
|
└── data/
|
|
39
|
+
└── train.csv
|
|
32
40
|
```
|
|
33
41
|
|
|
42
|
+
Project-specific Python virtual environments are created under the hidden
|
|
43
|
+
runtime directory `.my-project/envs/` (for example
|
|
44
|
+
`.my-project/envs/sklearn-basic-env`). Earlier versions of the platform used
|
|
45
|
+
a workspace-level `.venvs/` directory; that location is now deprecated for
|
|
46
|
+
project runs.
|
|
47
|
+
|
|
34
48
|
## Running
|
|
35
49
|
|
|
36
50
|
Run locally:
|
|
@@ -49,6 +63,6 @@ The template uses:
|
|
|
49
63
|
## Customization
|
|
50
64
|
|
|
51
65
|
You can customize:
|
|
52
|
-
- Experiment parameters in `project_config.yaml`
|
|
53
|
-
- Pipeline steps in `models/
|
|
54
|
-
- Chart visualizations in `charts/plot_metrics.py`
|
|
66
|
+
- Experiment parameters in `configs/project_config.yaml`
|
|
67
|
+
- Pipeline steps in `src/models/model.py`
|
|
68
|
+
- Chart visualizations in `src/charts/plot_metrics.py`
|
|
@@ -55,8 +55,8 @@ include-package-data = true
|
|
|
55
55
|
where = ["src"]
|
|
56
56
|
|
|
57
57
|
[tool.setuptools.package-data]
|
|
58
|
-
"
|
|
59
|
-
"
|
|
58
|
+
"expops.web" = ["ui/*"]
|
|
59
|
+
"expops" = [
|
|
60
60
|
"templates/*/*",
|
|
61
61
|
"templates/*/*/*",
|
|
62
62
|
"templates/*/*/*/*",
|
|
@@ -64,9 +64,12 @@ where = ["src"]
|
|
|
64
64
|
|
|
65
65
|
[tool.setuptools_scm]
|
|
66
66
|
local_scheme = "no-local-version"
|
|
67
|
-
write_to = "src/
|
|
67
|
+
write_to = "src/expops/_version.py"
|
|
68
|
+
# Use this version when building without git (e.g. on a cluster with only copied files)
|
|
69
|
+
fallback_version = "0.0.0"
|
|
68
70
|
|
|
69
71
|
[tool.pytest.ini_options]
|
|
70
72
|
pythonpath = ["src"]
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
[tool.ruff.lint]
|
|
75
|
+
ignore = ["F401", "F841", "E402"]
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.1.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 1,
|
|
31
|
+
__version__ = version = '0.1.22.dev0'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 1, 22, 'dev0')
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'ga532cd5e9'
|
{expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/custom/custom_adapter.py
RENAMED
|
@@ -9,11 +9,11 @@ import time
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import Any, Dict, Optional
|
|
11
11
|
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from
|
|
16
|
-
from
|
|
12
|
+
from expops.core import StepStateManager, get_context_factory, get_step_registry, set_current_context
|
|
13
|
+
from expops.core.compute_config import load_compute_config, map_compute_to_executor
|
|
14
|
+
from expops.core.runtime.custom_model_base import MLOpsCustomModelBase
|
|
15
|
+
from expops.core.execution.dask_networkx_executor import DaskNetworkXExecutor
|
|
16
|
+
from expops.core.graph.networkx_parser import parse_networkx_pipeline_from_config
|
|
17
17
|
|
|
18
18
|
from ..base import ModelAdapter
|
|
19
19
|
from ..config_schema import AdapterConfig
|
|
@@ -75,6 +75,8 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
75
75
|
self.step_registry = get_step_registry()
|
|
76
76
|
self.step_state_manager: StepStateManager | None = None
|
|
77
77
|
self.networkx_executor: DaskNetworkXExecutor | None = None
|
|
78
|
+
self._local_cluster: Any = None
|
|
79
|
+
self._local_client: Any = None
|
|
78
80
|
self.logger = logging.getLogger(__name__)
|
|
79
81
|
self._script_paths: list[Path] = []
|
|
80
82
|
self._chart_script_paths: list[Path] = []
|
|
@@ -84,7 +86,7 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
84
86
|
def _repo_root(self) -> Path:
|
|
85
87
|
"""Best-effort workspace root resolution (where projects live)."""
|
|
86
88
|
try:
|
|
87
|
-
from
|
|
89
|
+
from expops.core.workspace import get_workspace_root
|
|
88
90
|
return get_workspace_root()
|
|
89
91
|
except Exception:
|
|
90
92
|
return Path.cwd()
|
|
@@ -128,7 +130,7 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
128
130
|
except Exception:
|
|
129
131
|
pass
|
|
130
132
|
try:
|
|
131
|
-
from
|
|
133
|
+
from expops.core.workspace import infer_source_root
|
|
132
134
|
|
|
133
135
|
src_root = infer_source_root()
|
|
134
136
|
if src_root:
|
|
@@ -145,7 +147,8 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
145
147
|
"""Initialize the adapter: import model module, configure caching, and set up the executor."""
|
|
146
148
|
self.logger = logging.getLogger(__name__)
|
|
147
149
|
|
|
148
|
-
# Load scripts
|
|
150
|
+
# Load scripts and execution.workspace from config file
|
|
151
|
+
full_config: Dict[str, Any] = {}
|
|
149
152
|
try:
|
|
150
153
|
if self.project_path:
|
|
151
154
|
config_path = self.project_path / "configs" / "project_config.yaml"
|
|
@@ -159,6 +162,12 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
159
162
|
self._default_script = next(iter(self._scripts_section)) if self._scripts_section else None
|
|
160
163
|
except Exception as e:
|
|
161
164
|
self.logger.warning(f"Failed to load scripts section from config: {e}")
|
|
165
|
+
|
|
166
|
+
execution_workspace = getattr(self.run_context, "execution_workspace", None) if self.run_context else None
|
|
167
|
+
if execution_workspace is None and full_config:
|
|
168
|
+
from expops.runtime.context import parse_execution_workspace_config
|
|
169
|
+
exec_cfg = full_config.get("execution") if isinstance(full_config.get("execution"), dict) else {}
|
|
170
|
+
execution_workspace = parse_execution_workspace_config(exec_cfg.get("workspace") if isinstance(exec_cfg.get("workspace"), dict) else None)
|
|
162
171
|
|
|
163
172
|
scripts_section = self._scripts_section
|
|
164
173
|
default_script = self._default_script
|
|
@@ -172,7 +181,7 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
172
181
|
missing_script_paths: list[str] = []
|
|
173
182
|
|
|
174
183
|
# Import resolve_script_path helper
|
|
175
|
-
from
|
|
184
|
+
from expops.core.graph.pipeline_utils import resolve_script_path
|
|
176
185
|
|
|
177
186
|
for proc in process_cfgs:
|
|
178
187
|
if not isinstance(proc, dict):
|
|
@@ -293,14 +302,27 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
293
302
|
cache_config = _as_dict(cache_config)
|
|
294
303
|
cache_ttl_hours = cache_config.get("ttl_hours", 24) if isinstance(cache_config, dict) else 24
|
|
295
304
|
|
|
296
|
-
step_cache_dir
|
|
305
|
+
step_cache_dir: Path
|
|
306
|
+
env_cache_dir = os.getenv("MLOPS_STEP_CACHE_DIR")
|
|
307
|
+
if env_cache_dir:
|
|
308
|
+
step_cache_dir = Path(env_cache_dir)
|
|
309
|
+
elif self.project_path:
|
|
310
|
+
try:
|
|
311
|
+
from expops.core.workspace import get_project_runtime_root
|
|
312
|
+
|
|
313
|
+
runtime_root = get_project_runtime_root(self.project_path, self.project_path.name)
|
|
314
|
+
step_cache_dir = runtime_root / "cache" / "steps"
|
|
315
|
+
except Exception:
|
|
316
|
+
step_cache_dir = self.project_path / "cache" / "steps"
|
|
317
|
+
else:
|
|
318
|
+
step_cache_dir = Path("step_cache")
|
|
297
319
|
|
|
298
320
|
project_id_for_ns = self.project_path.name if self.project_path else "default"
|
|
299
321
|
backend_cfg = _as_dict(cache_config.get("backend", {}))
|
|
300
322
|
|
|
301
323
|
# Centralized KV/object-store creation (config -> env override -> safe fallback).
|
|
302
324
|
try:
|
|
303
|
-
from
|
|
325
|
+
from expops.storage.factory import create_kv_store, create_object_store
|
|
304
326
|
except Exception:
|
|
305
327
|
create_kv_store = None # type: ignore[assignment]
|
|
306
328
|
create_object_store = None # type: ignore[assignment]
|
|
@@ -319,16 +341,19 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
319
341
|
project_root=self.project_path,
|
|
320
342
|
)
|
|
321
343
|
else:
|
|
322
|
-
from
|
|
344
|
+
from expops.storage.adapters.memory_store import InMemoryStore
|
|
323
345
|
kv_store = InMemoryStore(project_id_for_ns)
|
|
324
346
|
|
|
325
347
|
obj_store = None
|
|
348
|
+
obj_prefix = None
|
|
326
349
|
if create_object_store:
|
|
327
350
|
try:
|
|
328
351
|
obj_store = create_object_store(cache_config if isinstance(cache_config, dict) else {}, env=os.environ)
|
|
352
|
+
if obj_store is not None:
|
|
353
|
+
obj_prefix = f"{project_id_for_ns}/cache"
|
|
329
354
|
except Exception:
|
|
330
355
|
obj_store = None
|
|
331
|
-
|
|
356
|
+
obj_prefix = None
|
|
332
357
|
|
|
333
358
|
self.step_state_manager = StepStateManager(
|
|
334
359
|
cache_dir=step_cache_dir,
|
|
@@ -337,6 +362,7 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
337
362
|
cache_ttl_hours=cache_ttl_hours,
|
|
338
363
|
object_store=obj_store,
|
|
339
364
|
object_prefix=obj_prefix,
|
|
365
|
+
project_root=self.project_path,
|
|
340
366
|
)
|
|
341
367
|
|
|
342
368
|
compute_cfg = {}
|
|
@@ -399,7 +425,26 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
399
425
|
pass
|
|
400
426
|
|
|
401
427
|
scheduler_address = executor_config.get("scheduler_address") or os.environ.get("DASK_SCHEDULER_ADDRESS")
|
|
402
|
-
|
|
428
|
+
initial_client: Any = None
|
|
429
|
+
if not scheduler_address and execution_workspace is not None:
|
|
430
|
+
try:
|
|
431
|
+
try:
|
|
432
|
+
from distributed import Client, LocalCluster
|
|
433
|
+
except Exception:
|
|
434
|
+
from dask.distributed import Client, LocalCluster
|
|
435
|
+
self._local_cluster = LocalCluster(
|
|
436
|
+
n_workers=max(1, n_workers),
|
|
437
|
+
threads_per_worker=1,
|
|
438
|
+
)
|
|
439
|
+
self._local_client = Client(self._local_cluster)
|
|
440
|
+
initial_client = self._local_client
|
|
441
|
+
scheduler_address = getattr(self._local_cluster, "scheduler_address", None) or getattr(getattr(self._local_client, "scheduler", None), "address", None)
|
|
442
|
+
self.logger.info(f"Started local process workers (strict_process_workers): n_workers={n_workers}, scheduler={scheduler_address}")
|
|
443
|
+
except Exception as e:
|
|
444
|
+
self.logger.warning(f"Failed to start local process workers, falling back to threads: {e}")
|
|
445
|
+
self._local_cluster = None
|
|
446
|
+
self._local_client = None
|
|
447
|
+
scheduler_mode = "distributed" if (scheduler_address or initial_client) else "threads"
|
|
403
448
|
|
|
404
449
|
extra_files_to_upload: list[str] = []
|
|
405
450
|
try:
|
|
@@ -407,6 +452,12 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
407
452
|
extra_files_to_upload.extend([str(path) for path in self._chart_script_paths if path])
|
|
408
453
|
except Exception:
|
|
409
454
|
extra_files_to_upload = []
|
|
455
|
+
# Paths to upload but not load (chart/reporting scripts run in subprocess with reporting env).
|
|
456
|
+
extra_files_no_load: list[str] = []
|
|
457
|
+
try:
|
|
458
|
+
extra_files_no_load = [str(path) for path in self._chart_script_paths if path]
|
|
459
|
+
except Exception:
|
|
460
|
+
pass
|
|
410
461
|
# Upload reporting entrypoint for worker-side chart imports (best-effort).
|
|
411
462
|
try:
|
|
412
463
|
rep_cfg_text = os.environ.get("MLOPS_REPORTING_CONFIG") or ""
|
|
@@ -419,6 +470,7 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
419
470
|
p = self._repo_root() / p
|
|
420
471
|
if p.exists():
|
|
421
472
|
extra_files_to_upload.append(str(p))
|
|
473
|
+
extra_files_no_load.append(str(p))
|
|
422
474
|
except Exception:
|
|
423
475
|
pass
|
|
424
476
|
|
|
@@ -429,11 +481,13 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
429
481
|
n_workers=n_workers,
|
|
430
482
|
scheduler_mode=scheduler_mode,
|
|
431
483
|
scheduler_address=scheduler_address,
|
|
432
|
-
client=
|
|
484
|
+
client=initial_client,
|
|
433
485
|
extra_files_to_upload=extra_files_to_upload,
|
|
486
|
+
extra_files_no_load=extra_files_no_load,
|
|
434
487
|
min_workers=min_workers_override,
|
|
435
488
|
wait_for_workers_sec=wait_for_workers_override,
|
|
436
489
|
dask_config_overrides=dask_overrides,
|
|
490
|
+
run_context=self.run_context,
|
|
437
491
|
)
|
|
438
492
|
mode_label = "distributed" if scheduler_mode == "distributed" else "threads"
|
|
439
493
|
self.logger.info(f"Initialized Dask NetworkX executor with {n_workers} workers ({mode_label} scheduler)")
|
|
@@ -442,7 +496,7 @@ class CustomModelAdapter(ModelAdapter):
|
|
|
442
496
|
|
|
443
497
|
# Make state manager available for manual step-level caching in decorators
|
|
444
498
|
try:
|
|
445
|
-
from
|
|
499
|
+
from expops.core.step_system import set_state_manager as _set_sm
|
|
446
500
|
_set_sm(self.step_state_manager)
|
|
447
501
|
except Exception:
|
|
448
502
|
pass
|