> built 2026-09-15 09:53 UTC from 0cb2609 (master) · meshed 0.1.168. Details: build_info.json

# index.html.md

<!-- generated by epythet -->

# meshed

Object composition.
In particular: Link functions up into callable objects (e.g. pipelines, DAGs, etc.)

To install: `pip install meshed`

[Documentation](https://i2mint.github.io/meshed/)

Note: The initial focus of `meshed` was on DAGs, a versatile and probably most known kind of composition of functions,
but `meshed` aims at capturing much more than that.

<!-- epythet:agentic-readme:start -->

# For AI agents

`meshed` ships tooling for coding agents. If you are one, start here.

**The documentation, machine-readable**: [`llms.txt`](https://i2mint.github.io/meshed/llms.txt) indexes every page; [`meshed.md`](https://i2mint.github.io/meshed/meshed.md) is the whole documentation in one file; every page has a `.md` twin; [`objects.inv`](https://i2mint.github.io/meshed/objects.inv) maps symbols to URLs.

If you identify as a dinosaur, the rest of this README is written for you, starting at [Quick Start]().

<!-- epythet:agentic-readme:end -->

# Quick Start

```python
from meshed import DAG

def this(a, b=1):
    return a + b
def that(x, b=1):
    return x * b
def combine(this, that):
    return (this, that)

dag = DAG((this, that, combine))
print(dag.synopsis_string())
```

```none
x,b -> that_ -> that
a,b -> this_ -> this
this,that -> combine_ -> combine
```

But what does it do?

It’s a callable, with a signature:

```python
from inspect import signature
signature(dag)
```

```none
<Signature (x, a, b=1)>
```

And when you call it, it executes the dag from the root values you give it and
returns the leaf output values.

```python
dag(1, 2, 3)  # (a+b,x*b) == (2+3,1*3) == (5, 3)
```

```none
(5, 3)
```

```python
dag(1, 2)  # (a+b,x*b) == (2+1,1*1) == (3, 1)
```

```none
(3, 1)
```

You can see (and save image, or ascii art) the dag:

```python
dag.dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/127779463-ae75604b-0d69-4ac4-b206-80c2c5ae582b.png)

You can extend a dag

```python
dag2 = DAG([*dag, lambda this, a: this + a])
dag2.dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/127779748-70b47907-e51f-4e64-bc18-9545ee07e632.png)

You can get a sub-dag by specifying desired input(s) and outputs.

```python
dag2[['that', 'this'], 'combine'].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/127779781-8aac40eb-ed52-4694-b50e-4af896cc30a2.png)

## Note on flexibility

The above DAG was created straight from the functions, using only the names of the
functions and their parameters to define how to hook the network up.

But if you didn’t write those functions specifically for that purpose, or you want
to use someone else’s functions, one would need to specify the relation between parameters, inputs and outputs.

For that purpose, functions can be adapted using the class FuncNode. The class allows you to essentially rename each of the parameters and also specify which output should be used as an argument for any other functions.

Let us consider the example below.

```python
def f(a, b):
    return a + b

def g(a_plus_b, d):
    return a_plus_b * d
```

Say we want the output of f to become the value of the parameter a_plus_b. We can do that by assigning the string ‘a_plus_b’ to the out parameter of a FuncNode representing the function f:

```python
f_node = FuncNode(func=f, out="a_plus_b")
```

We can now create a dag using our f_node instead of f:

```python
dag = DAG((f_node, g))
```

Our dag behaves as wanted:

```python
dag(a=1, b=2, d=3)
9
```

Now say we would also like for the value given to b to be also given to d. We can achieve that by binding d to b in the bind parameter of a FuncNode representing g:

```python
g_node = FuncNode(func=g, bind={"d": "b"})
```

The dag created with f_node and g_node has only two parameters, namely a and b:

```python
dag = DAG((f_node, g_node))
dag(a=1, b=2)
6
```

# Sub-DAGs

`dag[input_nodes:output_nodes]` is the sub-dag made of intersection of all
descendants of `input_nodes`
(inclusive) and ancestors of `output_nodes` (inclusive), where additionally,
when a func node is contained, it takes with it the input and output nodes
it needs.

```python
from meshed import DAG

def f(a): ...
def g(f): ...
def h(g): ...
def i(h): ...
dag = DAG([f, g, h, i])

dag.dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154749811-f9892ee6-617c-4fa6-9de9-1ebc509c04ae.png)

Get a subdag from `g_` (indicates the function here) to the end of `dag`

```python
subdag = dag['g_',:]
subdag.dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154749842-c2320d1c-368d-4be8-ac57-9a77f1bb081d.png)

From the beginning to `h_`

```python
dag[:, 'h_'].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154750524-ece7f4b6-a3f3-46c6-a66d-7dc9b8ef254a.png)

From `g_` to `h_` (both inclusive)

```python
dag['g_', 'h_'].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154749864-5a33aa13-0949-4aa7-945c-4d3fe7f07e7d.png)

Above we used function (node names) to specify what we wanted, but we can also
use names of input/output var-nodes. Do note the difference though.
The nodes you specify to get a sub-dag are INCLUSIVE, but when you
specify function nodes, you also get the input and output nodes of these
functions.

The `dag['g_', 'h_']` give us a sub-dag starting at `f` (the input node),
but when we ask `dag['g', 'h_']` instead, `g` being the output node of
function node `g_`, we only get `g -> h_ -> h`:

```python
dag['g', 'h'].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154750753-737e2705-0ea3-4595-a93a-1567862a6edd.png)

If we wanted to include `f` we’d have to specify it:

```python
dag['f', 'h'].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154749864-5a33aa13-0949-4aa7-945c-4d3fe7f07e7d.png)

Those were for simple pipelines, but let’s now look at a more complex dag.

Note the definition: `dag[input_nodes:output_nodes]` is the sub-dag made of intersection of all
descendants of `input_nodes`
(inclusive) and ancestors of `output_nodes` (inclusive), where additionally,
when a func node is contained, it takes with it the input and output nodes
it needs.

We’ll let the following examples self-comment:

```python
from meshed import DAG


def f(u, v): ...

def g(f): ...

def h(f, w): ...

def i(g, h): ...

def j(h, x): ...

def k(i): ...

def l(i, j): ...

dag = DAG([f, g, h, i, j, k, l])

dag.dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154748574-a7026125-659f-465b-9bc3-14a1864d14b2.png)
```python
dag[['u', 'f'], 'h'].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154748685-24e706ce-b68f-429a-b7b8-7bda62ccdf36.png)
```python
dag['u', 'h'].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154748865-6e729094-976a-4af3-87f0-b6dd3900fb8c.png)
```python
dag[['u', 'f'], ['h', 'g']].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154748905-4eaeccbe-6cca-4492-a7a2-48f7c9937b95.png)
```python
dag[['x', 'g'], 'k'].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154748937-7a278b25-6f0f-467c-a977-89a175e15abb.png)
```python
dag[['x', 'g'], ['l', 'k']].dot_digraph()
```

![image](https://user-images.githubusercontent.com/1906276/154748958-135792a6-ce16-4561-9cbe-4662113a1022.png)

# Examples

## A train/test ML pipeline

Consider a simple train/test ML pipeline that looks like this.

![image](https://user-images.githubusercontent.com/1906276/135151068-179d958e-9e96-48aa-9188-52ae22919c6e.png)

With this, we might decide we want to give the user control over how to do
`train_test_split` and `learner`, so we offer this interface to the user:

![image](https://user-images.githubusercontent.com/1906276/135151094-661850c0-f10c-49d8-ace2-46b3d994de80.png)

With that, the user can just bring its own `train_test_split` and `learner`
functions, and as long as it satisfied the
expected (and even better; declared and validatable) protocol, things will work.

In some situations we’d like to fix some of how `train_test_split` and
`learner` work, allowing the user to control only some aspects of them.
This function would look like this:

![image](https://user-images.githubusercontent.com/1906276/135151137-3d9a290f-d5e7-4f24-a418-82f1edb8a46a.png)

And inside, it does:

![image](https://user-images.githubusercontent.com/1906276/135151114-926b52b8-0536-4565-bd56-95099f21e4ff.png)

`meshed` allows us to easily manipulate such functional structures to
adapt them to our needs.

# itools module

Tools that enable operations on graphs where graphs are represented by an adjacency Mapping.

Again.

Graphs: You know them. Networks.
Nodes and edges, and the ecosystem descriptive or transformative functions surrounding these.
Few languages have builtin support for the graph data structure, but all have their libraries to compensate.

The one you’re looking at focuses on the representation of a graph as `Mapping` encoding
its [adjacency list](https://en.wikipedia.org/wiki/Adjacency_list).
That is, a dictionary-like interface that specifies the graph by specifying for each node
what nodes it’s adjacent to:

```python
assert graph[source_node] == set_of_nodes_that_source_node_has_edges_to
```

We emphasize that there is no specific graph instance that you need to squeeze your graph into to
be able to use the functions of `meshed`. Suffices that your graph’s structure is expressed by
that dict-like interface
– which grown-ups call `Mapping` (see the `collections.abc` or `typing` standard libs for more information).

You’ll find a lot of `Mapping`s around pythons.
And if the object you want to work with doesn’t have that interface,
you can easily create one using one of the many tools of `py2store` meant exactly for that purpose.

# Examples

```python
>>> from meshed.itools import edges, nodes, isolated_nodes
>>> graph = dict(a='c', b='ce', c='abde', d='c', e=['c', 'b'], f={})
>>> sorted(edges(graph))
[('a', 'c'), ('b', 'c'), ('b', 'e'), ('c', 'a'), ('c', 'b'), ('c', 'd'), ('c', 'e'), ('d', 'c'), ('e', 'b'), ('e', 'c')]
>>> sorted(nodes(graph))
['a', 'b', 'c', 'd', 'e', 'f']
>>> set(isolated_nodes(graph))
{'f'}
>>>
>>> from meshed.itools import edge_reversed_graph
>>> g = dict(a='c', b='cd', c='abd', e='')
>>> assert edge_reversed_graph(g) == {'c': ['a', 'b'], 'd': ['b', 'c'], 'a': ['c'], 'b': ['c'], 'e': []}
>>> reverse_g_with_sets = edge_reversed_graph(g, set, set.add)
>>> assert reverse_g_with_sets == {'c': {'a', 'b'}, 'd': {'b', 'c'}, 'a': {'c'}, 'b': {'c'}, 'e': set([])}
```

<p class="epythet-aggregates">This documentation as a single file: <a href="meshed.md">meshed.md</a> (Markdown, for agents).</p>


# _autosummary/meshed.base.html.md

# meshed.base

Define `FuncNode`, the unit of computation that `meshed` assembles into DAGs.

A `FuncNode` wraps a function together with a `name` (its identity in the network),
a `bind` (which scope variables feed which parameters) and an `out` (the scope
variable its result is written to). Calling the node on a scope, a mutable mapping,
reads its inputs from there and writes its output back. This module also holds the
helpers that validate, convert, rewrite and render such nodes; `meshed.dag` builds
on them to wire many nodes into a `DAG`.

Main entry points:

- `FuncNode`: wrap a function with its name, bind and out.
- `ensure_func_nodes`: turn a mix of callables and nodes into `FuncNode` objects.
- `ch_func_node_func`: swap a node’s function, guarded by a signature comparison.
- `func_nodes_to_code`: render nodes back as Python source.

```pycon
>>> fn = FuncNode(lambda x, y: x + y, name='add', out='total')
>>> fn
FuncNode(x,y -> add -> total)
>>> scope = {'x': 1, 'y': 2}
>>> fn.call_on_scope(scope)
3
>>> scope
{'x': 1, 'y': 2, 'total': 3}
```

### Functions

| [`basic_node_validator`](_autosummary/meshed.base.html.md#meshed.base.basic_node_validator)(func_node)                  | Validates a func node.                                                                                                                                         |
|---------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`ch_func_node_attrs`](_autosummary/meshed.base.html.md#meshed.base.ch_func_node_attrs)(fn, \*\*new_attrs_values)     | Returns a copy of the func node with some of its attributes changed                                                                                            |
| [`ch_func_node_func`](_autosummary/meshed.base.html.md#meshed.base.ch_func_node_func)(fn, func, \*[, ...])           | Return a copy of `fn` whose function is `func`, if `func_comparator` accepts the replacement; otherwise hand `(fn, func)` to `alternative`.                    |
| [`dot_lines_of_func_parameters`](_autosummary/meshed.base.html.md#meshed.base.dot_lines_of_func_parameters)(parameters, ...)    | Yield graphviz dot lines drawing `parameters` as variable nodes that feed a function node `func_id`, which in turn feeds the variable node `out`.              |
| [`duplicates`](_autosummary/meshed.base.html.md#meshed.base.duplicates)(elements)                             | List the elements that occur more than once, in order of first occurrence.                                                                                     |
| [`ensure_func_nodes`](_autosummary/meshed.base.html.md#meshed.base.ensure_func_nodes)(func_nodes)                    | Converts a list of objects to a list of FuncNodes.                                                                                                             |
| [`func_node_transformer`](_autosummary/meshed.base.html.md#meshed.base.func_node_transformer)(fn[, kwargs_transformers]) | Get a modified `FuncNode` from an iterable of `kwargs_trans` modifiers.                                                                                        |
| [`func_nodes_to_code`](_autosummary/meshed.base.html.md#meshed.base.func_nodes_to_code)(func_nodes[, func_name, ...]) | Convert an iterable of FuncNodes back to executable Python code.                                                                                               |
| [`get_init_params_of_instance`](_autosummary/meshed.base.html.md#meshed.base.get_init_params_of_instance)(obj)                 | Get names of instance object `obj` that are also parameters of the `__init__` of its class                                                                     |
| [`handle_variadics`](_autosummary/meshed.base.html.md#meshed.base.handle_variadics)(func)                           | Replace the variadic parameters of `func` (`*args`, `**kwargs`) with a tuple and a dict parameter of the same names, returning `func` itself when it has none. |
| [`identifier_mapping`](_autosummary/meshed.base.html.md#meshed.base.identifier_mapping)(x)                            | Get an `IdentifierMapping` dict from a more loosely defined `Bind`.                                                                                            |
| [`insert_func_if_compatible`](_autosummary/meshed.base.html.md#meshed.base.insert_func_if_compatible)([func_comparator])     | Make a `ch_func_node_func` variant with `func_comparator` fixed.                                                                                               |
| [`is_func_node`](_autosummary/meshed.base.html.md#meshed.base.is_func_node)(obj)                                | Whether `obj` is a `FuncNode` (checked by class name, so it survives reloads).                                                                                 |
| [`is_not_func_node`](_autosummary/meshed.base.html.md#meshed.base.is_not_func_node)(obj)                            | Whether `obj` is not a `FuncNode`.                                                                                                                             |
| [`param_to_dot_definition`](_autosummary/meshed.base.html.md#meshed.base.param_to_dot_definition)(p[, shape])              | Yield the dot line declaring parameter `p` as a node, labelled `name=` when it has a default and `*name` or `**name` when it is variadic.                      |
| [`raise_signature_mismatch_error`](_autosummary/meshed.base.html.md#meshed.base.raise_signature_mismatch_error)(fn, func)         | Raise a `ValueError` saying `func` cannot replace `fn.func` because their signatures differ; the default `alternative` of `ch_func_node_func`.                 |
| [`rebind_to_func`](_autosummary/meshed.base.html.md#meshed.base.rebind_to_func)(fnode, new_func)                  | Replaces `fnode.func` with `new_func`, changing the `.bind` accordingly.                                                                                       |
| [`underscore_func_node_names_maker`](_autosummary/meshed.base.html.md#meshed.base.underscore_func_node_names_maker)(func[, ...])    | This name maker will resolve names in the following fashion:                                                                                                   |
| [`validate_that_func_node_names_are_sane`](_autosummary/meshed.base.html.md#meshed.base.validate_that_func_node_names_are_sane)(...)      | Assert that the names of func_nodes are sane.                                                                                                                  |

### Classes

| [`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)(func[, name, bind, out, ...])   | A function wrapper that makes the function amenable to operating in a network.                               |
|-------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
| [`Mesh`](_autosummary/meshed.base.html.md#meshed.base.Mesh)(func_nodes)                         | Hold a collection of `FuncNode` objects, with no wiring or execution logic (for that, use `meshed.dag.DAG`). |

### *class* meshed.base.FuncNode(func, name=None, bind=<factory>, out=None, func_label=None, names_maker=<function underscore_func_node_names_maker>, node_validator=<function basic_node_validator>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A function wrapper that makes the function amenable to operating in a network.

* **Parameters:**
  * **func** ([`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)) – Function to wrap
  * **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – The name to associate to the function
  * **bind** ([`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)) – The {func_argname: external_name,…} mapping that defines where
    the node will source the data to call the function.
    This only has to be used if the external names are different from the names
    of the arguments of the function.
  * **out** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – The variable name the function should write it’s result to

Like we stated: `FuncNode` is meant to operate in computational networks.
But knowing what it does will help you make the networks you want, so we commend
your curiousity, and will oblige with an explanation.

Say you have a function to multiply numbers.

```pycon
>>> def multiply(x, y):
...     return x * y
```

And you use it in some code like this:

```pycon
>>> item_price = 3.5
>>> num_of_items = 2
>>> total_price = multiply(item_price, num_of_items)
```

What the execution of `total_price = multiply(item_price, num_of_items)` does is

- grab the values (in the locals scope – a dict), of `item_price` and `num_of_items`,
- call the multiply function on these, and then
- write the result to a variable (in locals) named `total_price`

`FuncNode` is a function wrapper that specification of such a
`output = function(...inputs...)` assignment statement
in such a way that it can carry it out on a `scope`.
A `scope` is a `dict` where the function can find it’s input values and write its
output values.

For example, the `FuncNode` form of the above statement would be:

```pycon
>>> func_node = FuncNode(
...     func=multiply,
...     bind={'x': 'item_price', 'y': 'num_of_items'})
>>> func_node
FuncNode(x=item_price,y=num_of_items -> multiply_ -> multiply)
```

Note the `bind` is a mapping **from** the variable names of the wrapped function
**to** the names of the scope.

That is, when it’s time to execute, it tells the `FuncNode` where to find the values
of its inputs.

If an input is not specified in this `bind` mapping, the scope
(external) name is supposed to be the same as the function’s (internal) name.

The purpose of a `FuncNode` is to source some inputs somewhere, compute something
with these, and write the result somewhere. That somewhere is what we call a
scope. A scope is a dictionary (or any mutuable mapping to be precise) and it works
like this:

```pycon
>>> scope = {'item_price': 3.5, 'num_of_items': 2}
>>> func_node.call_on_scope(scope)  # see that it returns 7.0
7.0
>>> scope  # but also wrote this in the scope
{'item_price': 3.5, 'num_of_items': 2, 'multiply': 7.0}
```

Consider `item_price,num_of_items -> multiply_ -> multiply`.
See that the name of the function is used for the name of its output,
and an underscore-suffixed name for its function name.
That’s the default behavior if you don’t specify either a name (of the function)
for the `FuncNode`, or a `out`.
The underscore is to distinguish from the name of the function itself.
The function gets the underscore because this favors particular naming style.

You can give it a custom name as well.

```pycon
>>> FuncNode(multiply, name='total_price', out='daily_expense')
FuncNode(x,y -> total_price -> daily_expense)
```

If you give an `out`, but not a `name` (for the function), the function’s
name will be taken:

```pycon
>>> FuncNode(multiply, out='daily_expense')
FuncNode(x,y -> multiply -> daily_expense)
```

If you give a `name`, but not a `out`, an underscore-prefixed version of
the `name` will be taken:

```pycon
>>> FuncNode(multiply, name='total_price')
FuncNode(x,y -> total_price -> _total_price)
```

#### NOTE
In the context of networks if you want to reuse a same function
(say, `multiply`) in multiple places
you’ll **need** to give it a custom name because the functions are identified by
this name in the network.

#### call_on_scope(scope, write_output_into_scope=True)

Call the function using the given scope both to source arguments and write
results.

#### NOTE
This method is only meant to be used as a backend to \_\_call_\_, not as
an actual interface method. Additional control/constraints on read and writes
can be implemented by providing a custom scope for that.

#### ch_attrs(\*\*new_attrs_values)

Returns a copy of the func node with some of its attributes changed

```pycon
>>> def plus(a, b):
...     return a + b
...
>>> def minus(a, b):
...     return a - b
...
>>> fn = FuncNode(func=plus, out='sum')
>>> fn.func == plus
True
>>> fn.name == 'plus'
True
>>> new_fn = fn.ch_attrs(func=minus)
>>> new_fn.func == minus
True
>>> new_fn.synopsis_string() == 'a,b -> plus -> sum'
True
>>>
>>>
>>> newer_fn = fn.ch_attrs(func=minus, name='sub', out='difference')
>>> newer_fn.synopsis_string() == 'a,b -> sub -> difference'
True
```

#### dot_lines(\*\*kwargs)

Returns a list of lines that can be used to make a dot graph

#### *classmethod* from_dict(dictionary)

The inverse of to_dict: Make a `FuncNode` from a dictionary of init args

#### *classmethod* has_as_instance(obj)

Verify if `obj` is an instance of a FuncNode (or specific sub-class).

The usefulness of this method is to not have to make a lambda with isinstance
when filtering.

```pycon
>>> FuncNode.has_as_instance(FuncNode(lambda x: x))
True
>>> FuncNode.has_as_instance("I am not a FuncNode: I'm a string")
False
```

#### names_maker(name=None, out=None)

This name maker will resolve names in the following fashion:

> 1. look at the (func) name and out given as arguments, if None…
> 2. use mk_func_name(func) to make names.

It will use the mk_func_name(func)  itself for out, but suffix the same with
an underscore to provide a mk_func_name.

This is so because here we want to allow easy construction of function networks
where a function’s output will be used as another’s input argument when
that argument has the the function’s (output) name.

#### node_validator()

Validates a func node. Raises ValidationError if something wrong. Returns None.

Validates:

* that the `func_node` params are valid, that is, if not `None`:
  * `func` should be a callable
  * `name` and `out` should be `str`
  * `bind` should be a `Dict[str, str]`
* that the names (`.name`, `.out` and all `.bind.values()`):
  * are valid python identifiers (alphanumeric or underscore not starting with
    digit)
  * are not repeated (no duplicates)
* that `.bind.keys()` are indeed present as params of `.func`

#### synopsis_string(bind_info='values')

Return the one-line `bind -> name -> out` synopsis of the node.

* **Parameters:**
  **bind_info** ([`Literal`](https://docs.python.org/3/library/typing.html#typing.Literal)[`'var_nodes'`, `'params'`, `'hybrid'`]) – 

  How to represent the bind in the synopsis string. Could be:
  - ’values’, `var_nodes` or `varnodes`: the values of the bind (default).
  - ’keys’ or ‘params’: the keys of the bind
  - ’hybrid’: the keys of the bind, but with the values that are the same as
    the keys omitted.

```pycon
>>> fn = FuncNode(
...     func=lambda y, c: None , name='h', bind={'y': 'b', 'c': 'c'}, out='d'
... )
>>> fn.synopsis_string()
'b,c -> h -> d'
>>> fn.synopsis_string(bind_info='keys')
'y,c -> h -> d'
>>> fn.synopsis_string(bind_info='hybrid')
'y=b,c -> h -> d'
```

#### to_dict()

The inverse of from_dict: FuncNode.from_dict(fn.to_dict()) == fn

### *class* meshed.base.Mesh(func_nodes)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Hold a collection of `FuncNode` objects, with no wiring or execution logic
(for that, use `meshed.dag.DAG`).

#### synopsis_string(bind_info='values')

Join the synopsis strings of the nodes, one per line.

### meshed.base.basic_node_validator(func_node)

Validates a func node. Raises ValidationError if something wrong. Returns None.

Validates:

* that the `func_node` params are valid, that is, if not `None`:
  * `func` should be a callable
  * `name` and `out` should be `str`
  * `bind` should be a `Dict[str, str]`
* that the names (`.name`, `.out` and all `.bind.values()`):
  * are valid python identifiers (alphanumeric or underscore not starting with
    digit)
  * are not repeated (no duplicates)
* that `.bind.keys()` are indeed present as params of `.func`

### meshed.base.ch_func_node_attrs(fn, \*\*new_attrs_values)

Returns a copy of the func node with some of its attributes changed

```pycon
>>> def plus(a, b):
...     return a + b
...
>>> def minus(a, b):
...     return a - b
...
>>> fn = FuncNode(func=plus, out='sum')
>>> fn.func == plus
True
>>> fn.name == 'plus'
True
>>> new_fn = ch_func_node_attrs(fn, func=minus)
>>> new_fn.func == minus
True
>>> new_fn.synopsis_string() == 'a,b -> plus -> sum'
True
>>>
>>>
>>> newer_fn = ch_func_node_attrs(fn, func=minus, name='sub', out='difference')
>>> newer_fn.synopsis_string() == 'a,b -> sub -> difference'
True
```

### meshed.base.ch_func_node_func(fn, func, \*, func_comparator=<function compare_signatures>, ch_func_node=<function \_ch_func_node_func>, alternative=<function raise_signature_mismatch_error>)

Return a copy of `fn` whose function is `func`, if `func_comparator`
accepts the replacement; otherwise hand `(fn, func)` to `alternative`.

This is what `DAG.ch_funcs` applies to each node it changes. The default
comparator requires the two signatures to match exactly; the default
`alternative` raises a `ValueError`.

* **Parameters:**
  * **func_comparator** ([`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[[`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable), [`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)], [`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)(`Comparison`)]) – Called as `func_comparator(fn.func, func)`; a truthy result
    allows the swap.
  * **ch_func_node** – How to build the new node once the swap is allowed; called as
    `ch_func_node(fn, func=func)`.
  * **alternative** – Called as `alternative(fn, func)` when the swap is refused; its
    return value is returned as is.

```pycon
>>> fn = FuncNode(lambda a, b: a + b, name='f')
>>> new_fn = ch_func_node_func(fn, lambda a, b: a * b)
>>> new_fn.call_on_scope({'a': 2, 'b': 3})
6
```

A function with a different signature is refused:

```pycon
>>> ch_func_node_func(fn, lambda a, b, c=0: a * b)
Traceback (most recent call last):
  ...
ValueError: You can only change the func of a FuncNode with a another func if the signatures match.
...
```

unless `alternative` says otherwise, here by keeping the original node:

```pycon
>>> kept = ch_func_node_func(
...     fn, lambda a, b, c=0: a * b, alternative=lambda fn, func: fn
... )
>>> kept is fn
True
```

### meshed.base.dot_lines_of_func_parameters(parameters, out, func_id, , func_label=None, vnode_shape='none', fnode_shape='box', func_display=True)

Yield graphviz dot lines drawing `parameters` as variable nodes that feed a
function node `func_id`, which in turn feeds the variable node `out`.

* **Parameters:**
  **func_display** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – When false, no function node is drawn and the parameter nodes
  point straight at `out`.
* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)]

### meshed.base.duplicates(elements)

List the elements that occur more than once, in order of first occurrence.

```pycon
>>> duplicates("abbaaeccf")
['a', 'b', 'c']
```

### meshed.base.ensure_func_nodes(func_nodes)

Converts a list of objects to a list of FuncNodes.

### meshed.base.func_node_transformer(fn, kwargs_transformers=())

Get a modified `FuncNode` from an iterable of `kwargs_trans` modifiers.

### meshed.base.func_nodes_to_code(func_nodes, func_name='generated_pipeline', , favor_positional=True)

Convert an iterable of FuncNodes back to executable Python code.

This is the inverse operation of code_to_fnodes - it takes FuncNodes and generates
Python code that would create equivalent FuncNodes when parsed.
When favor_positional is True, any keyword argument with key equal to its value
is moved to the positional arguments list:

> func(a=a, b=b, c=z, d=d)  ->  func(a, b, c=z, d=d)
* **Parameters:**
  * **func_nodes** ([`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)]) – Iterable of FuncNode instances to convert to code
  * **func_name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name for the generated function
  * **favor_positional** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool)) – When True, transforms kwargs of the form key=key into positional args.
* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)
* **Returns:**
  String containing Python code

### meshed.base.get_init_params_of_instance(obj)

Get names of instance object `obj` that are also parameters of the
`__init__` of its class

### meshed.base.handle_variadics(func)

Replace the variadic parameters of `func` (`*args`, `**kwargs`) with a
tuple and a dict parameter of the same names, returning `func` itself when it
has none.

### meshed.base.identifier_mapping(x)

Get an `IdentifierMapping` dict from a more loosely defined `Bind`.

You can get an identifier mapping (that is, an explicit for for a `bind` argument)
from…

… a single space-separated string

* **Return type:**
  [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)[`Identifier` ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)), `Identifier` ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str))]

```pycon
>>> identifier_mapping('x a_b yz')  #
{'x': 'x', 'a_b': 'a_b', 'yz': 'yz'}
```

… an iterable of strings or pairs of strings

```pycon
>>> identifier_mapping(['foo', ('bar', 'mitzvah')])
{'foo': 'foo', 'bar': 'mitzvah'}
```

… a dict will be considered to be the mapping itself

```pycon
>>> identifier_mapping({'x': 'y', 'a': 'b'})
{'x': 'y', 'a': 'b'}
```

### meshed.base.insert_func_if_compatible(func_comparator=<function compare_signatures>)

Make a `ch_func_node_func` variant with `func_comparator` fixed.

### meshed.base.is_func_node(obj)

Whether `obj` is a `FuncNode` (checked by class name, so it survives reloads).

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

```pycon
>>> is_func_node(FuncNode(lambda x: x))
True
>>> is_func_node("I am not a FuncNode: I'm a string")
False
```

### meshed.base.is_not_func_node(obj)

Whether `obj` is not a `FuncNode`.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

```pycon
>>> is_not_func_node(FuncNode(lambda x: x))
False
>>> is_not_func_node("I am not a FuncNode: I'm a string")
True
```

### meshed.base.param_to_dot_definition(p, shape='none')

Yield the dot line declaring parameter `p` as a node, labelled `name=` when
it has a default and `*name` or `**name` when it is variadic.

### meshed.base.raise_signature_mismatch_error(fn, func)

Raise a `ValueError` saying `func` cannot replace `fn.func` because their
signatures differ; the default `alternative` of `ch_func_node_func`.

### meshed.base.rebind_to_func(fnode, new_func)

Replaces `fnode.func` with `new_func`, changing the `.bind` accordingly.

```pycon
>>> fn = FuncNode(lambda x, y: x + y, bind={'x': 'X', 'y': 'Y'})
>>> fn.call_on_scope(dict(X=2, Y=3))
5
>>> new_fn = rebind_to_func(fn, lambda a, b, c=0: a * (b + c))
>>> new_fn.call_on_scope(dict(X=2, Y=3))
6
>>> new_fn.call_on_scope(dict(X=2, Y=3, c=1))
8
```

### meshed.base.underscore_func_node_names_maker(func, name=None, out=None)

This name maker will resolve names in the following fashion:

> 1. look at the (func) name and out given as arguments, if None…
> 2. use mk_func_name(func) to make names.

It will use the mk_func_name(func)  itself for out, but suffix the same with
an underscore to provide a mk_func_name.

This is so because here we want to allow easy construction of function networks
where a function’s output will be used as another’s input argument when
that argument has the the function’s (output) name.

### meshed.base.validate_that_func_node_names_are_sane(func_nodes)

Assert that the names of func_nodes are sane.
That is:

* are valid dot (graphviz) names (we’ll use str.isidentifier because lazy)
* All the `func.name` and `func.out` are unique
* more to come (TODO)…


# _autosummary/meshed.caching.html.md

# meshed.caching

Turn functions into cached properties of a class.

The functions here attach `functools.cached_property` attributes to a class
after the fact, so a value is computed once per instance, on first access, from
other attributes of that instance. `LazyProps` does this for every
one-argument callable of a subclass at class-creation time; the
`with_cached_properties` decorator does it for a chosen list of functions,
sourcing each function’s parameters from same-named instance attributes.

Main entry points:

- `LazyProps`: base class that makes each one-argument method a cached property.
- `with_cached_properties`: class decorator adding the given functions as cached
  properties.
- `add_cached_property_from_func`: the same for a single function, without decorating.

```pycon
>>> from meshed.caching import with_cached_properties
>>> def area(width, height):
...     print('computing area')
...     return width * height
>>> @with_cached_properties([area])
... class Rect:
...     def __init__(self, width, height):
...         self.width, self.height = width, height
>>> r = Rect(2, 3)
>>> r.area
computing area
6
>>> r.area
6
```

### Functions

| [`add_cached_property`](_autosummary/meshed.caching.html.md#meshed.caching.add_cached_property)(cls, method[, attr_name])   | Add a method as a cached property to a class.    |
|--------------------------------------------------------------------------------------------------|--------------------------------------------------|
| [`add_cached_property_from_func`](_autosummary/meshed.caching.html.md#meshed.caching.add_cached_property_from_func)(cls, func[, ...]) | Add a function cached property to a class.       |
| [`set_cached_property_attr`](_autosummary/meshed.caching.html.md#meshed.caching.set_cached_property_attr)(obj, name, value)      | Helper to set cached properties.                 |
| [`with_cached_properties`](_autosummary/meshed.caching.html.md#meshed.caching.with_cached_properties)(funcs)                   | A decorator to add cached properties to a class. |

### Classes

| [`LazyProps`](_autosummary/meshed.caching.html.md#meshed.caching.LazyProps)()   | A class that makes all its attributes cached_property properties.   |
|----------------------------------------------------------------|---------------------------------------------------------------------|

### *class* meshed.caching.LazyProps

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A class that makes all its attributes cached_property properties.

### Example

```pycon
>>> class Klass(LazyProps):
...     a = 1
...     b = 2
...
...     # methods with one argument are cached
...     def c(self):
...         print("computing c...")
...         return self.a + self.b
...
...     d = lambda x: 4
...     e = LazyProps.Literal(lambda x: 4)
...
...     @LazyProps.Literal  # to mark that this method should not be cached
...     def method1(self):
...         return self.a * 7
...
...     # Methods with more than one argument are not cached
...     def method2(self, x):
...         return x + 1
...
...
>>> k = Klass()
>>> k.b
2
>>> k.c
computing c...
3
>>> k.c  # note that c is not recomputed
3
>>> k.d  # d, a lambda with one argument, is treated as a cached property
4
>>> k.e()  # e is marked as a literal so is not a cached property, so need to call
4
>>> k.method1()  # method1 has one argument, but marked as a literal
7
>>> k.method2(10)  # method2 has more than one argument, so is not a cached property
11
```

#### Literal

alias of `LiteralVal`

### meshed.caching.add_cached_property(cls, method, attr_name=None)

Add a method as a cached property to a class.

### meshed.caching.add_cached_property_from_func(cls, func, attr_name=None)

Add a function cached property to a class.

### meshed.caching.set_cached_property_attr(obj, name, value)

Helper to set cached properties.

Reason: When adding cached_property dynamically (not just with the @cached_property)
the name is not set correctly. This solves that.

### meshed.caching.with_cached_properties(funcs)

A decorator to add cached properties to a class.


# _autosummary/meshed.components.html.md

# meshed.components

Ready-made extraction components for meshed graphs.

A `DAG` node needs a `__name__` and a signature to know what var node it reads
and what var node it writes. Plain `operator.itemgetter` and `attrgetter`
objects have no `__name__` and no usable one-parameter signature, so this module
wraps them in `Extractor`, a callable that
carries a chosen name and a single positional-only parameter, and can therefore
be listed directly among the functions given to `DAG`.

Main entry points:

- `Itemgetter`: extracts one item, or a tuple of items, from its input by key.
- `AttrGetter`: extracts one attribute, or a tuple of attributes, from its input.
- `Extractor`: the general form; give it a factory and the parameters to build with.

```pycon
>>> from meshed.components import Itemgetter
>>> get_ab = Itemgetter(['a', 'b'])
>>> get_ab({'a': 1, 'b': 2, 'c': 3})
(1, 2)
```

### Classes

| [`Extractor`](_autosummary/meshed.components.html.md#meshed.components.Extractor)(extractor_factory, extractor_params, \*)   | Callable extracting from its single input, named and signed to be a DAG node.   |
|-------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|

### *class* meshed.components.Extractor(extractor_factory, extractor_params, , name='extractor', input_name='x')

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Callable extracting from its single input, named and signed to be a DAG node.

Calling an instance applies `extractor_factory(extractor_params)` to the input.
The instance carries a chosen `__name__` and a one-parameter signature, which
is what `DAG` needs to wire it to var nodes.

* **Parameters:**
  * **extractor_factory** ([`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[[`Any`](https://docs.python.org/3/library/typing.html#typing.Any)], [`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)]) – Called once with `extractor_params` to make the
    function that is applied to the input.
  * **extractor_params** ([`Any`](https://docs.python.org/3/library/typing.html#typing.Any)) – Passed to `extractor_factory`.
  * **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Becomes the `__name__` of the instance.
  * **input_name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – Name of the single positional-only parameter of the instance’s
    signature (the var node a DAG will bind it to).


# _autosummary/meshed.composition.html.md

# meshed.composition

Specific use of FuncNode and DAG

### Functions

| `func_node_kwargs_trans`(func)                                                               |                                                                             |
|----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
| [`func_node_name_trans`](_autosummary/meshed.composition.html.md#meshed.composition.func_node_name_trans)(name_trans, \*[, ...]) |                                                                             |
| [`get_param`](_autosummary/meshed.composition.html.md#meshed.composition.get_param)(func)                             | Find the name of the parameter of a function with exactly one parameter.    |
| [`is_func_node_kwargs_trans`](_autosummary/meshed.composition.html.md#meshed.composition.is_func_node_kwargs_trans)(func)             | Returns True iff the only required params of func are FuncNode field names. |
| [`line_with_dag`](_autosummary/meshed.composition.html.md#meshed.composition.line_with_dag)(\*steps)                      | Emulate a Line object with a DAG                                            |
| `suffix_ids`(func_nodes[, renamer, ...])                                                     |                                                                             |

### meshed.composition.func_node_name_trans(name_trans, , also_apply_to_func_label=False)

* **Parameters:**
  * **name_trans** ([`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str)], [`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`None`](https://docs.python.org/3/builtins/constants.html#None)]) – A function taking a str and returning a str, or None (to indicate
    that no transformation should take place).
  * **also_apply_to_func_label** ([`bool`](https://docs.python.org/3/builtins/functions.html#bool))
* **Returns:**

### meshed.composition.get_param(func)

Find the name of the parameter of a function with exactly one parameter.
Raise an error if more or less parameters.

* **Parameters:**
  **func** – callable, the function to inspect
* **Returns:**
  str, the name of the single parameter of func

### meshed.composition.is_func_node_kwargs_trans(func)

Returns True iff the only required params of func are FuncNode field names.
This ensures that the func will be able to be bound to FuncNode fields and
therefore used as a func_node (kwargs) transformer.

* **Return type:**
  [`bool`](https://docs.python.org/3/builtins/functions.html#bool)

### meshed.composition.line_with_dag(\*steps)

Emulate a Line object with a DAG

* **Parameters:**
  **steps** – an iterable of callables, the steps of the pipeline. Each step should have exactly one parameter
  and the output of each step is fed into the next
* **Returns:**
  a DAG instance computing the composition of all the functions in steps, in the provided order


# _autosummary/meshed.dag.html.md

# meshed.dag

Making DAGs

Main entry points:

- `DAG`: a callable graph of functions; give it functions or `FuncNode` objects,
  call it with the root variables and get the leaf outputs back.
- `FuncNode` (`meshed.base`): wraps one function with the node `name`, the
  variables its parameters `bind` to, and the `out` variable it writes.
- `ch_funcs`: copy of a DAG with some of its node functions replaced.
- `ch_names`: copy of a DAG with its variables and function nodes renamed.
- `code_to_dag` (`meshed.makers`): build a DAG from Python source (a function
  or a string) whose statements are `out = func(...)` assignments.

In it’s simplest form, consider this:

```pycon
>>> from meshed import DAG
>>>
>>> def this(a, b=1):
...     return a + b
...
>>> def that(x, b=1):
...     return x * b
...
>>> def combine(this, that):
...     return (this, that)
...
>>>
>>> dag = DAG((this, that, combine))
>>> print(dag.synopsis_string())
a,b -> this_ -> this
x,b -> that_ -> that
this,that -> combine_ -> combine
```

But don’t be fooled: There’s much more to it!

## FAQ and Troubleshooting

### DAGs and Pipelines

```pycon
>>> from functools import partial
>>> from meshed import DAG
>>> def chunker(sequence, chk_size: int):
...     return zip(*[iter(sequence)] * chk_size)
>>>
>>> my_chunker = partial(chunker, chk_size=3)
>>> def to_list(iterable):
...     return list(iterable)
>>>
>>> vec = range(8)  # when appropriate, use easier to read sequences
>>> to_list(my_chunker(vec))
[(0, 1, 2), (3, 4, 5)]
```

Oh, that’s just a `my_chunker -> to_list` pipeline!
A pipeline is a subset of DAG, so let me do this:

```pycon
>>> dag = DAG([my_chunker, to_list])
>>> dag(vec)
Traceback (most recent call last):
...
TypeError: missing a required argument: 'iterable'
```

What happened here?
You’re assuming that saying `[my_chunker, to_list]` is enough for DAG to know that
what you meant is for `my_chunker` to feed it’s input to `to_list`.
Sure, DAG has enough information to do so, but the default connection policy doesn’t
assume that it’s a pipeline you want to make.
In fact, the order you specify the functions doesn’t have an affect on the connections
with the default connection policy.

See what the signature of `dag` is:

```pycon
>>> from inspect import signature
>>> str(signature(dag))
'(sequence, iterable, *, chk_size: int = 3)'
```

So dag actually works just fine. Here’s the proof:

```pycon
>>> chunks, as_list = dag(vec, [1, 2, 3])
>>> list(chunks), as_list
([(0, 1, 2), (3, 4, 5)], [1, 2, 3])
```

It’s just not what you might have intended.

Your best bet to get what you intended is to be explicit.

The way to be explicit is to not specify functions alone, but `FuncNodes` that
wrap them, along with the specification
the `name` the function will be referred to by,
the names that it’s parameters should `bind` to (that is, where the function
will get it’s import arguments from), and
the `out` name of where it should be it’s output.

In the current case a fully specified DAG would look something like this:

```pycon
>>> from meshed import FuncNode
>>> dag = DAG(
...     [
...         FuncNode(
...             func=my_chunker,
...             name='chunker',
...             bind=dict(sequence='sequence', chk_size='chk_size'),
...             out='chks'
...         ),
...         FuncNode(
...             func=to_list,
...             name='gather_chks_into_list',
...             bind=dict(iterable='chks'),
...             out='list_of_chks'
...         ),
...     ]
... )
>>> list(dag(vec))
[(0, 1, 2), (3, 4, 5)]
```

But really, if you didn’t care about the names of things,
all you need in this case was to make sure that the output of `my_chunker` was
fed to `to_list`, and therefore the following was sufficient:

```pycon
>>> dag = DAG([
...     FuncNode(my_chunker, out='chks'),  # call the output of chunker "chks"
...     FuncNode(to_list, bind=dict(iterable='chks'))  # source to_list input from "chks"
... ])
>>> list(dag(vec))
[(0, 1, 2), (3, 4, 5)]
```

Connection policies are very useful when you want to define ways for DAG to
“just figure it out” for you.
That is, you want to tell the machine to adapt to your thoughts, not vice versa.
We support such technological expectations!
The default connection policy is there to provide one such ways, but
by all means, use another!

Does this mean that connection policies are not for production code?
Well, it depends. The Zen of Python (`import this`)
states “explicit is better than implicit”, and indeed it’s often
a good fallback rule.
But defining components and the way they should be assembled can go a long way
in achieving consistency, separation of concerns, adaptability, and flexibility.
All quite useful things. Also in production. Especially in production.
That said it is your responsiblity to use the right policy for your particular context.

### Functions

| [`arg_names`](_autosummary/meshed.dag.html.md#meshed.dag.arg_names)(func, func_name[, exclude_names])      | List the parameter names of `func`, replacing any found in `exclude_names` with a free `<func_name>__<name>` variant.                                                                                          |
|---------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`attribute_vals`](_autosummary/meshed.dag.html.md#meshed.dag.attribute_vals)(objs, attrs[, egress])            | Extract attributes from an iterable of objects                                                                                                                                                                 |
| [`call_func`](_autosummary/meshed.dag.html.md#meshed.dag.call_func)(func, kwargs)                          | Re-key `kwargs` by each key's `__name__` and pass the resulting dict to `Sig(func).source_kwargs`.                                                                                                             |
| `ch_funcs`([func_nodes, func_mapping, ...])                                                       | Copy a DAG (or iterable of func nodes) with some of its node functions replaced.                                                                                                                               |
| `ch_names`([func_nodes, renamer])                                                                 | Renames variables and functions of a `DAG` or iterable of `FuncNodes`.                                                                                                                                         |
| `change_funcs`([func_nodes, func_mapping, ...])                                                   | Copy a DAG (or iterable of func nodes) with some of its node functions replaced.                                                                                                                               |
| [`change_value_on_cond`](_autosummary/meshed.dag.html.md#meshed.dag.change_value_on_cond)(d, cond, func)              | Replace, in place, each value `v` of `d` where `cond(k, v)` holds with `func(v)`, and return `d`.                                                                                                              |
| [`dag_to_code`](_autosummary/meshed.dag.html.md#meshed.dag.dag_to_code)(dag)                                 | Convert a DAG to code.                                                                                                                                                                                         |
| [`dflt_debugger_feedback`](_autosummary/meshed.dag.html.md#meshed.dag.dflt_debugger_feedback)(func_node, scope, ...)    | Print the step number, func node and scope, then return `output` unchanged (default feedback of `DAG.debugger`).                                                                                               |
| [`find_first_free_name`](_autosummary/meshed.dag.html.md#meshed.dag.find_first_free_name)(prefix[, ...])              | Return `prefix` if not in `exclude_names`, else the first free `prefix__<i>` with `i` counting up from `start_at`.                                                                                             |
| [`funcnodes_from_pairs`](_autosummary/meshed.dag.html.md#meshed.dag.funcnodes_from_pairs)(pairs)                      | Make one mock func node per `(arg, out)` pair (see `mk_mock_funcnode`).                                                                                                                                        |
| [`hook_up`](_autosummary/meshed.dag.html.md#meshed.dag.hook_up)(func, variables[, output_name])          | Source inputs and write outputs to given variables mapping.                                                                                                                                                    |
| [`mk_func_name`](_autosummary/meshed.dag.html.md#meshed.dag.mk_func_name)(func[, exclude_names])              | Derive a name for `func` (its `__name__`, a generated lambda name, or the wrapped function's name for a `partial`) that is not in `exclude_names`.                                                             |
| [`mk_list_names_unique`](_autosummary/meshed.dag.html.md#meshed.dag.mk_list_names_unique)(nodes[, exclude_names])     | List the `.name` of each node, suffixing repeats (and names in `exclude_names`) with `__<i>` so all are distinct.                                                                                              |
| [`mk_mock_funcnode`](_autosummary/meshed.dag.html.md#meshed.dag.mk_mock_funcnode)(arg, out)                       | Make a `FuncNode` whose no-op function takes the single parameter `arg` and writes to `out`, named `_mock_<arg>_<out>`.                                                                                        |
| [`mk_nodes_names_unique`](_autosummary/meshed.dag.html.md#meshed.dag.mk_nodes_names_unique)(nodes)                     | Set each node's `.name` in place to the unique names of `mk_list_names_unique` and return `nodes`.                                                                                                             |
| [`modified_func_node`](_autosummary/meshed.dag.html.md#meshed.dag.modified_func_node)(func_node, \*\*modifications) | Make a new `FuncNode` from `func_node` with some of `func`, `name`, `bind` and `out` replaced by `modifications`.                                                                                              |
| [`named_partial`](_autosummary/meshed.dag.html.md#meshed.dag.named_partial)(func, \*args[, \_\_name_\_])       | functools.partial, but with a \_\_name_\_                                                                                                                                                                      |
| [`order_subset_from_list`](_autosummary/meshed.dag.html.md#meshed.dag.order_subset_from_list)(items, sublist)           | Sort `sublist` by the position its elements have in `items`.                                                                                                                                                   |
| [`parametrized_dag_factory`](_autosummary/meshed.dag.html.md#meshed.dag.parametrized_dag_factory)(dag, param_var_nodes)   | Constructs a factory for sub-DAGs derived from the input DAG, with values of specific 'parameter' variable nodes precomputed and fixed.                                                                        |
| [`partialized_funcnodes`](_autosummary/meshed.dag.html.md#meshed.dag.partialized_funcnodes)(func_nodes, ...)           | Yield the func nodes, replacing the function of any node whose parameters include a `keyword_defaults` name with a partial where those parameters are defaulted and moved last; other nodes are yielded as is. |
| [`print_dag_string`](_autosummary/meshed.dag.html.md#meshed.dag.print_dag_string)(dag[, bind_info])               | Print `dag.synopsis_string(bind_info)`; the default shows an input as `param=var` only where the two names differ.                                                                                             |
| `rename_nodes`([func_nodes, renamer])                                                             | Renames variables and functions of a `DAG` or iterable of `FuncNodes`.                                                                                                                                         |
| [`reorder_on_constraints`](_autosummary/meshed.dag.html.md#meshed.dag.reorder_on_constraints)(funcnodes, outs)          | Topologically sort `funcnodes` after appending (in place) mock nodes that chain each `outs` element to the next, print the order, and return `(func_nodes, var_nodes)` without the mock nodes.                 |

### Classes

| [`DAG`](_autosummary/meshed.dag.html.md#meshed.dag.DAG)([func_nodes, cache_last_scope, ...])   | A callable graph of functions: root variables in, leaf variables out.   |
|---------------------------------------------------------------------------------------------|-------------------------------------------------------------------------|

### *class* meshed.dag.DAG(func_nodes=(), cache_last_scope=True, parameter_merge=functools.partial(<function parameter_merger>, same_kind=True, same_default=True, same_annotation=True), new_scope=<class 'dict'>, name=None, extract_output_from_scope=<function extract_values>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A callable graph of functions: root variables in, leaf variables out.

```pycon
>>> from meshed.dag import DAG, Sig
>>>
>>> def this(a, b=1):
...     return a + b
>>> def that(x, b=1):
...     return x * b
>>> def combine(this, that):
...     return (this, that)
>>>
>>> dag = DAG((this, that, combine))
>>> print(dag.synopsis_string())
a,b -> this_ -> this
x,b -> that_ -> that
this,that -> combine_ -> combine
```

But what does it do?

It’s a callable, with a signature:

```pycon
>>> Sig(dag)
<Sig (a, x, b=1)>
```

And when you call it, it executes the dag from the root values you give it and
returns the leaf output values.

```pycon
>>> dag(1, 2, 3)  # (a+b,x*b) == (1+3,2*3) == (4, 6)
(4, 6)
>>> dag(1, 2)  # (a+b,x*b) == (1+1,2*1) == (2, 2)
(2, 2)
```

The above DAG was created straight from the functions, using only the names of the
functions and their arguments to define how to hook the network up.

But if you didn’t write those functions specifically for that purpose, or you want
to use someone else’s functions, we got you covered.

You can define the name of the node (the `name` argument), the name of the output
(the `out` argument) and a mapping from the function’s arguments names to
“network names” (through the `bind` argument).
The edges of the DAG are defined by matching `out` TO `bind`.

#### add_edge(from_node, to_node, to_param=None)

Add an e

* **Parameters:**
  * **from_node**
  * **to_node**
  * **to_param**
* **Returns:**
  A new DAG with the edge added

```pycon
>>> def f(a, b): return a + b
>>> def g(c, d=1): return c * d
>>> def h(x, y=1): return x ** y
>>>
>>> three_funcs = DAG([f, g, h])
>>> assert (
...     three_funcs(x=1, c=2, a=3, b=4)
...     == (7, 2, 1)
...     == (f(a=3, b=4), g(c=2), h(x=1))
...     == (3 + 4, 2*1, 1** 1)
... )
>>> print(three_funcs.synopsis_string())
a,b -> f_ -> f
c,d -> g_ -> g
x,y -> h_ -> h
>>> hg = three_funcs.add_edge('h', 'g')
>>> assert (
...     hg(a=3, b=4, x=1)
...     == (7, 1)
...     == (f(a=3, b=4), g(c=h(x=1)))
...     == (3 + 4, 1 * (1 ** 1))
... )
>>> print(hg.synopsis_string())
a,b -> f_ -> f
x,y -> h_ -> h
h,d -> g_ -> g
>>>
>>> fhg = three_funcs.add_edge('h', 'g').add_edge('f', 'h')
>>> assert (
...     fhg(a=3, b=4)
...     == 7
...     == g(h(f(3, 4)))
...     == ((3 + 4) * 1) ** 1
... )
>>> print(fhg.synopsis_string())
a,b -> f_ -> f
f,y -> h_ -> h
h,d -> g_ -> g
```

The from and to nodes can be expressed by the `FuncNode` `name` (identifier)
or `out`, or even the function itself if it’s used only once in the `DAG`.

```pycon
>>> fhg = three_funcs.add_edge(h, 'g').add_edge('f_', 'h')
>>> assert fhg(a=3, b=4) == 7
```

By default, the edge will be added from `from_node.out` to the first
parameter of the function of `to_node`.
But if you want otherwise, you can specify the parameter the edge should be
connected to.
For example, see below how we connect the outputs of `g` and `h` to the
parameters `a` and `b` of `f` respectively:

```pycon
>>> f_of_g_and_h = (
...     DAG([f, g, h])
...     .add_edge(g, f, to_param='a')
...     .add_edge(h, f, 'b')
... )
>>> assert (
...     f_of_g_and_h(x=2, c=3, y=2, d=2)
...     == 10
...     == f(g(c=3, d=2), h(x=2, y=2))
...     == 3 * 2 + 2 ** 2
... )
>>>
>>> print(f_of_g_and_h.synopsis_string())
c,d -> g_ -> g
x,y -> h_ -> h
g,h -> f_ -> f
```

See Also `DAG.add_edges` to add multiple edges at once

#### add_edges(edges)

Adds multiple edges by applying `DAG.add_edge` multiple times.

* **Parameters:**
  **edges** – An iterable of `(from_node, to_node)` pairs or
  `(from_node, to_node, param)` triples.
* **Returns:**
  A new dag with the said edges added.

```pycon
>>> def f(a, b): return a + b
>>> def g(c, d=1): return c * d
>>> def h(x, y=1): return x ** y
>>> fhg = DAG([f, g, h]).add_edges([(h, 'g'), ('f_', 'h')])
>>> assert fhg(a=3, b=4) == 7
```

#### bindings_cleaner()

Make func node names unique and rewrite bind values that name a func node into
that node’s `out` (called at the end of `__post_init__`).

#### call_on_scope(scope=None)

Calls the func_nodes using scope (a dict or MutableMapping) both to
source it’s arguments and write it’s results.

#### NOTE
This method is only meant to be used as a backend to \_\_call_\_, not as
an actual interface method. Additional control/constraints on read and writes
can be implemented by providing a custom scope for that. For example, one could
log read and/or writes to specific keys, or disallow overwriting to an existing
key (useful for pipeline sanity), etc.

#### call_on_scope_iteratively(scope=None)

Calls the `func_nodes` using scope (a dict or MutableMapping) both to
source it’s arguments and write it’s results.

Use this function to control each func_node call step iteratively
(through a generator)

#### ch_funcs(ch_func_node_func=<function ch_func_node_func>, /, \*\*func_mapping)

Change some of the functions in the DAG.
More preciseluy get a copy of the DAG where in some of the functions have
changed.

* **Parameters:**
  **name_and_func** – `name=func` pairs where `name` is the
  `FuncNode.name` of the func nodes you want to change and func is the
  function you want to change it by.
* **Return type:**
  [`DAG`](_autosummary/meshed.dag.html.md#meshed.dag.DAG)
* **Returns:**
  A new DAG with the different functions.

```pycon
>>> from meshed import FuncNode, DAG
>>> from i2 import Sig
>>>
>>> def f(a, b):
...     return a + b
...
>>>
>>> def g(a_plus_b, x):
...     return a_plus_b * x
...
>>> f_node = FuncNode(func=f, out='a_plus_b')
>>> g_node = FuncNode(func=g, bind={'x': 'b'})
>>> d = DAG((f_node, g_node))
>>> print(d.synopsis_string())
a,b -> f -> a_plus_b
b,a_plus_b -> g_ -> g
>>> d(2, 3)  # (2 + 3) * 3 == 5 * 3
15
>>> dd = d.ch_funcs(f=lambda a, b: a - b)
>>> dd(2, 3)  # (2 - 3) * 3 == -1 * 3
-3
```

You can reference the `FuncNode` you want to change through its `.name` or
`.out` attribute (both are unique to this `FuncNode` in a `DAG`).

```pycon
>>> from i2 import Sig
>>>
>>> dag = DAG([
...     FuncNode(lambda a, b: a + b, name='f'),
...     FuncNode(lambda y=1, z=2: y * z, name='g', bind={'z': 'f'})
... ])
>>>
>>> Sig(dag)
<Sig (a, b, f=2, y=1)>
>>>
>>> dag.ch_funcs(g=lambda y=1, z=2: y / z)
DAG(func_nodes=[FuncNode(a,b -> f -> _f), FuncNode(z=_f,y -> g -> _g)], name=None)
```

But if you change the signature, even slightly you get an error.

Here we didn’t include the defaults:

```pycon
>>> dag.ch_funcs(g=lambda y, z: y / z)
Traceback (most recent call last):
  ...
ValueError: You can only change the func of a FuncNode with a another func if the signatures match.
  ...
```

Here we include defaults, but `z`’s is different:

```pycon
>>> dag.ch_funcs(g=lambda y=1, z=200: y / z)
Traceback (most recent call last):
  ...
ValueError: You can only change the func of a FuncNode with a another func if the signatures match.
  ...
```

Here the defaults are exactly the same, but the order of parameters is
different:

```pycon
>>> dag.ch_funcs(g=lambda z=2, y=1: y / z)
Traceback (most recent call last):
  ...
ValueError: You can only change the func of a FuncNode with a another func if the signatures match.
  ...
```

This validation of the functions controlled by the `func_comparator`
argument. By default this is the `compare_signatures` which compares the
signatures of the functions in the strictest way possible.
The is the right choice for a default since it will get you out of trouble
down the line.

But it’s also annoying in many situations, and in those cases you should
specify the `func_comparator` that makes sense for your context.

Since most of the time, you’ll want to compare functions solely based on
their signature, we provide a `compare_signatures` allows you to control the
signature comparison through a `signature_comparator` argument.

```pycon
>>> from meshed import compare_signatures
>>> from functools import partial
>>> on_names = lambda sig1, sig2: list(sig1.parameters) == list(sig2.parameters)
>>> same_names = partial(compare_signatures, signature_comparator=on_names)
>>> ch_fnode = partial(ch_func_node_func, func_comparator=same_names)
>>> d = dag.ch_funcs(ch_fnode, g=lambda y, z: y / z);
>>> Sig(d)
<Sig (a, b, y)>
>>> d(2, 3, 4)
0.8
```

And this one works too:

```pycon
>>> d = dag.ch_funcs(ch_fnode, g=lambda y=1, z=200: y / z);
```

But our `same_names` function compared names including their order.
If we want a function with the signature `(z=2, y=1)` to be able to be
“injected” we’ll need a different comparator:

```pycon
>>> _names = lambda sig1, sig2: set(sig1.parameters) == set(sig2.parameters)
>>> same_set_of_names = partial(
...     compare_signatures,
...     signature_comparator=(
...         lambda sig1, sig2: set(sig1.parameters) == set(sig2.parameters)
...     )
... )
>>> ch_fnode2 = partial(ch_func_node_func, func_comparator=same_set_of_names)
>>> d = dag.ch_funcs(ch_fnode2, g=lambda z=2, y=1: y / z);
```

#### copy(renamer=<function numbered_suffix_renamer>)

Make a new `DAG` from renamed copies of the func nodes (see `ch_names` for what `renamer` may be).

With the default renamer every variable and function node gets a `_1`
suffix (or an incremented one):

```pycon
>>> def f(a, b):
...     return a + b
>>> def g(f, c):
...     return f * c
>>> dag = DAG([f, g])
>>> print(dag.copy().synopsis_string())
a_1,b_1 -> f__1 -> f_1
f_1,c_1 -> g__1 -> g_1
```

#### debugger(feedback=<function dflt_debugger_feedback>)

Utility to debug DAGs by computing each step sequentially, with feedback.

* **Parameters:**
  **feedback** ([`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)) – A callable that defines what feedback is given, usually used to
  print/log some information and output some information for every step.
  Must be a function with signature `(func_node, scope, output, step)` or
  a subset thereof.
* **Returns:**

```pycon
>>> from inspect import signature
>>>
>>> def f(a, b):
...     return a + b
...
>>> def g(c, d=4):
...     return c * d
...
>>> def h(f, g):
...     return g - f
...
>>> dag2 = DAG([f, g, h], name='arithmetic')
>>> dag2
DAG(func_nodes=[FuncNode(a,b -> f_ -> f), FuncNode(c,d -> g_ -> g), FuncNode(f,g -> h_ -> h)], name='arithmetic')
>>> str(signature(dag2))
'(a, b, c, d=4)'
>>> dag2(1,2,3)
9
>>>
>>> debugger = dag2.debugger()
>>> str(signature(debugger))
'(a, b, c, d=4)'
>>> d = debugger(1,2,3)
>>> next(d)
0 --------------------------------------------------------------
    func_node=FuncNode(a,b -> f_ -> f)
    scope={'a': 1, 'b': 2, 'c': 3, 'd': 4, 'f': 3}
3
>>> next(d)
1 --------------------------------------------------------------
    func_node=FuncNode(c,d -> g_ -> g)
    scope={'a': 1, 'b': 2, 'c': 3, 'd': 4, 'f': 3, 'g': 12}
12
```

… and so on. You can also choose to run every step all at once, collecting
the `feedback` outputs of each step in a list, like this:

```pycon
>>> feedback_outputs = list(debugger(1,2,3))
0 --------------------------------------------------------------
    func_node=FuncNode(a,b -> f_ -> f)
    scope={'a': 1, 'b': 2, 'c': 3, 'd': 4, 'f': 3}
1 --------------------------------------------------------------
    func_node=FuncNode(c,d -> g_ -> g)
    scope={'a': 1, 'b': 2, 'c': 3, 'd': 4, 'f': 3, 'g': 12}
2 --------------------------------------------------------------
    func_node=FuncNode(f,g -> h_ -> h)
    scope={'a': 1, 'b': 2, 'c': 3, 'd': 4, 'f': 3, 'g': 12, 'h': 9}
```

#### dot_digraph(start_lines=(), , end_lines=(), vnode_shape='none', fnode_shape='box', func_display=True)

Make lines for dot (graphviz) specification of DAG

```pycon
>>> def add(a, b=1): return a + b
>>> def mult(x, y=3): return x * y
>>> def exp(mult, a): return mult ** a
>>> func_nodes = [
...     FuncNode(add, out='x'), FuncNode(mult, name='the_product'), FuncNode(exp)
... ]
>>> lines = list(DAG(func_nodes).dot_digraph_body())
>>> lines[0]
'x [label="x" shape="none"]'
```

#### dot_digraph_ascii(start_lines=(), , end_lines=(), vnode_shape='none', fnode_shape='box', func_display=True)

Make lines for dot (graphviz) specification of DAG

```pycon
>>> def add(a, b=1): return a + b
>>> def mult(x, y=3): return x * y
>>> def exp(mult, a): return mult ** a
>>> func_nodes = [
...     FuncNode(add, out='x'), FuncNode(mult, name='the_product'), FuncNode(exp)
... ]
>>> lines = list(DAG(func_nodes).dot_digraph_body())
>>> lines[0]
'x [label="x" shape="none"]'
```

#### dot_digraph_body(start_lines=(), , end_lines=(), vnode_shape='none', fnode_shape='box', func_display=True)

Make lines for dot (graphviz) specification of DAG

```pycon
>>> def add(a, b=1): return a + b
>>> def mult(x, y=3): return x * y
>>> def exp(mult, a): return mult ** a
>>> func_nodes = [
...     FuncNode(add, out='x'), FuncNode(mult, name='the_product'), FuncNode(exp)
... ]
>>> lines = list(DAG(func_nodes).dot_digraph_body())
>>> lines[0]
'x [label="x" shape="none"]'
```

#### extract_output_from_scope(keys)

Extract values from dict `d`, returning them:

- as a tuple if len(keys) > 1
- a single value if len(keys) == 1
- None if not

This is used as the default extractor in DAG

```pycon
>>> extract_values({'a': 1, 'b': 2, 'c': 3}, ['a', 'c'])
(1, 3)
```

Order matters!

```pycon
>>> extract_values({'a': 1, 'b': 2, 'c': 3}, ['c', 'a'])
(3, 1)
```

#### find_func_node(node, default=None)

Return the `FuncNode` that `node` refers to, or `default` when nothing matches.

A `FuncNode` is returned as is; anything else is looked up as a node name,
an `out`, or a function unique in the DAG.

```pycon
>>> def f(a, b):
...     return a + b
>>> dag = DAG([f])
>>> dag.find_func_node('f')  # by out
FuncNode(a,b -> f_ -> f)
>>> dag.find_func_node('f_')  # by name
FuncNode(a,b -> f_ -> f)
>>> dag.find_func_node(f)  # by function
FuncNode(a,b -> f_ -> f)
>>> dag.find_func_node('nope') is None
True
```

#### find_funcs(filt=None)

Yield the `.func` of the func nodes for which `filt` is true (all of them
when `filt` is `None`).

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)]

#### *classmethod* from_funcs(\*funcs, \*\*named_funcs)

* **Parameters:**
  * **funcs**
  * **named_funcs**
* **Returns:**

```pycon
>>> dag = DAG.from_funcs(
...     lambda a: a * 2,
...     x=lambda: 10,
...     y=lambda x, _0: x + _0  # _0 refers to first arg (lambda a: a * 2)
... )
>>> print(dag.synopsis_string())
a -> _0_ -> _0
 -> x_ -> x
x,_0 -> y_ -> y
>>> dag(3)
16
```

#### get_node_matching(idx)

Return `idx` itself if it names a var node, else the `FuncNode` that `idx` (a node name, an `out`, or a function unique in the DAG) indexes.

A string matching no node raises `KeyError`; an `idx` that is neither a
string nor a callable raises `NotFound`.

#### *property* graph_ids

The dict representing the `{from_node: to_nodes}` graph.
Like `.graph`, but with node ids (names).

```pycon
>>> from meshed.dag import DAG
>>> def add(a, b=1): return a + b
>>> def mult(x, y=3): return x * y
>>> def exp(mult, a): return mult ** a
>>> assert DAG([add, mult, exp]).graph_ids == {
...     'a': ['add_', 'exp_'],
...     'b': ['add_'],
...     'add_': ['add'],
...     'x': ['mult_'],
...     'y': ['mult_'],
...     'mult_': ['mult'],
...     'mult': ['exp_'],
...     'exp_': ['exp']
... }
```

#### new_scope

alias of [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

#### parameter_merge(, same_name=True, same_kind=True, same_default=True, same_annotation=True)

Validates that all the params are exactly the same, returning the first if so.

This is used when hooking up functions that use the same parameters (i.e. arg
names). When the name of an argument is used more than once, which kind, default,
and annotation should be used in the interface of the DAG?

If they’re all the same, there’s no problem.

But if they’re not the same, we need to provide control on which to ignore.

```pycon
>>> from inspect import Parameter as P
>>> PK = P.POSITIONAL_OR_KEYWORD
>>> KO = P.KEYWORD_ONLY
>>> parameter_merger(P('a', PK), P('a', PK))
<Parameter "a">
>>> parameter_merger(P('a', PK), P('different_name', PK), same_name=False)
<Parameter "a">
>>> parameter_merger(P('a', PK), P('a', KO), same_kind=False)
<Parameter "a">
>>> parameter_merger(P('a', PK), P('a', PK,  default=42), same_default=False)
<Parameter "a">
>>> parameter_merger(P('a', PK, default=42), P('a', PK), same_default=False)
<Parameter "a=42">
>>> parameter_merger(P('a', PK, annotation=int), P('a', PK), same_annotation=False)
<Parameter "a: int">
```

#### *property* params_for_src

The `{src_name: list_of_params_using_that_src,...}` dictionary.
That is, a `dict` having lists of all `Parameter` objs that are used by a
`node.bind` source (value of `node.bind`) for each such source in the graph

For each `func_node`, `func_node.bind` gives us the
`{param: varnode_src_name}` specification that tells us where (key of scope)
to source the arguments of the `func_node.func` for each `param` of that
function.

What `params_for_src` is, is the corresponding inverse map.
The `{varnode_src_name: list_of_params}` gathered by scanning each
`func_node` of the DAG.

#### partial(\*positional_dflts, \_remove_bound_arguments=False, \_consider_defaulted_arguments_as_bound=False, \*\*keyword_dflts)

Get a curried version of the DAG.

Like `functools.partial`, but returns a DAG (not just a callable) and allows
you to remove bound arguments as well as roll in orphaned_nodes.

* **Parameters:**
  * **positional_dflts** – Bind arguments positionally
  * **keyword_dflts** – Bind arguments through their names
  * **\_remove_bound_arguments** – False – set to True if you don’t want bound
    arguments to show up in the signature.
  * **\_consider_defaulted_arguments_as_bound** – False – set to True if
    you want to also consider arguments that already had defaults as bound
    (and be removed).
* **Returns:**

```pycon
>>> def f(a, b):
...     return a + b
>>> def g(c, d=4):
...     return c * d
>>> def h(f, g):
...     return g - f
>>> dag = DAG([f, g, h])
>>> from inspect import signature
>>> str(signature(dag))
'(a, b, c, d=4)'
>>> dag(1, 2, 3, 4)  # == (3 * 4) - (1 + 2) == 12 - 3 == 9
9
>>> dag(c=3, a=1, b=2, d=4)  # same as above
9
```

```pycon
>>> new_dag = dag.partial(c=3)
>>> isinstance(new_dag, DAG)  # it's a dag (not just a partialized callable!)
True
>>> str(signature(new_dag))
'(a, b, c=3, d=4)'
>>> new_dag(1, 2)  # same as dag(c=3, a=1, b=2, d=4), so:
9
```

#### process_item(item)

Resolve a `slice` of node specifications into `(input_nodes, output_nodes)` lists, as used by `__getitem__`.

Each side of the slice may be `None` (all var nodes), a space-separated
string of names, a callable, or an iterable of names and callables; names are
resolved with `get_node_matching`. An `item` that is not a `slice` fails
an assertion, and a side of none of these forms raises `ValidationError`.

#### *property* sig

The DAG’s `__signature__` (an `i2.Sig`); assigning to it replaces
`__signature__`.

#### src_name_params(src_names=None)

Generate Parameter instances that are needed to compute `src_names`

#### synopsis_string(bind_info='var_nodes')

Join the `synopsis_string` of every func node, one per line in topological
order; `bind_info` controls how inputs are shown (see
`FuncNode.synopsis_string`).

#### to_code()

Render the DAG as the source of a function named after the DAG, one `out =
node_name(args)` line per func node (see `dag_to_code`).

### meshed.dag.arg_names(func, func_name, exclude_names=())

List the parameter names of `func`, replacing any found in `exclude_names` with
a free `<func_name>__<name>` variant.

### meshed.dag.attribute_vals(objs, attrs, egress=None)

Extract attributes from an iterable of objects

```pycon
>>> list(attribute_vals([print, map], attrs=['__name__', '__module__']))
[('print', 'builtins'), ('map', 'builtins')]
```

### meshed.dag.call_func(func, kwargs)

Re-key `kwargs` by each key’s `__name__` and pass the resulting dict to
`Sig(func).source_kwargs`.

### meshed.dag.change_value_on_cond(d, cond, func)

Replace, in place, each value `v` of `d` where `cond(k, v)` holds with
`func(v)`, and return `d`.

### meshed.dag.dag_to_code(dag)

Convert a DAG to code.

```pycon
>>> from meshed import code_to_dag
>>> @code_to_dag
... def dag():
...     a = func1(x, y)
...     b = func2(a, z)
...     c = func3(a, w=b)
>>>
```

Original DAG:

```pycon
>>> print(dag.synopsis_string())
x,y -> func1 -> a
a,z -> func2 -> b
a,b -> func3 -> c
```

Generated code using dag_to_code function:

```pycon
>>> code = dag_to_code(dag)
>>> print(code)
def dag():
    a = func1(x, y)
    b = func2(a, z)
    c = func3(a, w=b)
```

Test round-trip conversion:

```pycon
>>> dag2 = code_to_dag(code)
>>> print(dag2.synopsis_string())
x,y -> func1 -> a
a,z -> func2 -> b
a,b -> func3 -> c

>>> # Verify they're equivalent:
>>> dag.synopsis_string() == dag2.synopsis_string()
True
```

### meshed.dag.dflt_debugger_feedback(func_node, scope, output, step)

Print the step number, func node and scope, then return `output` unchanged
(default feedback of `DAG.debugger`).

### meshed.dag.find_first_free_name(prefix, exclude_names=(), start_at=2)

Return `prefix` if not in `exclude_names`, else the first free `prefix__<i>`
with `i` counting up from `start_at`.

### meshed.dag.funcnodes_from_pairs(pairs)

Make one mock func node per `(arg, out)` pair (see `mk_mock_funcnode`).

### meshed.dag.hook_up(func, variables, output_name=None)

Source inputs and write outputs to given variables mapping.

Returns inputless and outputless function that will, when called,
get relevant inputs from the provided variables mapping and write it’s
output there as well.

* **Parameters:**
  * **variables** ([`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)) – The MutableMapping (like… a dict) where the function
    should both read it’s input and write it’s output.
  * **output_name** – The key of the variables mapping that should be used
    to write the output of the function
* **Returns:**
  A function

```pycon
>>> def formula1(w, /, x: float, y=1, *, z: int = 1):
...     return ((w + x) * y) ** z
```

```pycon
>>> d = {}
>>> f = hook_up(formula1, d)
>>> # NOTE: update d, not d = dict(...), which would make a DIFFERENT d
>>> d.update(w=2, x=3, y=4)  # not d = dict(w=2, x=3, y=4), which would
>>> f()
```

Note that there’s no output. The output is in d

```pycon
>>> d
{'w': 2, 'x': 3, 'y': 4, 'formula1': 20}
```

Again…

```pycon
>>> d.clear()
>>> d.update(w=1, x=2, y=3)
>>> f()
>>> d['formula1']
9
```

### meshed.dag.mk_func_name(func, exclude_names=())

Derive a name for `func` (its `__name__`, a generated lambda name, or the wrapped function’s name for a `partial`) that is not in `exclude_names`.

A `func` with no `__name__` that is not a `partial` raises `NameValidationError`.

### meshed.dag.mk_list_names_unique(nodes, exclude_names=())

List the `.name` of each node, suffixing repeats (and names in `exclude_names`)
with `__<i>` so all are distinct.

### meshed.dag.mk_mock_funcnode(arg, out)

Make a `FuncNode` whose no-op function takes the single parameter `arg` and
writes to `out`, named `_mock_<arg>_<out>`.

### meshed.dag.mk_nodes_names_unique(nodes)

Set each node’s `.name` in place to the unique names of `mk_list_names_unique`
and return `nodes`.

### meshed.dag.modified_func_node(func_node, \*\*modifications)

Make a new `FuncNode` from `func_node` with some of `func`, `name`, `bind`
and `out` replaced by `modifications`.

* **Return type:**
  [`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)

### meshed.dag.named_partial(func, \*args, \_\_name_\_=None, \*\*keywords)

functools.partial, but with a \_\_name_\_

```pycon
>>> f = named_partial(print, sep='\n')
>>> f.__name__
'print'
```

```pycon
>>> f = named_partial(print, sep='\n', __name__='now_partial_has_a_name')
>>> f.__name__
'now_partial_has_a_name'
```

### meshed.dag.names_and_outs(objs, \*, attrs=('name', 'out'), egress=<class 'itertools.chain'>)

Extract attributes from an iterable of objects

```pycon
>>> list(attribute_vals([print, map], attrs=['__name__', '__module__']))
[('print', 'builtins'), ('map', 'builtins')]
```

### meshed.dag.order_subset_from_list(items, sublist)

Sort `sublist` by the position its elements have in `items`.

### meshed.dag.parametrized_dag_factory(dag, param_var_nodes)

Constructs a factory for sub-DAGs derived from the input DAG, with values of
specific ‘parameter’ variable nodes precomputed and fixed. These precomputed nodes,
and their ancestor nodes (unless required elsewhere), are omitted from the sub-DAG.

The factory function produced by this operation requires arguments corresponding to
the ancestor nodes of the parameter variable nodes. These arguments are used to
compute the values of the parameter nodes.

This function reflects the typical structure of a class in object-oriented
programming, where initialization arguments are used to set certain fixed values
(attributes), which are then leveraged in subsequent methods.

```pycon
>>> import i2
>>> from meshed import code_to_dag
>>> @code_to_dag
... def testdag():
...     a = criss(aa, aaa)
...     b = cross(aa, bb)
...     c = apple(a, b)
...     d = sauce(a, b)
...     e = applesauce(c, d)
>>>
>>> dag_factory = parametrized_dag_factory(testdag, 'a')
>>> print(f"{i2.Sig(dag_factory)}")
(aa, aaa)
>>> d = dag_factory(aa=1, aaa=2)
>>> print(f"{i2.Sig(d)}")
(b)
>>> d(b='bananna')
'applesauce(c=apple(a=criss(aa=1, aaa=2), b=bananna), d=sauce(a=criss(aa=1, aaa=2), b=bananna))'
```

### meshed.dag.partialized_funcnodes(func_nodes, \*\*keyword_defaults)

Yield the func nodes, replacing the function of any node whose parameters include a
`keyword_defaults` name with a partial where those parameters are defaulted and
moved last; other nodes are yielded as is.

### meshed.dag.print_dag_string(dag, bind_info='hybrid')

Print `dag.synopsis_string(bind_info)`; the default shows an input as
`param=var` only where the two names differ.

### meshed.dag.reorder_on_constraints(funcnodes, outs)

Topologically sort `funcnodes` after appending (in place) mock nodes that chain
each `outs` element to the next, print the order, and return `(func_nodes,
var_nodes)` without the mock nodes.


# _autosummary/meshed.examples.html.md

# meshed.examples

Examples of using meshed.

### Modules

| [`online_marketing`](_autosummary/meshed.examples.online_marketing.html.md#module-meshed.examples.online_marketing)           | Online marketing funnel: impressions and clicks to sales and profit.                    |
|---------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|
| [`price_elasticity`](_autosummary/meshed.examples.price_elasticity.html.md#module-meshed.examples.price_elasticity)           | Price elasticity relates price to revenue, expense, and profit.                         |
| [`vaccine_vs_no_vaccine`](_autosummary/meshed.examples.vaccine_vs_no_vaccine.html.md#module-meshed.examples.vaccine_vs_no_vaccine) | Simple model relating vaccination to death toll, involving exposure and infection rate. |


# _autosummary/meshed.examples.online_marketing.html.md

# meshed.examples.online_marketing

Online marketing funnel: impressions and clicks to sales and profit.

```text
                           ┌──────────────────────┐
                           │ click_per_impression │
                           └──────────────────────┘
                             │
                             ▼
   ┌─────────────────┐     ┌──────────────────────┐
   │   impressions   │ ──▶ │        clicks        │
   └─────────────────┘     └──────────────────────┘
┌────┘                       │
│                            ▼
│  ┌─────────────────┐     ┌──────────────────────┐
│  │ sales_per_click │ ──▶ │        sales         │
│  └─────────────────┘     └──────────────────────┘
│                            │
│                            ▼
│                          ┌──────────────────────┐     ┌──────────────────┐
│                          │       revenue        │ ◀── │ revenue_per_sale │
│                          └──────────────────────┘     └──────────────────┘
│                            │
│                            ▼
│                          ┌──────────────────────┐
│                          │        profit        │ ◀┐
│                          └──────────────────────┘  │
│                          ┌──────────────────────┐  │
│                          │ cost_per_impression  │  │
│                          └──────────────────────┘  │
│                            │                       │
│                            ▼                       │
│                          ┌──────────────────────┐  │
└────────────────────────▶ │         cost         │ ─┘
                           └──────────────────────┘
```

### Functions

| `clicks`(impressions, click_per_impression)   |    |
|-----------------------------------------------|----|
| `cost`(impressions, cost_per_impression)      |    |
| `profit`(revenue, cost)                       |    |
| `revenue`(sales, revenue_per_sale)            |    |
| `sales`(clicks, sales_per_click)              |    |


# _autosummary/meshed.examples.price_elasticity.html.md

# meshed.examples.price_elasticity

Price elasticity relates price to revenue, expense, and profit.

```text
                   ┌─────────┐
                   │  base   │
                   └─────────┘
                     │
                     │
                     ▼
┌────────────┐     ┌─────────────────────────┐
│ elasticity │ ──▶ │          sold           │ ─┐
└────────────┘     └─────────────────────────┘  │
                     │               ▲          │
                     │               │          │
                     ▼               │          │
┌────────────┐     ┌─────────┐     ┌─────────┐  │
│    cost    │ ──▶ │ expense │     │  price  │  │
└────────────┘     └─────────┘     └─────────┘  │
                     │               │          │
                     │               │          │
                     ▼               ▼          │
                   ┌─────────┐     ┌─────────┐  │
                   │ profit  │ ◀── │ revenue │ ◀┘
                   └─────────┘     └─────────┘
```

### Functions

| `expense`(cost, sold)             |    |
|-----------------------------------|----|
| `profit`(revenue, expense)        |    |
| `revenue`(price, sold)            |    |
| `sold`(price, elasticity[, base]) |    |


# _autosummary/meshed.examples.vaccine_vs_no_vaccine.html.md

# meshed.examples.vaccine_vs_no_vaccine

Simple model relating vaccination to death toll, involving exposure and infection rate.

```text
                        ┌──────────────────────┐
                        │   death_vax_factor   │
                        └──────────────────────┘
                          │
                          ▼
┌─────────────────┐     ┌──────────────────────────────────┐
│ die_if_infected │ ──▶ │               die                │
└─────────────────┘     └──────────────────────────────────┘
                          │                       ▲    ▲
                          ▼                       │    │
┌─────────────────┐     ┌──────────────────────┐  │  ┌─────┐
│   population    │ ──▶ │      death_toll      │  │  │ vax │
└─────────────────┘     └──────────────────────┘  │  └─────┘
                                                  │    │
                        ┌──────────────────────┐  │    │
                        │ infection_vax_factor │  │    │
                        └──────────────────────┘  │    │
                          │                       │    │
                          ▼                       │    │
                        ┌──────────────────────┐  │    │
                     ┌▶ │       infected       │ ─┘    │
                     │  └──────────────────────┘       │
                     │    ▲                            │
                     │    └────────────────────────────┘
                     │  ┌──────────────────────┐
                     │  │       exposed        │
                     │  └──────────────────────┘
                     │    │
                     │    ▼
                     │  ┌──────────────────────┐
                     └─ │          r           │
                        └──────────────────────┘
                          ▲
                          │
                        ┌──────────────────────┐
                        │   infect_if_expose   │
                        └──────────────────────┘
```

### Functions

| `death_toll`(die[, population])              |    |
|----------------------------------------------|----|
| `die`(infected[, die_if_infected, vax, ...]) |    |
| `infected`([r, vax, infection_vax_factor])   |    |
| `r`([exposed, infect_if_expose])             |    |


# _autosummary/meshed.ext.gk.html.md

# meshed.ext.gk

This module is meant to explore a different representation of a computation graph
and a different way of executing it.
It is based on Yahoo’s graphkit library. The library hasn’t been maintained since 2018,
so vendored and modified here).
One of the main differences is that we got rid of the networkx dependency,
which was used to represent the computation graph.
Instead, this module uses meshed’s itools library to represent the computation graph.

### Yahoo’s graphkit library is under Apache License 2.0:

### Copyright 2016, Yahoo Inc.

### Licensed under the terms of the Apache License, Version 2.0. See the LICENSE file associated with the project for terms.

#### NOTE
This module is only meant to an exploratory “extension”. It is not planned to be maintained.

### Functions

| [`get_data_node`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.get_data_node)(name, graph)           | Gets a data node from a graph using its name                                                              |
|---------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|
| [`ready_to_delete_data_node`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.ready_to_delete_data_node)(name, ...) | Determines if a DataPlaceholderNode is ready to be deleted from the cache.                                |
| [`ready_to_schedule_operation`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.ready_to_schedule_operation)(op, ...) | Determines if a Operation is ready to be scheduled for execution based on what has already been executed. |

### Classes

| [`Data`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.Data)(\*\*kwargs)                           | This wraps any data that is consumed or produced by a Operation.                                                                                  |
|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------|
| [`DataPlaceholderNode`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.DataPlaceholderNode)                        | A node for the Network graph that describes the name of a Data instance produced or required by a layer.                                          |
| [`DeleteInstruction`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.DeleteInstruction)                          | An instruction for the compiled list of evaluation steps to free or delete a Data instance from the Network's cache after it is no longer needed. |
| [`FunctionalOperation`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.FunctionalOperation)(\*\*kwargs)            |                                                                                                                                                   |
| [`Network`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.Network)(\*\*kwargs)                        | This is the main network implementation.                                                                                                          |
| [`NetworkOperation`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.NetworkOperation)(\*\*kwargs)               |                                                                                                                                                   |
| [`Operation`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.Operation)([name, needs, provides, params]) | This is an abstract class representing a data transformation.                                                                                     |
| [`compose`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.compose)([name, merge])                     | This is a simple class that's used to compose `operation` instances into a computation graph.                                                     |
| [`operation`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.operation)([fn])                            | This object represents an operation in a computation graph.                                                                                       |
| [`optional`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.optional)                                   | Input values in `needs` may be designated as optional using this modifier.                                                                        |

### *class* meshed.ext.gk.Data(\*\*kwargs)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

This wraps any data that is consumed or produced
by a Operation. This data should also know how to serialize
itself appropriately.
This class an “abstract” class that should be extended by
any class working with data in the HiC framework.

### *class* meshed.ext.gk.DataPlaceholderNode

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

A node for the Network graph that describes the name of a Data instance
produced or required by a layer.

### *class* meshed.ext.gk.DeleteInstruction

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

An instruction for the compiled list of evaluation steps to free or delete
a Data instance from the Network’s cache after it is no longer needed.

### *class* meshed.ext.gk.FunctionalOperation(\*\*kwargs)

Bases: [`Operation`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.Operation)

### *class* meshed.ext.gk.Network(\*\*kwargs)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

This is the main network implementation. The class contains all of the
code necessary to weave together operations into a directed-acyclic-graph (DAG)
and pass data through.

#### add_op(operation)

Adds the given operation and its data requirements to the network graph
based on the name of the operation, the names of the operation’s needs, and
the names of the data it provides.

* **Parameters:**
  **operation** ([*Operation*](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.Operation)) – Operation object to add.

#### compile()

Create a set of steps for evaluating layers
and freeing memory as necessary

#### compute(outputs, named_inputs, method=None)

Run the graph. Any inputs to the network must be passed in by name.

* **Parameters:**
  * **output** ([*list*](https://docs.python.org/3/builtins/stdtypes.html#list)) – The names of the data node you’d like to have returned
    once all necessary computations are complete.
    If you set this variable to `None`, all
    data nodes will be kept and returned at runtime.
  * **named_inputs** ([*dict*](https://docs.python.org/3/builtins/stdtypes.html#dict)) – A dict of key/value pairs where the keys
    represent the data nodes you want to populate,
    and the values are the concrete values you
    want to set for the data node.
* **Returns:**
  a dictionary of output data objects, keyed by name.

#### plot(filename=None, show=False)

Plot the graph.

params:

* **Parameters:**
  * **filename** ([*str*](https://docs.python.org/3/builtins/stdtypes.html#str)) – Write the output to a png, pdf, or graphviz dot file. The extension
    controls the output format.
  * **show** (*boolean*) – If this is set to True, use matplotlib to show the graph diagram
    (Default: False)
* **Returns:**
  An instance of the pydot graph

#### show_layers()

Shows info (name, needs, and provides) about all layers in this network.

### *class* meshed.ext.gk.NetworkOperation(\*\*kwargs)

Bases: [`Operation`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.Operation)

#### set_execution_method(method)

Determine how the network will be executed.

* **Parameters:**
  **method** – If “parallel”, execute graph operations concurrently
  using a threadpool.

### *class* meshed.ext.gk.Operation(name='None', needs=None, provides=None, params=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

This is an abstract class representing a data transformation. To use this,
please inherit from this class and customize the `.compute` method to your
specific application.

Names may be given to this layer and its inputs and outputs. This is
important when connecting layers and data in a Network object, as the
names are used to construct the graph.

* **Parameters:**
  * **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – The name the operation (e.g. conv1, conv2, etc..)
  * **needs** ([`list`](https://docs.python.org/3/builtins/stdtypes.html#list)) – Names of input data objects this layer requires.
  * **provides** ([`list`](https://docs.python.org/3/builtins/stdtypes.html#list)) – Names of output data objects this provides.
  * **params** ([`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)) – 

    A dict of key/value pairs representing parameters
    associated with your operation. These values will be
    accessible using the `.params` attribute of your object.

    NOTE:
    : It’s important that any values stored in this
      argument must be pickelable.

#### compute(inputs)

This method must be implemented to perform this layer’s feed-forward
computation on a given set of inputs.

* **Parameters:**
  **inputs** ([*list*](https://docs.python.org/3/builtins/stdtypes.html#list)) – A list of [`Data`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.Data) objects on which to run the layer’s
  feed-forward computation.
* **Returns list:**
  Should return a list of [`Data`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.Data) objects representing
  the results of running the feed-forward computation on
  `inputs`.

### *class* meshed.ext.gk.compose(name=None, merge=False)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

This is a simple class that’s used to compose `operation` instances into
a computation graph.

* **Parameters:**
  * **name** ([*str*](https://docs.python.org/3/builtins/stdtypes.html#str)) – A name for the graph being composed by this object.
  * **merge** ([*bool*](https://docs.python.org/3/builtins/functions.html#bool)) – If `True`, this compose object will attempt to merge together
    `operation` instances that represent entire computation graphs.
    Specifically, if one of the `operation` instances passed to this
    `compose` object is itself a graph operation created by an
    earlier use of `compose` the sub-operations in that graph are
    compared against other operations passed to this `compose`
    instance (as well as the sub-operations of other graphs passed to
    this `compose` instance).  If any two operations are the same
    (based on name), then that operation is computed only once, instead
    of multiple times (one for each time the operation appears).

### meshed.ext.gk.get_data_node(name, graph)

Gets a data node from a graph using its name

### *class* meshed.ext.gk.operation(fn=None, \*\*kwargs)

Bases: [`Operation`](_autosummary/meshed.ext.gk.html.md#meshed.ext.gk.Operation)

This object represents an operation in a computation graph.  Its
relationship to other operations in the graph is specified via its
`needs` and `provides` arguments.

* **Parameters:**
  * **fn** (*function*) – The function used by this operation.  This does not need to be
    specified when the operation object is instantiated and can instead
    be set via `__call__` later.
  * **name** ([*str*](https://docs.python.org/3/builtins/stdtypes.html#str)) – The name of the operation in the computation graph.
  * **needs** ([*list*](https://docs.python.org/3/builtins/stdtypes.html#list)) – Names of input data objects this operation requires.  These should
    correspond to the `args` of `fn`.
  * **provides** ([*list*](https://docs.python.org/3/builtins/stdtypes.html#list)) – Names of output data objects this operation provides.
  * **params** ([*dict*](https://docs.python.org/3/builtins/stdtypes.html#dict)) – A dict of key/value pairs representing constant parameters
    associated with your operation.  These can correspond to either
    `args` or `kwargs` of `fn`.

### *class* meshed.ext.gk.optional

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

Input values in `needs` may be designated as optional using this modifier.
If this modifier is applied to an input value, that value will be input to
the `operation` if it is available.  The function underlying the
`operation` should have a parameter with the same name as the input value
in `needs`, and the input value will be passed as a keyword argument if
it is available.

Here is an example of an operation that uses an optional argument:

```default
from graphkit import operation, compose
from graphkit.modifiers import optional

# Function that adds either two or three numbers.
def myadd(a, b, c=0):
    return a + b + c

# Designate c as an optional argument.
graph = compose('mygraph')(
    operator(name='myadd', needs=['a', 'b', optional('c')], provides='sum')(myadd)
)

# The graph works with and without 'c' provided as input.
assert graph({'a': 5, 'b': 2, 'c': 4})['sum'] == 11
assert graph({'a': 5, 'b': 2})['sum'] == 7
```

### meshed.ext.gk.ready_to_delete_data_node(name, has_executed, graph)

Determines if a DataPlaceholderNode is ready to be deleted from the
cache.

* **Parameters:**
  * **name** – The name of the data node to check
  * **has_executed** – A set containing all operations that have been executed so far
  * **graph** – The networkx graph containing the operations and data nodes
* **Returns:**
  A boolean indicating whether the data node can be deleted or not.

### meshed.ext.gk.ready_to_schedule_operation(op, has_executed, graph)

Determines if a Operation is ready to be scheduled for execution based on
what has already been executed.

* **Parameters:**
  * **op** – The Operation object to check
  * **has_executed** – A set containing all operations that have been executed so far
  * **graph** – The networkx graph containing the operations and data nodes
* **Returns:**
  A boolean indicating whether the operation may be scheduled for
  execution based on what has already been executed.


# _autosummary/meshed.ext.html.md

# meshed.ext

vendors

### Modules

| [`gk`](_autosummary/meshed.ext.gk.html.md#module-meshed.ext.gk)   | This module is meant to explore a different representation of a computation graph and a different way of executing it.   |
|----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|


# _autosummary/meshed.html.md

# meshed

`meshed` contains a set of tools that allow the developer to provide a collection
of python objects (think functions) and some policy of how these should be connected
and get an aggregate object that will use the underlying objects in some way.

If you want something concrete, think of the python objects to be functions,
and the aggregation policies to be things like “function composition” (pipelines)
or DAGs.
But the intent is to be able to get more general aggregations than those.

## Extras

`itools.py` contain tools that enable operations on graphs where graphs are represented
by an adjacency Mapping.

### Modules

| [`base`](_autosummary/meshed.base.html.md#module-meshed.base)               | Define `FuncNode`, the unit of computation that `meshed` assembles into DAGs.   |
|----------------------------------------------------------------------------------------|---------------------------------------------------------------------------------|
| [`caching`](_autosummary/meshed.caching.html.md#module-meshed.caching)         | Turn functions into cached properties of a class.                               |
| [`components`](_autosummary/meshed.components.html.md#module-meshed.components)   | Ready-made extraction components for meshed graphs.                             |
| [`composition`](_autosummary/meshed.composition.html.md#module-meshed.composition) | Specific use of FuncNode and DAG                                                |
| [`dag`](_autosummary/meshed.dag.html.md#module-meshed.dag)                 | Making DAGs                                                                     |
| [`examples`](_autosummary/meshed.examples.html.md#module-meshed.examples)       | Examples of using meshed.                                                       |
| [`ext`](_autosummary/meshed.ext.html.md#module-meshed.ext)                 | vendors                                                                         |
| [`itools`](_autosummary/meshed.itools.html.md#module-meshed.itools)           | Graph operations over adjacency mappings.                                       |
| [`makers`](_autosummary/meshed.makers.html.md#module-meshed.makers)           | Makers                                                                          |
| [`scrap`](_autosummary/meshed.scrap.html.md#module-meshed.scrap)             | For scrap only                                                                  |
| [`slabs`](_autosummary/meshed.slabs.html.md#module-meshed.slabs)             | Tools to generate slabs.                                                        |
| [`tools`](_autosummary/meshed.tools.html.md#module-meshed.tools)             | Tools to work with meshed                                                       |
| [`util`](_autosummary/meshed.util.html.md#module-meshed.util)               | Function-wrapping, naming, and small data helpers shared across `meshed`.       |
| [`viz`](_autosummary/meshed.viz.html.md#module-meshed.viz)                 | Visualization utilities for the meshed package.                                 |


# _autosummary/meshed.itools.html.md

# meshed.itools

Graph operations over adjacency mappings.

Here a graph `g` is any `Mapping` whose keys are nodes and whose values
are iterables of the nodes they point to (`g[src]` lists the `dst` nodes of
the edges `src -> dst`). A plain `dict` of lists is the usual form, but any
Mapping with iterable values works, including strings, where each character is
a node. Nodes that only appear as destinations need not be keys. The functions
here mostly iterate or compute sets over such a mapping without building any
other graph structure; `meshed.dag` uses them to order and query its
`FuncNode` graph.

Main entry points:

- `topological_sort`: order the nodes so that every node comes after its parents.
- `edges` and `nodes`: iterate the edges or the (deduplicated) nodes of `g`.
- `root_nodes` and `leaf_nodes`: nodes with no parents, or no children.
- `ancestors` and `descendants`: everything reachable to, or from, some nodes.
- `edge_reversed_graph`: the same graph with every edge flipped.

```pycon
>>> from meshed.itools import topological_sort, root_nodes, leaf_nodes
>>> g = {0: [1, 2], 1: [3], 2: [3]}
>>> topological_sort(g)
[0, 1, 2, 3]
>>> root_nodes(g), leaf_nodes(g)
({0}, {3})
```

### Functions

| [`add_edge`](_autosummary/meshed.itools.html.md#meshed.itools.add_edge)(g, node1, node2)                        | Add an edge FROM node1 TO node2                                                            |
|---------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|
| [`ancestors`](_autosummary/meshed.itools.html.md#meshed.itools.ancestors)(g, source[, \_exclude_nodes])          | Set of all nodes (not in source) reachable TO `source` in `g`.                             |
| [`children`](_autosummary/meshed.itools.html.md#meshed.itools.children)(g, source)                              | Set of all nodes (not in source) adjacent FROM 'source' in 'g'                             |
| [`copy_of_g_with_some_keys_removed`](_autosummary/meshed.itools.html.md#meshed.itools.copy_of_g_with_some_keys_removed)(g, keys)        | Shallow copy of `g` without the given keys.                                                |
| [`descendants`](_autosummary/meshed.itools.html.md#meshed.itools.descendants)(g, source[, \_exclude_nodes])        | Returns the set of all nodes reachable FROM `source` in `g`.                               |
| [`edge_reversed_graph`](_autosummary/meshed.itools.html.md#meshed.itools.edge_reversed_graph)(g[, dst_nodes_factory, ...]) | Invert the from/to direction of the edges of the graph.                                    |
| [`edges`](_autosummary/meshed.itools.html.md#meshed.itools.edges)(g)                                         | Generates edges of graph, i.e. `(from_node, to_node)` tuples.                              |
| [`filter_dict_on_keys`](_autosummary/meshed.itools.html.md#meshed.itools.filter_dict_on_keys)(d, condition)                | Keep the `(k, v)` items of `d` for which `condition(k, v)` is true.                        |
| [`filter_dict_with_list_values`](_autosummary/meshed.itools.html.md#meshed.itools.filter_dict_with_list_values)(d, condition)       | Keep, in each value of `d`, only the elements satisfying `condition`.                      |
| [`find_path`](_autosummary/meshed.itools.html.md#meshed.itools.find_path)(g, src, dst[, path])                   | find a path from src to dst nodes in graph                                                 |
| [`graphviz_digraph`](_autosummary/meshed.itools.html.md#meshed.itools.graphviz_digraph)(d)                              | Makes a graphviz graph using the links specified by dict d                                 |
| [`has_cycle`](_autosummary/meshed.itools.html.md#meshed.itools.has_cycle)(g)                                     | Returns a list representing a cycle in the graph if any. An empty list indicates no cycle. |
| [`has_node`](_autosummary/meshed.itools.html.md#meshed.itools.has_node)(g, node[, check_adjacencies])           | Returns True if the graph has given node                                                   |
| [`in_degrees`](_autosummary/meshed.itools.html.md#meshed.itools.in_degrees)(g)                                    | Yield `(node, number_of_parents)` for every node of `g`.                                   |
| [`isolated_nodes`](_autosummary/meshed.itools.html.md#meshed.itools.isolated_nodes)(g)                                | Nodes of `g` whose adjacency is empty (no outgoing edges).                                 |
| [`leaf_nodes`](_autosummary/meshed.itools.html.md#meshed.itools.leaf_nodes)(g)                                    | Nodes of `g` that point to no other node (isolated nodes included).                        |
| [`nodes`](_autosummary/meshed.itools.html.md#meshed.itools.nodes)(g)                                         | Yield every node of `g` once: each key, then each node it points to.                       |
| [`nodes_of_graph`](_autosummary/meshed.itools.html.md#meshed.itools.nodes_of_graph)(graph)                            | Set of the keys of `graph` together with its values taken whole.                           |
| [`out_degrees`](_autosummary/meshed.itools.html.md#meshed.itools.out_degrees)(g)                                   | Yield `(node, number_of_children)` for every key of `g`.                                   |
| [`parents`](_autosummary/meshed.itools.html.md#meshed.itools.parents)(g, source)                               | Set of all nodes (not in source) adjacent TO 'source' in 'g'                               |
| [`predecessors`](_autosummary/meshed.itools.html.md#meshed.itools.predecessors)(g, node)                            | Iterator of nodes that have directed paths TO node                                         |
| [`random_graph`](_autosummary/meshed.itools.html.md#meshed.itools.random_graph)([n_nodes])                          | Get a random graph.                                                                        |
| [`reverse_edges`](_autosummary/meshed.itools.html.md#meshed.itools.reverse_edges)(g)                                 | Generator of reversed edges.                                                               |
| [`root_ancestors`](_autosummary/meshed.itools.html.md#meshed.itools.root_ancestors)(graph, nodes)                     | Returns the roots of the sub-dag that contribute to compute the given nodes.               |
| [`root_nodes`](_autosummary/meshed.itools.html.md#meshed.itools.root_nodes)(g)                                    | Nodes of `g` that no other node points to (isolated nodes included).                       |
| [`subtract_subgraph`](_autosummary/meshed.itools.html.md#meshed.itools.subtract_subgraph)(graph, subgraph)               | Copy of `graph` with the nodes of `subgraph` removed.                                      |
| [`successors`](_autosummary/meshed.itools.html.md#meshed.itools.successors)(g, node[, \_exclude_nodes])           | Iterator of nodes that have directed paths FROM node                                       |
| [`topological_sort`](_autosummary/meshed.itools.html.md#meshed.itools.topological_sort)(g)                              | Return the list of nodes in topological sort order.                                        |

### meshed.itools.add_edge(g, node1, node2)

Add an edge FROM node1 TO node2

### meshed.itools.ancestors(g, source, \_exclude_nodes=None)

Set of all nodes (not in source) reachable TO `source` in `g`.

```pycon
>>> g = {
...     0: [1, 2],
...     1: [2, 3, 4],
...     2: [4],
...     3: [4]
... }
>>> ancestors(g, [2, 3])
{0, 1}
>>> ancestors(g, [0])
set()
```

### meshed.itools.children(g, source)

Set of all nodes (not in source) adjacent FROM ‘source’ in ‘g’

```pycon
>>> g = {
...     0: [1, 2],
...     1: [2, 3, 4],
...     2: [1, 4],
...     3: [4]
... }
>>> children(g, [2, 3])
{1, 4}
>>> children(g, [4])
set()
```

### meshed.itools.copy_of_g_with_some_keys_removed(g, keys)

Shallow copy of `g` without the given keys.

A whitespace-separated string of keys is accepted. References to the removed
keys inside other adjacencies are kept.

### meshed.itools.descendants(g, source, \_exclude_nodes=None)

Returns the set of all nodes reachable FROM `source` in `g`.

```pycon
>>> g = {
...     0: [1, 2],
...     1: [2, 3, 4],
...     2: [4],
...     3: [4]
... }
>>> descendants(g, [2, 3])
{4}
>>> descendants(g, [4])
set()
```

### meshed.itools.edge_reversed_graph(g, dst_nodes_factory=<class 'list'>, dst_nodes_append=<method 'append' of 'list' objects>)

Invert the from/to direction of the edges of the graph.

* **Return type:**
  [`Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)[[`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)(`N`), [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)(`N`)]]

```pycon
>>> g = dict(a='c', b='cd', c='abd', e='')
>>> assert edge_reversed_graph(g) == {
...     'c': ['a', 'b'], 'd': ['b', 'c'], 'a': ['c'], 'b': ['c'], 'e': []}
>>> reverse_g_with_sets = edge_reversed_graph(g, set, set.add)
>>> assert reverse_g_with_sets == {
...     'c': {'a', 'b'}, 'd': {'b', 'c'}, 'a': {'c'}, 'b': {'c'}, 'e': set([])}
```

Testing border cases

```pycon
>>> assert edge_reversed_graph(dict(e='', a='e')) == {'e': ['a'], 'a': []}
>>> assert edge_reversed_graph(dict(a='e', e='')) == {'e': ['a'], 'a': []}
```

### meshed.itools.edges(g)

Generates edges of graph, i.e. `(from_node, to_node)` tuples.

```pycon
>>> g = dict(a='c', b='ce', c='abde', d='c', e=['c', 'z'], f={})
>>> assert sorted(edges(g)) == [
...     ('a', 'c'), ('b', 'c'), ('b', 'e'), ('c', 'a'), ('c', 'b'), ('c', 'd'),
...     ('c', 'e'), ('d', 'c'), ('e', 'c'), ('e', 'z')]
```

### meshed.itools.filter_dict_on_keys(d, condition)

Keep the `(k, v)` items of `d` for which `condition(k, v)` is true.

### meshed.itools.filter_dict_with_list_values(d, condition)

Keep, in each value of `d`, only the elements satisfying `condition`.

The filtered values are lists, whatever the originals were.

### meshed.itools.find_path(g, src, dst, path=None)

find a path from src to dst nodes in graph

```pycon
>>> g = dict(a='c', b='ce', c=list('abde'), d='c', e=['c', 'z'], f={})
>>> find_path(g, 'a', 'c')
['a', 'c']
>>> find_path(g, 'a', 'b')
['a', 'c', 'b']
>>> find_path(g, 'a', 'z')
['a', 'c', 'b', 'e', 'z']
>>> assert find_path(g, 'a', 'f') == None
```

### meshed.itools.graphviz_digraph(d)

Makes a graphviz graph using the links specified by dict d

### meshed.itools.has_cycle(g)

> Returns a list representing a cycle in the graph if any. An empty list indicates no cycle.
* **Parameters:**
  **g** ([`Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)[[`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)(`N`), [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)(`N`)]]) – 

  The graph to check for cycles, represented as a dictionary where keys are nodes
  : and values are lists of nodes pointing to the key node (parents of the key node).

  Example usage:
  ```pycon
  >>> g = dict(e=['c', 'd'], c=['b'], d=['b'], b=['a'])
  >>> has_cycle(g)
  []
  ```

  ```pycon
  >>> g['a'] = ['e']  # Introducing a cycle
  >>> has_cycle(g)
  ['e', 'c', 'b', 'a', 'e']
  ```
* **Return type:**
  [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`TypeVar`](https://docs.python.org/3/library/typing.html#typing.TypeVar)(`N`)]

Design notes:

- **Graph Representation**: The graph is interpreted such that each key is a child node,
  and the values are lists of its parents. This representation requires traversing
  the graph in reverse, from child to parent, to detect cycles.

I regret this design choice, which was aligned with the original problem that was
being solved, but which doesn’t follow the usual representation of a graph.

- **Consistent Return Type**: The function systematically returns a list. A non-empty
  list indicates a cycle (showing the path of the cycle), while an empty list indicates
  the absence of a cycle.
- **Depth-First Search (DFS)**: The function performs a DFS on the graph to detect
  cycles. It uses a recursion stack (rec_stack) to track the path being explored and
  a visited set (visited) to avoid re-exploring nodes.
- **Cycle Detection and Path Reconstruction**: When a node currently in the recursion
  stack is encountered again, a cycle is detected. The function then reconstructs the
  cycle path from the current path explored, including the start and end node to
  illustrate the cycle closure.
- **Efficient Backtracking**: After exploring a node’s children, the function
  backtracks by removing the node from the recursion stack and the current path,
  ensuring accurate path tracking for subsequent explorations.

### meshed.itools.has_node(g, node, check_adjacencies=True)

Returns True if the graph has given node

```pycon
>>> g = {
...     0: [1, 2],
...     1: [2]
... }
>>> has_node(g, 0)
True
>>> has_node(g, 2)
True
```

Note that 2 was found, though it’s not a key of `g`.
This shows that we don’t have to have an explicit `{2: []}` in `g`
to be able to see that it’s a node of `g`.
The function will go through the values of the mapping to try to find it
if it hasn’t been found before in the keys.

This can be inefficient, so if that matters, you can express your
graph `g` so that all nodes are explicitly declared as keys, and
use `check_adjacencies=False` to tell the function not to look into
the values of the `g` mapping.

```pycon
>>> has_node(g, 2, check_adjacencies=False)
False
>>> g = {
...     0: [1, 2],
...     1: [2],
...     2: []
... }
>>> has_node(g, 2, check_adjacencies=False)
True
```

### meshed.itools.in_degrees(g)

Yield `(node, number_of_parents)` for every node of `g`.

```pycon
>>> g = dict(a='c', b='ce', c='abde', d='c', e=['c', 'z'], f={})
>>> assert dict(in_degrees(g)) == (
... {'a': 1, 'b': 1, 'c': 4,  'd': 1, 'e': 2, 'f': 0, 'z': 1}
... )
```

### meshed.itools.isolated_nodes(g)

Nodes of `g` whose adjacency is empty (no outgoing edges).

```pycon
>>> g = dict(a='c', b='ce', c=list('abde'), d='c', e=['c', 'z'], f={})
>>> set(isolated_nodes(g))
{'f'}
```

### meshed.itools.leaf_nodes(g)

Nodes of `g` that point to no other node (isolated nodes included).

```pycon
>>> g = dict(a='c', b='ce', c='abde', d='c', e=['c', 'z'], f={})
>>> sorted(leaf_nodes(g))
['f', 'z']
```

Note that `f` is present: Isolated nodes are considered both as
root and leaf nodes both.

### meshed.itools.nodes(g)

Yield every node of `g` once: each key, then each node it points to.

```pycon
>>> g = dict(a='c', b='ce', c='abde', d='c', e=['c', 'z'], f={})
>>> sorted(nodes(g))
['a', 'b', 'c', 'd', 'e', 'f', 'z']
```

### meshed.itools.nodes_of_graph(graph)

Set of the keys of `graph` together with its values taken whole.

The values go in as they are, so they must be hashable.

### meshed.itools.out_degrees(g)

Yield `(node, number_of_children)` for every key of `g`.

```pycon
>>> g = dict(a='c', b='ce', c='abde', d='c', e=['c', 'z'], f={})
>>> assert dict(out_degrees(g)) == (
...     {'a': 1, 'b': 2, 'c': 4, 'd': 1, 'e': 2, 'f': 0}
... )
```

### meshed.itools.parents(g, source)

Set of all nodes (not in source) adjacent TO ‘source’ in ‘g’

```pycon
>>> g = {
...     0: [1, 2],
...     1: [2, 3, 4],
...     2: [1, 4],
...     3: [4]
... }
>>> parents(g, [2, 3])
{0, 1}
>>> parents(g, [0])
set()
```

### meshed.itools.predecessors(g, node)

Iterator of nodes that have directed paths TO node

```pycon
>>> g = {
...     0: [1, 2],
...     1: [2, 3, 4],
...     2: [1, 4],
...     3: [4]}
>>> set(predecessors(g, 4))
{0, 1, 2, 3}
>>> set(predecessors(g, 2))
{0, 1, 2}
>>> set(predecessors(g, 0))
set()
```

Notice that 2 is a predecessor of 2 here because of the presence
of a 2-1-2 directed path.

### meshed.itools.random_graph(n_nodes=7)

Get a random graph.

```pycon
>>> random_graph()
{0: [6, 3, 5, 2],
 1: [3, 2, 0, 6],
 2: [5, 6, 4, 0],
 3: [1, 0, 5, 6, 3],
 4: [],
 5: [1, 5, 3, 6],
 6: [4, 3, 1]}
>>> random_graph(3)
{0: [0], 1: [0], 2: []}
```

### meshed.itools.reverse_edges(g)

Generator of reversed edges. Like edges but with inverted edges.

```pycon
>>> g = dict(a='c', b='ce', c='abde', d='c', e=['c', 'z'], f={})
>>> assert sorted(reverse_edges(g)) == [
...     ('a', 'c'), ('b', 'c'), ('c', 'a'), ('c', 'b'), ('c', 'd'), ('c', 'e'),
...     ('d', 'c'), ('e', 'b'), ('e', 'c'), ('z', 'e')]
```

#### NOTE
Not to be confused with  `edge_reversed_graph` which inverts the direction
of edges.

### meshed.itools.root_ancestors(graph, nodes)

Returns the roots of the sub-dag that contribute to compute the given nodes.

### meshed.itools.root_nodes(g)

Nodes of `g` that no other node points to (isolated nodes included).

```pycon
>>> g = dict(a='c', b='ce', c='abde', d='c', e=['c', 'z'], f={})
>>> sorted(root_nodes(g))
['f']
```

Note that `f` is present: Isolated nodes are considered both as
root and leaf nodes both.

### meshed.itools.subtract_subgraph(graph, subgraph)

Copy of `graph` with the nodes of `subgraph` removed.

The nodes are those of `nodes_of_graph(subgraph)`; they are removed from keys
and adjacencies, and keys left with no adjacencies are dropped.

### meshed.itools.successors(g, node, \_exclude_nodes=None)

Iterator of nodes that have directed paths FROM node

```pycon
>>> g = {
...     0: [1, 2],
...     1: [2, 3, 4],
...     2: [1, 4],
...     3: [4]}
>>> assert set(successors(g, 1)) == {1, 2, 3, 4}
>>> assert set(successors(g, 3)) == {4}
>>> assert set(successors(g, 4)) == set()
```

Notice that 1 is a successor of 1 here because there’s a 1-2-1 directed path

### meshed.itools.topological_sort(g)

Return the list of nodes in topological sort order.

This order is such that a node’s parents will all occur before it:
if `order[i]` is a parent of `order[j]` then `i < j`.

This is often used to compute the order of computation in a DAG.

```pycon
>>> g = {
...     0: [4, 2],
...     4: [3, 1],
...     2: [3],
...     3: [1]
... }
>>>
>>> list(topological_sort(g))
[0, 4, 2, 3, 1]
```

Here’s an ascii art of the graph, to verify that the topological sort is
indeed as expected.

```text
┌───┐     ┌───┐     ┌───┐     ┌───┐
│ 0 │ ──▶ │ 2 │ ──▶ │ 3 │ ──▶ │ 1 │
└───┘     └───┘     └───┘     └───┘
  │                   ▲         ▲
  │                   │         │
  ▼                   │         │
┌───┐                 │         │
│ 4 │ ────────────────┼─────────┘
└───┘                 │
  │                   │
  └───────────────────┘
```


# _autosummary/meshed.makers.html.md

# meshed.makers

Makers

This module contains tools to make meshed objects in different ways.

Main entry points:

- `code_to_dag`: turn a function whose body is `out = func(args...)` lines
  (or such a function’s source string) into a `DAG`.
- `code_to_fnodes`: the same parsing, but returning the tuple of `FuncNode`
  objects instead of assembling a `DAG`.
- `src_to_func_node_factory`: the lower-level step yielding `FuncNode`
  factories (partials that still lack their `func`).
- `mk_fnodes_from_fn_factories`: inject functions into those factories to get
  `FuncNode` objects.

Let’s start with an example where we have some code representing a user story:

```pycon
>>> def user_story():
...     wfs = call(src_to_wf, data_src)
...     chks_iter = map(chunker, wfs)
...     chks = chain(chks_iter)
...     fvs = map(featurizer, chks)
...     model_outputs = map(model, fvs)
```

If the code is compliant (has only function calls and assignments of their result),
we can extract `FuncNode` factories from these lines (uses AST behind the scenes).

```pycon
>>> from meshed.makers import src_to_func_node_factory
>>> fnodes_factories = list(src_to_func_node_factory(user_story))
```

Each factory is a curried version of `FuncNode`, set up to be able to make a `DAG`
equivalent to the user story, once we provide the necessary functions (`call`,
`map`, and `chain`).

```pycon
>>> from functools import partial
>>> assert all(
... isinstance(x, partial) and issubclass(x.func, FuncNode) for x in fnodes_factories
... )
```

See that the `FuncNode` factories are all set up with
`name` (id),
`out` (output variable name),
`bind` (names of the variables where the function will source it’s arguments), and
`func_label` (which can be used when displaying the DAG, or as a key to the function
to use).

```pycon
>>> assert [x.keywords for x in fnodes_factories] == [
...  {'name': 'call',
...   'out': 'wfs',
...   'bind': {0: 'src_to_wf', 1: 'data_src'},
...   'func_label': 'call'},
...  {'name': 'map',
...   'out': 'chks_iter',
...   'bind': {0: 'chunker', 1: 'wfs'},
...   'func_label': 'map'},
...  {'name': 'chain',
...   'out': 'chks',
...   'bind': {0: 'chks_iter'},
...   'func_label': 'chain'},
...  {'name': 'map_04',
...   'out': 'fvs',
...   'bind': {0: 'featurizer', 1: 'chks'},
...   'func_label': 'map'},
...  {'name': 'map_05',
...   'out': 'model_outputs',
...   'bind': {0: 'model', 1: 'fvs'},
...   'func_label': 'map'}
... ]
```

What can we do with that?

Well, provide the functions, so the DAG can actually compute.

You can do it yourself, or get a little help with `mk_fnodes_from_fn_factories`.

```pycon
>>> from meshed.dag import DAG
>>> from meshed.makers import mk_fnodes_from_fn_factories
>>> fnodes = list(mk_fnodes_from_fn_factories(fnodes_factories))
>>> dag = DAG(fnodes)
>>> print(dag.synopsis_string())
src_to_wf,data_src -> call -> wfs
chunker,wfs -> map -> chks_iter
chks_iter -> chain -> chks
featurizer,chks -> map_04 -> fvs
model,fvs -> map_05 -> model_outputs
```

Wait! But we didn’t actually provide the functions we wanted to use!
What happened?!?
What happened is that `mk_fnodes_from_fn_factories` just made some for us.
It used the convenient `meshed.util.mk_place_holder_func` which makes a function
(that happens to actually compute something and be picklable).

```pycon
>>> from inspect import signature
>>> str(signature(dag))
'(src_to_wf, data_src, chunker, featurizer, model)'
```

We can actually call the `dag` and get something meaningful:

```pycon
>>> dag(1, 2, 3, 4, 5)
'map(model=5, fvs=map(featurizer=4, chks=chain(chks_iter=map(chunker=3, wfs=call(src_to_wf=1, data_src=2)))))'
```

If you don’t want `mk_fnodes_from_fn_factories` to do that (because you are in
prod and need to make sure as much as possible is explicitly as expected, you can
simply use a different `factory_to_func` argument. The default one is:

```pycon
>>> from meshed.makers import dlft_factory_to_func
```

which you can also reuse to make your own.
See below how we provide a `name_to_func_map` to specify how `func_label` values should
map to actual functions, and set `use_place_holder_fallback=False` to make
sure that we don’t ever fallback on a placeholder function as we did above.

```pycon
>>> def _call(x, y):
...     # would use operator.methodcaller('__call__') but doesn't have a __name__
...     return x + y
>>> def _map(x, y):
...     return [x, y]
>>> def _chain(iterable):
...     return sum(iterable)
>>>
>>> factory_to_func = partial(
...     dlft_factory_to_func,
...     name_to_func_map={'map': _map, 'chain': _chain, 'call': _call},
...     use_place_holder_fallback=False
... )
>>>
>>> fnodes = list(mk_fnodes_from_fn_factories(fnodes_factories, factory_to_func))
>>> dag = DAG(fnodes)
```

On the surface, we get the same dag as we had before – at least from the point of view
of the dag signature, names, and relationships between these names:

```pycon
>>> print(dag.synopsis_string())
src_to_wf,data_src -> call -> wfs
chunker,wfs -> map -> chks_iter
chks_iter -> chain -> chks
featurizer,chks -> map_04 -> fvs
model,fvs -> map_05 -> model_outputs
>>> str(signature(dag))
'(src_to_wf, data_src, chunker, featurizer, model)'
```

But see below that the dag is now using the functions we specified:

```pycon
>>> # dag(src_to_wf=1, data_src=2, chunker=3, featurizer=4, model=5)
>>> # will trigger this:
>>> # src_to_wf=1, data_src=2 -> call -> wfs == 1 + 2 == 3
>>> # chunker=3 , wfs=3 -> map -> chks_iter == [3, 3]
>>> # chks_iter=6 -> chain -> chks == 3 + 3 == 6
>>> # featurizer=4, chks=6 -> map_04 -> fvs == [4, 6]
>>> # model=5, fvs=[4, 6] -> map_05 -> model_outputs == [5, [4, 6]]
>>> dag(1, 2, 3, 4, 5)
[5, [4, 6]]
```

### Functions

| [`attr_dict`](_autosummary/meshed.makers.html.md#meshed.makers.attr_dict)(obj)                                 | Map every attribute name of `obj` not starting with an underscore to its value.                                                               |
|-------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| `code_to_dag`([src, func_src, ...])                                                             | Build a `DAG` from Python code whose lines are `out = func(args...)` calls.                                                                   |
| [`code_to_digraph`](_autosummary/meshed.makers.html.md#meshed.makers.code_to_digraph)(src)                           | Make a `graphviz.Digraph` of the `DAG` that `code_to_dag(src)` builds.                                                                        |
| `code_to_fnodes`([src, func_src, ...])                                                          | Parse `out = func(args...)` code into a tuple of `FuncNode` objects.                                                                          |
| [`dag_to_jdict`](_autosummary/meshed.makers.html.md#meshed.makers.dag_to_jdict)(dag, \*[, func_to_jdict])         | Will produce a json-serializable dictionary from a dag.                                                                                       |
| [`dlft_factory_to_func`](_autosummary/meshed.makers.html.md#meshed.makers.dlft_factory_to_func)(factory[, ...])           | Get a function for the given factory, looking its `func_label` up in `name_to_func_map`.                                                      |
| [`fnode_to_jdict`](_autosummary/meshed.makers.html.md#meshed.makers.fnode_to_jdict)(fnode, \*[, func_to_jdict])     | Serialize a `FuncNode` to a dict of its `name`, `func_label`, `bind` and `out`.                                                               |
| [`func_nodes_to_named_funcs`](_autosummary/meshed.makers.html.md#meshed.makers.func_nodes_to_named_funcs)(func_nodes)          | Make some components (kwargs) based on the `.out` and `.func` of the `FuncNode` objects.                                                      |
| [`is_from_ast_module`](_autosummary/meshed.makers.html.md#meshed.makers.is_from_ast_module)(o)                          | Tell whether the class of `o` reports `_ast` as its module.                                                                                   |
| `iterize`(func)                                                                                 |                                                                                                                                               |
| [`jdict_to_dag`](_autosummary/meshed.makers.html.md#meshed.makers.jdict_to_dag)(jdict, \*[, jdict_to_func])       | Will produce a dag from a json-serializable dictionary.                                                                                       |
| [`jdict_to_fnode`](_autosummary/meshed.makers.html.md#meshed.makers.jdict_to_fnode)(jdict, \*[, jdict_to_func])     | Rebuild a `FuncNode` from a dict made by `fnode_to_jdict`.                                                                                    |
| [`lined_dag`](_autosummary/meshed.makers.html.md#meshed.makers.lined_dag)(funcs)                               | Chain `funcs` into a `DAG` where each function's output feeds the first parameter of the next.                                                |
| [`mk_fnodes_from_fn_factories`](_autosummary/meshed.makers.html.md#meshed.makers.mk_fnodes_from_fn_factories)(fnodes_factories)  | Make func nodes from func node factories and a specification of how to make the nodes from these.                                             |
| [`named_funcs_to_func_nodes`](_autosummary/meshed.makers.html.md#meshed.makers.named_funcs_to_func_nodes)(named_funcs)         | Make `FuncNode` objects from keyword arguments, using the key as the `.out` of the `FuncNode` and the value as the `.func` of the `FuncNode`. |
| [`node_kwargs_to_func_node_factory`](_autosummary/meshed.makers.html.md#meshed.makers.node_kwargs_to_func_node_factory)(node_kwargs)  | Curry `FuncNode` with `node_kwargs` (`name`, `out`, `bind`, ...), leaving `func` to be supplied.                                              |
| [`parse_assignment`](_autosummary/meshed.makers.html.md#meshed.makers.parse_assignment)(body[, info])                 | Split an assignment statement into its `(target, call)` ast nodes.                                                                            |
| [`parse_assignment_steps`](_autosummary/meshed.makers.html.md#meshed.makers.parse_assignment_steps)(src)                    | Parse source code and generate tuples of information about it.                                                                                |
| [`parse_body`](_autosummary/meshed.makers.html.md#meshed.makers.parse_body)(body, \*[, body_index])             | Turn one body statement into a `(target, call)` pair of ast nodes, or `None`.                                                                 |
| [`parse_steps`](_autosummary/meshed.makers.html.md#meshed.makers.parse_steps)(src)                               | Parse source code and generate tuples of information about it.                                                                                |
| [`parsed_to_node_kwargs`](_autosummary/meshed.makers.html.md#meshed.makers.parsed_to_node_kwargs)(target_value)            | Extract FuncNode kwargs (name, out, and bind) from ast (target,value) pairs                                                                   |
| [`robust_ast_parse`](_autosummary/meshed.makers.html.md#meshed.makers.robust_ast_parse)(src)                          | Parse `src` with `ast.parse`, retrying with the common leading indent stripped on `IndentationError`.                                         |
| [`signed_itemgetter`](_autosummary/meshed.makers.html.md#meshed.makers.signed_itemgetter)(\*keys)                      | Like `operator.itemgetter`, except has a signature, which we needed                                                                           |
| [`simple_code_to_digraph`](_autosummary/meshed.makers.html.md#meshed.makers.simple_code_to_digraph)(src)                    | Make a `graphviz.Digraph` of the `DAG` that `code_to_dag(src)` builds.                                                                        |
| [`src_to_func_node_factory`](_autosummary/meshed.makers.html.md#meshed.makers.src_to_func_node_factory)(src[, exclude_names]) |                                                                                                                                               |
| [`triples_to_fnodes`](_autosummary/meshed.makers.html.md#meshed.makers.triples_to_fnodes)(triples)                     | Converts an iterable of func call triples to an iterable of `FuncNode` objects.                                                               |

### Classes

| [`dlft_factory_to_func_mapping`](_autosummary/meshed.makers.html.md#meshed.makers.dlft_factory_to_func_mapping)()   | Mapping view of `dlft_factory_to_func`: `m[factory]` is `dlft_factory_to_func(factory)`.   |
|-----------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------|

### meshed.makers.attr_dict(obj)

Map every attribute name of `obj` not starting with an underscore to its value.

### meshed.makers.code_to_digraph(src)

Make a `graphviz.Digraph` of the `DAG` that `code_to_dag(src)` builds.

### meshed.makers.dag_to_jdict(dag, , func_to_jdict=None)

Will produce a json-serializable dictionary from a dag.

### meshed.makers.dlft_factory_to_func(factory, name_to_func_map=None, use_place_holder_fallback=True)

Get a function for the given factory, looking its `func_label` up in `name_to_func_map`.

If the label is missing from the map, a placeholder function (see
`meshed.util.mk_place_holder_func`) is made unless `use_place_holder_fallback`
is `False`, in which case `KeyError` is raised.

### *class* meshed.makers.dlft_factory_to_func_mapping

Bases: [`Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)

Mapping view of `dlft_factory_to_func`: `m[factory]` is `dlft_factory_to_func(factory)`.

Only `__getitem__` is defined, so a subclass must add `__iter__` and
`__len__` before it can be instantiated.

### meshed.makers.extract_tokens(string, pos=0, endpos=9223372036854775807)

Return a list of all non-overlapping matches of pattern in string.

### meshed.makers.fnode_to_jdict(fnode, , func_to_jdict=None)

Serialize a `FuncNode` to a dict of its `name`, `func_label`, `bind` and `out`.

The function itself is included (under `func`) only when `func_to_jdict` is
given to serialize it.

### meshed.makers.func_nodes_to_named_funcs(func_nodes)

Make some components (kwargs) based on the `.out` and `.func` of the
`FuncNode` objects.

Example use: To get from `DAG` to `Slabs`.

* **Return type:**
  [`Mapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Mapping)[[`str`](https://docs.python.org/3/builtins/stdtypes.html#str), [`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)]

```pycon
>>> from meshed import DAG, FuncNode
>>> dag = DAG([
...     FuncNode(lambda x: x + 1, out='a'),
...     FuncNode(lambda a: a + 2, out='b',),
...     FuncNode(lambda a, b: a * b, out='c'),
... ])
>>> dag(x=10)
143
>>> named_funcs = func_nodes_to_named_funcs(dag.func_nodes)
>>> isinstance(named_funcs, dict)
True
>>> list(named_funcs)
['a', 'b', 'c']
>>> callable(named_funcs['a'])
True
>>> assert dag.find_func_node('a').func(3) == named_funcs['a'](3) ==4
```

The inverse of this function is `named_funcs_to_func_nodes`.

```pycon
>>> func_nodes = list(named_funcs_to_func_nodes(named_funcs))
>>> dag2 = DAG(func_nodes)
>>> assert dag2(x=3) == dag(x=3) == 24
```

### meshed.makers.is_from_ast_module(o)

Tell whether the class of `o` reports `_ast` as its module.

Note that on Python 3.12 the `ast` node classes report `ast`, not `_ast`,
so this returns `False` for them.

### meshed.makers.jdict_to_dag(jdict, , jdict_to_func=None)

Will produce a dag from a json-serializable dictionary.

### meshed.makers.jdict_to_fnode(jdict, , jdict_to_func=None)

Rebuild a `FuncNode` from a dict made by `fnode_to_jdict`.

`jdict_to_func` is required to turn `jdict["func"]` back into a callable;
without it, `NotImplementedError` is raised.

### meshed.makers.lined_dag(funcs)

Chain `funcs` into a `DAG` where each function’s output feeds the first parameter of the next.

Edges are added with `DAG.add_edges`, which raises `ValueError` if a
function’s first parameter already carries the name of another function in
`funcs`.

### meshed.makers.mk_fnodes_from_fn_factories(fnodes_factories, factory_to_func=<function dlft_factory_to_func>)

Make func nodes from func node factories and a specification of how to make the
nodes from these.

* **Parameters:**
  * **fnodes_factories** ([`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[`...`](https://docs.python.org/3/builtins/constants.html#Ellipsis), [`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)]]) – An iterable of FuncNodeFactory
  * **factory_to_func** ([`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[[`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[`...`](https://docs.python.org/3/builtins/constants.html#Ellipsis), [`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)]], [`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)]) – A function that will give you a function given a
    FuncNodeFactory input (where it will draw the information it needs to know
    what kind of function to make).
* **Return type:**
  [`Iterator`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator)[[`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)]
* **Returns:**

### meshed.makers.named_funcs_to_func_nodes(named_funcs)

Make `FuncNode` objects from keyword arguments, using the key as the `.out` of the
`FuncNode` and the value as the `.func` of the `FuncNode`.

Example use: To get from `Slabs` to `DAG`.

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)]

```pycon
>>> from meshed import DAG
>>> func_nodes = list(named_funcs_to_func_nodes(dict(
...     a=lambda x: x + 1,
...     b=lambda a: a + 2,
...     c=lambda a, b: a * b)
... ))
>>> dag = DAG(func_nodes)
>>> dag(x=3)
24
```

The inverse of this function is `func_nodes_to_named_funcs`.

```pycon
>>> named_funcs = func_nodes_to_named_funcs(dag.func_nodes)
>>> dag2 = DAG(named_funcs_to_func_nodes(named_funcs))
>>> assert dag2(x=3) == dag(x=3) == 24
```

### meshed.makers.node_kwargs_to_func_node_factory(node_kwargs)

Curry `FuncNode` with `node_kwargs` (`name`, `out`, `bind`, …), leaving
`func` to be supplied.

* **Return type:**
  [`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[[`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)], [`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)]

### meshed.makers.parse_assignment(body, info=None)

Split an assignment statement into its `(target, call)` ast nodes.

Raises `ValueError` if `body` is not an (annotated) assignment, and
`AssertionError` if it has several targets or its value is not a call.
The `info` argument is ignored (it is recomputed from `body`).

* **Return type:**
  [`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)

### meshed.makers.parse_assignment_steps(src)

Parse source code and generate tuples of information about it.

* **Parameters:**
  **src** – The source string or a python object whose code string can be extracted.
* **Returns:**
  And generator of “target_values”

```pycon
>>> from meshed.makers import parse_steps
>>> def foo():
...     x = func1(a, b=2)
...     y = func2(x, c=3)
>>> target_values = list(parse_steps(foo))
```

Let’s look at the first target_value to see what it contains:

```pycon
>>> name, call = target_values[0]  # a 2-tuple
>>> assert isinstance(name, ast.Name)  # the first element is a ast Name object
>>> sorted(vars(name))
['col_offset', 'ctx', 'end_col_offset', 'end_lineno', 'id', 'lineno']
>>> name.id
'x'
>>> assert isinstance(call, ast.Call)  # the first element is a ast Call object
>>> sorted(vars(call))
['args', 'col_offset', 'end_col_offset', 'end_lineno', 'func', 'keywords', 'lineno']
>>> call.args[0].id
'a'
>>> call.keywords[0].arg
'b'
>>> call.keywords[0].value.value
2
```

Basically, these ast objects contain all we need to know about the (parsed) source.

### meshed.makers.parse_body(body, , body_index=None)

Turn one body statement into a `(target, call)` pair of ast nodes, or `None`.

Assignments go through `parse_assignment`; a bare call gets the dummy target
`_{body_index}`; `return` statements and string constants (docstrings) give
`None` (skipped); anything else raises `ValueError`.

### meshed.makers.parse_steps(src)

Parse source code and generate tuples of information about it.

* **Parameters:**
  **src** – The source string or a python object whose code string can be extracted.
* **Returns:**
  And generator of “target_values”

```pycon
>>> from meshed.makers import parse_steps
>>> def foo():
...     x = func1(a, b=2)
...     y = func2(x, c=3)
>>> target_values = list(parse_steps(foo))
```

Let’s look at the first target_value to see what it contains:

```pycon
>>> name, call = target_values[0]  # a 2-tuple
>>> assert isinstance(name, ast.Name)  # the first element is a ast Name object
>>> sorted(vars(name))
['col_offset', 'ctx', 'end_col_offset', 'end_lineno', 'id', 'lineno']
>>> name.id
'x'
>>> assert isinstance(call, ast.Call)  # the first element is a ast Call object
>>> sorted(vars(call))
['args', 'col_offset', 'end_col_offset', 'end_lineno', 'func', 'keywords', 'lineno']
>>> call.args[0].id
'a'
>>> call.keywords[0].arg
'b'
>>> call.keywords[0].value.value
2
```

Basically, these ast objects contain all we need to know about the (parsed) source.

### meshed.makers.parsed_to_node_kwargs(target_value)

Extract FuncNode kwargs (name, out, and bind) from ast (target,value) pairs

* **Parameters:**
  **target_value** – A (target, value) pair
* **Return type:**
  [`Iterator`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator)[[`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)]
* **Returns:**
  A `{name:..., out:..., bind:...}` dict (meant to be used to curry FuncNode

Where can you make make target_values? With the `parse_assignment_steps` function.

```pycon
>>> from meshed.makers import parse_assignment_steps
>>> def foo():
...     x = func1(a, b=2)
...     y = func2(x, func1, c=3, d=x)
>>> for target_value in parse_assignment_steps(foo):
...     for d in parsed_to_node_kwargs(target_value):
...         print(d)
{'name': 'func1', 'out': 'x', 'bind': {0: 'a', 'b': 2}}
{'name': 'func2', 'out': 'y', 'bind': {0: 'x', 1: 'func1', 'c': 3, 'd': 'x'}}
```

### meshed.makers.robust_ast_parse(src)

Parse `src` with `ast.parse`, retrying with the common leading indent stripped
on `IndentationError`.

### meshed.makers.signed_itemgetter(\*keys)

Like `operator.itemgetter`, except has a signature, which we needed

### meshed.makers.simple_code_to_digraph(src)

Make a `graphviz.Digraph` of the `DAG` that `code_to_dag(src)` builds.

### meshed.makers.src_to_func_node_factory(src, exclude_names=None)

* **Parameters:**
  * **src** – Callable or string of callable.
  * **exclude_names** – Names to exclude when making func_nodes
* **Return type:**
  [`Iterator`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterator)[[`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode) | [`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[`...`](https://docs.python.org/3/builtins/constants.html#Ellipsis), [`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)]]
* **Returns:**

### meshed.makers.triples_to_fnodes(triples)

Converts an iterable of func call triples to an iterable of `FuncNode` objects.
(Which in turn can be converted to a `DAG`.)

Note how the python identifiers are extracted (on the basis of “an unbroken
sequence of alphanumerical (and underscore) characters”, ignoring all other
characters).

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)]

```pycon
>>> from meshed import DAG
>>> dag = DAG(
...     triples_to_fnodes(
...     [
...         ('alpha bravo', 'charlie', 'delta echo'),
...         (' foxtrot  &^$#', 'golf', '  alpha,  echo'),
...     ])
... )
>>> print(dag.synopsis_string())
delta,echo -> charlie -> alpha__bravo
alpha__bravo -> alpha__0 -> alpha
alpha__bravo -> bravo__1 -> bravo
alpha,echo -> golf -> foxtrot
```


# _autosummary/meshed.scrap.annotations_to_meshes.html.md

# meshed.scrap.annotations_to_meshes

Code related to work on the “From annotated functions to meshes” discussion:

[https://github.com/i2mint/meshed/discussions/55](https://github.com/i2mint/meshed/discussions/55)

### Functions

| [`callable_annots_to_signature`](_autosummary/meshed.scrap.annotations_to_meshes.html.md#meshed.scrap.annotations_to_meshes.callable_annots_to_signature)(callable_annots)   | Produces a signature from a Callable type annotation                                             |
|--------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| [`func_types_to_protocol`](_autosummary/meshed.scrap.annotations_to_meshes.html.md#meshed.scrap.annotations_to_meshes.func_types_to_protocol)(func_types[, name, ...]) | Produces a typing.Protocol based on a dictionary of `(method_name, Callable_type)` specification |
| [`func_types_to_scaffold`](_autosummary/meshed.scrap.annotations_to_meshes.html.md#meshed.scrap.annotations_to_meshes.func_types_to_scaffold)(func_types[, name])      | Produces a scaffold class containing the said methods, with given annotations                    |
| `test_func_types_to_protocol`()                                                                  |                                                                                                  |
| `test_func_types_to_scaffold`()                                                                  |                                                                                                  |
| `try_annotation_name`(arg_annotation, ...)                                                       |                                                                                                  |

### meshed.scrap.annotations_to_meshes.callable_annots_to_signature(callable_annots, mk_argname=<function try_annotation_name>)

Produces a signature from a Callable type annotation

* **Return type:**
  [`Signature`](https://docs.python.org/3/library/inspect.html#inspect.Signature)

```pycon
>>> from typing import Callable, NewType
>>> MyType = NewType('MyType', str)
>>> sig = callable_annots_to_signature(Callable[[MyType, str], str])
>>> import inspect
>>> isinstance(sig, inspect.Signature)
True
>>> list(sig.parameters.keys())
['self', 'mytype', 'arg_01']
>>> sig.parameters['arg_01'].annotation
<class 'str'>
```

### meshed.scrap.annotations_to_meshes.func_types_to_protocol(func_types, name=None, \*, mk_argname=<function try_annotation_name>)

Produces a typing.Protocol based on a dictionary of
`(method_name, Callable_type)` specification

* **Return type:**
  [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol)

### meshed.scrap.annotations_to_meshes.func_types_to_scaffold(func_types, name=None)

Produces a scaffold class containing the said methods, with given annotations

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)


# _autosummary/meshed.scrap.cached_dag.html.md

# meshed.scrap.cached_dag

### Functions

| `add`(a[, b])                                                      |                                                                                                                                                                                       |
|--------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`cached_dag_test`](_autosummary/meshed.scrap.cached_dag.html.md#meshed.scrap.cached_dag.cached_dag_test)() | Covering issue [https://github.com/i2mint/meshed/issues/34](https://github.com/i2mint/meshed/issues/34) about "CachedDag.cache should be populated with inputs that it was called on" |
| `exp`(mult[, n])                                                   |                                                                                                                                                                                       |
| `func_node_names_and_outs`(dag)                                    |                                                                                                                                                                                       |
| `get_first_item_and_assert_unicity`(seq)                           |                                                                                                                                                                                       |
| `mult`(x[, y])                                                     |                                                                                                                                                                                       |
| `subtract`(a[, b])                                                 |                                                                                                                                                                                       |

### Classes

| [`CachedDag`](_autosummary/meshed.scrap.cached_dag.html.md#meshed.scrap.cached_dag.CachedDag)(dag[, cache, name])   | Wraps a DAG, using it to compute any of it's var nodes from it's dependents, with the capability of caching intermediate var nodes for later reuse.   |
|----------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`NoOverwritesDict`](_autosummary/meshed.scrap.cached_dag.html.md#meshed.scrap.cached_dag.NoOverwritesDict)                | A dict where you're not allowed to write to a key that already has a value in it.                                                                     |
| `NoSuchKey`()                                                                    |                                                                                                                                                       |

### Exceptions

| [`NotAllowed`](_autosummary/meshed.scrap.cached_dag.html.md#meshed.scrap.cached_dag.NotAllowed)                | To use to indicate that something is not allowed              |
|----------------------------------------------------------------------------|---------------------------------------------------------------|
| [`OverWritesNotAllowedError`](_autosummary/meshed.scrap.cached_dag.html.md#meshed.scrap.cached_dag.OverWritesNotAllowedError) | Error to raise when a writes to existing keys are not allowed |

### *class* meshed.scrap.cached_dag.CachedDag(dag, cache=True, name=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Wraps a DAG, using it to compute any of it’s var nodes from it’s dependents,
with the capability of caching intermediate var nodes for later reuse.

```pycon
>>> def add(a, b=1):
...     return a + b
>>> def mult(x, y=2):
...     return x * y
>>> def subtract(a, b=4):
...     return a - b
>>> from meshed import code_to_dag
>>>
>>> @code_to_dag(func_src=locals())
... def dag(w, ww, www):
...     x = mult(w, ww)
...     y = add(x, www)
...     z = subtract(x, y)
>>> print(dag.dot_digraph_ascii())
```

```text
               w

            │
            │
            ▼
          ┌──────────┐
ww=   ──▶ │   mult   │
          └──────────┘
            │
            │
            ▼

               x       ─┐
                        │
            │           │
            │           │
            ▼           │
          ┌──────────┐  │
www=  ──▶ │   add    │  │
          └──────────┘  │
            │           │
            │           │
            ▼           │
                        │
               y=       │
                        │
            │           │
            │           │
            ▼           │
          ┌──────────┐  │
          │ subtract │ ◀┘
          └──────────┘
            │
            │
            ▼

               z
```

```pycon
>>> from inspect import signature
>>> g = CachedDag(dag)
>>> signature(g)
<Signature (k, /, **input_kwargs)>
```

We can get `ww` because it has a default:

(TODO: This (and further tests) stopped working since code_to_dag was enhanced
with the ability to use the wrapped function’s signature to determine the
signature of the output dag. Need to fix this.)

```pycon
>>> g('ww')
2
```

But we can’t get `y` because we don’t have what it depends on:

```pycon
>>> g('y')
Traceback (most recent call last):
    ...
TypeError: The input_kwargs of a dag call is missing 1 required argument: 'w'
```

It needs a `w?`! No, it needs an `x`! But to get an `x` you need a `w`,
and…

```pycon
>>> g('x')
Traceback (most recent call last):
    ...
TypeError: The input_kwargs of a dag call is missing 1 required argument: 'w'
```

So let’s give it a w!

```pycon
>>> g('x', w=3)  # == 3 * 2 ==
6
```

And now this works:

```pycon
>>> g('x')
6
```

because

```pycon
>>> g.cache
{'x': 6}
```

and this will work too:

```pycon
>>> g('y')
7
>>> g.cache
{'x': 6, 'y': 7}
```

But this is something we need to handle better!

```pycon
>>> g('x', w=10)
6
```

This is happending because there’s already a x in the cache, and it takes precedence.
This would be okay if consider CachedDag as a low level object that is never
actually used by a user.
But we need to protect the user from such effects!

First, we probably should cache inputs too.

Then we can:

- Make computation take precedence over cache, overwriting the existing cache
  with the new resulting values
- Allow the user to declare the entire cache, or just some variables in it,
  as write-once, to avoid creating bugs with the above proposal.
- Cache multiple paths (lru_cache style) for different input combinations

#### roots_for(node)

The set of roots that lead to `node`.

```pycon
>>> from meshed.makers import code_to_dag
>>> @code_to_dag
... def dag():
...     x = mult(w, ww)
...     y = add(x, www)
...     z = subtract(x, y)
>>> print(dag.synopsis_string())
w,ww -> mult -> x
x,www -> add -> y
x,y -> subtract -> z
>>> g = CachedDag(dag)
>>> sorted(g.roots_for('x'))
['w', 'ww']
>>> sorted(g.roots_for('y'))
['w', 'ww', 'www']
```

### *class* meshed.scrap.cached_dag.NoOverwritesDict

Bases: [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)

A dict where you’re not allowed to write to a key that already has a value in it.

```pycon
>>> d = NoOverwritesDict(a=1, b=2)
>>> d
{'a': 1, 'b': 2}
```

Writing is allowed, in new keys

```pycon
>>> d['c'] = 3
>>> d
{'a': 1, 'b': 2, 'c': 3}
```

It’s also okay to write into an existing key if the value it holds is identical.
In fact, the write doesn’t even happen.

```pycon
>>> d['b'] = 2
```

But if we try to write a different value…

```pycon
>>> d['b'] = 22
Traceback (most recent call last):
    ...
cached_dag.OverWritesNotAllowedError: The b key already exists and you're not allowed to change its value
```

### *exception* meshed.scrap.cached_dag.NotAllowed

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

To use to indicate that something is not allowed

### *exception* meshed.scrap.cached_dag.OverWritesNotAllowedError

Bases: [`NotAllowed`](_autosummary/meshed.scrap.cached_dag.html.md#meshed.scrap.cached_dag.NotAllowed)

Error to raise when a writes to existing keys are not allowed

### meshed.scrap.cached_dag.cached_dag_test()

Covering issue [https://github.com/i2mint/meshed/issues/34](https://github.com/i2mint/meshed/issues/34)
about “CachedDag.cache should be populated with inputs that it was called on”


# _autosummary/meshed.scrap.collapse_and_expand.html.md

# meshed.scrap.collapse_and_expand

Ideas on collapsing and expanding nodes
See “Collapse and expand nodes” discussion:
[https://github.com/i2mint/meshed/discussions/54](https://github.com/i2mint/meshed/discussions/54)

### Functions

| [`collapse_function_calls`](_autosummary/meshed.scrap.collapse_and_expand.html.md#meshed.scrap.collapse_and_expand.collapse_function_calls)(src[, ...])               | Contract function calls in a source code string.                       |
|----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------|
| [`expand_function_calls`](_autosummary/meshed.scrap.collapse_and_expand.html.md#meshed.scrap.collapse_and_expand.expand_function_calls)(src[, call_func_name, ...]) | Inverse of collapse_function_calls.                                    |
| `expand_nodes`(dag[, nodes, is_node, ...])                                                         |                                                                        |
| `get_src_string`(src)                                                                              |                                                                        |
| [`remove_decorator_code`](_autosummary/meshed.scrap.collapse_and_expand.html.md#meshed.scrap.collapse_and_expand.remove_decorator_code)(src[, decorator_names])     | Remove the code corresponding to decorators from a source code string. |

### Classes

| [`CollapsedDAG`](_autosummary/meshed.scrap.collapse_and_expand.html.md#meshed.scrap.collapse_and_expand.CollapsedDAG)(dag)   | To collapse a DAG into a single function   |
|----------------------------------------------------------------------|--------------------------------------------|

### *class* meshed.scrap.collapse_and_expand.CollapsedDAG(dag)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

To collapse a DAG into a single function

This is useful for when you want to use a DAG as a function,
but you don’t want to see all the arguments.

### meshed.scrap.collapse_and_expand.collapse_function_calls(src, call_func_name='call', , rm_decorator='code_to_dag', include=None)

Contract function calls in a source code string.

That is, in source code, or a dag made from code_to_dag, replace calls of the form
`call(func, arg)` with `func(arg)`.

#### NOTE
Doesn’t work with arbitrary DAG src, only those made from code_to_dag.

### meshed.scrap.collapse_and_expand.expand_function_calls(src, call_func_name='call', , include=None)

Inverse of collapse_function_calls.
It replaces calls of the form `func(arg)` with `call(func, arg)`,
except when the function call is part of a function definition header.
If include is None, it expands all function calls.
If include is a list of function names, only those functions are expanded.
If include is a callable, it’s used as a filter function.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### meshed.scrap.collapse_and_expand.remove_decorator_code(src, decorator_names=None)

Remove the code corresponding to decorators from a source code string.
If decorator_names is None, will remove all decorators.
If decorator_names is an iterable of strings, will remove the decorators with those names.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### Examples

```pycon
>>> src = '''
... @decorator
... def func():
...     pass
... '''
>>> print(remove_decorator_code(src))
def func():
    pass
```

```pycon
>>> src = '''
... @decorator1
... @decorator2
... def func():
...     pass
... '''
>>> print(remove_decorator_code(src, "decorator1"))
@decorator2
def func():
    pass
```


# _autosummary/meshed.scrap.conversion.html.md

# meshed.scrap.conversion

Utils to convert graphs from one specification to another

### Functions

| `dot_to_ipython_image`(dot_src, \*[, prog, ...])   |    |
|----------------------------------------------------|----|
| `dot_to_nx`(dot_src)                               |    |
| `dot_to_pydot`(dot_src)                            |    |
| `ensure_dot_code`(x)                               |    |


# _autosummary/meshed.scrap.dask_graph_language.html.md

# meshed.scrap.dask_graph_language

How to make dags from the dask specification

See [https://docs.dask.org/en/latest/graphs.html#example](https://docs.dask.org/en/latest/graphs.html#example) for the specification

### Functions

| `add`(a, b)                                        |    |
|----------------------------------------------------|----|
| `inc`(i)                                           |    |
| `node_funcs_from_dask_graph_dict`(dask_graph_dict) |    |


# _autosummary/meshed.scrap.gk_with_networkx.html.md

# meshed.scrap.gk_with_networkx

seriously modified version of yahoo/graphkit

### Classes

| [`Data`](_autosummary/meshed.scrap.gk_with_networkx.html.md#meshed.scrap.gk_with_networkx.Data)(\*\*kwargs)                           | This wraps any data that is consumed or produced by a Operation.           |
|---------------------------------------------------------------------------------------------|----------------------------------------------------------------------------|
| [`NetworkOperation`](_autosummary/meshed.scrap.gk_with_networkx.html.md#meshed.scrap.gk_with_networkx.NetworkOperation)(\*\*kwargs)               |                                                                            |
| [`Operation`](_autosummary/meshed.scrap.gk_with_networkx.html.md#meshed.scrap.gk_with_networkx.Operation)([name, needs, provides, params]) | This is an abstract class representing a data transformation.              |
| [`optional`](_autosummary/meshed.scrap.gk_with_networkx.html.md#meshed.scrap.gk_with_networkx.optional)                                   | Input values in `needs` may be designated as optional using this modifier. |

### *class* meshed.scrap.gk_with_networkx.Data(\*\*kwargs)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

This wraps any data that is consumed or produced
by a Operation. This data should also know how to serialize
itself appropriately.
This class an “abstract” class that should be extended by
any class working with data in the HiC framework.

### *class* meshed.scrap.gk_with_networkx.NetworkOperation(\*\*kwargs)

Bases: [`Operation`](_autosummary/meshed.scrap.gk_with_networkx.html.md#meshed.scrap.gk_with_networkx.Operation)

#### set_execution_method(method)

Determine how the network will be executed.

* **Parameters:**
  **method** – If “parallel”, execute graph operations concurrently
  using a threadpool.

### *class* meshed.scrap.gk_with_networkx.Operation(name='None', needs=None, provides=None, params=<factory>)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

This is an abstract class representing a data transformation. To use this,
please inherit from this class and customize the `.compute` method to your
specific application.

Names may be given to this layer and its inputs and outputs. This is
important when connecting layers and data in a Network object, as the
names are used to construct the graph.

* **Parameters:**
  * **name** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – The name the operation (e.g. conv1, conv2, etc..)
  * **needs** ([`list`](https://docs.python.org/3/builtins/stdtypes.html#list)) – Names of input data objects this layer requires.
  * **provides** ([`list`](https://docs.python.org/3/builtins/stdtypes.html#list)) – Names of output data objects this provides.
  * **params** ([`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)) – 

    A dict of key/value pairs representing parameters
    associated with your operation. These values will be
    accessible using the `.params` attribute of your object.

    NOTE:
    : It’s important that any values stored in this
      argument must be pickelable.

#### compute(inputs)

This method must be implemented to perform this layer’s feed-forward
computation on a given set of inputs.

* **Parameters:**
  **inputs** ([*list*](https://docs.python.org/3/builtins/stdtypes.html#list)) – A list of [`Data`](_autosummary/meshed.scrap.gk_with_networkx.html.md#meshed.scrap.gk_with_networkx.Data) objects on which to run the layer’s
  feed-forward computation.
* **Returns list:**
  Should return a list of [`Data`](_autosummary/meshed.scrap.gk_with_networkx.html.md#meshed.scrap.gk_with_networkx.Data) objects representing
  the results of running the feed-forward computation on
  `inputs`.

### *class* meshed.scrap.gk_with_networkx.optional

Bases: [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

Input values in `needs` may be designated as optional using this modifier.
If this modifier is applied to an input value, that value will be input to
the `operation` if it is available.  The function underlying the
`operation` should have a parameter with the same name as the input value
in `needs`, and the input value will be passed as a keyword argument if
it is available.

Here is an example of an operation that uses an optional argument:

```default
from graphkit import operation, compose
from graphkit.modifiers import optional

# Function that adds either two or three numbers.
def myadd(a, b, c=0):
    return a + b + c

# Designate c as an optional argument.
graph = compose('mygraph')(
    operator(name='myadd', needs=['a', 'b', optional('c')], provides='sum')(myadd)
)

# The graph works with and without 'c' provided as input.
assert graph({'a': 5, 'b': 2, 'c': 4})['sum'] == 11
assert graph({'a': 5, 'b': 2})['sum'] == 7
```


# _autosummary/meshed.scrap.gui_interaction.html.md

# meshed.scrap.gui_interaction

This module contains some ideas around making a two-way interaction between meshed
and a GUI that will enable the construction of meshes as well as rendering them,
and possibly running them.

### meshed.scrap.gui_interaction.extract_tokens(string, pos=0, endpos=9223372036854775807)

Return a list of all non-overlapping matches of pattern in string.


# _autosummary/meshed.scrap.html.md

# meshed.scrap

For scrap only

### Modules

| [`annotations_to_meshes`](_autosummary/meshed.scrap.annotations_to_meshes.html.md#module-meshed.scrap.annotations_to_meshes)   | Code related to work on the "From annotated functions to meshes" discussion:                                                                                                                   |
|--------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`cached_dag`](_autosummary/meshed.scrap.cached_dag.html.md#module-meshed.scrap.cached_dag)                         |                                                                                                                                                                                                |
| [`collapse_and_expand`](_autosummary/meshed.scrap.collapse_and_expand.html.md#module-meshed.scrap.collapse_and_expand)       | Ideas on collapsing and expanding nodes See "Collapse and expand nodes" discussion: [https://github.com/i2mint/meshed/discussions/54](https://github.com/i2mint/meshed/discussions/54)         |
| [`conversion`](_autosummary/meshed.scrap.conversion.html.md#module-meshed.scrap.conversion)                         | Utils to convert graphs from one specification to another                                                                                                                                      |
| [`dask_graph_language`](_autosummary/meshed.scrap.dask_graph_language.html.md#module-meshed.scrap.dask_graph_language)       | How to make dags from the dask specification                                                                                                                                                   |
| [`gk_with_networkx`](_autosummary/meshed.scrap.gk_with_networkx.html.md#module-meshed.scrap.gk_with_networkx)             | seriously modified version of yahoo/graphkit                                                                                                                                                   |
| [`gui_interaction`](_autosummary/meshed.scrap.gui_interaction.html.md#module-meshed.scrap.gui_interaction)               | This module contains some ideas around making a two-way interaction between meshed and a GUI that will enable the construction of meshes as well as rendering them, and possibly running them. |
| [`misc_utils`](_autosummary/meshed.scrap.misc_utils.html.md#module-meshed.scrap.misc_utils)                         | Misc utils                                                                                                                                                                                     |
| [`reactive_scope`](_autosummary/meshed.scrap.reactive_scope.html.md#module-meshed.scrap.reactive_scope)                 | Ideas towards a reactive-programming interpretation of meshes.                                                                                                                                 |
| [`wrapping_dags`](_autosummary/meshed.scrap.wrapping_dags.html.md#module-meshed.scrap.wrapping_dags)                   | Wrapping dags                                                                                                                                                                                  |


# _autosummary/meshed.scrap.misc_utils.html.md

# meshed.scrap.misc_utils

Misc utils

### Functions

| `coparents_sets`(g, source)                                                                     |                                                           |
|-------------------------------------------------------------------------------------------------|-----------------------------------------------------------|
| `dag_from_funcnodes`(dag, input_names)                                                          |                                                           |
| `extended_family`(g, source)                                                                    |                                                           |
| `funcnode_only`(source)                                                                         |                                                           |
| `kids_of_united_family`(g, source)                                                              |                                                           |
| `known_parents`(g, kid, source)                                                                 |                                                           |
| `list_coparents`(g, coparent)                                                                   |                                                           |
| [`mermaid_pack_nodes`](_autosummary/meshed.scrap.misc_utils.html.md#meshed.scrap.misc_utils.mermaid_pack_nodes)(mermaid_code, nodes[, ...]) | Output mermaid code with nodes packed into a single node. |

### meshed.scrap.misc_utils.mermaid_pack_nodes(mermaid_code, nodes, packed_node_name=None, , arrow='-->')

Output mermaid code with nodes packed into a single node.

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

```pycon
>>> mermaid_code = '''
... graph TD
...   A --> B
...   B --> C
...   A --> D
...   D --> E
...   E --> C
... '''
>>>
>>>
>>> print(mermaid_pack_nodes(mermaid_code, ['B', 'C', 'E'], 'BCE'))
graph TD
A -->BCE
A --> D
D -->BCE
```


# _autosummary/meshed.scrap.reactive_scope.html.md

# meshed.scrap.reactive_scope

Ideas towards a reactive-programming interpretation of meshes.
A scope (MutableMapping –think dict-like) that reacts to writes by computing
associated functions, themselves writing in the scope, creating a chain reaction that
propagates information through the scope.

### Classes

| [`ReactiveFuncNode`](_autosummary/meshed.scrap.reactive_scope.html.md#meshed.scrap.reactive_scope.ReactiveFuncNode)(func[, name, bind, out, ...])   | A `FuncNode` that computes on a scope only if the scope has what it takes                                                                                                  |
|---------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`ReactiveScope`](_autosummary/meshed.scrap.reactive_scope.html.md#meshed.scrap.reactive_scope.ReactiveScope)([func_nodes, scope_factory])       | A scope that reacts to writes by computing associated functions, themselves writing in the scope, creating a chain reaction that propagates information through the scope. |

### *class* meshed.scrap.reactive_scope.ReactiveFuncNode(func, name=None, bind=<factory>, out=None, func_label=None, names_maker=<function underscore_func_node_names_maker>, node_validator=<function basic_node_validator>)

Bases: [`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)

A `FuncNode` that computes on a scope only if the scope has what it takes

#### call_on_scope(scope, write_output_into_scope=True)

Call the function using the given scope both to source arguments and write
results.

#### NOTE
This method is only meant to be used as a backend to \_\_call_\_, not as
an actual interface method. Additional control/constraints on read and writes
can be implemented by providing a custom scope for that.

### *class* meshed.scrap.reactive_scope.ReactiveScope(func_nodes=(), scope_factory=<class 'dict'>)

Bases: [`MutableMapping`](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableMapping)

A scope that reacts to writes by computing associated functions, themselves writing
in the scope, creating a chain reaction that propagates information through the
scope.

* **Parameters:**
  * **func_nodes** (*Iterable* *[*[*ReactiveFuncNode*](_autosummary/meshed.scrap.reactive_scope.html.md#meshed.scrap.reactive_scope.ReactiveFuncNode) *]*) – The functions that will be called when the scope is written to.
  * **scope_factory** (*Callable* *[* *[* *]* *,* *MutableMapping* *]*) – A factory that returns a new scope. The scope will be cleared by calling this
    factory at each call to `.clear()`.

### Examples

First, we need some func nodes to define the reaction relationships.
We’ll stuff these func nodes in a DAG, for ease of use, but it’s not necessary.

```pycon
>>> from meshed import FuncNode, DAG
>>>
>>> def f(a, b):
...     return a + b
>>> def g(a_plus_b, d):
...     return a_plus_b * d
>>> f_node = FuncNode(func=f, out='a_plus_b')
>>> g_node = FuncNode(func=g, bind={'d': 'b'})
>>> d = DAG((f_node, g_node))
>>>
>>> print(d.dot_digraph_ascii())

              a

            │
            │
            ▼
          ┌────────┐
  b   ──▶ │   f    │
          └────────┘
  │         │
  │         │
  │         ▼
  │
  │        a_plus_b
  │
  │         │
  │         │
  │         ▼
  │       ┌────────┐
  └─────▶ │   g_   │
          └────────┘
            │
            │
            ▼

              g
```

Now we make a scope with these func nodes.

```pycon
>>> s = ReactiveScope(d)
```

The scope starts empty (by default).

```pycon
>>> s
<ReactiveScope with .scope: {}>
```

So if we try to access any key, we’ll get a KeyError.

```pycon
>>> s['g']
Traceback (most recent call last):
  ...
KeyError: 'g'
```

That’s because we didn’t put write anything in the scope yet.

But, if you give `g_` enough data to be able to compute `g` (namely, if you
write values of `b` and `a_plus_b`), then `g` will automatically be computed.

```pycon
>>> s['b'] = 3
>>> s['a_plus_b'] = 5
>>> s
<ReactiveScope with .scope: {'b': 3, 'a_plus_b': 5, 'g': 15}>
```

So now we can access `g`.

```pycon
>>> s['g']
15
```

Note though, that we first showed that `g` appeared in the scope before we
explicitly asked for it. This was to show that `g` was computed as a
side-effect of writing to the scope, not because we asked for it, triggering the
computation

Let’s clear the scope and show that by specifying `a` and `b`, we get all the
other values of the network.

```pycon
>>> s.clear()
>>> s
<ReactiveScope with .scope: {}>
>>> s['a'] = 3
>>> s['b'] = 4
>>> s
<ReactiveScope with .scope: {'a': 3, 'b': 4, 'a_plus_b': 7, 'g': 28}>
>>> s['g']  # (3 + 4) * 4 == 7 * 4 == 28
28
```

#### clear()

#### NOTE
This actually doesn’t clear the mapping, but rather, resets it to it’s original state,
as defined by the `.scope_factory`


# _autosummary/meshed.scrap.wrapping_dags.html.md

# meshed.scrap.wrapping_dags

Wrapping dags

### Functions

| `test_ddag`()   |    |
|-----------------|----|

### Classes

| [`DDag`](_autosummary/meshed.scrap.wrapping_dags.html.md#meshed.scrap.wrapping_dags.DDag)([func_nodes, cache_last_scope, ...])   |    |
|----------------------------------------------------------------------------------------------|----|

### *class* meshed.scrap.wrapping_dags.DDag(func_nodes=(), cache_last_scope=True, parameter_merge=functools.partial(<function parameter_merger>, same_kind=True, same_default=True, same_annotation=True), new_scope=<class 'dict'>, name=None, extract_output_from_scope=<function extract_values>)

Bases: [`DAG`](_autosummary/meshed.dag.html.md#meshed.dag.DAG)


# _autosummary/meshed.slabs.html.md

# meshed.slabs

Tools to generate slabs.

A slab is a dict that holds data generated by a stream for a given interval of time.

The main object of this module is `Slabs`, and object that defines how to
generate multiple streams, in the form of slabs.
More precisely, it defines how to source streams, operate on and combine these to create
further streams, and even push these streams to further processes, all through a single
simple interface: An (ordered) list of components that are called in sequence to either
pull data from some sources, compute a new stream based on previous ones, or push some
of the streams to further processes (such as visualization, or storage systems).

Main entry points:

- `Slabs`: the stream-of-slabs object; iterate it, or `run()` it for side effects.
- `IteratorExit`: raise it from a component to stop the iteration cleanly.
- `conditional_sentinel`: decorator returning a sentinel instead of calling the function
  when a condition on its arguments holds (`output_none_if_none_arguments` is one).

A slab is a collection of items of a same interval of time.
We represent a slab using a `dict` or mapping.
Typically, a slab will be the aggregation of multiple information streams that
happened around the same time.

`Slabs` is a tool that allows you to source multiple streams into a stream of
slabs that can contain the original data, or other datas computed from it, or both.

Note to developers, though the code below is a reduced form of the actual code,
it should be enough to understand the general idea.
For a discussion about the design of Slabs, see
[https://github.com/i2mint/meshed/discussions/49](https://github.com/i2mint/meshed/discussions/49).

```pycon
>>> class Slabs:
...     def _call_on_scope(self, scope):
...         '''
...         Calls the components 1 by 1, sourcing inputs and writing outputs in scope
...         '''
...
...     def __next__(self):
...         '''Get the next slab by calling _call_on_scope on an new empty scope.
...         At least one of the components will have to be argument-less and provide
...         some data for other components to get their inputs from, if any are needed.
...         '''
...         return self._call_on_scope(scope={})
...
...     def __iter__(self):
...         '''Iterates over slabs until a handle exception is raised.'''
...         # Simplified code:
...         with self:  # enter all the contexts that need to be entered
...             while True:  # loop until you encounter a handled exception
...                 try:
...                     yield next(self)
...                 except self.handle_exceptions as exc_val:
...                     # use specific exceptions to signal that iteration should stop
...                     break
```

### Functions

| [`all_arguments_are_none`](_autosummary/meshed.slabs.html.md#meshed.slabs.all_arguments_are_none)(args, kwargs)             | Return True if all arguments are None.                               |
|---------------------------------------------------------------------------------------------------|----------------------------------------------------------------------|
| [`conditional_sentinel`](_autosummary/meshed.slabs.html.md#meshed.slabs.conditional_sentinel)(condition_func[, sentinel]) | Decorator that returns sentinel based on a user-defined condition.   |
| [`do_nothing`](_autosummary/meshed.slabs.html.md#meshed.slabs.do_nothing)()                                     | Argument-less no-op, the default handler of handled exceptions.      |
| [`log_and_return`](_autosummary/meshed.slabs.html.md#meshed.slabs.log_and_return)(msg[, logger])                    | Pass `msg` to `logger` (`print` by default) and return it unchanged. |
| [`output_none_if_none_arguments`](_autosummary/meshed.slabs.html.md#meshed.slabs.output_none_if_none_arguments)(func)              | Decorator that returns None if all arguments are None.               |

### Classes

| `DoNotBreak`()                                                                             |                                                                                                                    |
|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
| [`ExceptionHandler`](_autosummary/meshed.slabs.html.md#meshed.slabs.ExceptionHandler)(\*args, \*\*kwargs)      | An exception handler is an argument-less callable that is called when a handled exception occurs during iteration. |
| [`Slabs`](_autosummary/meshed.slabs.html.md#meshed.slabs.Slabs)([handle_exceptions, scope_factory]) | Object to source and manipulate multiple streams.                                                                  |
| [`SlabsIter`](_autosummary/meshed.slabs.html.md#meshed.slabs.SlabsIter)                                 |                                                                                                                    |

### Exceptions

| [`ExceptionalException`](_autosummary/meshed.slabs.html.md#meshed.slabs.ExceptionalException)   | Raised when an exception was supposed to be handled, but no matching handler was found.                                 |
|-------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|
| [`IteratorExit`](_autosummary/meshed.slabs.html.md#meshed.slabs.IteratorExit)           | Raised when an iterator should quit being iterated on, signaling this event any process that cares to catch the signal. |

### *class* meshed.slabs.ExceptionHandler(\*args, \*\*kwargs)

Bases: [`Protocol`](https://docs.python.org/3/library/typing.html#typing.Protocol)

An exception handler is an argument-less callable that is called when a handled
exception occurs during iteration. Most often, the handler does nothing,
but could be used whose output will be ignored, unless it is do_not_break,
which will signal that the iteration should continue.

### *exception* meshed.slabs.ExceptionalException

Bases: [`Exception`](https://docs.python.org/3/builtins/exceptions.html#Exception)

Raised when an exception was supposed to be handled, but no matching handler
was found.

See the `_handle_exception` function, where it is raised.

### *exception* meshed.slabs.IteratorExit

Bases: [`BaseException`](https://docs.python.org/3/builtins/exceptions.html#BaseException)

Raised when an iterator should quit being iterated on, signaling this event
any process that cares to catch the signal.
We chose to inherit directly from `BaseException` instead of `Exception`
for the same reason that `GeneratorExit` does: Because it’s not technically
an error.

See: [https://docs.python.org/3/library/exceptions.html#GeneratorExit](https://docs.python.org/3/library/exceptions.html#GeneratorExit)

### *class* meshed.slabs.Slabs(handle_exceptions=(<class 'StopIteration'>, <class 'meshed.slabs.IteratorExit'>, <class 'KeyboardInterrupt'>), scope_factory=<class 'dict'>, \*\*components)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Object to source and manipulate multiple streams.

A slab is a collection of items of a same interval of time.
We represent a slab using a `dict` or mapping.
Typically, a slab will be the aggregation of multiple information streams that
happened around the same time.

For example, say and edge device had a microphone, light, and movement sensor.
An aggregate reading of these sensors could give you something like:

```pycon
>>> slab = {'audio': [1, 2, 4], 'light': 126, 'movement': None}
```

`movement` is `None` because the sensor is off. If it were on, we’d have True or
False as values.

From this information, you’d like to compute a `turn_mov_on` value based on the
formula.

```pycon
>>> from statistics import stdev
>>> vol = stdev
>>> should_turn_movement_sensor_on = lambda audio, light: vol(audio) * light > 50000
```

The produce of the volume and the lumens gives you 192, so you now have…

```pycon
>>> slab = {
...     'audio': [1, 2, 4],
...     'light': 126,
...     'should_turn_movement_sensor_on': False,
...     'movement': None
... }
```

The next slab that comes in is

```pycon
>>> slab = {'audio': [-96, 89, -92], 'light': 501, 'movement': None}
```

which puts us over the threshold so

```pycon
>>> slab = {
...     'audio': [-96, 89, -92],
...     'light': 501,
...     'should_turn_movement_sensor_on': True,
...     'movement': None
... }
```

and the movement sensor is turned on, the movement is detected, a `human_presence`
signal is computed, and a notification sent if that metric is above a given theshold.

The point here is that we incrementally compute various fields, enhancing our slab
of information, and we do so iteratively over over slab that is streaming to us
from our smart home device.

`SlabsIter` is there to help you create such slabs, from source to enhanced.

The situation above would look something along like this:

```pycon
>>> from statistics import stdev
>>>
>>> vol = stdev
>>>
>>> # Making a slabs iter object
>>> def make_a_slabs_iter():
...
...     # Mocking the sensor readers
...     audio_sensor_read = iter([[1, 2, 3], [-96, 87, -92], [320, -96, 99]]).__next__
...     light_sensor_read = iter([126, 501, 523]).__next__
...     movement_sensor_read = iter([None, None, True]).__next__
...
...     return Slabs(
...         # The first three components get data from the sensors.
...         # The *_read objects are all callable, returning the next
...         # chunk of data for that sensor, if any.
...         audio=audio_sensor_read,
...         light=light_sensor_read,
...         movement=movement_sensor_read,
...         # The next
...         should_turn_movement_sensor_on = lambda audio, light: vol(audio) * light > 50000,
...         human_presence_score = lambda audio, light, movement: movement and sum([vol(audio), light]),
...         should_notify = lambda human_presence_score: human_presence_score and human_presence_score > 700,
...         notify = lambda should_notify: print('someone is there') if should_notify else None
...     )
...
>>>
>>> si = make_a_slabs_iter()
>>> next(si)
{'audio': [1, 2, 3],
 'light': 126,
 'movement': None,
 'should_turn_movement_sensor_on': False,
 'human_presence_score': None,
 'should_notify': None,
 'notify': None}
>>> next(si)
{'audio': [-96, 87, -92],
 'light': 501,
 'movement': None,
 'should_turn_movement_sensor_on': True,
 'human_presence_score': None,
 'should_notify': None,
 'notify': None}
>>> next(si)
someone is there
{'audio': [320, -96, 99],
 'light': 523,
 'movement': True,
 'should_turn_movement_sensor_on': True,
 'human_presence_score': 731.1353726143957,
 'should_notify': True,
 'notify': None}
```

If you ask for the next slab, you’ll get a `StopIteration` (raised by the mocked
sources since they reached the end of their iterators).

```pycon
>>> next(si)
Traceback (most recent call last):
  ...
StopIteration
```

That said, if you iterate through a `SlabsIter` that handles the `StopIteration`
exception (it does by default), you’ll reach the end of you iteration gracefully.

```pycon
>>> si = make_a_slabs_iter()
>>> for slab in si:
...     pass
someone is there
>>> si = make_a_slabs_iter()
>>> slabs = list(si)  # gather all the slabs
someone is there
>>> len(slabs)
3
>>> slabs[-1]
{'audio': [320, -96, 99],
 'light': 523,
 'movement': True,
 'should_turn_movement_sensor_on': True,
 'human_presence_score': 731.1353726143957,
 'should_notify': True,
 'notify': None}
```

Note that `Slabs` uses a “scope” to store the intermediate results of the
computation. This scope is a `dict` by default, but you can pass any
`MutableMapping` to the `scope_factory` argument. This means that you can use
other means to store intermediate results simply by wrapping them in a
MutableMapping. For example, you could use message broker such as Redis to
store the intermediate results, and have the components read and write to it.

To help you with this, check out the [dol](https://pypi.org/project/dol/)
and [py2store](https://pypi.org/project/py2store/) libraries.

#### close(exc_type=None, exc_val=None, exc_tb=None)

Exit the component contexts entered by `open`.

* **Return type:**
  [`None`](https://docs.python.org/3/builtins/constants.html#None)

#### dot_digraph(\*args, \*\*kwargs)

Returns a dot_digraph of the DAG of the SlabsIter (see `DAG.dot_digraph`)

#### *classmethod* from_dag(func_nodes, \*, handle_exceptions=(<class 'StopIteration'>, <class 'meshed.slabs.IteratorExit'>, <class 'KeyboardInterrupt'>), scope_factory=<class 'dict'>)

Make a Slabs object from a list of functions and/or FuncNodes, DAG, …

#### *classmethod* from_func_nodes(func_nodes, \*, handle_exceptions=(<class 'StopIteration'>, <class 'meshed.slabs.IteratorExit'>, <class 'KeyboardInterrupt'>), scope_factory=<class 'dict'>)

Make a Slabs object from a list of functions and/or FuncNodes, DAG, …

#### open()

Enter the context of every component that has one, and return `self`.

#### run()

Iterate through all the slabs, discarding them (for the side effects only).

#### to_dag()

Build a `DAG` from the `FuncNode` objects of `to_func_nodes`.

* **Return type:**
  [`DAG`](_autosummary/meshed.dag.html.md#meshed.dag.DAG)

#### to_func_nodes()

Yield a `FuncNode` per component.

Each node’s name and output var node are the component’s name.

* **Return type:**
  [`Iterable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Iterable)[[`FuncNode`](_autosummary/meshed.base.html.md#meshed.base.FuncNode)]

### meshed.slabs.SlabsIter

alias of [`Slabs`](_autosummary/meshed.slabs.html.md#meshed.slabs.Slabs)

### meshed.slabs.all_arguments_are_none(args, kwargs)

Return True if all arguments are None.

### meshed.slabs.conditional_sentinel(condition_func, sentinel=None)

Decorator that returns sentinel based on a user-defined condition.

The condition function should take the arguments and keyword arguments of the
decorated function as input and return a boolean value. If the condition is met,
the sentinel value is returned instead of the decorated function’s return value.

* **Parameters:**
  * **condition_func** ([`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[[`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple), [`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)], [`bool`](https://docs.python.org/3/builtins/functions.html#bool)]) – A function that takes the arguments and keyword
    arguments of the decorated function as input and returns a boolean value.
  * **sentinel** ([`Any`](https://docs.python.org/3/library/typing.html#typing.Any)) – The value to return if the condition is met.

```pycon
>>> division_by_zero = lambda args, kwargs: (
...     (len(args) >= 2 and args[1] == 0) or
...     kwargs.get('y') == 0
... )
>>>
>>> @conditional_sentinel(division_by_zero, sentinel=0)
... def safe_division(x, y):
...     return x / y
...
>>> safe_division(10, 2)
5.0
>>> safe_division(10, 0)
0
>>>
```

See also `output_none_if_none_arguments`, made from `conditional_sentinel`:

```pycon
>>> @output_none_if_none_arguments
... def foo(x, y):
...     return x + y
>>>
>>> foo(1, 2)
3
>>> assert foo(None, None) is None
```

### meshed.slabs.do_nothing()

Argument-less no-op, the default handler of handled exceptions.

Its `None` output lets the `Slabs` iteration stop.

### meshed.slabs.log_and_return(msg, logger=<built-in function print>)

Pass `msg` to `logger` (`print` by default) and return it unchanged.

### meshed.slabs.output_none_if_none_arguments(func)

Decorator that returns None if all arguments are None.

```pycon
>>> @output_none_if_none_arguments
... def foo(x, y):
...     return x + y
>>>
>>> foo(1, 2)
3
>>> assert foo(None, None) is None
```


# _autosummary/meshed.tools.html.md

# meshed.tools

Tools to work with meshed

### Functions

| `find_funcs`(dag, func_outs)                                                                 |                                                                             |
|----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
| [`launch_funcs_webservice`](_autosummary/meshed.tools.html.md#meshed.tools.launch_funcs_webservice)(funcs)              | Launches a web service application with the specified functions.            |
| [`launch_webservice`](_autosummary/meshed.tools.html.md#meshed.tools.launch_webservice)(funcs_to_cloudify[, ...]) | Context manager to launch a web service application in a separate process.  |
| [`mk_dag_with_ws_funcs`](_autosummary/meshed.tools.html.md#meshed.tools.mk_dag_with_ws_funcs)(dag, ws_funcs)         | Creates a new DAG with the web service functions.                           |
| [`mk_hybrid_dag`](_autosummary/meshed.tools.html.md#meshed.tools.mk_hybrid_dag)(dag, func_ids_to_cloudify)    | Creates a hybrid DAG that uses the web service for the specified functions. |

### Classes

| `CloudFunctions`(funcs[, openapi_url, logger])   |    |
|--------------------------------------------------|----|

### meshed.tools.launch_funcs_webservice(funcs)

Launches a web service application with the specified functions.

* **Parameters:**
  **funcs** ([`list`](https://docs.python.org/3/builtins/stdtypes.html#list)[[`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)]) – functions to be hosted by the web service

### meshed.tools.launch_webservice(funcs_to_cloudify, wait_after_start_seconds=10)

Context manager to launch a web service application in a separate process.

### meshed.tools.mk_dag_with_ws_funcs(dag, ws_funcs)

Creates a new DAG with the web service functions.

* **Parameters:**
  * **dag** ([`DAG`](_autosummary/meshed.dag.html.md#meshed.dag.DAG)) – DAG to be hybridized
  * **ws_funcs** ([`dict`](https://docs.python.org/3/builtins/stdtypes.html#dict)) – mapping of web service functions
* **Returns:**
  new DAG with the web service functions
* **Return type:**
  [`DAG`](_autosummary/meshed.dag.html.md#meshed.dag.DAG)

### meshed.tools.mk_hybrid_dag(dag, func_ids_to_cloudify)

Creates a hybrid DAG that uses the web service for the specified functions.

* **Parameters:**
  * **dag** ([`DAG`](_autosummary/meshed.dag.html.md#meshed.dag.DAG)) – dag to be hybridized
  * **func_ids_to_cloudify** ([`list`](https://docs.python.org/3/builtins/stdtypes.html#list)) – list of function ids to be cloudified
* **Returns:**
  namedtuple with funcs_to_cloudify, ws_dag and ws_funcs
* **Return type:**
  namedtuple


# _autosummary/meshed.util.html.md

# meshed.util

Function-wrapping, naming, and small data helpers shared across `meshed`.

Most of what lives here is glue that the DAG machinery leans on: decorators
that turn a scalar function into one that maps over a stream (`iterize`,
`ConditionalIterize`), name generation that avoids clashes when several
functions share argument names (`find_first_free_name`, `mk_func_name`,
`arg_names`), signature reconciliation (`parameter_merger`), and dict
and iterable utilities (`extract_values`, `replace_item_in_iterable`).
A few graph-rendering helpers (`funcs_to_digraph`, `dot_to_ascii`) are
also kept here.

Main entry points:

- `iterize`: wrap `func` so it maps over an iterable (a partial of `map`).
- `ConditionalIterize`: iterize a call only when the first argument satisfies
  a condition (by default, when it is an `Iterator`).
- `provides`: decorator that records, on `func._provides`, the var node
  names a function can source.
- `parameter_merger`: check that several `inspect.Parameter` objects agree
  (name, kind, default, annotation) and return the first, raising
  `ValidationError` otherwise.
- `replace_item_in_iterable`: replace items of an iterable that satisfy a
  condition, keeping the container type for lists, tuples and sets.

```pycon
>>> from meshed.util import iterize
>>> times_ten = iterize(lambda x: x * 10)
>>> list(times_ten(iter([1, 2, 3])))
[10, 20, 30]
```

### Functions

| [`arg_names`](_autosummary/meshed.util.html.md#meshed.util.arg_names)(func, func_name[, exclude_names])       | List `func`'s parameter names, renaming those found in `exclude_names`.                                                                                                 |
|----------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`args_funcnames`](_autosummary/meshed.util.html.md#meshed.util.args_funcnames)(funcs[, name_of_func])             | Generates (arg_name, func_id) pairs from the iterable of functions                                                                                                      |
| [`conditional_trans`](_autosummary/meshed.util.html.md#meshed.util.conditional_trans)(obj, condition, trans)          | Conditionally transform an object unless it is marked as a literal.                                                                                                     |
| [`curry`](_autosummary/meshed.util.html.md#meshed.util.curry)(func)                                       | Wrap `func` so that positional arguments are passed to it as a single tuple.                                                                                            |
| [`dot_to_ascii`](_autosummary/meshed.util.html.md#meshed.util.dot_to_ascii)(dot[, fancy])                        | Convert a dot string to an ascii rendering of the diagram.                                                                                                              |
| [`extra_wraps`](_autosummary/meshed.util.html.md#meshed.util.extra_wraps)(func[, name, doc_prefix])             | Set `func.__name__` and `func.__doc__` in place, returning `func`.                                                                                                      |
| [`extract_dict`](_autosummary/meshed.util.html.md#meshed.util.extract_dict)(d, keys)                             | Extract items from dict `d`, returning them as a dict.                                                                                                                  |
| [`extract_items`](_autosummary/meshed.util.html.md#meshed.util.extract_items)(d, keys)                            | generator of (k, v) pairs extracted from d for keys                                                                                                                     |
| [`extract_values`](_autosummary/meshed.util.html.md#meshed.util.extract_values)(d, keys)                           | Extract values from dict `d`, returning them:                                                                                                                           |
| [`filepath_to_module`](_autosummary/meshed.util.html.md#meshed.util.filepath_to_module)(file_path)                     | A context manager to import a Python file as a module.                                                                                                                  |
| [`find_first_free_name`](_autosummary/meshed.util.html.md#meshed.util.find_first_free_name)(prefix[, ...])               | Return `prefix`, or the first `f"{prefix}__{i}"` not in `exclude_names`.                                                                                                |
| [`func_name`](_autosummary/meshed.util.html.md#meshed.util.func_name)(func)                                   | The func._\_name_\_ of a callable func, or makes and returns one if that fails.                                                                                         |
| [`funcs_conjunction`](_autosummary/meshed.util.html.md#meshed.util.funcs_conjunction)(\*funcs)                        | Makes a conjunction of functions.                                                                                                                                       |
| [`funcs_disjunction`](_autosummary/meshed.util.html.md#meshed.util.funcs_disjunction)(\*funcs)                        | Makes a disjunction of functions.                                                                                                                                       |
| [`funcs_to_digraph`](_autosummary/meshed.util.html.md#meshed.util.funcs_to_digraph)(funcs[, graph])                  | Add `(arg_name, func_name)` edges of `funcs` to a `graphviz.Digraph`.                                                                                                   |
| [`if_then_else`](_autosummary/meshed.util.html.md#meshed.util.if_then_else)(if_func, then_func, else_func, ...)  | Tool to "functionalize" the if-then-else logic.                                                                                                                         |
| [`incremental_str_maker`](_autosummary/meshed.util.html.md#meshed.util.incremental_str_maker)([str_format])               | Make a function that will produce a (incrementally) new string at every call.                                                                                           |
| [`instance_checker`](_autosummary/meshed.util.html.md#meshed.util.instance_checker)(class_or_tuple)                  | Makes a boolean function that checks the instance of an object                                                                                                          |
| [`inverse_dict_asserting_losslessness`](_autosummary/meshed.util.html.md#meshed.util.inverse_dict_asserting_losslessness)(d)            | Invert `d` (values become keys), asserting that no values are duplicated.                                                                                               |
| [`iterize`](_autosummary/meshed.util.html.md#meshed.util.iterize)(func[, name])                             | From an Input->Output function, makes a Iterator[Input]->Iterator[Output] Some call this "vectorization", but it's not really a vector, but an iterable, thus the name. |
| `lambda_name`()                                                                                    |                                                                                                                                                                         |
| [`mk_func_name`](_autosummary/meshed.util.html.md#meshed.util.mk_func_name)(func[, exclude_names])               | Makes a function name that doesn't clash with the exclude_names iterable.                                                                                               |
| [`mk_place_holder_func`](_autosummary/meshed.util.html.md#meshed.util.mk_place_holder_func)(arg_names_or_sig[, ...])     | Make (working and picklable) function with a specific signature.                                                                                                        |
| [`my_isinstance`](_autosummary/meshed.util.html.md#meshed.util.my_isinstance)(obj, class_or_tuple)                | Same as builtin instance, but without position only constraint.                                                                                                         |
| [`mywraps`](_autosummary/meshed.util.html.md#meshed.util.mywraps)(func[, name, doc_prefix])                 | Make a decorator applying `functools.wraps(func)` then `extra_wraps` to a callable.                                                                                     |
| [`named_partial`](_autosummary/meshed.util.html.md#meshed.util.named_partial)(func, \*args[, \_\_name_\_])        | functools.partial, but with a \_\_name_\_                                                                                                                               |
| [`numbered_suffix_renamer`](_autosummary/meshed.util.html.md#meshed.util.numbered_suffix_renamer)(name[, sep])              | Append `sep + "1"` to `name`, or increment its existing numbered suffix.                                                                                                |
| [`objects_defined_in_module`](_autosummary/meshed.util.html.md#meshed.util.objects_defined_in_module)(module, \*[, ...])      | Get a dictionary of objects defined in a Python module, optionally filtered by their names and values.                                                                  |
| [`ordered_set_operations`](_autosummary/meshed.util.html.md#meshed.util.ordered_set_operations)(a, b)                      | Returns a triple (a-b, a&b, b-a) for two iterables a and b.                                                                                                             |
| [`pairs`](_autosummary/meshed.util.html.md#meshed.util.pairs)(xs)                                         | List the consecutive `(xs[i], xs[i+1])` pairs of a sequence.                                                                                                            |
| [`parameter_merger`](_autosummary/meshed.util.html.md#meshed.util.parameter_merger)(\*params[, same_name, ...])      | Validates that all the params are exactly the same, returning the first if so.                                                                                          |
| [`print_ascii_graph`](_autosummary/meshed.util.html.md#meshed.util.print_ascii_graph)(funcs)                          | Print an ascii rendering of `funcs_to_digraph(funcs)`.                                                                                                                  |
| [`provides`](_autosummary/meshed.util.html.md#meshed.util.provides)(\*var_names)                             | Decorator to assign `var_names` to a `_provides` attribute of function.                                                                                                 |
| [`replace_item_in_iterable`](_autosummary/meshed.util.html.md#meshed.util.replace_item_in_iterable)(iterable, ...[, egress]) | Returns a list where all items satisfying `condition(item)` were replaced with `replacement(item)`.                                                                     |
| [`uncurry`](_autosummary/meshed.util.html.md#meshed.util.uncurry)(func)                                     | Wrap `func` so that it takes one tuple and unpacks it into positional arguments.                                                                                        |
| `unnameable_func_name`()                                                                           |                                                                                                                                                                         |

### Classes

| [`ConditionalIterize`](_autosummary/meshed.util.html.md#meshed.util.ConditionalIterize)(func[, iterize_type, ...])   | A decorator that "iterizes" a function call if input satisfies a condition.   |
|--------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
| [`ModuleNotFoundIgnore`](_autosummary/meshed.util.html.md#meshed.util.ModuleNotFoundIgnore)()                          | Context manager that suppresses any exception raised inside its block.        |

### Exceptions

| [`InvalidFunctionParameters`](_autosummary/meshed.util.html.md#meshed.util.InvalidFunctionParameters)   | To be used when a function's parameters are not compliant with some rule about them.   |
|------------------------------------------------------------------------------|----------------------------------------------------------------------------------------|
| [`NameValidationError`](_autosummary/meshed.util.html.md#meshed.util.NameValidationError)         | Use to indicate that there's a problem with a name or generating a valid name          |
| [`NotFound`](_autosummary/meshed.util.html.md#meshed.util.NotFound)                    | To be raised when something is expected to exist, but doesn't                          |
| [`NotUniqueError`](_autosummary/meshed.util.html.md#meshed.util.NotUniqueError)              | Error to be raised when unicity is expected, but violated                              |
| [`ValidationError`](_autosummary/meshed.util.html.md#meshed.util.ValidationError)             | Error that is raised when an object's validation failed                                |

### *class* meshed.util.ConditionalIterize(func, iterize_type=<class 'collections.abc.Iterator'>, iterize_condition=None)

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

A decorator that “iterizes” a function call if input satisfies a condition.
That is, apply `map(func, input)` (iterize) or `func(input)` according to some
conidition on `input`.

```pycon
>>> def foo(x, y=2):
...     return x * y
```

The function does this:

```pycon
>>> foo(3)
6
>>> foo('string')
'stringstring'
```

The iterized version of the function does this:

```pycon
>>> iterized_foo = iterize(foo)
>>> list(iterized_foo([1, 2, 3]))
[2, 4, 6]
```

```pycon
>>> from typing import Iterable
>>> new_foo = ConditionalIterize(foo, Iterable)
>>> new_foo(3)
6
>>> list(new_foo([1, 2, 3]))
[2, 4, 6]
```

See what happens if we do this:

```pycon
>>> list(new_foo('string'))
['ss', 'tt', 'rr', 'ii', 'nn', 'gg']
```

Maybe you expected `'stringstring'` because you are thinking of `string` as a valid,
single input. But the condition of iterization is to be an Iterable, which a
string is, thus the (perhaps) unexpected result.

In fact, this problem is a general one:
If your base function doesn’t process iterables, the `isinstance(x, Iterable)`
is good enough – but if it is supposed to process an iterable in the first place,
how can you distinguish whether to use the iterized version or not?
The solution depends on the situation and the iterface you want. You choose.

Since the situation where you’ll want to iterize functions in the first place is when
you’re building streaming pipelines, a good fallback choice is to iterize if and
only if the input is an iterator. This is condition will trigger the iterization
when the input has a `__next__` – so things like generators, but not lists,
tuples, sets, etc.

See in the following that `ConditionalIterize` also has a `wrap` class method
that can be used to wrap a function at definition time.

```pycon
>>> @ConditionalIterize.wrap(Iterator)  # Iterator is the default, so no need here
... def foo(x, y=2):
...     return x * y
>>> foo(3)
6
>>> foo('string')
'stringstring'
```

If you want to process a “stream” of numbers 1, 2, 3, don’t do it this way:

```pycon
>>> foo([1, 2, 3])
[1, 2, 3, 1, 2, 3]
```

Instead, you should explicitly wrap that iterable in an iterator, to trigger the
iterization:

```pycon
>>> list(foo(iter([1, 2, 3])))
[2, 4, 6]
```

So far, the only way we controlled the iterize condition is through a type.
Really, the condition that is used behind the scenes is
`isinstance(obj, self.iterize_type)`.
If you need more complex conditions though, you can specify it through the
`iterize_condition` argument. The `iterize_type` is also used to
annotate the resulting wrapped function if it’s first argument is annotated.
As a consequence, `iterize_type` needs to be a “generic” type.

```pycon
>>> @ConditionalIterize.wrap(Iterable, lambda x: isinstance(x, (list, tuple)))
... def foo(x: int, y=2):
...     return x * y
>>> foo(3)
6
>>> list(foo([1, 2, 3]))
[2, 4, 6]
>>> from inspect import signature
```

We annotated `x` as `int`, so see now the annotation of the wrapped function:

```pycon
>>> str(signature(foo))
'(x: Union[int, Iterable[int]], y=2)'
```

#### *classmethod* wrap(iterize_type=<class 'collections.abc.Iterator'>, iterize_condition=None)

Make a decorator building a `ConditionalIterize` with the given type and
condition.

### *exception* meshed.util.InvalidFunctionParameters

Bases: [`ValueError`](https://docs.python.org/3/builtins/exceptions.html#ValueError)

To be used when a function’s parameters are not compliant with some rule about
them.

### *class* meshed.util.ModuleNotFoundIgnore

Bases: [`object`](https://docs.python.org/3/builtins/functions.html#object)

Context manager that suppresses any exception raised inside its block.

Written to silence `ModuleNotFoundError`, but `__exit__` returns `True`
unconditionally, so every exception type is swallowed.

### *exception* meshed.util.NameValidationError

Bases: [`ValueError`](https://docs.python.org/3/builtins/exceptions.html#ValueError)

Use to indicate that there’s a problem with a name or generating a valid name

### *exception* meshed.util.NotFound

Bases: [`ValidationError`](_autosummary/meshed.util.html.md#meshed.util.ValidationError)

To be raised when something is expected to exist, but doesn’t

### *exception* meshed.util.NotUniqueError

Bases: [`ValidationError`](_autosummary/meshed.util.html.md#meshed.util.ValidationError)

Error to be raised when unicity is expected, but violated

### *exception* meshed.util.ValidationError

Bases: [`ValueError`](https://docs.python.org/3/builtins/exceptions.html#ValueError)

Error that is raised when an object’s validation failed

### meshed.util.arg_names(func, func_name, exclude_names=())

List `func`’s parameter names, renaming those found in `exclude_names`.

A clashing name becomes the first free `f"{func_name}__{name}"` variant
(see `find_first_free_name`).

```pycon
>>> arg_names(lambda a, b, c: None, 'myf', exclude_names=('a',))
['myf__a', 'b', 'c']
```

### meshed.util.args_funcnames(funcs, name_of_func=<function func_name>)

Generates (arg_name, func_id) pairs from the iterable of functions

### meshed.util.conditional_trans(obj, condition, trans)

Conditionally transform an object unless it is marked as a literal.

```pycon
>>> from functools import partial
>>> trans = partial(
...     conditional_trans, condition=str.isnumeric, trans=float
... )
>>> trans('not a number')
'not a number'
>>> trans('10')
10.0
```

To use this function but tell it to not transform some a specific input no matter
what, wrap the input with `Literal`

```pycon
>>> # from meshed import Literal
>>> conditional_trans(LiteralVal('10'), str.isnumeric, float)
'10'
```

### meshed.util.conservative_parameter_merge(\*params, same_name=True, same_kind=True, same_default=True, same_annotation=True)

Validates that all the params are exactly the same, returning the first if so.

This is used when hooking up functions that use the same parameters (i.e. arg
names). When the name of an argument is used more than once, which kind, default,
and annotation should be used in the interface of the DAG?

If they’re all the same, there’s no problem.

But if they’re not the same, we need to provide control on which to ignore.

```pycon
>>> from inspect import Parameter as P
>>> PK = P.POSITIONAL_OR_KEYWORD
>>> KO = P.KEYWORD_ONLY
>>> parameter_merger(P('a', PK), P('a', PK))
<Parameter "a">
>>> parameter_merger(P('a', PK), P('different_name', PK), same_name=False)
<Parameter "a">
>>> parameter_merger(P('a', PK), P('a', KO), same_kind=False)
<Parameter "a">
>>> parameter_merger(P('a', PK), P('a', PK,  default=42), same_default=False)
<Parameter "a">
>>> parameter_merger(P('a', PK, default=42), P('a', PK), same_default=False)
<Parameter "a=42">
>>> parameter_merger(P('a', PK, annotation=int), P('a', PK), same_annotation=False)
<Parameter "a: int">
```

### meshed.util.curry(func)

Wrap `func` so that positional arguments are passed to it as a single tuple.

```pycon
>>> curry(sum)(1, 2, 3)
6
```

### meshed.util.dot_to_ascii(dot, fancy=True)

Convert a dot string to an ascii rendering of the diagram.

Needs a connection to the internet to work.

```pycon
>>> graph_dot = '''
...     graph {
...         rankdir=LR
...         0 -- {1 2}
...         1 -- {2}
...         2 -> {0 1 3}
...         3
...     }
... '''
>>>
>>> graph_ascii = dot_to_ascii(graph_dot)
>>>
>>> print(graph_ascii)

                 ┌─────────┐
                 ▼         │
     ┌───┐     ┌───┐     ┌───┐     ┌───┐
  ┌▶ │ 0 │ ─── │ 1 │ ─── │   │ ──▶ │ 3 │
  │  └───┘     └───┘     │   │     └───┘
  │    │                 │   │
  │    └──────────────── │ 2 │
  │                      │   │
  │                      │   │
  └───────────────────── │   │
                         └───┘
```

### meshed.util.extra_wraps(func, name=None, doc_prefix='')

Set `func.__name__` and `func.__doc__` in place, returning `func`.

The name is `name` or `func_name(func)`; the doc becomes
`doc_prefix + func.__name__`.

### meshed.util.extract_dict(d, keys)

Extract items from dict `d`, returning them as a dict.

```pycon
>>> extract_dict({'a': 1, 'b': 2, 'c': 3}, ['a', 'c'])
{'a': 1, 'c': 3}
```

Order matters!

```pycon
>>> extract_dict({'a': 1, 'b': 2, 'c': 3}, ['c', 'a'])
{'c': 3, 'a': 1}
```

### meshed.util.extract_items(d, keys)

generator of (k, v) pairs extracted from d for keys

```pycon
>>> list(extract_items({'a': 1, 'b': 2, 'c': 3}, ['a', 'c']))
[('a', 1), ('c', 3)]
```

### meshed.util.extract_values(d, keys)

Extract values from dict `d`, returning them:

- as a tuple if len(keys) > 1
- a single value if len(keys) == 1
- None if not

This is used as the default extractor in DAG

```pycon
>>> extract_values({'a': 1, 'b': 2, 'c': 3}, ['a', 'c'])
(1, 3)
```

Order matters!

```pycon
>>> extract_values({'a': 1, 'b': 2, 'c': 3}, ['c', 'a'])
(3, 1)
```

### meshed.util.filepath_to_module(file_path)

A context manager to import a Python file as a module.

* **Parameters:**
  **file_path** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str)) – The file path of the Python file to import.
* **Yield:**
  The module object.

### meshed.util.find_first_free_name(prefix, exclude_names=(), start_at=2)

Return `prefix`, or the first `f"{prefix}__{i}"` not in `exclude_names`.

`prefix` itself is returned when it is not excluded; otherwise `i` counts
up from `start_at`.

```pycon
>>> find_first_free_name('ab', ('cd',))
'ab'
>>> find_first_free_name('ab', ('ab', 'ab__2'))
'ab__3'
```

### meshed.util.func_name(func)

The func._\_name_\_ of a callable func, or makes and returns one if that fails.
To make one, it calls unamed_func_name which produces incremental names to reduce the chances of clashing

* **Return type:**
  [`str`](https://docs.python.org/3/builtins/stdtypes.html#str)

### meshed.util.funcs_conjunction(\*funcs)

Makes a conjunction of functions. That is, `func1(x) and func2(x) and ...`

```pycon
>>> f = funcs_conjunction(lambda x: isinstance(x, str), lambda x: len(x) >= 5)
>>> f('app')  # because length is less than 5...
False
>>> f('apple')  # length at least 5 so...
True
```

Note that in:

```pycon
>>> f(42)
False
```

it is `False` because it is not a string.
This shows that the second function is not applied to the input at all, since it
doesn’t need to, and if it were, we’d get an error (length of a number?!).

### meshed.util.funcs_disjunction(\*funcs)

Makes a disjunction of functions. That is, `func1(x) or func2(x) or ...`

```pycon
>>> f = funcs_disjunction(lambda x: x > 10, lambda x: x < -5)
>>> f(7)
False
>>> f(-7)
True
```

### meshed.util.funcs_to_digraph(funcs, graph=None)

Add `(arg_name, func_name)` edges of `funcs` to a `graphviz.Digraph`.

A new `Digraph` is made if `graph` is None; functions are drawn as boxes.

### meshed.util.if_then_else(if_func, then_func, else_func, \*args, \*\*kwargs)

Tool to “functionalize” the if-then-else logic.

```pycon
>>> from functools import partial
>>> f = partial(if_then_else, str.isnumeric, int, str)
>>> f('a string')
'a string'
>>> f('42')
42
```

### meshed.util.incremental_str_maker(str_format='{:03.f}')

Make a function that will produce a (incrementally) new string at every call.

### meshed.util.instance_checker(class_or_tuple)

Makes a boolean function that checks the instance of an object

```pycon
>>> isinstance_of_str = instance_checker(str)
>>> isinstance_of_str('asdf')
True
>>> isinstance_of_str(3)
False
```

### meshed.util.inverse_dict_asserting_losslessness(d)

Invert `d` (values become keys), asserting that no values are duplicated.

Raises `AssertionError` if two keys share a value, since the inversion would
lose one of them.

```pycon
>>> inverse_dict_asserting_losslessness({'a': 1, 'b': 2})
{1: 'a', 2: 'b'}
```

### meshed.util.iterize(func, name=None)

From an Input->Output function, makes a Iterator[Input]->Iterator[Output]
Some call this “vectorization”, but it’s not really a vector, but an
iterable, thus the name.

`iterize` is a partial of `map`.

```pycon
>>> f = lambda x: x * 10
>>> f(2)
20
>>> iterized_f = iterize(f)
>>> list(iterized_f(iter([1,2,3])))
[10, 20, 30]
```

Consider the following pipeline:

```pycon
>>> from i2 import Pipe
>>> pipe = Pipe(lambda x: x * 2, lambda x: f"hello {x}")
>>> pipe(1)
'hello 2'
```

But what if you wanted to use the pipeline on a “stream” of data. The
following wouldn’t work:

```pycon
>>> try:
...     pipe(iter([1,2,3]))
... except TypeError as e:
...     print(f"{type(e).__name__}: {e}")
...
...
TypeError: unsupported operand type(s) for *: 'list_iterator' and 'int'
```

Remember that error: You’ll surely encounter it at some point.

The solution to it is (often): `iterize`,
which transforms a function that is meant to be applied to a single object,
into a function that is meant to be applied to an array, or any iterable
of such objects.
(You might be familiar (if you use `numpy` for example) with the related
concept of “vectorization”,
or [array programming](https://en.wikipedia.org/wiki/Array_programming).)

```pycon
>>> from i2 import Pipe
>>> from meshed.util import iterize
>>> from typing import Iterable
>>>
>>> pipe = Pipe(
...     iterize(lambda x: x * 2),
...     iterize(lambda x: f"hello {x}")
... )
>>> iterable = pipe([1, 2, 3])
>>> # see that the result is an iterable
>>> assert isinstance(iterable, Iterable)
>>> list(iterable)  # consume the iterable and gather it's items
['hello 2', 'hello 4', 'hello 6']
```

### meshed.util.mk_func_name(func, exclude_names=())

Makes a function name that doesn’t clash with the exclude_names iterable.
Tries it’s best to not be lazy, but instead extract a name from the function
itself.

### meshed.util.mk_place_holder_func(arg_names_or_sig, name=None, defaults=(), annotations=())

Make (working and picklable) function with a specific signature.

This is useful for testing as well as injecting compliant functions in DAG templates.

* **Parameters:**
  * **arg_names_or_sig** – Anything that i2.Sig can accept as it’s first input.
    (Such as a string of argument(s), function, signature, etc.)
  * **name** – The `__name__` to give the function.
  * **defaults** – If you want to add/change defaults
  * **annotations** – If you want to add/change annotations
* **Returns:**
  A (working and picklable) function with a specific signature

```pycon
>>> f = mk_place_holder_func('a b', 'my_func')
>>> f(1,2)
'my_func(a=1, b=2)'
```

The first argument can be any expression of a signature that `i2.Sig` can
understand. For instance, it could be a function itself.
See how the function takes on `mk_place_holder_func`’s signature and name in the
following example:

```pycon
>>> g = mk_place_holder_func(mk_place_holder_func)
>>> from inspect import signature
>>> str(signature(g))  # should give the same signature as mk_place_holder_func
'(arg_names_or_sig, name=None, defaults=(), annotations=())'
>>> g(1,2,defaults=3, annotations=4)
'mk_place_holder_func(arg_names_or_sig=1, name=2, defaults=3, annotations=4)'
```

### meshed.util.my_isinstance(obj, class_or_tuple)

Same as builtin instance, but without position only constraint.
Therefore, we can partialize class_or_tuple:

Otherwise, couldn’t do:

```pycon
>>> isinstance_of_str = partial(my_isinstance, class_or_tuple=str)
>>> isinstance_of_str('asdf')
True
>>> isinstance_of_str(3)
False
```

### meshed.util.mywraps(func, name=None, doc_prefix='')

Make a decorator applying `functools.wraps(func)` then `extra_wraps` to a
callable.

### meshed.util.named_partial(func, \*args, \_\_name_\_=None, \*\*keywords)

functools.partial, but with a \_\_name_\_

```pycon
>>> f = named_partial(print, sep='\n')
>>> f.__name__
'print'
```

```pycon
>>> f = named_partial(print, sep='\n', __name__='now_partial_has_a_name')
>>> f.__name__
'now_partial_has_a_name'
```

### meshed.util.numbered_suffix_renamer(name, sep='_')

Append `sep + "1"` to `name`, or increment its existing numbered suffix.

```pycon
>>> numbered_suffix_renamer('item')
'item_1'
>>> numbered_suffix_renamer('item_1')
'item_2'
```

### meshed.util.objects_defined_in_module(module, , name_filt=None, obj_filt=None)

Get a dictionary of objects defined in a Python module, optionally filtered by their names and values.

* **Parameters:**
  * **module** ([`str`](https://docs.python.org/3/builtins/stdtypes.html#str) | [`ModuleType`](https://docs.python.org/3/library/types.html#types.ModuleType)) – 

    The module to look up. Can either be
    - the module object itself,
    - a string specifying the module’s fully qualified name (e.g., ‘os.path’), or
    - a .py filepath to the module
  * **name_filt** ([`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable) | [`None`](https://docs.python.org/3/builtins/constants.html#None)) – An optional function used to filter the names of objects in the module.
    This function should take a single argument (the object name as a string)
    and return a boolean. Only objects whose names pass the filter (i.e.,
    for which the function returns True) are included.
    If None, no name filtering is applied.
  * **obj_filt** ([`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable) | [`None`](https://docs.python.org/3/builtins/constants.html#None)) – An optional function used to filter the objects in the module. This function should take a
    single argument (the object itself) and return a boolean. Only objects that pass the filter
    (i.e., for which the function returns True) are included.
    If None, no object filtering is applied.
* **Returns:**
  A dictionary where keys are names of objects defined in the module (filtered by name_filt and obj_filt)
  and values are the corresponding objects.
* **Return type:**
  [*dict*](https://docs.python.org/3/builtins/stdtypes.html#dict)

### Examples

```pycon
>>> import os
>>> all_os_objects = objects_defined_in_module(os)
>>> 'removedirs' in all_os_objects
True
>>> all_os_objects['removedirs'] == os.removedirs
True
```

See that you can specify the module via a string too, and filter to get only
callables that don’t start with an underscore:

```pycon
>>> this_modules_funcs = objects_defined_in_module(
...     'meshed.util',
...     name_filt=lambda name: not name.startswith('_'),
...     obj_filt=callable,
... )
>>> callable(this_modules_funcs['objects_defined_in_module'])
True
```

### meshed.util.ordered_set_operations(a, b)

Returns a triple (a-b, a&b, b-a) for two iterables a and b.
The operations are performed as if a and b were sets, but the order in a is conserved.

* **Return type:**
  [`tuple`](https://docs.python.org/3/builtins/stdtypes.html#tuple)[[`list`](https://docs.python.org/3/builtins/stdtypes.html#list), [`list`](https://docs.python.org/3/builtins/stdtypes.html#list), [`list`](https://docs.python.org/3/builtins/stdtypes.html#list)]

```pycon
>>> ordered_set_operations([1, 2, 3, 4], [3, 4, 5, 6])
([1, 2], [3, 4], [5, 6])
```

```pycon
>>> ordered_set_operations("abcde", "cdefg")
(['a', 'b'], ['c', 'd', 'e'], ['f', 'g'])
```

```pycon
>>> ordered_set_operations([1, 2, 2, 3], [2, 3, 3, 4])
([1], [2, 3], [4])
```

### meshed.util.pairs(xs)

List the consecutive `(xs[i], xs[i+1])` pairs of a sequence.

A sequence of length 0 or 1 is returned as is.

```pycon
>>> pairs([1, 2, 3])
[(1, 2), (2, 3)]
```

### meshed.util.parameter_merger(\*params, same_name=True, same_kind=True, same_default=True, same_annotation=True)

Validates that all the params are exactly the same, returning the first if so.

This is used when hooking up functions that use the same parameters (i.e. arg
names). When the name of an argument is used more than once, which kind, default,
and annotation should be used in the interface of the DAG?

If they’re all the same, there’s no problem.

But if they’re not the same, we need to provide control on which to ignore.

```pycon
>>> from inspect import Parameter as P
>>> PK = P.POSITIONAL_OR_KEYWORD
>>> KO = P.KEYWORD_ONLY
>>> parameter_merger(P('a', PK), P('a', PK))
<Parameter "a">
>>> parameter_merger(P('a', PK), P('different_name', PK), same_name=False)
<Parameter "a">
>>> parameter_merger(P('a', PK), P('a', KO), same_kind=False)
<Parameter "a">
>>> parameter_merger(P('a', PK), P('a', PK,  default=42), same_default=False)
<Parameter "a">
>>> parameter_merger(P('a', PK, default=42), P('a', PK), same_default=False)
<Parameter "a=42">
>>> parameter_merger(P('a', PK, annotation=int), P('a', PK), same_annotation=False)
<Parameter "a: int">
```

### meshed.util.print_ascii_graph(funcs)

Print an ascii rendering of `funcs_to_digraph(funcs)`.

Uses `dot_to_ascii`, so needs an internet connection.

### meshed.util.provides(\*var_names)

Decorator to assign `var_names` to a `_provides` attribute of function.

This is meant to be used to indicate to a mesh what var nodes a function can source
values for.

* **Return type:**
  [`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)[[[`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)], [`Callable`](https://docs.python.org/3/library/collections.abc.html#collections.abc.Callable)]

```pycon
>>> @provides('a', 'b')
... def f(x):
...     return x + 1
>>> f._provides
('a', 'b')
```

If no `var_names` are given, then the function name is used as the var name:

```pycon
>>> @provides()
... def g(x):
...     return x + 1
>>> g._provides
('g',)
```

If `var_names` contains `'_'`, then the function name is used as the var name
for that position:

```pycon
>>> @provides('b', '_')
... def h(x):
...     return x + 1
>>> h._provides
('b', 'h')
```

### meshed.util.replace_item_in_iterable(iterable, condition, replacement, , egress=None)

Returns a list where all items satisfying `condition(item)` were replaced
with `replacement(item)`.

If `condition` is not a callable, it will be considered as a value to check
against using `==`.

If `replacement` is not a callable, it will be considered as the actual
value to replace by.

* **Parameters:**
  * **iterable** – Input iterable of items
  * **condition** – Condition to apply to item to see if it should be replaced
  * **replacement** – (Conditional) replacement value or function
  * **egress** – The function to apply to transformed iterable

```pycon
>>> replace_item_in_iterable([1,2,3,4,5], condition=2, replacement = 'two')
[1, 'two', 3, 4, 5]
>>> is_even = lambda x: x % 2 == 0
>>> replace_item_in_iterable([1,2,3,4,5], condition=is_even, replacement = 'even')
[1, 'even', 3, 'even', 5]
>>> replace_item_in_iterable([1,2,3,4,5], is_even, replacement=lambda x: x * 10)
[1, 20, 3, 40, 5]
```

Note that if the input iterable is not a `list`, `tuple`, or `set`,
your output will be an iterator that you’ll have to iterate through to gather
transformed items.

```pycon
>>> g = replace_item_in_iterable(iter([1,2,3,4,5]), condition=2, replacement = 'two')
>>> isinstance(g, Iterator)
True
```

Unless you specify an egress of your choice:

```pycon
>>> replace_item_in_iterable(
... iter([1,2,3,4,5]), is_even, lambda x: x * 10, egress=sorted
... )
[1, 3, 5, 20, 40]
```

### meshed.util.uncurry(func)

Wrap `func` so that it takes one tuple and unpacks it into positional arguments.

```pycon
>>> uncurry(lambda a, b: a + b)((1, 2))
3
```


# _autosummary/meshed.viz.html.md

# meshed.viz

Visualization utilities for the meshed package.

### Functions

| [`add_new_line_if_none`](_autosummary/meshed.viz.html.md#meshed.viz.add_new_line_if_none)(s)                           | Since graphviz 0.18, need to have a newline in body lines.   |
|----------------------------------------------------------------------------------------------------|--------------------------------------------------------------|
| [`dot_lines_of_func_nodes`](_autosummary/meshed.viz.html.md#meshed.viz.dot_lines_of_func_nodes)(objs[, start_lines, ...]) | Get lines generator for the graphviz.DiGraph(body=list(...)) |
| [`dot_lines_of_objs`](_autosummary/meshed.viz.html.md#meshed.viz.dot_lines_of_objs)(objs[, start_lines, end_lines]) | Get lines generator for the graphviz.DiGraph(body=list(...)) |
| `visualize_graph`(graph)                                                                           |                                                              |
| `visualize_graph_interactive`(graph)                                                               |                                                              |

### meshed.viz.add_new_line_if_none(s)

Since graphviz 0.18, need to have a newline in body lines.
This util is there to address that, adding newlines to body lines
when missing.

### meshed.viz.dot_lines_of_func_nodes(objs, start_lines=(), end_lines=(), \*\*kwargs)

Get lines generator for the graphviz.DiGraph(body=list(…))

```pycon
>>> from meshed.base import FuncNode
>>> def add(a, b=1):
...     return a + b
>>> def mult(x, y=3):
...     return x * y
>>> def exp(mult, a):
...     return mult ** a
>>> func_nodes = [
...     FuncNode(add, out='x'),
...     FuncNode(mult, name='the_product'),
...     FuncNode(exp)
... ]
>>> lines = list(dot_lines_of_objs(func_nodes))
>>> assert lines == [
... 'x [label="x" shape="none"]',
... '_add [label="_add" shape="box"]',
... '_add -> x',
... 'a [label="a" shape="none"]',
... 'b [label="b=" shape="none"]',
... 'a -> _add',
... 'b -> _add',
... 'mult [label="mult" shape="none"]',
... 'the_product [label="the_product" shape="box"]',
... 'the_product -> mult',
... 'x [label="x" shape="none"]',
... 'y [label="y=" shape="none"]',
... 'x -> the_product',
... 'y -> the_product',
... 'exp [label="exp" shape="none"]',
... '_exp [label="_exp" shape="box"]',
... '_exp -> exp',
... 'mult [label="mult" shape="none"]',
... 'a [label="a" shape="none"]',
... 'mult -> _exp',
... 'a -> _exp'
... ]
```

```pycon
>>> from meshed.util import dot_to_ascii
>>>
>>> print(dot_to_ascii('\n'.join(lines)))

                a        ─┐
                          │
           │              │
           │              │
           ▼              │
         ┌─────────────┐  │
 b=  ──▶ │    _add     │  │
         └─────────────┘  │
           │              │
           │              │
           ▼              │
                          │
                x         │
                          │
           │              │
           │              │
           ▼              │
         ┌─────────────┐  │
 y=  ──▶ │ the_product │  │
         └─────────────┘  │
           │              │
           │              │
           ▼              │
                          │
              mult        │
                          │
           │              │
           │              │
           ▼              │
         ┌─────────────┐  │
         │    _exp     │ ◀┘
         └─────────────┘
           │
           │
           ▼

               exp
```

### meshed.viz.dot_lines_of_objs(objs, start_lines=(), end_lines=(), \*\*kwargs)

Get lines generator for the graphviz.DiGraph(body=list(…))

```pycon
>>> from meshed.base import FuncNode
>>> def add(a, b=1):
...     return a + b
>>> def mult(x, y=3):
...     return x * y
>>> def exp(mult, a):
...     return mult ** a
>>> func_nodes = [
...     FuncNode(add, out='x'),
...     FuncNode(mult, name='the_product'),
...     FuncNode(exp)
... ]
>>> lines = list(dot_lines_of_objs(func_nodes))
>>> assert lines == [
... 'x [label="x" shape="none"]',
... '_add [label="_add" shape="box"]',
... '_add -> x',
... 'a [label="a" shape="none"]',
... 'b [label="b=" shape="none"]',
... 'a -> _add',
... 'b -> _add',
... 'mult [label="mult" shape="none"]',
... 'the_product [label="the_product" shape="box"]',
... 'the_product -> mult',
... 'x [label="x" shape="none"]',
... 'y [label="y=" shape="none"]',
... 'x -> the_product',
... 'y -> the_product',
... 'exp [label="exp" shape="none"]',
... '_exp [label="_exp" shape="box"]',
... '_exp -> exp',
... 'mult [label="mult" shape="none"]',
... 'a [label="a" shape="none"]',
... 'mult -> _exp',
... 'a -> _exp'
... ]
```

```pycon
>>> from meshed.util import dot_to_ascii
>>>
>>> print(dot_to_ascii('\n'.join(lines)))

                a        ─┐
                          │
           │              │
           │              │
           ▼              │
         ┌─────────────┐  │
 b=  ──▶ │    _add     │  │
         └─────────────┘  │
           │              │
           │              │
           ▼              │
                          │
                x         │
                          │
           │              │
           │              │
           ▼              │
         ┌─────────────┐  │
 y=  ──▶ │ the_product │  │
         └─────────────┘  │
           │              │
           │              │
           ▼              │
                          │
              mult        │
                          │
           │              │
           │              │
           ▼              │
         ┌─────────────┐  │
         │    _exp     │ ◀┘
         └─────────────┘
           │
           │
           ▼

               exp
```


# about-this-build.html.md

<!-- generated by epythet -->

# About this build

This documentation was built on **2026-09-15 09:53 UTC** from commit <a href="https://github.com/i2mint/meshed/commit/0cb260952aa201313ccfbbca5a81dc0fd07c7a2a"><code>0cb2609</code></a> on branch <code>master</code>, for **meshed 0.1.168** (from <code>setup.cfg</code>).

#### NOTE
Nothing suggests a mismatch: the tree was clean at the commit above, and the documented version is the one on PyPI.

## Source

|                     |                                                                                                                                                      |
|---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| Commit              | <a href="https://github.com/i2mint/meshed/commit/0cb260952aa201313ccfbbca5a81dc0fd07c7a2a"><code>0cb260952aa201313ccfbbca5a81dc0fd07c7a2a</code></a> |
| Branch              | <code>master</code>                                                                                                                                  |
| Tags at this commit | <code>0.1.168</code>                                                                                                                                 |
| Working tree        | clean                                                                                                                                                |
| Remote              | <code>https://github.com/i2mint/meshed</code>                                                                                                        |

## Continuous integration

|              |                                                                                            |
|--------------|--------------------------------------------------------------------------------------------|
| Repository   | <code>i2mint/meshed</code>                                                                 |
| Run          | <a href="https://github.com/i2mint/meshed/actions/runs/34954693760">34954693760</a>        |
| Ref          | <code>refs/heads/master</code>                                                             |
| Event commit | <code>086bd85da534561b03653f6a24cddeee7e06e60d</code> (in the history of the built commit) |

## Tools

|          |         |
|----------|---------|
| epythet  | 0.2.8   |
| Sphinx   | 9.1.0   |
| docutils | 0.22.4  |
| Python   | 3.12.14 |

## Configuration as resolved

|               |                                                                   |
|---------------|-------------------------------------------------------------------|
| theme         | <code>auto</code> (Sphinx theme <code>pydata_sphinx_theme</code>) |
| accent        | <code>#486300</code>                                              |
| api_generator | <code>autosummary</code>                                          |
| ignore        | <code>tests/</code>                                               |
| agent_outputs | <code>true</code>                                                 |
| aggregates    | <code>md</code>                                                   |
| ai_artifacts  | <code>true</code>                                                 |

## Package on PyPI

Latest release: <a href="https://pypi.org/project/meshed/0.1.168/">0.1.168</a>, the same as the documented version.

## Reproduce

```bash
git clone https://github.com/i2mint/meshed && cd meshed
git checkout 0cb260952aa201313ccfbbca5a81dc0fd07c7a2a
pip install "epythet==0.2.8"
epythet quickstart . --ignore tests/
```

The same data, for machines: <a href="build_info.json"><code>build_info.json</code></a> (schema version 1).


# api.html.md

# API reference

| [`meshed`](_autosummary/meshed.html.md#module-meshed)   | `meshed` contains a set of tools that allow the developer to provide a collection of python objects (think functions) and some policy of how these should be connected and get an aggregate object that will use the underlying objects in some way.   |
|-------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|


