staged-pipeline 0.1.0a1__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 (63) hide show
  1. staged_pipeline-0.1.0a1/.editorconfig +18 -0
  2. staged_pipeline-0.1.0a1/.env.example +9 -0
  3. staged_pipeline-0.1.0a1/.gitattributes +6 -0
  4. staged_pipeline-0.1.0a1/.github/dependabot.yml +10 -0
  5. staged_pipeline-0.1.0a1/.github/workflows/check.yml +59 -0
  6. staged_pipeline-0.1.0a1/.github/workflows/release.yml +83 -0
  7. staged_pipeline-0.1.0a1/.gitignore +29 -0
  8. staged_pipeline-0.1.0a1/.pre-commit-config.yaml +76 -0
  9. staged_pipeline-0.1.0a1/.python-version +1 -0
  10. staged_pipeline-0.1.0a1/AGENTS.md +35 -0
  11. staged_pipeline-0.1.0a1/CHANGELOG.md +33 -0
  12. staged_pipeline-0.1.0a1/CLAUDE.md +2 -0
  13. staged_pipeline-0.1.0a1/LICENSE +21 -0
  14. staged_pipeline-0.1.0a1/PKG-INFO +123 -0
  15. staged_pipeline-0.1.0a1/README.md +97 -0
  16. staged_pipeline-0.1.0a1/docs/AUDIT.md +60 -0
  17. staged_pipeline-0.1.0a1/docs/architecture.md +545 -0
  18. staged_pipeline-0.1.0a1/docs/guide.md +377 -0
  19. staged_pipeline-0.1.0a1/docs/plan/DECISIONS.md +88 -0
  20. staged_pipeline-0.1.0a1/docs/plan/PLAN.md +381 -0
  21. staged_pipeline-0.1.0a1/docs/plan/PROGRESS.md +181 -0
  22. staged_pipeline-0.1.0a1/docs/research.md +120 -0
  23. staged_pipeline-0.1.0a1/examples/crawler.py +32 -0
  24. staged_pipeline-0.1.0a1/examples/export.py +63 -0
  25. staged_pipeline-0.1.0a1/pyproject.toml +260 -0
  26. staged_pipeline-0.1.0a1/scripts/github_bootstrap.py +153 -0
  27. staged_pipeline-0.1.0a1/src/staged_pipeline/__init__.py +81 -0
  28. staged_pipeline-0.1.0a1/src/staged_pipeline/_accounting.py +271 -0
  29. staged_pipeline-0.1.0a1/src/staged_pipeline/_clock.py +112 -0
  30. staged_pipeline-0.1.0a1/src/staged_pipeline/_errors.py +91 -0
  31. staged_pipeline-0.1.0a1/src/staged_pipeline/_graph.py +397 -0
  32. staged_pipeline-0.1.0a1/src/staged_pipeline/_inbox.py +213 -0
  33. staged_pipeline-0.1.0a1/src/staged_pipeline/_limit.py +116 -0
  34. staged_pipeline-0.1.0a1/src/staged_pipeline/_pipeline.py +334 -0
  35. staged_pipeline-0.1.0a1/src/staged_pipeline/_policy.py +322 -0
  36. staged_pipeline-0.1.0a1/src/staged_pipeline/_progress.py +377 -0
  37. staged_pipeline-0.1.0a1/src/staged_pipeline/_stage.py +526 -0
  38. staged_pipeline-0.1.0a1/src/staged_pipeline/_supervisor.py +78 -0
  39. staged_pipeline-0.1.0a1/src/staged_pipeline/integrations/__init__.py +1 -0
  40. staged_pipeline-0.1.0a1/src/staged_pipeline/integrations/tallyho.py +139 -0
  41. staged_pipeline-0.1.0a1/src/staged_pipeline/py.typed +0 -0
  42. staged_pipeline-0.1.0a1/src/staged_pipeline/testing.py +55 -0
  43. staged_pipeline-0.1.0a1/staged-pipeline-library.md +282 -0
  44. staged_pipeline-0.1.0a1/tests/conftest.py +12 -0
  45. staged_pipeline-0.1.0a1/tests/test_accounting.py +207 -0
  46. staged_pipeline-0.1.0a1/tests/test_audit_fixes.py +99 -0
  47. staged_pipeline-0.1.0a1/tests/test_clock.py +150 -0
  48. staged_pipeline-0.1.0a1/tests/test_dedup.py +174 -0
  49. staged_pipeline-0.1.0a1/tests/test_errors.py +55 -0
  50. staged_pipeline-0.1.0a1/tests/test_examples.py +27 -0
  51. staged_pipeline-0.1.0a1/tests/test_graph.py +246 -0
  52. staged_pipeline-0.1.0a1/tests/test_inbox.py +213 -0
  53. staged_pipeline-0.1.0a1/tests/test_limits.py +105 -0
  54. staged_pipeline-0.1.0a1/tests/test_pipeline.py +189 -0
  55. staged_pipeline-0.1.0a1/tests/test_policy.py +237 -0
  56. staged_pipeline-0.1.0a1/tests/test_progress.py +196 -0
  57. staged_pipeline-0.1.0a1/tests/test_routing.py +134 -0
  58. staged_pipeline-0.1.0a1/tests/test_skeleton.py +8 -0
  59. staged_pipeline-0.1.0a1/tests/test_stop.py +127 -0
  60. staged_pipeline-0.1.0a1/tests/test_tallyho.py +103 -0
  61. staged_pipeline-0.1.0a1/tests/test_testing.py +52 -0
  62. staged_pipeline-0.1.0a1/tests/test_worker_policies.py +186 -0
  63. staged_pipeline-0.1.0a1/uv.lock +918 -0
@@ -0,0 +1,18 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ trim_trailing_whitespace = true
8
+ indent_style = space
9
+ indent_size = 4
10
+
11
+ [*.{yml,yaml,toml,json}]
12
+ indent_size = 2
13
+
14
+ [*.md]
15
+ trim_trailing_whitespace = false
16
+
17
+ [Makefile]
18
+ indent_style = tab
@@ -0,0 +1,9 @@
1
+ # Шаблон окружения. Скопировать в .env (в .gitignore) и заполнить.
2
+ # Используется scripts/github_bootstrap.py (poe github), см. PLAN.md T7.1.
3
+
4
+ # Fine-grained PAT на один репозиторий: Administration RW, Contents RW,
5
+ # Workflows RW, Environments RW, Metadata R.
6
+ GH_TOKEN=
7
+ GITHUB_OWNER=0cherednoq
8
+ GITHUB_REPO=staged-pipeline
9
+ GITHUB_VISIBILITY=public
@@ -0,0 +1,6 @@
1
+ * text=auto eol=lf
2
+
3
+ *.png binary
4
+ *.jpg binary
5
+ *.gif binary
6
+ *.ico binary
@@ -0,0 +1,10 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: github-actions
4
+ directory: "/"
5
+ schedule:
6
+ interval: weekly
7
+ - package-ecosystem: uv
8
+ directory: "/"
9
+ schedule:
10
+ interval: weekly
@@ -0,0 +1,59 @@
1
+ name: check
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_call:
8
+
9
+ # UTF-8 вывод на всех ОС: инструменты (import-linter, pytest) печатают русский
10
+ # текст, а Windows-консоль по умолчанию не UTF-8 → UnicodeEncodeError.
11
+ env:
12
+ PYTHONUTF8: "1"
13
+
14
+ concurrency:
15
+ group: check-${{ github.workflow }}-${{ github.ref }}
16
+ cancel-in-progress: true
17
+
18
+ jobs:
19
+ check:
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ os: [ubuntu-latest, windows-latest]
24
+ runs-on: ${{ matrix.os }}
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: astral-sh/setup-uv@v6
28
+ with:
29
+ python-version: "3.13"
30
+ enable-cache: true
31
+ - run: uv sync --locked
32
+ - run: uv run poe check
33
+ - run: uv run poe deps
34
+ - run: uv run poe spell
35
+ - name: pre-commit (локальные хуки уже покрыты poe check)
36
+ run: uv run pre-commit run --all-files --show-diff-on-failure
37
+ env:
38
+ SKIP: ruff-format,ruff-check,mypy,import-linter,pytest
39
+
40
+ py314:
41
+ runs-on: ubuntu-latest
42
+ steps:
43
+ - uses: actions/checkout@v4
44
+ - uses: astral-sh/setup-uv@v6
45
+ with:
46
+ python-version: "3.14"
47
+ enable-cache: true
48
+ - run: uv sync --locked
49
+ - run: uv run poe test
50
+
51
+ build:
52
+ runs-on: ubuntu-latest
53
+ steps:
54
+ - uses: actions/checkout@v4
55
+ - uses: astral-sh/setup-uv@v6
56
+ - run: uv build
57
+ - run: uv run --with twine twine check --strict dist/*
58
+ - name: smoke-импорт колеса в чистом окружении
59
+ run: uv run --isolated --no-project --find-links dist --with staged-pipeline python -c "import staged_pipeline; print(staged_pipeline.__version__)"
@@ -0,0 +1,83 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ env:
8
+ PYTHONUTF8: "1"
9
+
10
+ concurrency:
11
+ group: release-${{ github.ref }}
12
+ cancel-in-progress: false
13
+
14
+ jobs:
15
+ check:
16
+ uses: ./.github/workflows/check.yml
17
+
18
+ build:
19
+ needs: check
20
+ runs-on: ubuntu-latest
21
+ steps:
22
+ - uses: actions/checkout@v4
23
+ - uses: astral-sh/setup-uv@v6
24
+ - run: uv build
25
+ - name: тег совпадает с версией
26
+ run: |
27
+ tag="${GITHUB_REF_NAME#v}"
28
+ ver=$(uv run --no-sync python -c "import tomllib, pathlib; print(tomllib.loads(pathlib.Path('pyproject.toml').read_text('utf-8'))['project']['version'])")
29
+ if [ "$tag" != "$ver" ]; then
30
+ echo "тег '$tag' не совпадает с версией в pyproject '$ver'"
31
+ exit 1
32
+ fi
33
+ - run: uv run --with twine twine check --strict dist/*
34
+ - uses: actions/upload-artifact@v4
35
+ with:
36
+ name: dist
37
+ path: dist/
38
+
39
+ smoke:
40
+ needs: build
41
+ strategy:
42
+ fail-fast: false
43
+ matrix:
44
+ os: [ubuntu-latest, windows-latest]
45
+ py: ["3.13", "3.14"]
46
+ runs-on: ${{ matrix.os }}
47
+ steps:
48
+ - uses: astral-sh/setup-uv@v6
49
+ with:
50
+ python-version: ${{ matrix.py }}
51
+ - uses: actions/download-artifact@v4
52
+ with:
53
+ name: dist
54
+ path: dist
55
+ - run: uv run --isolated --no-project --find-links dist --with staged-pipeline python -c "import staged_pipeline; print(staged_pipeline.__version__)"
56
+
57
+ publish:
58
+ needs: smoke
59
+ runs-on: ubuntu-latest
60
+ environment: pypi
61
+ permissions:
62
+ id-token: write
63
+ steps:
64
+ - uses: actions/download-artifact@v4
65
+ with:
66
+ name: dist
67
+ path: dist
68
+ - uses: pypa/gh-action-pypi-publish@release/v1
69
+
70
+ github-release:
71
+ needs: publish
72
+ runs-on: ubuntu-latest
73
+ permissions:
74
+ contents: write
75
+ steps:
76
+ - uses: actions/download-artifact@v4
77
+ with:
78
+ name: dist
79
+ path: dist
80
+ - name: GitHub Release
81
+ run: gh release create "$GITHUB_REF_NAME" dist/* --generate-notes
82
+ env:
83
+ GH_TOKEN: ${{ github.token }}
@@ -0,0 +1,29 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info/
8
+ .eggs/
9
+
10
+ # Virtual environments
11
+ .venv/
12
+
13
+ # Тестирование и покрытие
14
+ .pytest_cache/
15
+ .hypothesis/
16
+ .coverage
17
+ .coverage.*
18
+ coverage.xml
19
+ htmlcov/
20
+ .mypy_cache/
21
+ .ruff_cache/
22
+ .basedpyright/
23
+
24
+ # Секреты
25
+ .env
26
+
27
+ # IDE
28
+ .idea/
29
+ .vscode/
@@ -0,0 +1,76 @@
1
+ # Хуки pre-commit. На CI (T6.1) локальные хуки пропускаются (SKIP), т.к. их
2
+ # запускает уже `uv run poe check`. Локально оффлайн первый запуск недоступен:
3
+ # pre-commit клонирует репозитории хуков с GitHub (D-009) — это делается на CI.
4
+ minimum_pre_commit_version: "4.0.0"
5
+ default_install_hook_types: [pre-commit, pre-push]
6
+
7
+ repos:
8
+ - repo: https://github.com/pre-commit/pre-commit-hooks
9
+ rev: v6.0.0
10
+ hooks:
11
+ - id: check-added-large-files
12
+ - id: check-case-conflict
13
+ - id: check-merge-conflict
14
+ - id: check-toml
15
+ - id: check-yaml
16
+ - id: end-of-file-fixer
17
+ - id: mixed-line-ending
18
+ args: [--fix=lf]
19
+ - id: trailing-whitespace
20
+
21
+ - repo: https://github.com/astral-sh/uv-pre-commit
22
+ rev: 0.10.12
23
+ hooks:
24
+ - id: uv-lock
25
+
26
+ - repo: https://github.com/codespell-project/codespell
27
+ rev: v2.4.3
28
+ hooks:
29
+ - id: codespell
30
+ additional_dependencies: [tomli]
31
+
32
+ - repo: https://github.com/python-jsonschema/check-jsonschema
33
+ rev: 0.38.2
34
+ hooks:
35
+ - id: check-github-workflows
36
+
37
+ - repo: https://github.com/abravalheri/validate-pyproject
38
+ rev: v0.27
39
+ hooks:
40
+ - id: validate-pyproject
41
+
42
+ # Локальные хуки через uv run --frozen (на CI пропускаются через SKIP).
43
+ - repo: local
44
+ hooks:
45
+ - id: ruff-format
46
+ name: ruff format
47
+ entry: uv run --frozen ruff format --check
48
+ language: system
49
+ types_or: [python, pyi]
50
+ require_serial: true
51
+ - id: ruff-check
52
+ name: ruff check
53
+ entry: uv run --frozen ruff check
54
+ language: system
55
+ types_or: [python, pyi]
56
+ require_serial: true
57
+ - id: mypy
58
+ name: mypy
59
+ entry: uv run --frozen mypy
60
+ language: system
61
+ types_or: [python, pyi]
62
+ pass_filenames: false
63
+ require_serial: true
64
+ - id: import-linter
65
+ name: import-linter
66
+ entry: uv run --frozen lint-imports
67
+ language: system
68
+ pass_filenames: false
69
+ require_serial: true
70
+ - id: pytest
71
+ name: pytest
72
+ entry: uv run --frozen pytest
73
+ language: system
74
+ pass_filenames: false
75
+ require_serial: true
76
+ stages: [pre-push]
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,35 @@
1
+ # Правила разработки staged-pipeline
2
+
3
+ Полный процесс — [docs/plan/PLAN.md](docs/plan/PLAN.md). Ниже — то, что нельзя нарушать (§0.3).
4
+
5
+ ## Железные правила
6
+
7
+ - **Не ослаблять** линтеры, типизацию, покрытие (≥ 90%). Подавление — точечное и с причиной:
8
+ `# ruff: ignore[rule] # причина`, `# pyright: ignore[rule] # причина`.
9
+ - Запрещены (banned-api): `typing.Any`, `asyncio.get_event_loop`, `logging.basicConfig`,
10
+ `unittest.mock.patch`.
11
+ - **Ядро без зависимостей:** `dependencies = []`. Extras не импортируют внешних пакетов
12
+ (интеграция tallyho — через `Protocol`, architecture.md §9.3).
13
+ - Все исключения библиотеки — подклассы `StagedPipelineError`, кроме исходов `Skip`/`Error`
14
+ (они — `Outcome(Exception)`, архитектурно отдельны). Все модули объявляют `__all__`.
15
+ - Комментарии и docstring — на русском, идентификаторы — на английском. Google-style docstring.
16
+ - Решения architecture.md не менять молча: сначала запись в
17
+ [docs/plan/DECISIONS.md](docs/plan/DECISIONS.md), потом код.
18
+ - Файлы, которые пишет Python, — с `newline="\n"`.
19
+
20
+ ## Время и тесты
21
+
22
+ - Время — только через `Clock`; в тестах `FakeClock`. Реальные `asyncio.sleep` ≤ 10 мс и только там,
23
+ где проверяется сам event loop.
24
+ - Весь набор тестов < 30 с, `pytest-timeout = 5` на тест. Нет Docker, нагрузочных и хаос-тестов.
25
+
26
+ ## Гейты (Definition of Done)
27
+
28
+ - `uv run poe check` — формат, линт, типы, import-linter, deptry, codespell, pytest + покрытие.
29
+ - `uv run pre-commit run --all-files`.
30
+ - DoD конкретной карточки задачи в PLAN.md.
31
+
32
+ ## Коммиты
33
+
34
+ - Маленькие, одно логическое изменение. Сообщение на русском, заголовок `T<id>: <что>` ≤ 72 символов.
35
+ - Ветка работы — `impl/v1`; коммиты в `main` запрещены pre-commit-хуком.
@@ -0,0 +1,33 @@
1
+ # Changelog
2
+
3
+ Все заметные изменения этого проекта документируются здесь.
4
+
5
+ Формат основан на [Keep a Changelog](https://keepachangelog.com/ru/1.1.0/),
6
+ проект придерживается [семантического версионирования](https://semver.org/lang/ru/).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.1.0a1] - 2026-10-25
11
+
12
+ Первый альфа-релиз. Полный API v0.1 (architecture.md §4).
13
+
14
+ ### Added
15
+
16
+ - Ядро конвейера: `Pipeline`/`Stage`, пул воркеров на стадию, супервизор (fail-fast,
17
+ плоское исключение), вывод режима завершения из графа (DAG по писателям, цикл по quiescence).
18
+ - Политики исходов: `retry=` с backoff (`Expo`/`Fixed`), `skip_on`/`error_on`, `Skip`/`Error`,
19
+ предохранители `ErrorRate`/`NoSuccess`.
20
+ - Дедупликация (`key=`, `SeenStore`), `seed`/`resume`/`seed_open` (`Feeder`).
21
+ - Маршрутизация по типу выхода, `executor="thread"`, лимиты (`Limit`: concurrency + rate).
22
+ - Остановка: `cancel`/`drain`/таймаут.
23
+ - Прогресс: `view`/`watch`/`PipelineReport`, EWMA rate/latency, `expected`/`eta`, `Observer`.
24
+ - `staged_pipeline.testing` (`run_stage`, `FakeClock`), интеграция `integrations.tallyho`.
25
+ - CI (check/release), документация (README, docs/guide.md, docs/architecture.md).
26
+
27
+ ### Known limitations (alpha)
28
+
29
+ - Открытые пункты аудита (docs/AUDIT.md): V1 (гонка `ctx.incr` из sync-хендлера), V3, V5–V12.
30
+ - API может меняться до 1.0.
31
+
32
+ [Unreleased]: https://github.com/0cherednoq/staged-pipeline/compare/v0.1.0a1...HEAD
33
+ [0.1.0a1]: https://github.com/0cherednoq/staged-pipeline/releases/tag/v0.1.0a1
@@ -0,0 +1,2 @@
1
+ Правила разработки этого репозитория — в [AGENTS.md](AGENTS.md). Процесс и задачи —
2
+ [docs/plan/PLAN.md](docs/plan/PLAN.md).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 0cherednoq
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.
@@ -0,0 +1,123 @@
1
+ Metadata-Version: 2.5
2
+ Name: staged-pipeline
3
+ Version: 0.1.0a1
4
+ Summary: Декларативный конвейер стадий поверх asyncio: воркеры, dedup, ретраи, прогресс
5
+ Project-URL: Homepage, https://github.com/0cherednoq/staged-pipeline
6
+ Project-URL: Repository, https://github.com/0cherednoq/staged-pipeline
7
+ Project-URL: Issues, https://github.com/0cherednoq/staged-pipeline/issues
8
+ Project-URL: Changelog, https://github.com/0cherednoq/staged-pipeline/blob/main/CHANGELOG.md
9
+ Author: 0cherednoq
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: asyncio,dataflow,pipeline,seda
13
+ Classifier: Development Status :: 3 - Alpha
14
+ Classifier: Framework :: AsyncIO
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3 :: Only
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Software Development :: Libraries
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.13
24
+ Provides-Extra: tallyho
25
+ Description-Content-Type: text/markdown
26
+
27
+ # staged-pipeline
28
+
29
+ > **Статус: pre-release (0.1.0a).** API описан в [docs/architecture.md](docs/architecture.md),
30
+ > реализация — по [docs/plan/PLAN.md](docs/plan/PLAN.md). До релиза `0.1.0` возможны изменения.
31
+
32
+ Декларативный конвейер стадий поверх `asyncio` внутри одного процесса: пул воркеров на стадию,
33
+ дедупликация, ретраи с backoff, предохранители, лимиты и живой прогресс. Режим завершения выводится
34
+ из графа (DAG закрывается по писателям, цикл — по quiescence), поэтому «выбрать неправильный режим и
35
+ повиснуть» нельзя.
36
+
37
+ ## Чем это является
38
+
39
+ - слой внутри одного процесса и одного event loop: стадии с воркерами, маршрутизацией по типу,
40
+ политиками исходов (`retry`/`skip_on`/`error_on`), лимитами и дедупликацией;
41
+ - источник честного прогресса: `found / queued / in_flight / deferred / ok / skip / error /
42
+ cancelled / duplicates`, `expected` и `eta`;
43
+ - одноразовый граф, проверяемый до старта (ошибка топологии не запускает ничего).
44
+
45
+ ## Чем это не является
46
+
47
+ - не durable и не распределённая система — всё в одном процессе;
48
+ - не владеет хранилищем: устойчивость между прогонами даёт БД домена (resume засевом);
49
+ - не замена очереди задач (Tallyho и подобных) — это слой внутри одного Item.
50
+
51
+ ## Установка
52
+
53
+ ```bash
54
+ uv add staged-pipeline # ядро, без зависимостей
55
+ uv add "staged-pipeline[tallyho]" # + маркер интеграции с Tallyho
56
+ ```
57
+
58
+ Требуется Python 3.13+.
59
+
60
+ ## Quickstart
61
+
62
+ ```python
63
+ import asyncio
64
+ from staged_pipeline import Pipeline
65
+
66
+
67
+ async def scan(folder: str): # async-генератор: потоковый fan-out
68
+ for i in range(3):
69
+ yield f"{folder}/{i}"
70
+
71
+
72
+ async def resolve(path: str) -> list[str]: # атомарный fan-out
73
+ return [f"{path}.a", f"{path}.b"]
74
+
75
+
76
+ async def download(url: str) -> None: # терминальная стадия
77
+ ...
78
+
79
+
80
+ async def main() -> None:
81
+ pipe = Pipeline("export")
82
+ listing = pipe.stage("list", scan, workers=2)
83
+ resolving = pipe.stage("resolve", resolve, workers=8, key=lambda p: p)
84
+ media = pipe.stage("media", download, workers=4, key=lambda u: u)
85
+
86
+ listing.to(resolving)
87
+ resolving.to(media)
88
+ listing.seed(["inbox"])
89
+
90
+ report = await pipe.run()
91
+ print(report.stages["media"].ok)
92
+
93
+
94
+ asyncio.run(main())
95
+ ```
96
+
97
+ Больше примеров — в [examples/](examples/): `crawler.py` (цикл/самопетля) и `export.py`
98
+ (fan-out + dedup + resume). Оба исполняются в тестах.
99
+
100
+ ## Когда этапы Tallyho, а когда пайплайн
101
+
102
+ | Критерий | Этапы Tallyho (`sub_batch` + `fed_by`) | Пайплайн внутри Item |
103
+ |---|---|---|
104
+ | Элемент должен пережить падение воркера сам по себе | ✔ | ✘ (resume — через БД домена) |
105
+ | Элементы дешёвые (≪ 100 мс) и их 10⁴–10⁶ на единицу | дорого: строка + коммит на элемент | ✔ |
106
+ | Общая сессия/лиз/соединение на единицу | ✘ (лиз на задачу) | ✔ |
107
+ | Масштаб на несколько машин | ✔ | ✘ |
108
+ | Нужен точный итог по каждому элементу в БД | ✔ | домен пишет сам |
109
+
110
+ Мост прогресса и остановки к Tallyho — `staged_pipeline.integrations.tallyho` (`track`,
111
+ `outcome_for`), без зависимости от `tallyho`. Подробности — [architecture.md §9](docs/architecture.md).
112
+
113
+ ## Документация
114
+
115
+ - [Руководство по задачам (юз-кейсы с примерами)](docs/guide.md)
116
+ - [Архитектура и API](docs/architecture.md)
117
+ - [Prior art / ресёрч](docs/research.md)
118
+ - [План реализации](docs/plan/PLAN.md) · [прогресс](docs/plan/PROGRESS.md) ·
119
+ [решения](docs/plan/DECISIONS.md)
120
+
121
+ ## Лицензия
122
+
123
+ [MIT](LICENSE).
@@ -0,0 +1,97 @@
1
+ # staged-pipeline
2
+
3
+ > **Статус: pre-release (0.1.0a).** API описан в [docs/architecture.md](docs/architecture.md),
4
+ > реализация — по [docs/plan/PLAN.md](docs/plan/PLAN.md). До релиза `0.1.0` возможны изменения.
5
+
6
+ Декларативный конвейер стадий поверх `asyncio` внутри одного процесса: пул воркеров на стадию,
7
+ дедупликация, ретраи с backoff, предохранители, лимиты и живой прогресс. Режим завершения выводится
8
+ из графа (DAG закрывается по писателям, цикл — по quiescence), поэтому «выбрать неправильный режим и
9
+ повиснуть» нельзя.
10
+
11
+ ## Чем это является
12
+
13
+ - слой внутри одного процесса и одного event loop: стадии с воркерами, маршрутизацией по типу,
14
+ политиками исходов (`retry`/`skip_on`/`error_on`), лимитами и дедупликацией;
15
+ - источник честного прогресса: `found / queued / in_flight / deferred / ok / skip / error /
16
+ cancelled / duplicates`, `expected` и `eta`;
17
+ - одноразовый граф, проверяемый до старта (ошибка топологии не запускает ничего).
18
+
19
+ ## Чем это не является
20
+
21
+ - не durable и не распределённая система — всё в одном процессе;
22
+ - не владеет хранилищем: устойчивость между прогонами даёт БД домена (resume засевом);
23
+ - не замена очереди задач (Tallyho и подобных) — это слой внутри одного Item.
24
+
25
+ ## Установка
26
+
27
+ ```bash
28
+ uv add staged-pipeline # ядро, без зависимостей
29
+ uv add "staged-pipeline[tallyho]" # + маркер интеграции с Tallyho
30
+ ```
31
+
32
+ Требуется Python 3.13+.
33
+
34
+ ## Quickstart
35
+
36
+ ```python
37
+ import asyncio
38
+ from staged_pipeline import Pipeline
39
+
40
+
41
+ async def scan(folder: str): # async-генератор: потоковый fan-out
42
+ for i in range(3):
43
+ yield f"{folder}/{i}"
44
+
45
+
46
+ async def resolve(path: str) -> list[str]: # атомарный fan-out
47
+ return [f"{path}.a", f"{path}.b"]
48
+
49
+
50
+ async def download(url: str) -> None: # терминальная стадия
51
+ ...
52
+
53
+
54
+ async def main() -> None:
55
+ pipe = Pipeline("export")
56
+ listing = pipe.stage("list", scan, workers=2)
57
+ resolving = pipe.stage("resolve", resolve, workers=8, key=lambda p: p)
58
+ media = pipe.stage("media", download, workers=4, key=lambda u: u)
59
+
60
+ listing.to(resolving)
61
+ resolving.to(media)
62
+ listing.seed(["inbox"])
63
+
64
+ report = await pipe.run()
65
+ print(report.stages["media"].ok)
66
+
67
+
68
+ asyncio.run(main())
69
+ ```
70
+
71
+ Больше примеров — в [examples/](examples/): `crawler.py` (цикл/самопетля) и `export.py`
72
+ (fan-out + dedup + resume). Оба исполняются в тестах.
73
+
74
+ ## Когда этапы Tallyho, а когда пайплайн
75
+
76
+ | Критерий | Этапы Tallyho (`sub_batch` + `fed_by`) | Пайплайн внутри Item |
77
+ |---|---|---|
78
+ | Элемент должен пережить падение воркера сам по себе | ✔ | ✘ (resume — через БД домена) |
79
+ | Элементы дешёвые (≪ 100 мс) и их 10⁴–10⁶ на единицу | дорого: строка + коммит на элемент | ✔ |
80
+ | Общая сессия/лиз/соединение на единицу | ✘ (лиз на задачу) | ✔ |
81
+ | Масштаб на несколько машин | ✔ | ✘ |
82
+ | Нужен точный итог по каждому элементу в БД | ✔ | домен пишет сам |
83
+
84
+ Мост прогресса и остановки к Tallyho — `staged_pipeline.integrations.tallyho` (`track`,
85
+ `outcome_for`), без зависимости от `tallyho`. Подробности — [architecture.md §9](docs/architecture.md).
86
+
87
+ ## Документация
88
+
89
+ - [Руководство по задачам (юз-кейсы с примерами)](docs/guide.md)
90
+ - [Архитектура и API](docs/architecture.md)
91
+ - [Prior art / ресёрч](docs/research.md)
92
+ - [План реализации](docs/plan/PLAN.md) · [прогресс](docs/plan/PROGRESS.md) ·
93
+ [решения](docs/plan/DECISIONS.md)
94
+
95
+ ## Лицензия
96
+
97
+ [MIT](LICENSE).