# metadata.py

Alongside `items.py` you may create another file called `metadata.py`. It can be used to do advanced processing of the metadata you configured for your nodes and groups. Specifically, it allows each bundle to modify metadata before `items.py` is evaluated.

This is accomplished through metadata processors. Metadata processors are functions that take the metadata dictionary generated so far as their single argument. You must then return a dictionary with any modifications you need to make plus at least one of several options:

	@metadata_processor
	def my_metadata_processor(metadata):
	    metadata["foo"] = node.name
	    return metadata, DONE

You must always return the modified metadata dictionary as the first element. After that, there are a few options you can return. Every metadata processor from every bundle is called *repeatedly* with the latest metadata dictionary until it indicates that it is done by returning the `DONE` option or until *all* remaining metadata processors return `RUN_ME_AGAIN`. You must always return one of `DONE` or `RUN_ME_AGAIN`. Use the latter if your metadata processor depends on metadata that is generated by another metadata processor (which may be called after yours). Here is another example:

	@metadata_processor
	def first_metadata_processor(metadata):
	    metadata["foo"] = node.name
	    return metadata, DONE

	@metadata_processor
	def second_metadata_processor(metadata):
	    if "foo" in metadata:
	        metadata["bar"] = metadata["foo"]
	        return metadata, DONE
	    else:
	        return metadata, RUN_ME_AGAIN

In this example, `"bar"` can only be set once `"foo"` is available and thus the `second_metadata_processor` has to wait and request to `RUN_ME_AGAIN` until `first_metadata_processor` ran. This is necessary because the running order of metadata processors is undefined.

<div class="alert alert-danger">To avoid deadlocks when accessing <strong>other</strong> nodes' metadata from within a metadata processor, use <code>other_node.partial_metadata</code> instead of <code>other_node.metadata</code>. For the same reason, always use the <code>metadata</code> parameter to access the current node's metadata, never <code>node.metadata</code>.</div>

<br>

## Available options

<table>
<tr><th>Option</th><th>Description</th></tr>
<tr><td><code>DONE</code></td><td>Indicates that this metadata processor has done all it can and need not be called again. Return this whenever possible.</td></tr>
<tr><td><code>RUN_ME_AGAIN</code></td><td>Indicates that this metadata processor is still waiting for metadata from another metadata processor to become available.</td></tr>
<tr><td><code>DEFAULTS</code></td><td>The returned metadata dictionary will only be used to provide default values. The actual metadata generated so far will be recursively merged into the returned dict. When using this flag, you must not return the original metadata dictionary but construct a new one as in the example below.</td></tr>
<tr><td><code>OVERWRITE</code></td><td>The returned metadata dictionary will be recursively merged into the actual metadata generated so far (inverse of <code>DEFAULTS</code>). When using this flag, you must not return the original metadata dictionary but construct a new one as in the `DEFAULTS` example below.</td></tr>
</table>

Here is an example of how to use `DEFAULTS`:

	@metadata_processor
	def my_metadata_processor(metadata):
	    return {
	        "foo": {
	            "bar": 47,
	        },
	    }, DONE, DEFAULTS

This means `node.metadata["foo"]["bar"]` will be 47 by default, but can also be overridden in static metadata at the node/group level.

<br>

<div class="alert alert-info">For your convenience, you can access <code>repo</code>, <code>node</code>, <code>metadata_processor</code> and all the options in <code>metadata.py</code> without importing them.</div>
