Metadata-Version: 2.4
Name: fractal-processes
Version: 1.1.0
Summary: A small workflow engine: processes assembled from actions and run against a shared context, so a workflow is data rather than code.
Keywords: workflow,process,orchestration,saga,state machine
Author-email: Douwe van der Meij <douwe@karibu-online.nl>
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
License-File: LICENSE
Requires-Dist: fractal-specifications
Requires-Dist: pytest>=7.0.0 ; extra == "dev"
Requires-Dist: pytest-asyncio>=0.23.0 ; extra == "dev"
Requires-Dist: pytest-cov>=4.0.0 ; extra == "dev"
Requires-Dist: black>=23.0.0 ; extra == "dev"
Requires-Dist: ruff>=0.1.0 ; extra == "dev"
Requires-Dist: mypy>=1.0.0 ; extra == "dev"
Requires-Dist: isort>=5.13.2 ; extra == "dev"
Project-URL: Documentation, https://github.com/Fractal-Forge/fractal-processes#readme
Project-URL: Homepage, https://github.com/Fractal-Forge/fractal-processes
Project-URL: Issues, https://github.com/Fractal-Forge/fractal-processes/issues
Project-URL: Repository, https://github.com/Fractal-Forge/fractal-processes
Provides-Extra: dev

# Fractal Processes

> Fractal Processes is a small workflow engine: processes assembled from actions and run against a shared context, so a workflow is data rather than code.

[![PyPI Version][pypi-image]][pypi-url]
[![Build Status][build-image]][build-url]

<!-- Badges -->

[pypi-image]: https://img.shields.io/pypi/v/fractal-processes
[pypi-url]: https://pypi.org/project/fractal-processes/
[build-image]: https://github.com/Fractal-Forge/fractal-processes/actions/workflows/build.yml/badge.svg
[build-url]: https://github.com/Fractal-Forge/fractal-processes/actions/workflows/build.yml

## Installation

```sh
pip install fractal-processes
```

## Background

A `Process` is an ordered list of `Action`s, run against a `ProcessContext` that
carries state from one to the next. Actions cover the ordinary things a workflow
does — set a value, fetch or store an entity, dispatch a command, publish an
event — and control flow is itself made of actions, so branching, loops and
sub-processes live inside the process rather than in Python around it.

That is the whole point. A workflow assembled from data can be stored,
inspected, and changed without a deploy; a workflow written as a function
cannot. The cost is that you give up Python's syntax for the parts that become
actions, which is why this is worth reaching for when a workflow is
configuration and not worth it when it is just code.

Self-contained by design: this package imports no other Fractal library except
[fractal-specifications](https://github.com/douwevandermeij/fractal-specifications),
which it uses to express conditions.

## Usage

```python
from fractal_processes import (
    IfElseAction,
    Process,
    ProcessContext,
    SetContextVariableAction,
    SetValueAction,
    field_gt,
)

process = Process([
    SetContextVariableAction(discount=0),
    IfElseAction(
        field_gt("order.total", 100),
        [SetValueAction("discount", 10)],
        [SetValueAction("discount", 0)],
    ),
])

ctx = ProcessContext({"order": {"total": 250}})
process.run(ctx)

ctx["discount"]      # 10
ctx.order.total      # 250 — attribute access works too
```

`ProcessContext` supports dotted keys (`"order.total"`) and attribute access,
and merges nested dicts rather than replacing them.

## Actions

**State** — `SetContextVariableAction`, `SetValueAction`, `GetValueAction`,
`ApplyToValueAction`, `IncreaseValueAction`

**Entities** — `AddEntityAction`, `UpdateEntityAction`, `FetchEntityAction`,
`FindEntitiesAction`, `DeleteEntityAction`

**Messaging** — `CommandAction`, `QueryAction`, `PublishEventAction`

**Control flow** — `IfElseAction`, `WhileAction`, `ForEachAction`,
`TryExceptAction`, `SubProcessAction`, `ParallelAction`

**Diagnostics** — `PrintAction`, `PrintValueAction`, `RaiseExceptionAction`,
`CreateSpecificationAction`

## Conditions

Conditions are [specifications](https://github.com/douwevandermeij/fractal-specifications),
built with helpers that read the context:

```python
from fractal_processes import field_equals, field_gt, field_in, has_field, on_field

field_equals("user.role", "admin")
field_gt("order.total", 100)
field_in("status", ["draft", "review"])
has_field("user.email")
on_field("order.lines", lambda lines: len(lines) > 3)
```

`CallableSpecification` wraps any callable, for the cases the helpers do not
cover.

## Async

`AsyncProcess` and `AsyncAction` are the awaitable equivalents. Both provide a
synchronous wrapper, so an async process can be run from sync code.

## Development

```sh
make dev-install
make test
make lint
make format
```

