Blog
Guides

Let teammates upload a file and get a result back

DK
Dan Kowalsky
Founder ·

A lot of internal work is "here's a file, please fix it": a contact list full of duplicates, an export that needs reformatting, a batch of PDFs to merge. With Callables, a function can take a file upload and hand back a download, so teammates can do it themselves.

Take a file as input

Use File as a parameter type to get an upload field, and accept(...) to limit the file types:

from typing import Annotated

from callables import File, accept, deploy


@deploy(title="Clean up a contact list")
def clean_contacts(sheet: Annotated[File, accept(".csv")]) -> File:
    """Removes duplicate rows and fixes capitalization."""
    rows = sheet.read_text().splitlines()
    ...
    out = "/tmp/clean.csv"
    ...  # write the cleaned rows to out
    return File(out, name=f"clean-{sheet.name}")

Your teammate sees an upload field that only accepts CSV files. Inside the function, the upload has what you'd expect:

  • sheet.read_text() and sheet.read_bytes() for the contents
  • sheet.open() for a file object, and sheet.path for its path on disk
  • sheet.name and sheet.size

Return a file to download

Returning a File gives the person a download button. Return list[File] for several downloads.

To add downloads next to another result, use save_file. This function shows a summary and also offers the cleaned file:

from callables import File, accept, deploy, save_file


@deploy(title="Clean up a contact list")
def clean_contacts(sheet: Annotated[File, accept(".csv")]) -> str:
    ...
    save_file(out, name=f"clean-{sheet.name}")
    return f"Removed **{removed}** duplicates from {total} rows."

save_file also takes bytes, with a name.

Try it locally

Pass a file with @ and the path:

call local clean_contacts -i [email protected]

Outputs land in ./callables-output/, so you can check them before you push.

Limits to know

  • Uploads can be up to 100 MB.
  • A run can produce up to 100 MB and 20 files of output.
  • Files are deleted after 24 hours, so people should download what they need.
  • Functions with file inputs can't be scheduled, since nobody is there to pick the file.
  • Write temporary files to /tmp (up to 256 MB) or your home directory. Each run starts fresh.

Ideas

  • Merge or split PDFs.
  • Convert a supplier's spreadsheet into your import format.
  • Check a CSV against your database and return the rows that don't match.
  • Resize a folder of images uploaded as a zip.

Turn your scripts into tools your team can run

Add @deploy to a Python function and push. Your team gets a form, schedules and run history.

See how it works