# Results

> How the return type picks the display: Markdown, tables with CSV download, key-value lists and files.

Source: https://callables.app/docs/results

The return annotation decides how a result is shown. Always annotate it.

| Return annotation | Shown as |
|---|---|
| `-> str` | Markdown: headings, lists, links and tables work |
| `-> list[dict]`, a list of models, or a DataFrame | A table with CSV download |
| `-> dict` or a Pydantic model | A key-value list |
| `-> File` or `-> list[File]` | Download buttons |
| `-> None` | "Done" |
| Missing, or anything else | Raw JSON (avoid this) |

## Tables

Return a list of dicts, a list of Pydantic models or a pandas DataFrame:

```python
@deploy(title="Find a customer", secrets=["STRIPE_KEY"])
def find_customer(email: str) -> list[dict]:
    return [
        {"id": "cus_123", "name": "Ann Lee", "plan": "Pro"},
    ]
```

- Keys become column headers, so use readable keys.
- Keep rows flat, with scalar values. Nested values show as JSON.
- Every table can be downloaded as CSV.
- Rows can offer next actions. See [flows](https://callables.app/docs/flows).

## Markdown

Return a `str` and it's rendered as Markdown:

```python
@deploy(title="Weekly summary")
def weekly_summary(region: str = "NA") -> str:
    total = 48200
    return f"## {region}\n\nClosed this week: **${total:,}**"
```

## Records

Return a `dict` or a Pydantic model for one record, shown as labelled values.

## Files

Return a `File` or a list of them, and people get download buttons. See [files](https://callables.app/docs/files).

## Logs

`print()` output and `logging` show as the run's logs, live while it runs. Use them for progress, not for the result: return the result instead.
