flowyml 1.1.0__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. {flowyml-1.1.0 → flowyml-1.3.0}/LICENSE +1 -1
  2. {flowyml-1.1.0 → flowyml-1.3.0}/PKG-INFO +113 -12
  3. {flowyml-1.1.0 → flowyml-1.3.0}/README.md +108 -11
  4. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/__init__.py +3 -0
  5. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/assets/base.py +10 -0
  6. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/assets/metrics.py +6 -0
  7. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/cli/main.py +108 -2
  8. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/cli/run.py +9 -2
  9. flowyml-1.3.0/flowyml/core/execution_status.py +52 -0
  10. flowyml-1.3.0/flowyml/core/hooks.py +106 -0
  11. flowyml-1.3.0/flowyml/core/observability.py +210 -0
  12. flowyml-1.3.0/flowyml/core/orchestrator.py +274 -0
  13. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/pipeline.py +193 -231
  14. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/project.py +34 -2
  15. flowyml-1.3.0/flowyml/core/remote_orchestrator.py +109 -0
  16. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/resources.py +22 -5
  17. flowyml-1.3.0/flowyml/core/retry_policy.py +80 -0
  18. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/step.py +18 -1
  19. flowyml-1.3.0/flowyml/core/submission_result.py +53 -0
  20. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/versioning.py +2 -2
  21. flowyml-1.3.0/flowyml/integrations/keras.py +207 -0
  22. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/monitoring/alerts.py +2 -2
  23. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/__init__.py +15 -0
  24. flowyml-1.3.0/flowyml/stacks/aws.py +599 -0
  25. flowyml-1.3.0/flowyml/stacks/azure.py +295 -0
  26. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/components.py +24 -2
  27. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/gcp.py +158 -11
  28. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/local.py +5 -0
  29. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/artifacts.py +15 -5
  30. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/materializers/__init__.py +2 -0
  31. flowyml-1.3.0/flowyml/storage/materializers/cloudpickle.py +74 -0
  32. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/metadata.py +166 -5
  33. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/main.py +41 -1
  34. flowyml-1.3.0/flowyml/ui/backend/routers/assets.py +386 -0
  35. flowyml-1.3.0/flowyml/ui/backend/routers/client.py +46 -0
  36. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/routers/execution.py +13 -2
  37. flowyml-1.3.0/flowyml/ui/backend/routers/experiments.py +85 -0
  38. flowyml-1.3.0/flowyml/ui/backend/routers/metrics.py +213 -0
  39. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/routers/pipelines.py +63 -7
  40. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/routers/projects.py +33 -7
  41. flowyml-1.3.0/flowyml/ui/backend/routers/runs.py +208 -0
  42. flowyml-1.3.0/flowyml/ui/frontend/dist/assets/index-DcYwrn2j.css +1 -0
  43. flowyml-1.3.0/flowyml/ui/frontend/dist/assets/index-Dlz_ygOL.js +592 -0
  44. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/dist/index.html +2 -2
  45. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/App.jsx +4 -1
  46. flowyml-1.3.0/flowyml/ui/frontend/src/app/assets/page.jsx +427 -0
  47. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/dashboard/page.jsx +38 -7
  48. flowyml-1.3.0/flowyml/ui/frontend/src/app/experiments/page.jsx +107 -0
  49. flowyml-1.3.0/flowyml/ui/frontend/src/app/observability/page.jsx +277 -0
  50. flowyml-1.3.0/flowyml/ui/frontend/src/app/pipelines/page.jsx +131 -0
  51. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectArtifactsList.jsx +151 -0
  52. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectExperimentsList.jsx +145 -0
  53. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectHeader.jsx +45 -0
  54. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectHierarchy.jsx +467 -0
  55. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectMetricsPanel.jsx +253 -0
  56. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectPipelinesList.jsx +105 -0
  57. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectRelations.jsx +189 -0
  58. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectRunsList.jsx +136 -0
  59. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/_components/ProjectTabs.jsx +95 -0
  60. flowyml-1.3.0/flowyml/ui/frontend/src/app/projects/[projectId]/page.jsx +326 -0
  61. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/projects/page.jsx +13 -3
  62. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/runs/[runId]/page.jsx +79 -10
  63. flowyml-1.3.0/flowyml/ui/frontend/src/app/runs/page.jsx +128 -0
  64. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/settings/page.jsx +1 -0
  65. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/tokens/page.jsx +62 -16
  66. flowyml-1.3.0/flowyml/ui/frontend/src/components/AssetDetailsPanel.jsx +373 -0
  67. flowyml-1.3.0/flowyml/ui/frontend/src/components/AssetLineageGraph.jsx +291 -0
  68. flowyml-1.3.0/flowyml/ui/frontend/src/components/AssetStatsDashboard.jsx +302 -0
  69. flowyml-1.3.0/flowyml/ui/frontend/src/components/AssetTreeHierarchy.jsx +477 -0
  70. flowyml-1.3.0/flowyml/ui/frontend/src/components/ExperimentDetailsPanel.jsx +227 -0
  71. flowyml-1.3.0/flowyml/ui/frontend/src/components/NavigationTree.jsx +401 -0
  72. flowyml-1.3.0/flowyml/ui/frontend/src/components/PipelineDetailsPanel.jsx +239 -0
  73. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/PipelineGraph.jsx +67 -3
  74. flowyml-1.3.0/flowyml/ui/frontend/src/components/ProjectSelector.jsx +115 -0
  75. flowyml-1.3.0/flowyml/ui/frontend/src/components/RunDetailsPanel.jsx +298 -0
  76. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/header/Header.jsx +48 -1
  77. flowyml-1.3.0/flowyml/ui/frontend/src/components/plugins/ZenMLIntegration.jsx +106 -0
  78. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/sidebar/Sidebar.jsx +52 -26
  79. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/DataView.jsx +35 -17
  80. flowyml-1.3.0/flowyml/ui/frontend/src/components/ui/ErrorBoundary.jsx +118 -0
  81. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/contexts/ProjectContext.jsx +2 -2
  82. flowyml-1.3.0/flowyml/ui/frontend/src/contexts/ToastContext.jsx +116 -0
  83. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/layouts/MainLayout.jsx +5 -1
  84. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/router/index.jsx +4 -0
  85. flowyml-1.3.0/flowyml/ui/frontend/src/utils/date.js +10 -0
  86. flowyml-1.3.0/flowyml/ui/frontend/src/utils/downloads.js +11 -0
  87. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/utils/config.py +6 -0
  88. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/utils/stack_config.py +45 -3
  89. {flowyml-1.1.0 → flowyml-1.3.0}/pyproject.toml +13 -4
  90. flowyml-1.1.0/flowyml/integrations/keras.py +0 -134
  91. flowyml-1.1.0/flowyml/ui/backend/routers/assets.py +0 -45
  92. flowyml-1.1.0/flowyml/ui/backend/routers/experiments.py +0 -49
  93. flowyml-1.1.0/flowyml/ui/backend/routers/runs.py +0 -66
  94. flowyml-1.1.0/flowyml/ui/frontend/dist/assets/index-DFNQnrUj.js +0 -448
  95. flowyml-1.1.0/flowyml/ui/frontend/dist/assets/index-pWI271rZ.css +0 -1
  96. flowyml-1.1.0/flowyml/ui/frontend/src/app/assets/page.jsx +0 -397
  97. flowyml-1.1.0/flowyml/ui/frontend/src/app/experiments/page.jsx +0 -360
  98. flowyml-1.1.0/flowyml/ui/frontend/src/app/pipelines/page.jsx +0 -454
  99. flowyml-1.1.0/flowyml/ui/frontend/src/app/runs/page.jsx +0 -470
  100. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/assets/__init__.py +0 -0
  101. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/assets/artifact.py +0 -0
  102. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/assets/dataset.py +0 -0
  103. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/assets/featureset.py +0 -0
  104. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/assets/model.py +0 -0
  105. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/assets/registry.py +0 -0
  106. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/assets/report.py +0 -0
  107. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/cli/__init__.py +0 -0
  108. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/cli/experiment.py +0 -0
  109. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/cli/init.py +0 -0
  110. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/cli/stack_cli.py +0 -0
  111. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/cli/ui.py +0 -0
  112. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/__init__.py +0 -0
  113. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/advanced_cache.py +0 -0
  114. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/approval.py +0 -0
  115. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/cache.py +0 -0
  116. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/checkpoint.py +0 -0
  117. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/conditional.py +0 -0
  118. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/context.py +0 -0
  119. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/error_handling.py +0 -0
  120. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/executor.py +0 -0
  121. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/graph.py +0 -0
  122. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/parallel.py +0 -0
  123. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/scheduler.py +0 -0
  124. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/scheduler_config.py +0 -0
  125. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/step_grouping.py +0 -0
  126. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/core/templates.py +0 -0
  127. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/integrations/__init__.py +0 -0
  128. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/monitoring/__init__.py +0 -0
  129. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/monitoring/data.py +0 -0
  130. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/monitoring/llm.py +0 -0
  131. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/monitoring/monitor.py +0 -0
  132. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/monitoring/notifications.py +0 -0
  133. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/registry/__init__.py +0 -0
  134. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/registry/model_registry.py +0 -0
  135. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/registry/pipeline_registry.py +0 -0
  136. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/base.py +0 -0
  137. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/bridge.py +0 -0
  138. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/migration.py +0 -0
  139. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/plugin_config.py +0 -0
  140. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/plugins.py +0 -0
  141. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/stacks/registry.py +0 -0
  142. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/__init__.py +0 -0
  143. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/materializers/base.py +0 -0
  144. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/materializers/keras.py +0 -0
  145. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/materializers/numpy.py +0 -0
  146. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/materializers/pandas.py +0 -0
  147. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/materializers/pytorch.py +0 -0
  148. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/materializers/sklearn.py +0 -0
  149. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/storage/materializers/tensorflow.py +0 -0
  150. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/tracking/__init__.py +0 -0
  151. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/tracking/experiment.py +0 -0
  152. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/tracking/leaderboard.py +0 -0
  153. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/tracking/runs.py +0 -0
  154. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/__init__.py +0 -0
  155. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/Dockerfile +0 -0
  156. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/__init__.py +0 -0
  157. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/auth.py +0 -0
  158. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/routers/__init__.py +0 -0
  159. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/routers/leaderboard.py +0 -0
  160. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/routers/notifications.py +0 -0
  161. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/routers/plugins.py +0 -0
  162. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/routers/schedules.py +0 -0
  163. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/backend/routers/traces.py +0 -0
  164. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/Dockerfile +0 -0
  165. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/README.md +0 -0
  166. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/index.html +0 -0
  167. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/nginx.conf +0 -0
  168. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/package-lock.json +0 -0
  169. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/package.json +0 -0
  170. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/postcss.config.js +0 -0
  171. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/experiments/[experimentId]/page.jsx +0 -0
  172. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/leaderboard/page.jsx +0 -0
  173. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/plugins/page.jsx +0 -0
  174. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/schedules/page.jsx +0 -0
  175. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/app/traces/page.jsx +0 -0
  176. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/Layout.jsx +0 -0
  177. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/plugins/AddPluginDialog.jsx +0 -0
  178. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/plugins/InstalledPlugins.jsx +0 -0
  179. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/plugins/PluginBrowser.jsx +0 -0
  180. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/plugins/PluginManager.jsx +0 -0
  181. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/Badge.jsx +0 -0
  182. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/Button.jsx +0 -0
  183. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/Card.jsx +0 -0
  184. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/CodeSnippet.jsx +0 -0
  185. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/CollapsibleCard.jsx +0 -0
  186. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/EmptyState.jsx +0 -0
  187. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/ExecutionStatus.jsx +0 -0
  188. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/KeyValue.jsx +0 -0
  189. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/components/ui/ProjectSelector.jsx +0 -0
  190. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/contexts/ThemeContext.jsx +0 -0
  191. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/index.css +0 -0
  192. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/main.jsx +0 -0
  193. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/services/pluginService.js +0 -0
  194. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/utils/api.js +0 -0
  195. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/src/utils/cn.js +0 -0
  196. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/tailwind.config.js +0 -0
  197. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/frontend/vite.config.js +0 -0
  198. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/ui/utils.py +0 -0
  199. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/utils/__init__.py +0 -0
  200. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/utils/debug.py +0 -0
  201. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/utils/environment.py +0 -0
  202. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/utils/git.py +0 -0
  203. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/utils/logging.py +0 -0
  204. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/utils/performance.py +0 -0
  205. {flowyml-1.1.0 → flowyml-1.3.0}/flowyml/utils/validation.py +0 -0
@@ -2,7 +2,7 @@ Apache License
2
2
  Version 2.0, January 2004
3
3
  http://www.apache.org/licenses/
4
4
 
5
- Copyright 2024 Flowy Team
5
+ Copyright 2024 UnicoLab.ai
6
6
 
7
7
  Licensed under the Apache License, Version 2.0 (the "License");
8
8
  you may not use this file except in compliance with the License.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flowyml
3
- Version: 1.1.0
3
+ Version: 1.3.0
4
4
  Summary: Next-Generation ML Pipeline Framework
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -19,16 +19,20 @@ Classifier: Programming Language :: Python :: 3.13
19
19
  Classifier: Programming Language :: Python :: 3.14
20
20
  Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
21
  Provides-Extra: all
22
+ Provides-Extra: aws
23
+ Provides-Extra: azure
22
24
  Provides-Extra: gcp
23
25
  Provides-Extra: pytorch
24
26
  Provides-Extra: sklearn
25
27
  Provides-Extra: tensorflow
26
28
  Provides-Extra: ui
27
29
  Requires-Dist: click (>=8.0.0)
30
+ Requires-Dist: cloudpickle (>=2.0.0)
28
31
  Requires-Dist: croniter (>=2.0.1,<3.0.0)
29
32
  Requires-Dist: fastapi (>=0.122.0,<0.123.0) ; extra == "ui"
30
33
  Requires-Dist: google-cloud-aiplatform (>=1.35.0) ; extra == "gcp" or extra == "all"
31
34
  Requires-Dist: google-cloud-storage (>=2.10.0) ; extra == "gcp" or extra == "all"
35
+ Requires-Dist: httpx (>=0.24,<0.28)
32
36
  Requires-Dist: loguru (>=0.7.3,<0.8.0)
33
37
  Requires-Dist: numpy (>=1.20.0)
34
38
  Requires-Dist: pandas (>=1.3.0)
@@ -66,21 +70,25 @@ Description-Content-Type: text/markdown
66
70
 
67
71
  ---
68
72
 
69
- **flowyml** is the comprehensive ML pipeline framework that combines the **simplicity of a Python script** with the **power of an enterprise MLOps platform**.
73
+ **FlowyML** is the comprehensive ML pipeline framework that combines the **simplicity of a Python script** with the **power of an enterprise MLOps platform**.
70
74
 
71
- ## 🚀 Why flowyml?
75
+ ## 🚀 Why FlowyML?
72
76
 
73
- | Feature | flowyml | Traditional Orchestrators |
77
+ | Feature | FlowyML | Traditional Orchestrators |
74
78
  |---------|---------|---------------------------|
75
79
  | **Developer Experience** | 🐍 **Native Python** - No DSLs, no YAML hell. | 📜 Complex YAML or rigid DSLs. |
76
80
  | **Context Awareness** | 🧠 **Auto-Injection** - Params are just function args. | 🔌 Manual wiring of every parameter. |
77
81
  | **Caching** | ⚡ **Multi-Level** - Smart content-hashing & memoization. | 🐢 Basic file-timestamp checking. |
78
82
  | **Asset Management** | 📦 **First-Class Assets** - Models & Datasets with lineage. | 📁 Generic file paths only. |
79
83
  | **Architecture** | 🏗️ **Modular Stacks** - Local, Cloud, Hybrid. | 🔒 Vendor lock-in or complex setup. |
84
+ | **Deployment** | 🏢 **Local or Centralized** - Run locally or deploy as a company-wide hub. | 🧩 Fragmented or cloud-only. |
85
+ | **Flexibility** | 🔌 **Extensive Plugin Ecosystem** | Fixed integration with specific orchestrators or custom tools to be developed. |
86
+ | **Separation of Concerns** | 🪾 **Steps Grouping, branching and conditions** | Handling only orchestrator logic and task execution oriented. |
87
+ | **Features Rich** | 🌟 **Built-in experiment tracking, model leaderboard, human-in-the-loop, notifications, scheduling** | Very limited or none extra features. |
80
88
 
81
89
  ## 🚀 Feature Showcase
82
90
 
83
- flowyml is a complete toolkit for building, debugging, and deploying ML applications.
91
+ FlowyML is a complete toolkit for building, debugging, and deploying ML applications.
84
92
 
85
93
  ### 1. Zero-Boilerplate Orchestration
86
94
  Write pipelines as standard Python functions. No YAML, no DSLs.
@@ -110,18 +118,21 @@ def expensive_processing(data):
110
118
  ```
111
119
 
112
120
  ### 3. 🤖 LLM & GenAI Ready
113
- Trace token usage, latency, and costs automatically.
121
+ Trace token usage, latency, and costs automatically with built-in observability.
114
122
 
115
123
  ```python
116
124
  @step
117
125
  @trace_llm(model="gpt-4", tags=["production"])
118
126
  def generate_summary(text: str):
119
- # flowyml automatically tracks tokens, cost, and latency
127
+ # flowyml automatically tracks:
128
+ # - Token usage (prompt/completion)
129
+ # - Cost estimation
130
+ # - Latency & Success/Failure rates
120
131
  return openai.ChatCompletion.create(...)
121
132
  ```
122
133
 
123
- ### 4. ⚡ Efficient Step Grouping
124
- Group related steps to run in the same container - reduce overhead, maintain clarity.
134
+ ### 4. ⚡ Efficient Step Grouping & Separation of Concerns
135
+ Group related steps to run in the same container - reduce overhead, maintain clarity, and keep logic separate from configuration.
125
136
 
126
137
  ```python
127
138
  # Run preprocessing steps in same container (shares resources)
@@ -238,12 +249,13 @@ pipeline.run(debug=True) # Pauses at breakpoint
238
249
  ```
239
250
 
240
251
  ### 13. 📦 First-Class Assets
241
- Specialized types for ML workflows.
252
+ Assets are not just files; they are first-class citizens with lineage, metadata, and versioning.
242
253
 
243
254
  ```python
244
255
  from flowyml.core import Dataset, Model, Metrics, FeatureSet
245
256
 
246
- dataset = Dataset.create(data=df, name="training_data")
257
+ # Assets track their producer, lineage, and metadata automatically
258
+ dataset = Dataset.create(data=df, name="training_data", metadata={"source": "s3"})
247
259
  model = Model.create(artifact=trained_model, score=0.95)
248
260
  metrics = Metrics.create(values={"accuracy": 0.95})
249
261
  ```
@@ -285,11 +297,80 @@ if drift['drift_detected']:
285
297
  - **🔔 Notifications**: Slack/Email alerts.
286
298
  - **🛡️ Circuit Breakers**: Stop cascading failures.
287
299
 
288
- ### 18. 🔌 Universal Integrations
300
+ ### 18. 🏢 Centralized Hub & Docker
301
+ Ready for the enterprise. Run locally per project or deploy as a centralized entity for the company.
302
+ - **Docker Ready**: Backend and Frontend are fully dockerized.
303
+ - **Centralized Hub**: Share pipelines, artifacts, and experiments across the team.
304
+ - **Remote Execution**: Configure local clients to execute on the remote hub.
305
+
306
+ ### 19. 🔌 Universal Integrations
289
307
  - **ML Frameworks**: PyTorch, TensorFlow, Keras, Scikit-learn, HuggingFace.
290
308
  - **Cloud Providers**: AWS, GCP, Azure (via plugins).
291
309
  - **Tools**: MLflow, Weights & Biases, Great Expectations.
292
310
 
311
+ ### 20. 📊 Automatic Training History Tracking
312
+ FlowyML automatically captures and visualizes your model training progress with zero manual intervention.
313
+
314
+ ```python
315
+ from flowyml.integrations.keras import FlowymlKerasCallback
316
+
317
+ # Just add the callback - that's it!
318
+ callback = FlowymlKerasCallback(
319
+ experiment_name="my-experiment",
320
+ project="my-project"
321
+ )
322
+
323
+ model.fit(
324
+ x_train, y_train,
325
+ validation_data=(x_val, y_val),
326
+ epochs=50,
327
+ callbacks=[callback] # Auto-tracks all metrics!
328
+ )
329
+ ```
330
+
331
+ **What gets captured automatically:**
332
+ - ✅ Loss (train & validation) per epoch
333
+ - ✅ Accuracy (train & validation) per epoch
334
+ - ✅ All custom metrics (F1, precision, recall, etc.)
335
+ - ✅ Model architecture and parameters
336
+ - ✅ Interactive charts in the UI
337
+
338
+ **View beautiful training graphs in the UI:**
339
+ 1. Navigate to your project's Structure tab
340
+ 2. Click on any model artifact
341
+ 3. See interactive loss/accuracy charts over epochs!
342
+
343
+ No external tools needed - all visualization built into FlowyML.
344
+
345
+ ### 21. 📂 Project-Based Organization
346
+ Built-in multi-tenancy for managing multiple teams and initiatives.
347
+
348
+ ```python
349
+ from flowyml import Project
350
+
351
+ project = Project("recommendation_system")
352
+ pipeline = project.create_pipeline("training")
353
+
354
+ # All runs, artifacts, and metadata are automatically scoped to the project
355
+ runs = project.list_runs()
356
+ stats = project.get_stats()
357
+ ```
358
+
359
+ ### 22. 📝 Pipeline Templates
360
+ Stop reinventing the wheel. Use pre-built templates for common ML patterns.
361
+
362
+ ```python
363
+ from flowyml.core.templates import create_from_template
364
+
365
+ # Create a standard training pipeline in one line
366
+ pipeline = create_from_template(
367
+ "ml_training",
368
+ data_loader=my_loader,
369
+ trainer=my_trainer,
370
+ evaluator=my_evaluator
371
+ )
372
+ ```
373
+
293
374
  ## 📦 Installation
294
375
 
295
376
  ```bash
@@ -339,6 +420,26 @@ print(f"Run ID: {result.run_id}")
339
420
  print(f"Model Score: {result.outputs['model'].score}")
340
421
  ```
341
422
 
423
+ ### 23. 🌐 Pipeline Versioning
424
+ Git-like versioning for pipelines. Track changes, compare, rollback.
425
+
426
+ ```python
427
+ from flowyml import VersionedPipeline
428
+
429
+ pipeline = VersionedPipeline("training", version="v1.0.0")
430
+ pipeline.add_step(load_data)
431
+ pipeline.save_version()
432
+
433
+ # ... make changes ...
434
+ pipeline.version = "v1.1.0"
435
+ pipeline.save_version()
436
+
437
+ # Compare versions to see exactly what changed (steps, code, context)
438
+ diff = pipeline.compare_with("v1.0.0")
439
+ print(diff["modified_steps"]) # ['train_model']
440
+ print(diff["context_changes"]) # {'learning_rate': {'old': 0.01, 'new': 0.001}}
441
+ ```
442
+
342
443
  ## 🖥️ The flowyml UI
343
444
 
344
445
  Visualize your workflows, inspect artifacts, and monitor runs in real-time.
@@ -17,21 +17,25 @@
17
17
 
18
18
  ---
19
19
 
20
- **flowyml** is the comprehensive ML pipeline framework that combines the **simplicity of a Python script** with the **power of an enterprise MLOps platform**.
20
+ **FlowyML** is the comprehensive ML pipeline framework that combines the **simplicity of a Python script** with the **power of an enterprise MLOps platform**.
21
21
 
22
- ## 🚀 Why flowyml?
22
+ ## 🚀 Why FlowyML?
23
23
 
24
- | Feature | flowyml | Traditional Orchestrators |
24
+ | Feature | FlowyML | Traditional Orchestrators |
25
25
  |---------|---------|---------------------------|
26
26
  | **Developer Experience** | 🐍 **Native Python** - No DSLs, no YAML hell. | 📜 Complex YAML or rigid DSLs. |
27
27
  | **Context Awareness** | 🧠 **Auto-Injection** - Params are just function args. | 🔌 Manual wiring of every parameter. |
28
28
  | **Caching** | ⚡ **Multi-Level** - Smart content-hashing & memoization. | 🐢 Basic file-timestamp checking. |
29
29
  | **Asset Management** | 📦 **First-Class Assets** - Models & Datasets with lineage. | 📁 Generic file paths only. |
30
30
  | **Architecture** | 🏗️ **Modular Stacks** - Local, Cloud, Hybrid. | 🔒 Vendor lock-in or complex setup. |
31
+ | **Deployment** | 🏢 **Local or Centralized** - Run locally or deploy as a company-wide hub. | 🧩 Fragmented or cloud-only. |
32
+ | **Flexibility** | 🔌 **Extensive Plugin Ecosystem** | Fixed integration with specific orchestrators or custom tools to be developed. |
33
+ | **Separation of Concerns** | 🪾 **Steps Grouping, branching and conditions** | Handling only orchestrator logic and task execution oriented. |
34
+ | **Features Rich** | 🌟 **Built-in experiment tracking, model leaderboard, human-in-the-loop, notifications, scheduling** | Very limited or none extra features. |
31
35
 
32
36
  ## 🚀 Feature Showcase
33
37
 
34
- flowyml is a complete toolkit for building, debugging, and deploying ML applications.
38
+ FlowyML is a complete toolkit for building, debugging, and deploying ML applications.
35
39
 
36
40
  ### 1. Zero-Boilerplate Orchestration
37
41
  Write pipelines as standard Python functions. No YAML, no DSLs.
@@ -61,18 +65,21 @@ def expensive_processing(data):
61
65
  ```
62
66
 
63
67
  ### 3. 🤖 LLM & GenAI Ready
64
- Trace token usage, latency, and costs automatically.
68
+ Trace token usage, latency, and costs automatically with built-in observability.
65
69
 
66
70
  ```python
67
71
  @step
68
72
  @trace_llm(model="gpt-4", tags=["production"])
69
73
  def generate_summary(text: str):
70
- # flowyml automatically tracks tokens, cost, and latency
74
+ # flowyml automatically tracks:
75
+ # - Token usage (prompt/completion)
76
+ # - Cost estimation
77
+ # - Latency & Success/Failure rates
71
78
  return openai.ChatCompletion.create(...)
72
79
  ```
73
80
 
74
- ### 4. ⚡ Efficient Step Grouping
75
- Group related steps to run in the same container - reduce overhead, maintain clarity.
81
+ ### 4. ⚡ Efficient Step Grouping & Separation of Concerns
82
+ Group related steps to run in the same container - reduce overhead, maintain clarity, and keep logic separate from configuration.
76
83
 
77
84
  ```python
78
85
  # Run preprocessing steps in same container (shares resources)
@@ -189,12 +196,13 @@ pipeline.run(debug=True) # Pauses at breakpoint
189
196
  ```
190
197
 
191
198
  ### 13. 📦 First-Class Assets
192
- Specialized types for ML workflows.
199
+ Assets are not just files; they are first-class citizens with lineage, metadata, and versioning.
193
200
 
194
201
  ```python
195
202
  from flowyml.core import Dataset, Model, Metrics, FeatureSet
196
203
 
197
- dataset = Dataset.create(data=df, name="training_data")
204
+ # Assets track their producer, lineage, and metadata automatically
205
+ dataset = Dataset.create(data=df, name="training_data", metadata={"source": "s3"})
198
206
  model = Model.create(artifact=trained_model, score=0.95)
199
207
  metrics = Metrics.create(values={"accuracy": 0.95})
200
208
  ```
@@ -236,11 +244,80 @@ if drift['drift_detected']:
236
244
  - **🔔 Notifications**: Slack/Email alerts.
237
245
  - **🛡️ Circuit Breakers**: Stop cascading failures.
238
246
 
239
- ### 18. 🔌 Universal Integrations
247
+ ### 18. 🏢 Centralized Hub & Docker
248
+ Ready for the enterprise. Run locally per project or deploy as a centralized entity for the company.
249
+ - **Docker Ready**: Backend and Frontend are fully dockerized.
250
+ - **Centralized Hub**: Share pipelines, artifacts, and experiments across the team.
251
+ - **Remote Execution**: Configure local clients to execute on the remote hub.
252
+
253
+ ### 19. 🔌 Universal Integrations
240
254
  - **ML Frameworks**: PyTorch, TensorFlow, Keras, Scikit-learn, HuggingFace.
241
255
  - **Cloud Providers**: AWS, GCP, Azure (via plugins).
242
256
  - **Tools**: MLflow, Weights & Biases, Great Expectations.
243
257
 
258
+ ### 20. 📊 Automatic Training History Tracking
259
+ FlowyML automatically captures and visualizes your model training progress with zero manual intervention.
260
+
261
+ ```python
262
+ from flowyml.integrations.keras import FlowymlKerasCallback
263
+
264
+ # Just add the callback - that's it!
265
+ callback = FlowymlKerasCallback(
266
+ experiment_name="my-experiment",
267
+ project="my-project"
268
+ )
269
+
270
+ model.fit(
271
+ x_train, y_train,
272
+ validation_data=(x_val, y_val),
273
+ epochs=50,
274
+ callbacks=[callback] # Auto-tracks all metrics!
275
+ )
276
+ ```
277
+
278
+ **What gets captured automatically:**
279
+ - ✅ Loss (train & validation) per epoch
280
+ - ✅ Accuracy (train & validation) per epoch
281
+ - ✅ All custom metrics (F1, precision, recall, etc.)
282
+ - ✅ Model architecture and parameters
283
+ - ✅ Interactive charts in the UI
284
+
285
+ **View beautiful training graphs in the UI:**
286
+ 1. Navigate to your project's Structure tab
287
+ 2. Click on any model artifact
288
+ 3. See interactive loss/accuracy charts over epochs!
289
+
290
+ No external tools needed - all visualization built into FlowyML.
291
+
292
+ ### 21. 📂 Project-Based Organization
293
+ Built-in multi-tenancy for managing multiple teams and initiatives.
294
+
295
+ ```python
296
+ from flowyml import Project
297
+
298
+ project = Project("recommendation_system")
299
+ pipeline = project.create_pipeline("training")
300
+
301
+ # All runs, artifacts, and metadata are automatically scoped to the project
302
+ runs = project.list_runs()
303
+ stats = project.get_stats()
304
+ ```
305
+
306
+ ### 22. 📝 Pipeline Templates
307
+ Stop reinventing the wheel. Use pre-built templates for common ML patterns.
308
+
309
+ ```python
310
+ from flowyml.core.templates import create_from_template
311
+
312
+ # Create a standard training pipeline in one line
313
+ pipeline = create_from_template(
314
+ "ml_training",
315
+ data_loader=my_loader,
316
+ trainer=my_trainer,
317
+ evaluator=my_evaluator
318
+ )
319
+ ```
320
+
244
321
  ## 📦 Installation
245
322
 
246
323
  ```bash
@@ -290,6 +367,26 @@ print(f"Run ID: {result.run_id}")
290
367
  print(f"Model Score: {result.outputs['model'].score}")
291
368
  ```
292
369
 
370
+ ### 23. 🌐 Pipeline Versioning
371
+ Git-like versioning for pipelines. Track changes, compare, rollback.
372
+
373
+ ```python
374
+ from flowyml import VersionedPipeline
375
+
376
+ pipeline = VersionedPipeline("training", version="v1.0.0")
377
+ pipeline.add_step(load_data)
378
+ pipeline.save_version()
379
+
380
+ # ... make changes ...
381
+ pipeline.version = "v1.1.0"
382
+ pipeline.save_version()
383
+
384
+ # Compare versions to see exactly what changed (steps, code, context)
385
+ diff = pipeline.compare_with("v1.0.0")
386
+ print(diff["modified_steps"]) # ['train_model']
387
+ print(diff["context_changes"]) # {'learning_rate': {'old': 0.01, 'new': 0.001}}
388
+ ```
389
+
293
390
  ## 🖥️ The flowyml UI
294
391
 
295
392
  Visualize your workflows, inspect artifacts, and monitor runs in real-time.
@@ -38,6 +38,7 @@ from flowyml.assets.registry import AssetRegistry
38
38
  # Stack imports
39
39
  from flowyml.stacks.base import Stack
40
40
  from flowyml.stacks.local import LocalStack
41
+ from flowyml.stacks.components import ResourceConfig, DockerConfig
41
42
 
42
43
  # Tracking imports
43
44
  from flowyml.tracking.experiment import Experiment
@@ -140,6 +141,8 @@ __all__ = [
140
141
  # Stacks
141
142
  "Stack",
142
143
  "LocalStack",
144
+ "ResourceConfig",
145
+ "DockerConfig",
143
146
  # Tracking
144
147
  "Experiment",
145
148
  "Run",
@@ -77,6 +77,16 @@ class Asset:
77
77
  if parent:
78
78
  parent.children.append(self)
79
79
 
80
+ @property
81
+ def properties(self) -> dict[str, Any]:
82
+ """Expose mutable properties stored in metadata."""
83
+ return self.metadata.properties
84
+
85
+ @property
86
+ def tags(self) -> dict[str, str]:
87
+ """Expose mutable tags stored in metadata."""
88
+ return self.metadata.tags
89
+
80
90
  @classmethod
81
91
  def create(
82
92
  cls,
@@ -89,7 +89,10 @@ class Metrics(Asset):
89
89
  def create(
90
90
  cls,
91
91
  name: str | None = None,
92
+ version: str | None = None,
92
93
  parent: Asset | None = None,
94
+ tags: dict[str, str] | None = None,
95
+ properties: dict[str, Any] | None = None,
93
96
  **metrics,
94
97
  ) -> "Metrics":
95
98
  """Factory method to create metrics.
@@ -99,6 +102,9 @@ class Metrics(Asset):
99
102
  """
100
103
  return cls(
101
104
  name=name or "metrics",
105
+ version=version,
102
106
  data=metrics,
103
107
  parent=parent,
108
+ tags=tags,
109
+ properties=properties,
104
110
  )
@@ -48,9 +48,11 @@ def init(name: str, template: str, directory: str) -> None:
48
48
  @click.option("--stack", default="local", help="Stack to use for execution")
49
49
  @click.option("--context", "-c", multiple=True, help="Context parameters (key=value)")
50
50
  @click.option("--debug", is_flag=True, help="Enable debug mode")
51
- def run(pipeline_name: str, stack: str, context: tuple, debug: bool) -> None:
51
+ @click.option("--retry", type=int, help="Number of retries for the pipeline")
52
+ def run(pipeline_name: str, stack: str, context: tuple, debug: bool, retry: int | None) -> None:
52
53
  """Run a pipeline."""
53
54
  from flowyml.cli.run import run_pipeline
55
+ from flowyml.core.retry_policy import OrchestratorRetryPolicy
54
56
 
55
57
  # Parse context parameters
56
58
  ctx_params = {}
@@ -60,8 +62,13 @@ def run(pipeline_name: str, stack: str, context: tuple, debug: bool) -> None:
60
62
 
61
63
  click.echo(f"Running pipeline '{pipeline_name}' on stack '{stack}'...")
62
64
 
65
+ kwargs = {}
66
+ if retry:
67
+ kwargs["retry_policy"] = OrchestratorRetryPolicy(max_attempts=retry)
68
+ click.echo(f" Retry policy enabled: max_attempts={retry}")
69
+
63
70
  try:
64
- result = run_pipeline(pipeline_name, stack, ctx_params, debug)
71
+ result = run_pipeline(pipeline_name, stack, ctx_params, debug, **kwargs)
65
72
  click.echo("✓ Pipeline completed successfully")
66
73
  click.echo(f" Run ID: {result.get('run_id', 'N/A')}")
67
74
  click.echo(f" Duration: {result.get('duration', 'N/A')}")
@@ -70,6 +77,105 @@ def run(pipeline_name: str, stack: str, context: tuple, debug: bool) -> None:
70
77
  raise click.Abort()
71
78
 
72
79
 
80
+ @cli.group()
81
+ def schedule() -> None:
82
+ """Schedule management commands."""
83
+ pass
84
+
85
+
86
+ @schedule.command("create")
87
+ @click.argument("pipeline_name")
88
+ @click.argument("schedule_type", type=click.Choice(["cron", "interval", "daily", "hourly"]))
89
+ @click.argument("value")
90
+ @click.option("--stack", default="local", help="Stack to use for execution")
91
+ def create_schedule(pipeline_name: str, schedule_type: str, value: str, stack: str) -> None:
92
+ """Create a new schedule for a pipeline.
93
+
94
+ VALUE format depends on SCHEDULE_TYPE:
95
+ - cron: "*/5 * * * *"
96
+ - interval: seconds (e.g. 60)
97
+ - daily: "HH:MM" (e.g. 14:30)
98
+ - hourly: minute (e.g. 30)
99
+ """
100
+ from flowyml.core.scheduler import PipelineScheduler
101
+ from flowyml.cli.run import run_pipeline
102
+
103
+ # We need a callable for the scheduler.
104
+ # Since CLI is stateless, we wrap the run_pipeline command.
105
+ # Note: In a real distributed system, this would submit to a scheduler service.
106
+ # Here we are just registering it in the local scheduler DB.
107
+
108
+ # For now, we'll just use the scheduler API to register the definition
109
+ scheduler = PipelineScheduler()
110
+
111
+ # Define a wrapper that runs the pipeline via CLI logic
112
+ def job_func():
113
+ run_pipeline(pipeline_name, stack, {}, False)
114
+
115
+ try:
116
+ if schedule_type == "cron":
117
+ scheduler.schedule_cron(pipeline_name, job_func, value)
118
+ elif schedule_type == "interval":
119
+ scheduler.schedule_interval(pipeline_name, job_func, seconds=int(value))
120
+ elif schedule_type == "daily":
121
+ if ":" in value:
122
+ h, m = map(int, value.split(":"))
123
+ scheduler.schedule_daily(pipeline_name, job_func, hour=h, minute=m)
124
+ else:
125
+ raise ValueError("Daily value must be HH:MM")
126
+ elif schedule_type == "hourly":
127
+ scheduler.schedule_hourly(pipeline_name, job_func, minute=int(value))
128
+
129
+ click.echo(f"✓ Schedule created for '{pipeline_name}' ({schedule_type}={value})")
130
+ click.echo(" Note: Ensure the scheduler service is running to execute this schedule.")
131
+ except Exception as e:
132
+ click.echo(f"✗ Error creating schedule: {e}", err=True)
133
+
134
+
135
+ @schedule.command("list")
136
+ def list_schedules() -> None:
137
+ """List all active schedules."""
138
+ from flowyml.core.scheduler import PipelineScheduler
139
+
140
+ scheduler = PipelineScheduler()
141
+ jobs = scheduler.get_jobs()
142
+
143
+ if not jobs:
144
+ click.echo("No active schedules found.")
145
+ return
146
+
147
+ click.echo(f"Found {len(jobs)} schedules:\n")
148
+ for job in jobs:
149
+ click.echo(f" {job.id} - {job.name}")
150
+ click.echo(f" Next run: {job.next_run_time}")
151
+ click.echo()
152
+
153
+
154
+ @schedule.command("start")
155
+ def start_scheduler() -> None:
156
+ """Start the scheduler service (blocking)."""
157
+ from flowyml.core.scheduler import PipelineScheduler
158
+ import time
159
+
160
+ click.echo("🚀 Starting Scheduler Service...")
161
+ scheduler = PipelineScheduler()
162
+
163
+ try:
164
+ # In a real app, this would load definitions from DB and register them
165
+ # For now, it just runs the scheduler loop for existing in-memory jobs
166
+ # (which might be empty if we restarted).
167
+ # To make this persistent, we'd need to serialize job definitions to DB.
168
+ # The current Scheduler implementation supports SQLite persistence for job state,
169
+ # but we need to re-register jobs on startup.
170
+
171
+ click.echo(" Scheduler running. Press Ctrl+C to stop.")
172
+ while True:
173
+ scheduler.run_pending()
174
+ time.sleep(1)
175
+ except KeyboardInterrupt:
176
+ click.echo("\n🛑 Scheduler stopped.")
177
+
178
+
73
179
  @cli.group()
74
180
  def ui() -> None:
75
181
  """UI server commands."""
@@ -6,7 +6,13 @@ from pathlib import Path
6
6
  from typing import Any
7
7
 
8
8
 
9
- def run_pipeline(pipeline_name: str, stack: str, context_params: dict[str, Any], debug: bool) -> dict[str, Any]:
9
+ def run_pipeline(
10
+ pipeline_name: str,
11
+ stack: str,
12
+ context_params: dict[str, Any],
13
+ debug: bool,
14
+ **kwargs,
15
+ ) -> dict[str, Any]:
10
16
  """Run a pipeline by name.
11
17
 
12
18
  Args:
@@ -14,6 +20,7 @@ def run_pipeline(pipeline_name: str, stack: str, context_params: dict[str, Any],
14
20
  stack: Stack to use for execution
15
21
  context_params: Context parameters to override
16
22
  debug: Enable debug mode
23
+ **kwargs: Additional arguments passed to pipeline.run
17
24
 
18
25
  Returns:
19
26
  Dictionary with run results
@@ -65,7 +72,7 @@ def run_pipeline(pipeline_name: str, stack: str, context_params: dict[str, Any],
65
72
  pipeline.set_stack(stack)
66
73
 
67
74
  # Run pipeline
68
- result = pipeline.run(debug=debug)
75
+ result = pipeline.run(debug=debug, **kwargs)
69
76
 
70
77
  return {
71
78
  "run_id": result.run_id,
@@ -0,0 +1,52 @@
1
+ """Execution status tracking for pipeline runs."""
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class ExecutionStatus(str, Enum):
7
+ """Status of a pipeline or step execution."""
8
+
9
+ # Pre-execution states
10
+ INITIALIZING = "initializing"
11
+ PROVISIONING = "provisioning"
12
+
13
+ # Active execution states
14
+ RUNNING = "running"
15
+
16
+ # Terminal success states
17
+ COMPLETED = "completed"
18
+ CACHED = "cached"
19
+
20
+ # Terminal failure states
21
+ FAILED = "failed"
22
+ STOPPED = "stopped"
23
+ CANCELLED = "cancelled"
24
+
25
+ # Intermediate states
26
+ STOPPING = "stopping"
27
+ CANCELLING = "cancelling"
28
+
29
+ @property
30
+ def is_finished(self) -> bool:
31
+ """Check if execution is in a terminal state."""
32
+ return self in {
33
+ ExecutionStatus.COMPLETED,
34
+ ExecutionStatus.CACHED,
35
+ ExecutionStatus.FAILED,
36
+ ExecutionStatus.STOPPED,
37
+ ExecutionStatus.CANCELLED,
38
+ }
39
+
40
+ @property
41
+ def is_successful(self) -> bool:
42
+ """Check if execution completed successfully."""
43
+ return self in {ExecutionStatus.COMPLETED, ExecutionStatus.CACHED}
44
+
45
+ @property
46
+ def is_failed(self) -> bool:
47
+ """Check if execution failed."""
48
+ return self in {
49
+ ExecutionStatus.FAILED,
50
+ ExecutionStatus.STOPPED,
51
+ ExecutionStatus.CANCELLED,
52
+ }