Skip to main content

Fileboy for Python

The official Python client for Fileboy: upload files and videos, build image URLs that resize on the fly, and read video data. Its only dependency is requests.

Install

pip install fileboy

Python 3.8 or newer.

Quick start

import os
import fileboy

client = fileboy.Client(public_key=os.environ["FILEBOY_PUBLIC_KEY"])

file = client.upload_file("report.pdf")   # a path, a binary file object or bytes
print(file.id)                            # store this

client.build_file_url(file.id, download=True)
client.build_image_url(file.id, transforms=[{"type": "resize", "width": 300}, {"type": "format", "format": "webp"}])
# https://api.fileboy.io/images/get/<id>?transform=resize:300x_;format:webp

Django and other frameworks

Configure once, then call fileboy.client() anywhere:

# settings.py (or an AppConfig.ready())
import os
import fileboy

fileboy.configure(
    public_key=os.environ["FILEBOY_PUBLIC_KEY"],
    # private_key=...,   only if your app uses signed requests
    # api_url="https://api.fileboy.io",
)
# views.py
import fileboy

def upload(request):
    file = fileboy.client().upload_file(request.FILES["file"], name=request.FILES["file"].name)
    ...

FILEBOY_PUBLIC_KEY, FILEBOY_PRIVATE_KEY and FILEBOY_API_URL are read from the environment when you do not set them.

What you can do

Task Method
Upload a path, file object or bytes upload_file(file, name=, mime=, metadata=)
Upload from a path upload_file_from_path(path, ...)
Upload from a URL upload_file_from_url(url, name=, metadata=, expect=)
File details fetch_file_data(id_or_label)
File URL build_file_url(id_or_label, filename=, download=)
Image URL with transforms build_image_url(id_or_label, transforms=, filename=, download=)
Download bytes download_file(id_or_label, range=), download_image(id_or_label, transforms=, range=)
Upload a video upload_video(file, name=, mime=)
Video details fetch_video_data(id), fetch_video_info(id)
Manifest and poster URLs build_video_manifest_url(id, type="hls"), build_video_poster_url(id)
Custom poster upload_video_poster(video_id, image), download_video_poster(video_id)
Transcripts upload_video_transcript(id, file, language="English"), fetch_video_transcript(id, transcript_id)
List, update and delete files (private key) list_files(...), iter_files(...), update_file(id, ...), delete_file(id), delete_files(ids)
Manage videos, labels, usage (private key) list_videos, update_video, delete_video, list_labels, create_label, delete_label, get_usage
Signed access token create_access_token(read=, write=, upload=, expires_in=)

An id that is a UUID is used as is. Anything else is treated as a label in your app, and a value that already contains a + is passed through. Labels are created in the dashboard.

Uploads return a FileData dataclass (id, name, original_filename, mime, metadata, file_size, content_hash, signed, dies_at, created_at). upload_video returns a Video (id, name, raw_file_id). range is a (first_byte, last_byte) tuple.

Managing files

Listing, updating and deleting files, videos and labels needs your app's private key. With only the public key these methods raise ConfigurationError before any request is made.

client = fileboy.Client(public_key="PUBLIC", private_key="PRIVATE")

# One page, or every match across all pages
page = client.list_files(mime="image/", limit=50)
for file in page.items:
    print(file.name, file.labels)
more = client.list_files(cursor=page.next_cursor)  # next_cursor is None on the last page
for file in client.iter_files(metadata={"orderId": "42"}):
    print(file.id)

# Metadata is merged (None removes a key). Pass replace_metadata=True to replace it all.
client.update_file(file_id, name="new.png", metadata={"keep": "1", "drop": None},
                   add_labels=["hero"], remove_labels=["old"])
client.update_file("hero", name="renamed.png")  # an id without a hyphen is a label

client.delete_file(file_id)  # NotFoundError if it is already gone
result = client.delete_files([id_a, id_b])  # up to 100; result.deleted, .not_found, .failed

client.list_videos(status="ready")
client.update_video(video_id, name="launch.mp4")
client.delete_video(video_id)

client.list_labels()
client.create_label("hero", file_id=file_id)
client.delete_label("hero")

usage = client.get_usage()  # usage.files, usage.videos, usage.storage_bytes, usage.limits.files

Errors keep the API's code and status on the exception, and api_message holds the API's own message. NotFoundError, FileboyPermissionError/AuthenticationError and ValidationError tell you what went wrong without reading the code.

Image transforms

transforms= takes a list of dicts applied in order. The image service supports resize, format, quality, background and invert:

[
    {"type": "resize", "width": 200, "height": 200, "fit": "cover"},   # fit: contain cover fill inside outside
    {"type": "resize", "width": 400, "fit": "contain", "position": "top-left", "background": "#ffffff"},
    {"type": "format", "format": "webp"},                              # jpeg png webp tiff bmp
    {"type": "quality", "value": 75},
    {"type": "background", "color": "#fff"},
    {"type": "invert"},
]

You can also pass a dict of name: value, such as {"resize": "300x_", "format": "webp", "quality": 75}, or a ready-made string.

Errors

Every error is a FileboyError with status, code (the API's error code) and body.

Class When
AuthenticationError 401
FileboyPermissionError 403, including plan limits
NotFoundError 404
RateLimitError 429
BadRequestError other 4xx, such as a file that is too large
ValidationError the management API rejected your values (a BadRequestError)
ServerError 5xx
FileboyConnectionError timeouts and network failures
InvalidArgumentError, ConfigurationError bad arguments, before any request

FileboyPermissionError and FileboyConnectionError are prefixed so they do not shadow the Python built-ins PermissionError and ConnectionError.

Notes

  • File, image and video reads need no authorization, so URL builders never sign anything.
  • The shared demo key only accepts small images and cannot upload video.
  • The client uses a requests.Session, so connections are reused between calls.

Development

pip install -e ".[dev]"
pytest

The tests run against a local fake server. The transform builder is also checked against packages/sdk-fixtures/transforms.json, the same cases the Go image parser is tested with.

MIT licensed.

Webhooks

Verify the requests Fileboy sends to your endpoints. Use the raw body, exactly as received:

# Django
import fileboy
from django.http import HttpResponse, HttpResponseBadRequest
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def fileboy_webhook(request):
    try:
        event = fileboy.verify_webhook(request.body, request.headers, settings.FILEBOY_WEBHOOK_SECRET)
    except fileboy.WebhookVerificationError as error:
        return HttpResponseBadRequest(error.code)  # "invalid_signature", "timestamp_out_of_tolerance", ...
    if event["type"] == "video.ready":
        ...  # event["resource"]["urls"]["hls"], event["resource"]["duration"]
    return HttpResponse(status=200)

verify_webhook returns the parsed event (a dict) or raises WebhookVerificationError. The timestamp must be within 5 minutes (tolerance_seconds= changes that). Events carry a unique id that is the same on every retry, so use it to ignore duplicates. fileboy.sign_webhook(body, timestamp, secret) builds a signature for your own tests.

Publishing (maintainers)

You need a PyPI account that owns fileboy (the first upload claims the name) and an API token (account settings, scope: that project once it exists). Try TestPyPI first.

  1. Bump the version in src/fileboy/_version.py and pyproject.toml (keep them equal) and add a section to CHANGELOG.md.
  2. pip install -e '.[dev]' && pytest must pass.
  3. python -m pip install build twine && rm -rf dist && python -m build && twine check dist/*
  4. Rehearse: twine upload --repository testpypi dist/*.
  5. Publish: twine upload dist/* with username __token__ and the API token as the password.
  6. Tag the commit: git tag python-vX.Y.Z && git push origin python-vX.Y.Z.

PyPI never lets you reuse a version number, so bump it for every fix.

Metadata

Release files for fileboy 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fileboy 0.2.0
File Size Uploaded Provenance Actions
fileboy-0.2.0.tar.gz 31.3 kB Without provenance Details for fileboy-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for fileboy 0.2.0
File Interpreter ABI Platform Actions
fileboy-0.2.0-py3-none-any.whl Python 3 none any Details for fileboy-0.2.0-py3-none-any.whl

Total release size: 54.9 kB

Release files / fileboy-0.2.0.tar.gz

Download URL fileboy-0.2.0.tar.gz
Size 31.3 kB
Tags Source
SHA-256 checksum
How to use checksums
657d6bfbed80d4f2d16995fd85dd428bf4f380f47badc28049695f2e3c1be406
BLAKE2b-256 checksum
How to use checksums
d06317e9fcf8316ccb7dcce934955fd8e68450d05531095c1ed0d750e6a4265b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Release files / fileboy-0.2.0-py3-none-any.whl

Download URL fileboy-0.2.0-py3-none-any.whl
Size 23.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ce903748b2d5749df054e4a24d077475385890f62f5a8abe52f8557299d2849f
BLAKE2b-256 checksum
How to use checksums
6f17fe714798326409e7d8c07c979ba4903b5100588d8a7f609787f7a984572b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.6

Security for fileboy 0.2.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page