# Files

> Take file uploads, return files to download, and save extra files from a run.

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

Functions can take file uploads, return files to download, and save extra files alongside any result.

```python
from typing import Annotated

from callables import File, accept, deploy, save_file


@deploy(title="Clean up a contact list")
def clean_contacts(sheet: Annotated[File, accept(".csv")]) -> File:
    """Removes duplicate rows and fixes capitalisation."""
    rows = sheet.read_text().splitlines()
    save_file(f"{len(rows)} rows in".encode(), name="summary.txt")
    out = "/tmp/clean.csv"
    ...
    return File(out, name=f"clean-{sheet.name}")
```

## Uploads

A `File` parameter becomes an upload field. Use `Annotated[File, accept(".csv", ".xlsx")]` to limit the file types. Your function gets a `File` with:

- `.path`: where the file is on disk
- `.name`: the original file name
- `.size`: its size in bytes
- `.read_text()` and `.read_bytes()`: its contents
- `.open()`: a file object, like the built-in `open()`

## Downloads

Return a `File`, or a `list[File]`, and the person gets download buttons. `File(path, name=...)` sets the name they download it as.

## Extra files

`save_file(path_or_bytes, name=...)` adds a download alongside any return value, such as a table plus the spreadsheet it came from. It needs `name=` when you pass bytes.

## Locally

Pass a file to `call local` with `@`. Outputs land in `./callables-output/`, which `call init` adds to `.gitignore`.

```bash
call local clean_contacts -i sheet=@contacts.csv
```

## Limits

- 100 MB per upload.
- 100 MB and 20 files of output per run.
- Files are deleted after 24 hours.
- Functions with file inputs can't be scheduled, since nobody is there to pick the file.

Write temporary files under `/tmp` (up to 256 MB) or your home directory. See [builds and runtime](https://callables.app/docs/builds).
