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.
Files changed (190) hide show
  1. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/.github/workflows/release.yml +1 -1
  2. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/PKG-INFO +3 -2
  3. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/README.md +2 -1
  4. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/caching.md +23 -4
  5. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/reporting.md +9 -7
  6. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/getting-started/creating-a-project.md +29 -2
  7. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/getting-started/quick-start.md +1 -1
  8. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/project-structure/configuration.md +2 -0
  9. expops-0.1.22.dev0/docs/project-structure/overview.md +59 -0
  10. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/templates/premier-league.md +20 -6
  11. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/templates/sklearn-basic.md +22 -8
  12. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/pyproject.toml +7 -4
  13. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/__main__.py +1 -1
  14. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/_version.py +3 -3
  15. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/__init__.py +1 -1
  16. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/config_schema.py +0 -1
  17. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/custom/custom_adapter.py +70 -16
  18. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/plugin_manager.py +2 -2
  19. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/cluster/controller.py +65 -30
  20. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/cluster/process_runner.py +5 -5
  21. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/cluster/providers.py +3 -1
  22. expops-0.1.22.dev0/src/expops/core/__init__.py +106 -0
  23. expops-0.1.22.dev0/src/expops/core/cache_probe/__init__.py +13 -0
  24. expops-0.1.22.dev0/src/expops/core/cache_probe/cache_layout.py +101 -0
  25. expops-0.1.22.dev0/src/expops/core/cache_probe/probe_path.py +60 -0
  26. expops-0.1.22.dev0/src/expops/core/cache_probe/probe_path_selectors.py +317 -0
  27. expops-0.1.22.dev0/src/expops/core/execution/__init__.py +12 -0
  28. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/execution}/dask_networkx_executor.py +158 -94
  29. expops-0.1.22.dev0/src/expops/core/execution/executor_worker.py +2553 -0
  30. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/executor_worker.py +132 -119
  31. expops-0.1.22.dev0/src/expops/core/graph/__init__.py +18 -0
  32. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/graph}/graph_expansion.py +32 -16
  33. expops-0.1.22.dev0/src/expops/core/graph/networkx_parser.py +230 -0
  34. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/graph}/pipeline_tree.py +131 -43
  35. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/graph}/pipeline_utils.py +61 -7
  36. expops-0.1.22.dev0/src/expops/core/hashing/__init__.py +12 -0
  37. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/hashing}/data_hashing.py +1 -1
  38. expops-0.1.22.dev0/src/expops/core/hashing/process_hashing.py +293 -0
  39. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/networkx_parser.py +13 -35
  40. expops-0.1.22.dev0/src/expops/core/parallelism_utils.py +148 -0
  41. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/probe_path_selectors.py +38 -56
  42. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/process_hashing.py +16 -59
  43. expops-0.1.22.dev0/src/expops/core/runtime/__init__.py +14 -0
  44. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/runtime}/payload_spill.py +65 -44
  45. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/runtime}/step_state_manager.py +135 -102
  46. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/runtime}/step_system.py +63 -35
  47. expops-0.1.22.dev0/src/expops/core/step_system.py +2 -0
  48. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/workspace.py +17 -3
  49. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/conda_manager.py +2 -2
  50. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/setup_env.py +1 -1
  51. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/utils.py +50 -2
  52. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/venv_manager.py +44 -3
  53. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/main.py +154 -43
  54. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/managers/project_manager.py +111 -151
  55. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/managers/reproducibility_manager.py +38 -6
  56. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/platform.py +215 -135
  57. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/context.py +1 -30
  58. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/entrypoint.py +21 -2
  59. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/kv_utils.py +3 -3
  60. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/registry.py +1 -1
  61. expops-0.1.22.dev0/src/expops/runtime/context.py +66 -0
  62. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/runtime/env_export.py +14 -6
  63. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/gcp_kv_store.py +35 -8
  64. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/gcs_object_store.py +8 -1
  65. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/factory.py +42 -15
  66. expops-0.1.22.dev0/src/expops/templates/premier-league/.gitignore +21 -0
  67. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/premier-league/configs/compute_config.yaml +1 -0
  68. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/premier-league/configs/project_config.yaml +7 -8
  69. 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
  70. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/premier-league/requirements.txt +1 -1
  71. expops-0.1.22.dev0/src/expops/templates/premier-league/src/plot_metrics.py +207 -0
  72. {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
  73. expops-0.1.22.dev0/src/expops/templates/sklearn-basic/.gitignore +21 -0
  74. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/sklearn-basic/configs/compute_config.yaml +1 -0
  75. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/sklearn-basic/configs/project_config.yaml +4 -5
  76. expops-0.1.22.dev0/src/expops/templates/sklearn-basic/requirements-charts.txt +3 -0
  77. {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
  78. {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
  79. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/server.py +63 -23
  80. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/ui/mlops-charts.js +0 -5
  81. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/ui/script.js +16 -12
  82. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/PKG-INFO +3 -2
  83. expops-0.1.22.dev0/src/expops.egg-info/SOURCES.txt +169 -0
  84. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/top_level.txt +0 -1
  85. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/conftest.py +2 -2
  86. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/testing-plan.md +27 -24
  87. expops-0.1.22.dev0/tests/unit/test_cli/test_expops_run_infer_project.py +107 -0
  88. expops-0.1.22.dev0/tests/unit/test_cli/test_main_create_in_place.py +63 -0
  89. expops-0.1.22.dev0/tests/unit/test_core/test_cache_layout.py +83 -0
  90. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_dask_networkx_executor.py +100 -19
  91. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_data_hashing.py +1 -1
  92. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_executor_worker.py +159 -16
  93. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_graph_expansion.py +79 -45
  94. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_networkx_parser.py +1 -1
  95. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_networkx_parser_code_field.py +1 -1
  96. expops-0.1.22.dev0/tests/unit/test_core/test_parallelism_utils.py +29 -0
  97. expops-0.1.22.dev0/tests/unit/test_core/test_payload_spill.py +126 -0
  98. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_pipeline_tree_steps.py +57 -4
  99. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_prepare_runner_kwargs.py +1 -1
  100. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_probe_path_selectors_xpath.py +82 -6
  101. expops-0.1.22.dev0/tests/unit/test_core/test_process_hashing.py +189 -0
  102. expops-0.1.22.dev0/tests/unit/test_core/test_step_state_manager.py +192 -0
  103. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/test_step_system.py +61 -5
  104. expops-0.1.22.dev0/tests/unit/test_environment_paths.py +92 -0
  105. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_managers/test_reproducibility_manager.py +1 -1
  106. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_platform/test_dynamic_js_charts.py +76 -13
  107. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_platform/test_project_metadata_resilience.py +21 -15
  108. expops-0.1.22.dev0/tests/unit/test_projects/test_custom_adapter_object_store.py +111 -0
  109. expops-0.1.22.dev0/tests/unit/test_projects/test_new_project_layout.py +42 -0
  110. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_reporting/test_entrypoint.py +31 -2
  111. expops-0.1.22.dev0/tests/unit/test_runtime/__init__.py +1 -0
  112. expops-0.1.22.dev0/tests/unit/test_runtime/test_context.py +58 -0
  113. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/test_factory.py +12 -14
  114. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/test_gcp_kv_store.py +78 -15
  115. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/test_gcs_object_store.py +7 -7
  116. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/test_sqlite_store.py +1 -3
  117. expops-0.1.22.dev0/tests/unit/test_storage/test_step_state_manager_layout.py +51 -0
  118. expops-0.1.22.dev0/tests/unit/test_web/test_chart_config.py +51 -0
  119. expops-0.1.19.dev0/docs/project-structure/overview.md +0 -55
  120. expops-0.1.19.dev0/src/expops/__init__.py +0 -37
  121. expops-0.1.19.dev0/src/expops/__main__.py +0 -8
  122. expops-0.1.19.dev0/src/expops/core/__init__.py +0 -15
  123. expops-0.1.19.dev0/src/expops/main.py +0 -13
  124. expops-0.1.19.dev0/src/expops/reporting/__init__.py +0 -5
  125. expops-0.1.19.dev0/src/expops/reporting/context.py +0 -5
  126. expops-0.1.19.dev0/src/expops/reporting/registry.py +0 -5
  127. expops-0.1.19.dev0/src/expops/web/__init__.py +0 -3
  128. expops-0.1.19.dev0/src/expops/web/server.py +0 -17
  129. expops-0.1.19.dev0/src/expops.egg-info/SOURCES.txt +0 -153
  130. expops-0.1.19.dev0/src/mlops/core/__init__.py +0 -95
  131. expops-0.1.19.dev0/src/mlops/runtime/context.py +0 -37
  132. expops-0.1.19.dev0/src/mlops/templates/premier-league/charts/plot_metrics.py +0 -201
  133. expops-0.1.19.dev0/src/mlops/templates/sklearn-basic/README.md +0 -22
  134. expops-0.1.19.dev0/src/mlops/templates/sklearn-basic/charts/requirements.txt +0 -3
  135. expops-0.1.19.dev0/tests/unit/test_core/test_payload_spill.py +0 -80
  136. expops-0.1.19.dev0/tests/unit/test_core/test_process_hashing.py +0 -77
  137. expops-0.1.19.dev0/tests/unit/test_core/test_step_state_manager.py +0 -90
  138. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/.github/workflows/ci.yml +0 -0
  139. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/.gitignore +0 -0
  140. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/LICENSE +0 -0
  141. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/advanced/backends.md +0 -0
  142. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/data-parallelism.md +0 -0
  143. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/distributed.md +0 -0
  144. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/environments.md +0 -0
  145. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/pipelines.md +0 -0
  146. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/features/seed-parallelism.md +0 -0
  147. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/index.md +0 -0
  148. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/project-structure/model-code.md +0 -0
  149. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/requirements.txt +0 -0
  150. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/docs/web-ui/local-ui.md +0 -0
  151. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/setup.cfg +0 -0
  152. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/__init__.py +0 -0
  153. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/__init__.py +0 -0
  154. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/base.py +0 -0
  155. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/custom/__init__.py +0 -0
  156. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/sklearn/__init__.py +0 -0
  157. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/adapters/sklearn/adapter.py +0 -0
  158. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/cluster/__init__.py +0 -0
  159. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/core/compute_config.py +0 -0
  160. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/graph}/graph_types.py +0 -0
  161. {expops-0.1.19.dev0/src/mlops/core → expops-0.1.22.dev0/src/expops/core/runtime}/custom_model_base.py +0 -0
  162. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/__init__.py +0 -0
  163. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/base.py +0 -0
  164. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/factory.py +0 -0
  165. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/pyenv_manager.py +0 -0
  166. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/environment/system_manager.py +0 -0
  167. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/reporting/__init__.py +0 -0
  168. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/runtime/__init__.py +0 -0
  169. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/__init__.py +0 -0
  170. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/__init__.py +0 -0
  171. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/memory_store.py +0 -0
  172. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/redis_store.py +0 -0
  173. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/adapters/sqlite_store.py +0 -0
  174. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/interfaces/__init__.py +0 -0
  175. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/interfaces/kv_store.py +0 -0
  176. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/storage/path_utils.py +0 -0
  177. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/premier-league/data/England CSV.csv +0 -0
  178. {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
  179. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/sklearn-basic/data/train.csv +0 -0
  180. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/templates/sklearn-basic/requirements.txt +0 -0
  181. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/__init__.py +0 -0
  182. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/ui/index.html +0 -0
  183. {expops-0.1.19.dev0/src/mlops → expops-0.1.22.dev0/src/expops}/web/ui/styles.css +0 -0
  184. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/dependency_links.txt +0 -0
  185. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/entry_points.txt +0 -0
  186. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/src/expops.egg-info/requires.txt +0 -0
  187. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/__init__.py +0 -0
  188. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_core/__init__.py +0 -0
  189. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_managers/__init__.py +0 -0
  190. {expops-0.1.19.dev0 → expops-0.1.22.dev0}/tests/unit/test_storage/__init__.py +0 -0
@@ -40,7 +40,7 @@ jobs:
40
40
  id-token: write
41
41
  environment:
42
42
  name: pypi
43
- url: https://pypi.org/project/mlops-platform/
43
+ url: https://pypi.org/project/expops/
44
44
  steps:
45
45
  - name: Download dist artifacts
46
46
  uses: actions/download-artifact@v4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: expops
3
- Version: 0.1.19.dev0
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 mlops-platform
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 mlops-platform
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
- - Stored under a cache prefix (for example `cache/steps/steps/` in GCS).
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 (`models/` prefix)**:
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 `models/<run_id>/<process_name>/...` path.
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 `models/` 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.
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 `ctx.savefig()` to save figures
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 saving figures (REQUIRED)
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
- # MUST use ctx.savefig() to save the figure
49
- ctx.savefig('plot_metrics.png', fig=fig, dpi=150)
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 to:
117
+ Static charts produce image files (PNG) saved under the unified artifacts layout:
117
118
  ```
118
- artifacts/charts/<run-id>/
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
- ├── models/
39
- ├── charts/
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
- # prefix: sklearn-basic/cache/steps
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
- ├── models/
27
- └── premier_league_model.py
28
- ├── charts/
29
- ├── plot_metrics.py
30
- ├── plot_metrics.js
31
- └── requirements.txt
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
- ├── models/
26
- └── sklearn_model.py
27
- ├── charts/
28
- ├── plot_metrics.py
29
- └── requirements.txt
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/sklearn_model.py`
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
- "mlops.web" = ["ui/*"]
59
- "mlops" = [
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/mlops/_version.py"
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"]
@@ -2,7 +2,7 @@
2
2
  """
3
3
  MLOps Platform __main__ module
4
4
 
5
- Allows the package to be run with `python -m mlops.main`
5
+ Allows the package to be run with `python -m expops.main`
6
6
  """
7
7
 
8
8
  from .main import main
@@ -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.19.dev0'
32
- __version_tuple__ = version_tuple = (0, 1, 19, 'dev0')
31
+ __version__ = version = '0.1.22.dev0'
32
+ __version_tuple__ = version_tuple = (0, 1, 22, 'dev0')
33
33
 
34
- __commit_id__ = commit_id = 'g4b7fdd9d1'
34
+ __commit_id__ = commit_id = 'ga532cd5e9'
@@ -1,7 +1,7 @@
1
1
  """Adapter plugins package.
2
2
 
3
3
  This package contains subpackages that each expose an `Adapter` symbol
4
- for plugin discovery (e.g., `mlops.adapters.custom.Adapter`).
4
+ for plugin discovery (e.g., `expops.adapters.custom.Adapter`).
5
5
  """
6
6
 
7
7
  __all__ = [
@@ -66,7 +66,6 @@ class AdapterConfig(BaseModel):
66
66
  ],
67
67
  "execution": {
68
68
  "parallel": True,
69
- "failure_mode": "stop",
70
69
  "max_workers": 4
71
70
  }
72
71
  }
@@ -9,11 +9,11 @@ import time
9
9
  from pathlib import Path
10
10
  from typing import Any, Dict, Optional
11
11
 
12
- from mlops.core import StepStateManager, get_context_factory, get_step_registry, set_current_context
13
- from mlops.core.compute_config import load_compute_config, map_compute_to_executor
14
- from mlops.core.custom_model_base import MLOpsCustomModelBase
15
- from mlops.core.dask_networkx_executor import DaskNetworkXExecutor
16
- from mlops.core.networkx_parser import parse_networkx_pipeline_from_config
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 mlops.core.workspace import get_workspace_root
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 mlops.core.workspace import infer_source_root
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 section from config file
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 mlops.core.pipeline_utils import resolve_script_path
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 = (self.project_path / "cache" / "steps") if self.project_path else Path("step_cache")
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 mlops.storage.factory import create_kv_store, create_object_store
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 mlops.storage.adapters.memory_store import InMemoryStore
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
- obj_prefix = None
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
- scheduler_mode = "distributed" if scheduler_address else "threads"
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=None,
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 mlops.core.step_system import set_state_manager as _set_sm
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