Metadata-Version: 2.4
Name: maketab
Version: 0.4.4
Summary: Process nested JSON data into tabular output using jmespath queries with Pydantic models
Author: Zachary Povey
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: jmespath>=1.0.0
Requires-Dist: pyarrow>=14.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: pyyaml>=6.0.0
Provides-Extra: tui
Requires-Dist: textual[syntax]>=0.75.0; extra == 'tui'
Description-Content-Type: text/markdown

# maketab

Make nested data tabular using jmespath queries with Pydantic models.

## Multi-level explode

Query roots can nest. Give a root a `parent` (config) or a `root=` (annotation
API) and its query is evaluated within each element produced by that parent,
flattening nested lists to one output row per leaf element. Fields attached to an
ancestor level are broadcast onto every leaf row beneath them.

```python
from maketab import SchemaConfig, maketab_from_config

config = SchemaConfig.model_validate({
    "query_roots": [
        {"name": "task", "query": "tasks", "explode": True},
        {"name": "property", "parent": "task", "query": "properties", "explode": True},
    ],
    "fields": [
        {"name": "task_list_id", "type": "int", "query": "id"},
        {"name": "task_name", "type": "str", "query": "name", "root": "task"},
        {"name": "property_name", "type": "str", "query": "name", "root": "property"},
        {"name": "property_value", "type": "str", "query": "value", "root": "property"},
    ],
})

data = [{"id": 100, "tasks": [
    {"name": "do thing 1", "properties": [
        {"name": "type", "value": "bug"},
        {"name": "team", "value": "team a"},
    ]},
]}]

maketab_from_config(config, data).records  # one row per property
```

Notes:

- **Siblings**: two roots sharing one `parent` produce the cartesian product
  *within* each parent element — they never combine elements across parents.
- **Depth**: parent chains compose to arbitrary depth.
- **Empty/missing lists**: a parent whose child list is `[]` or absent
  contributes zero rows (no row with null leaf fields).

The same nesting is available through the annotation API via `Explode(root=...)`:

```python
from typing import Annotated
from pydantic import BaseModel
from maketab import Query, Explode, maketab

task = Explode("tasks")
prop = Explode("properties", root=task)  # nested within each task

class Row(BaseModel):
    task_list_id: Annotated[int, Query("id")]
    task_name: Annotated[str, Query("name", task)]
    property_name: Annotated[str, Query("name", prop)]

maketab(data, Row)
```

## Custom JMESPath functions

maketab adds a small catalog of custom JMESPath functions (currently
`get` and `to_key_value_pairs`) available in every query it evaluates.
See [`docs/jmespath-functions.md`](docs/jmespath-functions.md) for the
full reference with signatures, types, and examples.
