Uploader (Python)
Port em Python do pacote PHP coffeecode/uploader
de Robson V. Leite. Mantem o comportamento original (validacao por mime/extensao,
diretorios YYYY/MM, slug, redimensionamento de imagens) com uma API
framework-agnostica baseada em UploadedFile — aceita path em disco ou
stream em memoria, com adapters prontos para Flask e FastAPI.
Python port of the PHP package coffeecode/uploader by Robson V. Leite. Same behavior (mime/extension validation, year/month directories, slugged filenames, image resizing) with a framework-agnostic
UploadedFileAPI: accepts a filesystem path or an in-memory stream, with built-in adapters for Flask and FastAPI.
Destaques
- Upload simples de imagens, arquivos e midias
UploadedFile: abstracao unica para path em disco ou stream- Adapters:
from_flask,from_fastapi,from_stream,from_path,from_dict(compat com PHP$_FILES) - Gestao de diretorios com esquema de datas (
YYYY/MM) - Validacao por mime-type e extensao
- Redimensionamento e qualidade de imagem (substitui
ext-gdpor Pillow)
Instalacao
pip install coffeecode-uploader
Requer Python >= 3.9 e Pillow >= 10.
Uso
Flask
from flask import Flask, request
from coffeecode_uploader import Image, UploadedFile, UploaderException
@app.post("/avatar")
def avatar():
try:
upload = UploadedFile.from_flask(request.files["image"])
path = Image("uploads", "images").upload(upload, request.form["name"])
return {"path": path}
except UploaderException as e:
return {"error": str(e)}, 400
FastAPI
from fastapi import FastAPI, File, UploadFile, HTTPException
from coffeecode_uploader import Image, UploadedFile, UploaderException
app = FastAPI()
@app.post("/avatar")
async def avatar(name: str, image: UploadFile = File(...)):
try:
upload = UploadedFile.from_fastapi(image)
path = Image("uploads", "images").upload(upload, name)
return {"path": path}
except UploaderException as e:
raise HTTPException(400, str(e))
Stream em memoria
from io import BytesIO
from coffeecode_uploader import File, UploadedFile
upload = UploadedFile.from_stream(
BytesIO(pdf_bytes),
filename="report.pdf",
content_type="application/pdf",
)
path = File("uploads", "files").upload(upload, "Relatorio Mensal")
Path ja em disco
from coffeecode_uploader import File, UploadedFile
upload = UploadedFile.from_path("/tmp/report.pdf", content_type="application/pdf")
path = File("uploads", "files").upload(upload, "Relatorio")
Compat com $_FILES (PHP-style)
from coffeecode_uploader import File, UploadedFile
upload = UploadedFile.from_dict({
"name": "report.pdf",
"type": "application/pdf",
"tmp_name": "/tmp/upload.pdf",
})
path = File("uploads", "files").upload(upload, "Relatorio")
API
Construtores
Image(upload_dir, file_type_dir, month_year_path=True)
File(upload_dir, file_type_dir, month_year_path=True)
Media(upload_dir, file_type_dir, month_year_path=True)
Send(upload_dir, file_type_dir, allow_types, extensions, month_year_path=True)
upload(file: UploadedFile, name: str, ...)
Retorna a string com o caminho final relativo. Lanca UploaderException
quando o tipo MIME ou a extensao nao estao na lista permitida.
Image.upload(image, name, width=2000, quality=None)—qualityaceita{"jpg": 0..95, "png": 0..9}. Padrao:{"jpg": 75, "png": 5}. GIFs sao copiados sem reprocessamento (igual ao PHP).File.upload(file, name)Media.upload(media, name)Send.upload(file, name)
UploadedFile
| Metodo | Quando usar |
|---|---|
UploadedFile.from_flask(file_storage) |
request.files["x"] em Flask/Quart |
UploadedFile.from_fastapi(upload_file) |
UploadFile em FastAPI/Starlette |
UploadedFile.from_stream(stream, ...) |
BytesIO, S3 body, qualquer file-like binario |
UploadedFile.from_path(path, content_type) |
Arquivo ja em disco |
UploadedFile.from_dict({...}) |
Compat com $_FILES PHP |
.open() |
Context manager → file-like binario |
.save_to(dst) |
Copia para dst (preserva o source) |
.extension |
Extensao em lowercase a partir de filename |
Helpers
Cls.is_allowed()(aliasCls.isAllowed()) — lista de mime-types permitidos.Cls.is_extension()(aliasCls.isExtension()) — lista de extensoes permitidas.Uploader.multiple([...])— converte lista heterogenea (dict, FileStorage, UploadFile, UploadedFile) emlist[UploadedFile].
Migrar de v1.x
A v1 aceitava um dict no formato PHP $_FILES. Em v2 use UploadedFile:
# v1
file_dict = {"name": "x.pdf", "type": "application/pdf", "tmp_name": "/tmp/x"}
File("uploads", "files").upload(file_dict, "Doc")
# v2
upload = UploadedFile.from_dict(file_dict)
File("uploads", "files").upload(upload, "Doc")
Equivalencia com a versao PHP
| PHP | Python |
|---|---|
CoffeeCode\Uploader\Image |
coffeecode_uploader.Image |
CoffeeCode\Uploader\File |
coffeecode_uploader.File |
CoffeeCode\Uploader\Media |
coffeecode_uploader.Media |
CoffeeCode\Uploader\Send |
coffeecode_uploader.Send |
Exception |
UploaderException |
$_FILES['x'] |
UploadedFile.from_dict({...}) |
move_uploaded_file() |
UploadedFile.save_to() |
ext-gd |
Pillow |
monthYearPath |
month_year_path |
Creditos
- API e comportamento original: Robson V. Leite — coffeecode/uploader (MIT)
- Port Python: Kaue Leal
Licenca
MIT.
Release files for coffeecode-uploader 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| coffeecode_uploader-2.0.0.tar.gz | 14.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| coffeecode_uploader-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.8 kB
Release files / coffeecode_uploader-2.0.0.tar.gz
| Download URL | coffeecode_uploader-2.0.0.tar.gz |
|---|---|
| Size | 14.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
0c32e3dbcb4c2943c66193f13b536f5134630b2e8bc2dc239ceeca714fcb7907
|
|
BLAKE2b-256 checksum How to use checksums |
222d9be631553852d3722e85e9f7a14732b2c955b67be53404488688c0a8c370
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 30, 2026.
Transparency logRelease files / coffeecode_uploader-2.0.0-py3-none-any.whl
| Download URL | coffeecode_uploader-2.0.0-py3-none-any.whl |
|---|---|
| Size | 10.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
85388ebbf14ef3a6fb562f8ea4920662c55e144f45493cfdfe714e63b30663c5
|
|
BLAKE2b-256 checksum How to use checksums |
82ffcb8e79cb369f6912385b78fb8499de559eba62e48581037cdfe99182e98c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Apr 30, 2026.
Transparency log