Metadata-Version: 2.5
Name: notation
Version: 1.0.0
Summary: Declarative metadata registries for Python functions, with dictionary and attribute access.
Project-URL: Documentation, https://github.com/adamjpatterson/notation#readme
Project-URL: Issues, https://github.com/adamjpatterson/notation/issues
Project-URL: Source, https://github.com/adamjpatterson/notation
Author-email: Adam Patterson <adpatter2000@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: annotations,decorator,metadata,registry
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Typing :: Typed
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# Notation

Declare metadata beside a function with a decorator and retrieve it later from a registry.

## Installation

```bash
python -m pip install notation
```

Requires Python 3.8 or newer.

## Usage

**Annotate functions**

Positional values are stored under integer keys starting at `0`; keyword values are stored under their names. The decorator returns the original function unchanged.

```python
from notation import Notation

notes = Notation()

@notes("public", method="GET")
def index():
    return "Hello, World!"

notes[index]   # {0: 'public', 'method': 'GET'}
```

**Enumerate registered functions**

The supplied dictionary becomes the instance namespace, so `vars()` returns it directly:

```python
routes = Notation()

@routes(path="/hello")
def hello():
    return "Hello, World!"

handlers = {meta["path"]: fn for fn, meta in vars(routes).items()}
```

## API

`Notation(annotation=None)` installs `annotation`, which must be a `dict` or `None`, as the instance's `__dict__`. A supplied dictionary is used directly, not copied, and `vars(notation)` returns it. `None` creates a new empty dictionary.

- `notation[key]`, `notation[key] = value`, `key in notation` operate on the backing dictionary.
- `notation.name` reads, writes, or deletes the string key `"name"`. A missing attribute raises `AttributeError`; a missing item raises `KeyError`.
- `bool(notation)` is `False` when the backing dictionary is empty.
- `notation(*args, **kwargs)` returns a decorator that stores `{0: args[0], ..., **kwargs}` under the decorated function and returns the function. Decorating the same function again replaces its metadata.

Because the dictionary is the instance namespace, keys that spell Python protocol hooks, such as `__deepcopy__` or `__getstate__`, are visible to `copy` and `pickle`; avoid them as metadata keys. Overrides on `dict` subclasses, such as `defaultdict.__missing__`, apply to item access but not to attribute access. Iteration, `len`, `get`, item deletion, and equality are not provided; use `vars(notation)` instead.

Metadata is keyed by the exact function object. If another decorator replaces the function, the registry still refers to whichever object it was given. Decorators apply bottom-up, so apply `Notation` outermost to key the metadata by the object your module name refers to:

```python
import functools

@notes("public", method="GET")
@functools.lru_cache
def index():
    return "Hello, World!"

notes[index]   # {0: 'public', 'method': 'GET'}
```

With the order reversed, `notes` stores metadata under the inner function and `lru_cache` binds `index` to a new wrapper, so `notes[index]` raises `KeyError`.

## Tests

```bash
python -m pip install -e . mypy
python -m unittest discover -s tests
python -m mypy --strict src/notation tests/typecheck_notation.py
```

## License

MIT. See [LICENSE](https://github.com/adamjpatterson/notation/blob/main/LICENSE).
