ms-flow 0.1.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 (172) hide show
  1. ms_flow-0.1.0/.github/workflows/docs.yml +58 -0
  2. ms_flow-0.1.0/.github/workflows/publish.yml +31 -0
  3. ms_flow-0.1.0/.gitignore +37 -0
  4. ms_flow-0.1.0/LICENSE +21 -0
  5. ms_flow-0.1.0/PKG-INFO +77 -0
  6. ms_flow-0.1.0/README.md +45 -0
  7. ms_flow-0.1.0/docs/api_guide.md +191 -0
  8. ms_flow-0.1.0/docs/api_reference.md +46 -0
  9. ms_flow-0.1.0/docs/examples.md +191 -0
  10. ms_flow-0.1.0/docs/index.md +83 -0
  11. ms_flow-0.1.0/pyproject.toml +77 -0
  12. ms_flow-0.1.0/setup.cfg +4 -0
  13. ms_flow-0.1.0/src/ms_flow/__init__.py +26 -0
  14. ms_flow-0.1.0/src/ms_flow/_api_impl/__init__.py +9 -0
  15. ms_flow-0.1.0/src/ms_flow/_api_impl/advanced.py +64 -0
  16. ms_flow-0.1.0/src/ms_flow/_api_impl/job_api.py +579 -0
  17. ms_flow-0.1.0/src/ms_flow/_api_impl/project_runtime.py +886 -0
  18. ms_flow-0.1.0/src/ms_flow/advanced.py +5 -0
  19. ms_flow-0.1.0/src/ms_flow/api.py +79 -0
  20. ms_flow-0.1.0/src/ms_flow/artifacts.py +329 -0
  21. ms_flow-0.1.0/src/ms_flow/core/__init__.py +0 -0
  22. ms_flow-0.1.0/src/ms_flow/core/app_settings.py +133 -0
  23. ms_flow-0.1.0/src/ms_flow/core/apps.py +173 -0
  24. ms_flow-0.1.0/src/ms_flow/core/callable_refs.py +66 -0
  25. ms_flow-0.1.0/src/ms_flow/core/configuration.py +365 -0
  26. ms_flow-0.1.0/src/ms_flow/core/data/__init__.py +53 -0
  27. ms_flow-0.1.0/src/ms_flow/core/data/backends.py +708 -0
  28. ms_flow-0.1.0/src/ms_flow/core/data/bridge.py +212 -0
  29. ms_flow-0.1.0/src/ms_flow/core/data/contracts.py +534 -0
  30. ms_flow-0.1.0/src/ms_flow/core/data/planner.py +75 -0
  31. ms_flow-0.1.0/src/ms_flow/core/data/project_output.py +27 -0
  32. ms_flow-0.1.0/src/ms_flow/core/data/runtime.py +72 -0
  33. ms_flow-0.1.0/src/ms_flow/core/data/shard.py +556 -0
  34. ms_flow-0.1.0/src/ms_flow/core/database/__init__.py +33 -0
  35. ms_flow-0.1.0/src/ms_flow/core/database/base.py +229 -0
  36. ms_flow-0.1.0/src/ms_flow/core/database/executor.py +218 -0
  37. ms_flow-0.1.0/src/ms_flow/core/database/executor_models.py +112 -0
  38. ms_flow-0.1.0/src/ms_flow/core/database/master.py +168 -0
  39. ms_flow-0.1.0/src/ms_flow/core/database/master_models.py +40 -0
  40. ms_flow-0.1.0/src/ms_flow/core/database/project.py +678 -0
  41. ms_flow-0.1.0/src/ms_flow/core/database/project_models.py +59 -0
  42. ms_flow-0.1.0/src/ms_flow/core/database/project_records.py +100 -0
  43. ms_flow-0.1.0/src/ms_flow/core/database/project_store_ops.py +958 -0
  44. ms_flow-0.1.0/src/ms_flow/core/database/sqlite_utils.py +208 -0
  45. ms_flow-0.1.0/src/ms_flow/core/events.py +5 -0
  46. ms_flow-0.1.0/src/ms_flow/core/executor/__init__.py +62 -0
  47. ms_flow-0.1.0/src/ms_flow/core/executor/backend_selector.py +254 -0
  48. ms_flow-0.1.0/src/ms_flow/core/executor/command_inbox.py +40 -0
  49. ms_flow-0.1.0/src/ms_flow/core/executor/dispatch_model.py +71 -0
  50. ms_flow-0.1.0/src/ms_flow/core/executor/dispatch_service.py +397 -0
  51. ms_flow-0.1.0/src/ms_flow/core/executor/executor_registry.py +236 -0
  52. ms_flow-0.1.0/src/ms_flow/core/executor/hpc_adapter.py +436 -0
  53. ms_flow-0.1.0/src/ms_flow/core/executor/hpc_runtime.py +124 -0
  54. ms_flow-0.1.0/src/ms_flow/core/executor/job_monitoring.py +666 -0
  55. ms_flow-0.1.0/src/ms_flow/core/executor/job_snapshot.py +124 -0
  56. ms_flow-0.1.0/src/ms_flow/core/executor/lifecycle_controller.py +369 -0
  57. ms_flow-0.1.0/src/ms_flow/core/executor/local_adapters.py +497 -0
  58. ms_flow-0.1.0/src/ms_flow/core/executor/local_compute_scheduler.py +116 -0
  59. ms_flow-0.1.0/src/ms_flow/core/executor/local_scheduler.py +169 -0
  60. ms_flow-0.1.0/src/ms_flow/core/executor/manager/__init__.py +15 -0
  61. ms_flow-0.1.0/src/ms_flow/core/executor/manager/_manager.py +1904 -0
  62. ms_flow-0.1.0/src/ms_flow/core/executor/provisioning.py +443 -0
  63. ms_flow-0.1.0/src/ms_flow/core/executor/ray_adapter.py +452 -0
  64. ms_flow-0.1.0/src/ms_flow/core/executor/resource_manager.py +65 -0
  65. ms_flow-0.1.0/src/ms_flow/core/executor/result_handlers.py +696 -0
  66. ms_flow-0.1.0/src/ms_flow/core/executor/runner_refs.py +152 -0
  67. ms_flow-0.1.0/src/ms_flow/core/executor/runtime_state.py +209 -0
  68. ms_flow-0.1.0/src/ms_flow/core/executor/runtime_status_service.py +408 -0
  69. ms_flow-0.1.0/src/ms_flow/core/executor/services/__init__.py +0 -0
  70. ms_flow-0.1.0/src/ms_flow/core/executor/services/dispatch_pool.py +230 -0
  71. ms_flow-0.1.0/src/ms_flow/core/executor/services/event_recorder.py +155 -0
  72. ms_flow-0.1.0/src/ms_flow/core/executor/services/feeding.py +274 -0
  73. ms_flow-0.1.0/src/ms_flow/core/executor/services/job_commands.py +258 -0
  74. ms_flow-0.1.0/src/ms_flow/core/executor/services/job_status.py +481 -0
  75. ms_flow-0.1.0/src/ms_flow/core/executor/services/job_store.py +350 -0
  76. ms_flow-0.1.0/src/ms_flow/core/executor/services/payload_store.py +166 -0
  77. ms_flow-0.1.0/src/ms_flow/core/executor/services/persistence_coordinator.py +240 -0
  78. ms_flow-0.1.0/src/ms_flow/core/executor/services/sink_writer_pool.py +122 -0
  79. ms_flow-0.1.0/src/ms_flow/core/executor/staging_manager.py +131 -0
  80. ms_flow-0.1.0/src/ms_flow/core/executor/submission_service.py +604 -0
  81. ms_flow-0.1.0/src/ms_flow/core/executor/utils.py +40 -0
  82. ms_flow-0.1.0/src/ms_flow/core/project/__init__.py +21 -0
  83. ms_flow-0.1.0/src/ms_flow/core/project/catalog.py +343 -0
  84. ms_flow-0.1.0/src/ms_flow/core/project/context.py +45 -0
  85. ms_flow-0.1.0/src/ms_flow/core/project/manager.py +193 -0
  86. ms_flow-0.1.0/src/ms_flow/core/project/repository.py +264 -0
  87. ms_flow-0.1.0/src/ms_flow/core/project/resources.py +150 -0
  88. ms_flow-0.1.0/src/ms_flow/core/project/state.py +45 -0
  89. ms_flow-0.1.0/src/ms_flow/core/settings/__init__.py +0 -0
  90. ms_flow-0.1.0/src/ms_flow/core/settings/defaults.toml +42 -0
  91. ms_flow-0.1.0/src/ms_flow/core/settings/manager.py +397 -0
  92. ms_flow-0.1.0/src/ms_flow/core/settings/models.py +412 -0
  93. ms_flow-0.1.0/src/ms_flow/job_templates.py +171 -0
  94. ms_flow-0.1.0/src/ms_flow/logger.py +316 -0
  95. ms_flow-0.1.0/src/ms_flow/main.py +164 -0
  96. ms_flow-0.1.0/src/ms_flow/progress.py +70 -0
  97. ms_flow-0.1.0/src/ms_flow/query.py +255 -0
  98. ms_flow-0.1.0/src/ms_flow/runtime.py +208 -0
  99. ms_flow-0.1.0/src/ms_flow/selection.py +70 -0
  100. ms_flow-0.1.0/src/ms_flow/sinks.py +180 -0
  101. ms_flow-0.1.0/src/ms_flow/specs/__init__.py +42 -0
  102. ms_flow-0.1.0/src/ms_flow/specs/input.py +260 -0
  103. ms_flow-0.1.0/src/ms_flow/specs/output.py +73 -0
  104. ms_flow-0.1.0/src/ms_flow/specs/processor.py +30 -0
  105. ms_flow-0.1.0/src/ms_flow/specs/workflow.py +176 -0
  106. ms_flow-0.1.0/src/ms_flow/tasking.py +771 -0
  107. ms_flow-0.1.0/src/ms_flow.egg-info/PKG-INFO +77 -0
  108. ms_flow-0.1.0/src/ms_flow.egg-info/SOURCES.txt +170 -0
  109. ms_flow-0.1.0/src/ms_flow.egg-info/dependency_links.txt +1 -0
  110. ms_flow-0.1.0/src/ms_flow.egg-info/requires.txt +13 -0
  111. ms_flow-0.1.0/src/ms_flow.egg-info/scm_file_list.json +167 -0
  112. ms_flow-0.1.0/src/ms_flow.egg-info/scm_version.json +8 -0
  113. ms_flow-0.1.0/src/ms_flow.egg-info/top_level.txt +1 -0
  114. ms_flow-0.1.0/tests/adapter_contracts.py +142 -0
  115. ms_flow-0.1.0/tests/adapter_test_fakes.py +179 -0
  116. ms_flow-0.1.0/tests/adversarial_runtime_scenarios.py +390 -0
  117. ms_flow-0.1.0/tests/conftest.py +28 -0
  118. ms_flow-0.1.0/tests/test_app_registry.py +173 -0
  119. ms_flow-0.1.0/tests/test_artifact_registry.py +135 -0
  120. ms_flow-0.1.0/tests/test_backend_selector.py +101 -0
  121. ms_flow-0.1.0/tests/test_batched_overhead_benchmark.py +88 -0
  122. ms_flow-0.1.0/tests/test_benchmark.py +76 -0
  123. ms_flow-0.1.0/tests/test_data_api.py +109 -0
  124. ms_flow-0.1.0/tests/test_data_backend.py +444 -0
  125. ms_flow-0.1.0/tests/test_database_manager.py +92 -0
  126. ms_flow-0.1.0/tests/test_database_migrations.py +123 -0
  127. ms_flow-0.1.0/tests/test_db_pages.py +67 -0
  128. ms_flow-0.1.0/tests/test_deferred_chunk_resources.py +25 -0
  129. ms_flow-0.1.0/tests/test_dispatch_model.py +64 -0
  130. ms_flow-0.1.0/tests/test_executor_adapter_contracts.py +193 -0
  131. ms_flow-0.1.0/tests/test_executor_adapter_contracts_remote.py +291 -0
  132. ms_flow-0.1.0/tests/test_executor_manager.py +3623 -0
  133. ms_flow-0.1.0/tests/test_executor_retention.py +50 -0
  134. ms_flow-0.1.0/tests/test_file_sink_append.py +82 -0
  135. ms_flow-0.1.0/tests/test_gpu_token_semaphore.py +112 -0
  136. ms_flow-0.1.0/tests/test_graph_deferred_relation.py +125 -0
  137. ms_flow-0.1.0/tests/test_hpc_io_threads.py +71 -0
  138. ms_flow-0.1.0/tests/test_hpc_reattach.py +114 -0
  139. ms_flow-0.1.0/tests/test_job_templates.py +203 -0
  140. ms_flow-0.1.0/tests/test_jobspec_api.py +68 -0
  141. ms_flow-0.1.0/tests/test_local_compute_scheduler.py +69 -0
  142. ms_flow-0.1.0/tests/test_local_scheduler.py +162 -0
  143. ms_flow-0.1.0/tests/test_logging_manager.py +135 -0
  144. ms_flow-0.1.0/tests/test_molsuite_runtime.py +1137 -0
  145. ms_flow-0.1.0/tests/test_mrf070_runtime_overhead_benchmark.py +209 -0
  146. ms_flow-0.1.0/tests/test_mrf072_monitor_stability.py +240 -0
  147. ms_flow-0.1.0/tests/test_operational_store.py +43 -0
  148. ms_flow-0.1.0/tests/test_output_helpers.py +290 -0
  149. ms_flow-0.1.0/tests/test_output_sink_batching.py +291 -0
  150. ms_flow-0.1.0/tests/test_overhead_benchmark.py +97 -0
  151. ms_flow-0.1.0/tests/test_process_executor_benchmark.py +111 -0
  152. ms_flow-0.1.0/tests/test_progress.py +38 -0
  153. ms_flow-0.1.0/tests/test_project_catalog.py +146 -0
  154. ms_flow-0.1.0/tests/test_project_manager.py +82 -0
  155. ms_flow-0.1.0/tests/test_project_storage.py +22 -0
  156. ms_flow-0.1.0/tests/test_project_store.py +431 -0
  157. ms_flow-0.1.0/tests/test_provisioning.py +99 -0
  158. ms_flow-0.1.0/tests/test_public_api.py +148 -0
  159. ms_flow-0.1.0/tests/test_pydantic_configuration.py +79 -0
  160. ms_flow-0.1.0/tests/test_remote_e2e_optional.py +49 -0
  161. ms_flow-0.1.0/tests/test_resource_manager.py +32 -0
  162. ms_flow-0.1.0/tests/test_selection.py +30 -0
  163. ms_flow-0.1.0/tests/test_settings_manager.py +217 -0
  164. ms_flow-0.1.0/tests/test_shard_container.py +144 -0
  165. ms_flow-0.1.0/tests/test_simple_api.py +226 -0
  166. ms_flow-0.1.0/tests/test_sink_column_defaults.py +58 -0
  167. ms_flow-0.1.0/tests/test_sink_writer_pool.py +63 -0
  168. ms_flow-0.1.0/tests/test_sql_compiler.py +104 -0
  169. ms_flow-0.1.0/tests/test_staging_manager.py +78 -0
  170. ms_flow-0.1.0/tests/test_tasking_api.py +1129 -0
  171. ms_flow-0.1.0/tests/test_workflow_api.py +130 -0
  172. ms_flow-0.1.0/zensical.toml +79 -0
@@ -0,0 +1,58 @@
1
+ name: Documentation
2
+ on:
3
+ push:
4
+ branches:
5
+ - main
6
+ tags:
7
+ - "v*"
8
+ workflow_dispatch:
9
+
10
+ concurrency:
11
+ group: documentation
12
+ cancel-in-progress: false
13
+
14
+ permissions:
15
+ contents: write
16
+ pages: write
17
+ id-token: write
18
+
19
+ jobs:
20
+ deploy:
21
+ environment:
22
+ name: github-pages
23
+ url: ${{ steps.deployment.outputs.page_url }}
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v6
27
+ with:
28
+ fetch-depth: 0
29
+ - uses: actions/configure-pages@v6
30
+ - uses: actions/setup-python@v6
31
+ with:
32
+ python-version: 3.x
33
+ - run: pip install zensical "mkdocstrings[python]" "mike @ git+https://github.com/squidfunk/mike.git"
34
+ - name: Configure Git author
35
+ run: |
36
+ git config user.name "github-actions[bot]"
37
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
38
+ - name: Deploy development documentation
39
+ if: github.ref == 'refs/heads/main'
40
+ run: |
41
+ mike deploy --push dev
42
+ if ! mike list latest >/dev/null 2>&1; then
43
+ mike set-default --push dev
44
+ fi
45
+ - name: Deploy release documentation
46
+ if: startsWith(github.ref, 'refs/tags/v')
47
+ run: |
48
+ mike deploy --push --update-aliases --alias-type redirect "$GITHUB_REF_NAME" latest
49
+ mike set-default --push latest
50
+ - name: Export versioned site
51
+ run: |
52
+ mkdir -p site
53
+ git archive gh-pages | tar -x -C site
54
+ - uses: actions/upload-pages-artifact@v5
55
+ with:
56
+ path: site
57
+ - uses: actions/deploy-pages@v5
58
+ id: deployment
@@ -0,0 +1,31 @@
1
+ # Publish to PyPI on a GitHub release.
2
+ #
3
+ # No secrets: the job authenticates to PyPI over OIDC (Trusted Publishing).
4
+ # It has to be enabled on the PyPI side *before* the first upload -- for a
5
+ # project that does not exist yet, that is a "pending publisher" under
6
+ # Your projects > Publishing, and it must name this repo, `publish.yml`
7
+ # and the `pypi` environment below.
8
+ name: publish
9
+
10
+ on:
11
+ release:
12
+ types: [published]
13
+
14
+ jobs:
15
+ pypi:
16
+ runs-on: ubuntu-latest
17
+ environment: pypi
18
+ permissions:
19
+ # A permissions block sets every scope it does not name to none, so
20
+ # checkout needs contents spelled out or it cannot read a private repo.
21
+ contents: read
22
+ id-token: write # mint the OIDC token PyPI checks; no secret involved
23
+ steps:
24
+ - uses: actions/checkout@v7
25
+ with:
26
+ fetch-depth: 0 # setuptools-scm reads the version off the tag
27
+ - uses: actions/setup-python@v7
28
+ with:
29
+ python-version: "3.12"
30
+ - run: pipx run build
31
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,37 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ build/
6
+ dist/
7
+ .eggs/
8
+
9
+ # Test / coverage
10
+ .pytest_cache/
11
+ .coverage
12
+ htmlcov/
13
+
14
+ # Benchmark output (disposable, large)
15
+ .bench_runs/
16
+
17
+ # IDE / editor
18
+ .idea/
19
+ .vscode/
20
+
21
+ # Envs
22
+ .venv/
23
+ venv/
24
+
25
+ # Artefactos de corridas (ejemplos, proyectos de prueba)
26
+ demo_project/
27
+ chunk_payloads/
28
+ *.db
29
+ *.db-shm
30
+ *.db-wal
31
+ *.log
32
+
33
+ # Agentes / herramientas locales
34
+ .claude/
35
+ .aiassistant/
36
+
37
+ .idea/
ms_flow-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Mario S. Valdés-Tresanco, Mario E. Valdés-Tresanco, Ernesto Moreno, Pedro A. Valiente
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
ms_flow-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,77 @@
1
+ Metadata-Version: 2.4
2
+ Name: ms_flow
3
+ Version: 0.1.0
4
+ Summary: In-process, desktop-first, domain-agnostic job/task/executor orchestrator for massive data flows.
5
+ Author: Mario S. Valdés-Tresanco, Mario E. Valdés-Tresanco, Ernesto Moreno, Pedro A. Valiente
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/MolSuite/ms_flow
8
+ Project-URL: Documentation, https://github.com/MolSuite/ms_flow/tree/main/docs
9
+ Project-URL: Issues, https://github.com/MolSuite/ms_flow/issues
10
+ Keywords: orchestration,executor,jobs,pipeline,scientific-computing
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Programming Language :: Python :: 3 :: Only
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Topic :: Scientific/Engineering
17
+ Requires-Python: >=3.12
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: blinker>=1.6
21
+ Requires-Dist: loky>=3.0
22
+ Requires-Dist: pydantic>=2.0
23
+ Requires-Dist: sqlalchemy>=2.0
24
+ Requires-Dist: sqlmodel>=0.0.14
25
+ Requires-Dist: toml>=0.10
26
+ Requires-Dist: tqdm>=4.66
27
+ Provides-Extra: ray
28
+ Requires-Dist: ray>=2.6; extra == "ray"
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=7.0; extra == "dev"
31
+ Dynamic: license-file
32
+
33
+ # ms_flow
34
+
35
+ In-process, desktop-first, domain-agnostic orchestrator for massive data flows:
36
+ jobs, executors and persistence in the same process as your app — no broker, no
37
+ daemon, no server. Works from a Qt app, a notebook or a plain script.
38
+
39
+ ```python
40
+ from ms_flow.api import MolSuite, table_sink
41
+ from workers import double_value # el handler vive en un modulo importable
42
+
43
+ ms = MolSuite(app_id="demo")
44
+ ms.create_or_open_project(name="demo", folder="./demo_project", activate=True)
45
+
46
+ job_id = ms.run(
47
+ name="double_values",
48
+ input=[{"value": v} for v in range(1000)],
49
+ process=double_value,
50
+ output=table_sink("results", columns=("value", "double_value")),
51
+ executor="thread",
52
+ )
53
+ print(ms.wait_for_job(job_id).status)
54
+ ```
55
+
56
+ ## Install
57
+
58
+ ```bash
59
+ pip install ms_flow # core: control plane + SQLite + loky
60
+ pip install "ms_flow[ray]" # Ray executor
61
+ ```
62
+
63
+ ## Where to look
64
+
65
+ - [5-minute quickstart](docs/guides/quickstart_5min.md) — first working job.
66
+ - [Runnable examples](examples/README.md) — scripts y notebook.
67
+ - [Public API](docs/guides/public_api.md) — API.
68
+ - [Docs index](docs/README.md) — guides, contracts, operation
69
+ - [Benchmarks](benchmarks/README.md) — performance.
70
+
71
+ ## Status
72
+
73
+ Beta. The public API (`ms_flow.api`) is the stable surface; `ms_flow.core.*` may change without notice.
74
+
75
+ ## License
76
+
77
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,45 @@
1
+ # ms_flow
2
+
3
+ In-process, desktop-first, domain-agnostic orchestrator for massive data flows:
4
+ jobs, executors and persistence in the same process as your app — no broker, no
5
+ daemon, no server. Works from a Qt app, a notebook or a plain script.
6
+
7
+ ```python
8
+ from ms_flow.api import MolSuite, table_sink
9
+ from workers import double_value # el handler vive en un modulo importable
10
+
11
+ ms = MolSuite(app_id="demo")
12
+ ms.create_or_open_project(name="demo", folder="./demo_project", activate=True)
13
+
14
+ job_id = ms.run(
15
+ name="double_values",
16
+ input=[{"value": v} for v in range(1000)],
17
+ process=double_value,
18
+ output=table_sink("results", columns=("value", "double_value")),
19
+ executor="thread",
20
+ )
21
+ print(ms.wait_for_job(job_id).status)
22
+ ```
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ pip install ms_flow # core: control plane + SQLite + loky
28
+ pip install "ms_flow[ray]" # Ray executor
29
+ ```
30
+
31
+ ## Where to look
32
+
33
+ - [5-minute quickstart](docs/guides/quickstart_5min.md) — first working job.
34
+ - [Runnable examples](examples/README.md) — scripts y notebook.
35
+ - [Public API](docs/guides/public_api.md) — API.
36
+ - [Docs index](docs/README.md) — guides, contracts, operation
37
+ - [Benchmarks](benchmarks/README.md) — performance.
38
+
39
+ ## Status
40
+
41
+ Beta. The public API (`ms_flow.api`) is the stable surface; `ms_flow.core.*` may change without notice.
42
+
43
+ ## License
44
+
45
+ MIT — see [LICENSE](LICENSE).
@@ -0,0 +1,191 @@
1
+ # API guide
2
+
3
+ Use `MolSuite` as the public facade. A `MolSuite` instance owns the active
4
+ project and its executors, so close it with `shutdown()` when the work is done.
5
+
6
+ ```python
7
+ from ms_flow.api import MolSuite
8
+ ```
9
+
10
+ ## Projects
11
+
12
+ Projects are isolated per `app_id`. Opening a project activates it; jobs run
13
+ against the active project.
14
+
15
+ ```python
16
+ ms = MolSuite(app_id="demo")
17
+ try:
18
+ context = ms.create_or_open_project(name="demo", folder="./demo-project")
19
+ print(context.id)
20
+
21
+ ms.close_project() # the executors stay alive
22
+ ms.open_project(context.id)
23
+ finally:
24
+ ms.shutdown() # stops the whole runtime
25
+ ```
26
+
27
+ `close_project()` and `open_project()` fail explicitly if the active project
28
+ cannot drain its running jobs.
29
+
30
+ ## Run a job
31
+
32
+ `run()` is the shortest path: `input → process → output`. It returns a job
33
+ identifier immediately; `wait_for_job()` blocks until the job ends and returns
34
+ a `JobSnapshot`.
35
+
36
+ ```python
37
+ from workers import double_value
38
+
39
+ job_id = ms.run(
40
+ name="double-values",
41
+ input=[{"value": 1}, {"value": 2}, {"value": 3}],
42
+ process=double_value,
43
+ executor="thread",
44
+ store_results=True,
45
+ )
46
+ final = ms.wait_for_job(job_id)
47
+ print(final.status, final.chunks_done)
48
+ print(ms.get_job_outputs(job_id))
49
+ ```
50
+
51
+ !!! note "Workers must be importable"
52
+ The `process` callable has to live in an importable module. Functions
53
+ defined in the script you launch (`__main__`), lambdas, nested functions,
54
+ and notebook cells are rejected, because process and remote executors must
55
+ re-import the worker by name.
56
+
57
+ Each worker receives one payload dictionary and returns a dictionary.
58
+
59
+ ## Persist results with sinks
60
+
61
+ By default outputs are not kept. Pass a sink to write results incrementally,
62
+ and keep `store_results=False` so the operational database does not grow with
63
+ every result.
64
+
65
+ ```python
66
+ from ms_flow.api import file_sink, table_sink
67
+
68
+ job_id = ms.run(
69
+ name="double-values",
70
+ input=[{"value": value} for value in range(1000)],
71
+ process=double_value,
72
+ output=table_sink("results", columns=("value", "double_value")),
73
+ flush_every=100,
74
+ executor="thread",
75
+ )
76
+ ```
77
+
78
+ | Sink | Destination |
79
+ | --- | --- |
80
+ | `table_sink(table, columns=...)` | A table in the project database; the table must exist |
81
+ | `file_sink(path, fmt="json")` | A file under the project folder |
82
+ | `graph_sink(nodes=..., relations=...)` | Several related tables written in one transaction |
83
+
84
+ ## Read project data
85
+
86
+ `db_input_for()` describes a query instead of materialising rows. The chunk
87
+ carries the specification and the rows are read inside the worker.
88
+
89
+ ```python
90
+ from ms_flow.query import db_input_for
91
+ from workers import summarize_molecules
92
+
93
+ job_id = ms.run(
94
+ name="summarize-ready",
95
+ input=[
96
+ {
97
+ "molecules": db_input_for(
98
+ "molecules",
99
+ fields=("id", "name"),
100
+ filters={"status": "ready"},
101
+ order=("id",),
102
+ )
103
+ }
104
+ ],
105
+ process=summarize_molecules,
106
+ executor="thread",
107
+ store_results=True,
108
+ )
109
+ ```
110
+
111
+ ## Reusable definitions
112
+
113
+ Separate definition from execution with `workflow()`:
114
+
115
+ ```python
116
+ from ms_flow.api import workflow
117
+
118
+ spec = workflow(
119
+ name="double-values",
120
+ input=[{"value": 1}, {"value": 2}],
121
+ process=double_value,
122
+ executor="thread",
123
+ store_results=True,
124
+ )
125
+ job_id = ms.run(spec=spec)
126
+ ```
127
+
128
+ When a job is shared between scripts, a UI, and an application runtime, declare
129
+ it once with `streaming_job()` (one payload per chunk) or `batch_job()` (one
130
+ batch per chunk) and submit it with parameters:
131
+
132
+ ```python
133
+ from ms_flow.api import streaming_job
134
+ from workers import double_value, value_chunks
135
+
136
+ double_job = streaming_job(
137
+ name="double-values",
138
+ run_chunk=double_value,
139
+ chunker=value_chunks,
140
+ executor="thread",
141
+ store_results=True,
142
+ )
143
+ job_id = ms.submit_job(double_job, params={"count": 10})
144
+ ```
145
+
146
+ ## Follow progress
147
+
148
+ `watch_job()` renders a tqdm progress bar in a terminal or notebook and returns
149
+ the final snapshot. Pass `follow=False` for a non-blocking snapshot.
150
+
151
+ ```python
152
+ from ms_flow import watch_job
153
+
154
+ snapshot = watch_job(ms, job_id)
155
+ ```
156
+
157
+ Cancel a running job with `ms.cancel_job(job_id)`.
158
+
159
+ ## Application runtimes
160
+
161
+ Subclass `BaseRuntime` to build a domain facade on top of `MolSuite`. The
162
+ runtime fixes the `app_id` once and exposes the engine as `self.molsuite`.
163
+
164
+ ```python
165
+ from ms_flow.runtime import BaseRuntime
166
+
167
+
168
+ class DemoRuntime(BaseRuntime):
169
+ def __init__(self):
170
+ super().__init__("demoapp")
171
+
172
+ def double(self, values):
173
+ return self.run(
174
+ name="double-values",
175
+ input=[{"value": value} for value in values],
176
+ process=double_value,
177
+ executor="thread",
178
+ store_results=True,
179
+ )
180
+ ```
181
+
182
+ ## Choose the API level
183
+
184
+ | Need | Recommended API |
185
+ | --- | --- |
186
+ | Run `input → process → output` | `MolSuite.run()` |
187
+ | Reuse a common definition | `workflow()`, `streaming_job()`, or `batch_job()` |
188
+ | Describe project queries | `ms_flow.query` |
189
+ | Control tasks, staging, and finalize | `ms_flow.tasking` |
190
+ | Build a domain facade | `BaseRuntime` / `AppRuntime` |
191
+ | Extend the engine | `ms_flow.advanced` and, exceptionally, `ms_flow.core` |
@@ -0,0 +1,46 @@
1
+ # API reference
2
+
3
+ The reference below is generated directly from the current Python sources.
4
+ Names beginning with an underscore are implementation details.
5
+
6
+ ## MolSuite
7
+
8
+ ::: ms_flow.main.MolSuite
9
+ options:
10
+ inherited_members: true
11
+ # The mixin methods have no docstrings yet; hidden by default.
12
+ show_if_no_docstring: true
13
+
14
+ ## Application runtimes
15
+
16
+ ::: ms_flow.runtime.BaseRuntime
17
+
18
+ ::: ms_flow.runtime.AppRuntime
19
+
20
+ ## Workflow specs
21
+
22
+ ::: ms_flow.specs
23
+
24
+ ## Job templates
25
+
26
+ ::: ms_flow.job_templates
27
+
28
+ ## Sinks
29
+
30
+ ::: ms_flow.sinks
31
+
32
+ ## Queries
33
+
34
+ ::: ms_flow.query
35
+
36
+ ## Selections
37
+
38
+ ::: ms_flow.selection
39
+
40
+ ## Progress
41
+
42
+ ::: ms_flow.progress
43
+
44
+ ## Tasking
45
+
46
+ ::: ms_flow.tasking
@@ -0,0 +1,191 @@
1
+ # Examples
2
+
3
+ Every example imports its worker functions from `workers.py`, because workers
4
+ must be importable. Save this file next to the scripts:
5
+
6
+ ```python
7
+ # workers.py
8
+ def double_value(payload: dict) -> dict:
9
+ value = int(payload["value"])
10
+ return {"value": value, "double_value": value * 2}
11
+
12
+
13
+ def summarize_molecules(payload: dict) -> dict:
14
+ molecules = list(payload["molecules"])
15
+ return {
16
+ "molecule_count": len(molecules),
17
+ "molecule_names": [row["name"] for row in molecules],
18
+ }
19
+
20
+
21
+ def value_chunks(params: dict):
22
+ for value in range(int(params["count"])):
23
+ yield {"value": value}
24
+ ```
25
+
26
+ Each example creates its project in the current directory, so run them in a
27
+ scratch folder.
28
+
29
+ ## Persist results to a table
30
+
31
+ ```python
32
+ import sqlite3
33
+ from pathlib import Path
34
+
35
+ from ms_flow.api import MolSuite, table_sink
36
+ from workers import double_value
37
+
38
+ ms = MolSuite(app_id="demo")
39
+ try:
40
+ ms.create_or_open_project(
41
+ name="table-demo",
42
+ folder=Path("./table-demo").resolve(),
43
+ activate=True,
44
+ )
45
+
46
+ # A table sink writes to the project database: the table has to exist.
47
+ with sqlite3.connect(str(ms.project_db.db_path)) as conn:
48
+ conn.execute("DROP TABLE IF EXISTS results")
49
+ conn.execute("CREATE TABLE results (value INTEGER, double_value INTEGER)")
50
+
51
+ job_id = ms.run(
52
+ name="double-values",
53
+ input=[{"value": value} for value in (1, 2, 3, 4)],
54
+ process=double_value,
55
+ output=table_sink("results", columns=("value", "double_value")),
56
+ flush_every=2,
57
+ executor="thread",
58
+ )
59
+ final = ms.wait_for_job(job_id, poll_s=0.05)
60
+ print(final.status, final.chunks_done)
61
+
62
+ with sqlite3.connect(str(ms.project_db.db_path)) as conn:
63
+ rows = conn.execute("SELECT value, double_value FROM results ORDER BY value")
64
+ print(rows.fetchall())
65
+ finally:
66
+ ms.shutdown()
67
+ ```
68
+
69
+ ## Feed a job from project rows
70
+
71
+ The chunk carries the query, not the rows: they are read inside the worker.
72
+
73
+ ```python
74
+ import sqlite3
75
+ from pathlib import Path
76
+
77
+ from ms_flow.api import MolSuite
78
+ from ms_flow.query import db_input_for
79
+ from workers import summarize_molecules
80
+
81
+ ms = MolSuite(app_id="demo")
82
+ try:
83
+ ms.create_or_open_project(
84
+ name="query-demo",
85
+ folder=Path("./query-demo").resolve(),
86
+ activate=True,
87
+ )
88
+
89
+ with sqlite3.connect(str(ms.project_db.db_path)) as conn:
90
+ conn.execute(
91
+ "CREATE TABLE IF NOT EXISTS molecules "
92
+ "(id INTEGER PRIMARY KEY, name TEXT, status TEXT)"
93
+ )
94
+ conn.execute("DELETE FROM molecules")
95
+ conn.executemany(
96
+ "INSERT INTO molecules (id, name, status) VALUES (?, ?, ?)",
97
+ [(1, "MolA", "ready"), (2, "MolB", "ready"), (3, "MolC", "archived")],
98
+ )
99
+
100
+ job_id = ms.run(
101
+ name="summarize-ready",
102
+ input=[
103
+ {
104
+ "molecules": db_input_for(
105
+ "molecules",
106
+ fields=("id", "name"),
107
+ filters={"status": "ready"},
108
+ order=("id",),
109
+ )
110
+ }
111
+ ],
112
+ process=summarize_molecules,
113
+ executor="thread",
114
+ store_results=True,
115
+ )
116
+ final = ms.wait_for_job(job_id, poll_s=0.05)
117
+ print(final.status, ms.get_job_outputs(job_id))
118
+ finally:
119
+ ms.shutdown()
120
+ ```
121
+
122
+ ## Reusable streaming job
123
+
124
+ Declare the job once and submit it with different parameters.
125
+
126
+ ```python
127
+ from pathlib import Path
128
+
129
+ from ms_flow import watch_job
130
+ from ms_flow.api import MolSuite, streaming_job
131
+ from workers import double_value, value_chunks
132
+
133
+ double_job = streaming_job(
134
+ name="double-values",
135
+ run_chunk=double_value,
136
+ chunker=value_chunks,
137
+ executor="thread",
138
+ store_results=True,
139
+ )
140
+
141
+ ms = MolSuite(app_id="demo")
142
+ try:
143
+ ms.create_or_open_project(
144
+ name="streaming-demo",
145
+ folder=Path("./streaming-demo").resolve(),
146
+ activate=True,
147
+ )
148
+ job_id = ms.submit_job(double_job, params={"count": 5})
149
+ final = watch_job(ms, job_id)
150
+ print(final.status, len(ms.get_job_outputs(job_id)))
151
+ finally:
152
+ ms.shutdown()
153
+ ```
154
+
155
+ ## Application runtime
156
+
157
+ A domain facade over `MolSuite` for an application.
158
+
159
+ ```python
160
+ from pathlib import Path
161
+
162
+ from ms_flow.runtime import BaseRuntime
163
+ from workers import double_value
164
+
165
+
166
+ class DemoRuntime(BaseRuntime):
167
+ def __init__(self):
168
+ super().__init__("demoapp")
169
+
170
+ def double(self, values):
171
+ return self.run(
172
+ name="double-values",
173
+ input=[{"value": value} for value in values],
174
+ process=double_value,
175
+ executor="thread",
176
+ store_results=True,
177
+ )
178
+
179
+
180
+ runtime = DemoRuntime()
181
+ try:
182
+ runtime.create_or_open_project(
183
+ name="runtime-demo",
184
+ folder=Path("./runtime-demo").resolve(),
185
+ )
186
+ job_id = runtime.double([1, 2, 3])
187
+ final = runtime.molsuite.wait_for_job(job_id, poll_s=0.05)
188
+ print(final.status, runtime.molsuite.get_job_outputs(job_id))
189
+ finally:
190
+ runtime.shutdown()
191
+ ```